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