LCOV - code coverage report
Current view: top level - src/builtins - builtins-arguments-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 169 169 100.0 %
Date: 2017-10-20 Functions: 9 9 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-arguments-gen.h"
       6             : 
       7             : #include "src/builtins/builtins-utils-gen.h"
       8             : #include "src/builtins/builtins.h"
       9             : #include "src/code-factory.h"
      10             : #include "src/code-stub-assembler.h"
      11             : #include "src/frame-constants.h"
      12             : #include "src/interface-descriptors.h"
      13             : #include "src/objects-inl.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : 
      18             : typedef compiler::Node Node;
      19             : 
      20             : std::tuple<Node*, Node*, Node*>
      21          93 : ArgumentsBuiltinsAssembler::GetArgumentsFrameAndCount(Node* function,
      22             :                                                       ParameterMode mode) {
      23             :   CSA_ASSERT(this, HasInstanceType(function, JS_FUNCTION_TYPE));
      24             : 
      25          93 :   VARIABLE(frame_ptr, MachineType::PointerRepresentation());
      26          93 :   frame_ptr.Bind(LoadParentFramePointer());
      27             :   CSA_ASSERT(this,
      28             :              WordEqual(function,
      29             :                        LoadBufferObject(frame_ptr.value(),
      30             :                                         StandardFrameConstants::kFunctionOffset,
      31             :                                         MachineType::Pointer())));
      32         186 :   VARIABLE(argument_count, ParameterRepresentation(mode));
      33          93 :   VariableList list({&frame_ptr, &argument_count}, zone());
      34          93 :   Label done_argument_count(this, list);
      35             : 
      36             :   // Determine the number of passed parameters, which is either the count stored
      37             :   // in an arguments adapter frame or fetched from the shared function info.
      38             :   Node* frame_ptr_above = LoadBufferObject(
      39             :       frame_ptr.value(), StandardFrameConstants::kCallerFPOffset,
      40          93 :       MachineType::Pointer());
      41             :   Node* shared =
      42             :       LoadObjectField(function, JSFunction::kSharedFunctionInfoOffset);
      43             :   CSA_SLOW_ASSERT(this, HasInstanceType(shared, SHARED_FUNCTION_INFO_TYPE));
      44             :   Node* formal_parameter_count =
      45             :       LoadObjectField(shared, SharedFunctionInfo::kFormalParameterCountOffset,
      46          93 :                       MachineType::Int32());
      47          93 :   formal_parameter_count = Word32ToParameter(formal_parameter_count, mode);
      48             : 
      49          93 :   argument_count.Bind(formal_parameter_count);
      50             :   Node* marker_or_function = LoadBufferObject(
      51          93 :       frame_ptr_above, CommonFrameConstants::kContextOrFrameTypeOffset);
      52             :   GotoIf(
      53             :       MarkerIsNotFrameType(marker_or_function, StackFrame::ARGUMENTS_ADAPTOR),
      54         186 :       &done_argument_count);
      55             :   Node* adapted_parameter_count = LoadBufferObject(
      56          93 :       frame_ptr_above, ArgumentsAdaptorFrameConstants::kLengthOffset);
      57          93 :   frame_ptr.Bind(frame_ptr_above);
      58          93 :   argument_count.Bind(TaggedToParameter(adapted_parameter_count, mode));
      59          93 :   Goto(&done_argument_count);
      60             : 
      61          93 :   BIND(&done_argument_count);
      62             :   return std::tuple<Node*, Node*, Node*>(
      63         186 :       frame_ptr.value(), argument_count.value(), formal_parameter_count);
      64             : }
      65             : 
      66             : std::tuple<Node*, Node*, Node*>
      67         217 : ArgumentsBuiltinsAssembler::AllocateArgumentsObject(Node* map,
      68             :                                                     Node* arguments_count,
      69             :                                                     Node* parameter_map_count,
      70             :                                                     ParameterMode mode,
      71             :                                                     int base_size) {
      72             :   // Allocate the parameter object (either a Rest parameter object, a strict
      73             :   // argument object or a sloppy arguments object) and the elements/mapped
      74             :   // arguments together.
      75             :   int elements_offset = base_size;
      76             :   Node* element_count = arguments_count;
      77         217 :   if (parameter_map_count != nullptr) {
      78          31 :     base_size += FixedArray::kHeaderSize;
      79          31 :     element_count = IntPtrOrSmiAdd(element_count, parameter_map_count, mode);
      80             :   }
      81         217 :   bool empty = IsIntPtrOrSmiConstantZero(arguments_count, mode);
      82             :   DCHECK_IMPLIES(empty, parameter_map_count == nullptr);
      83             :   Node* size =
      84          93 :       empty ? IntPtrConstant(base_size)
      85             :             : ElementOffsetFromIndex(element_count, PACKED_ELEMENTS, mode,
      86         434 :                                      base_size + FixedArray::kHeaderSize);
      87         217 :   Node* result = Allocate(size);
      88         217 :   Comment("Initialize arguments object");
      89         217 :   StoreMapNoWriteBarrier(result, map);
      90         434 :   Node* empty_fixed_array = LoadRoot(Heap::kEmptyFixedArrayRootIndex);
      91         217 :   StoreObjectField(result, JSArray::kPropertiesOrHashOffset, empty_fixed_array);
      92             :   Node* smi_arguments_count = ParameterToTagged(arguments_count, mode);
      93             :   StoreObjectFieldNoWriteBarrier(result, JSArray::kLengthOffset,
      94         217 :                                  smi_arguments_count);
      95             :   Node* arguments = nullptr;
      96         217 :   if (!empty) {
      97         124 :     arguments = InnerAllocate(result, elements_offset);
      98             :     StoreObjectFieldNoWriteBarrier(arguments, FixedArray::kLengthOffset,
      99         124 :                                    smi_arguments_count);
     100         248 :     Node* fixed_array_map = LoadRoot(Heap::kFixedArrayMapRootIndex);
     101         124 :     StoreMapNoWriteBarrier(arguments, fixed_array_map);
     102             :   }
     103             :   Node* parameter_map = nullptr;
     104         217 :   if (parameter_map_count != nullptr) {
     105             :     Node* parameter_map_offset = ElementOffsetFromIndex(
     106          31 :         arguments_count, PACKED_ELEMENTS, mode, FixedArray::kHeaderSize);
     107          31 :     parameter_map = InnerAllocate(arguments, parameter_map_offset);
     108             :     StoreObjectFieldNoWriteBarrier(result, JSArray::kElementsOffset,
     109          31 :                                    parameter_map);
     110             :     Node* sloppy_elements_map =
     111          62 :         LoadRoot(Heap::kSloppyArgumentsElementsMapRootIndex);
     112          31 :     StoreMapNoWriteBarrier(parameter_map, sloppy_elements_map);
     113             :     parameter_map_count = ParameterToTagged(parameter_map_count, mode);
     114             :     StoreObjectFieldNoWriteBarrier(parameter_map, FixedArray::kLengthOffset,
     115          31 :                                    parameter_map_count);
     116             :   } else {
     117         186 :     if (empty) {
     118             :       StoreObjectFieldNoWriteBarrier(result, JSArray::kElementsOffset,
     119          93 :                                      empty_fixed_array);
     120             :     } else {
     121             :       StoreObjectFieldNoWriteBarrier(result, JSArray::kElementsOffset,
     122          93 :                                      arguments);
     123             :     }
     124             :   }
     125         217 :   return std::tuple<Node*, Node*, Node*>(result, arguments, parameter_map);
     126             : }
     127             : 
     128          93 : Node* ArgumentsBuiltinsAssembler::ConstructParametersObjectFromArgs(
     129             :     Node* map, Node* frame_ptr, Node* arg_count, Node* first_arg,
     130             :     Node* rest_count, ParameterMode param_mode, int base_size) {
     131             :   // Allocate the parameter object (either a Rest parameter object, a strict
     132             :   // argument object or a sloppy arguments object) and the elements together and
     133             :   // fill in the contents with the arguments above |formal_parameter_count|.
     134             :   Node* result;
     135             :   Node* elements;
     136             :   Node* unused;
     137         186 :   std::tie(result, elements, unused) =
     138             :       AllocateArgumentsObject(map, rest_count, nullptr, param_mode, base_size);
     139             :   DCHECK_NULL(unused);
     140          93 :   CodeStubArguments arguments(this, arg_count, frame_ptr, param_mode);
     141          93 :   VARIABLE(offset, MachineType::PointerRepresentation());
     142         186 :   offset.Bind(IntPtrConstant(FixedArrayBase::kHeaderSize - kHeapObjectTag));
     143          93 :   VariableList list({&offset}, zone());
     144             :   arguments.ForEach(list,
     145          93 :                     [this, elements, &offset](Node* arg) {
     146             :                       StoreNoWriteBarrier(MachineRepresentation::kTagged,
     147          93 :                                           elements, offset.value(), arg);
     148          93 :                       Increment(&offset, kPointerSize);
     149          93 :                     },
     150         186 :                     first_arg, nullptr, param_mode);
     151          93 :   return result;
     152             : }
     153             : 
     154          31 : Node* ArgumentsBuiltinsAssembler::EmitFastNewRestParameter(Node* context,
     155             :                                                            Node* function) {
     156             :   Node* frame_ptr;
     157             :   Node* argument_count;
     158             :   Node* formal_parameter_count;
     159             : 
     160             :   ParameterMode mode = OptimalParameterMode();
     161          31 :   Node* zero = IntPtrOrSmiConstant(0, mode);
     162             : 
     163          62 :   std::tie(frame_ptr, argument_count, formal_parameter_count) =
     164             :       GetArgumentsFrameAndCount(function, mode);
     165             : 
     166          31 :   VARIABLE(result, MachineRepresentation::kTagged);
     167          31 :   Label no_rest_parameters(this), runtime(this, Label::kDeferred),
     168          31 :       done(this, &result);
     169             : 
     170             :   Node* rest_count =
     171          31 :       IntPtrOrSmiSub(argument_count, formal_parameter_count, mode);
     172          62 :   Node* const native_context = LoadNativeContext(context);
     173             :   Node* const array_map =
     174          62 :       LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
     175             :   GotoIf(IntPtrOrSmiLessThanOrEqual(rest_count, zero, mode),
     176          62 :          &no_rest_parameters);
     177             : 
     178             :   GotoIfFixedArraySizeDoesntFitInNewSpace(
     179          31 :       rest_count, &runtime, JSArray::kSize + FixedArray::kHeaderSize, mode);
     180             : 
     181             :   // Allocate the Rest JSArray and the elements together and fill in the
     182             :   // contents with the arguments above |formal_parameter_count|.
     183             :   result.Bind(ConstructParametersObjectFromArgs(
     184             :       array_map, frame_ptr, argument_count, formal_parameter_count, rest_count,
     185          31 :       mode, JSArray::kSize));
     186          31 :   Goto(&done);
     187             : 
     188          31 :   BIND(&no_rest_parameters);
     189             :   {
     190             :     Node* arguments;
     191             :     Node* elements;
     192             :     Node* unused;
     193          62 :     std::tie(arguments, elements, unused) =
     194             :         AllocateArgumentsObject(array_map, zero, nullptr, mode, JSArray::kSize);
     195          31 :     result.Bind(arguments);
     196          31 :     Goto(&done);
     197             :   }
     198             : 
     199          31 :   BIND(&runtime);
     200             :   {
     201          31 :     result.Bind(CallRuntime(Runtime::kNewRestParameter, context, function));
     202          31 :     Goto(&done);
     203             :   }
     204             : 
     205          31 :   BIND(&done);
     206          62 :   return result.value();
     207             : }
     208             : 
     209          31 : Node* ArgumentsBuiltinsAssembler::EmitFastNewStrictArguments(Node* context,
     210             :                                                              Node* function) {
     211          31 :   VARIABLE(result, MachineRepresentation::kTagged);
     212          31 :   Label done(this, &result), empty(this), runtime(this, Label::kDeferred);
     213             : 
     214             :   Node* frame_ptr;
     215             :   Node* argument_count;
     216             :   Node* formal_parameter_count;
     217             : 
     218             :   ParameterMode mode = OptimalParameterMode();
     219          31 :   Node* zero = IntPtrOrSmiConstant(0, mode);
     220             : 
     221          62 :   std::tie(frame_ptr, argument_count, formal_parameter_count) =
     222             :       GetArgumentsFrameAndCount(function, mode);
     223             : 
     224             :   GotoIfFixedArraySizeDoesntFitInNewSpace(
     225             :       argument_count, &runtime,
     226          31 :       JSStrictArgumentsObject::kSize + FixedArray::kHeaderSize, mode);
     227             : 
     228          62 :   Node* const native_context = LoadNativeContext(context);
     229             :   Node* const map =
     230          62 :       LoadContextElement(native_context, Context::STRICT_ARGUMENTS_MAP_INDEX);
     231          62 :   GotoIf(WordEqual(argument_count, zero), &empty);
     232             : 
     233             :   result.Bind(ConstructParametersObjectFromArgs(
     234             :       map, frame_ptr, argument_count, zero, argument_count, mode,
     235          31 :       JSStrictArgumentsObject::kSize));
     236          31 :   Goto(&done);
     237             : 
     238          31 :   BIND(&empty);
     239             :   {
     240             :     Node* arguments;
     241             :     Node* elements;
     242             :     Node* unused;
     243          62 :     std::tie(arguments, elements, unused) = AllocateArgumentsObject(
     244             :         map, zero, nullptr, mode, JSStrictArgumentsObject::kSize);
     245          31 :     result.Bind(arguments);
     246          31 :     Goto(&done);
     247             :   }
     248             : 
     249          31 :   BIND(&runtime);
     250             :   {
     251          31 :     result.Bind(CallRuntime(Runtime::kNewStrictArguments, context, function));
     252          31 :     Goto(&done);
     253             :   }
     254             : 
     255          31 :   BIND(&done);
     256          62 :   return result.value();
     257             : }
     258             : 
     259          31 : Node* ArgumentsBuiltinsAssembler::EmitFastNewSloppyArguments(Node* context,
     260             :                                                              Node* function) {
     261             :   Node* frame_ptr;
     262             :   Node* argument_count;
     263             :   Node* formal_parameter_count;
     264          31 :   VARIABLE(result, MachineRepresentation::kTagged);
     265             : 
     266             :   ParameterMode mode = OptimalParameterMode();
     267          31 :   Node* zero = IntPtrOrSmiConstant(0, mode);
     268             : 
     269          31 :   Label done(this, &result), empty(this), no_parameters(this),
     270          31 :       runtime(this, Label::kDeferred);
     271             : 
     272          62 :   std::tie(frame_ptr, argument_count, formal_parameter_count) =
     273             :       GetArgumentsFrameAndCount(function, mode);
     274             : 
     275          62 :   GotoIf(WordEqual(argument_count, zero), &empty);
     276             : 
     277          62 :   GotoIf(WordEqual(formal_parameter_count, zero), &no_parameters);
     278             : 
     279             :   {
     280          31 :     Comment("Mapped parameter JSSloppyArgumentsObject");
     281             : 
     282             :     Node* mapped_count =
     283          31 :         IntPtrOrSmiMin(argument_count, formal_parameter_count, mode);
     284             : 
     285             :     Node* parameter_map_size =
     286          31 :         IntPtrOrSmiAdd(mapped_count, IntPtrOrSmiConstant(2, mode), mode);
     287             : 
     288             :     // Verify that the overall allocation will fit in new space.
     289             :     Node* elements_allocated =
     290          31 :         IntPtrOrSmiAdd(argument_count, parameter_map_size, mode);
     291             :     GotoIfFixedArraySizeDoesntFitInNewSpace(
     292             :         elements_allocated, &runtime,
     293          31 :         JSSloppyArgumentsObject::kSize + FixedArray::kHeaderSize * 2, mode);
     294             : 
     295          62 :     Node* const native_context = LoadNativeContext(context);
     296             :     Node* const map = LoadContextElement(
     297          62 :         native_context, Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX);
     298             :     Node* argument_object;
     299             :     Node* elements;
     300             :     Node* map_array;
     301          62 :     std::tie(argument_object, elements, map_array) =
     302             :         AllocateArgumentsObject(map, argument_count, parameter_map_size, mode,
     303             :                                 JSSloppyArgumentsObject::kSize);
     304             :     StoreObjectFieldNoWriteBarrier(
     305          31 :         argument_object, JSSloppyArgumentsObject::kCalleeOffset, function);
     306          31 :     StoreFixedArrayElement(map_array, 0, context, SKIP_WRITE_BARRIER);
     307          31 :     StoreFixedArrayElement(map_array, 1, elements, SKIP_WRITE_BARRIER);
     308             : 
     309          31 :     Comment("Fill in non-mapped parameters");
     310             :     Node* argument_offset =
     311             :         ElementOffsetFromIndex(argument_count, PACKED_ELEMENTS, mode,
     312          31 :                                FixedArray::kHeaderSize - kHeapObjectTag);
     313             :     Node* mapped_offset =
     314             :         ElementOffsetFromIndex(mapped_count, PACKED_ELEMENTS, mode,
     315          31 :                                FixedArray::kHeaderSize - kHeapObjectTag);
     316          31 :     CodeStubArguments arguments(this, argument_count, frame_ptr, mode);
     317          31 :     VARIABLE(current_argument, MachineType::PointerRepresentation());
     318          62 :     current_argument.Bind(arguments.AtIndexPtr(argument_count, mode));
     319          31 :     VariableList var_list1({&current_argument}, zone());
     320             :     mapped_offset = BuildFastLoop(
     321             :         var_list1, argument_offset, mapped_offset,
     322          31 :         [this, elements, &current_argument](Node* offset) {
     323          31 :           Increment(&current_argument, kPointerSize);
     324          31 :           Node* arg = LoadBufferObject(current_argument.value(), 0);
     325             :           StoreNoWriteBarrier(MachineRepresentation::kTagged, elements, offset,
     326          31 :                               arg);
     327          31 :         },
     328          62 :         -kPointerSize, INTPTR_PARAMETERS);
     329             : 
     330             :     // Copy the parameter slots and the holes in the arguments.
     331             :     // We need to fill in mapped_count slots. They index the context,
     332             :     // where parameters are stored in reverse order, at
     333             :     //   MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+argument_count-1
     334             :     // The mapped parameter thus need to get indices
     335             :     //   MIN_CONTEXT_SLOTS+parameter_count-1 ..
     336             :     //       MIN_CONTEXT_SLOTS+argument_count-mapped_count
     337             :     // We loop from right to left.
     338          31 :     Comment("Fill in mapped parameters");
     339          62 :     VARIABLE(context_index, OptimalParameterRepresentation());
     340             :     context_index.Bind(IntPtrOrSmiSub(
     341             :         IntPtrOrSmiAdd(IntPtrOrSmiConstant(Context::MIN_CONTEXT_SLOTS, mode),
     342             :                        formal_parameter_count, mode),
     343          31 :         mapped_count, mode));
     344          62 :     Node* the_hole = TheHoleConstant();
     345          31 :     VariableList var_list2({&context_index}, zone());
     346             :     const int kParameterMapHeaderSize =
     347             :         FixedArray::kHeaderSize + 2 * kPointerSize;
     348             :     Node* adjusted_map_array = IntPtrAdd(
     349             :         BitcastTaggedToWord(map_array),
     350          93 :         IntPtrConstant(kParameterMapHeaderSize - FixedArray::kHeaderSize));
     351             :     Node* zero_offset = ElementOffsetFromIndex(
     352          31 :         zero, PACKED_ELEMENTS, mode, FixedArray::kHeaderSize - kHeapObjectTag);
     353             :     BuildFastLoop(var_list2, mapped_offset, zero_offset,
     354             :                   [this, the_hole, elements, adjusted_map_array, &context_index,
     355          31 :                    mode](Node* offset) {
     356             :                     StoreNoWriteBarrier(MachineRepresentation::kTagged,
     357          31 :                                         elements, offset, the_hole);
     358             :                     StoreNoWriteBarrier(
     359             :                         MachineRepresentation::kTagged, adjusted_map_array,
     360          62 :                         offset, ParameterToTagged(context_index.value(), mode));
     361          31 :                     Increment(&context_index, 1, mode);
     362          31 :                   },
     363          62 :                   -kPointerSize, INTPTR_PARAMETERS);
     364             : 
     365          31 :     result.Bind(argument_object);
     366          62 :     Goto(&done);
     367             :   }
     368             : 
     369          31 :   BIND(&no_parameters);
     370             :   {
     371          31 :     Comment("No parameters JSSloppyArgumentsObject");
     372             :     GotoIfFixedArraySizeDoesntFitInNewSpace(
     373             :         argument_count, &runtime,
     374          31 :         JSSloppyArgumentsObject::kSize + FixedArray::kHeaderSize, mode);
     375          62 :     Node* const native_context = LoadNativeContext(context);
     376             :     Node* const map =
     377          62 :         LoadContextElement(native_context, Context::SLOPPY_ARGUMENTS_MAP_INDEX);
     378             :     result.Bind(ConstructParametersObjectFromArgs(
     379             :         map, frame_ptr, argument_count, zero, argument_count, mode,
     380          31 :         JSSloppyArgumentsObject::kSize));
     381             :     StoreObjectFieldNoWriteBarrier(
     382          31 :         result.value(), JSSloppyArgumentsObject::kCalleeOffset, function);
     383          31 :     Goto(&done);
     384             :   }
     385             : 
     386          31 :   BIND(&empty);
     387             :   {
     388          31 :     Comment("Empty JSSloppyArgumentsObject");
     389          62 :     Node* const native_context = LoadNativeContext(context);
     390             :     Node* const map =
     391          62 :         LoadContextElement(native_context, Context::SLOPPY_ARGUMENTS_MAP_INDEX);
     392             :     Node* arguments;
     393             :     Node* elements;
     394             :     Node* unused;
     395          62 :     std::tie(arguments, elements, unused) = AllocateArgumentsObject(
     396             :         map, zero, nullptr, mode, JSSloppyArgumentsObject::kSize);
     397          31 :     result.Bind(arguments);
     398             :     StoreObjectFieldNoWriteBarrier(
     399          31 :         result.value(), JSSloppyArgumentsObject::kCalleeOffset, function);
     400          31 :     Goto(&done);
     401             :   }
     402             : 
     403          31 :   BIND(&runtime);
     404             :   {
     405          31 :     result.Bind(CallRuntime(Runtime::kNewSloppyArguments, context, function));
     406          31 :     Goto(&done);
     407             :   }
     408             : 
     409          31 :   BIND(&done);
     410          62 :   return result.value();
     411             : }
     412             : 
     413             : }  // namespace internal
     414             : }  // namespace v8

Generated by: LCOV version 1.10