• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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