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