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