• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 namespace v8 {
18 namespace internal {
19 namespace compiler {
20 
21 namespace {
22 
FrameStateFlagForCall(Node * node)23 CallDescriptor::Flags FrameStateFlagForCall(Node* node) {
24   return OperatorProperties::HasFrameStateInput(node->op())
25              ? CallDescriptor::kNeedsFrameState
26              : CallDescriptor::kNoFlags;
27 }
28 
29 }  // namespace
30 
JSGenericLowering(JSGraph * jsgraph)31 JSGenericLowering::JSGenericLowering(JSGraph* jsgraph) : jsgraph_(jsgraph) {}
32 
~JSGenericLowering()33 JSGenericLowering::~JSGenericLowering() {}
34 
35 
Reduce(Node * node)36 Reduction 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   }
57 REPLACE_STUB_CALL(Add)
REPLACE_STUB_CALL(Subtract)58 REPLACE_STUB_CALL(Subtract)
59 REPLACE_STUB_CALL(Multiply)
60 REPLACE_STUB_CALL(Divide)
61 REPLACE_STUB_CALL(Modulus)
62 REPLACE_STUB_CALL(BitwiseAnd)
63 REPLACE_STUB_CALL(BitwiseOr)
64 REPLACE_STUB_CALL(BitwiseXor)
65 REPLACE_STUB_CALL(ShiftLeft)
66 REPLACE_STUB_CALL(ShiftRight)
67 REPLACE_STUB_CALL(ShiftRightLogical)
68 REPLACE_STUB_CALL(LessThan)
69 REPLACE_STUB_CALL(LessThanOrEqual)
70 REPLACE_STUB_CALL(GreaterThan)
71 REPLACE_STUB_CALL(GreaterThanOrEqual)
72 REPLACE_STUB_CALL(HasProperty)
73 REPLACE_STUB_CALL(Equal)
74 REPLACE_STUB_CALL(NotEqual)
75 REPLACE_STUB_CALL(ToInteger)
76 REPLACE_STUB_CALL(ToLength)
77 REPLACE_STUB_CALL(ToNumber)
78 REPLACE_STUB_CALL(ToName)
79 REPLACE_STUB_CALL(ToObject)
80 REPLACE_STUB_CALL(ToString)
81 #undef REPLACE_STUB_CALL
82 
83 void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
84                                             CallDescriptor::Flags flags) {
85   ReplaceWithStubCall(node, callable, flags, node->op()->properties());
86 }
87 
ReplaceWithStubCall(Node * node,Callable callable,CallDescriptor::Flags flags,Operator::Properties properties)88 void 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 
ReplaceWithRuntimeCall(Node * node,Runtime::FunctionId f,int nargs_override)101 void 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 
LowerJSStrictEqual(Node * node)118 void 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 
LowerJSStrictNotEqual(Node * node)127 void 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 
LowerJSToBoolean(Node * node)136 void 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 
LowerJSTypeOf(Node * node)145 void 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 
LowerJSLoadProperty(Node * node)155 void 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 
LowerJSLoadNamed(Node * node)179 void 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 
LowerJSLoadGlobal(Node * node)204 void 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 
LowerJSStoreProperty(Node * node)229 void 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 
LowerJSStoreNamed(Node * node)264 void 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 
LowerJSStoreGlobal(Node * node)297 void 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 
LowerJSDeleteProperty(Node * node)340 void 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 
LowerJSInstanceOf(Node * node)348 void JSGenericLowering::LowerJSInstanceOf(Node* node) {
349   CallDescriptor::Flags flags = FrameStateFlagForCall(node);
350   Callable callable = CodeFactory::InstanceOf(isolate());
351   ReplaceWithStubCall(node, callable, flags);
352 }
353 
LowerJSOrdinaryHasInstance(Node * node)354 void JSGenericLowering::LowerJSOrdinaryHasInstance(Node* node) {
355   CallDescriptor::Flags flags = FrameStateFlagForCall(node);
356   Callable callable = CodeFactory::OrdinaryHasInstance(isolate());
357   ReplaceWithStubCall(node, callable, flags);
358 }
359 
LowerJSLoadContext(Node * node)360 void 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 
LowerJSStoreContext(Node * node)378 void 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 
LowerJSCreate(Node * node)398 void JSGenericLowering::LowerJSCreate(Node* node) {
399   CallDescriptor::Flags flags = FrameStateFlagForCall(node);
400   Callable callable = CodeFactory::FastNewObject(isolate());
401   ReplaceWithStubCall(node, callable, flags);
402 }
403 
404 
LowerJSCreateArguments(Node * node)405 void 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 
LowerJSCreateArray(Node * node)421 void 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 
LowerJSCreateClosure(Node * node)435 void 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 
LowerJSCreateFunctionContext(Node * node)453 void 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 
LowerJSCreateIterResultObject(Node * node)467 void JSGenericLowering::LowerJSCreateIterResultObject(Node* node) {
468   ReplaceWithRuntimeCall(node, Runtime::kCreateIterResultObject);
469 }
470 
LowerJSCreateKeyValueArray(Node * node)471 void JSGenericLowering::LowerJSCreateKeyValueArray(Node* node) {
472   ReplaceWithRuntimeCall(node, Runtime::kCreateKeyValueArray);
473 }
474 
LowerJSCreateLiteralArray(Node * node)475 void 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 
LowerJSCreateLiteralObject(Node * node)494 void 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 
LowerJSCreateLiteralRegExp(Node * node)514 void 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 
LowerJSCreateCatchContext(Node * node)528 void 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 
LowerJSCreateWithContext(Node * node)538 void 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 
LowerJSCreateBlockContext(Node * node)544 void 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 
LowerJSCreateScriptContext(Node * node)551 void 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 
LowerJSCallConstruct(Node * node)558 void 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 
LowerJSCallFunction(Node * node)578 void 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 
LowerJSCallRuntime(Node * node)597 void JSGenericLowering::LowerJSCallRuntime(Node* node) {
598   const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op());
599   ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity()));
600 }
601 
LowerJSConvertReceiver(Node * node)602 void JSGenericLowering::LowerJSConvertReceiver(Node* node) {
603   ReplaceWithRuntimeCall(node, Runtime::kConvertReceiver);
604 }
605 
LowerJSForInNext(Node * node)606 void JSGenericLowering::LowerJSForInNext(Node* node) {
607   ReplaceWithRuntimeCall(node, Runtime::kForInNext);
608 }
609 
610 
LowerJSForInPrepare(Node * node)611 void JSGenericLowering::LowerJSForInPrepare(Node* node) {
612   ReplaceWithRuntimeCall(node, Runtime::kForInPrepare);
613 }
614 
LowerJSLoadMessage(Node * node)615 void 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 
LowerJSStoreMessage(Node * node)625 void 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 
LowerJSLoadModule(Node * node)636 void JSGenericLowering::LowerJSLoadModule(Node* node) {
637   UNREACHABLE();  // Eliminated in typed lowering.
638 }
639 
LowerJSStoreModule(Node * node)640 void JSGenericLowering::LowerJSStoreModule(Node* node) {
641   UNREACHABLE();  // Eliminated in typed lowering.
642 }
643 
LowerJSGeneratorStore(Node * node)644 void JSGenericLowering::LowerJSGeneratorStore(Node* node) {
645   UNREACHABLE();  // Eliminated in typed lowering.
646 }
647 
LowerJSGeneratorRestoreContinuation(Node * node)648 void JSGenericLowering::LowerJSGeneratorRestoreContinuation(Node* node) {
649   UNREACHABLE();  // Eliminated in typed lowering.
650 }
651 
LowerJSGeneratorRestoreRegister(Node * node)652 void JSGenericLowering::LowerJSGeneratorRestoreRegister(Node* node) {
653   UNREACHABLE();  // Eliminated in typed lowering.
654 }
655 
LowerJSStackCheck(Node * node)656 void 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 
zone() const699 Zone* JSGenericLowering::zone() const { return graph()->zone(); }
700 
701 
isolate() const702 Isolate* JSGenericLowering::isolate() const { return jsgraph()->isolate(); }
703 
704 
graph() const705 Graph* JSGenericLowering::graph() const { return jsgraph()->graph(); }
706 
707 
common() const708 CommonOperatorBuilder* JSGenericLowering::common() const {
709   return jsgraph()->common();
710 }
711 
712 
machine() const713 MachineOperatorBuilder* JSGenericLowering::machine() const {
714   return jsgraph()->machine();
715 }
716 
717 }  // namespace compiler
718 }  // namespace internal
719 }  // namespace v8
720