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