1// Copyright 2014 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-generic-lowering.h"
6
7#include "src/ast/ast.h"
8#include "src/code-factory.h"
9#include "src/code-stubs.h"
10#include "src/compiler/common-operator.h"
11#include "src/compiler/js-graph.h"
12#include "src/compiler/machine-operator.h"
13#include "src/compiler/node-matchers.h"
14#include "src/compiler/node-properties.h"
15#include "src/compiler/operator-properties.h"
16
17namespace v8 {
18namespace internal {
19namespace compiler {
20
21namespace {
22
23CallDescriptor::Flags FrameStateFlagForCall(Node* node) {
24  return OperatorProperties::HasFrameStateInput(node->op())
25             ? CallDescriptor::kNeedsFrameState
26             : CallDescriptor::kNoFlags;
27}
28
29}  // namespace
30
31JSGenericLowering::JSGenericLowering(JSGraph* jsgraph) : jsgraph_(jsgraph) {}
32
33JSGenericLowering::~JSGenericLowering() {}
34
35
36Reduction JSGenericLowering::Reduce(Node* node) {
37  switch (node->opcode()) {
38#define DECLARE_CASE(x)  \
39    case IrOpcode::k##x: \
40      Lower##x(node);    \
41      break;
42    JS_OP_LIST(DECLARE_CASE)
43#undef DECLARE_CASE
44    default:
45      // Nothing to see.
46      return NoChange();
47  }
48  return Changed(node);
49}
50
51#define REPLACE_STUB_CALL(Name)                                \
52  void JSGenericLowering::LowerJS##Name(Node* node) {          \
53    CallDescriptor::Flags flags = FrameStateFlagForCall(node); \
54    Callable callable = CodeFactory::Name(isolate());          \
55    ReplaceWithStubCall(node, callable, flags);                \
56  }
57REPLACE_STUB_CALL(Add)
58REPLACE_STUB_CALL(Subtract)
59REPLACE_STUB_CALL(Multiply)
60REPLACE_STUB_CALL(Divide)
61REPLACE_STUB_CALL(Modulus)
62REPLACE_STUB_CALL(BitwiseAnd)
63REPLACE_STUB_CALL(BitwiseOr)
64REPLACE_STUB_CALL(BitwiseXor)
65REPLACE_STUB_CALL(ShiftLeft)
66REPLACE_STUB_CALL(ShiftRight)
67REPLACE_STUB_CALL(ShiftRightLogical)
68REPLACE_STUB_CALL(LessThan)
69REPLACE_STUB_CALL(LessThanOrEqual)
70REPLACE_STUB_CALL(GreaterThan)
71REPLACE_STUB_CALL(GreaterThanOrEqual)
72REPLACE_STUB_CALL(HasProperty)
73REPLACE_STUB_CALL(Equal)
74REPLACE_STUB_CALL(NotEqual)
75REPLACE_STUB_CALL(ToInteger)
76REPLACE_STUB_CALL(ToLength)
77REPLACE_STUB_CALL(ToNumber)
78REPLACE_STUB_CALL(ToName)
79REPLACE_STUB_CALL(ToObject)
80REPLACE_STUB_CALL(ToString)
81#undef REPLACE_STUB_CALL
82
83void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
84                                            CallDescriptor::Flags flags) {
85  ReplaceWithStubCall(node, callable, flags, node->op()->properties());
86}
87
88void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
89                                            CallDescriptor::Flags flags,
90                                            Operator::Properties properties) {
91  const CallInterfaceDescriptor& descriptor = callable.descriptor();
92  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
93      isolate(), zone(), descriptor, descriptor.GetStackParameterCount(), flags,
94      properties);
95  Node* stub_code = jsgraph()->HeapConstant(callable.code());
96  node->InsertInput(zone(), 0, stub_code);
97  NodeProperties::ChangeOp(node, common()->Call(desc));
98}
99
100
101void JSGenericLowering::ReplaceWithRuntimeCall(Node* node,
102                                               Runtime::FunctionId f,
103                                               int nargs_override) {
104  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
105  Operator::Properties properties = node->op()->properties();
106  const Runtime::Function* fun = Runtime::FunctionForId(f);
107  int nargs = (nargs_override < 0) ? fun->nargs : nargs_override;
108  CallDescriptor* desc =
109      Linkage::GetRuntimeCallDescriptor(zone(), f, nargs, properties, flags);
110  Node* ref = jsgraph()->ExternalConstant(ExternalReference(f, isolate()));
111  Node* arity = jsgraph()->Int32Constant(nargs);
112  node->InsertInput(zone(), 0, jsgraph()->CEntryStubConstant(fun->result_size));
113  node->InsertInput(zone(), nargs + 1, ref);
114  node->InsertInput(zone(), nargs + 2, arity);
115  NodeProperties::ChangeOp(node, common()->Call(desc));
116}
117
118void JSGenericLowering::LowerJSStrictEqual(Node* node) {
119  // The === operator doesn't need the current context.
120  NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
121  Callable callable = CodeFactory::StrictEqual(isolate());
122  node->RemoveInput(4);  // control
123  ReplaceWithStubCall(node, callable, CallDescriptor::kNoFlags,
124                      Operator::kEliminatable);
125}
126
127void JSGenericLowering::LowerJSStrictNotEqual(Node* node) {
128  // The !== operator doesn't need the current context.
129  NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
130  Callable callable = CodeFactory::StrictNotEqual(isolate());
131  node->RemoveInput(4);  // control
132  ReplaceWithStubCall(node, callable, CallDescriptor::kNoFlags,
133                      Operator::kEliminatable);
134}
135
136void JSGenericLowering::LowerJSToBoolean(Node* node) {
137  // The ToBoolean conversion doesn't need the current context.
138  NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
139  Callable callable = CodeFactory::ToBoolean(isolate());
140  node->AppendInput(zone(), graph()->start());
141  ReplaceWithStubCall(node, callable, CallDescriptor::kNoAllocate,
142                      Operator::kEliminatable);
143}
144
145void JSGenericLowering::LowerJSTypeOf(Node* node) {
146  // The typeof operator doesn't need the current context.
147  NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
148  Callable callable = CodeFactory::Typeof(isolate());
149  node->AppendInput(zone(), graph()->start());
150  ReplaceWithStubCall(node, callable, CallDescriptor::kNoAllocate,
151                      Operator::kEliminatable);
152}
153
154
155void JSGenericLowering::LowerJSLoadProperty(Node* node) {
156  Node* closure = NodeProperties::GetValueInput(node, 2);
157  Node* effect = NodeProperties::GetEffectInput(node);
158  Node* control = NodeProperties::GetControlInput(node);
159  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
160  const PropertyAccess& p = PropertyAccessOf(node->op());
161  Callable callable = CodeFactory::KeyedLoadICInOptimizedCode(isolate());
162  // Load the type feedback vector from the closure.
163  Node* literals = effect = graph()->NewNode(
164      machine()->Load(MachineType::AnyTagged()), closure,
165      jsgraph()->IntPtrConstant(JSFunction::kLiteralsOffset - kHeapObjectTag),
166      effect, control);
167  Node* vector = effect = graph()->NewNode(
168      machine()->Load(MachineType::AnyTagged()), literals,
169      jsgraph()->IntPtrConstant(LiteralsArray::kFeedbackVectorOffset -
170                                kHeapObjectTag),
171      effect, control);
172  node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
173  node->ReplaceInput(3, vector);
174  node->ReplaceInput(6, effect);
175  ReplaceWithStubCall(node, callable, flags);
176}
177
178
179void JSGenericLowering::LowerJSLoadNamed(Node* node) {
180  Node* closure = NodeProperties::GetValueInput(node, 1);
181  Node* effect = NodeProperties::GetEffectInput(node);
182  Node* control = NodeProperties::GetControlInput(node);
183  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
184  NamedAccess const& p = NamedAccessOf(node->op());
185  Callable callable = CodeFactory::LoadICInOptimizedCode(isolate());
186  // Load the type feedback vector from the closure.
187  Node* literals = effect = graph()->NewNode(
188      machine()->Load(MachineType::AnyTagged()), closure,
189      jsgraph()->IntPtrConstant(JSFunction::kLiteralsOffset - kHeapObjectTag),
190      effect, control);
191  Node* vector = effect = graph()->NewNode(
192      machine()->Load(MachineType::AnyTagged()), literals,
193      jsgraph()->IntPtrConstant(LiteralsArray::kFeedbackVectorOffset -
194                                kHeapObjectTag),
195      effect, control);
196  node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
197  node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
198  node->ReplaceInput(3, vector);
199  node->ReplaceInput(6, effect);
200  ReplaceWithStubCall(node, callable, flags);
201}
202
203
204void JSGenericLowering::LowerJSLoadGlobal(Node* node) {
205  Node* closure = NodeProperties::GetValueInput(node, 0);
206  Node* effect = NodeProperties::GetEffectInput(node);
207  Node* control = NodeProperties::GetControlInput(node);
208  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
209  const LoadGlobalParameters& p = LoadGlobalParametersOf(node->op());
210  Callable callable =
211      CodeFactory::LoadGlobalICInOptimizedCode(isolate(), p.typeof_mode());
212  // Load the type feedback vector from the closure.
213  Node* literals = effect = graph()->NewNode(
214      machine()->Load(MachineType::AnyTagged()), closure,
215      jsgraph()->IntPtrConstant(JSFunction::kLiteralsOffset - kHeapObjectTag),
216      effect, control);
217  Node* vector = effect = graph()->NewNode(
218      machine()->Load(MachineType::AnyTagged()), literals,
219      jsgraph()->IntPtrConstant(LiteralsArray::kFeedbackVectorOffset -
220                                kHeapObjectTag),
221      effect, control);
222  node->InsertInput(zone(), 0, jsgraph()->SmiConstant(p.feedback().index()));
223  node->ReplaceInput(1, vector);
224  node->ReplaceInput(4, effect);
225  ReplaceWithStubCall(node, callable, flags);
226}
227
228
229void JSGenericLowering::LowerJSStoreProperty(Node* node) {
230  Node* receiver = NodeProperties::GetValueInput(node, 0);
231  Node* key = NodeProperties::GetValueInput(node, 1);
232  Node* value = NodeProperties::GetValueInput(node, 2);
233  Node* closure = NodeProperties::GetValueInput(node, 3);
234  Node* effect = NodeProperties::GetEffectInput(node);
235  Node* control = NodeProperties::GetControlInput(node);
236  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
237  PropertyAccess const& p = PropertyAccessOf(node->op());
238  LanguageMode language_mode = p.language_mode();
239  Callable callable =
240      CodeFactory::KeyedStoreICInOptimizedCode(isolate(), language_mode);
241  // Load the type feedback vector from the closure.
242  Node* literals = effect = graph()->NewNode(
243      machine()->Load(MachineType::AnyTagged()), closure,
244      jsgraph()->IntPtrConstant(JSFunction::kLiteralsOffset - kHeapObjectTag),
245      effect, control);
246  Node* vector = effect = graph()->NewNode(
247      machine()->Load(MachineType::AnyTagged()), literals,
248      jsgraph()->IntPtrConstant(LiteralsArray::kFeedbackVectorOffset -
249                                kHeapObjectTag),
250      effect, control);
251  typedef StoreWithVectorDescriptor Descriptor;
252  node->InsertInputs(zone(), 0, 1);
253  node->ReplaceInput(Descriptor::kReceiver, receiver);
254  node->ReplaceInput(Descriptor::kName, key);
255  node->ReplaceInput(Descriptor::kValue, value);
256  node->ReplaceInput(Descriptor::kSlot,
257                     jsgraph()->SmiConstant(p.feedback().index()));
258  node->ReplaceInput(Descriptor::kVector, vector);
259  node->ReplaceInput(7, effect);
260  ReplaceWithStubCall(node, callable, flags);
261}
262
263
264void JSGenericLowering::LowerJSStoreNamed(Node* node) {
265  Node* receiver = NodeProperties::GetValueInput(node, 0);
266  Node* value = NodeProperties::GetValueInput(node, 1);
267  Node* closure = NodeProperties::GetValueInput(node, 2);
268  Node* effect = NodeProperties::GetEffectInput(node);
269  Node* control = NodeProperties::GetControlInput(node);
270  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
271  NamedAccess const& p = NamedAccessOf(node->op());
272  Callable callable =
273      CodeFactory::StoreICInOptimizedCode(isolate(), p.language_mode());
274  // Load the type feedback vector from the closure.
275  Node* literals = effect = graph()->NewNode(
276      machine()->Load(MachineType::AnyTagged()), closure,
277      jsgraph()->IntPtrConstant(JSFunction::kLiteralsOffset - kHeapObjectTag),
278      effect, control);
279  Node* vector = effect = graph()->NewNode(
280      machine()->Load(MachineType::AnyTagged()), literals,
281      jsgraph()->IntPtrConstant(LiteralsArray::kFeedbackVectorOffset -
282                                kHeapObjectTag),
283      effect, control);
284  typedef StoreWithVectorDescriptor Descriptor;
285  node->InsertInputs(zone(), 0, 2);
286  node->ReplaceInput(Descriptor::kReceiver, receiver);
287  node->ReplaceInput(Descriptor::kName, jsgraph()->HeapConstant(p.name()));
288  node->ReplaceInput(Descriptor::kValue, value);
289  node->ReplaceInput(Descriptor::kSlot,
290                     jsgraph()->SmiConstant(p.feedback().index()));
291  node->ReplaceInput(Descriptor::kVector, vector);
292  node->ReplaceInput(7, effect);
293  ReplaceWithStubCall(node, callable, flags);
294}
295
296
297void JSGenericLowering::LowerJSStoreGlobal(Node* node) {
298  Node* value = NodeProperties::GetValueInput(node, 0);
299  Node* closure = NodeProperties::GetValueInput(node, 1);
300  Node* context = NodeProperties::GetContextInput(node);
301  Node* effect = NodeProperties::GetEffectInput(node);
302  Node* control = NodeProperties::GetControlInput(node);
303  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
304  const StoreGlobalParameters& p = StoreGlobalParametersOf(node->op());
305  Callable callable =
306      CodeFactory::StoreICInOptimizedCode(isolate(), p.language_mode());
307  // Load the type feedback vector from the closure.
308  Node* literals = effect = graph()->NewNode(
309      machine()->Load(MachineType::AnyTagged()), closure,
310      jsgraph()->IntPtrConstant(JSFunction::kLiteralsOffset - kHeapObjectTag),
311      effect, control);
312  Node* vector = effect = graph()->NewNode(
313      machine()->Load(MachineType::AnyTagged()), literals,
314      jsgraph()->IntPtrConstant(LiteralsArray::kFeedbackVectorOffset -
315                                kHeapObjectTag),
316      effect, control);
317  // Load global object from the context.
318  Node* native_context = effect =
319      graph()->NewNode(machine()->Load(MachineType::AnyTagged()), context,
320                       jsgraph()->IntPtrConstant(
321                           Context::SlotOffset(Context::NATIVE_CONTEXT_INDEX)),
322                       effect, control);
323  Node* global = effect = graph()->NewNode(
324      machine()->Load(MachineType::AnyTagged()), native_context,
325      jsgraph()->IntPtrConstant(Context::SlotOffset(Context::EXTENSION_INDEX)),
326      effect, control);
327  typedef StoreWithVectorDescriptor Descriptor;
328  node->InsertInputs(zone(), 0, 3);
329  node->ReplaceInput(Descriptor::kReceiver, global);
330  node->ReplaceInput(Descriptor::kName, jsgraph()->HeapConstant(p.name()));
331  node->ReplaceInput(Descriptor::kValue, value);
332  node->ReplaceInput(Descriptor::kSlot,
333                     jsgraph()->SmiConstant(p.feedback().index()));
334  node->ReplaceInput(Descriptor::kVector, vector);
335  node->ReplaceInput(7, effect);
336  ReplaceWithStubCall(node, callable, flags);
337}
338
339
340void JSGenericLowering::LowerJSDeleteProperty(Node* node) {
341  LanguageMode language_mode = OpParameter<LanguageMode>(node);
342  ReplaceWithRuntimeCall(node, is_strict(language_mode)
343                                   ? Runtime::kDeleteProperty_Strict
344                                   : Runtime::kDeleteProperty_Sloppy);
345}
346
347
348void JSGenericLowering::LowerJSInstanceOf(Node* node) {
349  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
350  Callable callable = CodeFactory::InstanceOf(isolate());
351  ReplaceWithStubCall(node, callable, flags);
352}
353
354void JSGenericLowering::LowerJSOrdinaryHasInstance(Node* node) {
355  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
356  Callable callable = CodeFactory::OrdinaryHasInstance(isolate());
357  ReplaceWithStubCall(node, callable, flags);
358}
359
360void JSGenericLowering::LowerJSLoadContext(Node* node) {
361  const ContextAccess& access = ContextAccessOf(node->op());
362  for (size_t i = 0; i < access.depth(); ++i) {
363    node->ReplaceInput(
364        0, graph()->NewNode(machine()->Load(MachineType::AnyTagged()),
365                            NodeProperties::GetValueInput(node, 0),
366                            jsgraph()->Int32Constant(
367                                Context::SlotOffset(Context::PREVIOUS_INDEX)),
368                            NodeProperties::GetEffectInput(node),
369                            graph()->start()));
370  }
371  node->ReplaceInput(1, jsgraph()->Int32Constant(Context::SlotOffset(
372                            static_cast<int>(access.index()))));
373  node->AppendInput(zone(), graph()->start());
374  NodeProperties::ChangeOp(node, machine()->Load(MachineType::AnyTagged()));
375}
376
377
378void JSGenericLowering::LowerJSStoreContext(Node* node) {
379  const ContextAccess& access = ContextAccessOf(node->op());
380  for (size_t i = 0; i < access.depth(); ++i) {
381    node->ReplaceInput(
382        0, graph()->NewNode(machine()->Load(MachineType::AnyTagged()),
383                            NodeProperties::GetValueInput(node, 0),
384                            jsgraph()->Int32Constant(
385                                Context::SlotOffset(Context::PREVIOUS_INDEX)),
386                            NodeProperties::GetEffectInput(node),
387                            graph()->start()));
388  }
389  node->ReplaceInput(2, NodeProperties::GetValueInput(node, 1));
390  node->ReplaceInput(1, jsgraph()->Int32Constant(Context::SlotOffset(
391                            static_cast<int>(access.index()))));
392  NodeProperties::ChangeOp(
393      node, machine()->Store(StoreRepresentation(MachineRepresentation::kTagged,
394                                                 kFullWriteBarrier)));
395}
396
397
398void JSGenericLowering::LowerJSCreate(Node* node) {
399  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
400  Callable callable = CodeFactory::FastNewObject(isolate());
401  ReplaceWithStubCall(node, callable, flags);
402}
403
404
405void JSGenericLowering::LowerJSCreateArguments(Node* node) {
406  CreateArgumentsType const type = CreateArgumentsTypeOf(node->op());
407  switch (type) {
408    case CreateArgumentsType::kMappedArguments:
409      ReplaceWithRuntimeCall(node, Runtime::kNewSloppyArguments_Generic);
410      break;
411    case CreateArgumentsType::kUnmappedArguments:
412      ReplaceWithRuntimeCall(node, Runtime::kNewStrictArguments);
413      break;
414    case CreateArgumentsType::kRestParameter:
415      ReplaceWithRuntimeCall(node, Runtime::kNewRestParameter);
416      break;
417  }
418}
419
420
421void JSGenericLowering::LowerJSCreateArray(Node* node) {
422  CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
423  int const arity = static_cast<int>(p.arity());
424  Handle<AllocationSite> const site = p.site();
425  Node* new_target = node->InputAt(1);
426  Node* type_info = site.is_null() ? jsgraph()->UndefinedConstant()
427                                   : jsgraph()->HeapConstant(site);
428  node->RemoveInput(1);
429  node->InsertInput(zone(), 1 + arity, new_target);
430  node->InsertInput(zone(), 2 + arity, type_info);
431  ReplaceWithRuntimeCall(node, Runtime::kNewArray, arity + 3);
432}
433
434
435void JSGenericLowering::LowerJSCreateClosure(Node* node) {
436  CreateClosureParameters const& p = CreateClosureParametersOf(node->op());
437  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
438  Handle<SharedFunctionInfo> const shared_info = p.shared_info();
439  node->InsertInput(zone(), 0, jsgraph()->HeapConstant(shared_info));
440
441  // Use the FastNewClosureStub only for functions allocated in new space.
442  if (p.pretenure() == NOT_TENURED) {
443    Callable callable = CodeFactory::FastNewClosure(isolate());
444    ReplaceWithStubCall(node, callable, flags);
445  } else {
446    ReplaceWithRuntimeCall(node, (p.pretenure() == TENURED)
447                                     ? Runtime::kNewClosure_Tenured
448                                     : Runtime::kNewClosure);
449  }
450}
451
452
453void JSGenericLowering::LowerJSCreateFunctionContext(Node* node) {
454  int const slot_count = OpParameter<int>(node->op());
455  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
456
457  if (slot_count <= FastNewFunctionContextStub::kMaximumSlots) {
458    Callable callable = CodeFactory::FastNewFunctionContext(isolate());
459    node->InsertInput(zone(), 1, jsgraph()->Int32Constant(slot_count));
460    ReplaceWithStubCall(node, callable, flags);
461  } else {
462    ReplaceWithRuntimeCall(node, Runtime::kNewFunctionContext);
463  }
464}
465
466
467void JSGenericLowering::LowerJSCreateIterResultObject(Node* node) {
468  ReplaceWithRuntimeCall(node, Runtime::kCreateIterResultObject);
469}
470
471void JSGenericLowering::LowerJSCreateKeyValueArray(Node* node) {
472  ReplaceWithRuntimeCall(node, Runtime::kCreateKeyValueArray);
473}
474
475void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) {
476  CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
477  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
478  node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.index()));
479  node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
480
481  // Use the FastCloneShallowArrayStub only for shallow boilerplates up to the
482  // initial length limit for arrays with "fast" elements kind.
483  if ((p.flags() & ArrayLiteral::kShallowElements) != 0 &&
484      p.length() < JSArray::kInitialMaxFastElementArray) {
485    Callable callable = CodeFactory::FastCloneShallowArray(isolate());
486    ReplaceWithStubCall(node, callable, flags);
487  } else {
488    node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
489    ReplaceWithRuntimeCall(node, Runtime::kCreateArrayLiteral);
490  }
491}
492
493
494void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) {
495  CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
496  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
497  node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.index()));
498  node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
499  node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
500
501  // Use the FastCloneShallowObjectStub only for shallow boilerplates without
502  // elements up to the number of properties that the stubs can handle.
503  if ((p.flags() & ObjectLiteral::kShallowProperties) != 0 &&
504      p.length() <= FastCloneShallowObjectStub::kMaximumClonedProperties) {
505    Callable callable =
506        CodeFactory::FastCloneShallowObject(isolate(), p.length());
507    ReplaceWithStubCall(node, callable, flags);
508  } else {
509    ReplaceWithRuntimeCall(node, Runtime::kCreateObjectLiteral);
510  }
511}
512
513
514void JSGenericLowering::LowerJSCreateLiteralRegExp(Node* node) {
515  CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
516  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
517  Callable callable = CodeFactory::FastCloneRegExp(isolate());
518  Node* literal_index = jsgraph()->SmiConstant(p.index());
519  Node* literal_flags = jsgraph()->SmiConstant(p.flags());
520  Node* pattern = jsgraph()->HeapConstant(p.constant());
521  node->InsertInput(graph()->zone(), 1, literal_index);
522  node->InsertInput(graph()->zone(), 2, pattern);
523  node->InsertInput(graph()->zone(), 3, literal_flags);
524  ReplaceWithStubCall(node, callable, flags);
525}
526
527
528void JSGenericLowering::LowerJSCreateCatchContext(Node* node) {
529  const CreateCatchContextParameters& parameters =
530      CreateCatchContextParametersOf(node->op());
531  node->InsertInput(zone(), 0,
532                    jsgraph()->HeapConstant(parameters.catch_name()));
533  node->InsertInput(zone(), 2,
534                    jsgraph()->HeapConstant(parameters.scope_info()));
535  ReplaceWithRuntimeCall(node, Runtime::kPushCatchContext);
536}
537
538void JSGenericLowering::LowerJSCreateWithContext(Node* node) {
539  Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node);
540  node->InsertInput(zone(), 1, jsgraph()->HeapConstant(scope_info));
541  ReplaceWithRuntimeCall(node, Runtime::kPushWithContext);
542}
543
544void JSGenericLowering::LowerJSCreateBlockContext(Node* node) {
545  Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node);
546  node->InsertInput(zone(), 0, jsgraph()->HeapConstant(scope_info));
547  ReplaceWithRuntimeCall(node, Runtime::kPushBlockContext);
548}
549
550
551void JSGenericLowering::LowerJSCreateScriptContext(Node* node) {
552  Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node);
553  node->InsertInput(zone(), 1, jsgraph()->HeapConstant(scope_info));
554  ReplaceWithRuntimeCall(node, Runtime::kNewScriptContext);
555}
556
557
558void JSGenericLowering::LowerJSCallConstruct(Node* node) {
559  CallConstructParameters const& p = CallConstructParametersOf(node->op());
560  int const arg_count = static_cast<int>(p.arity() - 2);
561  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
562  Callable callable = CodeFactory::Construct(isolate());
563  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
564      isolate(), zone(), callable.descriptor(), arg_count + 1, flags);
565  Node* stub_code = jsgraph()->HeapConstant(callable.code());
566  Node* stub_arity = jsgraph()->Int32Constant(arg_count);
567  Node* new_target = node->InputAt(arg_count + 1);
568  Node* receiver = jsgraph()->UndefinedConstant();
569  node->RemoveInput(arg_count + 1);  // Drop new target.
570  node->InsertInput(zone(), 0, stub_code);
571  node->InsertInput(zone(), 2, new_target);
572  node->InsertInput(zone(), 3, stub_arity);
573  node->InsertInput(zone(), 4, receiver);
574  NodeProperties::ChangeOp(node, common()->Call(desc));
575}
576
577
578void JSGenericLowering::LowerJSCallFunction(Node* node) {
579  CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
580  int const arg_count = static_cast<int>(p.arity() - 2);
581  ConvertReceiverMode const mode = p.convert_mode();
582  Callable callable = CodeFactory::Call(isolate(), mode);
583  CallDescriptor::Flags flags = FrameStateFlagForCall(node);
584  if (p.tail_call_mode() == TailCallMode::kAllow) {
585    flags |= CallDescriptor::kSupportsTailCalls;
586  }
587  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
588      isolate(), zone(), callable.descriptor(), arg_count + 1, flags);
589  Node* stub_code = jsgraph()->HeapConstant(callable.code());
590  Node* stub_arity = jsgraph()->Int32Constant(arg_count);
591  node->InsertInput(zone(), 0, stub_code);
592  node->InsertInput(zone(), 2, stub_arity);
593  NodeProperties::ChangeOp(node, common()->Call(desc));
594}
595
596
597void JSGenericLowering::LowerJSCallRuntime(Node* node) {
598  const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op());
599  ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity()));
600}
601
602void JSGenericLowering::LowerJSConvertReceiver(Node* node) {
603  ReplaceWithRuntimeCall(node, Runtime::kConvertReceiver);
604}
605
606void JSGenericLowering::LowerJSForInNext(Node* node) {
607  ReplaceWithRuntimeCall(node, Runtime::kForInNext);
608}
609
610
611void JSGenericLowering::LowerJSForInPrepare(Node* node) {
612  ReplaceWithRuntimeCall(node, Runtime::kForInPrepare);
613}
614
615void JSGenericLowering::LowerJSLoadMessage(Node* node) {
616  ExternalReference message_address =
617      ExternalReference::address_of_pending_message_obj(isolate());
618  node->RemoveInput(NodeProperties::FirstContextIndex(node));
619  node->InsertInput(zone(), 0, jsgraph()->ExternalConstant(message_address));
620  node->InsertInput(zone(), 1, jsgraph()->IntPtrConstant(0));
621  NodeProperties::ChangeOp(node, machine()->Load(MachineType::AnyTagged()));
622}
623
624
625void JSGenericLowering::LowerJSStoreMessage(Node* node) {
626  ExternalReference message_address =
627      ExternalReference::address_of_pending_message_obj(isolate());
628  node->RemoveInput(NodeProperties::FirstContextIndex(node));
629  node->InsertInput(zone(), 0, jsgraph()->ExternalConstant(message_address));
630  node->InsertInput(zone(), 1, jsgraph()->IntPtrConstant(0));
631  StoreRepresentation representation(MachineRepresentation::kTagged,
632                                     kNoWriteBarrier);
633  NodeProperties::ChangeOp(node, machine()->Store(representation));
634}
635
636void JSGenericLowering::LowerJSLoadModule(Node* node) {
637  UNREACHABLE();  // Eliminated in typed lowering.
638}
639
640void JSGenericLowering::LowerJSStoreModule(Node* node) {
641  UNREACHABLE();  // Eliminated in typed lowering.
642}
643
644void JSGenericLowering::LowerJSGeneratorStore(Node* node) {
645  UNREACHABLE();  // Eliminated in typed lowering.
646}
647
648void JSGenericLowering::LowerJSGeneratorRestoreContinuation(Node* node) {
649  UNREACHABLE();  // Eliminated in typed lowering.
650}
651
652void JSGenericLowering::LowerJSGeneratorRestoreRegister(Node* node) {
653  UNREACHABLE();  // Eliminated in typed lowering.
654}
655
656void JSGenericLowering::LowerJSStackCheck(Node* node) {
657  Node* effect = NodeProperties::GetEffectInput(node);
658  Node* control = NodeProperties::GetControlInput(node);
659
660  Node* limit = graph()->NewNode(
661      machine()->Load(MachineType::Pointer()),
662      jsgraph()->ExternalConstant(
663          ExternalReference::address_of_stack_limit(isolate())),
664      jsgraph()->IntPtrConstant(0), effect, control);
665  Node* pointer = graph()->NewNode(machine()->LoadStackPointer());
666
667  Node* check = graph()->NewNode(machine()->UintLessThan(), limit, pointer);
668  Node* branch =
669      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
670
671  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
672  Node* etrue = effect;
673
674  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
675  NodeProperties::ReplaceControlInput(node, if_false);
676  Node* efalse = node;
677
678  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
679  Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
680
681  // Wire the new diamond into the graph, {node} can still throw.
682  NodeProperties::ReplaceUses(node, node, ephi, node, node);
683  NodeProperties::ReplaceEffectInput(ephi, efalse, 1);
684
685  // TODO(mstarzinger): This iteration cuts out the IfSuccess projection from
686  // the node and places it inside the diamond. Come up with a helper method!
687  for (Node* use : node->uses()) {
688    if (use->opcode() == IrOpcode::kIfSuccess) {
689      use->ReplaceUses(merge);
690      merge->ReplaceInput(1, use);
691    }
692  }
693
694  // Turn the stack check into a runtime call.
695  ReplaceWithRuntimeCall(node, Runtime::kStackGuard);
696}
697
698
699Zone* JSGenericLowering::zone() const { return graph()->zone(); }
700
701
702Isolate* JSGenericLowering::isolate() const { return jsgraph()->isolate(); }
703
704
705Graph* JSGenericLowering::graph() const { return jsgraph()->graph(); }
706
707
708CommonOperatorBuilder* JSGenericLowering::common() const {
709  return jsgraph()->common();
710}
711
712
713MachineOperatorBuilder* JSGenericLowering::machine() const {
714  return jsgraph()->machine();
715}
716
717}  // namespace compiler
718}  // namespace internal
719}  // namespace v8
720