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