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