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/common-operator.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-properties.h"
16 : #include "src/compiler/node.h"
17 : #include "src/compiler/operator-properties.h"
18 : #include "src/compiler/simplified-operator.h"
19 : #include "src/compiler/state-values-utils.h"
20 : #include "src/objects-inl.h"
21 :
22 : namespace v8 {
23 : namespace internal {
24 : namespace compiler {
25 :
26 : namespace {
27 :
28 : // A helper class to construct inline allocations on the simplified operator
29 : // level. This keeps track of the effect chain for initial stores on a newly
30 : // allocated object and also provides helpers for commonly allocated objects.
31 : class AllocationBuilder final {
32 : public:
33 : AllocationBuilder(JSGraph* jsgraph, Node* effect, Node* control)
34 : : jsgraph_(jsgraph),
35 : allocation_(nullptr),
36 : effect_(effect),
37 108268 : control_(control) {}
38 :
39 : // Primitive allocation of static size.
40 108268 : void Allocate(int size, PretenureFlag pretenure = NOT_TENURED,
41 541340 : Type* type = Type::Any()) {
42 : DCHECK_LE(size, kMaxRegularHeapObjectSize);
43 : effect_ = graph()->NewNode(
44 324804 : common()->BeginRegion(RegionObservability::kNotObservable), effect_);
45 : allocation_ =
46 : graph()->NewNode(simplified()->Allocate(type, pretenure),
47 433072 : jsgraph()->Constant(size), effect_, control_);
48 108268 : effect_ = allocation_;
49 108268 : }
50 :
51 : // Primitive store into a field.
52 1844136 : void Store(const FieldAccess& access, Node* value) {
53 : effect_ = graph()->NewNode(simplified()->StoreField(access), allocation_,
54 1844136 : value, effect_, control_);
55 614712 : }
56 :
57 : // Primitive store into an element.
58 442914 : void Store(ElementAccess const& access, Node* index, Node* value) {
59 : effect_ = graph()->NewNode(simplified()->StoreElement(access), allocation_,
60 442914 : index, value, effect_, control_);
61 147638 : }
62 :
63 : // Compound allocation of a FixedArray.
64 54168 : void AllocateArray(int length, Handle<Map> map,
65 54168 : PretenureFlag pretenure = NOT_TENURED) {
66 : DCHECK(map->instance_type() == FIXED_ARRAY_TYPE ||
67 : map->instance_type() == FIXED_DOUBLE_ARRAY_TYPE);
68 : int size = (map->instance_type() == FIXED_ARRAY_TYPE)
69 : ? FixedArray::SizeFor(length)
70 54168 : : FixedDoubleArray::SizeFor(length);
71 54168 : Allocate(size, pretenure, Type::OtherInternal());
72 54168 : Store(AccessBuilder::ForMap(), map);
73 54168 : Store(AccessBuilder::ForFixedArrayLength(), jsgraph()->Constant(length));
74 54168 : }
75 :
76 : // Compound store of a constant into a field.
77 147544 : void Store(const FieldAccess& access, Handle<Object> value) {
78 147544 : Store(access, jsgraph()->Constant(value));
79 147544 : }
80 :
81 139116 : void FinishAndChange(Node* node) {
82 69558 : NodeProperties::SetType(allocation_, NodeProperties::GetType(node));
83 69558 : node->ReplaceInput(0, allocation_);
84 69558 : node->ReplaceInput(1, effect_);
85 69558 : node->TrimInputCount(2);
86 69558 : NodeProperties::ChangeOp(node, common()->FinishRegion());
87 69558 : }
88 :
89 116130 : Node* Finish() {
90 116130 : return graph()->NewNode(common()->FinishRegion(), allocation_, effect_);
91 : }
92 :
93 : protected:
94 : JSGraph* jsgraph() { return jsgraph_; }
95 1017596 : Graph* graph() { return jsgraph_->graph(); }
96 216536 : CommonOperatorBuilder* common() { return jsgraph_->common(); }
97 870618 : SimplifiedOperatorBuilder* simplified() { return jsgraph_->simplified(); }
98 :
99 : private:
100 : JSGraph* const jsgraph_;
101 : Node* allocation_;
102 : Node* effect_;
103 : Node* control_;
104 : };
105 :
106 : // Retrieves the frame state holding actual argument values.
107 1085 : Node* GetArgumentsFrameState(Node* frame_state) {
108 1085 : Node* const outer_state = NodeProperties::GetFrameStateInput(frame_state);
109 1085 : FrameStateInfo outer_state_info = OpParameter<FrameStateInfo>(outer_state);
110 : return outer_state_info.type() == FrameStateType::kArgumentsAdaptor
111 : ? outer_state
112 1085 : : frame_state;
113 : }
114 :
115 : // Checks whether allocation using the given target and new.target can be
116 : // inlined.
117 764 : bool IsAllocationInlineable(Handle<JSFunction> target,
118 : Handle<JSFunction> new_target) {
119 1528 : return new_target->has_initial_map() &&
120 1528 : !new_target->initial_map()->is_dictionary_map() &&
121 764 : new_target->initial_map()->constructor_or_backpointer() == *target;
122 : }
123 :
124 : // When initializing arrays, we'll unfold the loop if the number of
125 : // elements is known to be of this type.
126 : const int kElementLoopUnrollLimit = 16;
127 :
128 : // Limits up to which context allocations are inlined.
129 : const int kFunctionContextAllocationLimit = 16;
130 : const int kBlockContextAllocationLimit = 16;
131 :
132 : // Determines whether the given array or object literal boilerplate satisfies
133 : // all limits to be considered for fast deep-copying and computes the total
134 : // size of all objects that are part of the graph.
135 8125 : bool IsFastLiteral(Handle<JSObject> boilerplate, int max_depth,
136 : int* max_properties) {
137 : DCHECK_GE(max_depth, 0);
138 : DCHECK_GE(*max_properties, 0);
139 :
140 : // Make sure the boilerplate map is not deprecated.
141 8125 : if (!JSObject::TryMigrateInstance(boilerplate)) return false;
142 :
143 : // Check for too deep nesting.
144 8125 : if (max_depth == 0) return false;
145 :
146 : // Check the elements.
147 : Isolate* const isolate = boilerplate->GetIsolate();
148 : Handle<FixedArrayBase> elements(boilerplate->elements(), isolate);
149 12385 : if (elements->length() > 0 &&
150 4260 : elements->map() != isolate->heap()->fixed_cow_array_map()) {
151 2476 : if (boilerplate->HasFastSmiOrObjectElements()) {
152 : Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
153 : int length = elements->length();
154 11893 : for (int i = 0; i < length; i++) {
155 9944 : if ((*max_properties)-- == 0) return false;
156 : Handle<Object> value(fast_elements->get(i), isolate);
157 9930 : if (value->IsJSObject()) {
158 475 : Handle<JSObject> value_object = Handle<JSObject>::cast(value);
159 475 : if (!IsFastLiteral(value_object, max_depth - 1, max_properties)) {
160 0 : return false;
161 : }
162 : }
163 : }
164 513 : } else if (boilerplate->HasFastDoubleElements()) {
165 505 : if (elements->Size() > kMaxRegularHeapObjectSize) return false;
166 : } else {
167 : return false;
168 : }
169 : }
170 :
171 : // TODO(turbofan): Do we want to support out-of-object properties?
172 : Handle<FixedArray> properties(boilerplate->properties(), isolate);
173 8095 : if (properties->length() > 0) return false;
174 :
175 : // Check the in-object properties.
176 : Handle<DescriptorArray> descriptors(
177 : boilerplate->map()->instance_descriptors(), isolate);
178 : int limit = boilerplate->map()->NumberOfOwnDescriptors();
179 15736 : for (int i = 0; i < limit; i++) {
180 7641 : PropertyDetails details = descriptors->GetDetails(i);
181 12885 : if (details.location() != kField) continue;
182 : DCHECK_EQ(kData, details.kind());
183 2533 : if ((*max_properties)-- == 0) return false;
184 2533 : FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i);
185 2533 : if (boilerplate->IsUnboxedDoubleField(field_index)) continue;
186 2397 : Handle<Object> value(boilerplate->RawFastPropertyAt(field_index), isolate);
187 2397 : if (value->IsJSObject()) {
188 223 : Handle<JSObject> value_object = Handle<JSObject>::cast(value);
189 223 : if (!IsFastLiteral(value_object, max_depth - 1, max_properties)) {
190 0 : return false;
191 : }
192 : }
193 : }
194 : return true;
195 : }
196 :
197 : // Maximum depth and total number of elements and properties for literal
198 : // graphs to be considered for fast deep-copying. The limit is chosen to
199 : // match the maximum number of inobject properties, to ensure that the
200 : // performance of using object literals is not worse than using constructor
201 : // functions, see crbug.com/v8/6211 for details.
202 : const int kMaxFastLiteralDepth = 3;
203 : const int kMaxFastLiteralProperties =
204 : (JSObject::kMaxInstanceSize - JSObject::kHeaderSize) >> kPointerSizeLog2;
205 :
206 : } // namespace
207 :
208 31518773 : Reduction JSCreateLowering::Reduce(Node* node) {
209 31518773 : switch (node->opcode()) {
210 : case IrOpcode::kJSCreate:
211 822 : return ReduceJSCreate(node);
212 : case IrOpcode::kJSCreateArguments:
213 9338 : return ReduceJSCreateArguments(node);
214 : case IrOpcode::kJSCreateArray:
215 3875 : return ReduceJSCreateArray(node);
216 : case IrOpcode::kJSCreateIterResultObject:
217 12701 : return ReduceJSCreateIterResultObject(node);
218 : case IrOpcode::kJSCreateKeyValueArray:
219 14 : return ReduceJSCreateKeyValueArray(node);
220 : case IrOpcode::kJSCreateLiteralArray:
221 : case IrOpcode::kJSCreateLiteralObject:
222 73338 : return ReduceJSCreateLiteral(node);
223 : case IrOpcode::kJSCreateFunctionContext:
224 17201 : return ReduceJSCreateFunctionContext(node);
225 : case IrOpcode::kJSCreateWithContext:
226 813 : return ReduceJSCreateWithContext(node);
227 : case IrOpcode::kJSCreateCatchContext:
228 25969 : return ReduceJSCreateCatchContext(node);
229 : case IrOpcode::kJSCreateBlockContext:
230 6649 : return ReduceJSCreateBlockContext(node);
231 : default:
232 : break;
233 : }
234 : return NoChange();
235 : }
236 :
237 6711 : Reduction JSCreateLowering::ReduceJSCreate(Node* node) {
238 : DCHECK_EQ(IrOpcode::kJSCreate, node->opcode());
239 822 : Node* const target = NodeProperties::GetValueInput(node, 0);
240 : Type* const target_type = NodeProperties::GetType(target);
241 822 : Node* const new_target = NodeProperties::GetValueInput(node, 1);
242 : Type* const new_target_type = NodeProperties::GetType(new_target);
243 822 : Node* const effect = NodeProperties::GetEffectInput(node);
244 822 : Node* const control = NodeProperties::GetControlInput(node);
245 : // Extract constructor and original constructor function.
246 2408 : if (target_type->IsHeapConstant() && new_target_type->IsHeapConstant() &&
247 : new_target_type->AsHeapConstant()->Value()->IsJSFunction()) {
248 : Handle<JSFunction> constructor =
249 764 : Handle<JSFunction>::cast(target_type->AsHeapConstant()->Value());
250 : Handle<JSFunction> original_constructor =
251 : Handle<JSFunction>::cast(new_target_type->AsHeapConstant()->Value());
252 : DCHECK(constructor->IsConstructor());
253 : DCHECK(original_constructor->IsConstructor());
254 :
255 : // Check if we can inline the allocation.
256 764 : if (IsAllocationInlineable(constructor, original_constructor)) {
257 : // Force completion of inobject slack tracking before
258 : // generating code to finalize the instance size.
259 764 : original_constructor->CompleteInobjectSlackTrackingIfActive();
260 :
261 : // Compute instance size from initial map of {original_constructor}.
262 : Handle<Map> initial_map(original_constructor->initial_map(), isolate());
263 : int const instance_size = initial_map->instance_size();
264 :
265 : // Add a dependency on the {initial_map} to make sure that this code is
266 : // deoptimized whenever the {initial_map} of the {original_constructor}
267 : // changes.
268 : dependencies()->AssumeInitialMapCantChange(initial_map);
269 :
270 : // Emit code to allocate the JSObject instance for the
271 : // {original_constructor}.
272 : AllocationBuilder a(jsgraph(), effect, control);
273 764 : a.Allocate(instance_size);
274 764 : a.Store(AccessBuilder::ForMap(), initial_map);
275 : a.Store(AccessBuilder::ForJSObjectProperties(),
276 764 : jsgraph()->EmptyFixedArrayConstant());
277 : a.Store(AccessBuilder::ForJSObjectElements(),
278 764 : jsgraph()->EmptyFixedArrayConstant());
279 7194 : for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) {
280 : a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
281 2833 : jsgraph()->UndefinedConstant());
282 : }
283 : RelaxControls(node);
284 764 : a.FinishAndChange(node);
285 : return Changed(node);
286 : }
287 : }
288 : return NoChange();
289 : }
290 :
291 29093 : Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
292 : DCHECK_EQ(IrOpcode::kJSCreateArguments, node->opcode());
293 9338 : CreateArgumentsType type = CreateArgumentsTypeOf(node->op());
294 9338 : Node* const frame_state = NodeProperties::GetFrameStateInput(node);
295 9338 : Node* const outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
296 9338 : Node* const control = graph()->start();
297 9338 : FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
298 :
299 : // Use the ArgumentsAccessStub for materializing both mapped and unmapped
300 : // arguments object, but only for non-inlined (i.e. outermost) frames.
301 9338 : if (outer_state->opcode() != IrOpcode::kFrameState) {
302 8253 : switch (type) {
303 : case CreateArgumentsType::kMappedArguments: {
304 : // TODO(bmeurer): Make deoptimization mandatory for the various
305 : // arguments objects, so that we always have a shared_info here.
306 : Handle<SharedFunctionInfo> shared_info;
307 4932 : if (state_info.shared_info().ToHandle(&shared_info)) {
308 : // TODO(mstarzinger): Duplicate parameters are not handled yet.
309 4932 : if (shared_info->has_duplicate_parameters()) return NoChange();
310 : // If there is no aliasing, the arguments object elements are not
311 : // special in any way, we can just return an unmapped backing store.
312 4929 : if (shared_info->internal_formal_parameter_count() == 0) {
313 1089 : Node* const callee = NodeProperties::GetValueInput(node, 0);
314 1089 : Node* effect = NodeProperties::GetEffectInput(node);
315 : Node* const arguments_frame =
316 1089 : graph()->NewNode(simplified()->ArgumentsFrame());
317 : Node* const arguments_length = graph()->NewNode(
318 1089 : simplified()->ArgumentsLength(0, false), arguments_frame);
319 : // Allocate the elements backing store.
320 : Node* const elements = effect =
321 : graph()->NewNode(simplified()->NewUnmappedArgumentsElements(),
322 1089 : arguments_frame, arguments_length, effect);
323 : // Load the arguments object map.
324 : Node* const arguments_map = jsgraph()->HeapConstant(
325 1089 : handle(native_context()->sloppy_arguments_map(), isolate()));
326 : // Actually allocate and initialize the arguments object.
327 : AllocationBuilder a(jsgraph(), effect, control);
328 1089 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
329 : STATIC_ASSERT(JSSloppyArgumentsObject::kSize == 5 * kPointerSize);
330 1089 : a.Allocate(JSSloppyArgumentsObject::kSize);
331 1089 : a.Store(AccessBuilder::ForMap(), arguments_map);
332 1089 : a.Store(AccessBuilder::ForJSObjectProperties(), properties);
333 1089 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
334 1089 : a.Store(AccessBuilder::ForArgumentsLength(), arguments_length);
335 1089 : a.Store(AccessBuilder::ForArgumentsCallee(), callee);
336 : RelaxControls(node);
337 1089 : a.FinishAndChange(node);
338 : } else {
339 3840 : Callable callable = CodeFactory::FastNewSloppyArguments(isolate());
340 3840 : Operator::Properties properties = node->op()->properties();
341 : CallDescriptor* desc = Linkage::GetStubCallDescriptor(
342 : isolate(), graph()->zone(), callable.descriptor(), 0,
343 11520 : CallDescriptor::kNoFlags, properties);
344 3840 : const Operator* new_op = common()->Call(desc);
345 3840 : Node* stub_code = jsgraph()->HeapConstant(callable.code());
346 3840 : node->InsertInput(graph()->zone(), 0, stub_code);
347 3840 : node->RemoveInput(3); // Remove the frame state.
348 3840 : NodeProperties::ChangeOp(node, new_op);
349 : }
350 : return Changed(node);
351 : }
352 : return NoChange();
353 : }
354 : case CreateArgumentsType::kUnmappedArguments: {
355 : Handle<SharedFunctionInfo> shared_info;
356 2730 : if (state_info.shared_info().ToHandle(&shared_info)) {
357 2730 : Node* effect = NodeProperties::GetEffectInput(node);
358 : Node* const arguments_frame =
359 2730 : graph()->NewNode(simplified()->ArgumentsFrame());
360 : Node* const arguments_length = graph()->NewNode(
361 : simplified()->ArgumentsLength(
362 : shared_info->internal_formal_parameter_count(), false),
363 2730 : arguments_frame);
364 : // Allocate the elements backing store.
365 : Node* const elements = effect =
366 : graph()->NewNode(simplified()->NewUnmappedArgumentsElements(),
367 2730 : arguments_frame, arguments_length, effect);
368 : // Load the arguments object map.
369 : Node* const arguments_map = jsgraph()->HeapConstant(
370 2730 : handle(native_context()->strict_arguments_map(), isolate()));
371 : // Actually allocate and initialize the arguments object.
372 : AllocationBuilder a(jsgraph(), effect, control);
373 2730 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
374 : STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kPointerSize);
375 2730 : a.Allocate(JSStrictArgumentsObject::kSize);
376 2730 : a.Store(AccessBuilder::ForMap(), arguments_map);
377 2730 : a.Store(AccessBuilder::ForJSObjectProperties(), properties);
378 2730 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
379 2730 : a.Store(AccessBuilder::ForArgumentsLength(), arguments_length);
380 : RelaxControls(node);
381 2730 : a.FinishAndChange(node);
382 : } else {
383 0 : Callable callable = CodeFactory::FastNewStrictArguments(isolate());
384 0 : Operator::Properties properties = node->op()->properties();
385 : CallDescriptor* desc = Linkage::GetStubCallDescriptor(
386 : isolate(), graph()->zone(), callable.descriptor(), 0,
387 0 : CallDescriptor::kNeedsFrameState, properties);
388 0 : const Operator* new_op = common()->Call(desc);
389 0 : Node* stub_code = jsgraph()->HeapConstant(callable.code());
390 0 : node->InsertInput(graph()->zone(), 0, stub_code);
391 0 : NodeProperties::ChangeOp(node, new_op);
392 : }
393 : return Changed(node);
394 : }
395 : case CreateArgumentsType::kRestParameter: {
396 : Handle<SharedFunctionInfo> shared_info;
397 591 : if (state_info.shared_info().ToHandle(&shared_info)) {
398 591 : Node* effect = NodeProperties::GetEffectInput(node);
399 : Node* const arguments_frame =
400 591 : graph()->NewNode(simplified()->ArgumentsFrame());
401 : int formal_parameter_count =
402 : shared_info->internal_formal_parameter_count();
403 : Node* const rest_length = graph()->NewNode(
404 : simplified()->ArgumentsLength(formal_parameter_count, true),
405 591 : arguments_frame);
406 : // Allocate the elements backing store. Since
407 : // NewUnmappedArgumentsElements copies from the end of the arguments
408 : // adapter frame, this is a suffix of the actual arguments.
409 : Node* const elements = effect =
410 : graph()->NewNode(simplified()->NewUnmappedArgumentsElements(),
411 591 : arguments_frame, rest_length, effect);
412 : // Load the JSArray object map.
413 : Node* const jsarray_map = jsgraph()->HeapConstant(handle(
414 591 : native_context()->js_array_fast_elements_map_index(), isolate()));
415 : // Actually allocate and initialize the jsarray.
416 : AllocationBuilder a(jsgraph(), effect, control);
417 591 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
418 : STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize);
419 591 : a.Allocate(JSArray::kSize);
420 591 : a.Store(AccessBuilder::ForMap(), jsarray_map);
421 591 : a.Store(AccessBuilder::ForJSObjectProperties(), properties);
422 591 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
423 591 : a.Store(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS), rest_length);
424 : RelaxControls(node);
425 591 : a.FinishAndChange(node);
426 : } else {
427 0 : Callable callable = CodeFactory::FastNewRestParameter(isolate());
428 0 : Operator::Properties properties = node->op()->properties();
429 : CallDescriptor* desc = Linkage::GetStubCallDescriptor(
430 : isolate(), graph()->zone(), callable.descriptor(), 0,
431 0 : CallDescriptor::kNeedsFrameState, properties);
432 0 : const Operator* new_op = common()->Call(desc);
433 0 : Node* stub_code = jsgraph()->HeapConstant(callable.code());
434 0 : node->InsertInput(graph()->zone(), 0, stub_code);
435 0 : NodeProperties::ChangeOp(node, new_op);
436 : }
437 : return Changed(node);
438 : }
439 : }
440 0 : UNREACHABLE();
441 1085 : } else if (outer_state->opcode() == IrOpcode::kFrameState) {
442 : // Use inline allocation for all mapped arguments objects within inlined
443 : // (i.e. non-outermost) frames, independent of the object size.
444 1085 : if (type == CreateArgumentsType::kMappedArguments) {
445 : Handle<SharedFunctionInfo> shared;
446 340 : if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
447 340 : Node* const callee = NodeProperties::GetValueInput(node, 0);
448 340 : Node* const context = NodeProperties::GetContextInput(node);
449 340 : Node* effect = NodeProperties::GetEffectInput(node);
450 : // TODO(mstarzinger): Duplicate parameters are not handled yet.
451 340 : if (shared->has_duplicate_parameters()) return NoChange();
452 : // Choose the correct frame state and frame state info depending on
453 : // whether there conceptually is an arguments adaptor frame in the call
454 : // chain.
455 340 : Node* const args_state = GetArgumentsFrameState(frame_state);
456 340 : FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
457 : // Prepare element backing store to be used by arguments object.
458 340 : bool has_aliased_arguments = false;
459 340 : Node* const elements = AllocateAliasedArguments(
460 340 : effect, control, args_state, context, shared, &has_aliased_arguments);
461 680 : effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
462 : // Load the arguments object map.
463 : Node* const arguments_map = jsgraph()->HeapConstant(handle(
464 : has_aliased_arguments ? native_context()->fast_aliased_arguments_map()
465 : : native_context()->sloppy_arguments_map(),
466 680 : isolate()));
467 : // Actually allocate and initialize the arguments object.
468 : AllocationBuilder a(jsgraph(), effect, control);
469 340 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
470 340 : int length = args_state_info.parameter_count() - 1; // Minus receiver.
471 : STATIC_ASSERT(JSSloppyArgumentsObject::kSize == 5 * kPointerSize);
472 340 : a.Allocate(JSSloppyArgumentsObject::kSize);
473 340 : a.Store(AccessBuilder::ForMap(), arguments_map);
474 340 : a.Store(AccessBuilder::ForJSObjectProperties(), properties);
475 340 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
476 340 : a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length));
477 340 : a.Store(AccessBuilder::ForArgumentsCallee(), callee);
478 : RelaxControls(node);
479 340 : a.FinishAndChange(node);
480 : return Changed(node);
481 745 : } else if (type == CreateArgumentsType::kUnmappedArguments) {
482 : // Use inline allocation for all unmapped arguments objects within inlined
483 : // (i.e. non-outermost) frames, independent of the object size.
484 702 : Node* effect = NodeProperties::GetEffectInput(node);
485 : // Choose the correct frame state and frame state info depending on
486 : // whether there conceptually is an arguments adaptor frame in the call
487 : // chain.
488 702 : Node* const args_state = GetArgumentsFrameState(frame_state);
489 702 : FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
490 : // Prepare element backing store to be used by arguments object.
491 702 : Node* const elements = AllocateArguments(effect, control, args_state);
492 1404 : effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
493 : // Load the arguments object map.
494 : Node* const arguments_map = jsgraph()->HeapConstant(
495 702 : handle(native_context()->strict_arguments_map(), isolate()));
496 : // Actually allocate and initialize the arguments object.
497 : AllocationBuilder a(jsgraph(), effect, control);
498 702 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
499 702 : int length = args_state_info.parameter_count() - 1; // Minus receiver.
500 : STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kPointerSize);
501 702 : a.Allocate(JSStrictArgumentsObject::kSize);
502 702 : a.Store(AccessBuilder::ForMap(), arguments_map);
503 702 : a.Store(AccessBuilder::ForJSObjectProperties(), properties);
504 702 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
505 702 : a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length));
506 : RelaxControls(node);
507 702 : a.FinishAndChange(node);
508 : return Changed(node);
509 43 : } else if (type == CreateArgumentsType::kRestParameter) {
510 : Handle<SharedFunctionInfo> shared;
511 43 : if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
512 : int start_index = shared->internal_formal_parameter_count();
513 : // Use inline allocation for all unmapped arguments objects within inlined
514 : // (i.e. non-outermost) frames, independent of the object size.
515 43 : Node* effect = NodeProperties::GetEffectInput(node);
516 : // Choose the correct frame state and frame state info depending on
517 : // whether there conceptually is an arguments adaptor frame in the call
518 : // chain.
519 43 : Node* const args_state = GetArgumentsFrameState(frame_state);
520 43 : FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
521 : // Prepare element backing store to be used by the rest array.
522 43 : Node* const elements =
523 43 : AllocateRestArguments(effect, control, args_state, start_index);
524 86 : effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
525 : // Load the JSArray object map.
526 : Node* const jsarray_map = jsgraph()->HeapConstant(handle(
527 43 : native_context()->js_array_fast_elements_map_index(), isolate()));
528 : // Actually allocate and initialize the jsarray.
529 : AllocationBuilder a(jsgraph(), effect, control);
530 43 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
531 :
532 : // -1 to minus receiver
533 43 : int argument_count = args_state_info.parameter_count() - 1;
534 86 : int length = std::max(0, argument_count - start_index);
535 : STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize);
536 43 : a.Allocate(JSArray::kSize);
537 43 : a.Store(AccessBuilder::ForMap(), jsarray_map);
538 43 : a.Store(AccessBuilder::ForJSObjectProperties(), properties);
539 43 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
540 : a.Store(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS),
541 43 : jsgraph()->Constant(length));
542 : RelaxControls(node);
543 43 : a.FinishAndChange(node);
544 : return Changed(node);
545 : }
546 : }
547 :
548 : return NoChange();
549 : }
550 :
551 299 : Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length,
552 : int capacity,
553 1495 : Handle<AllocationSite> site) {
554 : DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
555 299 : Node* effect = NodeProperties::GetEffectInput(node);
556 299 : Node* control = NodeProperties::GetControlInput(node);
557 :
558 : // Extract transition and tenuring feedback from the {site} and add
559 : // appropriate code dependencies on the {site} if deoptimization is
560 : // enabled.
561 299 : PretenureFlag pretenure = site->GetPretenureMode();
562 : ElementsKind elements_kind = site->GetElementsKind();
563 : DCHECK(IsFastElementsKind(elements_kind));
564 299 : if (NodeProperties::GetType(length)->Max() > 0) {
565 : elements_kind = GetHoleyElementsKind(elements_kind);
566 : }
567 : dependencies()->AssumeTenuringDecision(site);
568 299 : dependencies()->AssumeTransitionStable(site);
569 :
570 : // Retrieve the initial map for the array.
571 : int const array_map_index = Context::ArrayMapIndex(elements_kind);
572 : Node* js_array_map = jsgraph()->HeapConstant(
573 299 : handle(Map::cast(native_context()->get(array_map_index)), isolate()));
574 :
575 : // Setup elements and properties.
576 : Node* elements;
577 299 : if (capacity == 0) {
578 0 : elements = jsgraph()->EmptyFixedArrayConstant();
579 : } else {
580 : elements = effect =
581 299 : AllocateElements(effect, control, elements_kind, capacity, pretenure);
582 : }
583 299 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
584 :
585 : // Perform the allocation of the actual JSArray object.
586 : AllocationBuilder a(jsgraph(), effect, control);
587 299 : a.Allocate(JSArray::kSize, pretenure);
588 299 : a.Store(AccessBuilder::ForMap(), js_array_map);
589 299 : a.Store(AccessBuilder::ForJSObjectProperties(), properties);
590 299 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
591 299 : a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length);
592 : RelaxControls(node);
593 299 : a.FinishAndChange(node);
594 299 : return Changed(node);
595 : }
596 :
597 74 : Reduction JSCreateLowering::ReduceNewArray(Node* node,
598 74 : std::vector<Node*> values,
599 444 : Handle<AllocationSite> site) {
600 : DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
601 74 : Node* effect = NodeProperties::GetEffectInput(node);
602 74 : Node* control = NodeProperties::GetControlInput(node);
603 :
604 : // Extract transition and tenuring feedback from the {site} and add
605 : // appropriate code dependencies on the {site} if deoptimization is
606 : // enabled.
607 74 : PretenureFlag pretenure = site->GetPretenureMode();
608 : ElementsKind elements_kind = site->GetElementsKind();
609 : DCHECK(IsFastElementsKind(elements_kind));
610 : dependencies()->AssumeTenuringDecision(site);
611 74 : dependencies()->AssumeTransitionStable(site);
612 :
613 : // Check {values} based on the {elements_kind}. These checks are guarded
614 : // by the {elements_kind} feedback on the {site}, so it's safe to just
615 : // deoptimize in this case.
616 74 : if (IsFastSmiElementsKind(elements_kind)) {
617 132285 : for (auto& value : values) {
618 264322 : if (!NodeProperties::GetType(value)->Is(Type::SignedSmall())) {
619 : value = effect =
620 162 : graph()->NewNode(simplified()->CheckSmi(), value, effect, control);
621 : }
622 : }
623 12 : } else if (IsFastDoubleElementsKind(elements_kind)) {
624 35 : for (auto& value : values) {
625 42 : if (!NodeProperties::GetType(value)->Is(Type::Number())) {
626 : value = effect = graph()->NewNode(simplified()->CheckNumber(), value,
627 45 : effect, control);
628 : }
629 : // Make sure we do not store signaling NaNs into double arrays.
630 63 : value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
631 : }
632 : }
633 :
634 : // Retrieve the initial map for the array.
635 : int const array_map_index = Context::ArrayMapIndex(elements_kind);
636 : Node* js_array_map = jsgraph()->HeapConstant(
637 74 : handle(Map::cast(native_context()->get(array_map_index)), isolate()));
638 :
639 : // Setup elements, properties and length.
640 : Node* elements = effect =
641 74 : AllocateElements(effect, control, elements_kind, values, pretenure);
642 74 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
643 148 : Node* length = jsgraph()->Constant(static_cast<int>(values.size()));
644 :
645 : // Perform the allocation of the actual JSArray object.
646 : AllocationBuilder a(jsgraph(), effect, control);
647 74 : a.Allocate(JSArray::kSize, pretenure);
648 74 : a.Store(AccessBuilder::ForMap(), js_array_map);
649 74 : a.Store(AccessBuilder::ForJSObjectProperties(), properties);
650 74 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
651 74 : a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length);
652 : RelaxControls(node);
653 74 : a.FinishAndChange(node);
654 74 : return Changed(node);
655 : }
656 :
657 327 : Reduction JSCreateLowering::ReduceNewArrayToStubCall(
658 1710 : Node* node, Handle<AllocationSite> site) {
659 327 : CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
660 327 : int const arity = static_cast<int>(p.arity());
661 327 : Node* target = NodeProperties::GetValueInput(node, 0);
662 327 : Node* new_target = NodeProperties::GetValueInput(node, 1);
663 : Type* new_target_type = NodeProperties::GetType(new_target);
664 :
665 : ElementsKind elements_kind = site->GetElementsKind();
666 : AllocationSiteOverrideMode override_mode =
667 : (AllocationSite::GetMode(elements_kind) == TRACK_ALLOCATION_SITE)
668 : ? DISABLE_ALLOCATION_SITES
669 327 : : DONT_OVERRIDE;
670 :
671 : // The Array constructor can only trigger an observable side-effect
672 : // if the new.target may be a proxy.
673 : Operator::Properties const properties =
674 327 : (new_target != target || new_target_type->Maybe(Type::Proxy()))
675 : ? Operator::kNoDeopt
676 653 : : Operator::kNoDeopt | Operator::kNoWrite;
677 :
678 327 : if (arity == 0) {
679 : ArrayNoArgumentConstructorStub stub(isolate(), elements_kind,
680 : override_mode);
681 : CallDescriptor* desc = Linkage::GetStubCallDescriptor(
682 : isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 1,
683 0 : CallDescriptor::kNeedsFrameState, properties);
684 0 : node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode()));
685 0 : node->InsertInput(graph()->zone(), 2, jsgraph()->HeapConstant(site));
686 0 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(0));
687 0 : node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
688 0 : NodeProperties::ChangeOp(node, common()->Call(desc));
689 : return Changed(node);
690 327 : } else if (arity == 1) {
691 : AllocationSiteOverrideMode override_mode =
692 : (AllocationSite::GetMode(elements_kind) == TRACK_ALLOCATION_SITE)
693 : ? DISABLE_ALLOCATION_SITES
694 306 : : DONT_OVERRIDE;
695 :
696 306 : if (IsHoleyElementsKind(elements_kind)) {
697 : ArraySingleArgumentConstructorStub stub(isolate(), elements_kind,
698 : override_mode);
699 : CallDescriptor* desc = Linkage::GetStubCallDescriptor(
700 : isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 2,
701 873 : CallDescriptor::kNeedsFrameState, properties);
702 582 : node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode()));
703 582 : node->InsertInput(graph()->zone(), 2, jsgraph()->HeapConstant(site));
704 582 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(1));
705 582 : node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
706 291 : NodeProperties::ChangeOp(node, common()->Call(desc));
707 : return Changed(node);
708 : }
709 :
710 15 : Node* effect = NodeProperties::GetEffectInput(node);
711 15 : Node* control = NodeProperties::GetControlInput(node);
712 15 : Node* length = NodeProperties::GetValueInput(node, 2);
713 : Node* equal = graph()->NewNode(simplified()->ReferenceEqual(), length,
714 30 : jsgraph()->ZeroConstant());
715 :
716 : Node* branch =
717 15 : graph()->NewNode(common()->Branch(BranchHint::kFalse), equal, control);
718 : Node* call_holey;
719 : Node* call_packed;
720 15 : Node* context = NodeProperties::GetContextInput(node);
721 15 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
722 15 : Node* if_equal = graph()->NewNode(common()->IfTrue(), branch);
723 : {
724 : ArraySingleArgumentConstructorStub stub(isolate(), elements_kind,
725 : override_mode);
726 : CallDescriptor* desc = Linkage::GetStubCallDescriptor(
727 : isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 2,
728 45 : CallDescriptor::kNeedsFrameState, properties);
729 :
730 45 : Node* inputs[] = {jsgraph()->HeapConstant(stub.GetCode()),
731 : node->InputAt(1),
732 30 : jsgraph()->HeapConstant(site),
733 15 : jsgraph()->Constant(1),
734 15 : jsgraph()->UndefinedConstant(),
735 : length,
736 : context,
737 : frame_state,
738 : effect,
739 75 : if_equal};
740 :
741 : call_holey =
742 30 : graph()->NewNode(common()->Call(desc), arraysize(inputs), inputs);
743 : }
744 15 : Node* if_not_equal = graph()->NewNode(common()->IfFalse(), branch);
745 : {
746 : // Require elements kind to "go holey."
747 : ArraySingleArgumentConstructorStub stub(
748 : isolate(), GetHoleyElementsKind(elements_kind), override_mode);
749 : CallDescriptor* desc = Linkage::GetStubCallDescriptor(
750 : isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 2,
751 45 : CallDescriptor::kNeedsFrameState, properties);
752 :
753 45 : Node* inputs[] = {jsgraph()->HeapConstant(stub.GetCode()),
754 : node->InputAt(1),
755 30 : jsgraph()->HeapConstant(site),
756 15 : jsgraph()->Constant(1),
757 15 : jsgraph()->UndefinedConstant(),
758 : length,
759 : context,
760 : frame_state,
761 : effect,
762 75 : if_not_equal};
763 :
764 : call_packed =
765 30 : graph()->NewNode(common()->Call(desc), arraysize(inputs), inputs);
766 : }
767 15 : Node* merge = graph()->NewNode(common()->Merge(2), call_holey, call_packed);
768 : Node* effect_phi = graph()->NewNode(common()->EffectPhi(2), call_holey,
769 15 : call_packed, merge);
770 : Node* phi =
771 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
772 15 : call_holey, call_packed, merge);
773 :
774 15 : ReplaceWithValue(node, phi, effect_phi, merge);
775 : return Changed(node);
776 : }
777 :
778 : DCHECK(arity > 1);
779 : ArrayNArgumentsConstructorStub stub(isolate());
780 : CallDescriptor* desc = Linkage::GetStubCallDescriptor(
781 : isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), arity + 1,
782 84 : CallDescriptor::kNeedsFrameState);
783 42 : node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode()));
784 42 : node->InsertInput(graph()->zone(), 2, jsgraph()->HeapConstant(site));
785 42 : node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
786 42 : node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
787 21 : NodeProperties::ChangeOp(node, common()->Call(desc));
788 : return Changed(node);
789 : }
790 :
791 4029 : Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) {
792 : DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
793 136734 : CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
794 3875 : Node* target = NodeProperties::GetValueInput(node, 0);
795 3875 : Node* new_target = NodeProperties::GetValueInput(node, 1);
796 :
797 : // TODO(mstarzinger): Array constructor can throw. Hook up exceptional edges.
798 3875 : if (NodeProperties::IsExceptionalCall(node)) return NoChange();
799 :
800 : // TODO(bmeurer): Optimize the subclassing case.
801 3857 : if (target != new_target) return NoChange();
802 :
803 : // Check if we have a feedback {site} on the {node}.
804 : Handle<AllocationSite> site = p.site();
805 3851 : if (p.site().is_null()) return NoChange();
806 :
807 : // Attempt to inline calls to the Array constructor for the relevant cases
808 : // where either no arguments are provided, or exactly one unsigned number
809 : // argument is given.
810 700 : if (site->CanInlineCall()) {
811 588 : if (p.arity() == 0) {
812 154 : Node* length = jsgraph()->ZeroConstant();
813 : int capacity = JSArray::kPreallocatedArrayElements;
814 154 : return ReduceNewArray(node, length, capacity, site);
815 434 : } else if (p.arity() == 1) {
816 360 : Node* length = NodeProperties::GetValueInput(node, 2);
817 : Type* length_type = NodeProperties::GetType(length);
818 360 : if (!length_type->Maybe(Type::Number())) {
819 : // Handle the single argument case, where we know that the value
820 : // cannot be a valid Array length.
821 0 : return ReduceNewArray(node, {length}, site);
822 : }
823 966 : if (length_type->Is(Type::SignedSmall()) && length_type->Min() >= 0 &&
824 812 : length_type->Max() <= kElementLoopUnrollLimit &&
825 153 : length_type->Min() == length_type->Max()) {
826 145 : int capacity = static_cast<int>(length_type->Max());
827 145 : return ReduceNewArray(node, length, capacity, site);
828 : }
829 74 : } else if (p.arity() <= JSArray::kInitialMaxFastElementArray) {
830 : std::vector<Node*> values;
831 74 : values.reserve(p.arity());
832 264542 : for (size_t i = 0; i < p.arity(); ++i) {
833 : values.push_back(
834 264394 : NodeProperties::GetValueInput(node, static_cast<int>(2 + i)));
835 : }
836 148 : return ReduceNewArray(node, values, site);
837 : }
838 : }
839 :
840 327 : return ReduceNewArrayToStubCall(node, site);
841 : }
842 :
843 50804 : Reduction JSCreateLowering::ReduceJSCreateIterResultObject(Node* node) {
844 : DCHECK_EQ(IrOpcode::kJSCreateIterResultObject, node->opcode());
845 12701 : Node* value = NodeProperties::GetValueInput(node, 0);
846 12701 : Node* done = NodeProperties::GetValueInput(node, 1);
847 12701 : Node* effect = NodeProperties::GetEffectInput(node);
848 :
849 : Node* iterator_result_map = jsgraph()->HeapConstant(
850 12701 : handle(native_context()->iterator_result_map(), isolate()));
851 :
852 : // Emit code to allocate the JSIteratorResult instance.
853 12701 : AllocationBuilder a(jsgraph(), effect, graph()->start());
854 12701 : a.Allocate(JSIteratorResult::kSize);
855 12701 : a.Store(AccessBuilder::ForMap(), iterator_result_map);
856 : a.Store(AccessBuilder::ForJSObjectProperties(),
857 12701 : jsgraph()->EmptyFixedArrayConstant());
858 : a.Store(AccessBuilder::ForJSObjectElements(),
859 12701 : jsgraph()->EmptyFixedArrayConstant());
860 12701 : a.Store(AccessBuilder::ForJSIteratorResultValue(), value);
861 12701 : a.Store(AccessBuilder::ForJSIteratorResultDone(), done);
862 : STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
863 12701 : a.FinishAndChange(node);
864 12701 : return Changed(node);
865 : }
866 :
867 84 : Reduction JSCreateLowering::ReduceJSCreateKeyValueArray(Node* node) {
868 : DCHECK_EQ(IrOpcode::kJSCreateKeyValueArray, node->opcode());
869 14 : Node* key = NodeProperties::GetValueInput(node, 0);
870 14 : Node* value = NodeProperties::GetValueInput(node, 1);
871 14 : Node* effect = NodeProperties::GetEffectInput(node);
872 :
873 : Node* array_map = jsgraph()->HeapConstant(
874 14 : handle(native_context()->js_array_fast_elements_map_index()));
875 14 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
876 14 : Node* length = jsgraph()->Constant(2);
877 :
878 14 : AllocationBuilder aa(jsgraph(), effect, graph()->start());
879 14 : aa.AllocateArray(2, factory()->fixed_array_map());
880 : aa.Store(AccessBuilder::ForFixedArrayElement(FAST_ELEMENTS),
881 14 : jsgraph()->Constant(0), key);
882 : aa.Store(AccessBuilder::ForFixedArrayElement(FAST_ELEMENTS),
883 14 : jsgraph()->Constant(1), value);
884 14 : Node* elements = aa.Finish();
885 :
886 14 : AllocationBuilder a(jsgraph(), elements, graph()->start());
887 14 : a.Allocate(JSArray::kSize);
888 14 : a.Store(AccessBuilder::ForMap(), array_map);
889 14 : a.Store(AccessBuilder::ForJSObjectProperties(), properties);
890 14 : a.Store(AccessBuilder::ForJSObjectElements(), elements);
891 14 : a.Store(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS), length);
892 : STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize);
893 14 : a.FinishAndChange(node);
894 14 : return Changed(node);
895 : }
896 :
897 73338 : Reduction JSCreateLowering::ReduceJSCreateLiteral(Node* node) {
898 : DCHECK(node->opcode() == IrOpcode::kJSCreateLiteralArray ||
899 : node->opcode() == IrOpcode::kJSCreateLiteralObject);
900 146659 : CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
901 73338 : Node* effect = NodeProperties::GetEffectInput(node);
902 73338 : Node* control = NodeProperties::GetControlInput(node);
903 :
904 : Handle<FeedbackVector> feedback_vector;
905 146676 : if (GetSpecializationFeedbackVector(node).ToHandle(&feedback_vector)) {
906 : FeedbackSlot slot(FeedbackVector::ToSlot(p.index()));
907 : Handle<Object> literal(feedback_vector->Get(slot), isolate());
908 73321 : if (literal->IsAllocationSite()) {
909 : Handle<AllocationSite> site = Handle<AllocationSite>::cast(literal);
910 : Handle<JSObject> boilerplate(JSObject::cast(site->transition_info()),
911 : isolate());
912 7427 : int max_properties = kMaxFastLiteralProperties;
913 7427 : if (IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) {
914 : AllocationSiteUsageContext site_context(isolate(), site, false);
915 7397 : site_context.EnterNewScope();
916 : Node* value = effect =
917 7397 : AllocateFastLiteral(effect, control, boilerplate, &site_context);
918 : site_context.ExitScope(site, boilerplate);
919 7397 : ReplaceWithValue(node, value, effect, control);
920 : return Replace(value);
921 : }
922 : }
923 : }
924 :
925 : return NoChange();
926 : }
927 :
928 126677 : Reduction JSCreateLowering::ReduceJSCreateFunctionContext(Node* node) {
929 : DCHECK_EQ(IrOpcode::kJSCreateFunctionContext, node->opcode());
930 17201 : const CreateFunctionContextParameters& parameters =
931 17201 : CreateFunctionContextParametersOf(node->op());
932 : int slot_count = parameters.slot_count();
933 : ScopeType scope_type = parameters.scope_type();
934 17201 : Node* const closure = NodeProperties::GetValueInput(node, 0);
935 :
936 : // Use inline allocation for function contexts up to a size limit.
937 17201 : if (slot_count < kFunctionContextAllocationLimit) {
938 : // JSCreateFunctionContext[slot_count < limit]](fun)
939 16780 : Node* effect = NodeProperties::GetEffectInput(node);
940 16780 : Node* control = NodeProperties::GetControlInput(node);
941 16780 : Node* context = NodeProperties::GetContextInput(node);
942 16780 : Node* extension = jsgraph()->TheHoleConstant();
943 : AllocationBuilder a(jsgraph(), effect, control);
944 : STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
945 16780 : int context_length = slot_count + Context::MIN_CONTEXT_SLOTS;
946 : Handle<Map> map;
947 16780 : switch (scope_type) {
948 : case EVAL_SCOPE:
949 4384 : map = factory()->eval_context_map();
950 4384 : break;
951 : case FUNCTION_SCOPE:
952 12396 : map = factory()->function_context_map();
953 12396 : break;
954 : default:
955 0 : UNREACHABLE();
956 : }
957 16780 : a.AllocateArray(context_length, map);
958 16780 : a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
959 16780 : a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
960 16780 : a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
961 : a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
962 16780 : jsgraph()->HeapConstant(native_context()));
963 75916 : for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) {
964 59136 : a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant());
965 : }
966 : RelaxControls(node);
967 16780 : a.FinishAndChange(node);
968 : return Changed(node);
969 : }
970 :
971 : return NoChange();
972 : }
973 :
974 3252 : Reduction JSCreateLowering::ReduceJSCreateWithContext(Node* node) {
975 : DCHECK_EQ(IrOpcode::kJSCreateWithContext, node->opcode());
976 813 : Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node);
977 813 : Node* object = NodeProperties::GetValueInput(node, 0);
978 813 : Node* closure = NodeProperties::GetValueInput(node, 1);
979 813 : Node* effect = NodeProperties::GetEffectInput(node);
980 813 : Node* control = NodeProperties::GetControlInput(node);
981 813 : Node* context = NodeProperties::GetContextInput(node);
982 :
983 : AllocationBuilder aa(jsgraph(), effect, control);
984 813 : aa.Allocate(ContextExtension::kSize);
985 813 : aa.Store(AccessBuilder::ForMap(), factory()->context_extension_map());
986 813 : aa.Store(AccessBuilder::ForContextExtensionScopeInfo(), scope_info);
987 813 : aa.Store(AccessBuilder::ForContextExtensionExtension(), object);
988 813 : Node* extension = aa.Finish();
989 :
990 : AllocationBuilder a(jsgraph(), extension, control);
991 : STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
992 813 : a.AllocateArray(Context::MIN_CONTEXT_SLOTS, factory()->with_context_map());
993 813 : a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
994 813 : a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
995 813 : a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
996 : a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
997 813 : jsgraph()->HeapConstant(native_context()));
998 : RelaxControls(node);
999 813 : a.FinishAndChange(node);
1000 813 : return Changed(node);
1001 : }
1002 :
1003 103876 : Reduction JSCreateLowering::ReduceJSCreateCatchContext(Node* node) {
1004 : DCHECK_EQ(IrOpcode::kJSCreateCatchContext, node->opcode());
1005 : const CreateCatchContextParameters& parameters =
1006 25969 : CreateCatchContextParametersOf(node->op());
1007 25969 : Node* exception = NodeProperties::GetValueInput(node, 0);
1008 25969 : Node* closure = NodeProperties::GetValueInput(node, 1);
1009 25969 : Node* effect = NodeProperties::GetEffectInput(node);
1010 25969 : Node* control = NodeProperties::GetControlInput(node);
1011 25969 : Node* context = NodeProperties::GetContextInput(node);
1012 :
1013 : AllocationBuilder aa(jsgraph(), effect, control);
1014 25969 : aa.Allocate(ContextExtension::kSize);
1015 25969 : aa.Store(AccessBuilder::ForMap(), factory()->context_extension_map());
1016 : aa.Store(AccessBuilder::ForContextExtensionScopeInfo(),
1017 25969 : parameters.scope_info());
1018 : aa.Store(AccessBuilder::ForContextExtensionExtension(),
1019 25969 : parameters.catch_name());
1020 25969 : Node* extension = aa.Finish();
1021 :
1022 : AllocationBuilder a(jsgraph(), extension, control);
1023 : STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
1024 : a.AllocateArray(Context::MIN_CONTEXT_SLOTS + 1,
1025 25969 : factory()->catch_context_map());
1026 25969 : a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
1027 25969 : a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
1028 25969 : a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
1029 : a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
1030 25969 : jsgraph()->HeapConstant(native_context()));
1031 : a.Store(AccessBuilder::ForContextSlot(Context::THROWN_OBJECT_INDEX),
1032 25969 : exception);
1033 : RelaxControls(node);
1034 25969 : a.FinishAndChange(node);
1035 25969 : return Changed(node);
1036 : }
1037 :
1038 34195 : Reduction JSCreateLowering::ReduceJSCreateBlockContext(Node* node) {
1039 : DCHECK_EQ(IrOpcode::kJSCreateBlockContext, node->opcode());
1040 6649 : Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node);
1041 6649 : int const context_length = scope_info->ContextLength();
1042 6649 : Node* const closure = NodeProperties::GetValueInput(node, 0);
1043 :
1044 : // Use inline allocation for block contexts up to a size limit.
1045 6649 : if (context_length < kBlockContextAllocationLimit) {
1046 : // JSCreateBlockContext[scope[length < limit]](fun)
1047 6649 : Node* effect = NodeProperties::GetEffectInput(node);
1048 6649 : Node* control = NodeProperties::GetControlInput(node);
1049 6649 : Node* context = NodeProperties::GetContextInput(node);
1050 6649 : Node* extension = jsgraph()->Constant(scope_info);
1051 :
1052 : AllocationBuilder a(jsgraph(), effect, control);
1053 : STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
1054 6649 : a.AllocateArray(context_length, factory()->block_context_map());
1055 6649 : a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
1056 6649 : a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
1057 6649 : a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
1058 : a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
1059 6649 : jsgraph()->HeapConstant(native_context()));
1060 14248 : for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) {
1061 7599 : a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant());
1062 : }
1063 : RelaxControls(node);
1064 6649 : a.FinishAndChange(node);
1065 : return Changed(node);
1066 : }
1067 :
1068 : return NoChange();
1069 : }
1070 :
1071 : // Helper that allocates a FixedArray holding argument values recorded in the
1072 : // given {frame_state}. Serves as backing store for JSCreateArguments nodes.
1073 857 : Node* JSCreateLowering::AllocateArguments(Node* effect, Node* control,
1074 857 : Node* frame_state) {
1075 857 : FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
1076 857 : int argument_count = state_info.parameter_count() - 1; // Minus receiver.
1077 886 : if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant();
1078 :
1079 : // Prepare an iterator over argument values recorded in the frame state.
1080 : Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
1081 : StateValuesAccess parameters_access(parameters);
1082 828 : auto parameters_it = ++parameters_access.begin();
1083 :
1084 : // Actually allocate the backing store.
1085 : AllocationBuilder a(jsgraph(), effect, control);
1086 828 : a.AllocateArray(argument_count, factory()->fixed_array_map());
1087 2708 : for (int i = 0; i < argument_count; ++i, ++parameters_it) {
1088 : DCHECK_NOT_NULL((*parameters_it).node);
1089 1880 : a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node);
1090 : }
1091 828 : return a.Finish();
1092 : }
1093 :
1094 : // Helper that allocates a FixedArray holding argument values recorded in the
1095 : // given {frame_state}. Serves as backing store for JSCreateArguments nodes.
1096 43 : Node* JSCreateLowering::AllocateRestArguments(Node* effect, Node* control,
1097 : Node* frame_state,
1098 43 : int start_index) {
1099 43 : FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
1100 43 : int argument_count = state_info.parameter_count() - 1; // Minus receiver.
1101 86 : int num_elements = std::max(0, argument_count - start_index);
1102 44 : if (num_elements == 0) return jsgraph()->EmptyFixedArrayConstant();
1103 :
1104 : // Prepare an iterator over argument values recorded in the frame state.
1105 : Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
1106 : StateValuesAccess parameters_access(parameters);
1107 42 : auto parameters_it = ++parameters_access.begin();
1108 :
1109 : // Skip unused arguments.
1110 63 : for (int i = 0; i < start_index; i++) {
1111 21 : ++parameters_it;
1112 : }
1113 :
1114 : // Actually allocate the backing store.
1115 : AllocationBuilder a(jsgraph(), effect, control);
1116 42 : a.AllocateArray(num_elements, factory()->fixed_array_map());
1117 133 : for (int i = 0; i < num_elements; ++i, ++parameters_it) {
1118 : DCHECK_NOT_NULL((*parameters_it).node);
1119 91 : a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node);
1120 : }
1121 42 : return a.Finish();
1122 : }
1123 :
1124 : // Helper that allocates a FixedArray serving as a parameter map for values
1125 : // recorded in the given {frame_state}. Some elements map to slots within the
1126 : // given {context}. Serves as backing store for JSCreateArguments nodes.
1127 340 : Node* JSCreateLowering::AllocateAliasedArguments(
1128 : Node* effect, Node* control, Node* frame_state, Node* context,
1129 692 : Handle<SharedFunctionInfo> shared, bool* has_aliased_arguments) {
1130 340 : FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
1131 340 : int argument_count = state_info.parameter_count() - 1; // Minus receiver.
1132 398 : if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant();
1133 :
1134 : // If there is no aliasing, the arguments object elements are not special in
1135 : // any way, we can just return an unmapped backing store instead.
1136 : int parameter_count = shared->internal_formal_parameter_count();
1137 282 : if (parameter_count == 0) {
1138 155 : return AllocateArguments(effect, control, frame_state);
1139 : }
1140 :
1141 : // Calculate number of argument values being aliased/mapped.
1142 : int mapped_count = Min(argument_count, parameter_count);
1143 127 : *has_aliased_arguments = true;
1144 :
1145 : // Prepare an iterator over argument values recorded in the frame state.
1146 : Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
1147 : StateValuesAccess parameters_access(parameters);
1148 127 : auto parameters_it = ++parameters_access.begin();
1149 :
1150 : // The unmapped argument values recorded in the frame state are stored yet
1151 : // another indirection away and then linked into the parameter map below,
1152 : // whereas mapped argument values are replaced with a hole instead.
1153 : AllocationBuilder aa(jsgraph(), effect, control);
1154 127 : aa.AllocateArray(argument_count, factory()->fixed_array_map());
1155 317 : for (int i = 0; i < mapped_count; ++i, ++parameters_it) {
1156 190 : aa.Store(AccessBuilder::ForFixedArraySlot(i), jsgraph()->TheHoleConstant());
1157 : }
1158 39 : for (int i = mapped_count; i < argument_count; ++i, ++parameters_it) {
1159 : DCHECK_NOT_NULL((*parameters_it).node);
1160 39 : aa.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node);
1161 : }
1162 127 : Node* arguments = aa.Finish();
1163 :
1164 : // Actually allocate the backing store.
1165 : AllocationBuilder a(jsgraph(), arguments, control);
1166 127 : a.AllocateArray(mapped_count + 2, factory()->sloppy_arguments_elements_map());
1167 127 : a.Store(AccessBuilder::ForFixedArraySlot(0), context);
1168 127 : a.Store(AccessBuilder::ForFixedArraySlot(1), arguments);
1169 317 : for (int i = 0; i < mapped_count; ++i) {
1170 190 : int idx = Context::MIN_CONTEXT_SLOTS + parameter_count - 1 - i;
1171 190 : a.Store(AccessBuilder::ForFixedArraySlot(i + 2), jsgraph()->Constant(idx));
1172 : }
1173 127 : return a.Finish();
1174 : }
1175 :
1176 299 : Node* JSCreateLowering::AllocateElements(Node* effect, Node* control,
1177 : ElementsKind elements_kind,
1178 : int capacity,
1179 1908 : PretenureFlag pretenure) {
1180 : DCHECK_LE(1, capacity);
1181 : DCHECK_LE(capacity, JSArray::kInitialMaxFastElementArray);
1182 :
1183 : Handle<Map> elements_map = IsFastDoubleElementsKind(elements_kind)
1184 : ? factory()->fixed_double_array_map()
1185 598 : : factory()->fixed_array_map();
1186 : ElementAccess access = IsFastDoubleElementsKind(elements_kind)
1187 : ? AccessBuilder::ForFixedDoubleArrayElement()
1188 299 : : AccessBuilder::ForFixedArrayElement();
1189 299 : Node* value = jsgraph()->TheHoleConstant();
1190 :
1191 : // Actually allocate the backing store.
1192 : AllocationBuilder a(jsgraph(), effect, control);
1193 299 : a.AllocateArray(capacity, elements_map, pretenure);
1194 1609 : for (int i = 0; i < capacity; ++i) {
1195 1310 : Node* index = jsgraph()->Constant(i);
1196 1310 : a.Store(access, index, value);
1197 : }
1198 299 : return a.Finish();
1199 : }
1200 :
1201 74 : Node* JSCreateLowering::AllocateElements(Node* effect, Node* control,
1202 : ElementsKind elements_kind,
1203 132271 : std::vector<Node*> const& values,
1204 132271 : PretenureFlag pretenure) {
1205 74 : int const capacity = static_cast<int>(values.size());
1206 : DCHECK_LE(1, capacity);
1207 : DCHECK_LE(capacity, JSArray::kInitialMaxFastElementArray);
1208 :
1209 : Handle<Map> elements_map = IsFastDoubleElementsKind(elements_kind)
1210 : ? factory()->fixed_double_array_map()
1211 148 : : factory()->fixed_array_map();
1212 : ElementAccess access = IsFastDoubleElementsKind(elements_kind)
1213 : ? AccessBuilder::ForFixedDoubleArrayElement()
1214 74 : : AccessBuilder::ForFixedArrayElement();
1215 :
1216 : // Actually allocate the backing store.
1217 : AllocationBuilder a(jsgraph(), effect, control);
1218 74 : a.AllocateArray(capacity, elements_map, pretenure);
1219 132271 : for (int i = 0; i < capacity; ++i) {
1220 132197 : Node* index = jsgraph()->Constant(i);
1221 264394 : a.Store(access, index, values[i]);
1222 : }
1223 74 : return a.Finish();
1224 : }
1225 :
1226 7971 : Node* JSCreateLowering::AllocateFastLiteral(
1227 : Node* effect, Node* control, Handle<JSObject> boilerplate,
1228 41591 : AllocationSiteUsageContext* site_context) {
1229 : Handle<AllocationSite> current_site(*site_context->current(), isolate());
1230 7971 : dependencies()->AssumeTransitionStable(current_site);
1231 :
1232 : PretenureFlag pretenure = NOT_TENURED;
1233 7971 : if (FLAG_allocation_site_pretenuring) {
1234 : Handle<AllocationSite> top_site(*site_context->top(), isolate());
1235 7971 : pretenure = top_site->GetPretenureMode();
1236 7971 : if (current_site.is_identical_to(top_site)) {
1237 : // We install a dependency for pretenuring only on the outermost literal.
1238 : dependencies()->AssumeTenuringDecision(top_site);
1239 : }
1240 : }
1241 :
1242 : // Setup the properties backing store.
1243 7971 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
1244 :
1245 : // Compute the in-object properties to store first (might have effects).
1246 : Handle<Map> boilerplate_map(boilerplate->map(), isolate());
1247 : ZoneVector<std::pair<FieldAccess, Node*>> inobject_fields(zone());
1248 7971 : inobject_fields.reserve(boilerplate_map->GetInObjectProperties());
1249 : int const boilerplate_nof = boilerplate_map->NumberOfOwnDescriptors();
1250 15612 : for (int i = 0; i < boilerplate_nof; ++i) {
1251 : PropertyDetails const property_details =
1252 7641 : boilerplate_map->instance_descriptors()->GetDetails(i);
1253 12749 : if (property_details.location() != kField) continue;
1254 : DCHECK_EQ(kData, property_details.kind());
1255 : Handle<Name> property_name(
1256 : boilerplate_map->instance_descriptors()->GetKey(i), isolate());
1257 2533 : FieldIndex index = FieldIndex::ForDescriptor(*boilerplate_map, i);
1258 : FieldAccess access = {kTaggedBase, index.offset(),
1259 : property_name, MaybeHandle<Map>(),
1260 : Type::Any(), MachineType::AnyTagged(),
1261 : kFullWriteBarrier};
1262 : Node* value;
1263 2533 : if (boilerplate->IsUnboxedDoubleField(index)) {
1264 : access.machine_type = MachineType::Float64();
1265 : access.type = Type::Number();
1266 136 : value = jsgraph()->Constant(boilerplate->RawFastDoublePropertyAt(index));
1267 : } else {
1268 : Handle<Object> boilerplate_value(boilerplate->RawFastPropertyAt(index),
1269 2397 : isolate());
1270 2397 : if (boilerplate_value->IsJSObject()) {
1271 : Handle<JSObject> boilerplate_object =
1272 223 : Handle<JSObject>::cast(boilerplate_value);
1273 223 : Handle<AllocationSite> current_site = site_context->EnterNewScope();
1274 : value = effect = AllocateFastLiteral(effect, control,
1275 223 : boilerplate_object, site_context);
1276 : site_context->ExitScope(current_site, boilerplate_object);
1277 2174 : } else if (property_details.representation().IsDouble()) {
1278 : double number = Handle<HeapNumber>::cast(boilerplate_value)->value();
1279 : // Allocate a mutable HeapNumber box and store the value into it.
1280 : AllocationBuilder builder(jsgraph(), effect, control);
1281 0 : builder.Allocate(HeapNumber::kSize, pretenure);
1282 : builder.Store(AccessBuilder::ForMap(),
1283 0 : factory()->mutable_heap_number_map());
1284 : builder.Store(AccessBuilder::ForHeapNumberValue(),
1285 0 : jsgraph()->Constant(number));
1286 0 : value = effect = builder.Finish();
1287 2174 : } else if (property_details.representation().IsSmi()) {
1288 : // Ensure that value is stored as smi.
1289 : value = boilerplate_value->IsUninitialized(isolate())
1290 : ? jsgraph()->ZeroConstant()
1291 2160 : : jsgraph()->Constant(boilerplate_value);
1292 : } else {
1293 1094 : value = jsgraph()->Constant(boilerplate_value);
1294 : }
1295 : }
1296 2533 : inobject_fields.push_back(std::make_pair(access, value));
1297 : }
1298 :
1299 : // Fill slack at the end of the boilerplate object with filler maps.
1300 : int const boilerplate_length = boilerplate_map->GetInObjectProperties();
1301 20639 : for (int index = static_cast<int>(inobject_fields.size());
1302 : index < boilerplate_length; ++index) {
1303 : FieldAccess access =
1304 4697 : AccessBuilder::ForJSObjectInObjectProperty(boilerplate_map, index);
1305 4697 : Node* value = jsgraph()->HeapConstant(factory()->one_pointer_filler_map());
1306 4697 : inobject_fields.push_back(std::make_pair(access, value));
1307 : }
1308 :
1309 : // Setup the elements backing store.
1310 7971 : Node* elements = AllocateFastLiteralElements(effect, control, boilerplate,
1311 7971 : pretenure, site_context);
1312 15942 : if (elements->op()->EffectOutputCount() > 0) effect = elements;
1313 :
1314 : // Actually allocate and initialize the object.
1315 : AllocationBuilder builder(jsgraph(), effect, control);
1316 : builder.Allocate(boilerplate_map->instance_size(), pretenure,
1317 7971 : Type::For(boilerplate_map));
1318 7971 : builder.Store(AccessBuilder::ForMap(), boilerplate_map);
1319 7971 : builder.Store(AccessBuilder::ForJSObjectProperties(), properties);
1320 7971 : builder.Store(AccessBuilder::ForJSObjectElements(), elements);
1321 7971 : if (boilerplate_map->IsJSArrayMap()) {
1322 : Handle<JSArray> boilerplate_array = Handle<JSArray>::cast(boilerplate);
1323 : builder.Store(
1324 : AccessBuilder::ForJSArrayLength(boilerplate_array->GetElementsKind()),
1325 5108 : handle(boilerplate_array->length(), isolate()));
1326 : }
1327 23172 : for (auto const& inobject_field : inobject_fields) {
1328 7230 : builder.Store(inobject_field.first, inobject_field.second);
1329 : }
1330 7971 : return builder.Finish();
1331 : }
1332 :
1333 7971 : Node* JSCreateLowering::AllocateFastLiteralElements(
1334 : Node* effect, Node* control, Handle<JSObject> boilerplate,
1335 38272 : PretenureFlag pretenure, AllocationSiteUsageContext* site_context) {
1336 : Handle<FixedArrayBase> boilerplate_elements(boilerplate->elements(),
1337 : isolate());
1338 :
1339 : // Empty or copy-on-write elements just store a constant.
1340 12201 : if (boilerplate_elements->length() == 0 ||
1341 4230 : boilerplate_elements->map() == isolate()->heap()->fixed_cow_array_map()) {
1342 5561 : if (pretenure == TENURED &&
1343 : isolate()->heap()->InNewSpace(*boilerplate_elements)) {
1344 : // If we would like to pretenure a fixed cow array, we must ensure that
1345 : // the array is already in old space, otherwise we'll create too many
1346 : // old-to-new-space pointers (overflowing the store buffer).
1347 : boilerplate_elements = Handle<FixedArrayBase>(
1348 : isolate()->factory()->CopyAndTenureFixedCOWArray(
1349 0 : Handle<FixedArray>::cast(boilerplate_elements)));
1350 0 : boilerplate->set_elements(*boilerplate_elements);
1351 : }
1352 5525 : return jsgraph()->HeapConstant(boilerplate_elements);
1353 : }
1354 :
1355 : // Compute the elements to store first (might have effects).
1356 : int const elements_length = boilerplate_elements->length();
1357 : Handle<Map> elements_map(boilerplate_elements->map(), isolate());
1358 2446 : ZoneVector<Node*> elements_values(elements_length, zone());
1359 2446 : if (elements_map->instance_type() == FIXED_DOUBLE_ARRAY_TYPE) {
1360 : Handle<FixedDoubleArray> elements =
1361 : Handle<FixedDoubleArray>::cast(boilerplate_elements);
1362 7701 : for (int i = 0; i < elements_length; ++i) {
1363 7701 : if (elements->is_the_hole(i)) {
1364 138 : elements_values[i] = jsgraph()->TheHoleConstant();
1365 : } else {
1366 15264 : elements_values[i] = jsgraph()->Constant(elements->get_scalar(i));
1367 : }
1368 : }
1369 : } else {
1370 : Handle<FixedArray> elements =
1371 : Handle<FixedArray>::cast(boilerplate_elements);
1372 6402 : for (int i = 0; i < elements_length; ++i) {
1373 6402 : if (elements->is_the_hole(isolate(), i)) {
1374 2950 : elements_values[i] = jsgraph()->TheHoleConstant();
1375 : } else {
1376 : Handle<Object> element_value(elements->get(i), isolate());
1377 4927 : if (element_value->IsJSObject()) {
1378 : Handle<JSObject> boilerplate_object =
1379 351 : Handle<JSObject>::cast(element_value);
1380 351 : Handle<AllocationSite> current_site = site_context->EnterNewScope();
1381 351 : elements_values[i] = effect = AllocateFastLiteral(
1382 351 : effect, control, boilerplate_object, site_context);
1383 : site_context->ExitScope(current_site, boilerplate_object);
1384 : } else {
1385 9152 : elements_values[i] = jsgraph()->Constant(element_value);
1386 : }
1387 : }
1388 : }
1389 : }
1390 :
1391 : // Allocate the backing store array and store the elements.
1392 : AllocationBuilder builder(jsgraph(), effect, control);
1393 2446 : builder.AllocateArray(elements_length, elements_map, pretenure);
1394 : ElementAccess const access =
1395 : (elements_map->instance_type() == FIXED_DOUBLE_ARRAY_TYPE)
1396 : ? AccessBuilder::ForFixedDoubleArrayElement()
1397 2446 : : AccessBuilder::ForFixedArrayElement();
1398 14103 : for (int i = 0; i < elements_length; ++i) {
1399 42309 : builder.Store(access, jsgraph()->Constant(i), elements_values[i]);
1400 : }
1401 2446 : return builder.Finish();
1402 : }
1403 :
1404 73338 : MaybeHandle<FeedbackVector> JSCreateLowering::GetSpecializationFeedbackVector(
1405 : Node* node) {
1406 73338 : Node* const closure = NodeProperties::GetValueInput(node, 0);
1407 73338 : switch (closure->opcode()) {
1408 : case IrOpcode::kHeapConstant: {
1409 69032 : Handle<HeapObject> object = OpParameter<Handle<HeapObject>>(closure);
1410 : return handle(Handle<JSFunction>::cast(object)->feedback_vector());
1411 : }
1412 : case IrOpcode::kParameter: {
1413 4289 : int const index = ParameterIndexOf(closure->op());
1414 : // The closure is always the last parameter to a JavaScript function, and
1415 : // {Parameter} indices start at -1, so value outputs of {Start} look like
1416 : // this: closure, receiver, param0, ..., paramN, context.
1417 4289 : if (index == -1) {
1418 4289 : return feedback_vector_;
1419 : }
1420 : break;
1421 : }
1422 : default:
1423 : break;
1424 : }
1425 : return MaybeHandle<FeedbackVector>();
1426 : }
1427 :
1428 0 : Factory* JSCreateLowering::factory() const { return isolate()->factory(); }
1429 :
1430 44480 : Graph* JSCreateLowering::graph() const { return jsgraph()->graph(); }
1431 :
1432 260050 : Isolate* JSCreateLowering::isolate() const { return jsgraph()->isolate(); }
1433 :
1434 0 : JSOperatorBuilder* JSCreateLowering::javascript() const {
1435 0 : return jsgraph()->javascript();
1436 : }
1437 :
1438 4272 : CommonOperatorBuilder* JSCreateLowering::common() const {
1439 4272 : return jsgraph()->common();
1440 : }
1441 :
1442 13335 : SimplifiedOperatorBuilder* JSCreateLowering::simplified() const {
1443 13335 : return jsgraph()->simplified();
1444 : }
1445 :
1446 0 : MachineOperatorBuilder* JSCreateLowering::machine() const {
1447 0 : return jsgraph()->machine();
1448 : }
1449 :
1450 : } // namespace compiler
1451 : } // namespace internal
1452 : } // namespace v8
|