• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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