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/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 392 : ArgumentsBuiltinsAssembler::AllocateArgumentsObject(Node* map,
24 : Node* arguments_count,
25 : Node* parameter_map_count,
26 : ParameterMode mode,
27 : int base_size) {
28 : // Allocate the parameter object (either a Rest parameter object, a strict
29 : // argument object or a sloppy arguments object) and the elements/mapped
30 : // arguments together.
31 392 : int elements_offset = base_size;
32 392 : Node* element_count = arguments_count;
33 392 : if (parameter_map_count != nullptr) {
34 56 : base_size += FixedArray::kHeaderSize;
35 56 : element_count = IntPtrOrSmiAdd(element_count, parameter_map_count, mode);
36 : }
37 392 : bool empty = IsIntPtrOrSmiConstantZero(arguments_count, mode);
38 : DCHECK_IMPLIES(empty, parameter_map_count == nullptr);
39 : TNode<IntPtrT> size =
40 168 : empty ? IntPtrConstant(base_size)
41 : : ElementOffsetFromIndex(element_count, PACKED_ELEMENTS, mode,
42 560 : base_size + FixedArray::kHeaderSize);
43 392 : TNode<Object> result = Allocate(size);
44 392 : Comment("Initialize arguments object");
45 392 : StoreMapNoWriteBarrier(result, map);
46 392 : Node* empty_fixed_array = LoadRoot(RootIndex::kEmptyFixedArray);
47 392 : StoreObjectField(result, JSArray::kPropertiesOrHashOffset, empty_fixed_array);
48 392 : Node* smi_arguments_count = ParameterToTagged(arguments_count, mode);
49 392 : StoreObjectFieldNoWriteBarrier(result, JSArray::kLengthOffset,
50 392 : smi_arguments_count);
51 392 : Node* arguments = nullptr;
52 392 : if (!empty) {
53 224 : arguments = InnerAllocate(CAST(result), elements_offset);
54 224 : StoreObjectFieldNoWriteBarrier(arguments, FixedArray::kLengthOffset,
55 448 : smi_arguments_count);
56 224 : Node* fixed_array_map = LoadRoot(RootIndex::kFixedArrayMap);
57 224 : StoreMapNoWriteBarrier(arguments, fixed_array_map);
58 : }
59 392 : Node* parameter_map = nullptr;
60 392 : if (parameter_map_count != nullptr) {
61 : TNode<IntPtrT> parameter_map_offset = ElementOffsetFromIndex(
62 56 : arguments_count, PACKED_ELEMENTS, mode, FixedArray::kHeaderSize);
63 56 : parameter_map = InnerAllocate(CAST(arguments), parameter_map_offset);
64 56 : StoreObjectFieldNoWriteBarrier(result, JSArray::kElementsOffset,
65 112 : parameter_map);
66 : Node* sloppy_elements_map =
67 56 : LoadRoot(RootIndex::kSloppyArgumentsElementsMap);
68 56 : StoreMapNoWriteBarrier(parameter_map, sloppy_elements_map);
69 56 : parameter_map_count = ParameterToTagged(parameter_map_count, mode);
70 56 : StoreObjectFieldNoWriteBarrier(parameter_map, FixedArray::kLengthOffset,
71 112 : parameter_map_count);
72 : } else {
73 336 : if (empty) {
74 168 : StoreObjectFieldNoWriteBarrier(result, JSArray::kElementsOffset,
75 168 : empty_fixed_array);
76 : } else {
77 168 : StoreObjectFieldNoWriteBarrier(result, JSArray::kElementsOffset,
78 336 : arguments);
79 : }
80 : }
81 392 : return std::tuple<Node*, Node*, Node*>(result, arguments, parameter_map);
82 : }
83 :
84 168 : Node* ArgumentsBuiltinsAssembler::ConstructParametersObjectFromArgs(
85 : Node* map, Node* frame_ptr, Node* arg_count, Node* first_arg,
86 : Node* rest_count, ParameterMode param_mode, int base_size) {
87 : // Allocate the parameter object (either a Rest parameter object, a strict
88 : // argument object or a sloppy arguments object) and the elements together and
89 : // fill in the contents with the arguments above |formal_parameter_count|.
90 : Node* result;
91 : Node* elements;
92 : Node* unused;
93 336 : std::tie(result, elements, unused) =
94 504 : AllocateArgumentsObject(map, rest_count, nullptr, param_mode, base_size);
95 : DCHECK_NULL(unused);
96 168 : CodeStubArguments arguments(this, arg_count, frame_ptr, param_mode);
97 336 : VARIABLE(offset, MachineType::PointerRepresentation());
98 168 : offset.Bind(IntPtrConstant(FixedArrayBase::kHeaderSize - kHeapObjectTag));
99 336 : VariableList list({&offset}, zone());
100 336 : arguments.ForEach(list,
101 504 : [this, elements, &offset](Node* arg) {
102 336 : StoreNoWriteBarrier(MachineRepresentation::kTagged,
103 168 : elements, offset.value(), arg);
104 168 : Increment(&offset, kTaggedSize);
105 168 : },
106 168 : first_arg, nullptr, param_mode);
107 336 : return result;
108 : }
109 :
110 56 : Node* ArgumentsBuiltinsAssembler::EmitFastNewRestParameter(Node* context,
111 : Node* function) {
112 56 : ParameterMode mode = OptimalParameterMode();
113 56 : Node* zero = IntPtrOrSmiConstant(0, mode);
114 :
115 : ArgumentsBuiltinsFromDSLAssembler::ArgumentsInfo info =
116 112 : GetArgumentsFrameAndCount(CAST(context),
117 112 : UncheckedCast<JSFunction>(function));
118 :
119 112 : VARIABLE(result, MachineRepresentation::kTagged);
120 112 : Label no_rest_parameters(this), runtime(this, Label::kDeferred),
121 112 : done(this, &result);
122 :
123 : Node* rest_count =
124 56 : IntPtrOrSmiSub(info.argument_count, info.formal_parameter_count, mode);
125 56 : Node* const native_context = LoadNativeContext(context);
126 : Node* const array_map =
127 56 : LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
128 112 : GotoIf(IntPtrOrSmiLessThanOrEqual(rest_count, zero, mode),
129 56 : &no_rest_parameters);
130 :
131 56 : GotoIfFixedArraySizeDoesntFitInNewSpace(
132 56 : rest_count, &runtime, JSArray::kSize + FixedArray::kHeaderSize, mode);
133 :
134 : // Allocate the Rest JSArray and the elements together and fill in the
135 : // contents with the arguments above |formal_parameter_count|.
136 56 : result.Bind(ConstructParametersObjectFromArgs(
137 : array_map, info.frame, info.argument_count, info.formal_parameter_count,
138 56 : rest_count, mode, JSArray::kSize));
139 56 : Goto(&done);
140 :
141 56 : BIND(&no_rest_parameters);
142 : {
143 : Node* arguments;
144 : Node* elements;
145 : Node* unused;
146 112 : std::tie(arguments, elements, unused) =
147 168 : AllocateArgumentsObject(array_map, zero, nullptr, mode, JSArray::kSize);
148 56 : result.Bind(arguments);
149 56 : Goto(&done);
150 : }
151 :
152 56 : BIND(&runtime);
153 : {
154 56 : result.Bind(CallRuntime(Runtime::kNewRestParameter, context, function));
155 56 : Goto(&done);
156 : }
157 :
158 56 : BIND(&done);
159 112 : return result.value();
160 : }
161 :
162 56 : Node* ArgumentsBuiltinsAssembler::EmitFastNewStrictArguments(Node* context,
163 : Node* function) {
164 112 : VARIABLE(result, MachineRepresentation::kTagged);
165 112 : Label done(this, &result), empty(this), runtime(this, Label::kDeferred);
166 :
167 56 : ParameterMode mode = OptimalParameterMode();
168 56 : Node* zero = IntPtrOrSmiConstant(0, mode);
169 :
170 : ArgumentsBuiltinsFromDSLAssembler::ArgumentsInfo info =
171 112 : GetArgumentsFrameAndCount(CAST(context),
172 112 : UncheckedCast<JSFunction>(function));
173 :
174 56 : GotoIfFixedArraySizeDoesntFitInNewSpace(
175 : info.argument_count, &runtime,
176 56 : JSStrictArgumentsObject::kSize + FixedArray::kHeaderSize, mode);
177 :
178 56 : Node* const native_context = LoadNativeContext(context);
179 : Node* const map =
180 56 : LoadContextElement(native_context, Context::STRICT_ARGUMENTS_MAP_INDEX);
181 56 : GotoIf(WordEqual(info.argument_count, zero), &empty);
182 :
183 56 : result.Bind(ConstructParametersObjectFromArgs(
184 : map, info.frame, info.argument_count, zero, info.argument_count, mode,
185 56 : JSStrictArgumentsObject::kSize));
186 56 : Goto(&done);
187 :
188 56 : BIND(&empty);
189 : {
190 : Node* arguments;
191 : Node* elements;
192 : Node* unused;
193 112 : std::tie(arguments, elements, unused) = AllocateArgumentsObject(
194 56 : map, zero, nullptr, mode, JSStrictArgumentsObject::kSize);
195 56 : result.Bind(arguments);
196 56 : Goto(&done);
197 : }
198 :
199 56 : BIND(&runtime);
200 : {
201 56 : result.Bind(CallRuntime(Runtime::kNewStrictArguments, context, function));
202 56 : Goto(&done);
203 : }
204 :
205 56 : BIND(&done);
206 112 : return result.value();
207 : }
208 :
209 56 : Node* ArgumentsBuiltinsAssembler::EmitFastNewSloppyArguments(Node* context,
210 : Node* function) {
211 112 : VARIABLE(result, MachineRepresentation::kTagged);
212 :
213 56 : ParameterMode mode = OptimalParameterMode();
214 56 : Node* zero = IntPtrOrSmiConstant(0, mode);
215 :
216 112 : Label done(this, &result), empty(this), no_parameters(this),
217 112 : runtime(this, Label::kDeferred);
218 :
219 : ArgumentsBuiltinsFromDSLAssembler::ArgumentsInfo info =
220 112 : GetArgumentsFrameAndCount(CAST(context),
221 112 : UncheckedCast<JSFunction>(function));
222 :
223 56 : GotoIf(WordEqual(info.argument_count, zero), &empty);
224 :
225 56 : GotoIf(WordEqual(info.formal_parameter_count, zero), &no_parameters);
226 :
227 : {
228 56 : Comment("Mapped parameter JSSloppyArgumentsObject");
229 :
230 : Node* mapped_count =
231 56 : IntPtrOrSmiMin(info.argument_count, info.formal_parameter_count, mode);
232 :
233 : Node* parameter_map_size =
234 56 : IntPtrOrSmiAdd(mapped_count, IntPtrOrSmiConstant(2, mode), mode);
235 :
236 : // Verify that the overall allocation will fit in new space.
237 : Node* elements_allocated =
238 56 : IntPtrOrSmiAdd(info.argument_count, parameter_map_size, mode);
239 56 : GotoIfFixedArraySizeDoesntFitInNewSpace(
240 : elements_allocated, &runtime,
241 56 : JSSloppyArgumentsObject::kSize + FixedArray::kHeaderSize * 2, mode);
242 :
243 56 : Node* const native_context = LoadNativeContext(context);
244 112 : Node* const map = LoadContextElement(
245 168 : native_context, Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX);
246 : Node* argument_object;
247 : Node* elements;
248 : Node* map_array;
249 112 : std::tie(argument_object, elements, map_array) =
250 112 : AllocateArgumentsObject(map, info.argument_count, parameter_map_size,
251 56 : mode, JSSloppyArgumentsObject::kSize);
252 56 : StoreObjectFieldNoWriteBarrier(
253 112 : argument_object, JSSloppyArgumentsObject::kCalleeOffset, function);
254 56 : StoreFixedArrayElement(CAST(map_array), 0, context, SKIP_WRITE_BARRIER);
255 56 : StoreFixedArrayElement(CAST(map_array), 1, elements, SKIP_WRITE_BARRIER);
256 :
257 56 : Comment("Fill in non-mapped parameters");
258 : Node* argument_offset =
259 112 : ElementOffsetFromIndex(info.argument_count, PACKED_ELEMENTS, mode,
260 112 : FixedArray::kHeaderSize - kHeapObjectTag);
261 : Node* mapped_offset =
262 112 : ElementOffsetFromIndex(mapped_count, PACKED_ELEMENTS, mode,
263 112 : FixedArray::kHeaderSize - kHeapObjectTag);
264 56 : CodeStubArguments arguments(this, info.argument_count, info.frame, mode);
265 112 : VARIABLE(current_argument, MachineType::PointerRepresentation());
266 56 : current_argument.Bind(arguments.AtIndexPtr(info.argument_count, mode));
267 112 : VariableList var_list1({¤t_argument}, zone());
268 112 : mapped_offset = BuildFastLoop(
269 : var_list1, argument_offset, mapped_offset,
270 224 : [this, elements, ¤t_argument](Node* offset) {
271 56 : Increment(¤t_argument, kSystemPointerSize);
272 168 : Node* arg = LoadBufferObject(current_argument.value(), 0);
273 56 : StoreNoWriteBarrier(MachineRepresentation::kTagged, elements, offset,
274 56 : arg);
275 56 : },
276 56 : -kTaggedSize, INTPTR_PARAMETERS);
277 :
278 : // Copy the parameter slots and the holes in the arguments.
279 : // We need to fill in mapped_count slots. They index the context,
280 : // where parameters are stored in reverse order, at
281 : // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+argument_count-1
282 : // The mapped parameter thus need to get indices
283 : // MIN_CONTEXT_SLOTS+parameter_count-1 ..
284 : // MIN_CONTEXT_SLOTS+argument_count-mapped_count
285 : // We loop from right to left.
286 56 : Comment("Fill in mapped parameters");
287 112 : VARIABLE(context_index, OptimalParameterRepresentation());
288 56 : context_index.Bind(IntPtrOrSmiSub(
289 : IntPtrOrSmiAdd(IntPtrOrSmiConstant(Context::MIN_CONTEXT_SLOTS, mode),
290 : info.formal_parameter_count, mode),
291 56 : mapped_count, mode));
292 56 : Node* the_hole = TheHoleConstant();
293 112 : VariableList var_list2({&context_index}, zone());
294 56 : const int kParameterMapHeaderSize = FixedArray::OffsetOfElementAt(2);
295 112 : Node* adjusted_map_array = IntPtrAdd(
296 : BitcastTaggedToWord(map_array),
297 168 : IntPtrConstant(kParameterMapHeaderSize - FixedArray::kHeaderSize));
298 112 : Node* zero_offset = ElementOffsetFromIndex(
299 112 : zero, PACKED_ELEMENTS, mode, FixedArray::kHeaderSize - kHeapObjectTag);
300 112 : BuildFastLoop(
301 : var_list2, mapped_offset, zero_offset,
302 168 : [=, &context_index](Node* offset) {
303 112 : StoreNoWriteBarrier(MachineRepresentation::kTagged, elements, offset,
304 336 : the_hole);
305 112 : StoreNoWriteBarrier(MachineRepresentation::kTagged,
306 56 : adjusted_map_array, offset,
307 224 : ParameterToTagged(context_index.value(), mode));
308 56 : Increment(&context_index, 1, mode);
309 56 : },
310 56 : -kTaggedSize, INTPTR_PARAMETERS);
311 :
312 56 : result.Bind(argument_object);
313 56 : Goto(&done);
314 : }
315 :
316 56 : BIND(&no_parameters);
317 : {
318 56 : Comment("No parameters JSSloppyArgumentsObject");
319 56 : GotoIfFixedArraySizeDoesntFitInNewSpace(
320 : info.argument_count, &runtime,
321 56 : JSSloppyArgumentsObject::kSize + FixedArray::kHeaderSize, mode);
322 56 : Node* const native_context = LoadNativeContext(context);
323 : Node* const map =
324 56 : LoadContextElement(native_context, Context::SLOPPY_ARGUMENTS_MAP_INDEX);
325 56 : result.Bind(ConstructParametersObjectFromArgs(
326 : map, info.frame, info.argument_count, zero, info.argument_count, mode,
327 56 : JSSloppyArgumentsObject::kSize));
328 56 : StoreObjectFieldNoWriteBarrier(
329 56 : result.value(), JSSloppyArgumentsObject::kCalleeOffset, function);
330 56 : Goto(&done);
331 : }
332 :
333 56 : BIND(&empty);
334 : {
335 56 : Comment("Empty JSSloppyArgumentsObject");
336 56 : Node* const native_context = LoadNativeContext(context);
337 : Node* const map =
338 56 : LoadContextElement(native_context, Context::SLOPPY_ARGUMENTS_MAP_INDEX);
339 : Node* arguments;
340 : Node* elements;
341 : Node* unused;
342 112 : std::tie(arguments, elements, unused) = AllocateArgumentsObject(
343 56 : map, zero, nullptr, mode, JSSloppyArgumentsObject::kSize);
344 56 : result.Bind(arguments);
345 56 : StoreObjectFieldNoWriteBarrier(
346 56 : result.value(), JSSloppyArgumentsObject::kCalleeOffset, function);
347 56 : Goto(&done);
348 : }
349 :
350 56 : BIND(&runtime);
351 : {
352 56 : result.Bind(CallRuntime(Runtime::kNewSloppyArguments, context, function));
353 56 : Goto(&done);
354 : }
355 :
356 56 : BIND(&done);
357 112 : return result.value();
358 : }
359 :
360 : } // namespace internal
361 87414 : } // namespace v8
|