LCOV - code coverage report
Current view: top level - src/builtins - builtins-function-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 94 94 100.0 %
Date: 2017-10-20 Functions: 5 5 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/zone/zone-list-inl.h"  // TODO(mstarzinger): Temporary cycle breaker.
      10             : 
      11             : namespace v8 {
      12             : namespace internal {
      13             : 
      14         124 : TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
      15          31 :   Label slow(this);
      16             : 
      17             :   // TODO(ishell): use constants from Descriptor once the JSFunction linkage
      18             :   // arguments are reordered.
      19             :   Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
      20             :   Node* context = Parameter(BuiltinDescriptor::kContext);
      21             :   Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
      22             : 
      23          93 :   CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
      24             : 
      25             :   // Check that receiver has instance type of JS_FUNCTION_TYPE
      26          62 :   Node* receiver = args.GetReceiver();
      27          62 :   GotoIf(TaggedIsSmi(receiver), &slow);
      28             : 
      29          62 :   Node* receiver_map = LoadMap(receiver);
      30             :   {
      31          62 :     Node* instance_type = LoadMapInstanceType(receiver_map);
      32             :     GotoIfNot(
      33             :         Word32Or(InstanceTypeEqual(instance_type, JS_FUNCTION_TYPE),
      34          93 :                  InstanceTypeEqual(instance_type, JS_BOUND_FUNCTION_TYPE)),
      35          62 :         &slow);
      36             :   }
      37             : 
      38             :   // Disallow binding of slow-mode functions. We need to figure out whether the
      39             :   // length and name property are in the original state.
      40          31 :   Comment("Disallow binding of slow-mode functions");
      41          62 :   GotoIf(IsDictionaryMap(receiver_map), &slow);
      42             : 
      43             :   // Check whether the length and name properties are still present as
      44             :   // AccessorInfo objects. In that case, their value can be recomputed even if
      45             :   // the actual value on the object changes.
      46          31 :   Comment("Check descriptor array length");
      47          62 :   Node* descriptors = LoadMapDescriptors(receiver_map);
      48          62 :   Node* descriptors_length = LoadFixedArrayBaseLength(descriptors);
      49          93 :   GotoIf(SmiLessThanOrEqual(descriptors_length, SmiConstant(1)), &slow);
      50             : 
      51             :   // Check whether the length and name properties are still present as
      52             :   // AccessorInfo objects. In that case, their value can be recomputed even if
      53             :   // the actual value on the object changes.
      54          31 :   Comment("Check name and length properties");
      55             :   {
      56             :     const int length_index = JSFunction::kLengthDescriptorIndex;
      57             :     Node* maybe_length = LoadFixedArrayElement(
      58          31 :         descriptors, DescriptorArray::ToKeyIndex(length_index));
      59          31 :     GotoIf(WordNotEqual(maybe_length, LoadRoot(Heap::klength_stringRootIndex)),
      60          31 :            &slow);
      61             : 
      62             :     Node* maybe_length_accessor = LoadFixedArrayElement(
      63          31 :         descriptors, DescriptorArray::ToValueIndex(length_index));
      64          62 :     GotoIf(TaggedIsSmi(maybe_length_accessor), &slow);
      65          62 :     Node* length_value_map = LoadMap(maybe_length_accessor);
      66          62 :     GotoIfNot(IsAccessorInfoMap(length_value_map), &slow);
      67             : 
      68             :     const int name_index = JSFunction::kNameDescriptorIndex;
      69             :     Node* maybe_name = LoadFixedArrayElement(
      70          31 :         descriptors, DescriptorArray::ToKeyIndex(name_index));
      71          31 :     GotoIf(WordNotEqual(maybe_name, LoadRoot(Heap::kname_stringRootIndex)),
      72          31 :            &slow);
      73             : 
      74             :     Node* maybe_name_accessor = LoadFixedArrayElement(
      75          31 :         descriptors, DescriptorArray::ToValueIndex(name_index));
      76          62 :     GotoIf(TaggedIsSmi(maybe_name_accessor), &slow);
      77          62 :     Node* name_value_map = LoadMap(maybe_name_accessor);
      78          62 :     GotoIfNot(IsAccessorInfoMap(name_value_map), &slow);
      79             :   }
      80             : 
      81             :   // Choose the right bound function map based on whether the target is
      82             :   // constructable.
      83          31 :   Comment("Choose the right bound function map");
      84          62 :   VARIABLE(bound_function_map, MachineRepresentation::kTagged);
      85             :   {
      86             :     Label with_constructor(this);
      87          31 :     VariableList vars({&bound_function_map}, zone());
      88          62 :     Node* native_context = LoadNativeContext(context);
      89             : 
      90          31 :     Label map_done(this, vars);
      91          62 :     GotoIf(IsConstructorMap(receiver_map), &with_constructor);
      92             : 
      93             :     bound_function_map.Bind(LoadContextElement(
      94          62 :         native_context, Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX));
      95          31 :     Goto(&map_done);
      96             : 
      97          31 :     BIND(&with_constructor);
      98             :     bound_function_map.Bind(LoadContextElement(
      99          62 :         native_context, Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX));
     100          31 :     Goto(&map_done);
     101             : 
     102          62 :     BIND(&map_done);
     103             :   }
     104             : 
     105             :   // Verify that __proto__ matches that of a the target bound function.
     106          31 :   Comment("Verify that __proto__ matches target bound function");
     107          62 :   Node* prototype = LoadMapPrototype(receiver_map);
     108          93 :   Node* expected_prototype = LoadMapPrototype(bound_function_map.value());
     109          62 :   GotoIf(WordNotEqual(prototype, expected_prototype), &slow);
     110             : 
     111             :   // Allocate the arguments array.
     112          31 :   Comment("Allocate the arguments array");
     113          62 :   VARIABLE(argument_array, MachineRepresentation::kTagged);
     114             :   {
     115             :     Label empty_arguments(this);
     116          31 :     Label arguments_done(this, &argument_array);
     117          93 :     GotoIf(Uint32LessThanOrEqual(argc, Int32Constant(1)), &empty_arguments);
     118             :     Node* elements_length =
     119         124 :         ChangeUint32ToWord(Unsigned(Int32Sub(argc, Int32Constant(1))));
     120             :     Node* elements =
     121             :         AllocateFixedArray(PACKED_ELEMENTS, elements_length, INTPTR_PARAMETERS,
     122          31 :                            kAllowLargeObjectAllocation);
     123          62 :     VARIABLE(index, MachineType::PointerRepresentation());
     124          62 :     index.Bind(IntPtrConstant(0));
     125          31 :     VariableList foreach_vars({&index}, zone());
     126             :     args.ForEach(foreach_vars,
     127          31 :                  [this, elements, &index](Node* arg) {
     128          31 :                    StoreFixedArrayElement(elements, index.value(), arg);
     129          31 :                    Increment(&index);
     130          31 :                  },
     131          93 :                  IntPtrConstant(1));
     132          31 :     argument_array.Bind(elements);
     133          31 :     Goto(&arguments_done);
     134             : 
     135          31 :     BIND(&empty_arguments);
     136          62 :     argument_array.Bind(EmptyFixedArrayConstant());
     137          31 :     Goto(&arguments_done);
     138             : 
     139          62 :     BIND(&arguments_done);
     140             :   }
     141             : 
     142             :   // Determine bound receiver.
     143          31 :   Comment("Determine bound receiver");
     144          62 :   VARIABLE(bound_receiver, MachineRepresentation::kTagged);
     145             :   {
     146             :     Label has_receiver(this);
     147          31 :     Label receiver_done(this, &bound_receiver);
     148          93 :     GotoIf(Word32NotEqual(argc, Int32Constant(0)), &has_receiver);
     149          62 :     bound_receiver.Bind(UndefinedConstant());
     150          31 :     Goto(&receiver_done);
     151             : 
     152          31 :     BIND(&has_receiver);
     153          62 :     bound_receiver.Bind(args.AtIndex(0));
     154          31 :     Goto(&receiver_done);
     155             : 
     156          62 :     BIND(&receiver_done);
     157             :   }
     158             : 
     159             :   // Allocate the resulting bound function.
     160          31 :   Comment("Allocate the resulting bound function");
     161             :   {
     162          31 :     Node* bound_function = Allocate(JSBoundFunction::kSize);
     163          31 :     StoreMapNoWriteBarrier(bound_function, bound_function_map.value());
     164             :     StoreObjectFieldNoWriteBarrier(
     165          31 :         bound_function, JSBoundFunction::kBoundTargetFunctionOffset, receiver);
     166             :     StoreObjectFieldNoWriteBarrier(bound_function,
     167             :                                    JSBoundFunction::kBoundThisOffset,
     168          31 :                                    bound_receiver.value());
     169             :     StoreObjectFieldNoWriteBarrier(bound_function,
     170             :                                    JSBoundFunction::kBoundArgumentsOffset,
     171          31 :                                    argument_array.value());
     172          62 :     Node* empty_fixed_array = EmptyFixedArrayConstant();
     173             :     StoreObjectFieldNoWriteBarrier(
     174          31 :         bound_function, JSObject::kPropertiesOrHashOffset, empty_fixed_array);
     175             :     StoreObjectFieldNoWriteBarrier(bound_function, JSObject::kElementsOffset,
     176          31 :                                    empty_fixed_array);
     177             : 
     178          31 :     args.PopAndReturn(bound_function);
     179             :   }
     180             : 
     181          31 :   BIND(&slow);
     182             :   Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
     183          31 :                                MachineType::TaggedPointer());
     184             :   TailCallStub(CodeFactory::FunctionPrototypeBind(isolate()), context, target,
     185          93 :                new_target, argc);
     186          31 : }
     187             : 
     188             : // ES6 #sec-function.prototype-@@hasinstance
     189          93 : TF_BUILTIN(FunctionPrototypeHasInstance, CodeStubAssembler) {
     190             :   Node* context = Parameter(Descriptor::kContext);
     191             :   Node* f = Parameter(Descriptor::kReceiver);
     192             :   Node* v = Parameter(Descriptor::kV);
     193          31 :   Node* result = OrdinaryHasInstance(context, f, v);
     194          31 :   Return(result);
     195          31 : }
     196             : 
     197             : }  // namespace internal
     198             : }  // namespace v8

Generated by: LCOV version 1.10