Line data Source code
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/allocation-site-scopes.h"
8 : #include "src/code-factory.h"
9 : #include "src/compilation-dependencies.h"
10 : #include "src/compiler/access-builder.h"
11 : #include "src/compiler/allocation-builder.h"
12 : #include "src/compiler/common-operator.h"
13 : #include "src/compiler/js-graph.h"
14 : #include "src/compiler/js-operator.h"
15 : #include "src/compiler/linkage.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 :
23 : namespace v8 {
24 : namespace internal {
25 : namespace compiler {
26 :
27 : namespace {
28 :
29 : // Retrieves the frame state holding actual argument values.
30 1296 : Node* GetArgumentsFrameState(Node* frame_state) {
31 1296 : Node* const outer_state = NodeProperties::GetFrameStateInput(frame_state);
32 1296 : FrameStateInfo outer_state_info = OpParameter<FrameStateInfo>(outer_state);
33 : return outer_state_info.type() == FrameStateType::kArgumentsAdaptor
34 : ? outer_state
35 1296 : : frame_state;
36 : }
37 :
38 : // Checks whether allocation using the given target and new.target can be
39 : // inlined.
40 5495 : bool IsAllocationInlineable(Handle<JSFunction> target,
41 : Handle<JSFunction> new_target) {
42 10986 : return new_target->has_initial_map() &&
43 10986 : !new_target->initial_map()->is_dictionary_map() &&
44 5495 : new_target->initial_map()->constructor_or_backpointer() == *target;
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 : // Determines whether the given array or object literal boilerplate satisfies
56 : // all limits to be considered for fast deep-copying and computes the total
57 : // size of all objects that are part of the graph.
58 5384 : bool IsFastLiteral(Handle<JSObject> boilerplate, int max_depth,
59 : int* max_properties) {
60 : DCHECK_GE(max_depth, 0);
61 : DCHECK_GE(*max_properties, 0);
62 :
63 : // Make sure the boilerplate map is not deprecated.
64 5384 : if (!JSObject::TryMigrateInstance(boilerplate)) return false;
65 :
66 : // Check for too deep nesting.
67 5384 : if (max_depth == 0) return false;
68 :
69 : // Check the elements.
70 : Isolate* const isolate = boilerplate->GetIsolate();
71 : Handle<FixedArrayBase> elements(boilerplate->elements(), isolate);
72 8740 : if (elements->length() > 0 &&
73 3356 : elements->map() != isolate->heap()->fixed_cow_array_map()) {
74 1624 : if (boilerplate->HasSmiOrObjectElements()) {
75 : Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
76 : int length = elements->length();
77 8664 : for (int i = 0; i < length; i++) {
78 7634 : if ((*max_properties)-- == 0) return false;
79 : Handle<Object> value(fast_elements->get(i), isolate);
80 7625 : if (value->IsJSObject()) {
81 497 : Handle<JSObject> value_object = Handle<JSObject>::cast(value);
82 497 : if (!IsFastLiteral(value_object, max_depth - 1, max_properties)) {
83 0 : return false;
84 : }
85 : }
86 : }
87 585 : } else if (boilerplate->HasDoubleElements()) {
88 553 : if (elements->Size() > kMaxRegularHeapObjectSize) return false;
89 : } else {
90 : return false;
91 : }
92 : }
93 :
94 : // TODO(turbofan): Do we want to support out-of-object properties?
95 10670 : if (!(boilerplate->HasFastProperties() &&
96 10630 : boilerplate->property_array()->length() == 0)) {
97 : return false;
98 : }
99 :
100 : // Check the in-object properties.
101 : Handle<DescriptorArray> descriptors(
102 : boilerplate->map()->instance_descriptors(), isolate);
103 : int limit = boilerplate->map()->NumberOfOwnDescriptors();
104 10949 : for (int i = 0; i < limit; i++) {
105 5654 : PropertyDetails details = descriptors->GetDetails(i);
106 8954 : if (details.location() != kField) continue;
107 : DCHECK_EQ(kData, details.kind());
108 2448 : if ((*max_properties)-- == 0) return false;
109 2448 : FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i);
110 2448 : if (boilerplate->IsUnboxedDoubleField(field_index)) continue;
111 2354 : Handle<Object> value(boilerplate->RawFastPropertyAt(field_index), isolate);
112 2354 : if (value->IsJSObject()) {
113 292 : Handle<JSObject> value_object = Handle<JSObject>::cast(value);
114 292 : if (!IsFastLiteral(value_object, max_depth - 1, max_properties)) {
115 0 : return false;
116 : }
117 : }
118 : }
119 : return true;
120 : }
121 :
122 : // Maximum depth and total number of elements and properties for literal
123 : // graphs to be considered for fast deep-copying. The limit is chosen to
124 : // match the maximum number of inobject properties, to ensure that the
125 : // performance of using object literals is not worse than using constructor
126 : // functions, see crbug.com/v8/6211 for details.
127 : const int kMaxFastLiteralDepth = 3;
128 : const int kMaxFastLiteralProperties = JSObject::kMaxInObjectProperties;
129 :
130 : } // namespace
131 :
132 31819399 : Reduction JSCreateLowering::Reduce(Node* node) {
133 31819399 : switch (node->opcode()) {
134 : case IrOpcode::kJSCreate:
135 6411 : return ReduceJSCreate(node);
136 : case IrOpcode::kJSCreateArguments:
137 17954 : return ReduceJSCreateArguments(node);
138 : case IrOpcode::kJSCreateArray:
139 1153 : return ReduceJSCreateArray(node);
140 : case IrOpcode::kJSCreateBoundFunction:
141 94 : return ReduceJSCreateBoundFunction(node);
142 : case IrOpcode::kJSCreateClosure:
143 585545 : return ReduceJSCreateClosure(node);
144 : case IrOpcode::kJSCreateIterResultObject:
145 2963 : return ReduceJSCreateIterResultObject(node);
146 : case IrOpcode::kJSCreateKeyValueArray:
147 84 : return ReduceJSCreateKeyValueArray(node);
148 : case IrOpcode::kJSCreateLiteralArray:
149 : case IrOpcode::kJSCreateLiteralObject:
150 61692 : return ReduceJSCreateLiteralArrayOrObject(node);
151 : case IrOpcode::kJSCreateLiteralRegExp:
152 10168 : return ReduceJSCreateLiteralRegExp(node);
153 : case IrOpcode::kJSCreateEmptyLiteralArray:
154 23220 : return ReduceJSCreateEmptyLiteralArray(node);
155 : case IrOpcode::kJSCreateEmptyLiteralObject:
156 6879 : return ReduceJSCreateEmptyLiteralObject(node);
157 : case IrOpcode::kJSCreateFunctionContext:
158 27323 : return ReduceJSCreateFunctionContext(node);
159 : case IrOpcode::kJSCreateWithContext:
160 494 : return ReduceJSCreateWithContext(node);
161 : case IrOpcode::kJSCreateCatchContext:
162 17904 : return ReduceJSCreateCatchContext(node);
163 : case IrOpcode::kJSCreateBlockContext:
164 8881 : return ReduceJSCreateBlockContext(node);
165 : case IrOpcode::kJSCreateGeneratorObject:
166 1586 : return ReduceJSCreateGeneratorObject(node);
167 : default:
168 : break;
169 : }
170 : return NoChange();
171 : }
172 :
173 32127 : Reduction JSCreateLowering::ReduceJSCreate(Node* node) {
174 : DCHECK_EQ(IrOpcode::kJSCreate, node->opcode());
175 6411 : Node* const target = NodeProperties::GetValueInput(node, 0);
176 : Type* const target_type = NodeProperties::GetType(target);
177 6411 : Node* const new_target = NodeProperties::GetValueInput(node, 1);
178 : Type* const new_target_type = NodeProperties::GetType(new_target);
179 6411 : Node* const effect = NodeProperties::GetEffectInput(node);
180 6411 : Node* const control = NodeProperties::GetControlInput(node);
181 : // Extract constructor and original constructor function.
182 17165 : if (target_type->IsHeapConstant() && new_target_type->IsHeapConstant() &&
183 10761 : target_type->AsHeapConstant()->Value()->IsJSFunction() &&
184 : new_target_type->AsHeapConstant()->Value()->IsJSFunction()) {
185 : Handle<JSFunction> constructor =
186 : Handle<JSFunction>::cast(target_type->AsHeapConstant()->Value());
187 4350 : if (!constructor->IsConstructor()) return NoChange();
188 : Handle<JSFunction> original_constructor =
189 : Handle<JSFunction>::cast(new_target_type->AsHeapConstant()->Value());
190 4350 : if (!original_constructor->IsConstructor()) return NoChange();
191 :
192 : // Check if we can inline the allocation.
193 4342 : if (IsAllocationInlineable(constructor, original_constructor)) {
194 : // Force completion of inobject slack tracking before
195 : // generating code to finalize the instance size.
196 4338 : original_constructor->CompleteInobjectSlackTrackingIfActive();
197 : Handle<Map> initial_map(original_constructor->initial_map(), isolate());
198 : int const instance_size = initial_map->instance_size();
199 :
200 : // Add a dependency on the {initial_map} to make sure that this code is
201 : // deoptimized whenever the {initial_map} changes.
202 : dependencies()->AssumeInitialMapCantChange(initial_map);
203 :
204 : // Emit code to allocate the JSObject instance for the
205 : // {original_constructor}.
206 : AllocationBuilder a(jsgraph(), effect, control);
207 4338 : a.Allocate(instance_size);
208 4338 : a.Store(AccessBuilder::ForMap(), initial_map);
209 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
210 4338 : jsgraph()->EmptyFixedArrayConstant());
211 : a.Store(AccessBuilder::ForJSObjectElements(),
212 4338 : jsgraph()->EmptyFixedArrayConstant());
213 25404 : for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) {
214 : a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
215 8364 : jsgraph()->UndefinedConstant());
216 : }
217 : RelaxControls(node);
218 4338 : a.FinishAndChange(node);
219 : return Changed(node);
220 : }
221 : }
222 : return NoChange();
223 : }
224 :
225 55146 : Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
226 : DCHECK_EQ(IrOpcode::kJSCreateArguments, node->opcode());
227 17954 : CreateArgumentsType type = CreateArgumentsTypeOf(node->op());
228 17954 : Node* const frame_state = NodeProperties::GetFrameStateInput(node);
229 17954 : Node* const outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
230 17954 : Node* const control = graph()->start();
231 17954 : FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
232 : Handle<SharedFunctionInfo> shared =
233 : state_info.shared_info().ToHandleChecked();
234 :
235 : // Use the ArgumentsAccessStub for materializing both mapped and unmapped
236 : // arguments object, but only for non-inlined (i.e. outermost) frames.
237 17954 : if (outer_state->opcode() != IrOpcode::kFrameState) {
238 16658 : switch (type) {
239 : case CreateArgumentsType::kMappedArguments: {
240 : // TODO(mstarzinger): Duplicate parameters are not handled yet.
241 9817 : if (shared->has_duplicate_parameters()) return NoChange();
242 9811 : Node* const callee = NodeProperties::GetValueInput(node, 0);
243 9811 : Node* const context = NodeProperties::GetContextInput(node);
244 9811 : Node* effect = NodeProperties::GetEffectInput(node);
245 : Node* const arguments_frame =
246 9811 : graph()->NewNode(simplified()->ArgumentsFrame());
247 : Node* const arguments_length = graph()->NewNode(
248 : simplified()->ArgumentsLength(
249 : shared->internal_formal_parameter_count(), false),
250 9811 : arguments_frame);
251 : // Allocate the elements backing store.
252 9811 : bool has_aliased_arguments = false;
253 : Node* const elements = effect = AllocateAliasedArguments(
254 : effect, control, context, arguments_frame, arguments_length, shared,
255 9811 : &has_aliased_arguments);
256 : // Load the arguments object map.
257 : Node* const arguments_map = jsgraph()->HeapConstant(
258 : handle(has_aliased_arguments
259 : ? native_context()->fast_aliased_arguments_map()
260 : : native_context()->sloppy_arguments_map(),
261 19622 : isolate()));
262 : // Actually allocate and initialize the arguments object.
263 : AllocationBuilder a(jsgraph(), effect, control);
264 9811 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
265 : STATIC_ASSERT(JSSloppyArgumentsObject::kSize == 5 * kPointerSize);
266 9811 : a.Allocate(JSSloppyArgumentsObject::kSize);
267 9811 : a.Store(AccessBuilder::ForMap(), arguments_map);
268 9811 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
269 9811 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
270 9811 : a.Store(AccessBuilder::ForArgumentsLength(), arguments_length);
271 9811 : a.Store(AccessBuilder::ForArgumentsCallee(), callee);
272 : RelaxControls(node);
273 9811 : a.FinishAndChange(node);
274 : return Changed(node);
275 : }
276 : case CreateArgumentsType::kUnmappedArguments: {
277 6179 : Node* effect = NodeProperties::GetEffectInput(node);
278 : Node* const arguments_frame =
279 6179 : graph()->NewNode(simplified()->ArgumentsFrame());
280 : Node* const arguments_length = graph()->NewNode(
281 : simplified()->ArgumentsLength(
282 : shared->internal_formal_parameter_count(), false),
283 6179 : arguments_frame);
284 : // Allocate the elements backing store.
285 : Node* const elements = effect =
286 : graph()->NewNode(simplified()->NewArgumentsElements(0),
287 6179 : arguments_frame, arguments_length, effect);
288 : // Load the arguments object map.
289 : Node* const arguments_map = jsgraph()->HeapConstant(
290 6179 : handle(native_context()->strict_arguments_map(), isolate()));
291 : // Actually allocate and initialize the arguments object.
292 : AllocationBuilder a(jsgraph(), effect, control);
293 6179 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
294 : STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kPointerSize);
295 6179 : a.Allocate(JSStrictArgumentsObject::kSize);
296 6179 : a.Store(AccessBuilder::ForMap(), arguments_map);
297 6179 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
298 6179 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
299 6179 : a.Store(AccessBuilder::ForArgumentsLength(), arguments_length);
300 : RelaxControls(node);
301 6179 : a.FinishAndChange(node);
302 : return Changed(node);
303 : }
304 : case CreateArgumentsType::kRestParameter: {
305 662 : Node* effect = NodeProperties::GetEffectInput(node);
306 : Node* const arguments_frame =
307 662 : graph()->NewNode(simplified()->ArgumentsFrame());
308 : Node* const rest_length = graph()->NewNode(
309 : simplified()->ArgumentsLength(
310 : shared->internal_formal_parameter_count(), true),
311 662 : arguments_frame);
312 : // Allocate the elements backing store. Since NewArgumentsElements
313 : // copies from the end of the arguments adapter frame, this is a suffix
314 : // of the actual arguments.
315 : Node* const elements = effect =
316 : graph()->NewNode(simplified()->NewArgumentsElements(0),
317 662 : arguments_frame, rest_length, effect);
318 : // Load the JSArray object map.
319 : Node* const jsarray_map = jsgraph()->HeapConstant(handle(
320 662 : native_context()->js_array_fast_elements_map_index(), isolate()));
321 : // Actually allocate and initialize the jsarray.
322 : AllocationBuilder a(jsgraph(), effect, control);
323 662 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
324 : STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize);
325 662 : a.Allocate(JSArray::kSize);
326 662 : a.Store(AccessBuilder::ForMap(), jsarray_map);
327 662 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
328 662 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
329 662 : a.Store(AccessBuilder::ForJSArrayLength(PACKED_ELEMENTS), rest_length);
330 : RelaxControls(node);
331 662 : a.FinishAndChange(node);
332 : return Changed(node);
333 : }
334 : }
335 0 : UNREACHABLE();
336 1296 : } else if (outer_state->opcode() == IrOpcode::kFrameState) {
337 : // Use inline allocation for all mapped arguments objects within inlined
338 : // (i.e. non-outermost) frames, independent of the object size.
339 1296 : if (type == CreateArgumentsType::kMappedArguments) {
340 647 : Node* const callee = NodeProperties::GetValueInput(node, 0);
341 647 : Node* const context = NodeProperties::GetContextInput(node);
342 647 : Node* effect = NodeProperties::GetEffectInput(node);
343 : // TODO(mstarzinger): Duplicate parameters are not handled yet.
344 647 : if (shared->has_duplicate_parameters()) return NoChange();
345 : // Choose the correct frame state and frame state info depending on
346 : // whether there conceptually is an arguments adaptor frame in the call
347 : // chain.
348 647 : Node* const args_state = GetArgumentsFrameState(frame_state);
349 647 : FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
350 : // Prepare element backing store to be used by arguments object.
351 647 : bool has_aliased_arguments = false;
352 647 : Node* const elements = AllocateAliasedArguments(
353 647 : effect, control, args_state, context, shared, &has_aliased_arguments);
354 1294 : effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
355 : // Load the arguments object map.
356 : Node* const arguments_map = jsgraph()->HeapConstant(handle(
357 : has_aliased_arguments ? native_context()->fast_aliased_arguments_map()
358 : : native_context()->sloppy_arguments_map(),
359 1294 : isolate()));
360 : // Actually allocate and initialize the arguments object.
361 : AllocationBuilder a(jsgraph(), effect, control);
362 647 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
363 647 : int length = args_state_info.parameter_count() - 1; // Minus receiver.
364 : STATIC_ASSERT(JSSloppyArgumentsObject::kSize == 5 * kPointerSize);
365 647 : a.Allocate(JSSloppyArgumentsObject::kSize);
366 647 : a.Store(AccessBuilder::ForMap(), arguments_map);
367 647 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
368 647 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
369 647 : a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length));
370 647 : a.Store(AccessBuilder::ForArgumentsCallee(), callee);
371 : RelaxControls(node);
372 647 : a.FinishAndChange(node);
373 : return Changed(node);
374 649 : } else if (type == CreateArgumentsType::kUnmappedArguments) {
375 : // Use inline allocation for all unmapped arguments objects within inlined
376 : // (i.e. non-outermost) frames, independent of the object size.
377 397 : Node* effect = NodeProperties::GetEffectInput(node);
378 : // Choose the correct frame state and frame state info depending on
379 : // whether there conceptually is an arguments adaptor frame in the call
380 : // chain.
381 397 : Node* const args_state = GetArgumentsFrameState(frame_state);
382 397 : FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
383 : // Prepare element backing store to be used by arguments object.
384 397 : Node* const elements = AllocateArguments(effect, control, args_state);
385 794 : effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
386 : // Load the arguments object map.
387 : Node* const arguments_map = jsgraph()->HeapConstant(
388 397 : handle(native_context()->strict_arguments_map(), isolate()));
389 : // Actually allocate and initialize the arguments object.
390 : AllocationBuilder a(jsgraph(), effect, control);
391 397 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
392 397 : int length = args_state_info.parameter_count() - 1; // Minus receiver.
393 : STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kPointerSize);
394 397 : a.Allocate(JSStrictArgumentsObject::kSize);
395 397 : a.Store(AccessBuilder::ForMap(), arguments_map);
396 397 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
397 397 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
398 397 : a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length));
399 : RelaxControls(node);
400 397 : a.FinishAndChange(node);
401 : return Changed(node);
402 252 : } else if (type == CreateArgumentsType::kRestParameter) {
403 : int start_index = shared->internal_formal_parameter_count();
404 : // Use inline allocation for all unmapped arguments objects within inlined
405 : // (i.e. non-outermost) frames, independent of the object size.
406 252 : Node* effect = NodeProperties::GetEffectInput(node);
407 : // Choose the correct frame state and frame state info depending on
408 : // whether there conceptually is an arguments adaptor frame in the call
409 : // chain.
410 252 : Node* const args_state = GetArgumentsFrameState(frame_state);
411 252 : FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
412 : // Prepare element backing store to be used by the rest array.
413 252 : Node* const elements =
414 252 : AllocateRestArguments(effect, control, args_state, start_index);
415 504 : effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
416 : // Load the JSArray object map.
417 : Node* const jsarray_map = jsgraph()->HeapConstant(handle(
418 252 : native_context()->js_array_fast_elements_map_index(), isolate()));
419 : // Actually allocate and initialize the jsarray.
420 : AllocationBuilder a(jsgraph(), effect, control);
421 252 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
422 :
423 : // -1 to minus receiver
424 252 : int argument_count = args_state_info.parameter_count() - 1;
425 504 : int length = std::max(0, argument_count - start_index);
426 : STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize);
427 252 : a.Allocate(JSArray::kSize);
428 252 : a.Store(AccessBuilder::ForMap(), jsarray_map);
429 252 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
430 252 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
431 : a.Store(AccessBuilder::ForJSArrayLength(PACKED_ELEMENTS),
432 252 : jsgraph()->Constant(length));
433 : RelaxControls(node);
434 252 : a.FinishAndChange(node);
435 : return Changed(node);
436 : }
437 : }
438 :
439 : return NoChange();
440 : }
441 :
442 10946 : Reduction JSCreateLowering::ReduceJSCreateGeneratorObject(Node* node) {
443 : DCHECK_EQ(IrOpcode::kJSCreateGeneratorObject, node->opcode());
444 1586 : Node* const closure = NodeProperties::GetValueInput(node, 0);
445 1586 : Node* const receiver = NodeProperties::GetValueInput(node, 1);
446 1586 : Node* const context = NodeProperties::GetContextInput(node);
447 : Type* const closure_type = NodeProperties::GetType(closure);
448 1586 : Node* effect = NodeProperties::GetEffectInput(node);
449 1586 : Node* const control = NodeProperties::GetControlInput(node);
450 1586 : if (closure_type->IsHeapConstant()) {
451 : DCHECK(closure_type->AsHeapConstant()->Value()->IsJSFunction());
452 : Handle<JSFunction> js_function =
453 : Handle<JSFunction>::cast(closure_type->AsHeapConstant()->Value());
454 1560 : JSFunction::EnsureHasInitialMap(js_function);
455 :
456 : // Force completion of inobject slack tracking before
457 : // generating code to finalize the instance size.
458 1560 : js_function->CompleteInobjectSlackTrackingIfActive();
459 : Handle<Map> initial_map(js_function->initial_map(), isolate());
460 : DCHECK(initial_map->instance_type() == JS_GENERATOR_OBJECT_TYPE ||
461 : initial_map->instance_type() == JS_ASYNC_GENERATOR_OBJECT_TYPE);
462 :
463 : // Add a dependency on the {initial_map} to make sure that this code is
464 : // deoptimized whenever the {initial_map} changes.
465 : dependencies()->AssumeInitialMapCantChange(initial_map);
466 :
467 : // Allocate a register file.
468 : DCHECK(js_function->shared()->HasBytecodeArray());
469 : int size = js_function->shared()->bytecode_array()->register_count();
470 : Node* register_file = effect =
471 1560 : AllocateElements(effect, control, HOLEY_ELEMENTS, size, NOT_TENURED);
472 :
473 : // Emit code to allocate the JS[Async]GeneratorObject instance.
474 : AllocationBuilder a(jsgraph(), effect, control);
475 1560 : a.Allocate(initial_map->instance_size());
476 1560 : Node* empty_fixed_array = jsgraph()->EmptyFixedArrayConstant();
477 1560 : Node* undefined = jsgraph()->UndefinedConstant();
478 1560 : a.Store(AccessBuilder::ForMap(), initial_map);
479 1560 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), empty_fixed_array);
480 1560 : a.Store(AccessBuilder::ForJSObjectElements(), empty_fixed_array);
481 1560 : a.Store(AccessBuilder::ForJSGeneratorObjectContext(), context);
482 1560 : a.Store(AccessBuilder::ForJSGeneratorObjectFunction(), closure);
483 1560 : a.Store(AccessBuilder::ForJSGeneratorObjectReceiver(), receiver);
484 1560 : a.Store(AccessBuilder::ForJSGeneratorObjectInputOrDebugPos(), undefined);
485 : a.Store(AccessBuilder::ForJSGeneratorObjectResumeMode(),
486 1560 : jsgraph()->Constant(JSGeneratorObject::kNext));
487 : a.Store(AccessBuilder::ForJSGeneratorObjectContinuation(),
488 1560 : jsgraph()->Constant(JSGeneratorObject::kGeneratorExecuting));
489 1560 : a.Store(AccessBuilder::ForJSGeneratorObjectRegisterFile(), register_file);
490 :
491 1560 : if (initial_map->instance_type() == JS_ASYNC_GENERATOR_OBJECT_TYPE) {
492 144 : a.Store(AccessBuilder::ForJSAsyncGeneratorObjectQueue(), undefined);
493 : a.Store(AccessBuilder::ForJSAsyncGeneratorObjectAwaitedPromise(),
494 144 : undefined);
495 : }
496 :
497 : // Handle in-object properties, too.
498 1592 : for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) {
499 : a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
500 16 : undefined);
501 : }
502 1560 : a.FinishAndChange(node);
503 : return Changed(node);
504 : }
505 : return NoChange();
506 : }
507 :
508 : // Constructs an array with a variable {length} when no upper bound
509 : // is known for the capacity.
510 339 : Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length,
511 : Handle<Map> initial_map,
512 1017 : PretenureFlag pretenure) {
513 : DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
514 339 : Node* effect = NodeProperties::GetEffectInput(node);
515 339 : Node* control = NodeProperties::GetControlInput(node);
516 :
517 : // Constructing an Array via new Array(N) where N is an unsigned
518 : // integer, always creates a holey backing store.
519 339 : if (!IsHoleyElementsKind(initial_map->elements_kind())) {
520 : initial_map = Map::AsElementsKind(
521 200 : initial_map, GetHoleyElementsKind(initial_map->elements_kind()));
522 : }
523 :
524 : // Check that the {limit} is an unsigned integer in the valid range.
525 : // This has to be kept in sync with src/runtime/runtime-array.cc,
526 : // where this limit is protected.
527 : length = effect = graph()->NewNode(
528 : simplified()->CheckBounds(), length,
529 : jsgraph()->Constant(JSArray::kInitialMaxFastElementArray), effect,
530 678 : control);
531 :
532 : // Construct elements and properties for the resulting JSArray.
533 : Node* elements = effect =
534 : graph()->NewNode(IsDoubleElementsKind(initial_map->elements_kind())
535 : ? simplified()->NewDoubleElements(pretenure)
536 : : simplified()->NewSmiOrObjectElements(pretenure),
537 678 : length, effect, control);
538 339 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
539 :
540 : // Perform the allocation of the actual JSArray object.
541 : AllocationBuilder a(jsgraph(), effect, control);
542 339 : a.Allocate(initial_map->instance_size(), pretenure);
543 339 : a.Store(AccessBuilder::ForMap(), initial_map);
544 339 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
545 339 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
546 : a.Store(AccessBuilder::ForJSArrayLength(initial_map->elements_kind()),
547 339 : length);
548 678 : for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) {
549 : a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
550 0 : jsgraph()->UndefinedConstant());
551 : }
552 : RelaxControls(node);
553 339 : a.FinishAndChange(node);
554 339 : return Changed(node);
555 : }
556 :
557 : // Constructs an array with a variable {length} when an actual
558 : // upper bound is known for the {capacity}.
559 1336 : Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length,
560 : int capacity,
561 : Handle<Map> initial_map,
562 3523 : PretenureFlag pretenure) {
563 : DCHECK(node->opcode() == IrOpcode::kJSCreateArray ||
564 : node->opcode() == IrOpcode::kJSCreateEmptyLiteralArray);
565 1336 : Node* effect = NodeProperties::GetEffectInput(node);
566 1336 : Node* control = NodeProperties::GetControlInput(node);
567 :
568 : // Determine the appropriate elements kind.
569 : ElementsKind elements_kind = initial_map->elements_kind();
570 1336 : if (NodeProperties::GetType(length)->Max() > 0.0) {
571 : elements_kind = GetHoleyElementsKind(elements_kind);
572 193 : initial_map = Map::AsElementsKind(initial_map, elements_kind);
573 : }
574 : DCHECK(IsFastElementsKind(elements_kind));
575 :
576 : // Setup elements and properties.
577 : Node* elements;
578 1336 : if (capacity == 0) {
579 829 : elements = jsgraph()->EmptyFixedArrayConstant();
580 : } else {
581 : elements = effect =
582 507 : AllocateElements(effect, control, elements_kind, capacity, pretenure);
583 : }
584 1336 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
585 :
586 : // Perform the allocation of the actual JSArray object.
587 : AllocationBuilder a(jsgraph(), effect, control);
588 1336 : a.Allocate(initial_map->instance_size(), pretenure);
589 1336 : a.Store(AccessBuilder::ForMap(), initial_map);
590 1336 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
591 1336 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
592 1336 : a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length);
593 2716 : for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) {
594 : a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
595 22 : jsgraph()->UndefinedConstant());
596 : }
597 : RelaxControls(node);
598 1336 : a.FinishAndChange(node);
599 1336 : return Changed(node);
600 : }
601 :
602 189 : Reduction JSCreateLowering::ReduceNewArray(Node* node,
603 189 : std::vector<Node*> values,
604 : Handle<Map> initial_map,
605 609 : PretenureFlag pretenure) {
606 : DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
607 189 : Node* effect = NodeProperties::GetEffectInput(node);
608 189 : Node* control = NodeProperties::GetControlInput(node);
609 :
610 : // Determine the appropriate elements kind.
611 : ElementsKind elements_kind = initial_map->elements_kind();
612 : DCHECK(IsFastElementsKind(elements_kind));
613 :
614 : // Check {values} based on the {elements_kind}. These checks are guarded
615 : // by the {elements_kind} feedback on the {site}, so it's safe to just
616 : // deoptimize in this case.
617 189 : if (IsSmiElementsKind(elements_kind)) {
618 290 : for (auto& value : values) {
619 384 : if (!NodeProperties::GetType(value)->Is(Type::SignedSmall())) {
620 : value = effect =
621 75 : graph()->NewNode(simplified()->CheckSmi(), value, effect, control);
622 : }
623 : }
624 140 : } else if (IsDoubleElementsKind(elements_kind)) {
625 104 : for (auto& value : values) {
626 120 : if (!NodeProperties::GetType(value)->Is(Type::Number())) {
627 : value = effect = graph()->NewNode(simplified()->CheckNumber(), value,
628 0 : effect, control);
629 : }
630 : // Make sure we do not store signaling NaNs into double arrays.
631 180 : value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
632 : }
633 : }
634 :
635 : // Setup elements, properties and length.
636 : Node* elements = effect =
637 189 : AllocateElements(effect, control, elements_kind, values, pretenure);
638 189 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
639 378 : Node* length = jsgraph()->Constant(static_cast<int>(values.size()));
640 :
641 : // Perform the allocation of the actual JSArray object.
642 : AllocationBuilder a(jsgraph(), effect, control);
643 189 : a.Allocate(initial_map->instance_size(), pretenure);
644 189 : a.Store(AccessBuilder::ForMap(), initial_map);
645 189 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
646 189 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
647 189 : a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length);
648 462 : for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) {
649 : a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
650 42 : jsgraph()->UndefinedConstant());
651 : }
652 : RelaxControls(node);
653 189 : a.FinishAndChange(node);
654 189 : return Changed(node);
655 : }
656 :
657 95 : Reduction JSCreateLowering::ReduceNewArrayToStubCall(
658 475 : Node* node, Handle<AllocationSite> site) {
659 95 : CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
660 95 : int const arity = static_cast<int>(p.arity());
661 95 : Node* target = NodeProperties::GetValueInput(node, 0);
662 95 : Node* new_target = NodeProperties::GetValueInput(node, 1);
663 : Type* new_target_type = NodeProperties::GetType(new_target);
664 : Node* type_info = site.is_null() ? jsgraph()->UndefinedConstant()
665 190 : : jsgraph()->HeapConstant(site);
666 :
667 : ElementsKind elements_kind =
668 95 : site.is_null() ? GetInitialFastElementsKind() : site->GetElementsKind();
669 : AllocationSiteOverrideMode override_mode =
670 78 : (site.is_null() || AllocationSite::ShouldTrack(elements_kind))
671 : ? DISABLE_ALLOCATION_SITES
672 95 : : DONT_OVERRIDE;
673 :
674 : // The Array constructor can only trigger an observable side-effect
675 : // if the new.target may be a proxy.
676 : Operator::Properties const properties =
677 95 : (new_target != target || new_target_type->Maybe(Type::Proxy()))
678 : ? Operator::kNoDeopt
679 190 : : Operator::kNoDeopt | Operator::kNoWrite;
680 :
681 95 : if (arity == 0) {
682 : ArrayNoArgumentConstructorStub stub(isolate(), elements_kind,
683 : override_mode);
684 : CallDescriptor* desc = Linkage::GetStubCallDescriptor(
685 : isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(),
686 0 : arity + 1, CallDescriptor::kNeedsFrameState, properties);
687 0 : node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode()));
688 0 : node->InsertInput(graph()->zone(), 2, type_info);
689 0 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
690 0 : node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
691 0 : NodeProperties::ChangeOp(node, common()->Call(desc));
692 95 : } else if (arity == 1) {
693 : // Require elements kind to "go holey".
694 : ArraySingleArgumentConstructorStub stub(
695 : isolate(), GetHoleyElementsKind(elements_kind), override_mode);
696 : CallDescriptor* desc = Linkage::GetStubCallDescriptor(
697 : isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(),
698 380 : arity + 1, CallDescriptor::kNeedsFrameState, properties);
699 190 : node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode()));
700 95 : node->InsertInput(graph()->zone(), 2, type_info);
701 190 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
702 190 : node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
703 95 : NodeProperties::ChangeOp(node, common()->Call(desc));
704 : } else {
705 : DCHECK_GT(arity, 1);
706 : ArrayNArgumentsConstructorStub stub(isolate());
707 : CallDescriptor* desc = Linkage::GetStubCallDescriptor(
708 : isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(),
709 0 : arity + 1, CallDescriptor::kNeedsFrameState);
710 0 : node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode()));
711 0 : node->InsertInput(graph()->zone(), 2, type_info);
712 0 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
713 0 : node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
714 0 : NodeProperties::ChangeOp(node, common()->Call(desc));
715 : }
716 95 : return Changed(node);
717 : }
718 :
719 4542 : Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) {
720 : DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
721 1273 : CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
722 1153 : int const arity = static_cast<int>(p.arity());
723 : Handle<AllocationSite> const site = p.site();
724 : PretenureFlag pretenure = NOT_TENURED;
725 : Handle<JSFunction> constructor(native_context()->array_function(), isolate());
726 1153 : Node* target = NodeProperties::GetValueInput(node, 0);
727 1153 : Node* new_target = NodeProperties::GetValueInput(node, 1);
728 : Type* new_target_type = (target == new_target)
729 : ? Type::HeapConstant(constructor, zone())
730 1153 : : NodeProperties::GetType(new_target);
731 :
732 : // Extract original constructor function.
733 2306 : if (new_target_type->IsHeapConstant() &&
734 : new_target_type->AsHeapConstant()->Value()->IsJSFunction()) {
735 : Handle<JSFunction> original_constructor =
736 : Handle<JSFunction>::cast(new_target_type->AsHeapConstant()->Value());
737 : DCHECK(constructor->IsConstructor());
738 : DCHECK(original_constructor->IsConstructor());
739 :
740 : // Check if we can inline the allocation.
741 1153 : if (IsAllocationInlineable(constructor, original_constructor)) {
742 : // Force completion of inobject slack tracking before
743 : // generating code to finalize the instance size.
744 1153 : original_constructor->CompleteInobjectSlackTrackingIfActive();
745 : Handle<Map> initial_map(original_constructor->initial_map(), isolate());
746 :
747 : // Add a dependency on the {initial_map} to make sure that this code is
748 : // deoptimized whenever the {initial_map} changes.
749 : dependencies()->AssumeInitialMapCantChange(initial_map);
750 :
751 : // Tells whether we are protected by either the {site} or a
752 : // protector cell to do certain speculative optimizations.
753 : bool can_inline_call = false;
754 :
755 : // Check if we have a feedback {site} on the {node}.
756 1153 : if (!site.is_null()) {
757 : ElementsKind elements_kind = site->GetElementsKind();
758 516 : if (initial_map->elements_kind() != elements_kind) {
759 399 : initial_map = Map::AsElementsKind(initial_map, elements_kind);
760 : }
761 : can_inline_call = site->CanInlineCall();
762 516 : pretenure = site->GetPretenureMode();
763 :
764 516 : dependencies()->AssumeTransitionStable(site);
765 : dependencies()->AssumeTenuringDecision(site);
766 : } else {
767 : can_inline_call = isolate()->IsArrayConstructorIntact();
768 : }
769 :
770 1153 : if (arity == 0) {
771 314 : Node* length = jsgraph()->ZeroConstant();
772 : int capacity = JSArray::kPreallocatedArrayElements;
773 314 : return ReduceNewArray(node, length, capacity, initial_map, pretenure);
774 839 : } else if (arity == 1) {
775 719 : Node* length = NodeProperties::GetValueInput(node, 2);
776 : Type* length_type = NodeProperties::GetType(length);
777 719 : if (!length_type->Maybe(Type::Number())) {
778 : // Handle the single argument case, where we know that the value
779 : // cannot be a valid Array length.
780 : ElementsKind elements_kind = initial_map->elements_kind();
781 : elements_kind = GetMoreGeneralElementsKind(
782 : elements_kind, IsHoleyElementsKind(elements_kind)
783 : ? HOLEY_ELEMENTS
784 77 : : PACKED_ELEMENTS);
785 77 : initial_map = Map::AsElementsKind(initial_map, elements_kind);
786 : return ReduceNewArray(node, std::vector<Node*>{length}, initial_map,
787 231 : pretenure);
788 : }
789 1727 : if (length_type->Is(Type::SignedSmall()) && length_type->Min() >= 0 &&
790 1380 : length_type->Max() <= kElementLoopUnrollLimit &&
791 202 : length_type->Min() == length_type->Max()) {
792 194 : int capacity = static_cast<int>(length_type->Max());
793 194 : return ReduceNewArray(node, length, capacity, initial_map, pretenure);
794 : }
795 448 : if (length_type->Maybe(Type::UnsignedSmall()) && can_inline_call) {
796 339 : return ReduceNewArray(node, length, initial_map, pretenure);
797 : }
798 120 : } else if (arity <= JSArray::kInitialMaxFastElementArray) {
799 : // Gather the values to store into the newly created array.
800 : bool values_all_smis = true, values_all_numbers = true,
801 : values_any_nonnumber = false;
802 : std::vector<Node*> values;
803 120 : values.reserve(p.arity());
804 650 : for (int i = 0; i < arity; ++i) {
805 530 : Node* value = NodeProperties::GetValueInput(node, 2 + i);
806 : Type* value_type = NodeProperties::GetType(value);
807 530 : if (!value_type->Is(Type::SignedSmall())) {
808 : values_all_smis = false;
809 : }
810 530 : if (!value_type->Is(Type::Number())) {
811 : values_all_numbers = false;
812 : }
813 530 : if (!value_type->Maybe(Type::Number())) {
814 : values_any_nonnumber = true;
815 : }
816 530 : values.push_back(value);
817 : }
818 :
819 : // Try to figure out the ideal elements kind statically.
820 : ElementsKind elements_kind = initial_map->elements_kind();
821 120 : if (values_all_smis) {
822 : // Smis can be stored with any elements kind.
823 77 : } else if (values_all_numbers) {
824 : elements_kind = GetMoreGeneralElementsKind(
825 : elements_kind, IsHoleyElementsKind(elements_kind)
826 : ? HOLEY_DOUBLE_ELEMENTS
827 20 : : PACKED_DOUBLE_ELEMENTS);
828 57 : } else if (values_any_nonnumber) {
829 : elements_kind = GetMoreGeneralElementsKind(
830 : elements_kind, IsHoleyElementsKind(elements_kind)
831 : ? HOLEY_ELEMENTS
832 35 : : PACKED_ELEMENTS);
833 22 : } else if (!can_inline_call) {
834 : // We have some crazy combination of types for the {values} where
835 : // there's no clear decision on the elements kind statically. And
836 : // we don't have a protection against deoptimization loops for the
837 : // checks that are introduced in the call to ReduceNewArray, so
838 : // we cannot inline this invocation of the Array constructor here.
839 : return NoChange();
840 : }
841 112 : initial_map = Map::AsElementsKind(initial_map, elements_kind);
842 :
843 224 : return ReduceNewArray(node, values, initial_map, pretenure);
844 : }
845 : }
846 : }
847 :
848 : // TODO(bmeurer): Optimize the subclassing case.
849 109 : if (target != new_target) return NoChange();
850 :
851 95 : return ReduceNewArrayToStubCall(node, site);
852 : }
853 :
854 521 : Reduction JSCreateLowering::ReduceJSCreateBoundFunction(Node* node) {
855 : DCHECK_EQ(IrOpcode::kJSCreateBoundFunction, node->opcode());
856 94 : CreateBoundFunctionParameters const& p =
857 94 : CreateBoundFunctionParametersOf(node->op());
858 94 : int const arity = static_cast<int>(p.arity());
859 : Handle<Map> const map = p.map();
860 94 : Node* bound_target_function = NodeProperties::GetValueInput(node, 0);
861 94 : Node* bound_this = NodeProperties::GetValueInput(node, 1);
862 94 : Node* effect = NodeProperties::GetEffectInput(node);
863 94 : Node* control = NodeProperties::GetControlInput(node);
864 :
865 : // Create the [[BoundArguments]] for the result.
866 94 : Node* bound_arguments = jsgraph()->EmptyFixedArrayConstant();
867 94 : if (arity > 0) {
868 : AllocationBuilder a(jsgraph(), effect, control);
869 51 : a.AllocateArray(arity, factory()->fixed_array_map());
870 118 : for (int i = 0; i < arity; ++i) {
871 67 : a.Store(AccessBuilder::ForFixedArraySlot(i),
872 134 : NodeProperties::GetValueInput(node, 2 + i));
873 : }
874 51 : bound_arguments = effect = a.Finish();
875 : }
876 :
877 : // Create the JSBoundFunction result.
878 : AllocationBuilder a(jsgraph(), effect, control);
879 94 : a.Allocate(JSBoundFunction::kSize, NOT_TENURED, Type::BoundFunction());
880 94 : a.Store(AccessBuilder::ForMap(), map);
881 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
882 94 : jsgraph()->EmptyFixedArrayConstant());
883 : a.Store(AccessBuilder::ForJSObjectElements(),
884 94 : jsgraph()->EmptyFixedArrayConstant());
885 : a.Store(AccessBuilder::ForJSBoundFunctionBoundTargetFunction(),
886 94 : bound_target_function);
887 94 : a.Store(AccessBuilder::ForJSBoundFunctionBoundThis(), bound_this);
888 94 : a.Store(AccessBuilder::ForJSBoundFunctionBoundArguments(), bound_arguments);
889 : RelaxControls(node);
890 94 : a.FinishAndChange(node);
891 94 : return Changed(node);
892 : }
893 :
894 596299 : Reduction JSCreateLowering::ReduceJSCreateClosure(Node* node) {
895 : DCHECK_EQ(IrOpcode::kJSCreateClosure, node->opcode());
896 585545 : CreateClosureParameters const& p = CreateClosureParametersOf(node->op());
897 : Handle<SharedFunctionInfo> shared = p.shared_info();
898 585547 : Node* effect = NodeProperties::GetEffectInput(node);
899 585547 : Node* control = NodeProperties::GetControlInput(node);
900 585547 : Node* context = NodeProperties::GetContextInput(node);
901 :
902 : // Use inline allocation of closures only for instantiation sites that have
903 : // seen more than one instantiation, this simplifies the generated code and
904 : // also serves as a heuristic of which allocation sites benefit from it.
905 585547 : FeedbackSlot slot(FeedbackVector::ToSlot(p.feedback().index()));
906 : Handle<Cell> vector_cell(Cell::cast(p.feedback().vector()->Get(slot)));
907 585547 : if (vector_cell->map() == isolate()->heap()->many_closures_cell_map()) {
908 : Handle<Map> function_map(
909 : Map::cast(native_context()->get(shared->function_map_index())));
910 : Node* lazy_compile_builtin = jsgraph()->HeapConstant(
911 2246 : handle(isolate()->builtins()->builtin(Builtins::kCompileLazy)));
912 : DCHECK(!function_map->IsInobjectSlackTrackingInProgress());
913 : DCHECK(!function_map->is_dictionary_map());
914 :
915 : // Emit code to allocate the JSFunction instance.
916 : AllocationBuilder a(jsgraph(), effect, control);
917 2246 : a.Allocate(function_map->instance_size());
918 2246 : a.Store(AccessBuilder::ForMap(), function_map);
919 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
920 2246 : jsgraph()->EmptyFixedArrayConstant());
921 : a.Store(AccessBuilder::ForJSObjectElements(),
922 2246 : jsgraph()->EmptyFixedArrayConstant());
923 2246 : a.Store(AccessBuilder::ForJSFunctionSharedFunctionInfo(), shared);
924 2246 : a.Store(AccessBuilder::ForJSFunctionContext(), context);
925 2246 : a.Store(AccessBuilder::ForJSFunctionFeedbackVector(), vector_cell);
926 2246 : a.Store(AccessBuilder::ForJSFunctionCode(), lazy_compile_builtin);
927 : STATIC_ASSERT(JSFunction::kSizeWithoutPrototype == 7 * kPointerSize);
928 2246 : if (function_map->has_prototype_slot()) {
929 : a.Store(AccessBuilder::ForJSFunctionPrototypeOrInitialMap(),
930 1733 : jsgraph()->TheHoleConstant());
931 : STATIC_ASSERT(JSFunction::kSizeWithPrototype == 8 * kPointerSize);
932 : }
933 2320 : for (int i = 0; i < function_map->GetInObjectProperties(); i++) {
934 : a.Store(AccessBuilder::ForJSObjectInObjectProperty(function_map, i),
935 37 : jsgraph()->UndefinedConstant());
936 : }
937 : RelaxControls(node);
938 2246 : a.FinishAndChange(node);
939 : return Changed(node);
940 : }
941 :
942 : return NoChange();
943 : }
944 :
945 11852 : Reduction JSCreateLowering::ReduceJSCreateIterResultObject(Node* node) {
946 : DCHECK_EQ(IrOpcode::kJSCreateIterResultObject, node->opcode());
947 2963 : Node* value = NodeProperties::GetValueInput(node, 0);
948 2963 : Node* done = NodeProperties::GetValueInput(node, 1);
949 2963 : Node* effect = NodeProperties::GetEffectInput(node);
950 :
951 : Node* iterator_result_map = jsgraph()->HeapConstant(
952 2963 : handle(native_context()->iterator_result_map(), isolate()));
953 :
954 : // Emit code to allocate the JSIteratorResult instance.
955 2963 : AllocationBuilder a(jsgraph(), effect, graph()->start());
956 2963 : a.Allocate(JSIteratorResult::kSize);
957 2963 : a.Store(AccessBuilder::ForMap(), iterator_result_map);
958 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
959 2963 : jsgraph()->EmptyFixedArrayConstant());
960 : a.Store(AccessBuilder::ForJSObjectElements(),
961 2963 : jsgraph()->EmptyFixedArrayConstant());
962 2963 : a.Store(AccessBuilder::ForJSIteratorResultValue(), value);
963 2963 : a.Store(AccessBuilder::ForJSIteratorResultDone(), done);
964 : STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
965 2963 : a.FinishAndChange(node);
966 2963 : return Changed(node);
967 : }
968 :
969 504 : Reduction JSCreateLowering::ReduceJSCreateKeyValueArray(Node* node) {
970 : DCHECK_EQ(IrOpcode::kJSCreateKeyValueArray, node->opcode());
971 84 : Node* key = NodeProperties::GetValueInput(node, 0);
972 84 : Node* value = NodeProperties::GetValueInput(node, 1);
973 84 : Node* effect = NodeProperties::GetEffectInput(node);
974 :
975 : Node* array_map = jsgraph()->HeapConstant(
976 84 : handle(native_context()->js_array_fast_elements_map_index()));
977 84 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
978 84 : Node* length = jsgraph()->Constant(2);
979 :
980 84 : AllocationBuilder aa(jsgraph(), effect, graph()->start());
981 84 : aa.AllocateArray(2, factory()->fixed_array_map());
982 : aa.Store(AccessBuilder::ForFixedArrayElement(PACKED_ELEMENTS),
983 84 : jsgraph()->Constant(0), key);
984 : aa.Store(AccessBuilder::ForFixedArrayElement(PACKED_ELEMENTS),
985 84 : jsgraph()->Constant(1), value);
986 84 : Node* elements = aa.Finish();
987 :
988 84 : AllocationBuilder a(jsgraph(), elements, graph()->start());
989 84 : a.Allocate(JSArray::kSize);
990 84 : a.Store(AccessBuilder::ForMap(), array_map);
991 84 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
992 84 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
993 84 : a.Store(AccessBuilder::ForJSArrayLength(PACKED_ELEMENTS), length);
994 : STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize);
995 84 : a.FinishAndChange(node);
996 84 : return Changed(node);
997 : }
998 :
999 61692 : Reduction JSCreateLowering::ReduceJSCreateLiteralArrayOrObject(Node* node) {
1000 : DCHECK(node->opcode() == IrOpcode::kJSCreateLiteralArray ||
1001 : node->opcode() == IrOpcode::kJSCreateLiteralObject);
1002 61692 : CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
1003 61692 : Node* effect = NodeProperties::GetEffectInput(node);
1004 61692 : Node* control = NodeProperties::GetControlInput(node);
1005 :
1006 : Handle<Object> feedback(p.feedback().vector()->Get(p.feedback().slot()),
1007 : isolate());
1008 61692 : if (feedback->IsAllocationSite()) {
1009 : Handle<AllocationSite> site = Handle<AllocationSite>::cast(feedback);
1010 : Handle<JSObject> boilerplate(site->boilerplate(), isolate());
1011 4595 : int max_properties = kMaxFastLiteralProperties;
1012 4595 : if (IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) {
1013 : AllocationSiteUsageContext site_context(isolate(), site, false);
1014 4506 : site_context.EnterNewScope();
1015 : Node* value = effect =
1016 4506 : AllocateFastLiteral(effect, control, boilerplate, &site_context);
1017 : site_context.ExitScope(site, boilerplate);
1018 4506 : ReplaceWithValue(node, value, effect, control);
1019 : return Replace(value);
1020 : }
1021 : }
1022 : return NoChange();
1023 : }
1024 :
1025 25704 : Reduction JSCreateLowering::ReduceJSCreateEmptyLiteralArray(Node* node) {
1026 : DCHECK_EQ(IrOpcode::kJSCreateEmptyLiteralArray, node->opcode());
1027 23220 : FeedbackParameter const& p = FeedbackParameterOf(node->op());
1028 : Handle<Object> feedback(p.feedback().vector()->Get(p.feedback().slot()),
1029 : isolate());
1030 23220 : if (feedback->IsAllocationSite()) {
1031 : Handle<AllocationSite> site = Handle<AllocationSite>::cast(feedback);
1032 : DCHECK(!site->PointsToLiteral());
1033 : Handle<Map> const initial_map(
1034 : native_context()->GetInitialJSArrayMap(site->GetElementsKind()),
1035 828 : isolate());
1036 828 : PretenureFlag const pretenure = site->GetPretenureMode();
1037 828 : dependencies()->AssumeTransitionStable(site);
1038 : dependencies()->AssumeTenuringDecision(site);
1039 828 : Node* length = jsgraph()->ZeroConstant();
1040 828 : return ReduceNewArray(node, length, 0, initial_map, pretenure);
1041 : }
1042 : return NoChange();
1043 : }
1044 :
1045 53255 : Reduction JSCreateLowering::ReduceJSCreateEmptyLiteralObject(Node* node) {
1046 : DCHECK_EQ(IrOpcode::kJSCreateEmptyLiteralObject, node->opcode());
1047 6879 : Node* effect = NodeProperties::GetEffectInput(node);
1048 6879 : Node* control = NodeProperties::GetControlInput(node);
1049 :
1050 : // Retrieve the initial map for the object.
1051 6879 : Handle<Map> map = factory()->ObjectLiteralMapFromCache(native_context(), 0);
1052 : DCHECK(!map->is_dictionary_map());
1053 : DCHECK(!map->IsInobjectSlackTrackingInProgress());
1054 6879 : Node* js_object_map = jsgraph()->HeapConstant(map);
1055 :
1056 : // Setup elements and properties.
1057 6879 : Node* elements = jsgraph()->EmptyFixedArrayConstant();
1058 6879 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
1059 :
1060 : // Perform the allocation of the actual JSArray object.
1061 : AllocationBuilder a(jsgraph(), effect, control);
1062 6879 : a.Allocate(map->instance_size());
1063 6879 : a.Store(AccessBuilder::ForMap(), js_object_map);
1064 6879 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
1065 6879 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
1066 51478 : for (int i = 0; i < map->GetInObjectProperties(); i++) {
1067 : a.Store(AccessBuilder::ForJSObjectInObjectProperty(map, i),
1068 18860 : jsgraph()->UndefinedConstant());
1069 : }
1070 :
1071 : RelaxControls(node);
1072 6879 : a.FinishAndChange(node);
1073 6879 : return Changed(node);
1074 : }
1075 :
1076 10168 : Reduction JSCreateLowering::ReduceJSCreateLiteralRegExp(Node* node) {
1077 : DCHECK_EQ(IrOpcode::kJSCreateLiteralRegExp, node->opcode());
1078 10168 : CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
1079 10168 : Node* effect = NodeProperties::GetEffectInput(node);
1080 10168 : Node* control = NodeProperties::GetControlInput(node);
1081 :
1082 : Handle<Object> feedback(p.feedback().vector()->Get(p.feedback().slot()),
1083 : isolate());
1084 10168 : if (feedback->IsJSRegExp()) {
1085 248 : Handle<JSRegExp> boilerplate = Handle<JSRegExp>::cast(feedback);
1086 248 : Node* value = effect = AllocateLiteralRegExp(effect, control, boilerplate);
1087 248 : ReplaceWithValue(node, value, effect, control);
1088 : return Replace(value);
1089 : }
1090 : return NoChange();
1091 : }
1092 :
1093 159128 : Reduction JSCreateLowering::ReduceJSCreateFunctionContext(Node* node) {
1094 : DCHECK_EQ(IrOpcode::kJSCreateFunctionContext, node->opcode());
1095 27323 : const CreateFunctionContextParameters& parameters =
1096 27323 : CreateFunctionContextParametersOf(node->op());
1097 : int slot_count = parameters.slot_count();
1098 : ScopeType scope_type = parameters.scope_type();
1099 27323 : Node* const closure = NodeProperties::GetValueInput(node, 0);
1100 :
1101 : // Use inline allocation for function contexts up to a size limit.
1102 27323 : if (slot_count < kFunctionContextAllocationLimit) {
1103 : // JSCreateFunctionContext[slot_count < limit]](fun)
1104 21832 : Node* effect = NodeProperties::GetEffectInput(node);
1105 21832 : Node* control = NodeProperties::GetControlInput(node);
1106 21832 : Node* context = NodeProperties::GetContextInput(node);
1107 21832 : Node* extension = jsgraph()->TheHoleConstant();
1108 : AllocationBuilder a(jsgraph(), effect, control);
1109 : STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
1110 21832 : int context_length = slot_count + Context::MIN_CONTEXT_SLOTS;
1111 : Handle<Map> map;
1112 21832 : switch (scope_type) {
1113 : case EVAL_SCOPE:
1114 3269 : map = factory()->eval_context_map();
1115 3269 : break;
1116 : case FUNCTION_SCOPE:
1117 18563 : map = factory()->function_context_map();
1118 18563 : break;
1119 : default:
1120 0 : UNREACHABLE();
1121 : }
1122 21832 : a.AllocateArray(context_length, map);
1123 21832 : a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
1124 21832 : a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
1125 21832 : a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
1126 : a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
1127 21832 : jsgraph()->HeapConstant(native_context()));
1128 88141 : for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) {
1129 66309 : a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant());
1130 : }
1131 : RelaxControls(node);
1132 21832 : a.FinishAndChange(node);
1133 : return Changed(node);
1134 : }
1135 :
1136 : return NoChange();
1137 : }
1138 :
1139 1976 : Reduction JSCreateLowering::ReduceJSCreateWithContext(Node* node) {
1140 : DCHECK_EQ(IrOpcode::kJSCreateWithContext, node->opcode());
1141 494 : Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node);
1142 494 : Node* object = NodeProperties::GetValueInput(node, 0);
1143 494 : Node* closure = NodeProperties::GetValueInput(node, 1);
1144 494 : Node* effect = NodeProperties::GetEffectInput(node);
1145 494 : Node* control = NodeProperties::GetControlInput(node);
1146 494 : Node* context = NodeProperties::GetContextInput(node);
1147 :
1148 : AllocationBuilder aa(jsgraph(), effect, control);
1149 494 : aa.Allocate(ContextExtension::kSize);
1150 494 : aa.Store(AccessBuilder::ForMap(), factory()->context_extension_map());
1151 494 : aa.Store(AccessBuilder::ForContextExtensionScopeInfo(), scope_info);
1152 494 : aa.Store(AccessBuilder::ForContextExtensionExtension(), object);
1153 494 : Node* extension = aa.Finish();
1154 :
1155 : AllocationBuilder a(jsgraph(), extension, control);
1156 : STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
1157 494 : a.AllocateArray(Context::MIN_CONTEXT_SLOTS, factory()->with_context_map());
1158 494 : a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
1159 494 : a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
1160 494 : a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
1161 : a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
1162 494 : jsgraph()->HeapConstant(native_context()));
1163 : RelaxControls(node);
1164 494 : a.FinishAndChange(node);
1165 494 : return Changed(node);
1166 : }
1167 :
1168 71616 : Reduction JSCreateLowering::ReduceJSCreateCatchContext(Node* node) {
1169 : DCHECK_EQ(IrOpcode::kJSCreateCatchContext, node->opcode());
1170 : const CreateCatchContextParameters& parameters =
1171 17904 : CreateCatchContextParametersOf(node->op());
1172 17904 : Node* exception = NodeProperties::GetValueInput(node, 0);
1173 17904 : Node* closure = NodeProperties::GetValueInput(node, 1);
1174 17904 : Node* effect = NodeProperties::GetEffectInput(node);
1175 17904 : Node* control = NodeProperties::GetControlInput(node);
1176 17904 : Node* context = NodeProperties::GetContextInput(node);
1177 :
1178 : AllocationBuilder aa(jsgraph(), effect, control);
1179 17904 : aa.Allocate(ContextExtension::kSize);
1180 17904 : aa.Store(AccessBuilder::ForMap(), factory()->context_extension_map());
1181 : aa.Store(AccessBuilder::ForContextExtensionScopeInfo(),
1182 17904 : parameters.scope_info());
1183 : aa.Store(AccessBuilder::ForContextExtensionExtension(),
1184 17904 : parameters.catch_name());
1185 17904 : Node* extension = aa.Finish();
1186 :
1187 : AllocationBuilder a(jsgraph(), extension, control);
1188 : STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
1189 : a.AllocateArray(Context::MIN_CONTEXT_SLOTS + 1,
1190 17904 : factory()->catch_context_map());
1191 17904 : a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
1192 17904 : a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
1193 17904 : a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
1194 : a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
1195 17904 : jsgraph()->HeapConstant(native_context()));
1196 : a.Store(AccessBuilder::ForContextSlot(Context::THROWN_OBJECT_INDEX),
1197 17904 : exception);
1198 : RelaxControls(node);
1199 17904 : a.FinishAndChange(node);
1200 17904 : return Changed(node);
1201 : }
1202 :
1203 45580 : Reduction JSCreateLowering::ReduceJSCreateBlockContext(Node* node) {
1204 : DCHECK_EQ(IrOpcode::kJSCreateBlockContext, node->opcode());
1205 8881 : Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node);
1206 8881 : int const context_length = scope_info->ContextLength();
1207 8881 : Node* const closure = NodeProperties::GetValueInput(node, 0);
1208 :
1209 : // Use inline allocation for block contexts up to a size limit.
1210 8881 : if (context_length < kBlockContextAllocationLimit) {
1211 : // JSCreateBlockContext[scope[length < limit]](fun)
1212 8881 : Node* effect = NodeProperties::GetEffectInput(node);
1213 8881 : Node* control = NodeProperties::GetControlInput(node);
1214 8881 : Node* context = NodeProperties::GetContextInput(node);
1215 8881 : Node* extension = jsgraph()->Constant(scope_info);
1216 :
1217 : AllocationBuilder a(jsgraph(), effect, control);
1218 : STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
1219 8881 : a.AllocateArray(context_length, factory()->block_context_map());
1220 8881 : a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
1221 8881 : a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
1222 8881 : a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
1223 : a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
1224 8881 : jsgraph()->HeapConstant(native_context()));
1225 18937 : for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) {
1226 10056 : a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant());
1227 : }
1228 : RelaxControls(node);
1229 8881 : a.FinishAndChange(node);
1230 : return Changed(node);
1231 : }
1232 :
1233 : return NoChange();
1234 : }
1235 :
1236 : // Helper that allocates a FixedArray holding argument values recorded in the
1237 : // given {frame_state}. Serves as backing store for JSCreateArguments nodes.
1238 571 : Node* JSCreateLowering::AllocateArguments(Node* effect, Node* control,
1239 571 : Node* frame_state) {
1240 571 : FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
1241 571 : int argument_count = state_info.parameter_count() - 1; // Minus receiver.
1242 602 : if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant();
1243 :
1244 : // Prepare an iterator over argument values recorded in the frame state.
1245 : Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
1246 : StateValuesAccess parameters_access(parameters);
1247 540 : auto parameters_it = ++parameters_access.begin();
1248 :
1249 : // Actually allocate the backing store.
1250 : AllocationBuilder a(jsgraph(), effect, control);
1251 540 : a.AllocateArray(argument_count, factory()->fixed_array_map());
1252 1839 : for (int i = 0; i < argument_count; ++i, ++parameters_it) {
1253 : DCHECK_NOT_NULL((*parameters_it).node);
1254 1299 : a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node);
1255 : }
1256 540 : return a.Finish();
1257 : }
1258 :
1259 : // Helper that allocates a FixedArray holding argument values recorded in the
1260 : // given {frame_state}. Serves as backing store for JSCreateArguments nodes.
1261 252 : Node* JSCreateLowering::AllocateRestArguments(Node* effect, Node* control,
1262 : Node* frame_state,
1263 252 : int start_index) {
1264 252 : FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
1265 252 : int argument_count = state_info.parameter_count() - 1; // Minus receiver.
1266 504 : int num_elements = std::max(0, argument_count - start_index);
1267 378 : if (num_elements == 0) return jsgraph()->EmptyFixedArrayConstant();
1268 :
1269 : // Prepare an iterator over argument values recorded in the frame state.
1270 : Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
1271 : StateValuesAccess parameters_access(parameters);
1272 126 : auto parameters_it = ++parameters_access.begin();
1273 :
1274 : // Skip unused arguments.
1275 147 : for (int i = 0; i < start_index; i++) {
1276 21 : ++parameters_it;
1277 : }
1278 :
1279 : // Actually allocate the backing store.
1280 : AllocationBuilder a(jsgraph(), effect, control);
1281 126 : a.AllocateArray(num_elements, factory()->fixed_array_map());
1282 385 : for (int i = 0; i < num_elements; ++i, ++parameters_it) {
1283 : DCHECK_NOT_NULL((*parameters_it).node);
1284 259 : a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node);
1285 : }
1286 126 : return a.Finish();
1287 : }
1288 :
1289 : // Helper that allocates a FixedArray serving as a parameter map for values
1290 : // recorded in the given {frame_state}. Some elements map to slots within the
1291 : // given {context}. Serves as backing store for JSCreateArguments nodes.
1292 647 : Node* JSCreateLowering::AllocateAliasedArguments(
1293 : Node* effect, Node* control, Node* frame_state, Node* context,
1294 2318 : Handle<SharedFunctionInfo> shared, bool* has_aliased_arguments) {
1295 647 : FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
1296 647 : int argument_count = state_info.parameter_count() - 1; // Minus receiver.
1297 735 : if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant();
1298 :
1299 : // If there is no aliasing, the arguments object elements are not special in
1300 : // any way, we can just return an unmapped backing store instead.
1301 : int parameter_count = shared->internal_formal_parameter_count();
1302 559 : if (parameter_count == 0) {
1303 174 : return AllocateArguments(effect, control, frame_state);
1304 : }
1305 :
1306 : // Calculate number of argument values being aliased/mapped.
1307 : int mapped_count = Min(argument_count, parameter_count);
1308 385 : *has_aliased_arguments = true;
1309 :
1310 : // Prepare an iterator over argument values recorded in the frame state.
1311 : Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
1312 : StateValuesAccess parameters_access(parameters);
1313 385 : auto parameters_it = ++parameters_access.begin();
1314 :
1315 : // The unmapped argument values recorded in the frame state are stored yet
1316 : // another indirection away and then linked into the parameter map below,
1317 : // whereas mapped argument values are replaced with a hole instead.
1318 : AllocationBuilder aa(jsgraph(), effect, control);
1319 385 : aa.AllocateArray(argument_count, factory()->fixed_array_map());
1320 1115 : for (int i = 0; i < mapped_count; ++i, ++parameters_it) {
1321 730 : aa.Store(AccessBuilder::ForFixedArraySlot(i), jsgraph()->TheHoleConstant());
1322 : }
1323 7 : for (int i = mapped_count; i < argument_count; ++i, ++parameters_it) {
1324 : DCHECK_NOT_NULL((*parameters_it).node);
1325 7 : aa.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node);
1326 : }
1327 385 : Node* arguments = aa.Finish();
1328 :
1329 : // Actually allocate the backing store.
1330 : AllocationBuilder a(jsgraph(), arguments, control);
1331 385 : a.AllocateArray(mapped_count + 2, factory()->sloppy_arguments_elements_map());
1332 385 : a.Store(AccessBuilder::ForFixedArraySlot(0), context);
1333 385 : a.Store(AccessBuilder::ForFixedArraySlot(1), arguments);
1334 1115 : for (int i = 0; i < mapped_count; ++i) {
1335 730 : int idx = Context::MIN_CONTEXT_SLOTS + parameter_count - 1 - i;
1336 730 : a.Store(AccessBuilder::ForFixedArraySlot(i + 2), jsgraph()->Constant(idx));
1337 : }
1338 385 : return a.Finish();
1339 : }
1340 :
1341 : // Helper that allocates a FixedArray serving as a parameter map for values
1342 : // unknown at compile-time, the true {arguments_length} and {arguments_frame}
1343 : // values can only be determined dynamically at run-time and are provided.
1344 : // Serves as backing store for JSCreateArguments nodes.
1345 9811 : Node* JSCreateLowering::AllocateAliasedArguments(
1346 : Node* effect, Node* control, Node* context, Node* arguments_frame,
1347 : Node* arguments_length, Handle<SharedFunctionInfo> shared,
1348 16547 : bool* has_aliased_arguments) {
1349 : // If there is no aliasing, the arguments object elements are not
1350 : // special in any way, we can just return an unmapped backing store.
1351 : int parameter_count = shared->internal_formal_parameter_count();
1352 9811 : if (parameter_count == 0) {
1353 : return graph()->NewNode(simplified()->NewArgumentsElements(0),
1354 15286 : arguments_frame, arguments_length, effect);
1355 : }
1356 :
1357 : // From here on we are going to allocate a mapped (aka. aliased) elements
1358 : // backing store. We do not statically know how many arguments exist, but
1359 : // dynamically selecting the hole for some of the "mapped" elements allows
1360 : // using a static shape for the parameter map.
1361 : int mapped_count = parameter_count;
1362 2168 : *has_aliased_arguments = true;
1363 :
1364 : // The unmapped argument values are stored yet another indirection away and
1365 : // then linked into the parameter map below, whereas mapped argument values
1366 : // (i.e. the first {mapped_count} elements) are replaced with a hole instead.
1367 : Node* arguments =
1368 : graph()->NewNode(simplified()->NewArgumentsElements(mapped_count),
1369 2168 : arguments_frame, arguments_length, effect);
1370 :
1371 : // Actually allocate the backing store.
1372 : AllocationBuilder a(jsgraph(), arguments, control);
1373 2168 : a.AllocateArray(mapped_count + 2, factory()->sloppy_arguments_elements_map());
1374 2168 : a.Store(AccessBuilder::ForFixedArraySlot(0), context);
1375 2168 : a.Store(AccessBuilder::ForFixedArraySlot(1), arguments);
1376 6961 : for (int i = 0; i < mapped_count; ++i) {
1377 4793 : int idx = Context::MIN_CONTEXT_SLOTS + parameter_count - 1 - i;
1378 : Node* value = graph()->NewNode(
1379 : common()->Select(MachineRepresentation::kTagged),
1380 : graph()->NewNode(simplified()->NumberLessThan(), jsgraph()->Constant(i),
1381 : arguments_length),
1382 23965 : jsgraph()->Constant(idx), jsgraph()->TheHoleConstant());
1383 4793 : a.Store(AccessBuilder::ForFixedArraySlot(i + 2), value);
1384 : }
1385 2168 : return a.Finish();
1386 : }
1387 :
1388 2067 : Node* JSCreateLowering::AllocateElements(Node* effect, Node* control,
1389 : ElementsKind elements_kind,
1390 : int capacity,
1391 22541 : PretenureFlag pretenure) {
1392 : DCHECK_LE(1, capacity);
1393 : DCHECK_LE(capacity, JSArray::kInitialMaxFastElementArray);
1394 :
1395 : Handle<Map> elements_map = IsDoubleElementsKind(elements_kind)
1396 : ? factory()->fixed_double_array_map()
1397 4134 : : factory()->fixed_array_map();
1398 : ElementAccess access = IsDoubleElementsKind(elements_kind)
1399 : ? AccessBuilder::ForFixedDoubleArrayElement()
1400 2067 : : AccessBuilder::ForFixedArrayElement();
1401 2067 : Node* value = jsgraph()->TheHoleConstant();
1402 :
1403 : // Actually allocate the backing store.
1404 : AllocationBuilder a(jsgraph(), effect, control);
1405 2067 : a.AllocateArray(capacity, elements_map, pretenure);
1406 20474 : for (int i = 0; i < capacity; ++i) {
1407 18407 : Node* index = jsgraph()->Constant(i);
1408 18407 : a.Store(access, index, value);
1409 : }
1410 2067 : return a.Finish();
1411 : }
1412 :
1413 189 : Node* JSCreateLowering::AllocateElements(Node* effect, Node* control,
1414 : ElementsKind elements_kind,
1415 772 : std::vector<Node*> const& values,
1416 772 : PretenureFlag pretenure) {
1417 189 : int const capacity = static_cast<int>(values.size());
1418 : DCHECK_LE(1, capacity);
1419 : DCHECK_LE(capacity, JSArray::kInitialMaxFastElementArray);
1420 :
1421 : Handle<Map> elements_map = IsDoubleElementsKind(elements_kind)
1422 : ? factory()->fixed_double_array_map()
1423 378 : : factory()->fixed_array_map();
1424 : ElementAccess access = IsDoubleElementsKind(elements_kind)
1425 : ? AccessBuilder::ForFixedDoubleArrayElement()
1426 189 : : AccessBuilder::ForFixedArrayElement();
1427 :
1428 : // Actually allocate the backing store.
1429 : AllocationBuilder a(jsgraph(), effect, control);
1430 189 : a.AllocateArray(capacity, elements_map, pretenure);
1431 772 : for (int i = 0; i < capacity; ++i) {
1432 583 : Node* index = jsgraph()->Constant(i);
1433 1166 : a.Store(access, index, values[i]);
1434 : }
1435 189 : return a.Finish();
1436 : }
1437 :
1438 5171 : Node* JSCreateLowering::AllocateFastLiteral(
1439 : Node* effect, Node* control, Handle<JSObject> boilerplate,
1440 27346 : AllocationSiteUsageContext* site_context) {
1441 : Handle<AllocationSite> current_site(*site_context->current(), isolate());
1442 5171 : dependencies()->AssumeTransitionStable(current_site);
1443 :
1444 : PretenureFlag pretenure = NOT_TENURED;
1445 5171 : if (FLAG_allocation_site_pretenuring) {
1446 : Handle<AllocationSite> top_site(*site_context->top(), isolate());
1447 5171 : pretenure = top_site->GetPretenureMode();
1448 5171 : if (current_site.is_identical_to(top_site)) {
1449 : // We install a dependency for pretenuring only on the outermost literal.
1450 : dependencies()->AssumeTenuringDecision(top_site);
1451 : }
1452 : }
1453 :
1454 : // Setup the properties backing store.
1455 5171 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
1456 :
1457 : // Compute the in-object properties to store first (might have effects).
1458 : Handle<Map> boilerplate_map(boilerplate->map(), isolate());
1459 : ZoneVector<std::pair<FieldAccess, Node*>> inobject_fields(zone());
1460 5171 : inobject_fields.reserve(boilerplate_map->GetInObjectProperties());
1461 : int const boilerplate_nof = boilerplate_map->NumberOfOwnDescriptors();
1462 10825 : for (int i = 0; i < boilerplate_nof; ++i) {
1463 : PropertyDetails const property_details =
1464 5654 : boilerplate_map->instance_descriptors()->GetDetails(i);
1465 8860 : if (property_details.location() != kField) continue;
1466 : DCHECK_EQ(kData, property_details.kind());
1467 : Handle<Name> property_name(
1468 : boilerplate_map->instance_descriptors()->GetKey(i), isolate());
1469 2448 : FieldIndex index = FieldIndex::ForDescriptor(*boilerplate_map, i);
1470 : FieldAccess access = {kTaggedBase, index.offset(),
1471 : property_name, MaybeHandle<Map>(),
1472 : Type::Any(), MachineType::AnyTagged(),
1473 : kFullWriteBarrier};
1474 : Node* value;
1475 2448 : if (boilerplate->IsUnboxedDoubleField(index)) {
1476 : access.machine_type = MachineType::Float64();
1477 : access.type = Type::Number();
1478 94 : value = jsgraph()->Constant(boilerplate->RawFastDoublePropertyAt(index));
1479 : } else {
1480 : Handle<Object> boilerplate_value(boilerplate->RawFastPropertyAt(index),
1481 2354 : isolate());
1482 2354 : if (boilerplate_value->IsJSObject()) {
1483 : Handle<JSObject> boilerplate_object =
1484 292 : Handle<JSObject>::cast(boilerplate_value);
1485 292 : Handle<AllocationSite> current_site = site_context->EnterNewScope();
1486 : value = effect = AllocateFastLiteral(effect, control,
1487 292 : boilerplate_object, site_context);
1488 : site_context->ExitScope(current_site, boilerplate_object);
1489 2062 : } else if (property_details.representation().IsDouble()) {
1490 : double number = Handle<HeapNumber>::cast(boilerplate_value)->value();
1491 : // Allocate a mutable HeapNumber box and store the value into it.
1492 : AllocationBuilder builder(jsgraph(), effect, control);
1493 0 : builder.Allocate(HeapNumber::kSize, pretenure);
1494 : builder.Store(AccessBuilder::ForMap(),
1495 0 : factory()->mutable_heap_number_map());
1496 : builder.Store(AccessBuilder::ForHeapNumberValue(),
1497 0 : jsgraph()->Constant(number));
1498 0 : value = effect = builder.Finish();
1499 2062 : } else if (property_details.representation().IsSmi()) {
1500 : // Ensure that value is stored as smi.
1501 : value = boilerplate_value->IsUninitialized(isolate())
1502 : ? jsgraph()->ZeroConstant()
1503 1540 : : jsgraph()->Constant(boilerplate_value);
1504 : } else {
1505 1292 : value = jsgraph()->Constant(boilerplate_value);
1506 : }
1507 : }
1508 2448 : inobject_fields.push_back(std::make_pair(access, value));
1509 : }
1510 :
1511 : // Fill slack at the end of the boilerplate object with filler maps.
1512 : int const boilerplate_length = boilerplate_map->GetInObjectProperties();
1513 11974 : for (int index = static_cast<int>(inobject_fields.size());
1514 : index < boilerplate_length; ++index) {
1515 : FieldAccess access =
1516 1632 : AccessBuilder::ForJSObjectInObjectProperty(boilerplate_map, index);
1517 1632 : Node* value = jsgraph()->HeapConstant(factory()->one_pointer_filler_map());
1518 1632 : inobject_fields.push_back(std::make_pair(access, value));
1519 : }
1520 :
1521 : // Setup the elements backing store.
1522 5171 : Node* elements = AllocateFastLiteralElements(effect, control, boilerplate,
1523 5171 : pretenure, site_context);
1524 10342 : if (elements->op()->EffectOutputCount() > 0) effect = elements;
1525 :
1526 : // Actually allocate and initialize the object.
1527 : AllocationBuilder builder(jsgraph(), effect, control);
1528 : builder.Allocate(boilerplate_map->instance_size(), pretenure,
1529 5171 : Type::For(boilerplate_map));
1530 5171 : builder.Store(AccessBuilder::ForMap(), boilerplate_map);
1531 5171 : builder.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
1532 5171 : builder.Store(AccessBuilder::ForJSObjectElements(), elements);
1533 5171 : if (boilerplate_map->IsJSArrayMap()) {
1534 : Handle<JSArray> boilerplate_array = Handle<JSArray>::cast(boilerplate);
1535 : builder.Store(
1536 : AccessBuilder::ForJSArrayLength(boilerplate_array->GetElementsKind()),
1537 3206 : handle(boilerplate_array->length(), isolate()));
1538 : }
1539 14422 : for (auto const& inobject_field : inobject_fields) {
1540 4080 : builder.Store(inobject_field.first, inobject_field.second);
1541 : }
1542 5171 : return builder.Finish();
1543 : }
1544 :
1545 5171 : Node* JSCreateLowering::AllocateFastLiteralElements(
1546 : Node* effect, Node* control, Handle<JSObject> boilerplate,
1547 30847 : PretenureFlag pretenure, AllocationSiteUsageContext* site_context) {
1548 : Handle<FixedArrayBase> boilerplate_elements(boilerplate->elements(),
1549 : isolate());
1550 :
1551 : // Empty or copy-on-write elements just store a constant.
1552 8462 : if (boilerplate_elements->length() == 0 ||
1553 3291 : boilerplate_elements->map() == isolate()->heap()->fixed_cow_array_map()) {
1554 3652 : if (pretenure == TENURED &&
1555 : isolate()->heap()->InNewSpace(*boilerplate_elements)) {
1556 : // If we would like to pretenure a fixed cow array, we must ensure that
1557 : // the array is already in old space, otherwise we'll create too many
1558 : // old-to-new-space pointers (overflowing the store buffer).
1559 : boilerplate_elements = Handle<FixedArrayBase>(
1560 : isolate()->factory()->CopyAndTenureFixedCOWArray(
1561 0 : Handle<FixedArray>::cast(boilerplate_elements)));
1562 0 : boilerplate->set_elements(*boilerplate_elements);
1563 : }
1564 3612 : return jsgraph()->HeapConstant(boilerplate_elements);
1565 : }
1566 :
1567 : // Compute the elements to store first (might have effects).
1568 : int const elements_length = boilerplate_elements->length();
1569 : Handle<Map> elements_map(boilerplate_elements->map(), isolate());
1570 1559 : ZoneVector<Node*> elements_values(elements_length, zone());
1571 1559 : if (elements_map->instance_type() == FIXED_DOUBLE_ARRAY_TYPE) {
1572 : Handle<FixedDoubleArray> elements =
1573 : Handle<FixedDoubleArray>::cast(boilerplate_elements);
1574 7192 : for (int i = 0; i < elements_length; ++i) {
1575 7192 : if (elements->is_the_hole(i)) {
1576 160 : elements_values[i] = jsgraph()->TheHoleConstant();
1577 : } else {
1578 14224 : elements_values[i] = jsgraph()->Constant(elements->get_scalar(i));
1579 : }
1580 : }
1581 : } else {
1582 : Handle<FixedArray> elements =
1583 : Handle<FixedArray>::cast(boilerplate_elements);
1584 5053 : for (int i = 0; i < elements_length; ++i) {
1585 5053 : if (elements->is_the_hole(isolate(), i)) {
1586 4282 : elements_values[i] = jsgraph()->TheHoleConstant();
1587 : } else {
1588 : Handle<Object> element_value(elements->get(i), isolate());
1589 2912 : if (element_value->IsJSObject()) {
1590 : Handle<JSObject> boilerplate_object =
1591 373 : Handle<JSObject>::cast(element_value);
1592 373 : Handle<AllocationSite> current_site = site_context->EnterNewScope();
1593 373 : elements_values[i] = effect = AllocateFastLiteral(
1594 373 : effect, control, boilerplate_object, site_context);
1595 : site_context->ExitScope(current_site, boilerplate_object);
1596 : } else {
1597 5078 : elements_values[i] = jsgraph()->Constant(element_value);
1598 : }
1599 : }
1600 : }
1601 : }
1602 :
1603 : // Allocate the backing store array and store the elements.
1604 : AllocationBuilder builder(jsgraph(), effect, control);
1605 1559 : builder.AllocateArray(elements_length, elements_map, pretenure);
1606 : ElementAccess const access =
1607 : (elements_map->instance_type() == FIXED_DOUBLE_ARRAY_TYPE)
1608 : ? AccessBuilder::ForFixedDoubleArrayElement()
1609 1559 : : AccessBuilder::ForFixedArrayElement();
1610 12245 : for (int i = 0; i < elements_length; ++i) {
1611 36735 : builder.Store(access, jsgraph()->Constant(i), elements_values[i]);
1612 : }
1613 1559 : return builder.Finish();
1614 : }
1615 :
1616 248 : Node* JSCreateLowering::AllocateLiteralRegExp(Node* effect, Node* control,
1617 248 : Handle<JSRegExp> boilerplate) {
1618 : Handle<Map> boilerplate_map(boilerplate->map(), isolate());
1619 :
1620 : // Sanity check that JSRegExp object layout hasn't changed.
1621 : STATIC_ASSERT(JSRegExp::kDataOffset == JSObject::kHeaderSize);
1622 : STATIC_ASSERT(JSRegExp::kSourceOffset ==
1623 : JSRegExp::kDataOffset + kPointerSize);
1624 : STATIC_ASSERT(JSRegExp::kFlagsOffset ==
1625 : JSRegExp::kSourceOffset + kPointerSize);
1626 : STATIC_ASSERT(JSRegExp::kSize == JSRegExp::kFlagsOffset + kPointerSize);
1627 : STATIC_ASSERT(JSRegExp::kLastIndexOffset == JSRegExp::kSize);
1628 : STATIC_ASSERT(JSRegExp::kInObjectFieldCount == 1); // LastIndex.
1629 :
1630 : const PretenureFlag pretenure = NOT_TENURED;
1631 : const int size =
1632 : JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1633 :
1634 : AllocationBuilder builder(jsgraph(), effect, control);
1635 248 : builder.Allocate(size, pretenure, Type::For(boilerplate_map));
1636 248 : builder.Store(AccessBuilder::ForMap(), boilerplate_map);
1637 : builder.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
1638 248 : handle(boilerplate->raw_properties_or_hash(), isolate()));
1639 : builder.Store(AccessBuilder::ForJSObjectElements(),
1640 248 : handle(boilerplate->elements(), isolate()));
1641 :
1642 : builder.Store(AccessBuilder::ForJSRegExpData(),
1643 248 : handle(boilerplate->data(), isolate()));
1644 : builder.Store(AccessBuilder::ForJSRegExpSource(),
1645 248 : handle(boilerplate->source(), isolate()));
1646 : builder.Store(AccessBuilder::ForJSRegExpFlags(),
1647 248 : handle(boilerplate->flags(), isolate()));
1648 : builder.Store(AccessBuilder::ForJSRegExpLastIndex(),
1649 248 : handle(boilerplate->last_index(), isolate()));
1650 :
1651 248 : return builder.Finish();
1652 : }
1653 :
1654 0 : Factory* JSCreateLowering::factory() const { return isolate()->factory(); }
1655 :
1656 81770 : Graph* JSCreateLowering::graph() const { return jsgraph()->graph(); }
1657 :
1658 848772 : Isolate* JSCreateLowering::isolate() const { return jsgraph()->isolate(); }
1659 :
1660 4888 : CommonOperatorBuilder* JSCreateLowering::common() const {
1661 4888 : return jsgraph()->common();
1662 : }
1663 :
1664 55512 : SimplifiedOperatorBuilder* JSCreateLowering::simplified() const {
1665 55512 : return jsgraph()->simplified();
1666 : }
1667 :
1668 : } // namespace compiler
1669 : } // namespace internal
1670 : } // namespace v8
|