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