LCOV - code coverage report
Current view: top level - src/builtins - builtins-function-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 106 106 100.0 %
Date: 2019-04-19 Functions: 6 6 100.0 %

          Line data    Source code
       1             : // Copyright 2017 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/builtins/builtins-utils-gen.h"
       6             : #include "src/builtins/builtins.h"
       7             : #include "src/code-stub-assembler.h"
       8             : #include "src/frame-constants.h"
       9             : #include "src/objects/api-callbacks.h"
      10             : #include "src/objects/descriptor-array.h"
      11             : 
      12             : namespace v8 {
      13             : namespace internal {
      14             : 
      15         224 : TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
      16         112 :   Label slow(this);
      17             : 
      18             :   // TODO(ishell): use constants from Descriptor once the JSFunction linkage
      19             :   // arguments are reordered.
      20             :   Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);
      21             :   Node* context = Parameter(Descriptor::kContext);
      22             :   Node* new_target = Parameter(Descriptor::kJSNewTarget);
      23             : 
      24         168 :   CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
      25             : 
      26             :   // Check that receiver has instance type of JS_FUNCTION_TYPE
      27         112 :   Node* receiver = args.GetReceiver();
      28         112 :   GotoIf(TaggedIsSmi(receiver), &slow);
      29             : 
      30         112 :   Node* receiver_map = LoadMap(receiver);
      31             :   {
      32         112 :     Node* instance_type = LoadMapInstanceType(receiver_map);
      33          56 :     GotoIfNot(
      34         224 :         Word32Or(InstanceTypeEqual(instance_type, JS_FUNCTION_TYPE),
      35         168 :                  InstanceTypeEqual(instance_type, JS_BOUND_FUNCTION_TYPE)),
      36          56 :         &slow);
      37             :   }
      38             : 
      39             :   // Disallow binding of slow-mode functions. We need to figure out whether the
      40             :   // length and name property are in the original state.
      41          56 :   Comment("Disallow binding of slow-mode functions");
      42         112 :   GotoIf(IsDictionaryMap(receiver_map), &slow);
      43             : 
      44             :   // Check whether the length and name properties are still present as
      45             :   // AccessorInfo objects. In that case, their value can be recomputed even if
      46             :   // the actual value on the object changes.
      47          56 :   Comment("Check descriptor array length");
      48          56 :   TNode<DescriptorArray> descriptors = LoadMapDescriptors(receiver_map);
      49             :   // Minimum descriptor array length required for fast path.
      50             :   const int min_nof_descriptors = i::Max(JSFunction::kLengthDescriptorIndex,
      51             :                                          JSFunction::kNameDescriptorIndex);
      52          56 :   TNode<Int32T> nof_descriptors = LoadNumberOfDescriptors(descriptors);
      53          56 :   GotoIf(
      54         168 :       Int32LessThanOrEqual(nof_descriptors, Int32Constant(min_nof_descriptors)),
      55          56 :       &slow);
      56             : 
      57             :   // Check whether the length and name properties are still present as
      58             :   // AccessorInfo objects. In that case, their value can be recomputed even if
      59             :   // the actual value on the object changes.
      60          56 :   Comment("Check name and length properties");
      61             :   {
      62             :     const int length_index = JSFunction::kLengthDescriptorIndex;
      63             :     TNode<Name> maybe_length =
      64          56 :         LoadKeyByDescriptorEntry(descriptors, length_index);
      65         112 :     GotoIf(WordNotEqual(maybe_length, LoadRoot(RootIndex::klength_string)),
      66          56 :            &slow);
      67             : 
      68             :     TNode<Object> maybe_length_accessor =
      69          56 :         LoadValueByDescriptorEntry(descriptors, length_index);
      70         112 :     GotoIf(TaggedIsSmi(maybe_length_accessor), &slow);
      71         112 :     Node* length_value_map = LoadMap(CAST(maybe_length_accessor));
      72         112 :     GotoIfNot(IsAccessorInfoMap(length_value_map), &slow);
      73             : 
      74             :     const int name_index = JSFunction::kNameDescriptorIndex;
      75          56 :     TNode<Name> maybe_name = LoadKeyByDescriptorEntry(descriptors, name_index);
      76         112 :     GotoIf(WordNotEqual(maybe_name, LoadRoot(RootIndex::kname_string)), &slow);
      77             : 
      78             :     TNode<Object> maybe_name_accessor =
      79          56 :         LoadValueByDescriptorEntry(descriptors, name_index);
      80         112 :     GotoIf(TaggedIsSmi(maybe_name_accessor), &slow);
      81          56 :     TNode<Map> name_value_map = LoadMap(CAST(maybe_name_accessor));
      82         112 :     GotoIfNot(IsAccessorInfoMap(name_value_map), &slow);
      83             :   }
      84             : 
      85             :   // Choose the right bound function map based on whether the target is
      86             :   // constructable.
      87          56 :   Comment("Choose the right bound function map");
      88         112 :   VARIABLE(bound_function_map, MachineRepresentation::kTagged);
      89             :   {
      90          56 :     Label with_constructor(this);
      91         112 :     VariableList vars({&bound_function_map}, zone());
      92         112 :     Node* native_context = LoadNativeContext(context);
      93             : 
      94          56 :     Label map_done(this, vars);
      95         112 :     GotoIf(IsConstructorMap(receiver_map), &with_constructor);
      96             : 
      97         112 :     bound_function_map.Bind(LoadContextElement(
      98         112 :         native_context, Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX));
      99          56 :     Goto(&map_done);
     100             : 
     101          56 :     BIND(&with_constructor);
     102         112 :     bound_function_map.Bind(LoadContextElement(
     103         112 :         native_context, Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX));
     104          56 :     Goto(&map_done);
     105             : 
     106          56 :     BIND(&map_done);
     107             :   }
     108             : 
     109             :   // Verify that __proto__ matches that of a the target bound function.
     110          56 :   Comment("Verify that __proto__ matches target bound function");
     111         112 :   Node* prototype = LoadMapPrototype(receiver_map);
     112         168 :   Node* expected_prototype = LoadMapPrototype(bound_function_map.value());
     113         112 :   GotoIf(WordNotEqual(prototype, expected_prototype), &slow);
     114             : 
     115             :   // Allocate the arguments array.
     116          56 :   Comment("Allocate the arguments array");
     117         112 :   VARIABLE(argument_array, MachineRepresentation::kTagged);
     118             :   {
     119          56 :     Label empty_arguments(this);
     120          56 :     Label arguments_done(this, &argument_array);
     121         168 :     GotoIf(Uint32LessThanOrEqual(argc, Int32Constant(1)), &empty_arguments);
     122             :     TNode<IntPtrT> elements_length =
     123         224 :         Signed(ChangeUint32ToWord(Unsigned(Int32Sub(argc, Int32Constant(1)))));
     124             :     TNode<FixedArray> elements = CAST(AllocateFixedArray(
     125             :         PACKED_ELEMENTS, elements_length, kAllowLargeObjectAllocation));
     126         112 :     VARIABLE(index, MachineType::PointerRepresentation());
     127         112 :     index.Bind(IntPtrConstant(0));
     128         112 :     VariableList foreach_vars({&index}, zone());
     129          56 :     args.ForEach(foreach_vars,
     130         224 :                  [this, elements, &index](Node* arg) {
     131         112 :                    StoreFixedArrayElement(elements, index.value(), arg);
     132          56 :                    Increment(&index);
     133          56 :                  },
     134         168 :                  IntPtrConstant(1));
     135          56 :     argument_array.Bind(elements);
     136          56 :     Goto(&arguments_done);
     137             : 
     138          56 :     BIND(&empty_arguments);
     139         112 :     argument_array.Bind(EmptyFixedArrayConstant());
     140          56 :     Goto(&arguments_done);
     141             : 
     142          56 :     BIND(&arguments_done);
     143             :   }
     144             : 
     145             :   // Determine bound receiver.
     146          56 :   Comment("Determine bound receiver");
     147         112 :   VARIABLE(bound_receiver, MachineRepresentation::kTagged);
     148             :   {
     149          56 :     Label has_receiver(this);
     150          56 :     Label receiver_done(this, &bound_receiver);
     151         168 :     GotoIf(Word32NotEqual(argc, Int32Constant(0)), &has_receiver);
     152         112 :     bound_receiver.Bind(UndefinedConstant());
     153          56 :     Goto(&receiver_done);
     154             : 
     155          56 :     BIND(&has_receiver);
     156         112 :     bound_receiver.Bind(args.AtIndex(0));
     157          56 :     Goto(&receiver_done);
     158             : 
     159          56 :     BIND(&receiver_done);
     160             :   }
     161             : 
     162             :   // Allocate the resulting bound function.
     163          56 :   Comment("Allocate the resulting bound function");
     164             :   {
     165         112 :     Node* bound_function = Allocate(JSBoundFunction::kSize);
     166          56 :     StoreMapNoWriteBarrier(bound_function, bound_function_map.value());
     167             :     StoreObjectFieldNoWriteBarrier(
     168          56 :         bound_function, JSBoundFunction::kBoundTargetFunctionOffset, receiver);
     169          56 :     StoreObjectFieldNoWriteBarrier(bound_function,
     170             :                                    JSBoundFunction::kBoundThisOffset,
     171          56 :                                    bound_receiver.value());
     172          56 :     StoreObjectFieldNoWriteBarrier(bound_function,
     173             :                                    JSBoundFunction::kBoundArgumentsOffset,
     174          56 :                                    argument_array.value());
     175         112 :     Node* empty_fixed_array = EmptyFixedArrayConstant();
     176             :     StoreObjectFieldNoWriteBarrier(
     177          56 :         bound_function, JSObject::kPropertiesOrHashOffset, empty_fixed_array);
     178             :     StoreObjectFieldNoWriteBarrier(bound_function, JSObject::kElementsOffset,
     179          56 :                                    empty_fixed_array);
     180             : 
     181          56 :     args.PopAndReturn(bound_function);
     182             :   }
     183             : 
     184          56 :   BIND(&slow);
     185             :   {
     186             :     // We are not using Parameter(Descriptor::kJSTarget) and loading the value
     187             :     // from the current frame here in order to reduce register pressure on the
     188             :     // fast path.
     189          56 :     TNode<JSFunction> target = LoadTargetFromFrame();
     190          56 :     TailCallBuiltin(Builtins::kFunctionPrototypeBind, context, target,
     191          56 :                     new_target, argc);
     192             :   }
     193          56 : }
     194             : 
     195             : // ES6 #sec-function.prototype-@@hasinstance
     196         168 : TF_BUILTIN(FunctionPrototypeHasInstance, CodeStubAssembler) {
     197             :   Node* context = Parameter(Descriptor::kContext);
     198             :   Node* f = Parameter(Descriptor::kReceiver);
     199             :   Node* v = Parameter(Descriptor::kV);
     200          56 :   Node* result = OrdinaryHasInstance(context, f, v);
     201          56 :   Return(result);
     202          56 : }
     203             : 
     204             : }  // namespace internal
     205       59480 : }  // namespace v8

Generated by: LCOV version 1.10