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

Generated by: LCOV version 1.10