1 // Copyright 2016 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/compiler/js-create-lowering.h"
6
7 #include "src/codegen/code-factory.h"
8 #include "src/compiler/access-builder.h"
9 #include "src/compiler/allocation-builder-inl.h"
10 #include "src/compiler/common-operator.h"
11 #include "src/compiler/compilation-dependencies.h"
12 #include "src/compiler/js-graph.h"
13 #include "src/compiler/js-operator.h"
14 #include "src/compiler/linkage.h"
15 #include "src/compiler/node-matchers.h"
16 #include "src/compiler/node-properties.h"
17 #include "src/compiler/node.h"
18 #include "src/compiler/operator-properties.h"
19 #include "src/compiler/simplified-operator.h"
20 #include "src/compiler/state-values-utils.h"
21 #include "src/execution/protectors.h"
22 #include "src/objects/arguments.h"
23 #include "src/objects/hash-table-inl.h"
24 #include "src/objects/heap-number.h"
25 #include "src/objects/js-collection-iterator.h"
26 #include "src/objects/js-generator.h"
27 #include "src/objects/js-promise.h"
28 #include "src/objects/js-regexp-inl.h"
29 #include "src/objects/objects-inl.h"
30 #include "src/objects/template-objects.h"
31
32 namespace v8 {
33 namespace internal {
34 namespace compiler {
35
36 namespace {
37
38 // Retrieves the frame state holding actual argument values.
GetArgumentsFrameState(Node * frame_state)39 Node* GetArgumentsFrameState(Node* frame_state) {
40 Node* const outer_state = NodeProperties::GetFrameStateInput(frame_state);
41 FrameStateInfo outer_state_info = FrameStateInfoOf(outer_state->op());
42 return outer_state_info.type() == FrameStateType::kArgumentsAdaptor
43 ? outer_state
44 : frame_state;
45 }
46
47 // When initializing arrays, we'll unfold the loop if the number of
48 // elements is known to be of this type.
49 const int kElementLoopUnrollLimit = 16;
50
51 // Limits up to which context allocations are inlined.
52 const int kFunctionContextAllocationLimit = 16;
53 const int kBlockContextAllocationLimit = 16;
54
55 } // namespace
56
Reduce(Node * node)57 Reduction JSCreateLowering::Reduce(Node* node) {
58 DisallowHeapAccess disallow_heap_access;
59 switch (node->opcode()) {
60 case IrOpcode::kJSCreate:
61 return ReduceJSCreate(node);
62 case IrOpcode::kJSCreateArguments:
63 return ReduceJSCreateArguments(node);
64 case IrOpcode::kJSCreateArray:
65 return ReduceJSCreateArray(node);
66 case IrOpcode::kJSCreateArrayIterator:
67 return ReduceJSCreateArrayIterator(node);
68 case IrOpcode::kJSCreateAsyncFunctionObject:
69 return ReduceJSCreateAsyncFunctionObject(node);
70 case IrOpcode::kJSCreateBoundFunction:
71 return ReduceJSCreateBoundFunction(node);
72 case IrOpcode::kJSCreateClosure:
73 return ReduceJSCreateClosure(node);
74 case IrOpcode::kJSCreateCollectionIterator:
75 return ReduceJSCreateCollectionIterator(node);
76 case IrOpcode::kJSCreateIterResultObject:
77 return ReduceJSCreateIterResultObject(node);
78 case IrOpcode::kJSCreateStringIterator:
79 return ReduceJSCreateStringIterator(node);
80 case IrOpcode::kJSCreateKeyValueArray:
81 return ReduceJSCreateKeyValueArray(node);
82 case IrOpcode::kJSCreatePromise:
83 return ReduceJSCreatePromise(node);
84 case IrOpcode::kJSCreateLiteralArray:
85 case IrOpcode::kJSCreateLiteralObject:
86 return ReduceJSCreateLiteralArrayOrObject(node);
87 case IrOpcode::kJSCreateLiteralRegExp:
88 return ReduceJSCreateLiteralRegExp(node);
89 case IrOpcode::kJSGetTemplateObject:
90 return ReduceJSGetTemplateObject(node);
91 case IrOpcode::kJSCreateEmptyLiteralArray:
92 return ReduceJSCreateEmptyLiteralArray(node);
93 case IrOpcode::kJSCreateEmptyLiteralObject:
94 return ReduceJSCreateEmptyLiteralObject(node);
95 case IrOpcode::kJSCreateFunctionContext:
96 return ReduceJSCreateFunctionContext(node);
97 case IrOpcode::kJSCreateWithContext:
98 return ReduceJSCreateWithContext(node);
99 case IrOpcode::kJSCreateCatchContext:
100 return ReduceJSCreateCatchContext(node);
101 case IrOpcode::kJSCreateBlockContext:
102 return ReduceJSCreateBlockContext(node);
103 case IrOpcode::kJSCreateGeneratorObject:
104 return ReduceJSCreateGeneratorObject(node);
105 case IrOpcode::kJSCreateObject:
106 return ReduceJSCreateObject(node);
107 default:
108 break;
109 }
110 return NoChange();
111 }
112
ReduceJSCreate(Node * node)113 Reduction JSCreateLowering::ReduceJSCreate(Node* node) {
114 DCHECK_EQ(IrOpcode::kJSCreate, node->opcode());
115 Node* const new_target = NodeProperties::GetValueInput(node, 1);
116 Node* const effect = NodeProperties::GetEffectInput(node);
117 Node* const control = NodeProperties::GetControlInput(node);
118
119 base::Optional<MapRef> initial_map =
120 NodeProperties::GetJSCreateMap(broker(), node);
121 if (!initial_map.has_value()) return NoChange();
122
123 JSFunctionRef original_constructor =
124 HeapObjectMatcher(new_target).Ref(broker()).AsJSFunction();
125 SlackTrackingPrediction slack_tracking_prediction =
126 dependencies()->DependOnInitialMapInstanceSizePrediction(
127 original_constructor);
128
129 // Emit code to allocate the JSObject instance for the
130 // {original_constructor}.
131 AllocationBuilder a(jsgraph(), effect, control);
132 a.Allocate(slack_tracking_prediction.instance_size());
133 a.Store(AccessBuilder::ForMap(), *initial_map);
134 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
135 jsgraph()->EmptyFixedArrayConstant());
136 a.Store(AccessBuilder::ForJSObjectElements(),
137 jsgraph()->EmptyFixedArrayConstant());
138 for (int i = 0; i < slack_tracking_prediction.inobject_property_count();
139 ++i) {
140 a.Store(AccessBuilder::ForJSObjectInObjectProperty(*initial_map, i),
141 jsgraph()->UndefinedConstant());
142 }
143
144 RelaxControls(node);
145 a.FinishAndChange(node);
146 return Changed(node);
147 }
148
ReduceJSCreateArguments(Node * node)149 Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
150 DCHECK_EQ(IrOpcode::kJSCreateArguments, node->opcode());
151 CreateArgumentsType type = CreateArgumentsTypeOf(node->op());
152 Node* const frame_state = NodeProperties::GetFrameStateInput(node);
153 Node* const outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
154 Node* const control = graph()->start();
155 FrameStateInfo state_info = FrameStateInfoOf(frame_state->op());
156 SharedFunctionInfoRef shared(broker(),
157 state_info.shared_info().ToHandleChecked());
158
159 // Use the ArgumentsAccessStub for materializing both mapped and unmapped
160 // arguments object, but only for non-inlined (i.e. outermost) frames.
161 if (outer_state->opcode() != IrOpcode::kFrameState) {
162 switch (type) {
163 case CreateArgumentsType::kMappedArguments: {
164 // TODO(turbofan): Duplicate parameters are not handled yet.
165 if (shared.has_duplicate_parameters()) return NoChange();
166 Node* const callee = NodeProperties::GetValueInput(node, 0);
167 Node* const context = NodeProperties::GetContextInput(node);
168 Node* effect = NodeProperties::GetEffectInput(node);
169 Node* const arguments_frame =
170 graph()->NewNode(simplified()->ArgumentsFrame());
171 Node* const arguments_length =
172 graph()->NewNode(simplified()->ArgumentsLength(
173 shared.internal_formal_parameter_count()),
174 arguments_frame);
175 // Allocate the elements backing store.
176 bool has_aliased_arguments = false;
177 Node* const elements = effect = AllocateAliasedArguments(
178 effect, control, context, arguments_frame, arguments_length, shared,
179 &has_aliased_arguments);
180 // Load the arguments object map.
181 Node* const arguments_map = jsgraph()->Constant(
182 has_aliased_arguments
183 ? native_context().fast_aliased_arguments_map()
184 : native_context().sloppy_arguments_map());
185 // Actually allocate and initialize the arguments object.
186 AllocationBuilder a(jsgraph(), effect, control);
187 STATIC_ASSERT(JSSloppyArgumentsObject::kSize == 5 * kTaggedSize);
188 a.Allocate(JSSloppyArgumentsObject::kSize);
189 a.Store(AccessBuilder::ForMap(), arguments_map);
190 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
191 jsgraph()->EmptyFixedArrayConstant());
192 a.Store(AccessBuilder::ForJSObjectElements(), elements);
193 a.Store(AccessBuilder::ForArgumentsLength(), arguments_length);
194 a.Store(AccessBuilder::ForArgumentsCallee(), callee);
195 RelaxControls(node);
196 a.FinishAndChange(node);
197 return Changed(node);
198 }
199 case CreateArgumentsType::kUnmappedArguments: {
200 Node* effect = NodeProperties::GetEffectInput(node);
201 Node* const arguments_frame =
202 graph()->NewNode(simplified()->ArgumentsFrame());
203 Node* const arguments_length =
204 graph()->NewNode(simplified()->ArgumentsLength(
205 shared.internal_formal_parameter_count()),
206 arguments_frame);
207 // Allocate the elements backing store.
208 Node* const elements = effect =
209 graph()->NewNode(simplified()->NewArgumentsElements(
210 CreateArgumentsType::kUnmappedArguments,
211 shared.internal_formal_parameter_count()),
212 arguments_frame, arguments_length, effect);
213 // Load the arguments object map.
214 Node* const arguments_map =
215 jsgraph()->Constant(native_context().strict_arguments_map());
216 // Actually allocate and initialize the arguments object.
217 AllocationBuilder a(jsgraph(), effect, control);
218 STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kTaggedSize);
219 a.Allocate(JSStrictArgumentsObject::kSize);
220 a.Store(AccessBuilder::ForMap(), arguments_map);
221 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
222 jsgraph()->EmptyFixedArrayConstant());
223 a.Store(AccessBuilder::ForJSObjectElements(), elements);
224 a.Store(AccessBuilder::ForArgumentsLength(), arguments_length);
225 RelaxControls(node);
226 a.FinishAndChange(node);
227 return Changed(node);
228 }
229 case CreateArgumentsType::kRestParameter: {
230 Node* effect = NodeProperties::GetEffectInput(node);
231 Node* const arguments_frame =
232 graph()->NewNode(simplified()->ArgumentsFrame());
233 Node* const arguments_length =
234 graph()->NewNode(simplified()->ArgumentsLength(
235 shared.internal_formal_parameter_count()),
236 arguments_frame);
237 Node* const rest_length = graph()->NewNode(
238 simplified()->RestLength(shared.internal_formal_parameter_count()),
239 arguments_frame);
240 // Allocate the elements backing store.
241 Node* const elements = effect =
242 graph()->NewNode(simplified()->NewArgumentsElements(
243 CreateArgumentsType::kRestParameter,
244 shared.internal_formal_parameter_count()),
245 arguments_frame, arguments_length, effect);
246 // Load the JSArray object map.
247 Node* const jsarray_map = jsgraph()->Constant(
248 native_context().js_array_packed_elements_map());
249 // Actually allocate and initialize the jsarray.
250 AllocationBuilder a(jsgraph(), effect, control);
251 STATIC_ASSERT(JSArray::kHeaderSize == 4 * kTaggedSize);
252 a.Allocate(JSArray::kHeaderSize);
253 a.Store(AccessBuilder::ForMap(), jsarray_map);
254 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
255 jsgraph()->EmptyFixedArrayConstant());
256 a.Store(AccessBuilder::ForJSObjectElements(), elements);
257 a.Store(AccessBuilder::ForJSArrayLength(PACKED_ELEMENTS), rest_length);
258 RelaxControls(node);
259 a.FinishAndChange(node);
260 return Changed(node);
261 }
262 }
263 UNREACHABLE();
264 }
265 // Use inline allocation for all mapped arguments objects within inlined
266 // (i.e. non-outermost) frames, independent of the object size.
267 DCHECK_EQ(outer_state->opcode(), IrOpcode::kFrameState);
268 switch (type) {
269 case CreateArgumentsType::kMappedArguments: {
270 Node* const callee = NodeProperties::GetValueInput(node, 0);
271 Node* const context = NodeProperties::GetContextInput(node);
272 Node* effect = NodeProperties::GetEffectInput(node);
273 // TODO(turbofan): Duplicate parameters are not handled yet.
274 if (shared.has_duplicate_parameters()) return NoChange();
275 // Choose the correct frame state and frame state info depending on
276 // whether there conceptually is an arguments adaptor frame in the call
277 // chain.
278 Node* const args_state = GetArgumentsFrameState(frame_state);
279 if (args_state->InputAt(kFrameStateParametersInput)->opcode() ==
280 IrOpcode::kDeadValue) {
281 // This protects against an incompletely propagated DeadValue node.
282 // If the FrameState has a DeadValue input, then this node will be
283 // pruned anyway.
284 return NoChange();
285 }
286 FrameStateInfo args_state_info = FrameStateInfoOf(args_state->op());
287 int length = args_state_info.parameter_count() - 1; // Minus receiver.
288 // Check that the array allocated for arguments is not "large".
289 {
290 const int alloc_size = FixedArray::SizeFor(length);
291 if (alloc_size > kMaxRegularHeapObjectSize) return NoChange();
292 }
293 // Prepare element backing store to be used by arguments object.
294 bool has_aliased_arguments = false;
295 Node* const elements = AllocateAliasedArguments(
296 effect, control, args_state, context, shared, &has_aliased_arguments);
297 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
298 // Load the arguments object map.
299 Node* const arguments_map = jsgraph()->Constant(
300 has_aliased_arguments ? native_context().fast_aliased_arguments_map()
301 : native_context().sloppy_arguments_map());
302 // Actually allocate and initialize the arguments object.
303 AllocationBuilder a(jsgraph(), effect, control);
304 STATIC_ASSERT(JSSloppyArgumentsObject::kSize == 5 * kTaggedSize);
305 a.Allocate(JSSloppyArgumentsObject::kSize);
306 a.Store(AccessBuilder::ForMap(), arguments_map);
307 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
308 jsgraph()->EmptyFixedArrayConstant());
309 a.Store(AccessBuilder::ForJSObjectElements(), elements);
310 a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length));
311 a.Store(AccessBuilder::ForArgumentsCallee(), callee);
312 RelaxControls(node);
313 a.FinishAndChange(node);
314 return Changed(node);
315 }
316 case CreateArgumentsType::kUnmappedArguments: {
317 // Use inline allocation for all unmapped arguments objects within inlined
318 // (i.e. non-outermost) frames, independent of the object size.
319 Node* effect = NodeProperties::GetEffectInput(node);
320 // Choose the correct frame state and frame state info depending on
321 // whether there conceptually is an arguments adaptor frame in the call
322 // chain.
323 Node* const args_state = GetArgumentsFrameState(frame_state);
324 if (args_state->InputAt(kFrameStateParametersInput)->opcode() ==
325 IrOpcode::kDeadValue) {
326 // This protects against an incompletely propagated DeadValue node.
327 // If the FrameState has a DeadValue input, then this node will be
328 // pruned anyway.
329 return NoChange();
330 }
331 FrameStateInfo args_state_info = FrameStateInfoOf(args_state->op());
332 int length = args_state_info.parameter_count() - 1; // Minus receiver.
333 // Check that the array allocated for arguments is not "large".
334 {
335 const int alloc_size = FixedArray::SizeFor(length);
336 if (alloc_size > kMaxRegularHeapObjectSize) return NoChange();
337 }
338 // Prepare element backing store to be used by arguments object.
339 Node* const elements = AllocateArguments(effect, control, args_state);
340 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
341 // Load the arguments object map.
342 Node* const arguments_map =
343 jsgraph()->Constant(native_context().strict_arguments_map());
344 // Actually allocate and initialize the arguments object.
345 AllocationBuilder a(jsgraph(), effect, control);
346 STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kTaggedSize);
347 a.Allocate(JSStrictArgumentsObject::kSize);
348 a.Store(AccessBuilder::ForMap(), arguments_map);
349 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
350 jsgraph()->EmptyFixedArrayConstant());
351 a.Store(AccessBuilder::ForJSObjectElements(), elements);
352 a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length));
353 RelaxControls(node);
354 a.FinishAndChange(node);
355 return Changed(node);
356 }
357 case CreateArgumentsType::kRestParameter: {
358 int start_index = shared.internal_formal_parameter_count();
359 // Use inline allocation for all unmapped arguments objects within inlined
360 // (i.e. non-outermost) frames, independent of the object size.
361 Node* effect = NodeProperties::GetEffectInput(node);
362 // Choose the correct frame state and frame state info depending on
363 // whether there conceptually is an arguments adaptor frame in the call
364 // chain.
365 Node* const args_state = GetArgumentsFrameState(frame_state);
366 if (args_state->InputAt(kFrameStateParametersInput)->opcode() ==
367 IrOpcode::kDeadValue) {
368 // This protects against an incompletely propagated DeadValue node.
369 // If the FrameState has a DeadValue input, then this node will be
370 // pruned anyway.
371 return NoChange();
372 }
373 FrameStateInfo args_state_info = FrameStateInfoOf(args_state->op());
374 // Prepare element backing store to be used by the rest array.
375 Node* const elements =
376 AllocateRestArguments(effect, control, args_state, start_index);
377 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
378 // Load the JSArray object map.
379 Node* const jsarray_map =
380 jsgraph()->Constant(native_context().js_array_packed_elements_map());
381 // Actually allocate and initialize the jsarray.
382 AllocationBuilder a(jsgraph(), effect, control);
383
384 // -1 to minus receiver
385 int argument_count = args_state_info.parameter_count() - 1;
386 int length = std::max(0, argument_count - start_index);
387 STATIC_ASSERT(JSArray::kHeaderSize == 4 * kTaggedSize);
388 a.Allocate(JSArray::kHeaderSize);
389 a.Store(AccessBuilder::ForMap(), jsarray_map);
390 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
391 jsgraph()->EmptyFixedArrayConstant());
392 a.Store(AccessBuilder::ForJSObjectElements(), elements);
393 a.Store(AccessBuilder::ForJSArrayLength(PACKED_ELEMENTS),
394 jsgraph()->Constant(length));
395 RelaxControls(node);
396 a.FinishAndChange(node);
397 return Changed(node);
398 }
399 }
400 UNREACHABLE();
401 }
402
ReduceJSCreateGeneratorObject(Node * node)403 Reduction JSCreateLowering::ReduceJSCreateGeneratorObject(Node* node) {
404 DCHECK_EQ(IrOpcode::kJSCreateGeneratorObject, node->opcode());
405 Node* const closure = NodeProperties::GetValueInput(node, 0);
406 Node* const receiver = NodeProperties::GetValueInput(node, 1);
407 Node* const context = NodeProperties::GetContextInput(node);
408 Type const closure_type = NodeProperties::GetType(closure);
409 Node* effect = NodeProperties::GetEffectInput(node);
410 Node* const control = NodeProperties::GetControlInput(node);
411 if (closure_type.IsHeapConstant()) {
412 DCHECK(closure_type.AsHeapConstant()->Ref().IsJSFunction());
413 JSFunctionRef js_function =
414 closure_type.AsHeapConstant()->Ref().AsJSFunction();
415 if (!js_function.has_initial_map()) return NoChange();
416
417 SlackTrackingPrediction slack_tracking_prediction =
418 dependencies()->DependOnInitialMapInstanceSizePrediction(js_function);
419
420 MapRef initial_map = js_function.initial_map();
421 DCHECK(initial_map.instance_type() == JS_GENERATOR_OBJECT_TYPE ||
422 initial_map.instance_type() == JS_ASYNC_GENERATOR_OBJECT_TYPE);
423
424 // Allocate a register file.
425 SharedFunctionInfoRef shared = js_function.shared();
426 DCHECK(shared.HasBytecodeArray());
427 int parameter_count_no_receiver = shared.internal_formal_parameter_count();
428 int size = parameter_count_no_receiver +
429 shared.GetBytecodeArray().register_count();
430 AllocationBuilder ab(jsgraph(), effect, control);
431 ab.AllocateArray(size, MapRef(broker(), factory()->fixed_array_map()));
432 for (int i = 0; i < size; ++i) {
433 ab.Store(AccessBuilder::ForFixedArraySlot(i),
434 jsgraph()->UndefinedConstant());
435 }
436 Node* parameters_and_registers = effect = ab.Finish();
437
438 // Emit code to allocate the JS[Async]GeneratorObject instance.
439 AllocationBuilder a(jsgraph(), effect, control);
440 a.Allocate(slack_tracking_prediction.instance_size());
441 Node* undefined = jsgraph()->UndefinedConstant();
442 a.Store(AccessBuilder::ForMap(), initial_map);
443 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
444 jsgraph()->EmptyFixedArrayConstant());
445 a.Store(AccessBuilder::ForJSObjectElements(),
446 jsgraph()->EmptyFixedArrayConstant());
447 a.Store(AccessBuilder::ForJSGeneratorObjectContext(), context);
448 a.Store(AccessBuilder::ForJSGeneratorObjectFunction(), closure);
449 a.Store(AccessBuilder::ForJSGeneratorObjectReceiver(), receiver);
450 a.Store(AccessBuilder::ForJSGeneratorObjectInputOrDebugPos(), undefined);
451 a.Store(AccessBuilder::ForJSGeneratorObjectResumeMode(),
452 jsgraph()->Constant(JSGeneratorObject::kNext));
453 a.Store(AccessBuilder::ForJSGeneratorObjectContinuation(),
454 jsgraph()->Constant(JSGeneratorObject::kGeneratorExecuting));
455 a.Store(AccessBuilder::ForJSGeneratorObjectParametersAndRegisters(),
456 parameters_and_registers);
457
458 if (initial_map.instance_type() == JS_ASYNC_GENERATOR_OBJECT_TYPE) {
459 a.Store(AccessBuilder::ForJSAsyncGeneratorObjectQueue(), undefined);
460 a.Store(AccessBuilder::ForJSAsyncGeneratorObjectIsAwaiting(),
461 jsgraph()->ZeroConstant());
462 }
463
464 // Handle in-object properties, too.
465 for (int i = 0; i < slack_tracking_prediction.inobject_property_count();
466 ++i) {
467 a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
468 undefined);
469 }
470 a.FinishAndChange(node);
471 return Changed(node);
472 }
473 return NoChange();
474 }
475
476 // Constructs an array with a variable {length} when no upper bound
477 // is known for the capacity.
ReduceNewArray(Node * node,Node * length,MapRef initial_map,ElementsKind elements_kind,AllocationType allocation,const SlackTrackingPrediction & slack_tracking_prediction)478 Reduction JSCreateLowering::ReduceNewArray(
479 Node* node, Node* length, MapRef initial_map, ElementsKind elements_kind,
480 AllocationType allocation,
481 const SlackTrackingPrediction& slack_tracking_prediction) {
482 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
483 Node* effect = NodeProperties::GetEffectInput(node);
484 Node* control = NodeProperties::GetControlInput(node);
485
486 // Constructing an Array via new Array(N) where N is an unsigned
487 // integer, always creates a holey backing store.
488 ASSIGN_RETURN_NO_CHANGE_IF_DATA_MISSING(
489 initial_map,
490 initial_map.AsElementsKind(GetHoleyElementsKind(elements_kind)));
491
492 // Because CheckBounds performs implicit conversion from string to number, an
493 // additional CheckNumber is required to behave correctly for calls with a
494 // single string argument.
495 length = effect = graph()->NewNode(
496 simplified()->CheckNumber(FeedbackSource{}), length, effect, control);
497
498 // Check that the {limit} is an unsigned integer in the valid range.
499 // This has to be kept in sync with src/runtime/runtime-array.cc,
500 // where this limit is protected.
501 length = effect = graph()->NewNode(
502 simplified()->CheckBounds(FeedbackSource()), length,
503 jsgraph()->Constant(JSArray::kInitialMaxFastElementArray), effect,
504 control);
505
506 // Construct elements and properties for the resulting JSArray.
507 Node* elements = effect =
508 graph()->NewNode(IsDoubleElementsKind(initial_map.elements_kind())
509 ? simplified()->NewDoubleElements(allocation)
510 : simplified()->NewSmiOrObjectElements(allocation),
511 length, effect, control);
512
513 // Perform the allocation of the actual JSArray object.
514 AllocationBuilder a(jsgraph(), effect, control);
515 a.Allocate(slack_tracking_prediction.instance_size(), allocation);
516 a.Store(AccessBuilder::ForMap(), initial_map);
517 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
518 jsgraph()->EmptyFixedArrayConstant());
519 a.Store(AccessBuilder::ForJSObjectElements(), elements);
520 a.Store(AccessBuilder::ForJSArrayLength(initial_map.elements_kind()), length);
521 for (int i = 0; i < slack_tracking_prediction.inobject_property_count();
522 ++i) {
523 a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
524 jsgraph()->UndefinedConstant());
525 }
526 RelaxControls(node);
527 a.FinishAndChange(node);
528 return Changed(node);
529 }
530
531 // Constructs an array with a variable {length} when an actual
532 // upper bound is known for the {capacity}.
ReduceNewArray(Node * node,Node * length,int capacity,MapRef initial_map,ElementsKind elements_kind,AllocationType allocation,const SlackTrackingPrediction & slack_tracking_prediction)533 Reduction JSCreateLowering::ReduceNewArray(
534 Node* node, Node* length, int capacity, MapRef initial_map,
535 ElementsKind elements_kind, AllocationType allocation,
536 const SlackTrackingPrediction& slack_tracking_prediction) {
537 DCHECK(node->opcode() == IrOpcode::kJSCreateArray ||
538 node->opcode() == IrOpcode::kJSCreateEmptyLiteralArray);
539 DCHECK(NodeProperties::GetType(length).Is(Type::Number()));
540 Node* effect = NodeProperties::GetEffectInput(node);
541 Node* control = NodeProperties::GetControlInput(node);
542
543 // Determine the appropriate elements kind.
544 if (NodeProperties::GetType(length).Max() > 0.0) {
545 elements_kind = GetHoleyElementsKind(elements_kind);
546 }
547 ASSIGN_RETURN_NO_CHANGE_IF_DATA_MISSING(
548 initial_map, initial_map.AsElementsKind(elements_kind));
549 DCHECK(IsFastElementsKind(elements_kind));
550
551 // Setup elements and properties.
552 Node* elements;
553 if (capacity == 0) {
554 elements = jsgraph()->EmptyFixedArrayConstant();
555 } else {
556 elements = effect =
557 AllocateElements(effect, control, elements_kind, capacity, allocation);
558 }
559
560 // Perform the allocation of the actual JSArray object.
561 AllocationBuilder a(jsgraph(), effect, control);
562 a.Allocate(slack_tracking_prediction.instance_size(), allocation);
563 a.Store(AccessBuilder::ForMap(), initial_map);
564 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
565 jsgraph()->EmptyFixedArrayConstant());
566 a.Store(AccessBuilder::ForJSObjectElements(), elements);
567 a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length);
568 for (int i = 0; i < slack_tracking_prediction.inobject_property_count();
569 ++i) {
570 a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
571 jsgraph()->UndefinedConstant());
572 }
573 RelaxControls(node);
574 a.FinishAndChange(node);
575 return Changed(node);
576 }
577
ReduceNewArray(Node * node,std::vector<Node * > values,MapRef initial_map,ElementsKind elements_kind,AllocationType allocation,const SlackTrackingPrediction & slack_tracking_prediction)578 Reduction JSCreateLowering::ReduceNewArray(
579 Node* node, std::vector<Node*> values, MapRef initial_map,
580 ElementsKind elements_kind, AllocationType allocation,
581 const SlackTrackingPrediction& slack_tracking_prediction) {
582 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
583 Node* effect = NodeProperties::GetEffectInput(node);
584 Node* control = NodeProperties::GetControlInput(node);
585
586 // Determine the appropriate elements kind.
587 DCHECK(IsFastElementsKind(elements_kind));
588 ASSIGN_RETURN_NO_CHANGE_IF_DATA_MISSING(
589 initial_map, initial_map.AsElementsKind(elements_kind));
590
591 // Check {values} based on the {elements_kind}. These checks are guarded
592 // by the {elements_kind} feedback on the {site}, so it's safe to just
593 // deoptimize in this case.
594 if (IsSmiElementsKind(elements_kind)) {
595 for (auto& value : values) {
596 if (!NodeProperties::GetType(value).Is(Type::SignedSmall())) {
597 value = effect = graph()->NewNode(
598 simplified()->CheckSmi(FeedbackSource()), value, effect, control);
599 }
600 }
601 } else if (IsDoubleElementsKind(elements_kind)) {
602 for (auto& value : values) {
603 if (!NodeProperties::GetType(value).Is(Type::Number())) {
604 value = effect =
605 graph()->NewNode(simplified()->CheckNumber(FeedbackSource()), value,
606 effect, control);
607 }
608 // Make sure we do not store signaling NaNs into double arrays.
609 value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
610 }
611 }
612
613 // Setup elements, properties and length.
614 Node* elements = effect =
615 AllocateElements(effect, control, elements_kind, values, allocation);
616 Node* length = jsgraph()->Constant(static_cast<int>(values.size()));
617
618 // Perform the allocation of the actual JSArray object.
619 AllocationBuilder a(jsgraph(), effect, control);
620 a.Allocate(slack_tracking_prediction.instance_size(), allocation);
621 a.Store(AccessBuilder::ForMap(), initial_map);
622 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
623 jsgraph()->EmptyFixedArrayConstant());
624 a.Store(AccessBuilder::ForJSObjectElements(), elements);
625 a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length);
626 for (int i = 0; i < slack_tracking_prediction.inobject_property_count();
627 ++i) {
628 a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
629 jsgraph()->UndefinedConstant());
630 }
631 RelaxControls(node);
632 a.FinishAndChange(node);
633 return Changed(node);
634 }
635
ReduceJSCreateArray(Node * node)636 Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) {
637 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
638 CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
639 int const arity = static_cast<int>(p.arity());
640 base::Optional<AllocationSiteRef> site_ref;
641 {
642 Handle<AllocationSite> site;
643 if (p.site().ToHandle(&site)) {
644 site_ref = AllocationSiteRef(broker(), site);
645 }
646 }
647 AllocationType allocation = AllocationType::kYoung;
648
649 base::Optional<MapRef> initial_map =
650 NodeProperties::GetJSCreateMap(broker(), node);
651 if (!initial_map.has_value()) return NoChange();
652
653 Node* new_target = NodeProperties::GetValueInput(node, 1);
654 JSFunctionRef original_constructor =
655 HeapObjectMatcher(new_target).Ref(broker()).AsJSFunction();
656 SlackTrackingPrediction slack_tracking_prediction =
657 dependencies()->DependOnInitialMapInstanceSizePrediction(
658 original_constructor);
659
660 // Tells whether we are protected by either the {site} or a
661 // protector cell to do certain speculative optimizations.
662 bool can_inline_call = false;
663
664 // Check if we have a feedback {site} on the {node}.
665 ElementsKind elements_kind = initial_map->elements_kind();
666 if (site_ref) {
667 elements_kind = site_ref->GetElementsKind();
668 can_inline_call = site_ref->CanInlineCall();
669 allocation = dependencies()->DependOnPretenureMode(*site_ref);
670 dependencies()->DependOnElementsKind(*site_ref);
671 } else {
672 PropertyCellRef array_constructor_protector(
673 broker(), factory()->array_constructor_protector());
674 can_inline_call = array_constructor_protector.value().AsSmi() ==
675 Protectors::kProtectorValid;
676 }
677
678 if (arity == 0) {
679 Node* length = jsgraph()->ZeroConstant();
680 int capacity = JSArray::kPreallocatedArrayElements;
681 return ReduceNewArray(node, length, capacity, *initial_map, elements_kind,
682 allocation, slack_tracking_prediction);
683 } else if (arity == 1) {
684 Node* length = NodeProperties::GetValueInput(node, 2);
685 Type length_type = NodeProperties::GetType(length);
686 if (!length_type.Maybe(Type::Number())) {
687 // Handle the single argument case, where we know that the value
688 // cannot be a valid Array length.
689 elements_kind = GetMoreGeneralElementsKind(
690 elements_kind, IsHoleyElementsKind(elements_kind) ? HOLEY_ELEMENTS
691 : PACKED_ELEMENTS);
692 return ReduceNewArray(node, std::vector<Node*>{length}, *initial_map,
693 elements_kind, allocation,
694 slack_tracking_prediction);
695 }
696 if (length_type.Is(Type::SignedSmall()) && length_type.Min() >= 0 &&
697 length_type.Max() <= kElementLoopUnrollLimit &&
698 length_type.Min() == length_type.Max()) {
699 int capacity = static_cast<int>(length_type.Max());
700 // Replace length with a constant in order to protect against a potential
701 // typer bug leading to length > capacity.
702 length = jsgraph()->Constant(capacity);
703 return ReduceNewArray(node, length, capacity, *initial_map, elements_kind,
704 allocation, slack_tracking_prediction);
705 }
706 if (length_type.Maybe(Type::UnsignedSmall()) && can_inline_call) {
707 return ReduceNewArray(node, length, *initial_map, elements_kind,
708 allocation, slack_tracking_prediction);
709 }
710 } else if (arity <= JSArray::kInitialMaxFastElementArray) {
711 // Gather the values to store into the newly created array.
712 bool values_all_smis = true, values_all_numbers = true,
713 values_any_nonnumber = false;
714 std::vector<Node*> values;
715 values.reserve(p.arity());
716 for (int i = 0; i < arity; ++i) {
717 Node* value = NodeProperties::GetValueInput(node, 2 + i);
718 Type value_type = NodeProperties::GetType(value);
719 if (!value_type.Is(Type::SignedSmall())) {
720 values_all_smis = false;
721 }
722 if (!value_type.Is(Type::Number())) {
723 values_all_numbers = false;
724 }
725 if (!value_type.Maybe(Type::Number())) {
726 values_any_nonnumber = true;
727 }
728 values.push_back(value);
729 }
730
731 // Try to figure out the ideal elements kind statically.
732 if (values_all_smis) {
733 // Smis can be stored with any elements kind.
734 } else if (values_all_numbers) {
735 elements_kind = GetMoreGeneralElementsKind(
736 elements_kind, IsHoleyElementsKind(elements_kind)
737 ? HOLEY_DOUBLE_ELEMENTS
738 : PACKED_DOUBLE_ELEMENTS);
739 } else if (values_any_nonnumber) {
740 elements_kind = GetMoreGeneralElementsKind(
741 elements_kind, IsHoleyElementsKind(elements_kind) ? HOLEY_ELEMENTS
742 : PACKED_ELEMENTS);
743 } else if (!can_inline_call) {
744 // We have some crazy combination of types for the {values} where
745 // there's no clear decision on the elements kind statically. And
746 // we don't have a protection against deoptimization loops for the
747 // checks that are introduced in the call to ReduceNewArray, so
748 // we cannot inline this invocation of the Array constructor here.
749 return NoChange();
750 }
751 return ReduceNewArray(node, values, *initial_map, elements_kind, allocation,
752 slack_tracking_prediction);
753 }
754 return NoChange();
755 }
756
ReduceJSCreateArrayIterator(Node * node)757 Reduction JSCreateLowering::ReduceJSCreateArrayIterator(Node* node) {
758 DCHECK_EQ(IrOpcode::kJSCreateArrayIterator, node->opcode());
759 CreateArrayIteratorParameters const& p =
760 CreateArrayIteratorParametersOf(node->op());
761 Node* iterated_object = NodeProperties::GetValueInput(node, 0);
762 Node* effect = NodeProperties::GetEffectInput(node);
763 Node* control = NodeProperties::GetControlInput(node);
764
765 // Create the JSArrayIterator result.
766 AllocationBuilder a(jsgraph(), effect, control);
767 a.Allocate(JSArrayIterator::kHeaderSize, AllocationType::kYoung,
768 Type::OtherObject());
769 a.Store(AccessBuilder::ForMap(),
770 native_context().initial_array_iterator_map());
771 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
772 jsgraph()->EmptyFixedArrayConstant());
773 a.Store(AccessBuilder::ForJSObjectElements(),
774 jsgraph()->EmptyFixedArrayConstant());
775 a.Store(AccessBuilder::ForJSArrayIteratorIteratedObject(), iterated_object);
776 a.Store(AccessBuilder::ForJSArrayIteratorNextIndex(),
777 jsgraph()->ZeroConstant());
778 a.Store(AccessBuilder::ForJSArrayIteratorKind(),
779 jsgraph()->Constant(static_cast<int>(p.kind())));
780 RelaxControls(node);
781 a.FinishAndChange(node);
782 return Changed(node);
783 }
784
ReduceJSCreateAsyncFunctionObject(Node * node)785 Reduction JSCreateLowering::ReduceJSCreateAsyncFunctionObject(Node* node) {
786 DCHECK_EQ(IrOpcode::kJSCreateAsyncFunctionObject, node->opcode());
787 int const register_count = RegisterCountOf(node->op());
788 Node* closure = NodeProperties::GetValueInput(node, 0);
789 Node* receiver = NodeProperties::GetValueInput(node, 1);
790 Node* promise = NodeProperties::GetValueInput(node, 2);
791 Node* context = NodeProperties::GetContextInput(node);
792 Node* effect = NodeProperties::GetEffectInput(node);
793 Node* control = NodeProperties::GetControlInput(node);
794
795 // Create the register file.
796 AllocationBuilder ab(jsgraph(), effect, control);
797 ab.AllocateArray(register_count,
798 MapRef(broker(), factory()->fixed_array_map()));
799 for (int i = 0; i < register_count; ++i) {
800 ab.Store(AccessBuilder::ForFixedArraySlot(i),
801 jsgraph()->UndefinedConstant());
802 }
803 Node* parameters_and_registers = effect = ab.Finish();
804
805 // Create the JSAsyncFunctionObject result.
806 AllocationBuilder a(jsgraph(), effect, control);
807 a.Allocate(JSAsyncFunctionObject::kHeaderSize);
808 a.Store(AccessBuilder::ForMap(),
809 native_context().async_function_object_map());
810 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
811 jsgraph()->EmptyFixedArrayConstant());
812 a.Store(AccessBuilder::ForJSObjectElements(),
813 jsgraph()->EmptyFixedArrayConstant());
814 a.Store(AccessBuilder::ForJSGeneratorObjectContext(), context);
815 a.Store(AccessBuilder::ForJSGeneratorObjectFunction(), closure);
816 a.Store(AccessBuilder::ForJSGeneratorObjectReceiver(), receiver);
817 a.Store(AccessBuilder::ForJSGeneratorObjectInputOrDebugPos(),
818 jsgraph()->UndefinedConstant());
819 a.Store(AccessBuilder::ForJSGeneratorObjectResumeMode(),
820 jsgraph()->Constant(JSGeneratorObject::kNext));
821 a.Store(AccessBuilder::ForJSGeneratorObjectContinuation(),
822 jsgraph()->Constant(JSGeneratorObject::kGeneratorExecuting));
823 a.Store(AccessBuilder::ForJSGeneratorObjectParametersAndRegisters(),
824 parameters_and_registers);
825 a.Store(AccessBuilder::ForJSAsyncFunctionObjectPromise(), promise);
826 a.FinishAndChange(node);
827 return Changed(node);
828 }
829
830 namespace {
831
MapForCollectionIterationKind(const NativeContextRef & native_context,CollectionKind collection_kind,IterationKind iteration_kind)832 MapRef MapForCollectionIterationKind(const NativeContextRef& native_context,
833 CollectionKind collection_kind,
834 IterationKind iteration_kind) {
835 switch (collection_kind) {
836 case CollectionKind::kSet:
837 switch (iteration_kind) {
838 case IterationKind::kKeys:
839 UNREACHABLE();
840 case IterationKind::kValues:
841 return native_context.set_value_iterator_map();
842 case IterationKind::kEntries:
843 return native_context.set_key_value_iterator_map();
844 }
845 break;
846 case CollectionKind::kMap:
847 switch (iteration_kind) {
848 case IterationKind::kKeys:
849 return native_context.map_key_iterator_map();
850 case IterationKind::kValues:
851 return native_context.map_value_iterator_map();
852 case IterationKind::kEntries:
853 return native_context.map_key_value_iterator_map();
854 }
855 break;
856 }
857 UNREACHABLE();
858 }
859
860 } // namespace
861
ReduceJSCreateCollectionIterator(Node * node)862 Reduction JSCreateLowering::ReduceJSCreateCollectionIterator(Node* node) {
863 DCHECK_EQ(IrOpcode::kJSCreateCollectionIterator, node->opcode());
864 CreateCollectionIteratorParameters const& p =
865 CreateCollectionIteratorParametersOf(node->op());
866 Node* iterated_object = NodeProperties::GetValueInput(node, 0);
867 Node* effect = NodeProperties::GetEffectInput(node);
868 Node* control = NodeProperties::GetControlInput(node);
869
870 // Load the OrderedHashTable from the {receiver}.
871 Node* table = effect = graph()->NewNode(
872 simplified()->LoadField(AccessBuilder::ForJSCollectionTable()),
873 iterated_object, effect, control);
874
875 // Create the JSCollectionIterator result.
876 AllocationBuilder a(jsgraph(), effect, control);
877 a.Allocate(JSCollectionIterator::kHeaderSize, AllocationType::kYoung,
878 Type::OtherObject());
879 a.Store(AccessBuilder::ForMap(),
880 MapForCollectionIterationKind(native_context(), p.collection_kind(),
881 p.iteration_kind()));
882 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
883 jsgraph()->EmptyFixedArrayConstant());
884 a.Store(AccessBuilder::ForJSObjectElements(),
885 jsgraph()->EmptyFixedArrayConstant());
886 a.Store(AccessBuilder::ForJSCollectionIteratorTable(), table);
887 a.Store(AccessBuilder::ForJSCollectionIteratorIndex(),
888 jsgraph()->ZeroConstant());
889 RelaxControls(node);
890 a.FinishAndChange(node);
891 return Changed(node);
892 }
893
ReduceJSCreateBoundFunction(Node * node)894 Reduction JSCreateLowering::ReduceJSCreateBoundFunction(Node* node) {
895 DCHECK_EQ(IrOpcode::kJSCreateBoundFunction, node->opcode());
896 CreateBoundFunctionParameters const& p =
897 CreateBoundFunctionParametersOf(node->op());
898 int const arity = static_cast<int>(p.arity());
899 MapRef const map(broker(), p.map());
900 Node* bound_target_function = NodeProperties::GetValueInput(node, 0);
901 Node* bound_this = NodeProperties::GetValueInput(node, 1);
902 Node* effect = NodeProperties::GetEffectInput(node);
903 Node* control = NodeProperties::GetControlInput(node);
904
905 // Create the [[BoundArguments]] for the result.
906 Node* bound_arguments = jsgraph()->EmptyFixedArrayConstant();
907 if (arity > 0) {
908 AllocationBuilder a(jsgraph(), effect, control);
909 a.AllocateArray(arity, MapRef(broker(), factory()->fixed_array_map()));
910 for (int i = 0; i < arity; ++i) {
911 a.Store(AccessBuilder::ForFixedArraySlot(i),
912 NodeProperties::GetValueInput(node, 2 + i));
913 }
914 bound_arguments = effect = a.Finish();
915 }
916
917 // Create the JSBoundFunction result.
918 AllocationBuilder a(jsgraph(), effect, control);
919 a.Allocate(JSBoundFunction::kHeaderSize, AllocationType::kYoung,
920 Type::BoundFunction());
921 a.Store(AccessBuilder::ForMap(), map);
922 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
923 jsgraph()->EmptyFixedArrayConstant());
924 a.Store(AccessBuilder::ForJSObjectElements(),
925 jsgraph()->EmptyFixedArrayConstant());
926 a.Store(AccessBuilder::ForJSBoundFunctionBoundTargetFunction(),
927 bound_target_function);
928 a.Store(AccessBuilder::ForJSBoundFunctionBoundThis(), bound_this);
929 a.Store(AccessBuilder::ForJSBoundFunctionBoundArguments(), bound_arguments);
930 RelaxControls(node);
931 a.FinishAndChange(node);
932 return Changed(node);
933 }
934
ReduceJSCreateClosure(Node * node)935 Reduction JSCreateLowering::ReduceJSCreateClosure(Node* node) {
936 JSCreateClosureNode n(node);
937 CreateClosureParameters const& p = n.Parameters();
938 SharedFunctionInfoRef shared(broker(), p.shared_info());
939 FeedbackCellRef feedback_cell = n.GetFeedbackCellRefChecked(broker());
940 HeapObjectRef code(broker(), p.code());
941 Effect effect = n.effect();
942 Control control = n.control();
943 Node* context = n.context();
944
945 // Use inline allocation of closures only for instantiation sites that have
946 // seen more than one instantiation, this simplifies the generated code and
947 // also serves as a heuristic of which allocation sites benefit from it.
948 if (!feedback_cell.map().equals(
949 MapRef(broker(), factory()->many_closures_cell_map()))) {
950 return NoChange();
951 }
952
953 MapRef function_map =
954 native_context().GetFunctionMapFromIndex(shared.function_map_index());
955 DCHECK(!function_map.IsInobjectSlackTrackingInProgress());
956 DCHECK(!function_map.is_dictionary_map());
957
958 // TODO(turbofan): We should use the pretenure flag from {p} here,
959 // but currently the heuristic in the parser works against us, as
960 // it marks closures like
961 //
962 // args[l] = function(...) { ... }
963 //
964 // for old-space allocation, which doesn't always make sense. For
965 // example in case of the bluebird-parallel benchmark, where this
966 // is a core part of the *promisify* logic (see crbug.com/810132).
967 AllocationType allocation = AllocationType::kYoung;
968
969 // Emit code to allocate the JSFunction instance.
970 STATIC_ASSERT(JSFunction::kSizeWithoutPrototype == 7 * kTaggedSize);
971 AllocationBuilder a(jsgraph(), effect, control);
972 a.Allocate(function_map.instance_size(), allocation, Type::Function());
973 a.Store(AccessBuilder::ForMap(), function_map);
974 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
975 jsgraph()->EmptyFixedArrayConstant());
976 a.Store(AccessBuilder::ForJSObjectElements(),
977 jsgraph()->EmptyFixedArrayConstant());
978 a.Store(AccessBuilder::ForJSFunctionSharedFunctionInfo(), shared);
979 a.Store(AccessBuilder::ForJSFunctionContext(), context);
980 a.Store(AccessBuilder::ForJSFunctionFeedbackCell(), feedback_cell);
981 a.Store(AccessBuilder::ForJSFunctionCode(), code);
982 STATIC_ASSERT(JSFunction::kSizeWithoutPrototype == 7 * kTaggedSize);
983 if (function_map.has_prototype_slot()) {
984 a.Store(AccessBuilder::ForJSFunctionPrototypeOrInitialMap(),
985 jsgraph()->TheHoleConstant());
986 STATIC_ASSERT(JSFunction::kSizeWithPrototype == 8 * kTaggedSize);
987 }
988 for (int i = 0; i < function_map.GetInObjectProperties(); i++) {
989 a.Store(AccessBuilder::ForJSObjectInObjectProperty(function_map, i),
990 jsgraph()->UndefinedConstant());
991 }
992 RelaxControls(node);
993 a.FinishAndChange(node);
994 return Changed(node);
995 }
996
ReduceJSCreateIterResultObject(Node * node)997 Reduction JSCreateLowering::ReduceJSCreateIterResultObject(Node* node) {
998 DCHECK_EQ(IrOpcode::kJSCreateIterResultObject, node->opcode());
999 Node* value = NodeProperties::GetValueInput(node, 0);
1000 Node* done = NodeProperties::GetValueInput(node, 1);
1001 Node* effect = NodeProperties::GetEffectInput(node);
1002
1003 Node* iterator_result_map =
1004 jsgraph()->Constant(native_context().iterator_result_map());
1005
1006 // Emit code to allocate the JSIteratorResult instance.
1007 AllocationBuilder a(jsgraph(), effect, graph()->start());
1008 a.Allocate(JSIteratorResult::kSize);
1009 a.Store(AccessBuilder::ForMap(), iterator_result_map);
1010 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
1011 jsgraph()->EmptyFixedArrayConstant());
1012 a.Store(AccessBuilder::ForJSObjectElements(),
1013 jsgraph()->EmptyFixedArrayConstant());
1014 a.Store(AccessBuilder::ForJSIteratorResultValue(), value);
1015 a.Store(AccessBuilder::ForJSIteratorResultDone(), done);
1016 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kTaggedSize);
1017 a.FinishAndChange(node);
1018 return Changed(node);
1019 }
1020
ReduceJSCreateStringIterator(Node * node)1021 Reduction JSCreateLowering::ReduceJSCreateStringIterator(Node* node) {
1022 DCHECK_EQ(IrOpcode::kJSCreateStringIterator, node->opcode());
1023 Node* string = NodeProperties::GetValueInput(node, 0);
1024 Node* effect = NodeProperties::GetEffectInput(node);
1025
1026 Node* map =
1027 jsgraph()->Constant(native_context().initial_string_iterator_map());
1028 // Allocate new iterator and attach the iterator to this string.
1029 AllocationBuilder a(jsgraph(), effect, graph()->start());
1030 a.Allocate(JSStringIterator::kHeaderSize, AllocationType::kYoung,
1031 Type::OtherObject());
1032 a.Store(AccessBuilder::ForMap(), map);
1033 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
1034 jsgraph()->EmptyFixedArrayConstant());
1035 a.Store(AccessBuilder::ForJSObjectElements(),
1036 jsgraph()->EmptyFixedArrayConstant());
1037 a.Store(AccessBuilder::ForJSStringIteratorString(), string);
1038 a.Store(AccessBuilder::ForJSStringIteratorIndex(), jsgraph()->SmiConstant(0));
1039 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kTaggedSize);
1040 a.FinishAndChange(node);
1041 return Changed(node);
1042 }
1043
ReduceJSCreateKeyValueArray(Node * node)1044 Reduction JSCreateLowering::ReduceJSCreateKeyValueArray(Node* node) {
1045 DCHECK_EQ(IrOpcode::kJSCreateKeyValueArray, node->opcode());
1046 Node* key = NodeProperties::GetValueInput(node, 0);
1047 Node* value = NodeProperties::GetValueInput(node, 1);
1048 Node* effect = NodeProperties::GetEffectInput(node);
1049
1050 Node* array_map =
1051 jsgraph()->Constant(native_context().js_array_packed_elements_map());
1052 Node* length = jsgraph()->Constant(2);
1053
1054 AllocationBuilder aa(jsgraph(), effect, graph()->start());
1055 aa.AllocateArray(2, MapRef(broker(), factory()->fixed_array_map()));
1056 aa.Store(AccessBuilder::ForFixedArrayElement(PACKED_ELEMENTS),
1057 jsgraph()->ZeroConstant(), key);
1058 aa.Store(AccessBuilder::ForFixedArrayElement(PACKED_ELEMENTS),
1059 jsgraph()->OneConstant(), value);
1060 Node* elements = aa.Finish();
1061
1062 AllocationBuilder a(jsgraph(), elements, graph()->start());
1063 a.Allocate(JSArray::kHeaderSize);
1064 a.Store(AccessBuilder::ForMap(), array_map);
1065 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
1066 jsgraph()->EmptyFixedArrayConstant());
1067 a.Store(AccessBuilder::ForJSObjectElements(), elements);
1068 a.Store(AccessBuilder::ForJSArrayLength(PACKED_ELEMENTS), length);
1069 STATIC_ASSERT(JSArray::kHeaderSize == 4 * kTaggedSize);
1070 a.FinishAndChange(node);
1071 return Changed(node);
1072 }
1073
ReduceJSCreatePromise(Node * node)1074 Reduction JSCreateLowering::ReduceJSCreatePromise(Node* node) {
1075 DCHECK_EQ(IrOpcode::kJSCreatePromise, node->opcode());
1076 Node* effect = NodeProperties::GetEffectInput(node);
1077
1078 MapRef promise_map = native_context().promise_function().initial_map();
1079
1080 AllocationBuilder a(jsgraph(), effect, graph()->start());
1081 a.Allocate(promise_map.instance_size());
1082 a.Store(AccessBuilder::ForMap(), promise_map);
1083 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
1084 jsgraph()->EmptyFixedArrayConstant());
1085 a.Store(AccessBuilder::ForJSObjectElements(),
1086 jsgraph()->EmptyFixedArrayConstant());
1087 a.Store(AccessBuilder::ForJSObjectOffset(JSPromise::kReactionsOrResultOffset),
1088 jsgraph()->ZeroConstant());
1089 STATIC_ASSERT(v8::Promise::kPending == 0);
1090 a.Store(AccessBuilder::ForJSObjectOffset(JSPromise::kFlagsOffset),
1091 jsgraph()->ZeroConstant());
1092 STATIC_ASSERT(JSPromise::kHeaderSize == 5 * kTaggedSize);
1093 for (int offset = JSPromise::kHeaderSize;
1094 offset < JSPromise::kSizeWithEmbedderFields; offset += kTaggedSize) {
1095 a.Store(AccessBuilder::ForJSObjectOffset(offset),
1096 jsgraph()->ZeroConstant());
1097 }
1098 a.FinishAndChange(node);
1099 return Changed(node);
1100 }
1101
ReduceJSCreateLiteralArrayOrObject(Node * node)1102 Reduction JSCreateLowering::ReduceJSCreateLiteralArrayOrObject(Node* node) {
1103 DCHECK(node->opcode() == IrOpcode::kJSCreateLiteralArray ||
1104 node->opcode() == IrOpcode::kJSCreateLiteralObject);
1105 JSCreateLiteralOpNode n(node);
1106 CreateLiteralParameters const& p = n.Parameters();
1107 Effect effect = n.effect();
1108 Control control = n.control();
1109 ProcessedFeedback const& feedback =
1110 broker()->GetFeedbackForArrayOrObjectLiteral(p.feedback());
1111 if (!feedback.IsInsufficient()) {
1112 AllocationSiteRef site = feedback.AsLiteral().value();
1113 if (site.IsFastLiteral()) {
1114 AllocationType allocation = AllocationType::kYoung;
1115 if (FLAG_allocation_site_pretenuring) {
1116 allocation = dependencies()->DependOnPretenureMode(site);
1117 }
1118 dependencies()->DependOnElementsKinds(site);
1119 JSObjectRef boilerplate = site.boilerplate().value();
1120 Node* value = effect =
1121 AllocateFastLiteral(effect, control, boilerplate, allocation);
1122 ReplaceWithValue(node, value, effect, control);
1123 return Replace(value);
1124 }
1125 }
1126
1127 return NoChange();
1128 }
1129
ReduceJSCreateEmptyLiteralArray(Node * node)1130 Reduction JSCreateLowering::ReduceJSCreateEmptyLiteralArray(Node* node) {
1131 JSCreateEmptyLiteralArrayNode n(node);
1132 FeedbackParameter const& p = n.Parameters();
1133 ProcessedFeedback const& feedback =
1134 broker()->GetFeedbackForArrayOrObjectLiteral(p.feedback());
1135 if (!feedback.IsInsufficient()) {
1136 AllocationSiteRef site = feedback.AsLiteral().value();
1137 DCHECK(!site.PointsToLiteral());
1138 MapRef initial_map =
1139 native_context().GetInitialJSArrayMap(site.GetElementsKind());
1140 AllocationType const allocation =
1141 dependencies()->DependOnPretenureMode(site);
1142 dependencies()->DependOnElementsKind(site);
1143 Node* length = jsgraph()->ZeroConstant();
1144 DCHECK(!initial_map.IsInobjectSlackTrackingInProgress());
1145 SlackTrackingPrediction slack_tracking_prediction(
1146 initial_map, initial_map.instance_size());
1147 return ReduceNewArray(node, length, 0, initial_map,
1148 initial_map.elements_kind(), allocation,
1149 slack_tracking_prediction);
1150 }
1151 return NoChange();
1152 }
1153
ReduceJSCreateEmptyLiteralObject(Node * node)1154 Reduction JSCreateLowering::ReduceJSCreateEmptyLiteralObject(Node* node) {
1155 DCHECK_EQ(IrOpcode::kJSCreateEmptyLiteralObject, node->opcode());
1156 Node* effect = NodeProperties::GetEffectInput(node);
1157 Node* control = NodeProperties::GetControlInput(node);
1158
1159 // Retrieve the initial map for the object.
1160 MapRef map = native_context().object_function().initial_map();
1161 DCHECK(!map.is_dictionary_map());
1162 DCHECK(!map.IsInobjectSlackTrackingInProgress());
1163 Node* js_object_map = jsgraph()->Constant(map);
1164
1165 // Setup elements and properties.
1166 Node* elements = jsgraph()->EmptyFixedArrayConstant();
1167
1168 // Perform the allocation of the actual JSArray object.
1169 AllocationBuilder a(jsgraph(), effect, control);
1170 a.Allocate(map.instance_size());
1171 a.Store(AccessBuilder::ForMap(), js_object_map);
1172 a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
1173 jsgraph()->EmptyFixedArrayConstant());
1174 a.Store(AccessBuilder::ForJSObjectElements(), elements);
1175 for (int i = 0; i < map.GetInObjectProperties(); i++) {
1176 a.Store(AccessBuilder::ForJSObjectInObjectProperty(map, i),
1177 jsgraph()->UndefinedConstant());
1178 }
1179
1180 RelaxControls(node);
1181 a.FinishAndChange(node);
1182 return Changed(node);
1183 }
1184
ReduceJSCreateLiteralRegExp(Node * node)1185 Reduction JSCreateLowering::ReduceJSCreateLiteralRegExp(Node* node) {
1186 JSCreateLiteralRegExpNode n(node);
1187 CreateLiteralParameters const& p = n.Parameters();
1188 Effect effect = n.effect();
1189 Control control = n.control();
1190 ProcessedFeedback const& feedback =
1191 broker()->GetFeedbackForRegExpLiteral(p.feedback());
1192 if (!feedback.IsInsufficient()) {
1193 JSRegExpRef literal = feedback.AsRegExpLiteral().value();
1194 Node* value = effect = AllocateLiteralRegExp(effect, control, literal);
1195 ReplaceWithValue(node, value, effect, control);
1196 return Replace(value);
1197 }
1198 return NoChange();
1199 }
1200
ReduceJSGetTemplateObject(Node * node)1201 Reduction JSCreateLowering::ReduceJSGetTemplateObject(Node* node) {
1202 JSGetTemplateObjectNode n(node);
1203 GetTemplateObjectParameters const& parameters = n.Parameters();
1204 SharedFunctionInfoRef shared(broker(), parameters.shared());
1205 JSArrayRef template_object = shared.GetTemplateObject(
1206 TemplateObjectDescriptionRef(broker(), parameters.description()),
1207 parameters.feedback());
1208 Node* value = jsgraph()->Constant(template_object);
1209 ReplaceWithValue(node, value);
1210 return Replace(value);
1211 }
1212
ReduceJSCreateFunctionContext(Node * node)1213 Reduction JSCreateLowering::ReduceJSCreateFunctionContext(Node* node) {
1214 DCHECK_EQ(IrOpcode::kJSCreateFunctionContext, node->opcode());
1215 const CreateFunctionContextParameters& parameters =
1216 CreateFunctionContextParametersOf(node->op());
1217 ScopeInfoRef scope_info(broker(), parameters.scope_info());
1218 int slot_count = parameters.slot_count();
1219 ScopeType scope_type = parameters.scope_type();
1220
1221 // Use inline allocation for function contexts up to a size limit.
1222 if (slot_count < kFunctionContextAllocationLimit) {
1223 // JSCreateFunctionContext[slot_count < limit]](fun)
1224 Node* effect = NodeProperties::GetEffectInput(node);
1225 Node* control = NodeProperties::GetControlInput(node);
1226 Node* context = NodeProperties::GetContextInput(node);
1227 AllocationBuilder a(jsgraph(), effect, control);
1228 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 2); // Ensure fully covered.
1229 int context_length = slot_count + Context::MIN_CONTEXT_SLOTS;
1230 switch (scope_type) {
1231 case EVAL_SCOPE:
1232 a.AllocateContext(context_length, native_context().eval_context_map());
1233 break;
1234 case FUNCTION_SCOPE:
1235 a.AllocateContext(context_length,
1236 native_context().function_context_map());
1237 break;
1238 default:
1239 UNREACHABLE();
1240 }
1241 a.Store(AccessBuilder::ForContextSlot(Context::SCOPE_INFO_INDEX),
1242 scope_info);
1243 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
1244 for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) {
1245 a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant());
1246 }
1247 RelaxControls(node);
1248 a.FinishAndChange(node);
1249 return Changed(node);
1250 }
1251
1252 return NoChange();
1253 }
1254
ReduceJSCreateWithContext(Node * node)1255 Reduction JSCreateLowering::ReduceJSCreateWithContext(Node* node) {
1256 DCHECK_EQ(IrOpcode::kJSCreateWithContext, node->opcode());
1257 ScopeInfoRef scope_info(broker(), ScopeInfoOf(node->op()));
1258 Node* extension = NodeProperties::GetValueInput(node, 0);
1259 Node* effect = NodeProperties::GetEffectInput(node);
1260 Node* control = NodeProperties::GetControlInput(node);
1261 Node* context = NodeProperties::GetContextInput(node);
1262
1263 AllocationBuilder a(jsgraph(), effect, control);
1264 STATIC_ASSERT(Context::MIN_CONTEXT_EXTENDED_SLOTS ==
1265 3); // Ensure fully covered.
1266 a.AllocateContext(Context::MIN_CONTEXT_EXTENDED_SLOTS,
1267 native_context().with_context_map());
1268 a.Store(AccessBuilder::ForContextSlot(Context::SCOPE_INFO_INDEX), scope_info);
1269 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
1270 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
1271 RelaxControls(node);
1272 a.FinishAndChange(node);
1273 return Changed(node);
1274 }
1275
ReduceJSCreateCatchContext(Node * node)1276 Reduction JSCreateLowering::ReduceJSCreateCatchContext(Node* node) {
1277 DCHECK_EQ(IrOpcode::kJSCreateCatchContext, node->opcode());
1278 ScopeInfoRef scope_info(broker(), ScopeInfoOf(node->op()));
1279 Node* exception = NodeProperties::GetValueInput(node, 0);
1280 Node* effect = NodeProperties::GetEffectInput(node);
1281 Node* control = NodeProperties::GetControlInput(node);
1282 Node* context = NodeProperties::GetContextInput(node);
1283
1284 AllocationBuilder a(jsgraph(), effect, control);
1285 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 2); // Ensure fully covered.
1286 a.AllocateContext(Context::MIN_CONTEXT_SLOTS + 1,
1287 native_context().catch_context_map());
1288 a.Store(AccessBuilder::ForContextSlot(Context::SCOPE_INFO_INDEX), scope_info);
1289 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
1290 a.Store(AccessBuilder::ForContextSlot(Context::THROWN_OBJECT_INDEX),
1291 exception);
1292 RelaxControls(node);
1293 a.FinishAndChange(node);
1294 return Changed(node);
1295 }
1296
ReduceJSCreateBlockContext(Node * node)1297 Reduction JSCreateLowering::ReduceJSCreateBlockContext(Node* node) {
1298 DCHECK_EQ(IrOpcode::kJSCreateBlockContext, node->opcode());
1299 ScopeInfoRef scope_info(broker(), ScopeInfoOf(node->op()));
1300 int const context_length = scope_info.ContextLength();
1301
1302 // Use inline allocation for block contexts up to a size limit.
1303 if (context_length < kBlockContextAllocationLimit) {
1304 // JSCreateBlockContext[scope[length < limit]](fun)
1305 Node* effect = NodeProperties::GetEffectInput(node);
1306 Node* control = NodeProperties::GetControlInput(node);
1307 Node* context = NodeProperties::GetContextInput(node);
1308
1309 AllocationBuilder a(jsgraph(), effect, control);
1310 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 2); // Ensure fully covered.
1311 a.AllocateContext(context_length, native_context().block_context_map());
1312 a.Store(AccessBuilder::ForContextSlot(Context::SCOPE_INFO_INDEX),
1313 scope_info);
1314 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
1315 for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) {
1316 a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant());
1317 }
1318 RelaxControls(node);
1319 a.FinishAndChange(node);
1320 return Changed(node);
1321 }
1322
1323 return NoChange();
1324 }
1325
1326 namespace {
GetObjectCreateMap(JSHeapBroker * broker,HeapObjectRef prototype)1327 base::Optional<MapRef> GetObjectCreateMap(JSHeapBroker* broker,
1328 HeapObjectRef prototype) {
1329 MapRef standard_map =
1330 broker->target_native_context().object_function().initial_map();
1331 if (prototype.equals(standard_map.prototype())) {
1332 return standard_map;
1333 }
1334 if (prototype.map().oddball_type() == OddballType::kNull) {
1335 return broker->target_native_context()
1336 .slow_object_with_null_prototype_map();
1337 }
1338 if (prototype.IsJSObject()) {
1339 return prototype.AsJSObject().GetObjectCreateMap();
1340 }
1341 return base::Optional<MapRef>();
1342 }
1343 } // namespace
1344
ReduceJSCreateObject(Node * node)1345 Reduction JSCreateLowering::ReduceJSCreateObject(Node* node) {
1346 DCHECK_EQ(IrOpcode::kJSCreateObject, node->opcode());
1347 Node* effect = NodeProperties::GetEffectInput(node);
1348 Node* control = NodeProperties::GetControlInput(node);
1349 Node* prototype = NodeProperties::GetValueInput(node, 0);
1350 Type prototype_type = NodeProperties::GetType(prototype);
1351 if (!prototype_type.IsHeapConstant()) return NoChange();
1352
1353 HeapObjectRef prototype_const = prototype_type.AsHeapConstant()->Ref();
1354 auto maybe_instance_map = GetObjectCreateMap(broker(), prototype_const);
1355 if (!maybe_instance_map) return NoChange();
1356 MapRef instance_map = maybe_instance_map.value();
1357
1358 Node* properties = jsgraph()->EmptyFixedArrayConstant();
1359 if (instance_map.is_dictionary_map()) {
1360 DCHECK_EQ(prototype_const.map().oddball_type(), OddballType::kNull);
1361 // Allocate an empty NameDictionary as backing store for the properties.
1362 MapRef map(broker(), factory()->name_dictionary_map());
1363 int capacity =
1364 NameDictionary::ComputeCapacity(NameDictionary::kInitialCapacity);
1365 DCHECK(base::bits::IsPowerOfTwo(capacity));
1366 int length = NameDictionary::EntryToIndex(InternalIndex(capacity));
1367 int size = NameDictionary::SizeFor(length);
1368
1369 AllocationBuilder a(jsgraph(), effect, control);
1370 a.Allocate(size, AllocationType::kYoung, Type::Any());
1371 a.Store(AccessBuilder::ForMap(), map);
1372 // Initialize FixedArray fields.
1373 a.Store(AccessBuilder::ForFixedArrayLength(),
1374 jsgraph()->SmiConstant(length));
1375 // Initialize HashTable fields.
1376 a.Store(AccessBuilder::ForHashTableBaseNumberOfElements(),
1377 jsgraph()->SmiConstant(0));
1378 a.Store(AccessBuilder::ForHashTableBaseNumberOfDeletedElement(),
1379 jsgraph()->SmiConstant(0));
1380 a.Store(AccessBuilder::ForHashTableBaseCapacity(),
1381 jsgraph()->SmiConstant(capacity));
1382 // Initialize Dictionary fields.
1383 a.Store(AccessBuilder::ForDictionaryNextEnumerationIndex(),
1384 jsgraph()->SmiConstant(PropertyDetails::kInitialIndex));
1385 a.Store(AccessBuilder::ForDictionaryObjectHashIndex(),
1386 jsgraph()->SmiConstant(PropertyArray::kNoHashSentinel));
1387 // Initialize the Properties fields.
1388 Node* undefined = jsgraph()->UndefinedConstant();
1389 STATIC_ASSERT(NameDictionary::kElementsStartIndex ==
1390 NameDictionary::kObjectHashIndex + 1);
1391 for (int index = NameDictionary::kElementsStartIndex; index < length;
1392 index++) {
1393 a.Store(AccessBuilder::ForFixedArraySlot(index, kNoWriteBarrier),
1394 undefined);
1395 }
1396 properties = effect = a.Finish();
1397 }
1398
1399 int const instance_size = instance_map.instance_size();
1400 if (instance_size > kMaxRegularHeapObjectSize) return NoChange();
1401 CHECK(!instance_map.IsInobjectSlackTrackingInProgress());
1402
1403 // Emit code to allocate the JSObject instance for the given
1404 // {instance_map}.
1405 AllocationBuilder a(jsgraph(), effect, control);
1406 a.Allocate(instance_size, AllocationType::kYoung, Type::Any());
1407 a.Store(AccessBuilder::ForMap(), instance_map);
1408 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
1409 a.Store(AccessBuilder::ForJSObjectElements(),
1410 jsgraph()->EmptyFixedArrayConstant());
1411 // Initialize Object fields.
1412 Node* undefined = jsgraph()->UndefinedConstant();
1413 for (int offset = JSObject::kHeaderSize; offset < instance_size;
1414 offset += kTaggedSize) {
1415 a.Store(AccessBuilder::ForJSObjectOffset(offset, kNoWriteBarrier),
1416 undefined);
1417 }
1418 Node* value = effect = a.Finish();
1419
1420 ReplaceWithValue(node, value, effect, control);
1421 return Replace(value);
1422 }
1423
1424 // Helper that allocates a FixedArray holding argument values recorded in the
1425 // given {frame_state}. Serves as backing store for JSCreateArguments nodes.
AllocateArguments(Node * effect,Node * control,Node * frame_state)1426 Node* JSCreateLowering::AllocateArguments(Node* effect, Node* control,
1427 Node* frame_state) {
1428 FrameStateInfo state_info = FrameStateInfoOf(frame_state->op());
1429 int argument_count = state_info.parameter_count() - 1; // Minus receiver.
1430 if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant();
1431
1432 // Prepare an iterator over argument values recorded in the frame state.
1433 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
1434 StateValuesAccess parameters_access(parameters);
1435 auto parameters_it = ++parameters_access.begin();
1436
1437 // Actually allocate the backing store.
1438 AllocationBuilder a(jsgraph(), effect, control);
1439 a.AllocateArray(argument_count,
1440 MapRef(broker(), factory()->fixed_array_map()));
1441 for (int i = 0; i < argument_count; ++i, ++parameters_it) {
1442 DCHECK_NOT_NULL(parameters_it.node());
1443 a.Store(AccessBuilder::ForFixedArrayElement(), jsgraph()->Constant(i),
1444 parameters_it.node());
1445 }
1446 return a.Finish();
1447 }
1448
1449 // Helper that allocates a FixedArray holding argument values recorded in the
1450 // given {frame_state}. Serves as backing store for JSCreateArguments nodes.
AllocateRestArguments(Node * effect,Node * control,Node * frame_state,int start_index)1451 Node* JSCreateLowering::AllocateRestArguments(Node* effect, Node* control,
1452 Node* frame_state,
1453 int start_index) {
1454 FrameStateInfo state_info = FrameStateInfoOf(frame_state->op());
1455 int argument_count = state_info.parameter_count() - 1; // Minus receiver.
1456 int num_elements = std::max(0, argument_count - start_index);
1457 if (num_elements == 0) return jsgraph()->EmptyFixedArrayConstant();
1458
1459 // Prepare an iterator over argument values recorded in the frame state.
1460 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
1461 StateValuesAccess parameters_access(parameters);
1462 auto parameters_it = ++parameters_access.begin();
1463
1464 // Skip unused arguments.
1465 for (int i = 0; i < start_index; i++) {
1466 ++parameters_it;
1467 }
1468
1469 // Actually allocate the backing store.
1470 AllocationBuilder a(jsgraph(), effect, control);
1471 a.AllocateArray(num_elements, MapRef(broker(), factory()->fixed_array_map()));
1472 for (int i = 0; i < num_elements; ++i, ++parameters_it) {
1473 DCHECK_NOT_NULL(parameters_it.node());
1474 a.Store(AccessBuilder::ForFixedArrayElement(), jsgraph()->Constant(i),
1475 parameters_it.node());
1476 }
1477 return a.Finish();
1478 }
1479
1480 // Helper that allocates a FixedArray serving as a parameter map for values
1481 // recorded in the given {frame_state}. Some elements map to slots within the
1482 // given {context}. Serves as backing store for JSCreateArguments nodes.
AllocateAliasedArguments(Node * effect,Node * control,Node * frame_state,Node * context,const SharedFunctionInfoRef & shared,bool * has_aliased_arguments)1483 Node* JSCreateLowering::AllocateAliasedArguments(
1484 Node* effect, Node* control, Node* frame_state, Node* context,
1485 const SharedFunctionInfoRef& shared, bool* has_aliased_arguments) {
1486 FrameStateInfo state_info = FrameStateInfoOf(frame_state->op());
1487 int argument_count = state_info.parameter_count() - 1; // Minus receiver.
1488 if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant();
1489
1490 // If there is no aliasing, the arguments object elements are not special in
1491 // any way, we can just return an unmapped backing store instead.
1492 int parameter_count = shared.internal_formal_parameter_count();
1493 if (parameter_count == 0) {
1494 return AllocateArguments(effect, control, frame_state);
1495 }
1496
1497 // Calculate number of argument values being aliased/mapped.
1498 int mapped_count = std::min(argument_count, parameter_count);
1499 *has_aliased_arguments = true;
1500
1501 // Prepare an iterator over argument values recorded in the frame state.
1502 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
1503 StateValuesAccess parameters_access(parameters);
1504 auto parameters_it = ++parameters_access.begin();
1505
1506 // The unmapped argument values recorded in the frame state are stored yet
1507 // another indirection away and then linked into the parameter map below,
1508 // whereas mapped argument values are replaced with a hole instead.
1509 AllocationBuilder aa(jsgraph(), effect, control);
1510 aa.AllocateArray(argument_count,
1511 MapRef(broker(), factory()->fixed_array_map()));
1512 for (int i = 0; i < mapped_count; ++i, ++parameters_it) {
1513 aa.Store(AccessBuilder::ForFixedArrayElement(), jsgraph()->Constant(i),
1514 jsgraph()->TheHoleConstant());
1515 }
1516 for (int i = mapped_count; i < argument_count; ++i, ++parameters_it) {
1517 DCHECK_NOT_NULL(parameters_it.node());
1518 aa.Store(AccessBuilder::ForFixedArrayElement(), jsgraph()->Constant(i),
1519 parameters_it.node());
1520 }
1521 Node* arguments = aa.Finish();
1522
1523 // Actually allocate the backing store.
1524 AllocationBuilder a(jsgraph(), arguments, control);
1525 a.AllocateSloppyArgumentElements(
1526 mapped_count,
1527 MapRef(broker(), factory()->sloppy_arguments_elements_map()));
1528 a.Store(AccessBuilder::ForSloppyArgumentsElementsContext(), context);
1529 a.Store(AccessBuilder::ForSloppyArgumentsElementsArguments(), arguments);
1530 for (int i = 0; i < mapped_count; ++i) {
1531 int idx = shared.context_header_size() + parameter_count - 1 - i;
1532 a.Store(AccessBuilder::ForSloppyArgumentsElementsMappedEntry(),
1533 jsgraph()->Constant(i), jsgraph()->Constant(idx));
1534 }
1535 return a.Finish();
1536 }
1537
1538 // Helper that allocates a FixedArray serving as a parameter map for values
1539 // unknown at compile-time, the true {arguments_length} and {arguments_frame}
1540 // values can only be determined dynamically at run-time and are provided.
1541 // Serves as backing store for JSCreateArguments nodes.
AllocateAliasedArguments(Node * effect,Node * control,Node * context,Node * arguments_frame,Node * arguments_length,const SharedFunctionInfoRef & shared,bool * has_aliased_arguments)1542 Node* JSCreateLowering::AllocateAliasedArguments(
1543 Node* effect, Node* control, Node* context, Node* arguments_frame,
1544 Node* arguments_length, const SharedFunctionInfoRef& shared,
1545 bool* has_aliased_arguments) {
1546 // If there is no aliasing, the arguments object elements are not
1547 // special in any way, we can just return an unmapped backing store.
1548 int parameter_count = shared.internal_formal_parameter_count();
1549 if (parameter_count == 0) {
1550 return graph()->NewNode(
1551 simplified()->NewArgumentsElements(
1552 CreateArgumentsType::kUnmappedArguments, parameter_count),
1553 arguments_frame, arguments_length, effect);
1554 }
1555
1556 // From here on we are going to allocate a mapped (aka. aliased) elements
1557 // backing store. We do not statically know how many arguments exist, but
1558 // dynamically selecting the hole for some of the "mapped" elements allows
1559 // using a static shape for the parameter map.
1560 int mapped_count = parameter_count;
1561 *has_aliased_arguments = true;
1562
1563 // The unmapped argument values are stored yet another indirection away and
1564 // then linked into the parameter map below, whereas mapped argument values
1565 // (i.e. the first {mapped_count} elements) are replaced with a hole instead.
1566 Node* arguments = effect =
1567 graph()->NewNode(simplified()->NewArgumentsElements(
1568 CreateArgumentsType::kMappedArguments, mapped_count),
1569 arguments_frame, arguments_length, effect);
1570
1571 // Actually allocate the backing store.
1572 AllocationBuilder a(jsgraph(), effect, control);
1573 a.AllocateSloppyArgumentElements(
1574 mapped_count,
1575 MapRef(broker(), factory()->sloppy_arguments_elements_map()));
1576 a.Store(AccessBuilder::ForSloppyArgumentsElementsContext(), context);
1577 a.Store(AccessBuilder::ForSloppyArgumentsElementsArguments(), arguments);
1578 for (int i = 0; i < mapped_count; ++i) {
1579 int idx = shared.context_header_size() + parameter_count - 1 - i;
1580 Node* value = graph()->NewNode(
1581 common()->Select(MachineRepresentation::kTagged),
1582 graph()->NewNode(simplified()->NumberLessThan(), jsgraph()->Constant(i),
1583 arguments_length),
1584 jsgraph()->Constant(idx), jsgraph()->TheHoleConstant());
1585 a.Store(AccessBuilder::ForSloppyArgumentsElementsMappedEntry(),
1586 jsgraph()->Constant(i), value);
1587 }
1588 return a.Finish();
1589 }
1590
AllocateElements(Node * effect,Node * control,ElementsKind elements_kind,int capacity,AllocationType allocation)1591 Node* JSCreateLowering::AllocateElements(Node* effect, Node* control,
1592 ElementsKind elements_kind,
1593 int capacity,
1594 AllocationType allocation) {
1595 DCHECK_LE(1, capacity);
1596 DCHECK_LE(capacity, JSArray::kInitialMaxFastElementArray);
1597
1598 Handle<Map> elements_map = IsDoubleElementsKind(elements_kind)
1599 ? factory()->fixed_double_array_map()
1600 : factory()->fixed_array_map();
1601 ElementAccess access = IsDoubleElementsKind(elements_kind)
1602 ? AccessBuilder::ForFixedDoubleArrayElement()
1603 : AccessBuilder::ForFixedArrayElement();
1604 Node* value = jsgraph()->TheHoleConstant();
1605
1606 // Actually allocate the backing store.
1607 AllocationBuilder a(jsgraph(), effect, control);
1608 a.AllocateArray(capacity, MapRef(broker(), elements_map), allocation);
1609 for (int i = 0; i < capacity; ++i) {
1610 Node* index = jsgraph()->Constant(i);
1611 a.Store(access, index, value);
1612 }
1613 return a.Finish();
1614 }
1615
AllocateElements(Node * effect,Node * control,ElementsKind elements_kind,std::vector<Node * > const & values,AllocationType allocation)1616 Node* JSCreateLowering::AllocateElements(Node* effect, Node* control,
1617 ElementsKind elements_kind,
1618 std::vector<Node*> const& values,
1619 AllocationType allocation) {
1620 int const capacity = static_cast<int>(values.size());
1621 DCHECK_LE(1, capacity);
1622 DCHECK_LE(capacity, JSArray::kInitialMaxFastElementArray);
1623
1624 Handle<Map> elements_map = IsDoubleElementsKind(elements_kind)
1625 ? factory()->fixed_double_array_map()
1626 : factory()->fixed_array_map();
1627 ElementAccess access = IsDoubleElementsKind(elements_kind)
1628 ? AccessBuilder::ForFixedDoubleArrayElement()
1629 : AccessBuilder::ForFixedArrayElement();
1630
1631 // Actually allocate the backing store.
1632 AllocationBuilder a(jsgraph(), effect, control);
1633 a.AllocateArray(capacity, MapRef(broker(), elements_map), allocation);
1634 for (int i = 0; i < capacity; ++i) {
1635 Node* index = jsgraph()->Constant(i);
1636 a.Store(access, index, values[i]);
1637 }
1638 return a.Finish();
1639 }
1640
AllocateFastLiteral(Node * effect,Node * control,JSObjectRef boilerplate,AllocationType allocation)1641 Node* JSCreateLowering::AllocateFastLiteral(Node* effect, Node* control,
1642 JSObjectRef boilerplate,
1643 AllocationType allocation) {
1644 // Compute the in-object properties to store first (might have effects).
1645 MapRef boilerplate_map = boilerplate.map();
1646 ZoneVector<std::pair<FieldAccess, Node*>> inobject_fields(zone());
1647 inobject_fields.reserve(boilerplate_map.GetInObjectProperties());
1648 int const boilerplate_nof = boilerplate_map.NumberOfOwnDescriptors();
1649 for (InternalIndex i : InternalIndex::Range(boilerplate_nof)) {
1650 PropertyDetails const property_details =
1651 boilerplate_map.GetPropertyDetails(i);
1652 if (property_details.location() != kField) continue;
1653 DCHECK_EQ(kData, property_details.kind());
1654 NameRef property_name = boilerplate_map.GetPropertyKey(i);
1655 FieldIndex index = boilerplate_map.GetFieldIndexFor(i);
1656 ConstFieldInfo const_field_info(boilerplate_map.object());
1657 FieldAccess access = {kTaggedBase,
1658 index.offset(),
1659 property_name.object(),
1660 MaybeHandle<Map>(),
1661 Type::Any(),
1662 MachineType::AnyTagged(),
1663 kFullWriteBarrier,
1664 LoadSensitivity::kUnsafe,
1665 const_field_info};
1666 Node* value;
1667 if (boilerplate_map.IsUnboxedDoubleField(i)) {
1668 access.machine_type = MachineType::Float64();
1669 access.type = Type::Number();
1670 uint64_t value_bits = boilerplate.RawFastDoublePropertyAsBitsAt(index);
1671 if (value_bits == kHoleNanInt64) {
1672 // This special case is analogous to is_uninitialized being true in the
1673 // non-unboxed-double case below. The store of the hole NaN value here
1674 // will always be followed by another store that actually initializes
1675 // the field. The hole NaN should therefore be unobservable.
1676 // Load elimination expects there to be at most one const store to any
1677 // given field, so we always mark the unobservable ones as mutable.
1678 access.const_field_info = ConstFieldInfo::None();
1679 }
1680 value = jsgraph()->Constant(bit_cast<double>(value_bits));
1681 } else {
1682 ObjectRef boilerplate_value = boilerplate.RawFastPropertyAt(index);
1683 bool is_uninitialized =
1684 boilerplate_value.IsHeapObject() &&
1685 boilerplate_value.AsHeapObject().map().oddball_type() ==
1686 OddballType::kUninitialized;
1687 if (is_uninitialized) {
1688 access.const_field_info = ConstFieldInfo::None();
1689 }
1690 if (boilerplate_value.IsJSObject()) {
1691 JSObjectRef boilerplate_object = boilerplate_value.AsJSObject();
1692 value = effect = AllocateFastLiteral(effect, control,
1693 boilerplate_object, allocation);
1694 } else if (property_details.representation().IsDouble()) {
1695 double number = boilerplate_value.AsHeapNumber().value();
1696 // Allocate a mutable HeapNumber box and store the value into it.
1697 AllocationBuilder builder(jsgraph(), effect, control);
1698 builder.Allocate(HeapNumber::kSize, allocation);
1699 builder.Store(AccessBuilder::ForMap(),
1700 MapRef(broker(), factory()->heap_number_map()));
1701 builder.Store(AccessBuilder::ForHeapNumberValue(),
1702 jsgraph()->Constant(number));
1703 value = effect = builder.Finish();
1704 } else if (property_details.representation().IsSmi()) {
1705 // Ensure that value is stored as smi.
1706 value = is_uninitialized
1707 ? jsgraph()->ZeroConstant()
1708 : jsgraph()->Constant(boilerplate_value.AsSmi());
1709 } else {
1710 value = jsgraph()->Constant(boilerplate_value);
1711 }
1712 }
1713 inobject_fields.push_back(std::make_pair(access, value));
1714 }
1715
1716 // Fill slack at the end of the boilerplate object with filler maps.
1717 int const boilerplate_length = boilerplate_map.GetInObjectProperties();
1718 for (int index = static_cast<int>(inobject_fields.size());
1719 index < boilerplate_length; ++index) {
1720 FieldAccess access =
1721 AccessBuilder::ForJSObjectInObjectProperty(boilerplate_map, index);
1722 Node* value = jsgraph()->HeapConstant(factory()->one_pointer_filler_map());
1723 inobject_fields.push_back(std::make_pair(access, value));
1724 }
1725
1726 // Setup the elements backing store.
1727 Node* elements =
1728 AllocateFastLiteralElements(effect, control, boilerplate, allocation);
1729 if (elements->op()->EffectOutputCount() > 0) effect = elements;
1730
1731 // Actually allocate and initialize the object.
1732 AllocationBuilder builder(jsgraph(), effect, control);
1733 builder.Allocate(boilerplate_map.instance_size(), allocation,
1734 Type::For(boilerplate_map));
1735 builder.Store(AccessBuilder::ForMap(), boilerplate_map);
1736 builder.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
1737 jsgraph()->EmptyFixedArrayConstant());
1738 builder.Store(AccessBuilder::ForJSObjectElements(), elements);
1739 if (boilerplate.IsJSArray()) {
1740 JSArrayRef boilerplate_array = boilerplate.AsJSArray();
1741 builder.Store(
1742 AccessBuilder::ForJSArrayLength(boilerplate_array.GetElementsKind()),
1743 boilerplate_array.length());
1744 }
1745 for (auto const& inobject_field : inobject_fields) {
1746 builder.Store(inobject_field.first, inobject_field.second);
1747 }
1748 return builder.Finish();
1749 }
1750
AllocateFastLiteralElements(Node * effect,Node * control,JSObjectRef boilerplate,AllocationType allocation)1751 Node* JSCreateLowering::AllocateFastLiteralElements(Node* effect, Node* control,
1752 JSObjectRef boilerplate,
1753 AllocationType allocation) {
1754 FixedArrayBaseRef boilerplate_elements = boilerplate.elements();
1755
1756 // Empty or copy-on-write elements just store a constant.
1757 int const elements_length = boilerplate_elements.length();
1758 MapRef elements_map = boilerplate_elements.map();
1759 if (boilerplate_elements.length() == 0 || elements_map.IsFixedCowArrayMap()) {
1760 if (allocation == AllocationType::kOld) {
1761 boilerplate.EnsureElementsTenured();
1762 boilerplate_elements = boilerplate.elements();
1763 }
1764 return jsgraph()->HeapConstant(boilerplate_elements.object());
1765 }
1766
1767 // Compute the elements to store first (might have effects).
1768 ZoneVector<Node*> elements_values(elements_length, zone());
1769 if (elements_map.instance_type() == FIXED_DOUBLE_ARRAY_TYPE) {
1770 FixedDoubleArrayRef elements = boilerplate_elements.AsFixedDoubleArray();
1771 for (int i = 0; i < elements_length; ++i) {
1772 Float64 value = elements.get(i);
1773 if (value.is_hole_nan()) {
1774 elements_values[i] = jsgraph()->TheHoleConstant();
1775 } else {
1776 elements_values[i] = jsgraph()->Constant(value.get_scalar());
1777 }
1778 }
1779 } else {
1780 FixedArrayRef elements = boilerplate_elements.AsFixedArray();
1781 for (int i = 0; i < elements_length; ++i) {
1782 ObjectRef element_value = elements.get(i);
1783 if (element_value.IsJSObject()) {
1784 elements_values[i] = effect = AllocateFastLiteral(
1785 effect, control, element_value.AsJSObject(), allocation);
1786 } else {
1787 elements_values[i] = jsgraph()->Constant(element_value);
1788 }
1789 }
1790 }
1791
1792 // Allocate the backing store array and store the elements.
1793 AllocationBuilder builder(jsgraph(), effect, control);
1794 builder.AllocateArray(elements_length, elements_map, allocation);
1795 ElementAccess const access =
1796 (elements_map.instance_type() == FIXED_DOUBLE_ARRAY_TYPE)
1797 ? AccessBuilder::ForFixedDoubleArrayElement()
1798 : AccessBuilder::ForFixedArrayElement();
1799 for (int i = 0; i < elements_length; ++i) {
1800 builder.Store(access, jsgraph()->Constant(i), elements_values[i]);
1801 }
1802 return builder.Finish();
1803 }
1804
AllocateLiteralRegExp(Node * effect,Node * control,JSRegExpRef boilerplate)1805 Node* JSCreateLowering::AllocateLiteralRegExp(Node* effect, Node* control,
1806 JSRegExpRef boilerplate) {
1807 MapRef boilerplate_map = boilerplate.map();
1808
1809 // Sanity check that JSRegExp object layout hasn't changed.
1810 STATIC_ASSERT(static_cast<int>(JSRegExp::kDataOffset) ==
1811 static_cast<int>(JSObject::kHeaderSize));
1812 STATIC_ASSERT(JSRegExp::kSourceOffset == JSRegExp::kDataOffset + kTaggedSize);
1813 STATIC_ASSERT(JSRegExp::kFlagsOffset ==
1814 JSRegExp::kSourceOffset + kTaggedSize);
1815 STATIC_ASSERT(JSRegExp::kHeaderSize == JSRegExp::kFlagsOffset + kTaggedSize);
1816 STATIC_ASSERT(JSRegExp::kLastIndexOffset == JSRegExp::kHeaderSize);
1817 STATIC_ASSERT(JSRegExp::kInObjectFieldCount == 1); // LastIndex.
1818
1819 const AllocationType allocation = AllocationType::kYoung;
1820 const int size =
1821 JSRegExp::kHeaderSize + JSRegExp::kInObjectFieldCount * kTaggedSize;
1822
1823 AllocationBuilder builder(jsgraph(), effect, control);
1824 builder.Allocate(size, allocation, Type::For(boilerplate_map));
1825 builder.Store(AccessBuilder::ForMap(), boilerplate_map);
1826 builder.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
1827 boilerplate.raw_properties_or_hash());
1828 builder.Store(AccessBuilder::ForJSObjectElements(), boilerplate.elements());
1829
1830 builder.Store(AccessBuilder::ForJSRegExpData(), boilerplate.data());
1831 builder.Store(AccessBuilder::ForJSRegExpSource(), boilerplate.source());
1832 builder.Store(AccessBuilder::ForJSRegExpFlags(), boilerplate.flags());
1833 builder.Store(AccessBuilder::ForJSRegExpLastIndex(),
1834 boilerplate.last_index());
1835
1836 return builder.Finish();
1837 }
1838
factory() const1839 Factory* JSCreateLowering::factory() const {
1840 return jsgraph()->isolate()->factory();
1841 }
1842
graph() const1843 Graph* JSCreateLowering::graph() const { return jsgraph()->graph(); }
1844
common() const1845 CommonOperatorBuilder* JSCreateLowering::common() const {
1846 return jsgraph()->common();
1847 }
1848
simplified() const1849 SimplifiedOperatorBuilder* JSCreateLowering::simplified() const {
1850 return jsgraph()->simplified();
1851 }
1852
native_context() const1853 NativeContextRef JSCreateLowering::native_context() const {
1854 return broker()->target_native_context();
1855 }
1856
1857 } // namespace compiler
1858 } // namespace internal
1859 } // namespace v8
1860