LCOV - code coverage report
Current view: top level - src/builtins - builtins-call-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 171 171 100.0 %
Date: 2017-10-20 Functions: 17 17 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-call-gen.h"
       6             : 
       7             : #include "src/builtins/builtins-utils-gen.h"
       8             : #include "src/builtins/builtins.h"
       9             : #include "src/globals.h"
      10             : #include "src/heap/heap-inl.h"
      11             : #include "src/isolate.h"
      12             : #include "src/macro-assembler.h"
      13             : #include "src/objects/arguments.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : 
      18          31 : void Builtins::Generate_CallFunction_ReceiverIsNullOrUndefined(
      19             :     MacroAssembler* masm) {
      20          31 :   Generate_CallFunction(masm, ConvertReceiverMode::kNullOrUndefined);
      21          31 : }
      22             : 
      23          31 : void Builtins::Generate_CallFunction_ReceiverIsNotNullOrUndefined(
      24             :     MacroAssembler* masm) {
      25          31 :   Generate_CallFunction(masm, ConvertReceiverMode::kNotNullOrUndefined);
      26          31 : }
      27             : 
      28          31 : void Builtins::Generate_CallFunction_ReceiverIsAny(MacroAssembler* masm) {
      29          31 :   Generate_CallFunction(masm, ConvertReceiverMode::kAny);
      30          31 : }
      31             : 
      32          31 : void Builtins::Generate_CallBoundFunction(MacroAssembler* masm) {
      33          31 :   Generate_CallBoundFunctionImpl(masm);
      34          31 : }
      35             : 
      36          31 : void Builtins::Generate_Call_ReceiverIsNullOrUndefined(MacroAssembler* masm) {
      37          31 :   Generate_Call(masm, ConvertReceiverMode::kNullOrUndefined);
      38          31 : }
      39             : 
      40          31 : void Builtins::Generate_Call_ReceiverIsNotNullOrUndefined(
      41             :     MacroAssembler* masm) {
      42          31 :   Generate_Call(masm, ConvertReceiverMode::kNotNullOrUndefined);
      43          31 : }
      44             : 
      45          31 : void Builtins::Generate_Call_ReceiverIsAny(MacroAssembler* masm) {
      46          31 :   Generate_Call(masm, ConvertReceiverMode::kAny);
      47          31 : }
      48             : 
      49          31 : void Builtins::Generate_CallVarargs(MacroAssembler* masm) {
      50          31 :   Generate_CallOrConstructVarargs(masm, masm->isolate()->builtins()->Call());
      51          31 : }
      52             : 
      53          31 : void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm) {
      54             :   Generate_CallOrConstructForwardVarargs(masm, CallOrConstructMode::kCall,
      55          31 :                                          masm->isolate()->builtins()->Call());
      56          31 : }
      57             : 
      58          31 : void Builtins::Generate_CallFunctionForwardVarargs(MacroAssembler* masm) {
      59             :   Generate_CallOrConstructForwardVarargs(
      60             :       masm, CallOrConstructMode::kCall,
      61          31 :       masm->isolate()->builtins()->CallFunction());
      62          31 : }
      63             : 
      64          62 : void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike(
      65             :     Node* target, Node* new_target, Node* arguments_list, Node* context) {
      66          62 :   VARIABLE(var_elements, MachineRepresentation::kTagged);
      67         124 :   VARIABLE(var_length, MachineRepresentation::kWord32);
      68          62 :   Label if_done(this), if_arguments(this), if_array(this),
      69          62 :       if_holey_array(this, Label::kDeferred),
      70          62 :       if_runtime(this, Label::kDeferred);
      71             : 
      72             :   // Perform appropriate checks on {target} (and {new_target} first).
      73          62 :   if (new_target == nullptr) {
      74             :     // Check that {target} is Callable.
      75             :     Label if_target_callable(this),
      76          31 :         if_target_not_callable(this, Label::kDeferred);
      77          62 :     GotoIf(TaggedIsSmi(target), &if_target_not_callable);
      78          62 :     Branch(IsCallable(target), &if_target_callable, &if_target_not_callable);
      79          31 :     BIND(&if_target_not_callable);
      80             :     {
      81             :       CallRuntime(Runtime::kThrowApplyNonFunction, context, target);
      82          31 :       Unreachable();
      83             :     }
      84          62 :     BIND(&if_target_callable);
      85             :   } else {
      86             :     // Check that {target} is a Constructor.
      87             :     Label if_target_constructor(this),
      88          31 :         if_target_not_constructor(this, Label::kDeferred);
      89          62 :     GotoIf(TaggedIsSmi(target), &if_target_not_constructor);
      90             :     Branch(IsConstructor(target), &if_target_constructor,
      91          62 :            &if_target_not_constructor);
      92          31 :     BIND(&if_target_not_constructor);
      93             :     {
      94             :       CallRuntime(Runtime::kThrowNotConstructor, context, target);
      95          31 :       Unreachable();
      96             :     }
      97          31 :     BIND(&if_target_constructor);
      98             : 
      99             :     // Check that {new_target} is a Constructor.
     100          31 :     Label if_new_target_constructor(this),
     101          31 :         if_new_target_not_constructor(this, Label::kDeferred);
     102          62 :     GotoIf(TaggedIsSmi(new_target), &if_new_target_not_constructor);
     103             :     Branch(IsConstructor(new_target), &if_new_target_constructor,
     104          62 :            &if_new_target_not_constructor);
     105          31 :     BIND(&if_new_target_not_constructor);
     106             :     {
     107             :       CallRuntime(Runtime::kThrowNotConstructor, context, new_target);
     108          31 :       Unreachable();
     109             :     }
     110          62 :     BIND(&if_new_target_constructor);
     111             :   }
     112             : 
     113         124 :   GotoIf(TaggedIsSmi(arguments_list), &if_runtime);
     114         124 :   Node* arguments_list_map = LoadMap(arguments_list);
     115         124 :   Node* native_context = LoadNativeContext(context);
     116             : 
     117             :   // Check if {arguments_list} is an (unmodified) arguments object.
     118             :   Node* sloppy_arguments_map =
     119         124 :       LoadContextElement(native_context, Context::SLOPPY_ARGUMENTS_MAP_INDEX);
     120         124 :   GotoIf(WordEqual(arguments_list_map, sloppy_arguments_map), &if_arguments);
     121             :   Node* strict_arguments_map =
     122         124 :       LoadContextElement(native_context, Context::STRICT_ARGUMENTS_MAP_INDEX);
     123         124 :   GotoIf(WordEqual(arguments_list_map, strict_arguments_map), &if_arguments);
     124             : 
     125             :   // Check if {arguments_list} is a fast JSArray.
     126         124 :   Branch(IsJSArrayMap(arguments_list_map), &if_array, &if_runtime);
     127             : 
     128          62 :   BIND(&if_array);
     129             :   {
     130             :     // Try to extract the elements from a JSArray object.
     131             :     var_elements.Bind(
     132          62 :         LoadObjectField(arguments_list, JSArray::kElementsOffset));
     133             :     var_length.Bind(LoadAndUntagToWord32ObjectField(arguments_list,
     134         124 :                                                     JSArray::kLengthOffset));
     135             : 
     136             :     // Holey arrays and double backing stores need special treatment.
     137             :     STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
     138             :     STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
     139             :     STATIC_ASSERT(PACKED_ELEMENTS == 2);
     140             :     STATIC_ASSERT(HOLEY_ELEMENTS == 3);
     141             :     STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4);
     142             :     STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5);
     143             :     STATIC_ASSERT(LAST_FAST_ELEMENTS_KIND == HOLEY_DOUBLE_ELEMENTS);
     144             : 
     145         124 :     Node* kind = LoadMapElementsKind(arguments_list_map);
     146             : 
     147         124 :     GotoIf(Int32GreaterThan(kind, Int32Constant(LAST_FAST_ELEMENTS_KIND)),
     148         124 :            &if_runtime);
     149         186 :     Branch(Word32And(kind, Int32Constant(1)), &if_holey_array, &if_done);
     150             :   }
     151             : 
     152          62 :   BIND(&if_holey_array);
     153             :   {
     154             :     // For holey JSArrays we need to check that the array prototype chain
     155             :     // protector is intact and our prototype is the Array.prototype actually.
     156             :     GotoIfNot(IsPrototypeInitialArrayPrototype(context, arguments_list_map),
     157         124 :               &if_runtime);
     158         124 :     Branch(IsArrayProtectorCellInvalid(), &if_runtime, &if_done);
     159             :   }
     160             : 
     161          62 :   BIND(&if_arguments);
     162             :   {
     163             :     // Try to extract the elements from an JSArgumentsObject.
     164             :     Node* length =
     165             :         LoadObjectField(arguments_list, JSArgumentsObject::kLengthOffset);
     166             :     Node* elements =
     167             :         LoadObjectField(arguments_list, JSArgumentsObject::kElementsOffset);
     168         124 :     Node* elements_length = LoadFixedArrayBaseLength(elements);
     169         124 :     GotoIfNot(WordEqual(length, elements_length), &if_runtime);
     170          62 :     var_elements.Bind(elements);
     171         124 :     var_length.Bind(SmiToWord32(length));
     172          62 :     Goto(&if_done);
     173             :   }
     174             : 
     175          62 :   BIND(&if_runtime);
     176             :   {
     177             :     // Ask the runtime to create the list (actually a FixedArray).
     178             :     Node* elements =
     179             :         CallRuntime(Runtime::kCreateListFromArrayLike, context, arguments_list);
     180          62 :     var_elements.Bind(elements);
     181             :     var_length.Bind(
     182         124 :         LoadAndUntagToWord32ObjectField(elements, FixedArray::kLengthOffset));
     183          62 :     Goto(&if_done);
     184             :   }
     185             : 
     186             :   // Tail call to the appropriate builtin (depending on whether we have
     187             :   // a {new_target} passed).
     188          62 :   BIND(&if_done);
     189             :   {
     190          62 :     Label if_not_double(this), if_double(this);
     191          62 :     Node* elements = var_elements.value();
     192          62 :     Node* length = var_length.value();
     193         124 :     Node* args_count = Int32Constant(0);  // args already on the stack
     194             : 
     195         124 :     Branch(IsFixedDoubleArray(elements), &if_double, &if_not_double);
     196             : 
     197          62 :     BIND(&if_not_double);
     198          62 :     if (new_target == nullptr) {
     199          31 :       Callable callable = CodeFactory::CallVarargs(isolate());
     200          31 :       TailCallStub(callable, context, target, args_count, elements, length);
     201             :     } else {
     202          31 :       Callable callable = CodeFactory::ConstructVarargs(isolate());
     203             :       TailCallStub(callable, context, target, new_target, args_count, elements,
     204          31 :                    length);
     205             :     }
     206             : 
     207          62 :     BIND(&if_double);
     208             :     {
     209             :       // Kind is hardcoded here because CreateListFromArrayLike will only
     210             :       // produce holey double arrays.
     211             :       CallOrConstructDoubleVarargs(target, new_target, elements, length,
     212             :                                    args_count, context,
     213         124 :                                    Int32Constant(HOLEY_DOUBLE_ELEMENTS));
     214          62 :     }
     215          62 :   }
     216          62 : }
     217             : 
     218             : // Takes a FixedArray of doubles and creates a new FixedArray with those doubles
     219             : // boxed as HeapNumbers, then tail calls CallVarargs/ConstructVarargs depending
     220             : // on whether {new_target} was passed.
     221         124 : void CallOrConstructBuiltinsAssembler::CallOrConstructDoubleVarargs(
     222             :     Node* target, Node* new_target, Node* elements, Node* length,
     223             :     Node* args_count, Node* context, Node* kind) {
     224         248 :   Label if_holey_double(this), if_packed_double(this), if_done(this);
     225             : 
     226             :   const ElementsKind new_kind = PACKED_ELEMENTS;
     227             :   const ParameterMode mode = INTPTR_PARAMETERS;
     228             :   const WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER;
     229         248 :   Node* intptr_length = ChangeInt32ToIntPtr(length);
     230             : 
     231             :   // Allocate a new FixedArray of Objects.
     232             :   Node* new_elements =
     233             :       AllocateFixedArray(new_kind, intptr_length, mode,
     234         124 :                          CodeStubAssembler::kAllowLargeObjectAllocation);
     235         248 :   Branch(Word32Equal(kind, Int32Constant(HOLEY_DOUBLE_ELEMENTS)),
     236         248 :          &if_holey_double, &if_packed_double);
     237             : 
     238         124 :   BIND(&if_holey_double);
     239             :   {
     240             :     // Fill the FixedArray with pointers to HeapObjects.
     241             :     CopyFixedArrayElements(HOLEY_DOUBLE_ELEMENTS, elements, new_kind,
     242             :                            new_elements, intptr_length, intptr_length,
     243         124 :                            barrier_mode);
     244         124 :     Goto(&if_done);
     245             :   }
     246             : 
     247         124 :   BIND(&if_packed_double);
     248             :   {
     249             :     CopyFixedArrayElements(PACKED_DOUBLE_ELEMENTS, elements, new_kind,
     250             :                            new_elements, intptr_length, intptr_length,
     251         124 :                            barrier_mode);
     252         124 :     Goto(&if_done);
     253             :   }
     254             : 
     255         124 :   BIND(&if_done);
     256             :   {
     257         124 :     if (new_target == nullptr) {
     258          62 :       Callable callable = CodeFactory::CallVarargs(isolate());
     259          62 :       TailCallStub(callable, context, target, args_count, new_elements, length);
     260             :     } else {
     261          62 :       Callable callable = CodeFactory::ConstructVarargs(isolate());
     262             :       TailCallStub(callable, context, target, new_target, args_count,
     263          62 :                    new_elements, length);
     264             :     }
     265         124 :   }
     266         124 : }
     267             : 
     268          62 : void CallOrConstructBuiltinsAssembler::CallOrConstructWithSpread(
     269             :     Node* target, Node* new_target, Node* spread, Node* args_count,
     270             :     Node* context) {
     271         124 :   Label if_done(this), if_holey(this), if_runtime(this, Label::kDeferred);
     272             : 
     273         124 :   VARIABLE(spread_result, MachineRepresentation::kTagged, spread);
     274             : 
     275         124 :   GotoIf(TaggedIsSmi(spread), &if_runtime);
     276         124 :   Node* spread_map = LoadMap(spread);
     277         124 :   GotoIfNot(IsJSArrayMap(spread_map), &if_runtime);
     278             : 
     279             :   // Check that we have the original ArrayPrototype.
     280         124 :   GotoIfNot(IsPrototypeInitialArrayPrototype(context, spread_map), &if_runtime);
     281             : 
     282             :   // Check that the ArrayPrototype hasn't been modified in a way that would
     283             :   // affect iteration.
     284         124 :   Node* protector_cell = LoadRoot(Heap::kArrayIteratorProtectorRootIndex);
     285             :   DCHECK(isolate()->heap()->array_iterator_protector()->IsPropertyCell());
     286             :   GotoIfNot(
     287             :       WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
     288          62 :                 SmiConstant(Isolate::kProtectorValid)),
     289          62 :       &if_runtime);
     290             : 
     291             :   // Check that the map of the initial array iterator hasn't changed.
     292         124 :   Node* native_context = LoadNativeContext(context);
     293         124 :   Node* arr_it_proto_map = LoadMap(CAST(LoadContextElement(
     294         124 :       native_context, Context::INITIAL_ARRAY_ITERATOR_PROTOTYPE_INDEX)));
     295             :   Node* initial_map = LoadContextElement(
     296         124 :       native_context, Context::INITIAL_ARRAY_ITERATOR_PROTOTYPE_MAP_INDEX);
     297         124 :   GotoIfNot(WordEqual(arr_it_proto_map, initial_map), &if_runtime);
     298             : 
     299         124 :   Node* kind = LoadMapElementsKind(spread_map);
     300             : 
     301             :   STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
     302             :   STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
     303             :   STATIC_ASSERT(PACKED_ELEMENTS == 2);
     304             :   STATIC_ASSERT(HOLEY_ELEMENTS == 3);
     305             :   STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4);
     306             :   STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5);
     307             :   STATIC_ASSERT(LAST_FAST_ELEMENTS_KIND == HOLEY_DOUBLE_ELEMENTS);
     308             : 
     309         124 :   GotoIf(Int32GreaterThan(kind, Int32Constant(LAST_FAST_ELEMENTS_KIND)),
     310         124 :          &if_runtime);
     311         186 :   Branch(Word32And(kind, Int32Constant(1)), &if_holey, &if_done);
     312             : 
     313             :   // Check the ArrayProtector cell for holey arrays.
     314          62 :   BIND(&if_holey);
     315         124 :   { Branch(IsArrayProtectorCellInvalid(), &if_runtime, &if_done); }
     316             : 
     317          62 :   BIND(&if_runtime);
     318             :   {
     319          62 :     Node* spread_iterable = LoadContextElement(LoadNativeContext(context),
     320         186 :                                                Context::SPREAD_ITERABLE_INDEX);
     321             :     spread_result.Bind(CallJS(CodeFactory::Call(isolate()), context,
     322         186 :                               spread_iterable, UndefinedConstant(), spread));
     323             :     CSA_ASSERT(this, IsJSArray(spread_result.value()));
     324          62 :     Goto(&if_done);
     325             :   }
     326             : 
     327          62 :   BIND(&if_done);
     328             :   {
     329             :     // The result from if_runtime can be an array of doubles.
     330          62 :     Label if_not_double(this), if_double(this);
     331             :     Node* elements =
     332          62 :         LoadObjectField(spread_result.value(), JSArray::kElementsOffset);
     333             :     Node* length = LoadAndUntagToWord32ObjectField(spread_result.value(),
     334         124 :                                                    JSArray::kLengthOffset);
     335             : 
     336         186 :     Node* kind = LoadMapElementsKind(LoadMap(elements));
     337             :     CSA_ASSERT(this, Int32LessThanOrEqual(
     338             :                          kind, Int32Constant(LAST_FAST_ELEMENTS_KIND)));
     339             : 
     340         124 :     Branch(Int32GreaterThan(kind, Int32Constant(HOLEY_ELEMENTS)), &if_double,
     341          62 :            &if_not_double);
     342             : 
     343          62 :     BIND(&if_not_double);
     344             :     {
     345          62 :       if (new_target == nullptr) {
     346          31 :         Callable callable = CodeFactory::CallVarargs(isolate());
     347          31 :         TailCallStub(callable, context, target, args_count, elements, length);
     348             :       } else {
     349          31 :         Callable callable = CodeFactory::ConstructVarargs(isolate());
     350             :         TailCallStub(callable, context, target, new_target, args_count,
     351          31 :                      elements, length);
     352             :       }
     353             :     }
     354             : 
     355          62 :     BIND(&if_double);
     356             :     {
     357             :       CallOrConstructDoubleVarargs(target, new_target, elements, length,
     358          62 :                                    args_count, context, kind);
     359          62 :     }
     360          62 :   }
     361          62 : }
     362             : 
     363         124 : TF_BUILTIN(CallWithArrayLike, CallOrConstructBuiltinsAssembler) {
     364             :   Node* target = Parameter(CallWithArrayLikeDescriptor::kTarget);
     365             :   Node* new_target = nullptr;
     366             :   Node* arguments_list = Parameter(CallWithArrayLikeDescriptor::kArgumentsList);
     367             :   Node* context = Parameter(CallWithArrayLikeDescriptor::kContext);
     368          31 :   CallOrConstructWithArrayLike(target, new_target, arguments_list, context);
     369          31 : }
     370             : 
     371         124 : TF_BUILTIN(CallWithSpread, CallOrConstructBuiltinsAssembler) {
     372             :   Node* target = Parameter(CallWithSpreadDescriptor::kTarget);
     373             :   Node* new_target = nullptr;
     374             :   Node* spread = Parameter(CallWithSpreadDescriptor::kSpread);
     375             :   Node* args_count = Parameter(CallWithSpreadDescriptor::kArgumentsCount);
     376             :   Node* context = Parameter(CallWithSpreadDescriptor::kContext);
     377          31 :   CallOrConstructWithSpread(target, new_target, spread, args_count, context);
     378          31 : }
     379             : 
     380             : }  // namespace internal
     381             : }  // namespace v8

Generated by: LCOV version 1.10