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
22namespace v8 {
23namespace internal {
24namespace compiler {
25
26namespace {
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.
31class AllocationBuilder final {
32 public:
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.
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.
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.
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.
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.
80  void Store(const FieldAccess& access, Handle<Object> value) {
81    Store(access, jsgraph()->Constant(value));
82  }
83
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
92  Node* Finish() {
93    return graph()->NewNode(common()->FinishRegion(), allocation_, effect_);
94  }
95
96 protected:
97  JSGraph* jsgraph() { return jsgraph_; }
98  Graph* graph() { return jsgraph_->graph(); }
99  CommonOperatorBuilder* common() { return jsgraph_->common(); }
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.
110Node* 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.
120bool 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.
128const int kElementLoopUnrollLimit = 16;
129
130// Limits up to which context allocations are inlined.
131const int kFunctionContextAllocationLimit = 16;
132const 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.
137bool 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.
201const int kMaxFastLiteralDepth = 3;
202const int kMaxFastLiteralProperties = 8;
203
204}  // namespace
205
206Reduction 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
235Reduction 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
289Reduction 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
540Reduction 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
586Reduction 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
715Reduction 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
754Reduction 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
778Reduction 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
808Reduction 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
839Reduction 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
885Reduction 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
914Reduction 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
949Reduction 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.
984Node* 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.
1007Node* 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.
1038Node* 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
1087Node* 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
1122Node* 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
1229Node* 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
1309MaybeHandle<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
1333Factory* JSCreateLowering::factory() const { return isolate()->factory(); }
1334
1335Graph* JSCreateLowering::graph() const { return jsgraph()->graph(); }
1336
1337Isolate* JSCreateLowering::isolate() const { return jsgraph()->isolate(); }
1338
1339JSOperatorBuilder* JSCreateLowering::javascript() const {
1340  return jsgraph()->javascript();
1341}
1342
1343CommonOperatorBuilder* JSCreateLowering::common() const {
1344  return jsgraph()->common();
1345}
1346
1347SimplifiedOperatorBuilder* JSCreateLowering::simplified() const {
1348  return jsgraph()->simplified();
1349}
1350
1351MachineOperatorBuilder* JSCreateLowering::machine() const {
1352  return jsgraph()->machine();
1353}
1354
1355}  // namespace compiler
1356}  // namespace internal
1357}  // namespace v8
1358