v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
js-create-lowering.cc
Go to the documentation of this file.
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
6
7#include <optional>
8
18#include "src/compiler/node.h"
31
32namespace v8 {
33namespace internal {
34namespace compiler {
35
36namespace {
37
38// Retrieves the frame state holding actual argument values.
39FrameState GetArgumentsFrameState(FrameState frame_state) {
40 FrameState outer_state{NodeProperties::GetFrameStateInput(frame_state)};
41 return outer_state.frame_state_info().type() ==
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.
49const int kElementLoopUnrollLimit = 16;
50
51// Limits up to which context allocations are inlined.
52const int kFunctionContextAllocationLimit = 16;
53const int kBlockContextAllocationLimit = 16;
54
55} // namespace
56
58 switch (node->opcode()) {
59 case IrOpcode::kJSCreate:
60 return ReduceJSCreate(node);
61 case IrOpcode::kJSCreateArguments:
62 return ReduceJSCreateArguments(node);
63 case IrOpcode::kJSCreateArray:
64 return ReduceJSCreateArray(node);
65 case IrOpcode::kJSCreateArrayIterator:
66 return ReduceJSCreateArrayIterator(node);
67 case IrOpcode::kJSCreateAsyncFunctionObject:
69 case IrOpcode::kJSCreateBoundFunction:
70 return ReduceJSCreateBoundFunction(node);
71 case IrOpcode::kJSCreateClosure:
72 return ReduceJSCreateClosure(node);
73 case IrOpcode::kJSCreateCollectionIterator:
75 case IrOpcode::kJSCreateIterResultObject:
77 case IrOpcode::kJSCreateStringIterator:
79 case IrOpcode::kJSCreateKeyValueArray:
80 return ReduceJSCreateKeyValueArray(node);
81 case IrOpcode::kJSCreatePromise:
82 return ReduceJSCreatePromise(node);
83 case IrOpcode::kJSCreateLiteralArray:
84 case IrOpcode::kJSCreateLiteralObject:
86 case IrOpcode::kJSCreateLiteralRegExp:
87 return ReduceJSCreateLiteralRegExp(node);
88 case IrOpcode::kJSGetTemplateObject:
89 return ReduceJSGetTemplateObject(node);
90 case IrOpcode::kJSCreateEmptyLiteralArray:
92 case IrOpcode::kJSCreateEmptyLiteralObject:
94 case IrOpcode::kJSCreateFunctionContext:
96 case IrOpcode::kJSCreateWithContext:
97 return ReduceJSCreateWithContext(node);
98 case IrOpcode::kJSCreateCatchContext:
99 return ReduceJSCreateCatchContext(node);
100 case IrOpcode::kJSCreateBlockContext:
101 return ReduceJSCreateBlockContext(node);
102 case IrOpcode::kJSCreateGeneratorObject:
104 case IrOpcode::kJSCreateObject:
105 return ReduceJSCreateObject(node);
106 case IrOpcode::kJSCreateStringWrapper:
107 return ReduceJSCreateStringWrapper(node);
108 default:
109 break;
110 }
111 return NoChange();
112}
113
115 DCHECK_EQ(IrOpcode::kJSCreate, node->opcode());
117 Node* const effect = NodeProperties::GetEffectInput(node);
118 Node* const control = NodeProperties::GetControlInput(node);
119
120 OptionalMapRef initial_map = 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 =
127 original_constructor);
128
129 // Emit code to allocate the JSObject instance for the
130 // {original_constructor}.
131 AllocationBuilder a(jsgraph(), broker(), effect, control);
132 a.Allocate(slack_tracking_prediction.instance_size());
135 jsgraph()->EmptyFixedArrayConstant());
137 jsgraph()->EmptyFixedArrayConstant());
138 for (int i = 0; i < slack_tracking_prediction.inobject_property_count();
139 ++i) {
141 jsgraph()->UndefinedConstant());
142 }
143
144 RelaxControls(node);
145 a.FinishAndChange(node);
146 return Changed(node);
147}
148
150 DCHECK_EQ(IrOpcode::kJSCreateArguments, node->opcode());
153 Node* const control = graph()->start();
154 FrameStateInfo state_info = frame_state.frame_state_info();
155 SharedFunctionInfoRef shared =
156 MakeRef(broker(), state_info.shared_info().ToHandleChecked());
157
158 // Use the ArgumentsAccessStub for materializing both mapped and unmapped
159 // arguments object, but only for non-inlined (i.e. outermost) frames.
160 if (frame_state.outer_frame_state()->opcode() != IrOpcode::kFrameState) {
161 switch (type) {
163 // TODO(turbofan): Duplicate parameters are not handled yet.
164 if (shared.has_duplicate_parameters()) return NoChange();
165 Node* const callee = NodeProperties::GetValueInput(node, 0);
166 Node* const context = NodeProperties::GetContextInput(node);
167 Node* effect = NodeProperties::GetEffectInput(node);
168 Node* const arguments_length =
169 graph()->NewNode(simplified()->ArgumentsLength());
170 // Allocate the elements backing store.
171 bool has_aliased_arguments = false;
172 Node* const elements = effect = TryAllocateAliasedArguments(
173 effect, control, context, arguments_length, shared,
174 &has_aliased_arguments);
175 if (elements == nullptr) return NoChange();
176
177 // Load the arguments object map.
178 Node* const arguments_map = jsgraph()->ConstantNoHole(
179 has_aliased_arguments
180 ? native_context().fast_aliased_arguments_map(broker())
181 : native_context().sloppy_arguments_map(broker()),
182 broker());
183 // Actually allocate and initialize the arguments object.
184 AllocationBuilder a(jsgraph(), broker(), effect, control);
185 static_assert(JSSloppyArgumentsObject::kSize == 5 * kTaggedSize);
186 a.Allocate(JSSloppyArgumentsObject::kSize);
187 a.Store(AccessBuilder::ForMap(), arguments_map);
189 jsgraph()->EmptyFixedArrayConstant());
190 a.Store(AccessBuilder::ForJSObjectElements(), elements);
191 a.Store(AccessBuilder::ForArgumentsLength(), arguments_length);
192 a.Store(AccessBuilder::ForArgumentsCallee(), callee);
193 RelaxControls(node);
194 a.FinishAndChange(node);
195 return Changed(node);
196 }
198 Node* effect = NodeProperties::GetEffectInput(node);
199 Node* const arguments_length =
200 graph()->NewNode(simplified()->ArgumentsLength());
201 // Allocate the elements backing store.
202 Node* const elements = effect = graph()->NewNode(
203 simplified()->NewArgumentsElements(
205 shared.internal_formal_parameter_count_without_receiver()),
206 arguments_length, effect);
207 // Load the arguments object map.
208 Node* const arguments_map = jsgraph()->ConstantNoHole(
209 native_context().strict_arguments_map(broker()), broker());
210 // Actually allocate and initialize the arguments object.
211 AllocationBuilder a(jsgraph(), broker(), effect, control);
212 static_assert(JSStrictArgumentsObject::kSize == 4 * kTaggedSize);
213 a.Allocate(JSStrictArgumentsObject::kSize);
214 a.Store(AccessBuilder::ForMap(), arguments_map);
216 jsgraph()->EmptyFixedArrayConstant());
217 a.Store(AccessBuilder::ForJSObjectElements(), elements);
218 a.Store(AccessBuilder::ForArgumentsLength(), arguments_length);
219 RelaxControls(node);
220 a.FinishAndChange(node);
221 return Changed(node);
222 }
224 Node* effect = NodeProperties::GetEffectInput(node);
225 Node* const arguments_length =
226 graph()->NewNode(simplified()->ArgumentsLength());
227 Node* const rest_length = graph()->NewNode(simplified()->RestLength(
228 shared.internal_formal_parameter_count_without_receiver()));
229 // Allocate the elements backing store.
230 Node* const elements = effect = graph()->NewNode(
231 simplified()->NewArgumentsElements(
233 shared.internal_formal_parameter_count_without_receiver()),
234 arguments_length, effect);
235 // Load the JSArray object map.
236 Node* const jsarray_map = jsgraph()->ConstantNoHole(
237 native_context().js_array_packed_elements_map(broker()), broker());
238 // Actually allocate and initialize the jsarray.
239 AllocationBuilder a(jsgraph(), broker(), effect, control);
240 static_assert(JSArray::kHeaderSize == 4 * kTaggedSize);
241 a.Allocate(JSArray::kHeaderSize);
242 a.Store(AccessBuilder::ForMap(), jsarray_map);
244 jsgraph()->EmptyFixedArrayConstant());
245 a.Store(AccessBuilder::ForJSObjectElements(), elements);
247 RelaxControls(node);
248 a.FinishAndChange(node);
249 return Changed(node);
250 }
251 }
252 UNREACHABLE();
253 }
254 // Use inline allocation for all mapped arguments objects within inlined
255 // (i.e. non-outermost) frames, independent of the object size.
256 DCHECK_EQ(frame_state.outer_frame_state()->opcode(), IrOpcode::kFrameState);
257 switch (type) {
259 Node* const callee = NodeProperties::GetValueInput(node, 0);
260 Node* const context = NodeProperties::GetContextInput(node);
261 Node* effect = NodeProperties::GetEffectInput(node);
262 // TODO(turbofan): Duplicate parameters are not handled yet.
263 if (shared.has_duplicate_parameters()) return NoChange();
264 // Choose the correct frame state and frame state info depending on
265 // whether there conceptually is an inlined arguments frame in the call
266 // chain.
267 FrameState args_state = GetArgumentsFrameState(frame_state);
268 if (args_state.parameters()->opcode() == IrOpcode::kDeadValue) {
269 // This protects against an incompletely propagated DeadValue node.
270 // If the FrameState has a DeadValue input, then this node will be
271 // pruned anyway.
272 return NoChange();
273 }
274 FrameStateInfo args_state_info = args_state.frame_state_info();
275 int length = args_state_info.parameter_count() - 1; // Minus receiver.
276 // Prepare element backing store to be used by arguments object.
277 bool has_aliased_arguments = false;
278 Node* const elements = TryAllocateAliasedArguments(
279 effect, control, args_state, context, shared, &has_aliased_arguments);
280 if (elements == nullptr) return NoChange();
281 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
282 // Load the arguments object map.
283 Node* const arguments_map = jsgraph()->ConstantNoHole(
284 has_aliased_arguments
285 ? native_context().fast_aliased_arguments_map(broker())
286 : native_context().sloppy_arguments_map(broker()),
287 broker());
288 // Actually allocate and initialize the arguments object.
289 AllocationBuilder a(jsgraph(), broker(), effect, control);
290 static_assert(JSSloppyArgumentsObject::kSize == 5 * kTaggedSize);
291 a.Allocate(JSSloppyArgumentsObject::kSize);
292 a.Store(AccessBuilder::ForMap(), arguments_map);
294 jsgraph()->EmptyFixedArrayConstant());
295 a.Store(AccessBuilder::ForJSObjectElements(), elements);
297 jsgraph()->ConstantNoHole(length));
298 a.Store(AccessBuilder::ForArgumentsCallee(), callee);
299 RelaxControls(node);
300 a.FinishAndChange(node);
301 return Changed(node);
302 }
304 // Use inline allocation for all unmapped arguments objects within inlined
305 // (i.e. non-outermost) frames, independent of the object size.
306 Node* effect = NodeProperties::GetEffectInput(node);
307 // Choose the correct frame state and frame state info depending on
308 // whether there conceptually is an inlined arguments frame in the call
309 // chain.
310 FrameState args_state = GetArgumentsFrameState(frame_state);
311 if (args_state.parameters()->opcode() == IrOpcode::kDeadValue) {
312 // This protects against an incompletely propagated DeadValue node.
313 // If the FrameState has a DeadValue input, then this node will be
314 // pruned anyway.
315 return NoChange();
316 }
317 FrameStateInfo args_state_info = args_state.frame_state_info();
318 int length = args_state_info.parameter_count() - 1; // Minus receiver.
319 // Prepare element backing store to be used by arguments object.
320 Node* const elements = TryAllocateArguments(effect, control, args_state);
321 if (elements == nullptr) return NoChange();
322 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
323 // Load the arguments object map.
324 Node* const arguments_map = jsgraph()->ConstantNoHole(
325 native_context().strict_arguments_map(broker()), broker());
326 // Actually allocate and initialize the arguments object.
327 AllocationBuilder a(jsgraph(), broker(), effect, control);
328 static_assert(JSStrictArgumentsObject::kSize == 4 * kTaggedSize);
329 a.Allocate(JSStrictArgumentsObject::kSize);
330 a.Store(AccessBuilder::ForMap(), arguments_map);
332 jsgraph()->EmptyFixedArrayConstant());
333 a.Store(AccessBuilder::ForJSObjectElements(), elements);
335 jsgraph()->ConstantNoHole(length));
336 RelaxControls(node);
337 a.FinishAndChange(node);
338 return Changed(node);
339 }
341 int start_index =
342 shared.internal_formal_parameter_count_without_receiver();
343 // Use inline allocation for all unmapped arguments objects within inlined
344 // (i.e. non-outermost) frames, independent of the object size.
345 Node* effect = NodeProperties::GetEffectInput(node);
346 // Choose the correct frame state and frame state info depending on
347 // whether there conceptually is an inlined arguments frame in the call
348 // chain.
349 FrameState args_state = GetArgumentsFrameState(frame_state);
350 if (args_state.parameters()->opcode() == IrOpcode::kDeadValue) {
351 // This protects against an incompletely propagated DeadValue node.
352 // If the FrameState has a DeadValue input, then this node will be
353 // pruned anyway.
354 return NoChange();
355 }
356 FrameStateInfo args_state_info = args_state.frame_state_info();
357 // Prepare element backing store to be used by the rest array.
358 Node* const elements =
359 TryAllocateRestArguments(effect, control, args_state, start_index);
360 if (elements == nullptr) return NoChange();
361 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
362 // Load the JSArray object map.
363 Node* const jsarray_map = jsgraph()->ConstantNoHole(
364 native_context().js_array_packed_elements_map(broker()), broker());
365 // Actually allocate and initialize the jsarray.
366 AllocationBuilder a(jsgraph(), broker(), effect, control);
367
368 // -1 to minus receiver
369 int argument_count = args_state_info.parameter_count() - 1;
370 int length = std::max(0, argument_count - start_index);
371 static_assert(JSArray::kHeaderSize == 4 * kTaggedSize);
372 a.Allocate(ALIGN_TO_ALLOCATION_ALIGNMENT(JSArray::kHeaderSize));
373 a.Store(AccessBuilder::ForMap(), jsarray_map);
375 jsgraph()->EmptyFixedArrayConstant());
376 a.Store(AccessBuilder::ForJSObjectElements(), elements);
378 jsgraph()->ConstantNoHole(length));
379 RelaxControls(node);
380 a.FinishAndChange(node);
381 return Changed(node);
382 }
383 }
384 UNREACHABLE();
385}
386
388 DCHECK_EQ(IrOpcode::kJSCreateGeneratorObject, node->opcode());
389 Node* const closure = NodeProperties::GetValueInput(node, 0);
391 Node* const context = NodeProperties::GetContextInput(node);
392 Type const closure_type = NodeProperties::GetType(closure);
393 Node* effect = NodeProperties::GetEffectInput(node);
394 Node* const control = NodeProperties::GetControlInput(node);
395 if (closure_type.IsHeapConstant()) {
396 DCHECK(closure_type.AsHeapConstant()->Ref().IsJSFunction());
397 JSFunctionRef js_function =
398 closure_type.AsHeapConstant()->Ref().AsJSFunction();
399 if (!js_function.has_initial_map(broker())) return NoChange();
400
401 SlackTrackingPrediction slack_tracking_prediction =
403
404 MapRef initial_map = js_function.initial_map(broker());
405 DCHECK(initial_map.instance_type() == JS_GENERATOR_OBJECT_TYPE ||
406 initial_map.instance_type() == JS_ASYNC_GENERATOR_OBJECT_TYPE);
407
408 // Allocate a register file.
409 SharedFunctionInfoRef shared = js_function.shared(broker());
410 DCHECK(shared.HasBytecodeArray());
411 int parameter_count_no_receiver =
412 shared.internal_formal_parameter_count_without_receiver();
413 int length = parameter_count_no_receiver +
414 shared.GetBytecodeArray(broker()).register_count();
415 MapRef fixed_array_map = broker()->fixed_array_map();
416 AllocationBuilder ab(jsgraph(), broker(), effect, control);
417 if (!ab.CanAllocateArray(length, fixed_array_map)) {
418 return NoChange();
419 }
420 ab.AllocateArray(length, fixed_array_map);
421 for (int i = 0; i < length; ++i) {
423 jsgraph()->UndefinedConstant());
424 }
425 Node* parameters_and_registers = effect = ab.Finish();
426
427 // Emit code to allocate the JS[Async]GeneratorObject instance.
428 AllocationBuilder a(jsgraph(), broker(), effect, control);
429 a.Allocate(slack_tracking_prediction.instance_size());
430 Node* undefined = jsgraph()->UndefinedConstant();
433 jsgraph()->EmptyFixedArrayConstant());
435 jsgraph()->EmptyFixedArrayConstant());
441 jsgraph()->ConstantNoHole(JSGeneratorObject::kNext));
445 parameters_and_registers);
446
447 if (initial_map.instance_type() == JS_ASYNC_GENERATOR_OBJECT_TYPE) {
450 jsgraph()->ZeroConstant());
451 }
452
453 // Handle in-object properties, too.
454 for (int i = 0; i < slack_tracking_prediction.inobject_property_count();
455 ++i) {
457 undefined);
458 }
459 a.FinishAndChange(node);
460 return Changed(node);
461 }
462 return NoChange();
463}
464
465// Constructs an array with a variable {length} when no upper bound
466// is known for the capacity.
468 Node* node, Node* length, MapRef initial_map, ElementsKind elements_kind,
469 AllocationType allocation,
470 const SlackTrackingPrediction& slack_tracking_prediction) {
471 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
472 Node* effect = NodeProperties::GetEffectInput(node);
473 Node* control = NodeProperties::GetControlInput(node);
474
475 // Constructing an Array via new Array(N) where N is an unsigned
476 // integer, always creates a holey backing store.
477 OptionalMapRef maybe_initial_map =
478 initial_map.AsElementsKind(broker(), GetHoleyElementsKind(elements_kind));
479 if (!maybe_initial_map.has_value()) return NoChange();
480 initial_map = maybe_initial_map.value();
481
482 // Because CheckBounds performs implicit conversion from string to number, an
483 // additional CheckNumber is required to behave correctly for calls with a
484 // single string argument.
485 length = effect = graph()->NewNode(
486 simplified()->CheckNumber(FeedbackSource{}), length, effect, control);
487
488 // Check that the {limit} is an unsigned integer in the valid range.
489 // This has to be kept in sync with src/runtime/runtime-array.cc,
490 // where this limit is protected.
491 length = effect = graph()->NewNode(
493 jsgraph()->ConstantNoHole(JSArray::kInitialMaxFastElementArray), effect,
494 control);
495
496 // Construct elements and properties for the resulting JSArray.
497 Node* elements = effect =
499 ? simplified()->NewDoubleElements(allocation)
500 : simplified()->NewSmiOrObjectElements(allocation),
501 length, effect, control);
502
503 // Perform the allocation of the actual JSArray object.
504 AllocationBuilder a(jsgraph(), broker(), effect, control);
505 a.Allocate(slack_tracking_prediction.instance_size(), allocation);
508 jsgraph()->EmptyFixedArrayConstant());
509 a.Store(AccessBuilder::ForJSObjectElements(), elements);
510 a.Store(AccessBuilder::ForJSArrayLength(initial_map.elements_kind()), length);
511 for (int i = 0; i < slack_tracking_prediction.inobject_property_count();
512 ++i) {
514 jsgraph()->UndefinedConstant());
515 }
516 RelaxControls(node);
517 a.FinishAndChange(node);
518 return Changed(node);
519}
520
521// Constructs an array with a variable {length} when an actual
522// upper bound is known for the {capacity}.
524 Node* node, Node* length, int capacity, MapRef initial_map,
525 ElementsKind elements_kind, AllocationType allocation,
526 const SlackTrackingPrediction& slack_tracking_prediction) {
527 DCHECK(node->opcode() == IrOpcode::kJSCreateArray ||
528 node->opcode() == IrOpcode::kJSCreateEmptyLiteralArray);
529 DCHECK(NodeProperties::GetType(length).Is(Type::Number()));
530 Node* effect = NodeProperties::GetEffectInput(node);
531 Node* control = NodeProperties::GetControlInput(node);
532
533 // Determine the appropriate elements kind.
534 if (NodeProperties::GetType(length).Max() > 0.0) {
535 elements_kind = GetHoleyElementsKind(elements_kind);
536 }
537
538 OptionalMapRef maybe_initial_map =
539 initial_map.AsElementsKind(broker(), elements_kind);
540 if (!maybe_initial_map.has_value()) return NoChange();
541 initial_map = maybe_initial_map.value();
542
543 DCHECK(IsFastElementsKind(elements_kind));
544
545 // Setup elements and properties.
546 Node* elements;
547 if (capacity == 0) {
548 elements = jsgraph()->EmptyFixedArrayConstant();
549 } else {
550 elements = effect =
551 AllocateElements(effect, control, elements_kind, capacity, allocation);
552 }
553
554 // Perform the allocation of the actual JSArray object.
555 AllocationBuilder a(jsgraph(), broker(), effect, control);
556 a.Allocate(slack_tracking_prediction.instance_size(), allocation);
559 jsgraph()->EmptyFixedArrayConstant());
560 a.Store(AccessBuilder::ForJSObjectElements(), elements);
561 a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length);
562 for (int i = 0; i < slack_tracking_prediction.inobject_property_count();
563 ++i) {
565 jsgraph()->UndefinedConstant());
566 }
567 RelaxControls(node);
568 a.FinishAndChange(node);
569 return Changed(node);
570}
571
573 Node* node, std::vector<Node*> values, MapRef initial_map,
574 ElementsKind elements_kind, AllocationType allocation,
575 const SlackTrackingPrediction& slack_tracking_prediction) {
576 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
577 Node* effect = NodeProperties::GetEffectInput(node);
578 Node* control = NodeProperties::GetControlInput(node);
579
580 // Determine the appropriate elements kind.
581 DCHECK(IsFastElementsKind(elements_kind));
582
583 OptionalMapRef maybe_initial_map =
584 initial_map.AsElementsKind(broker(), elements_kind);
585 if (!maybe_initial_map.has_value()) return NoChange();
586 initial_map = maybe_initial_map.value();
587
588 // Check {values} based on the {elements_kind}. These checks are guarded
589 // by the {elements_kind} feedback on the {site}, so it's safe to just
590 // deoptimize in this case.
591 if (IsSmiElementsKind(elements_kind)) {
592 for (auto& value : values) {
594 value = effect = graph()->NewNode(
595 simplified()->CheckSmi(FeedbackSource()), value, effect, control);
596 }
597 }
598 } else if (IsDoubleElementsKind(elements_kind)) {
599 for (auto& value : values) {
600 if (!NodeProperties::GetType(value).Is(Type::Number())) {
601 value = effect =
602 graph()->NewNode(simplified()->CheckNumber(FeedbackSource()), value,
603 effect, control);
604 }
605 // Make sure we do not store signaling NaNs into double arrays.
606 value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
607 }
608 }
609
610 // Setup elements, properties and length.
611 Node* elements = effect =
612 AllocateElements(effect, control, elements_kind, values, allocation);
613 Node* length = jsgraph()->ConstantNoHole(static_cast<int>(values.size()));
614
615 // Perform the allocation of the actual JSArray object.
616 AllocationBuilder a(jsgraph(), broker(), effect, control);
617 a.Allocate(slack_tracking_prediction.instance_size(), allocation);
620 jsgraph()->EmptyFixedArrayConstant());
621 a.Store(AccessBuilder::ForJSObjectElements(), elements);
622 a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length);
623 for (int i = 0; i < slack_tracking_prediction.inobject_property_count();
624 ++i) {
626 jsgraph()->UndefinedConstant());
627 }
628 RelaxControls(node);
629 a.FinishAndChange(node);
630 return Changed(node);
631}
632
634 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
635 CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
636 int const arity = static_cast<int>(p.arity());
637 OptionalAllocationSiteRef site_ref = p.site();
639
640 OptionalMapRef initial_map = NodeProperties::GetJSCreateMap(broker(), node);
641 if (!initial_map.has_value()) return NoChange();
642
644 JSFunctionRef original_constructor =
645 HeapObjectMatcher(new_target).Ref(broker()).AsJSFunction();
646 SlackTrackingPrediction slack_tracking_prediction =
648 original_constructor);
649
650 // Tells whether we are protected by either the {site} or a
651 // protector cell to do certain speculative optimizations.
652 bool can_inline_call = false;
653
654 // Check if we have a feedback {site} on the {node}.
655 ElementsKind elements_kind = initial_map->elements_kind();
656 if (site_ref) {
657 elements_kind = site_ref->GetElementsKind();
658 can_inline_call = site_ref->CanInlineCall();
659 allocation = dependencies()->DependOnPretenureMode(*site_ref);
661 } else {
662 PropertyCellRef array_constructor_protector =
663 MakeRef(broker(), factory()->array_constructor_protector());
664 array_constructor_protector.CacheAsProtector(broker());
665 can_inline_call = array_constructor_protector.value(broker()).AsSmi() ==
667 }
668
669 if (arity == 0) {
670 Node* length = jsgraph()->ZeroConstant();
672 return ReduceNewArray(node, length, capacity, *initial_map, elements_kind,
673 allocation, slack_tracking_prediction);
674 } else if (arity == 1) {
675 Node* length = NodeProperties::GetValueInput(node, 2);
676 Type length_type = NodeProperties::GetType(length);
677 if (!length_type.Maybe(Type::Number())) {
678 // Handle the single argument case, where we know that the value
679 // cannot be a valid Array length.
680 elements_kind = GetMoreGeneralElementsKind(
681 elements_kind, IsHoleyElementsKind(elements_kind) ? HOLEY_ELEMENTS
683 return ReduceNewArray(node, std::vector<Node*>{length}, *initial_map,
684 elements_kind, allocation,
685 slack_tracking_prediction);
686 }
687 if (length_type.Is(Type::SignedSmall()) && length_type.Min() >= 0 &&
688 length_type.Max() <= kElementLoopUnrollLimit &&
689 length_type.Min() == length_type.Max()) {
690 int capacity = static_cast<int>(length_type.Max());
691 // Replace length with a constant in order to protect against a potential
692 // typer bug leading to length > capacity.
693 length = jsgraph()->ConstantNoHole(capacity);
694 return ReduceNewArray(node, length, capacity, *initial_map, elements_kind,
695 allocation, slack_tracking_prediction);
696 }
697 if (length_type.Maybe(Type::UnsignedSmall()) && can_inline_call) {
698 return ReduceNewArray(node, length, *initial_map, elements_kind,
699 allocation, slack_tracking_prediction);
700 }
701 } else if (arity <= JSArray::kInitialMaxFastElementArray) {
702 // Gather the values to store into the newly created array.
703 bool values_all_smis = true, values_all_numbers = true,
704 values_any_nonnumber = false;
705 std::vector<Node*> values;
706 values.reserve(p.arity());
707 for (int i = 0; i < arity; ++i) {
708 Node* value = NodeProperties::GetValueInput(node, 2 + i);
709 Type value_type = NodeProperties::GetType(value);
710 if (!value_type.Is(Type::SignedSmall())) {
711 values_all_smis = false;
712 }
713 if (!value_type.Is(Type::Number())) {
714 values_all_numbers = false;
715 }
716 if (!value_type.Maybe(Type::Number())) {
717 values_any_nonnumber = true;
718 }
719 values.push_back(value);
720 }
721
722 // Try to figure out the ideal elements kind statically.
723 if (values_all_smis) {
724 // Smis can be stored with any elements kind.
725 } else if (values_all_numbers) {
726 elements_kind = GetMoreGeneralElementsKind(
727 elements_kind, IsHoleyElementsKind(elements_kind)
730 } else if (values_any_nonnumber) {
731 elements_kind = GetMoreGeneralElementsKind(
732 elements_kind, IsHoleyElementsKind(elements_kind) ? HOLEY_ELEMENTS
734 } else if (!can_inline_call) {
735 // We have some crazy combination of types for the {values} where
736 // there's no clear decision on the elements kind statically. And
737 // we don't have a protection against deoptimization loops for the
738 // checks that are introduced in the call to ReduceNewArray, so
739 // we cannot inline this invocation of the Array constructor here.
740 return NoChange();
741 }
742 return ReduceNewArray(node, values, *initial_map, elements_kind, allocation,
743 slack_tracking_prediction);
744 }
745 return NoChange();
746}
747
749 DCHECK_EQ(IrOpcode::kJSCreateArrayIterator, node->opcode());
752 Node* iterated_object = NodeProperties::GetValueInput(node, 0);
753 Node* effect = NodeProperties::GetEffectInput(node);
754 Node* control = NodeProperties::GetControlInput(node);
755
756 // Create the JSArrayIterator result.
757 AllocationBuilder a(jsgraph(), broker(), effect, control);
758 a.Allocate(JSArrayIterator::kHeaderSize, AllocationType::kYoung,
759 Type::OtherObject());
760 a.Store(AccessBuilder::ForMap(),
761 native_context().initial_array_iterator_map(broker()));
763 jsgraph()->EmptyFixedArrayConstant());
765 jsgraph()->EmptyFixedArrayConstant());
766 a.Store(AccessBuilder::ForJSArrayIteratorIteratedObject(), iterated_object);
768 jsgraph()->ZeroConstant());
770 jsgraph()->ConstantNoHole(static_cast<int>(p.kind())));
771 RelaxControls(node);
772 a.FinishAndChange(node);
773 return Changed(node);
774}
775
777 DCHECK_EQ(IrOpcode::kJSCreateAsyncFunctionObject, node->opcode());
778 int const register_count = RegisterCountOf(node->op());
779 Node* closure = NodeProperties::GetValueInput(node, 0);
781 Node* promise = NodeProperties::GetValueInput(node, 2);
782 Node* context = NodeProperties::GetContextInput(node);
783 Node* effect = NodeProperties::GetEffectInput(node);
784 Node* control = NodeProperties::GetControlInput(node);
785
786 // Create the register file.
787 MapRef fixed_array_map = broker()->fixed_array_map();
788 AllocationBuilder ab(jsgraph(), broker(), effect, control);
789 CHECK(ab.CanAllocateArray(register_count, fixed_array_map));
790 ab.AllocateArray(register_count, fixed_array_map);
791 for (int i = 0; i < register_count; ++i) {
793 jsgraph()->UndefinedConstant());
794 }
795 Node* parameters_and_registers = effect = ab.Finish();
796
797 // Create the JSAsyncFunctionObject result.
798 AllocationBuilder a(jsgraph(), broker(), effect, control);
799 a.Allocate(JSAsyncFunctionObject::kHeaderSize);
800 a.Store(AccessBuilder::ForMap(),
801 native_context().async_function_object_map(broker()));
803 jsgraph()->EmptyFixedArrayConstant());
805 jsgraph()->EmptyFixedArrayConstant());
810 jsgraph()->UndefinedConstant());
812 jsgraph()->ConstantNoHole(JSGeneratorObject::kNext));
816 parameters_and_registers);
818 a.FinishAndChange(node);
819 return Changed(node);
820}
821
822namespace {
823
824MapRef MapForCollectionIterationKind(JSHeapBroker* broker,
826 CollectionKind collection_kind,
827 IterationKind iteration_kind) {
828 switch (collection_kind) {
830 switch (iteration_kind) {
832 UNREACHABLE();
834 return native_context.set_value_iterator_map(broker);
836 return native_context.set_key_value_iterator_map(broker);
837 }
838 break;
840 switch (iteration_kind) {
842 return native_context.map_key_iterator_map(broker);
844 return native_context.map_value_iterator_map(broker);
846 return native_context.map_key_value_iterator_map(broker);
847 }
848 break;
849 }
850 UNREACHABLE();
851}
852
853} // namespace
854
856 DCHECK_EQ(IrOpcode::kJSCreateCollectionIterator, node->opcode());
859 Node* iterated_object = NodeProperties::GetValueInput(node, 0);
860 Node* effect = NodeProperties::GetEffectInput(node);
861 Node* control = NodeProperties::GetControlInput(node);
862
863 // Load the OrderedHashTable from the {receiver}.
864 Node* table = effect = graph()->NewNode(
866 iterated_object, effect, control);
867
868 // Create the JSCollectionIterator result.
869 AllocationBuilder a(jsgraph(), broker(), effect, control);
870 a.Allocate(JSCollectionIterator::kHeaderSize, AllocationType::kYoung,
871 Type::OtherObject());
872 a.Store(
874 MapForCollectionIterationKind(broker(), native_context(),
877 jsgraph()->EmptyFixedArrayConstant());
879 jsgraph()->EmptyFixedArrayConstant());
882 jsgraph()->ZeroConstant());
883 RelaxControls(node);
884 a.FinishAndChange(node);
885 return Changed(node);
886}
887
889 DCHECK_EQ(IrOpcode::kJSCreateBoundFunction, node->opcode());
892 int const arity = static_cast<int>(p.arity());
893 MapRef const map = p.map();
894 Node* bound_target_function = NodeProperties::GetValueInput(node, 0);
895 Node* bound_this = NodeProperties::GetValueInput(node, 1);
896 Node* effect = NodeProperties::GetEffectInput(node);
897 Node* control = NodeProperties::GetControlInput(node);
898
899 // Create the [[BoundArguments]] for the result.
900 Node* bound_arguments = jsgraph()->EmptyFixedArrayConstant();
901 if (arity > 0) {
902 MapRef fixed_array_map = broker()->fixed_array_map();
903 AllocationBuilder ab(jsgraph(), broker(), effect, control);
904 CHECK(ab.CanAllocateArray(arity, fixed_array_map));
905 ab.AllocateArray(arity, fixed_array_map);
906 for (int i = 0; i < arity; ++i) {
909 }
910 bound_arguments = effect = ab.Finish();
911 }
912
913 // Create the JSBoundFunction result.
914 AllocationBuilder a(jsgraph(), broker(), effect, control);
915 a.Allocate(JSBoundFunction::kHeaderSize, AllocationType::kYoung,
916 Type::BoundFunction());
917 a.Store(AccessBuilder::ForMap(), map);
919 jsgraph()->EmptyFixedArrayConstant());
921 jsgraph()->EmptyFixedArrayConstant());
923 bound_target_function);
924 a.Store(AccessBuilder::ForJSBoundFunctionBoundThis(), bound_this);
925 a.Store(AccessBuilder::ForJSBoundFunctionBoundArguments(), bound_arguments);
926 RelaxControls(node);
927 a.FinishAndChange(node);
928 return Changed(node);
929}
930
933 CreateClosureParameters const& p = n.Parameters();
935 FeedbackCellRef feedback_cell = n.GetFeedbackCellRefChecked(broker());
936#ifndef V8_ENABLE_LEAPTIERING
937 HeapObjectRef code = p.code();
938#endif
939 Effect effect = n.effect();
940 Control control = n.control();
941 Node* context = n.context();
942
943 // Use inline allocation of closures only for instantiation sites that have
944 // seen more than one instantiation, this simplifies the generated code and
945 // also serves as a heuristic of which allocation sites benefit from it.
946 if (!feedback_cell.map(broker()).equals(broker()->many_closures_cell_map())) {
947 return NoChange();
948 }
949
950 // Don't inline anything for class constructors.
951 if (IsClassConstructor(shared.kind())) return NoChange();
952
954 broker(), shared.function_map_index());
955 DCHECK(!function_map.IsInobjectSlackTrackingInProgress());
956 DCHECK(!function_map.is_dictionary_map());
957
958#ifdef V8_ENABLE_LEAPTIERING
959 // TODO(saelo): we should embed the dispatch handle directly into the
960 // generated code instead of loading it at runtime from the FeedbackCell.
961 // This will likely first require GC support though.
962 Node* feedback_cell_node = jsgraph()->ConstantNoHole(feedback_cell, broker());
963 Node* dispatch_handle;
964 if (shared.HasBuiltinId()) {
965 // This uses a smi constant to store the static dispatch handle, since
966 // currently we expect dispatch handles to be encoded as numbers in the
967 // deopt metadata.
968 // TODO(olivf): Dispatch handles should be supported in deopt metadata.
969 dispatch_handle = jsgraph()->SmiConstant(
970 jsgraph()
971 ->isolate()
972 ->builtin_dispatch_handle(shared.builtin_id())
973 .value());
974 } else {
975 DCHECK(feedback_cell.object()->dispatch_handle() != kNullJSDispatchHandle);
976 dispatch_handle = effect = graph()->NewNode(
977 simplified()->LoadField(
978 AccessBuilder::ForFeedbackCellDispatchHandleNoWriteBarrier()),
979 feedback_cell_node, effect, control);
980 }
981#endif // V8_ENABLE_LEAPTIERING
982
983 // TODO(turbofan): We should use the pretenure flag from {p} here,
984 // but currently the heuristic in the parser works against us, as
985 // it marks closures like
986 //
987 // args[l] = function(...) { ... }
988 //
989 // for old-space allocation, which doesn't always make sense. For
990 // example in case of the bluebird-parallel benchmark, where this
991 // is a core part of the *promisify* logic (see crbug.com/810132).
993
994 // Emit code to allocate the JSFunction instance.
996 AllocationBuilder a(jsgraph(), broker(), effect, control);
997 a.Allocate(function_map.instance_size(), allocation,
998 Type::CallableFunction());
999 a.Store(AccessBuilder::ForMap(), function_map);
1001 jsgraph()->EmptyFixedArrayConstant());
1003 jsgraph()->EmptyFixedArrayConstant());
1005 a.Store(AccessBuilder::ForJSFunctionContext(), context);
1006 a.Store(AccessBuilder::ForJSFunctionFeedbackCell(), feedback_cell);
1007#ifdef V8_ENABLE_LEAPTIERING
1008 a.Store(AccessBuilder::ForJSFunctionDispatchHandleNoWriteBarrier(),
1009 dispatch_handle);
1010#else
1011 a.Store(AccessBuilder::ForJSFunctionCode(), code);
1012#endif // V8_ENABLE_LEAPTIERING
1013 static_assert(JSFunction::kSizeWithoutPrototype == 7 * kTaggedSize);
1014 if (function_map.has_prototype_slot()) {
1016 jsgraph()->TheHoleConstant());
1017 static_assert(JSFunction::kSizeWithPrototype == 8 * kTaggedSize);
1018 }
1019 for (int i = 0; i < function_map.GetInObjectProperties(); i++) {
1020 a.Store(AccessBuilder::ForJSObjectInObjectProperty(function_map, i),
1021 jsgraph()->UndefinedConstant());
1022 }
1023 RelaxControls(node);
1024 a.FinishAndChange(node);
1025 return Changed(node);
1026}
1027
1029 DCHECK_EQ(IrOpcode::kJSCreateIterResultObject, node->opcode());
1030 Node* value = NodeProperties::GetValueInput(node, 0);
1031 Node* done = NodeProperties::GetValueInput(node, 1);
1032 Node* effect = NodeProperties::GetEffectInput(node);
1033
1034 Node* iterator_result_map = jsgraph()->ConstantNoHole(
1035 native_context().iterator_result_map(broker()), broker());
1036
1037 // Emit code to allocate the JSIteratorResult instance.
1038 AllocationBuilder a(jsgraph(), broker(), effect, graph()->start());
1039 a.Allocate(JSIteratorResult::kSize);
1040 a.Store(AccessBuilder::ForMap(), iterator_result_map);
1042 jsgraph()->EmptyFixedArrayConstant());
1044 jsgraph()->EmptyFixedArrayConstant());
1047 static_assert(JSIteratorResult::kSize == 5 * kTaggedSize);
1048 a.FinishAndChange(node);
1049 return Changed(node);
1050}
1051
1053 DCHECK_EQ(IrOpcode::kJSCreateStringIterator, node->opcode());
1054 Node* string = NodeProperties::GetValueInput(node, 0);
1055 Node* effect = NodeProperties::GetEffectInput(node);
1056
1057 Node* map = jsgraph()->ConstantNoHole(
1058 native_context().initial_string_iterator_map(broker()), broker());
1059 // Allocate new iterator and attach the iterator to this string.
1060 AllocationBuilder a(jsgraph(), broker(), effect, graph()->start());
1061 a.Allocate(JSStringIterator::kHeaderSize, AllocationType::kYoung,
1062 Type::OtherObject());
1063 a.Store(AccessBuilder::ForMap(), map);
1065 jsgraph()->EmptyFixedArrayConstant());
1067 jsgraph()->EmptyFixedArrayConstant());
1069 a.Store(AccessBuilder::ForJSStringIteratorIndex(), jsgraph()->SmiConstant(0));
1070 static_assert(JSIteratorResult::kSize == 5 * kTaggedSize);
1071 a.FinishAndChange(node);
1072 return Changed(node);
1073}
1074
1076 DCHECK_EQ(IrOpcode::kJSCreateKeyValueArray, node->opcode());
1078 Node* value = NodeProperties::GetValueInput(node, 1);
1079 Node* effect = NodeProperties::GetEffectInput(node);
1080
1081 Node* array_map = jsgraph()->ConstantNoHole(
1082 native_context().js_array_packed_elements_map(broker()), broker());
1083 Node* length = jsgraph()->ConstantNoHole(2);
1084
1085 AllocationBuilder aa(jsgraph(), broker(), effect, graph()->start());
1086 aa.AllocateArray(2, broker()->fixed_array_map());
1088 jsgraph()->ZeroConstant(), key);
1090 jsgraph()->OneConstant(), value);
1091 Node* elements = aa.Finish();
1092
1093 AllocationBuilder a(jsgraph(), broker(), elements, graph()->start());
1094 a.Allocate(ALIGN_TO_ALLOCATION_ALIGNMENT(JSArray::kHeaderSize));
1095 a.Store(AccessBuilder::ForMap(), array_map);
1097 jsgraph()->EmptyFixedArrayConstant());
1098 a.Store(AccessBuilder::ForJSObjectElements(), elements);
1100 static_assert(JSArray::kHeaderSize == 4 * kTaggedSize);
1101 a.FinishAndChange(node);
1102 return Changed(node);
1103}
1104
1106 DCHECK_EQ(IrOpcode::kJSCreatePromise, node->opcode());
1107 Node* effect = NodeProperties::GetEffectInput(node);
1108
1109 MapRef promise_map =
1110 native_context().promise_function(broker()).initial_map(broker());
1111
1112 AllocationBuilder a(jsgraph(), broker(), effect, graph()->start());
1113 a.Allocate(promise_map.instance_size());
1114 a.Store(AccessBuilder::ForMap(), promise_map);
1116 jsgraph()->EmptyFixedArrayConstant());
1118 jsgraph()->EmptyFixedArrayConstant());
1119 a.Store(AccessBuilder::ForJSObjectOffset(JSPromise::kReactionsOrResultOffset),
1120 jsgraph()->ZeroConstant());
1121 static_assert(v8::Promise::kPending == 0);
1122 a.Store(AccessBuilder::ForJSObjectOffset(JSPromise::kFlagsOffset),
1123 jsgraph()->ZeroConstant());
1124 static_assert(JSPromise::kHeaderSize == 5 * kTaggedSize);
1125 for (int offset = JSPromise::kHeaderSize;
1128 jsgraph()->ZeroConstant());
1129 }
1130 a.FinishAndChange(node);
1131 return Changed(node);
1132}
1133
1135 DCHECK(node->opcode() == IrOpcode::kJSCreateLiteralArray ||
1136 node->opcode() == IrOpcode::kJSCreateLiteralObject);
1138 CreateLiteralParameters const& p = n.Parameters();
1139 Effect effect = n.effect();
1140 Control control = n.control();
1141 ProcessedFeedback const& feedback =
1143 if (!feedback.IsInsufficient()) {
1144 AllocationSiteRef site = feedback.AsLiteral().value();
1145 if (!site.boilerplate(broker()).has_value()) return NoChange();
1147 int max_properties = kMaxFastLiteralProperties;
1148 std::optional<Node*> maybe_value = TryAllocateFastLiteral(
1149 effect, control, *site.boilerplate(broker()), allocation,
1150 kMaxFastLiteralDepth, &max_properties);
1151 if (!maybe_value.has_value()) return NoChange();
1153 Node* value = effect = maybe_value.value();
1154 ReplaceWithValue(node, value, effect, control);
1155 return Replace(value);
1156 }
1157 return NoChange();
1158}
1159
1162 FeedbackParameter const& p = n.Parameters();
1163 ProcessedFeedback const& feedback =
1165 if (!feedback.IsInsufficient()) {
1166 AllocationSiteRef site = feedback.AsLiteral().value();
1167 DCHECK(!site.PointsToLiteral());
1169 native_context().GetInitialJSArrayMap(broker(), site.GetElementsKind());
1170 AllocationType const allocation =
1173 Node* length = jsgraph()->ZeroConstant();
1174 DCHECK(!initial_map.IsInobjectSlackTrackingInProgress());
1175 SlackTrackingPrediction slack_tracking_prediction(
1176 initial_map, initial_map.instance_size());
1177 return ReduceNewArray(node, length, 0, initial_map,
1178 initial_map.elements_kind(), allocation,
1179 slack_tracking_prediction);
1180 }
1181 return NoChange();
1182}
1183
1185 DCHECK_EQ(IrOpcode::kJSCreateEmptyLiteralObject, node->opcode());
1186 Node* effect = NodeProperties::GetEffectInput(node);
1187 Node* control = NodeProperties::GetControlInput(node);
1188
1189 // Retrieve the initial map for the object.
1190 MapRef map = native_context().object_function(broker()).initial_map(broker());
1191 DCHECK(!map.is_dictionary_map());
1192 DCHECK(!map.IsInobjectSlackTrackingInProgress());
1193 Node* js_object_map = jsgraph()->ConstantNoHole(map, broker());
1194
1195 // Setup elements and properties.
1196 Node* elements = jsgraph()->EmptyFixedArrayConstant();
1197
1198 // Perform the allocation of the actual JSArray object.
1199 AllocationBuilder a(jsgraph(), broker(), effect, control);
1200 a.Allocate(map.instance_size());
1201 a.Store(AccessBuilder::ForMap(), js_object_map);
1203 jsgraph()->EmptyFixedArrayConstant());
1204 a.Store(AccessBuilder::ForJSObjectElements(), elements);
1205 for (int i = 0; i < map.GetInObjectProperties(); i++) {
1207 jsgraph()->UndefinedConstant());
1208 }
1209
1210 RelaxControls(node);
1211 a.FinishAndChange(node);
1212 return Changed(node);
1213}
1214
1217 CreateLiteralParameters const& p = n.Parameters();
1218 Effect effect = n.effect();
1219 Control control = n.control();
1220 ProcessedFeedback const& feedback =
1222 if (!feedback.IsInsufficient()) {
1224 feedback.AsRegExpLiteral().value();
1225 Node* value = effect = AllocateLiteralRegExp(effect, control, literal);
1226 ReplaceWithValue(node, value, effect, control);
1227 return Replace(value);
1228 }
1229 return NoChange();
1230}
1231
1234 GetTemplateObjectParameters const& parameters = n.Parameters();
1235
1236 const ProcessedFeedback& feedback =
1238 // TODO(v8:7790): Consider not generating JSGetTemplateObject operator
1239 // in the BytecodeGraphBuilder in the first place, if template_object is not
1240 // available.
1241 if (feedback.IsInsufficient()) return NoChange();
1242
1243 JSArrayRef template_object = feedback.AsTemplateObject().value();
1244 Node* value = jsgraph()->ConstantNoHole(template_object, broker());
1245 ReplaceWithValue(node, value);
1246 return Replace(value);
1247}
1248
1250 DCHECK_EQ(IrOpcode::kJSCreateFunctionContext, node->opcode());
1251 const CreateFunctionContextParameters& parameters =
1253 ScopeInfoRef scope_info = parameters.scope_info();
1254 int slot_count = parameters.slot_count();
1255 ScopeType scope_type = parameters.scope_type();
1256
1257 // Use inline allocation for function contexts up to a size limit.
1258 if (slot_count < kFunctionContextAllocationLimit) {
1259 // JSCreateFunctionContext[slot_count < limit]](fun)
1260 Node* effect = NodeProperties::GetEffectInput(node);
1261 Node* control = NodeProperties::GetControlInput(node);
1262 Node* context = NodeProperties::GetContextInput(node);
1263 AllocationBuilder a(jsgraph(), broker(), effect, control);
1264 static_assert(Context::MIN_CONTEXT_SLOTS == 2); // Ensure fully covered.
1265 int context_length = slot_count + Context::MIN_CONTEXT_SLOTS;
1266 switch (scope_type) {
1267 case EVAL_SCOPE:
1268 a.AllocateContext(context_length,
1269 native_context().eval_context_map(broker()));
1270 break;
1271 case FUNCTION_SCOPE:
1272 a.AllocateContext(context_length,
1273 native_context().function_context_map(broker()));
1274 break;
1275 default:
1276 UNREACHABLE();
1277 }
1279 scope_info);
1281 for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) {
1282 a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant());
1283 }
1284 RelaxControls(node);
1285 a.FinishAndChange(node);
1286 return Changed(node);
1287 }
1288
1289 return NoChange();
1290}
1291
1293 DCHECK_EQ(IrOpcode::kJSCreateWithContext, node->opcode());
1294 ScopeInfoRef scope_info = ScopeInfoOf(node->op());
1296 Node* effect = NodeProperties::GetEffectInput(node);
1297 Node* control = NodeProperties::GetControlInput(node);
1298 Node* context = NodeProperties::GetContextInput(node);
1299
1300 AllocationBuilder a(jsgraph(), broker(), effect, control);
1302 3); // Ensure fully covered.
1303 a.AllocateContext(Context::MIN_CONTEXT_EXTENDED_SLOTS,
1304 native_context().with_context_map(broker()));
1308 RelaxControls(node);
1309 a.FinishAndChange(node);
1310 return Changed(node);
1311}
1312
1314 DCHECK_EQ(IrOpcode::kJSCreateCatchContext, node->opcode());
1315 ScopeInfoRef scope_info = ScopeInfoOf(node->op());
1316 Node* exception = NodeProperties::GetValueInput(node, 0);
1317 Node* effect = NodeProperties::GetEffectInput(node);
1318 Node* control = NodeProperties::GetControlInput(node);
1319 Node* context = NodeProperties::GetContextInput(node);
1320
1321 AllocationBuilder a(jsgraph(), broker(), effect, control);
1322 static_assert(Context::MIN_CONTEXT_SLOTS == 2); // Ensure fully covered.
1323 a.AllocateContext(Context::MIN_CONTEXT_SLOTS + 1,
1324 native_context().catch_context_map(broker()));
1328 exception);
1329 RelaxControls(node);
1330 a.FinishAndChange(node);
1331 return Changed(node);
1332}
1333
1335 DCHECK_EQ(IrOpcode::kJSCreateBlockContext, node->opcode());
1336 ScopeInfoRef scope_info = ScopeInfoOf(node->op());
1337 int const context_length = scope_info.ContextLength();
1338
1339 // Use inline allocation for block contexts up to a size limit.
1340 if (context_length < kBlockContextAllocationLimit) {
1341 // JSCreateBlockContext[scope[length < limit]](fun)
1342 Node* effect = NodeProperties::GetEffectInput(node);
1343 Node* control = NodeProperties::GetControlInput(node);
1344 Node* context = NodeProperties::GetContextInput(node);
1345
1346 AllocationBuilder a(jsgraph(), broker(), effect, control);
1347 static_assert(Context::MIN_CONTEXT_SLOTS == 2); // Ensure fully covered.
1348 a.AllocateContext(context_length,
1349 native_context().block_context_map(broker()));
1351 scope_info);
1353 for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) {
1354 a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant());
1355 }
1356 RelaxControls(node);
1357 a.FinishAndChange(node);
1358 return Changed(node);
1359 }
1360
1361 return NoChange();
1362}
1363
1364namespace {
1365
1366OptionalMapRef GetObjectCreateMap(JSHeapBroker* broker,
1367 HeapObjectRef prototype) {
1368 MapRef standard_map =
1369 broker->target_native_context().object_function(broker).initial_map(
1370 broker);
1371 if (prototype.equals(standard_map.prototype(broker))) {
1372 return standard_map;
1373 }
1374 if (prototype.map(broker).oddball_type(broker) == OddballType::kNull) {
1375 return broker->target_native_context().slow_object_with_null_prototype_map(
1376 broker);
1377 }
1378 if (prototype.IsJSObject()) {
1379 return prototype.AsJSObject().GetObjectCreateMap(broker);
1380 }
1381 return OptionalMapRef();
1382}
1383
1384} // namespace
1385
1387 DCHECK_EQ(IrOpcode::kJSCreateObject, node->opcode());
1388 Node* effect = NodeProperties::GetEffectInput(node);
1389 Node* control = NodeProperties::GetControlInput(node);
1390 Node* prototype = NodeProperties::GetValueInput(node, 0);
1391 Type prototype_type = NodeProperties::GetType(prototype);
1392 if (!prototype_type.IsHeapConstant()) return NoChange();
1393
1394 HeapObjectRef prototype_const = prototype_type.AsHeapConstant()->Ref();
1395 auto maybe_instance_map = GetObjectCreateMap(broker(), prototype_const);
1396 if (!maybe_instance_map) return NoChange();
1397 MapRef instance_map = maybe_instance_map.value();
1398
1399 Node* properties = jsgraph()->EmptyFixedArrayConstant();
1400 if (instance_map.is_dictionary_map()) {
1401 DCHECK_EQ(prototype_const.map(broker()).oddball_type(broker()),
1403 // Allocate an empty NameDictionary as backing store for the properties.
1404 MapRef map = broker()->name_dictionary_map();
1405 int capacity =
1406 NameDictionary::ComputeCapacity(NameDictionary::kInitialCapacity);
1408 int length = NameDictionary::EntryToIndex(InternalIndex(capacity));
1409 int size = NameDictionary::SizeFor(length);
1410
1411 AllocationBuilder a(jsgraph(), broker(), effect, control);
1412 a.Allocate(size, AllocationType::kYoung, Type::Any());
1413 a.Store(AccessBuilder::ForMap(), map);
1414 // Initialize FixedArray fields.
1416 jsgraph()->SmiConstant(length));
1417 // Initialize HashTable fields.
1419 jsgraph()->SmiConstant(0));
1421 jsgraph()->SmiConstant(0));
1423 jsgraph()->SmiConstant(capacity));
1424 // Initialize Dictionary fields.
1426 jsgraph()->SmiConstant(PropertyDetails::kInitialIndex));
1428 jsgraph()->SmiConstant(PropertyArray::kNoHashSentinel));
1429 // Initialize NameDictionary fields.
1431 jsgraph()->SmiConstant(NameDictionary::kFlagsDefault));
1432 // Initialize the Properties fields.
1433 Node* undefined = jsgraph()->UndefinedConstant();
1434 static_assert(NameDictionary::kElementsStartIndex ==
1436 for (int index = NameDictionary::kElementsStartIndex; index < length;
1437 index++) {
1439 undefined);
1440 }
1441 properties = effect = a.Finish();
1442 }
1443
1444 int const instance_size = instance_map.instance_size();
1445 if (instance_size > kMaxRegularHeapObjectSize) return NoChange();
1447
1448 // Emit code to allocate the JSObject instance for the given
1449 // {instance_map}.
1450 AllocationBuilder a(jsgraph(), broker(), effect, control);
1451 a.Allocate(instance_size, AllocationType::kYoung, Type::Any());
1452 a.Store(AccessBuilder::ForMap(), instance_map);
1453 a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
1455 jsgraph()->EmptyFixedArrayConstant());
1456 // Initialize Object fields.
1457 Node* undefined = jsgraph()->UndefinedConstant();
1458 for (int offset = JSObject::kHeaderSize; offset < instance_size;
1459 offset += kTaggedSize) {
1461 undefined);
1462 }
1463 Node* value = effect = a.Finish();
1464
1465 ReplaceWithValue(node, value, effect, control);
1466 return Replace(value);
1467}
1468
1470 DCHECK_EQ(IrOpcode::kJSCreateStringWrapper, node->opcode());
1471 Node* effect = NodeProperties::GetEffectInput(node);
1472 Node* primitive_value = NodeProperties::GetValueInput(node, 0);
1473
1474 MapRef map = native_context().string_function(broker()).initial_map(broker());
1475 DCHECK_EQ(map.instance_size(), JSPrimitiveWrapper::kHeaderSize);
1476 CHECK(!map.IsInobjectSlackTrackingInProgress());
1477
1478 // Emit code to allocate the JSPrimitiveWrapper instance for the given {map}.
1479 AllocationBuilder a(jsgraph(), broker(), effect, graph()->start());
1480 a.Allocate(JSPrimitiveWrapper::kHeaderSize, AllocationType::kYoung,
1481 Type::StringWrapper());
1482 a.Store(AccessBuilder::ForMap(), map);
1484 jsgraph()->EmptyFixedArrayConstant());
1486 jsgraph()->EmptyFixedArrayConstant());
1487 a.Store(AccessBuilder::ForJSPrimitiveWrapperValue(), primitive_value);
1488 a.FinishAndChange(node);
1489 return Changed(node);
1490}
1491
1492// Helper that allocates a FixedArray holding argument values recorded in the
1493// given {frame_state}. Serves as backing store for JSCreateArguments nodes.
1495 FrameState frame_state) {
1496 FrameStateInfo state_info = frame_state.frame_state_info();
1497 int argument_count = state_info.parameter_count() - 1; // Minus receiver.
1498 if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant();
1499
1500 // Prepare an iterator over argument values recorded in the frame state.
1501 Node* const parameters = frame_state.parameters();
1502 StateValuesAccess parameters_access(parameters);
1503 auto parameters_it = parameters_access.begin_without_receiver();
1504
1505 // Actually allocate the backing store.
1506 MapRef fixed_array_map = broker()->fixed_array_map();
1507 AllocationBuilder ab(jsgraph(), broker(), effect, control);
1508 if (!ab.CanAllocateArray(argument_count, fixed_array_map)) {
1509 return nullptr;
1510 }
1511 ab.AllocateArray(argument_count, fixed_array_map);
1512 for (int i = 0; i < argument_count; ++i, ++parameters_it) {
1513 DCHECK_NOT_NULL(parameters_it.node());
1515 jsgraph()->ConstantNoHole(i), parameters_it.node());
1516 }
1517 return ab.Finish();
1518}
1519
1520// Helper that allocates a FixedArray holding argument values recorded in the
1521// given {frame_state}. Serves as backing store for JSCreateArguments nodes.
1523 FrameState frame_state,
1524 int start_index) {
1525 FrameStateInfo state_info = frame_state.frame_state_info();
1526 int argument_count = state_info.parameter_count() - 1; // Minus receiver.
1527 int num_elements = std::max(0, argument_count - start_index);
1528 if (num_elements == 0) return jsgraph()->EmptyFixedArrayConstant();
1529
1530 // Prepare an iterator over argument values recorded in the frame state.
1531 Node* const parameters = frame_state.parameters();
1532 StateValuesAccess parameters_access(parameters);
1533 auto parameters_it =
1534 parameters_access.begin_without_receiver_and_skip(start_index);
1535
1536 // Actually allocate the backing store.
1537 MapRef fixed_array_map = broker()->fixed_array_map();
1538 AllocationBuilder ab(jsgraph(), broker(), effect, control);
1539 if (!ab.CanAllocateArray(num_elements, fixed_array_map)) {
1540 return nullptr;
1541 }
1542 ab.AllocateArray(num_elements, fixed_array_map);
1543 for (int i = 0; i < num_elements; ++i, ++parameters_it) {
1544 DCHECK_NOT_NULL(parameters_it.node());
1546 jsgraph()->ConstantNoHole(i), parameters_it.node());
1547 }
1548 return ab.Finish();
1549}
1550
1551// Helper that allocates a FixedArray serving as a parameter map for values
1552// recorded in the given {frame_state}. Some elements map to slots within the
1553// given {context}. Serves as backing store for JSCreateArguments nodes.
1555 Node* effect, Node* control, FrameState frame_state, Node* context,
1556 SharedFunctionInfoRef shared, bool* has_aliased_arguments) {
1557 FrameStateInfo state_info = frame_state.frame_state_info();
1558 int argument_count = state_info.parameter_count() - 1; // Minus receiver.
1559 if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant();
1560
1561 // If there is no aliasing, the arguments object elements are not special in
1562 // any way, we can just return an unmapped backing store instead.
1563 int parameter_count =
1564 shared.internal_formal_parameter_count_without_receiver();
1565 if (parameter_count == 0) {
1566 return TryAllocateArguments(effect, control, frame_state);
1567 }
1568
1569 // Calculate number of argument values being aliased/mapped.
1570 int mapped_count = std::min(argument_count, parameter_count);
1571 *has_aliased_arguments = true;
1572
1573 MapRef sloppy_arguments_elements_map =
1574 broker()->sloppy_arguments_elements_map();
1575 AllocationBuilder ab(jsgraph(), broker(), effect, control);
1576
1577 if (!ab.CanAllocateSloppyArgumentElements(mapped_count,
1578 sloppy_arguments_elements_map)) {
1579 return nullptr;
1580 }
1581
1582 MapRef fixed_array_map = broker()->fixed_array_map();
1583 if (!ab.CanAllocateArray(argument_count, fixed_array_map)) {
1584 return nullptr;
1585 }
1586
1587 // Prepare an iterator over argument values recorded in the frame state.
1588 Node* const parameters = frame_state.parameters();
1589 StateValuesAccess parameters_access(parameters);
1590 auto parameters_it =
1591 parameters_access.begin_without_receiver_and_skip(mapped_count);
1592
1593 // The unmapped argument values recorded in the frame state are stored yet
1594 // another indirection away and then linked into the parameter map below,
1595 // whereas mapped argument values are replaced with a hole instead.
1596 ab.AllocateArray(argument_count, fixed_array_map);
1597 for (int i = 0; i < mapped_count; ++i) {
1599 jsgraph()->ConstantNoHole(i), jsgraph()->TheHoleConstant());
1600 }
1601 for (int i = mapped_count; i < argument_count; ++i, ++parameters_it) {
1602 DCHECK_NOT_NULL(parameters_it.node());
1604 jsgraph()->ConstantNoHole(i), parameters_it.node());
1605 }
1606 Node* arguments = ab.Finish();
1607
1608 // Actually allocate the backing store.
1609 AllocationBuilder a(jsgraph(), broker(), arguments, control);
1610 a.AllocateSloppyArgumentElements(mapped_count, sloppy_arguments_elements_map);
1613 for (int i = 0; i < mapped_count; ++i) {
1614 int idx = shared.context_parameters_start() + parameter_count - 1 - i;
1616 jsgraph()->ConstantNoHole(i), jsgraph()->ConstantNoHole(idx));
1617 }
1618 return a.Finish();
1619}
1620
1621// Helper that allocates a FixedArray serving as a parameter map for values
1622// unknown at compile-time, the true {arguments_length} and {arguments_frame}
1623// values can only be determined dynamically at run-time and are provided.
1624// Serves as backing store for JSCreateArguments nodes.
1626 Node* effect, Node* control, Node* context, Node* arguments_length,
1627 SharedFunctionInfoRef shared, bool* has_aliased_arguments) {
1628 // If there is no aliasing, the arguments object elements are not
1629 // special in any way, we can just return an unmapped backing store.
1630 int parameter_count =
1631 shared.internal_formal_parameter_count_without_receiver();
1632 if (parameter_count == 0) {
1633 return graph()->NewNode(
1634 simplified()->NewArgumentsElements(
1636 arguments_length, effect);
1637 }
1638
1639 int mapped_count = parameter_count;
1640 MapRef sloppy_arguments_elements_map =
1641 broker()->sloppy_arguments_elements_map();
1642
1643 {
1644 AllocationBuilder ab(jsgraph(), broker(), effect, control);
1645 if (!ab.CanAllocateSloppyArgumentElements(mapped_count,
1646 sloppy_arguments_elements_map)) {
1647 return nullptr;
1648 }
1649 }
1650
1651 // From here on we are going to allocate a mapped (aka. aliased) elements
1652 // backing store. We do not statically know how many arguments exist, but
1653 // dynamically selecting the hole for some of the "mapped" elements allows
1654 // using a static shape for the parameter map.
1655 *has_aliased_arguments = true;
1656
1657 // The unmapped argument values are stored yet another indirection away and
1658 // then linked into the parameter map below, whereas mapped argument values
1659 // (i.e. the first {mapped_count} elements) are replaced with a hole instead.
1660 Node* arguments = effect =
1661 graph()->NewNode(simplified()->NewArgumentsElements(
1663 arguments_length, effect);
1664
1665 // Actually allocate the backing store.
1666 AllocationBuilder a(jsgraph(), broker(), effect, control);
1667 a.AllocateSloppyArgumentElements(mapped_count, sloppy_arguments_elements_map);
1670 for (int i = 0; i < mapped_count; ++i) {
1671 int idx = shared.context_parameters_start() + parameter_count - 1 - i;
1672 Node* value = graph()->NewNode(
1674 graph()->NewNode(simplified()->NumberLessThan(),
1675 jsgraph()->ConstantNoHole(i), arguments_length),
1676 jsgraph()->ConstantNoHole(idx), jsgraph()->TheHoleConstant());
1678 jsgraph()->ConstantNoHole(i), value);
1679 }
1680 return a.Finish();
1681}
1682
1684 ElementsKind elements_kind,
1685 int capacity,
1686 AllocationType allocation) {
1687 DCHECK_LE(1, capacity);
1689
1690 Handle<Map> elements_map = IsDoubleElementsKind(elements_kind)
1691 ? factory()->fixed_double_array_map()
1692 : factory()->fixed_array_map();
1693 ElementAccess access = IsDoubleElementsKind(elements_kind)
1696 Node* value = jsgraph()->TheHoleConstant();
1697
1698 // Actually allocate the backing store.
1699 AllocationBuilder a(jsgraph(), broker(), effect, control);
1700 a.AllocateArray(capacity, MakeRef(broker(), elements_map), allocation);
1701 for (int i = 0; i < capacity; ++i) {
1702 Node* index = jsgraph()->ConstantNoHole(i);
1703 a.Store(access, index, value);
1704 }
1705 return a.Finish();
1706}
1707
1709 ElementsKind elements_kind,
1710 std::vector<Node*> const& values,
1711 AllocationType allocation) {
1712 int const capacity = static_cast<int>(values.size());
1713 DCHECK_LE(1, capacity);
1715
1716 Handle<Map> elements_map = IsDoubleElementsKind(elements_kind)
1717 ? factory()->fixed_double_array_map()
1718 : factory()->fixed_array_map();
1719 ElementAccess access = IsDoubleElementsKind(elements_kind)
1722
1723 // Actually allocate the backing store.
1724 AllocationBuilder a(jsgraph(), broker(), effect, control);
1725 a.AllocateArray(capacity, MakeRef(broker(), elements_map), allocation);
1726 for (int i = 0; i < capacity; ++i) {
1727 Node* index = jsgraph()->ConstantNoHole(i);
1728 a.Store(access, index, values[i]);
1729 }
1730 return a.Finish();
1731}
1732
1734 Node* effect, Node* control, JSObjectRef boilerplate,
1735 AllocationType allocation, int max_depth, int* max_properties) {
1736 DCHECK_GE(max_depth, 0);
1737 DCHECK_GE(*max_properties, 0);
1738
1739 if (max_depth == 0) return {};
1740
1741 // Prevent concurrent migrations of boilerplate objects.
1742 JSHeapBroker::BoilerplateMigrationGuardIfNeeded boilerplate_access_guard(
1743 broker());
1744
1745 // Now that we hold the migration lock, get the current map.
1746 MapRef boilerplate_map = boilerplate.map(broker());
1747 // Protect against concurrent changes to the boilerplate object by checking
1748 // for an identical value at the end of the compilation.
1750 boilerplate_map);
1751 {
1752 OptionalMapRef current_boilerplate_map =
1753 boilerplate.map_direct_read(broker());
1754 if (!current_boilerplate_map.has_value() ||
1755 !current_boilerplate_map->equals(boilerplate_map)) {
1756 return {};
1757 }
1758 }
1759
1760 // Bail out if the boilerplate map has been deprecated. The map could of
1761 // course be deprecated at some point after the line below, but it's not a
1762 // correctness issue -- it only means the literal won't be created with the
1763 // most up to date map(s).
1764 if (boilerplate_map.is_deprecated()) return {};
1765
1766 // We currently only support in-object properties.
1767 if (boilerplate.map(broker()).elements_kind() == DICTIONARY_ELEMENTS ||
1768 boilerplate.map(broker()).is_dictionary_map() ||
1769 !boilerplate.raw_properties_or_hash(broker()).has_value()) {
1770 return {};
1771 }
1772 {
1773 ObjectRef properties = *boilerplate.raw_properties_or_hash(broker());
1774 bool const empty = properties.IsSmi() ||
1775 properties.equals(broker()->empty_fixed_array()) ||
1776 properties.equals(broker()->empty_property_array());
1777 if (!empty) return {};
1778 }
1779
1780 // Compute the in-object properties to store first (might have effects).
1782 inobject_fields.reserve(boilerplate_map.GetInObjectProperties());
1783 int const boilerplate_nof = boilerplate_map.NumberOfOwnDescriptors();
1784 for (InternalIndex i : InternalIndex::Range(boilerplate_nof)) {
1785 PropertyDetails const property_details =
1786 boilerplate_map.GetPropertyDetails(broker(), i);
1787 if (property_details.location() != PropertyLocation::kField) continue;
1788 DCHECK_EQ(PropertyKind::kData, property_details.kind());
1789 if ((*max_properties)-- == 0) return {};
1790
1791 NameRef property_name = boilerplate_map.GetPropertyKey(broker(), i);
1792 FieldIndex index =
1793 FieldIndex::ForDetails(*boilerplate_map.object(), property_details);
1794 ConstFieldInfo const_field_info(boilerplate_map);
1795 FieldAccess access = {kTaggedBase,
1796 index.offset(),
1797 property_name.object(),
1798 OptionalMapRef(),
1799 Type::Any(),
1802 "TryAllocateFastLiteral",
1803 const_field_info};
1804
1805 // Note: the use of RawInobjectPropertyAt (vs. the higher-level
1806 // GetOwnFastConstantDataProperty) here is necessary, since the underlying
1807 // value may be `uninitialized`, which the latter explicitly does not
1808 // support.
1809 OptionalObjectRef maybe_boilerplate_value =
1810 boilerplate.RawInobjectPropertyAt(broker(), index);
1811 if (!maybe_boilerplate_value.has_value()) return {};
1812
1813 // Note: We don't need to take a compilation dependency verifying the value
1814 // of `boilerplate_value`, since boilerplate properties are constant after
1815 // initialization modulo map migration. We protect against concurrent map
1816 // migrations (other than elements kind transition, which don't affect us)
1817 // via the boilerplate_migration_access lock.
1818 ObjectRef boilerplate_value = maybe_boilerplate_value.value();
1819
1820 // Uninitialized fields are marked through the `uninitialized_value` marker
1821 // (even for Smi representation!), or in the case of Double representation
1822 // through a HeapNumber containing the hole-NaN. Since Double-to-Tagged
1823 // representation changes are done in-place, we may even encounter these
1824 // HeapNumbers in Tagged representation.
1825 // Note that although we create nodes to write `uninitialized_value` into
1826 // the object, the field should be overwritten immediately with a real
1827 // value, and `uninitialized_value` should never be exposed to JS.
1828 ObjectRef uninitialized_marker = broker()->uninitialized_value();
1829 if (boilerplate_value.equals(uninitialized_marker) ||
1830 (boilerplate_value.IsHeapNumber() &&
1831 boilerplate_value.AsHeapNumber().value_as_bits() == kHoleNanInt64)) {
1832 access.const_field_info = ConstFieldInfo::None();
1833 }
1834
1835 Node* value;
1836 if (boilerplate_value.IsJSObject()) {
1837 JSObjectRef boilerplate_object = boilerplate_value.AsJSObject();
1838 std::optional<Node*> maybe_value =
1839 TryAllocateFastLiteral(effect, control, boilerplate_object,
1840 allocation, max_depth - 1, max_properties);
1841 if (!maybe_value.has_value()) return {};
1842 value = effect = maybe_value.value();
1843 } else if (property_details.representation().IsDouble()) {
1844 double number = boilerplate_value.AsHeapNumber().value();
1845 // Allocate a mutable HeapNumber box and store the value into it.
1846 AllocationBuilder builder(jsgraph(), broker(), effect, control);
1847 builder.Allocate(sizeof(HeapNumber), allocation);
1848 builder.Store(AccessBuilder::ForMap(), broker()->heap_number_map());
1850 jsgraph()->ConstantMaybeHole(number));
1851 value = effect = builder.Finish();
1852 } else {
1853 // It's fine to store the 'uninitialized' marker into a Smi field since
1854 // it will get overwritten anyways and the store's MachineType (AnyTagged)
1855 // is compatible with it.
1856 DCHECK_IMPLIES(property_details.representation().IsSmi() &&
1857 !boilerplate_value.IsSmi(),
1858 boilerplate_value.equals(uninitialized_marker));
1859 value = jsgraph()->ConstantMaybeHole(boilerplate_value, broker());
1860 }
1861 inobject_fields.push_back(std::make_pair(access, value));
1862 }
1863
1864 // Fill slack at the end of the boilerplate object with filler maps.
1865 int const boilerplate_length = boilerplate_map.GetInObjectProperties();
1866 for (int index = static_cast<int>(inobject_fields.size());
1867 index < boilerplate_length; ++index) {
1869 // TODO(wenyuzhao): Fix incorrect MachineType when V8_MAP_PACKING is
1870 // enabled.
1871 FieldAccess access =
1872 AccessBuilder::ForJSObjectInObjectProperty(boilerplate_map, index);
1873 Node* value =
1874 jsgraph()->HeapConstantNoHole(factory()->one_pointer_filler_map());
1875 inobject_fields.push_back(std::make_pair(access, value));
1876 }
1877
1878 // Setup the elements backing store.
1879 std::optional<Node*> maybe_elements = TryAllocateFastLiteralElements(
1880 effect, control, boilerplate, allocation, max_depth, max_properties);
1881 if (!maybe_elements.has_value()) return {};
1882 Node* elements = maybe_elements.value();
1883 if (elements->op()->EffectOutputCount() > 0) effect = elements;
1884
1885 // Actually allocate and initialize the object.
1886 AllocationBuilder builder(jsgraph(), broker(), effect, control);
1887 builder.Allocate(boilerplate_map.instance_size(), allocation,
1888 Type::For(boilerplate_map, broker()));
1889 builder.Store(AccessBuilder::ForMap(), boilerplate_map);
1891 jsgraph()->EmptyFixedArrayConstant());
1892 builder.Store(AccessBuilder::ForJSObjectElements(), elements);
1893 if (boilerplate.IsJSArray()) {
1894 JSArrayRef boilerplate_array = boilerplate.AsJSArray();
1896 boilerplate_array.map(broker()).elements_kind()),
1897 boilerplate_array.GetBoilerplateLength(broker()));
1898 }
1899 for (auto const& inobject_field : inobject_fields) {
1900 builder.Store(inobject_field.first, inobject_field.second);
1901 }
1902 return builder.Finish();
1903}
1904
1906 Node* effect, Node* control, JSObjectRef boilerplate,
1907 AllocationType allocation, int max_depth, int* max_properties) {
1908 DCHECK_GT(max_depth, 0);
1909 DCHECK_GE(*max_properties, 0);
1910
1911 OptionalFixedArrayBaseRef maybe_boilerplate_elements =
1912 boilerplate.elements(broker(), kRelaxedLoad);
1913 if (!maybe_boilerplate_elements.has_value()) return {};
1914 FixedArrayBaseRef boilerplate_elements = maybe_boilerplate_elements.value();
1915 // Protect against concurrent changes to the boilerplate object by checking
1916 // for an identical value at the end of the compilation.
1918 boilerplate, JSObject::kElementsOffset, boilerplate_elements);
1919
1920 // Empty or copy-on-write elements just store a constant.
1921 const uint32_t elements_length = boilerplate_elements.length();
1922 MapRef elements_map = boilerplate_elements.map(broker());
1923 // Protect against concurrent changes to the boilerplate object by checking
1924 // for an identical value at the end of the compilation.
1925 dependencies()->DependOnObjectSlotValue(boilerplate_elements,
1926 HeapObject::kMapOffset, elements_map);
1927 if (boilerplate_elements.length() == 0 ||
1928 elements_map.IsFixedCowArrayMap(broker())) {
1929 if (allocation == AllocationType::kOld &&
1930 !boilerplate.IsElementsTenured(boilerplate_elements)) {
1931 return {};
1932 }
1933 return jsgraph()->ConstantNoHole(boilerplate_elements, broker());
1934 }
1935
1936 // Compute the elements to store first (might have effects).
1937 ZoneVector<Node*> elements_values(elements_length, zone());
1938 if (boilerplate_elements.IsFixedDoubleArray()) {
1939 uint32_t const size =
1940 FixedDoubleArray::SizeFor(boilerplate_elements.length());
1941 if (size > kMaxRegularHeapObjectSize) return {};
1942
1943 FixedDoubleArrayRef elements = boilerplate_elements.AsFixedDoubleArray();
1944 for (uint32_t i = 0; i < elements_length; ++i) {
1945 Float64 value = elements.GetFromImmutableFixedDoubleArray(i);
1946 elements_values[i] = value.is_hole_nan()
1947 ? jsgraph()->TheHoleConstant()
1948 : jsgraph()->ConstantNoHole(value.get_scalar());
1949 }
1950 } else {
1951 FixedArrayRef elements = boilerplate_elements.AsFixedArray();
1952 for (uint32_t i = 0; i < elements_length; ++i) {
1953 if ((*max_properties)-- == 0) return {};
1954 OptionalObjectRef element_value = elements.TryGet(broker(), i);
1955 if (!element_value.has_value()) return {};
1956 if (element_value->IsJSObject()) {
1957 std::optional<Node*> object =
1958 TryAllocateFastLiteral(effect, control, element_value->AsJSObject(),
1959 allocation, max_depth - 1, max_properties);
1960 if (!object.has_value()) return {};
1961 elements_values[i] = effect = *object;
1962 } else {
1963 elements_values[i] =
1964 jsgraph()->ConstantMaybeHole(*element_value, broker());
1965 }
1966 }
1967 }
1968
1969 // Allocate the backing store array and store the elements.
1970 AllocationBuilder ab(jsgraph(), broker(), effect, control);
1971 CHECK(ab.CanAllocateArray(elements_length, elements_map, allocation));
1972 ab.AllocateArray(elements_length, elements_map, allocation);
1973 ElementAccess const access = boilerplate_elements.IsFixedDoubleArray()
1976 for (uint32_t i = 0; i < elements_length; ++i) {
1977 ab.Store(access, jsgraph()->ConstantNoHole(i), elements_values[i]);
1978 }
1979 return ab.Finish();
1980}
1981
1983 Node* effect, Node* control, RegExpBoilerplateDescriptionRef boilerplate) {
1985 native_context().regexp_function(broker()).initial_map(broker());
1986
1987 // Sanity check that JSRegExp object layout hasn't changed.
1988 static_assert(JSRegExp::kDataOffset == JSObject::kHeaderSize);
1989 static_assert(JSRegExp::kSourceOffset == JSRegExp::kDataOffset + kTaggedSize);
1990 static_assert(JSRegExp::kFlagsOffset ==
1991 JSRegExp::kSourceOffset + kTaggedSize);
1992 static_assert(JSRegExp::kHeaderSize == JSRegExp::kFlagsOffset + kTaggedSize);
1993 static_assert(JSRegExp::kLastIndexOffset == JSRegExp::kHeaderSize);
1995
1996 AllocationBuilder builder(jsgraph(), broker(), effect, control);
2001 jsgraph()->EmptyFixedArrayConstant());
2003 jsgraph()->EmptyFixedArrayConstant());
2004
2005 builder.Store(AccessBuilder::ForJSRegExpData(), boilerplate.data(broker()));
2007 boilerplate.source(broker()));
2009 jsgraph()->SmiConstant(boilerplate.flags()));
2012
2013 return builder.Finish();
2014}
2015
2017 return jsgraph()->isolate()->factory();
2018}
2019
2021
2025
2029
2033
2037
2038} // namespace compiler
2039} // namespace internal
2040} // namespace v8
int16_t parameter_count
Definition builtins.cc:67
static FieldIndex ForDetails(Tagged< Map > map, PropertyDetails details)
static constexpr int kMapOffset
v8::internal::Factory * factory()
Definition isolate.h:1527
static const int kInitialMaxFastElementArray
Definition js-array.h:144
static const int kPreallocatedArrayElements
Definition js-array.h:122
static constexpr int kSizeWithPrototype
static constexpr int kSizeWithoutPrototype
static const int kGeneratorExecuting
static const int kSizeWithEmbedderFields
Definition js-promise.h:75
static constexpr int Size()
Definition js-regexp.h:119
static constexpr int kLastIndexOffset
Definition js-regexp.h:108
static constexpr int kInitialLastIndexValue
Definition js-regexp.h:111
static constexpr MachineType AnyTagged()
static constexpr int kFlagsDefault
Definition dictionary.h:262
static const int kFlagsIndex
Definition dictionary.h:247
static const int kInitialCapacity
Definition dictionary.h:250
static const int kNoHashSentinel
PropertyLocation location() const
Representation representation() const
static const int kProtectorValid
Definition protectors.h:15
constexpr bool IsSmi() const
constexpr bool IsDouble() const
void reserve(size_t new_cap)
void push_back(const T &value)
static ElementAccess ForFixedArrayElement()
static ElementAccess ForSloppyArgumentsElementsMappedEntry()
static FieldAccess ForJSCollectionIteratorTable()
static FieldAccess ForMap(WriteBarrierKind write_barrier=kMapWriteBarrier)
static FieldAccess ForJSBoundFunctionBoundTargetFunction()
static FieldAccess ForJSBoundFunctionBoundArguments()
static FieldAccess ForJSObjectOffset(int offset, WriteBarrierKind write_barrier_kind=kFullWriteBarrier)
static FieldAccess ForSloppyArgumentsElementsArguments()
static FieldAccess ForFixedArraySlot(size_t index, WriteBarrierKind write_barrier_kind=kFullWriteBarrier)
static FieldAccess ForJSArrayIteratorNextIndex()
static FieldAccess ForJSObjectPropertiesOrHashKnownPointer()
static FieldAccess ForJSArrayIteratorIteratedObject()
static FieldAccess ForHashTableBaseNumberOfElements()
static FieldAccess ForJSBoundFunctionBoundThis()
static FieldAccess ForJSCollectionIteratorIndex()
static FieldAccess ForJSObjectInObjectProperty(MapRef map, int index, MachineType machine_type=MachineType::AnyTagged())
static FieldAccess ForJSGeneratorObjectContext()
static FieldAccess ForJSFunctionSharedFunctionInfo()
static FieldAccess ForJSGeneratorObjectInputOrDebugPos()
static FieldAccess ForJSArrayLength(ElementsKind elements_kind)
static FieldAccess ForJSIteratorResultValue()
static FieldAccess ForJSPrimitiveWrapperValue()
static FieldAccess ForJSAsyncFunctionObjectPromise()
static FieldAccess ForContextSlot(size_t index)
static FieldAccess ForJSObjectPropertiesOrHash()
static FieldAccess ForJSFunctionFeedbackCell()
static ElementAccess ForFixedDoubleArrayElement()
static FieldAccess ForJSGeneratorObjectReceiver()
static FieldAccess ForHashTableBaseNumberOfDeletedElement()
static FieldAccess ForNameDictionaryFlagsIndex()
static FieldAccess ForJSGeneratorObjectFunction()
static FieldAccess ForDictionaryNextEnumerationIndex()
static FieldAccess ForJSGeneratorObjectResumeMode()
static FieldAccess ForSloppyArgumentsElementsContext()
static FieldAccess ForJSAsyncGeneratorObjectQueue()
static FieldAccess ForJSAsyncGeneratorObjectIsAwaiting()
static FieldAccess ForJSGeneratorObjectContinuation()
static FieldAccess ForJSFunctionPrototypeOrInitialMap()
static FieldAccess ForDictionaryObjectHashIndex()
static FieldAccess ForJSGeneratorObjectParametersAndRegisters()
void AllocateArray(int length, MapRef map, AllocationType allocation=AllocationType::kYoung)
void Allocate(int size, AllocationType allocation=AllocationType::kYoung, Type type=Type::Any())
bool CanAllocateArray(int length, MapRef map, AllocationType allocation=AllocationType::kYoung)
bool CanAllocateSloppyArgumentElements(int length, MapRef map, AllocationType allocation=AllocationType::kYoung)
void Store(const FieldAccess &access, Node *value)
SlackTrackingPrediction DependOnInitialMapInstanceSizePrediction(JSFunctionRef function)
void DependOnObjectSlotValue(HeapObjectRef object, int offset, ObjectRef value)
AllocationType DependOnPretenureMode(AllocationSiteRef site)
OptionalAllocationSiteRef site() const
SharedFunctionInfoRef shared_info() const
FeedbackSource const & feedback() const
IndirectHandle< FeedbackCell > object() const
FeedbackSource const & feedback() const
OptionalObjectRef TryGet(JSHeapBroker *broker, int i) const
Float64 GetFromImmutableFixedDoubleArray(int i) const
MaybeIndirectHandle< SharedFunctionInfo > shared_info() const
const FrameStateInfo & frame_state_info() const
OptionalMapRef map_direct_read(JSHeapBroker *broker) const
V8_EXPORT_PRIVATE MapRef map(JSHeapBroker *broker) const
ObjectRef GetBoilerplateLength(JSHeapBroker *broker) const
Node * TryAllocateArguments(Node *effect, Node *control, FrameState frame_state)
Node * AllocateLiteralRegExp(Node *effect, Node *control, RegExpBoilerplateDescriptionRef boilerplate)
Reduction ReduceNewArray(Node *node, Node *length, MapRef initial_map, ElementsKind elements_kind, AllocationType allocation, const SlackTrackingPrediction &slack_tracking_prediction)
std::optional< Node * > TryAllocateFastLiteralElements(Node *effect, Node *control, JSObjectRef boilerplate, AllocationType allocation, int max_depth, int *max_properties)
Node * TryAllocateRestArguments(Node *effect, Node *control, FrameState frame_state, int start_index)
SimplifiedOperatorBuilder * simplified() const
CompilationDependencies * dependencies() const
Node * TryAllocateAliasedArguments(Node *effect, Node *control, FrameState frame_state, Node *context, SharedFunctionInfoRef shared, bool *has_aliased_arguments)
std::optional< Node * > TryAllocateFastLiteral(Node *effect, Node *control, JSObjectRef boilerplate, AllocationType allocation, int max_depth, int *max_properties)
Node * AllocateElements(Node *effect, Node *control, ElementsKind elements_kind, int capacity, AllocationType allocation)
SharedFunctionInfoRef shared(JSHeapBroker *broker) const
bool has_initial_map(JSHeapBroker *broker) const
MapRef initial_map(JSHeapBroker *broker) const
Node * ConstantMaybeHole(ObjectRef ref, JSHeapBroker *broker)
Definition js-graph.cc:64
SimplifiedOperatorBuilder * simplified() const
Definition js-graph.h:105
Node * HeapConstantNoHole(Handle< HeapObject > value)
Definition js-graph.cc:146
Isolate * isolate() const
Definition js-graph.h:106
Node * ConstantNoHole(ObjectRef ref, JSHeapBroker *broker)
Definition js-graph.cc:51
Node * SmiConstant(int32_t immediate)
Definition js-graph.h:99
CompilationDependencies * dependencies() const
ProcessedFeedback const & GetFeedbackForArrayOrObjectLiteral(FeedbackSource const &source)
NativeContextRef target_native_context() const
ProcessedFeedback const & GetFeedbackForTemplateObject(FeedbackSource const &source)
ProcessedFeedback const & GetFeedbackForRegExpLiteral(FeedbackSource const &source)
OptionalFixedArrayBaseRef elements(JSHeapBroker *broker, RelaxedLoadTag) const
OptionalObjectRef RawInobjectPropertyAt(JSHeapBroker *broker, FieldIndex index) const
OptionalObjectRef raw_properties_or_hash(JSHeapBroker *broker) const
bool IsElementsTenured(FixedArrayBaseRef elements)
CommonOperatorBuilder * common() const
NameRef GetPropertyKey(JSHeapBroker *broker, InternalIndex descriptor_index) const
PropertyDetails GetPropertyDetails(JSHeapBroker *broker, InternalIndex descriptor_index) const
IndirectHandle< Map > object() const
bool IsFixedCowArrayMap(JSHeapBroker *broker) const
HeapObjectRef prototype(JSHeapBroker *broker) const
bool IsInobjectSlackTrackingInProgress() const
IndirectHandle< Name > object() const
MapRef GetFunctionMapFromIndex(JSHeapBroker *broker, int index) const
MapRef GetInitialJSArrayMap(JSHeapBroker *broker, ElementsKind kind) const
static Type GetType(const Node *node)
static OptionalMapRef GetJSCreateMap(JSHeapBroker *broker, Node *receiver)
static Node * GetEffectInput(Node *node, int index=0)
static Node * GetContextInput(Node *node)
static Node * GetFrameStateInput(Node *node)
static Node * GetValueInput(Node *node, int index)
static Node * GetControlInput(Node *node, int index=0)
constexpr IrOpcode::Value opcode() const
Definition node.h:52
const Operator * op() const
Definition node.h:50
void CacheAsProtector(JSHeapBroker *broker) const
Definition heap-refs.h:545
ObjectRef value(JSHeapBroker *broker) const
StringRef source(JSHeapBroker *broker) const
HeapObjectRef data(JSHeapBroker *broker) const
Node * NewNode(const Operator *op, int input_count, Node *const *inputs, bool incomplete=false)
bool Maybe(Type that) const
const HeapConstantType * AsHeapConstant() const
static Type For(MapRef type, JSHeapBroker *broker)
bool Is(Type that) const
#define V8_MAP_PACKING_BOOL
Definition globals.h:93
#define ALIGN_TO_ALLOCATION_ALIGNMENT(value)
Definition globals.h:1796
int start
DirectHandle< Object > new_target
Definition execution.cc:75
Isolate * isolate
JSHeapBroker * broker
int32_t offset
std::string extension
std::optional< TNode< JSArray > > a
TNode< Object > receiver
FunctionLiteral * literal
Definition liveedit.cc:294
int n
Definition mul-fft.cc:296
constexpr bool IsPowerOfTwo(T value)
Definition bits.h:187
const CreateArrayIteratorParameters & CreateArrayIteratorParametersOf(const Operator *op)
const int kMaxFastLiteralDepth
Definition globals.h:127
const CreateBoundFunctionParameters & CreateBoundFunctionParametersOf(const Operator *op)
const int kMaxFastLiteralProperties
Definition globals.h:128
ScopeInfoRef ScopeInfoOf(const Operator *op)
const CreateCollectionIteratorParameters & CreateCollectionIteratorParametersOf(const Operator *op)
CreateFunctionContextParameters const & CreateFunctionContextParametersOf(Operator const *op)
const CreateArrayParameters & CreateArrayParametersOf(const Operator *op)
CreateArgumentsType const & CreateArgumentsTypeOf(const Operator *op)
int RegisterCountOf(Operator const *op)
ref_traits< T >::ref_type MakeRef(JSHeapBroker *broker, Tagged< T > object)
HeapObjectMatcherImpl< IrOpcode::kHeapConstant > HeapObjectMatcher
constexpr int kTaggedSize
Definition globals.h:542
constexpr int kMaxRegularHeapObjectSize
Definition globals.h:680
constexpr bool IsHoleyElementsKind(ElementsKind kind)
bool IsClassConstructor(FunctionKind kind)
bool Is(IndirectHandle< U > value)
Definition handles-inl.h:51
constexpr bool IsSmiElementsKind(ElementsKind kind)
constexpr uint64_t kHoleNanInt64
Definition globals.h:1960
constexpr JSDispatchHandle kNullJSDispatchHandle(0)
ElementsKind GetHoleyElementsKind(ElementsKind packed_kind)
DONT_OVERRIDE DISABLE_ALLOCATION_SITES HOLEY_ELEMENTS
bool IsFastElementsKind(ElementsKind kind)
DONT_OVERRIDE DISABLE_ALLOCATION_SITES DISABLE_ALLOCATION_SITES HOLEY_DOUBLE_ELEMENTS
return value
Definition map-inl.h:893
constexpr bool IsDoubleElementsKind(ElementsKind kind)
ElementsKind GetMoreGeneralElementsKind(ElementsKind from_kind, ElementsKind to_kind)
!IsContextMap !IsContextMap native_context
Definition map-inl.h:877
static constexpr RelaxedLoadTag kRelaxedLoad
Definition globals.h:2909
uint32_t equals
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487