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

Generated by: LCOV version 1.10