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