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

Generated by: LCOV version 1.10