• 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/builtins/builtins-constructor.h"
9 #include "src/codegen/code-factory.h"
10 #include "src/codegen/interface-descriptors-inl.h"
11 #include "src/compiler/access-builder.h"
12 #include "src/compiler/common-operator.h"
13 #include "src/compiler/js-graph.h"
14 #include "src/compiler/js-heap-broker.h"
15 #include "src/compiler/machine-operator.h"
16 #include "src/compiler/node-matchers.h"
17 #include "src/compiler/node-properties.h"
18 #include "src/compiler/operator-properties.h"
19 #include "src/compiler/processed-feedback.h"
20 #include "src/compiler/simplified-operator.h"
21 #include "src/objects/feedback-cell.h"
22 #include "src/objects/feedback-vector.h"
23 #include "src/objects/scope-info.h"
24 #include "src/objects/template-objects-inl.h"
25 
26 namespace v8 {
27 namespace internal {
28 namespace compiler {
29 
30 namespace {
31 
FrameStateFlagForCall(Node * node)32 CallDescriptor::Flags FrameStateFlagForCall(Node* node) {
33   return OperatorProperties::HasFrameStateInput(node->op())
34              ? CallDescriptor::kNeedsFrameState
35              : CallDescriptor::kNoFlags;
36 }
37 
38 }  // namespace
39 
JSGenericLowering(JSGraph * jsgraph,Editor * editor,JSHeapBroker * broker)40 JSGenericLowering::JSGenericLowering(JSGraph* jsgraph, Editor* editor,
41                                      JSHeapBroker* broker)
42     : AdvancedReducer(editor), jsgraph_(jsgraph), broker_(broker) {}
43 
44 JSGenericLowering::~JSGenericLowering() = default;
45 
46 
Reduce(Node * node)47 Reduction JSGenericLowering::Reduce(Node* node) {
48   switch (node->opcode()) {
49 #define DECLARE_CASE(x, ...) \
50   case IrOpcode::k##x:       \
51     Lower##x(node);          \
52     break;
53     JS_OP_LIST(DECLARE_CASE)
54 #undef DECLARE_CASE
55     default:
56       // Nothing to see.
57       return NoChange();
58   }
59   return Changed(node);
60 }
61 
62 #define REPLACE_STUB_CALL(Name)                       \
63   void JSGenericLowering::LowerJS##Name(Node* node) { \
64     ReplaceWithBuiltinCall(node, Builtin::k##Name);   \
65   }
66 REPLACE_STUB_CALL(ToLength)
REPLACE_STUB_CALL(ToNumber)67 REPLACE_STUB_CALL(ToNumber)
68 REPLACE_STUB_CALL(ToNumberConvertBigInt)
69 REPLACE_STUB_CALL(ToNumeric)
70 REPLACE_STUB_CALL(ToName)
71 REPLACE_STUB_CALL(ToObject)
72 REPLACE_STUB_CALL(ToString)
73 REPLACE_STUB_CALL(ForInEnumerate)
74 REPLACE_STUB_CALL(AsyncFunctionEnter)
75 REPLACE_STUB_CALL(AsyncFunctionReject)
76 REPLACE_STUB_CALL(AsyncFunctionResolve)
77 REPLACE_STUB_CALL(FulfillPromise)
78 REPLACE_STUB_CALL(PerformPromiseThen)
79 REPLACE_STUB_CALL(PromiseResolve)
80 REPLACE_STUB_CALL(RejectPromise)
81 REPLACE_STUB_CALL(ResolvePromise)
82 #undef REPLACE_STUB_CALL
83 
84 void JSGenericLowering::ReplaceWithBuiltinCall(Node* node, Builtin builtin) {
85   CallDescriptor::Flags flags = FrameStateFlagForCall(node);
86   Callable callable = Builtins::CallableFor(isolate(), builtin);
87   ReplaceWithBuiltinCall(node, callable, flags);
88 }
89 
ReplaceWithBuiltinCall(Node * node,Callable callable,CallDescriptor::Flags flags)90 void JSGenericLowering::ReplaceWithBuiltinCall(Node* node, Callable callable,
91                                                CallDescriptor::Flags flags) {
92   ReplaceWithBuiltinCall(node, callable, flags, node->op()->properties());
93 }
94 
ReplaceWithBuiltinCall(Node * node,Callable callable,CallDescriptor::Flags flags,Operator::Properties properties)95 void JSGenericLowering::ReplaceWithBuiltinCall(
96     Node* node, Callable callable, CallDescriptor::Flags flags,
97     Operator::Properties properties) {
98   const CallInterfaceDescriptor& descriptor = callable.descriptor();
99   auto call_descriptor = Linkage::GetStubCallDescriptor(
100       zone(), descriptor, descriptor.GetStackParameterCount(), flags,
101       properties);
102   Node* stub_code = jsgraph()->HeapConstant(callable.code());
103   node->InsertInput(zone(), 0, stub_code);
104   NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
105 }
106 
ReplaceWithRuntimeCall(Node * node,Runtime::FunctionId f,int nargs_override)107 void JSGenericLowering::ReplaceWithRuntimeCall(Node* node,
108                                                Runtime::FunctionId f,
109                                                int nargs_override) {
110   CallDescriptor::Flags flags = FrameStateFlagForCall(node);
111   Operator::Properties properties = node->op()->properties();
112   const Runtime::Function* fun = Runtime::FunctionForId(f);
113   int nargs = (nargs_override < 0) ? fun->nargs : nargs_override;
114   auto call_descriptor =
115       Linkage::GetRuntimeCallDescriptor(zone(), f, nargs, properties, flags);
116   Node* ref = jsgraph()->ExternalConstant(ExternalReference::Create(f));
117   Node* arity = jsgraph()->Int32Constant(nargs);
118   node->InsertInput(zone(), 0, jsgraph()->CEntryStubConstant(fun->result_size));
119   node->InsertInput(zone(), nargs + 1, ref);
120   node->InsertInput(zone(), nargs + 2, arity);
121   NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
122 }
123 
ReplaceUnaryOpWithBuiltinCall(Node * node,Builtin builtin_without_feedback,Builtin builtin_with_feedback)124 void JSGenericLowering::ReplaceUnaryOpWithBuiltinCall(
125     Node* node, Builtin builtin_without_feedback,
126     Builtin builtin_with_feedback) {
127   DCHECK(JSOperator::IsUnaryWithFeedback(node->opcode()));
128   const FeedbackParameter& p = FeedbackParameterOf(node->op());
129   if (CollectFeedbackInGenericLowering() && p.feedback().IsValid()) {
130     Callable callable = Builtins::CallableFor(isolate(), builtin_with_feedback);
131     Node* slot = jsgraph()->UintPtrConstant(p.feedback().slot.ToInt());
132     const CallInterfaceDescriptor& descriptor = callable.descriptor();
133     CallDescriptor::Flags flags = FrameStateFlagForCall(node);
134     auto call_descriptor = Linkage::GetStubCallDescriptor(
135         zone(), descriptor, descriptor.GetStackParameterCount(), flags,
136         node->op()->properties());
137     Node* stub_code = jsgraph()->HeapConstant(callable.code());
138     STATIC_ASSERT(JSUnaryOpNode::ValueIndex() == 0);
139     STATIC_ASSERT(JSUnaryOpNode::FeedbackVectorIndex() == 1);
140     DCHECK_EQ(node->op()->ValueInputCount(), 2);
141     node->InsertInput(zone(), 0, stub_code);
142     node->InsertInput(zone(), 2, slot);
143     NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
144   } else {
145     node->RemoveInput(JSUnaryOpNode::FeedbackVectorIndex());
146     ReplaceWithBuiltinCall(node, builtin_without_feedback);
147   }
148 }
149 
150 #define DEF_UNARY_LOWERING(Name)                                    \
151   void JSGenericLowering::LowerJS##Name(Node* node) {               \
152     ReplaceUnaryOpWithBuiltinCall(node, Builtin::k##Name,           \
153                                   Builtin::k##Name##_WithFeedback); \
154   }
155 DEF_UNARY_LOWERING(BitwiseNot)
DEF_UNARY_LOWERING(Decrement)156 DEF_UNARY_LOWERING(Decrement)
157 DEF_UNARY_LOWERING(Increment)
158 DEF_UNARY_LOWERING(Negate)
159 #undef DEF_UNARY_LOWERING
160 
161 void JSGenericLowering::ReplaceBinaryOpWithBuiltinCall(
162     Node* node, Builtin builtin_without_feedback,
163     Builtin builtin_with_feedback) {
164   DCHECK(JSOperator::IsBinaryWithFeedback(node->opcode()));
165   Builtin builtin;
166   const FeedbackParameter& p = FeedbackParameterOf(node->op());
167   if (CollectFeedbackInGenericLowering() && p.feedback().IsValid()) {
168     Node* slot = jsgraph()->UintPtrConstant(p.feedback().slot.ToInt());
169     STATIC_ASSERT(JSBinaryOpNode::LeftIndex() == 0);
170     STATIC_ASSERT(JSBinaryOpNode::RightIndex() == 1);
171     STATIC_ASSERT(JSBinaryOpNode::FeedbackVectorIndex() == 2);
172     DCHECK_EQ(node->op()->ValueInputCount(), 3);
173     node->InsertInput(zone(), 2, slot);
174     builtin = builtin_with_feedback;
175   } else {
176     node->RemoveInput(JSBinaryOpNode::FeedbackVectorIndex());
177     builtin = builtin_without_feedback;
178   }
179 
180   ReplaceWithBuiltinCall(node, builtin);
181 }
182 
183 #define DEF_BINARY_LOWERING(Name)                                    \
184   void JSGenericLowering::LowerJS##Name(Node* node) {                \
185     ReplaceBinaryOpWithBuiltinCall(node, Builtin::k##Name,           \
186                                    Builtin::k##Name##_WithFeedback); \
187   }
188 // Binary ops.
189 DEF_BINARY_LOWERING(Add)
DEF_BINARY_LOWERING(BitwiseAnd)190 DEF_BINARY_LOWERING(BitwiseAnd)
191 DEF_BINARY_LOWERING(BitwiseOr)
192 DEF_BINARY_LOWERING(BitwiseXor)
193 DEF_BINARY_LOWERING(Divide)
194 DEF_BINARY_LOWERING(Exponentiate)
195 DEF_BINARY_LOWERING(Modulus)
196 DEF_BINARY_LOWERING(Multiply)
197 DEF_BINARY_LOWERING(ShiftLeft)
198 DEF_BINARY_LOWERING(ShiftRight)
199 DEF_BINARY_LOWERING(ShiftRightLogical)
200 DEF_BINARY_LOWERING(Subtract)
201 // Compare ops.
202 DEF_BINARY_LOWERING(Equal)
203 DEF_BINARY_LOWERING(GreaterThan)
204 DEF_BINARY_LOWERING(GreaterThanOrEqual)
205 DEF_BINARY_LOWERING(InstanceOf)
206 DEF_BINARY_LOWERING(LessThan)
207 DEF_BINARY_LOWERING(LessThanOrEqual)
208 #undef DEF_BINARY_LOWERING
209 
210 void JSGenericLowering::LowerJSStrictEqual(Node* node) {
211   // The === operator doesn't need the current context.
212   NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
213   DCHECK_EQ(node->op()->ControlInputCount(), 1);
214   node->RemoveInput(NodeProperties::FirstControlIndex(node));
215 
216   Builtin builtin;
217   const FeedbackParameter& p = FeedbackParameterOf(node->op());
218   if (CollectFeedbackInGenericLowering() && p.feedback().IsValid()) {
219     Node* slot = jsgraph()->UintPtrConstant(p.feedback().slot.ToInt());
220     STATIC_ASSERT(JSStrictEqualNode::LeftIndex() == 0);
221     STATIC_ASSERT(JSStrictEqualNode::RightIndex() == 1);
222     STATIC_ASSERT(JSStrictEqualNode::FeedbackVectorIndex() == 2);
223     DCHECK_EQ(node->op()->ValueInputCount(), 3);
224     node->InsertInput(zone(), 2, slot);
225     builtin = Builtin::kStrictEqual_WithFeedback;
226   } else {
227     node->RemoveInput(JSStrictEqualNode::FeedbackVectorIndex());
228     builtin = Builtin::kStrictEqual;
229   }
230 
231   Callable callable = Builtins::CallableFor(isolate(), builtin);
232   ReplaceWithBuiltinCall(node, callable, CallDescriptor::kNoFlags,
233                          Operator::kEliminatable);
234 }
235 
236 namespace {
237 
238 // The megamorphic load builtin can be used as a performance optimization in
239 // some cases - unlike the full builtin, the megamorphic builtin does fewer
240 // checks and does not collect feedback.
ShouldUseMegamorphicLoadBuiltin(FeedbackSource const & source,base::Optional<NameRef> name,JSHeapBroker * broker)241 bool ShouldUseMegamorphicLoadBuiltin(FeedbackSource const& source,
242                                      base::Optional<NameRef> name,
243                                      JSHeapBroker* broker) {
244   ProcessedFeedback const& feedback =
245       broker->GetFeedbackForPropertyAccess(source, AccessMode::kLoad, name);
246 
247   if (feedback.kind() == ProcessedFeedback::kElementAccess) {
248     return feedback.AsElementAccess().transition_groups().empty();
249   } else if (feedback.kind() == ProcessedFeedback::kNamedAccess) {
250     return feedback.AsNamedAccess().maps().empty();
251   } else if (feedback.kind() == ProcessedFeedback::kInsufficient) {
252     return false;
253   }
254   UNREACHABLE();
255 }
256 
257 }  // namespace
258 
LowerJSHasProperty(Node * node)259 void JSGenericLowering::LowerJSHasProperty(Node* node) {
260   JSHasPropertyNode n(node);
261   const PropertyAccess& p = n.Parameters();
262   if (!p.feedback().IsValid()) {
263     node->RemoveInput(JSHasPropertyNode::FeedbackVectorIndex());
264     ReplaceWithBuiltinCall(node, Builtin::kHasProperty);
265   } else {
266     STATIC_ASSERT(n.FeedbackVectorIndex() == 2);
267     n->InsertInput(zone(), 2,
268                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
269     ReplaceWithBuiltinCall(node, Builtin::kKeyedHasIC);
270   }
271 }
272 
LowerJSLoadProperty(Node * node)273 void JSGenericLowering::LowerJSLoadProperty(Node* node) {
274   JSLoadPropertyNode n(node);
275   const PropertyAccess& p = n.Parameters();
276   FrameState frame_state = n.frame_state();
277   Node* outer_state = frame_state.outer_frame_state();
278   STATIC_ASSERT(n.FeedbackVectorIndex() == 2);
279   if (outer_state->opcode() != IrOpcode::kFrameState) {
280     n->RemoveInput(n.FeedbackVectorIndex());
281     n->InsertInput(zone(), 2,
282                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
283     ReplaceWithBuiltinCall(
284         node, ShouldUseMegamorphicLoadBuiltin(p.feedback(), {}, broker())
285                   ? Builtin::kKeyedLoadICTrampoline_Megamorphic
286                   : Builtin::kKeyedLoadICTrampoline);
287   } else {
288     n->InsertInput(zone(), 2,
289                    jsgraph()->TaggedIndexConstant(p.feedback().index()));
290     ReplaceWithBuiltinCall(
291         node, ShouldUseMegamorphicLoadBuiltin(p.feedback(), {}, broker())
292                   ? Builtin::kKeyedLoadIC_Megamorphic
293                   : Builtin::kKeyedLoadIC);
294   }
295 }
296 
LowerJSLoadNamed(Node * node)297 void JSGenericLowering::LowerJSLoadNamed(Node* node) {
298   JSLoadNamedNode n(node);
299   NamedAccess const& p = n.Parameters();
300   FrameState frame_state = n.frame_state();
301   Node* outer_state = frame_state.outer_frame_state();
302   STATIC_ASSERT(n.FeedbackVectorIndex() == 1);
303   if (!p.feedback().IsValid()) {
304     n->RemoveInput(n.FeedbackVectorIndex());
305     node->InsertInput(zone(), 1, jsgraph()->Constant(p.name(broker())));
306     ReplaceWithBuiltinCall(node, Builtin::kGetProperty);
307   } else if (outer_state->opcode() != IrOpcode::kFrameState) {
308     n->RemoveInput(n.FeedbackVectorIndex());
309     node->InsertInput(zone(), 1, jsgraph()->Constant(p.name(broker())));
310     node->InsertInput(zone(), 2,
311                       jsgraph()->TaggedIndexConstant(p.feedback().index()));
312     ReplaceWithBuiltinCall(node, ShouldUseMegamorphicLoadBuiltin(
313                                      p.feedback(), p.name(broker()), broker())
314                                      ? Builtin::kLoadICTrampoline_Megamorphic
315                                      : Builtin::kLoadICTrampoline);
316   } else {
317     node->InsertInput(zone(), 1, jsgraph()->Constant(p.name(broker())));
318     node->InsertInput(zone(), 2,
319                       jsgraph()->TaggedIndexConstant(p.feedback().index()));
320     ReplaceWithBuiltinCall(node, ShouldUseMegamorphicLoadBuiltin(
321                                      p.feedback(), p.name(broker()), broker())
322                                      ? Builtin::kLoadIC_Megamorphic
323                                      : Builtin::kLoadIC);
324   }
325 }
326 
LowerJSLoadNamedFromSuper(Node * node)327 void JSGenericLowering::LowerJSLoadNamedFromSuper(Node* node) {
328   JSLoadNamedFromSuperNode n(node);
329   NamedAccess const& p = n.Parameters();
330   Node* effect = NodeProperties::GetEffectInput(node);
331   Node* control = NodeProperties::GetControlInput(node);
332   // Node inputs: receiver, home object, FeedbackVector.
333   // LoadSuperIC expects: receiver, lookup start object, name, slot,
334   // FeedbackVector.
335   Node* home_object_map = effect = graph()->NewNode(
336       jsgraph()->simplified()->LoadField(AccessBuilder::ForMap()),
337       n.home_object(), effect, control);
338   Node* home_object_proto = effect = graph()->NewNode(
339       jsgraph()->simplified()->LoadField(AccessBuilder::ForMapPrototype()),
340       home_object_map, effect, control);
341   n->ReplaceInput(n.HomeObjectIndex(), home_object_proto);
342   NodeProperties::ReplaceEffectInput(node, effect);
343   STATIC_ASSERT(n.FeedbackVectorIndex() == 2);
344   // If the code below will be used for the invalid feedback case, it needs to
345   // be double-checked that the FeedbackVector parameter will be the
346   // UndefinedConstant.
347   DCHECK(p.feedback().IsValid());
348   node->InsertInput(zone(), 2, jsgraph()->Constant(p.name(broker())));
349   node->InsertInput(zone(), 3,
350                     jsgraph()->TaggedIndexConstant(p.feedback().index()));
351   ReplaceWithBuiltinCall(node, Builtin::kLoadSuperIC);
352 }
353 
LowerJSLoadGlobal(Node * node)354 void JSGenericLowering::LowerJSLoadGlobal(Node* node) {
355   JSLoadGlobalNode n(node);
356   const LoadGlobalParameters& p = n.Parameters();
357   CallDescriptor::Flags flags = FrameStateFlagForCall(node);
358   FrameState frame_state = n.frame_state();
359   Node* outer_state = frame_state.outer_frame_state();
360   STATIC_ASSERT(n.FeedbackVectorIndex() == 0);
361   if (outer_state->opcode() != IrOpcode::kFrameState) {
362     n->RemoveInput(n.FeedbackVectorIndex());
363     node->InsertInput(zone(), 0, jsgraph()->Constant(p.name(broker())));
364     node->InsertInput(zone(), 1,
365                       jsgraph()->TaggedIndexConstant(p.feedback().index()));
366     Callable callable = CodeFactory::LoadGlobalIC(isolate(), p.typeof_mode());
367     ReplaceWithBuiltinCall(node, callable, flags);
368   } else {
369     node->InsertInput(zone(), 0, jsgraph()->Constant(p.name(broker())));
370     node->InsertInput(zone(), 1,
371                       jsgraph()->TaggedIndexConstant(p.feedback().index()));
372     Callable callable =
373         CodeFactory::LoadGlobalICInOptimizedCode(isolate(), p.typeof_mode());
374     ReplaceWithBuiltinCall(node, callable, flags);
375   }
376 }
377 
LowerJSGetIterator(Node * node)378 void JSGenericLowering::LowerJSGetIterator(Node* node) {
379   // TODO(v8:9625): Currently, the GetIterator operator is desugared in the
380   // native context specialization phase. Thus, the following generic lowering
381   // is not reachable unless that phase is disabled (e.g. for
382   // native-context-independent code).
383   // We can add a check in native context specialization to avoid desugaring
384   // the GetIterator operator when feedback is megamorphic. This would reduce
385   // the size of the compiled code as it would insert 1 call to the builtin
386   // instead of 2 calls resulting from the generic lowering of the LoadNamed
387   // and Call operators.
388 
389   JSGetIteratorNode n(node);
390   GetIteratorParameters const& p = n.Parameters();
391   Node* load_slot =
392       jsgraph()->TaggedIndexConstant(p.loadFeedback().slot.ToInt());
393   Node* call_slot =
394       jsgraph()->TaggedIndexConstant(p.callFeedback().slot.ToInt());
395   STATIC_ASSERT(n.FeedbackVectorIndex() == 1);
396   node->InsertInput(zone(), 1, load_slot);
397   node->InsertInput(zone(), 2, call_slot);
398 
399   ReplaceWithBuiltinCall(node, Builtin::kGetIteratorWithFeedback);
400 }
401 
LowerJSSetKeyedProperty(Node * node)402 void JSGenericLowering::LowerJSSetKeyedProperty(Node* node) {
403   JSSetKeyedPropertyNode n(node);
404   const PropertyAccess& p = n.Parameters();
405   FrameState frame_state = n.frame_state();
406   Node* outer_state = frame_state.outer_frame_state();
407   STATIC_ASSERT(n.FeedbackVectorIndex() == 3);
408   if (outer_state->opcode() != IrOpcode::kFrameState) {
409     n->RemoveInput(n.FeedbackVectorIndex());
410     node->InsertInput(zone(), 3,
411                       jsgraph()->TaggedIndexConstant(p.feedback().index()));
412 
413     // KeyedStoreIC is currently a base class for multiple keyed property store
414     // operations and contains mixed logic for set and define operations,
415     // the paths are controlled by feedback.
416     // TODO(v8:12548): refactor SetKeyedIC as a subclass of KeyedStoreIC, which
417     // can be called here.
418     ReplaceWithBuiltinCall(node, Builtin::kKeyedStoreICTrampoline);
419   } else {
420     node->InsertInput(zone(), 3,
421                       jsgraph()->TaggedIndexConstant(p.feedback().index()));
422     ReplaceWithBuiltinCall(node, Builtin::kKeyedStoreIC);
423   }
424 }
425 
LowerJSDefineKeyedOwnProperty(Node * node)426 void JSGenericLowering::LowerJSDefineKeyedOwnProperty(Node* node) {
427   JSDefineKeyedOwnPropertyNode n(node);
428   const PropertyAccess& p = n.Parameters();
429   FrameState frame_state = n.frame_state();
430   Node* outer_state = frame_state.outer_frame_state();
431   STATIC_ASSERT(n.FeedbackVectorIndex() == 3);
432   if (outer_state->opcode() != IrOpcode::kFrameState) {
433     n->RemoveInput(n.FeedbackVectorIndex());
434     node->InsertInput(zone(), 3,
435                       jsgraph()->TaggedIndexConstant(p.feedback().index()));
436     ReplaceWithBuiltinCall(node, Builtin::kDefineKeyedOwnICTrampoline);
437   } else {
438     node->InsertInput(zone(), 3,
439                       jsgraph()->TaggedIndexConstant(p.feedback().index()));
440     ReplaceWithBuiltinCall(node, Builtin::kDefineKeyedOwnIC);
441   }
442 }
443 
LowerJSSetNamedProperty(Node * node)444 void JSGenericLowering::LowerJSSetNamedProperty(Node* node) {
445   JSSetNamedPropertyNode n(node);
446   NamedAccess const& p = n.Parameters();
447   FrameState frame_state = n.frame_state();
448   Node* outer_state = frame_state.outer_frame_state();
449   STATIC_ASSERT(n.FeedbackVectorIndex() == 2);
450   if (!p.feedback().IsValid()) {
451     n->RemoveInput(n.FeedbackVectorIndex());
452     node->InsertInput(zone(), 1, jsgraph()->Constant(p.name(broker())));
453     ReplaceWithRuntimeCall(node, Runtime::kSetNamedProperty);
454   } else if (outer_state->opcode() != IrOpcode::kFrameState) {
455     n->RemoveInput(n.FeedbackVectorIndex());
456     node->InsertInput(zone(), 1, jsgraph()->Constant(p.name(broker())));
457     node->InsertInput(zone(), 3,
458                       jsgraph()->TaggedIndexConstant(p.feedback().index()));
459     // StoreIC is currently a base class for multiple property store operations
460     // and contains mixed logic for named and keyed, set and define operations,
461     // the paths are controlled by feedback.
462     // TODO(v8:12548): refactor SetNamedIC as a subclass of StoreIC, which can
463     // be called here.
464     ReplaceWithBuiltinCall(node, Builtin::kStoreICTrampoline);
465   } else {
466     node->InsertInput(zone(), 1, jsgraph()->Constant(p.name(broker())));
467     node->InsertInput(zone(), 3,
468                       jsgraph()->TaggedIndexConstant(p.feedback().index()));
469     ReplaceWithBuiltinCall(node, Builtin::kStoreIC);
470   }
471 }
472 
LowerJSDefineNamedOwnProperty(Node * node)473 void JSGenericLowering::LowerJSDefineNamedOwnProperty(Node* node) {
474   CallDescriptor::Flags flags = FrameStateFlagForCall(node);
475   JSDefineNamedOwnPropertyNode n(node);
476   DefineNamedOwnPropertyParameters const& p = n.Parameters();
477   FrameState frame_state = n.frame_state();
478   Node* outer_state = frame_state.outer_frame_state();
479   STATIC_ASSERT(n.FeedbackVectorIndex() == 2);
480   if (outer_state->opcode() != IrOpcode::kFrameState) {
481     n->RemoveInput(n.FeedbackVectorIndex());
482     node->InsertInput(zone(), 1, jsgraph()->Constant(p.name(broker())));
483     node->InsertInput(zone(), 3,
484                       jsgraph()->TaggedIndexConstant(p.feedback().index()));
485     Callable callable = CodeFactory::DefineNamedOwnIC(isolate());
486     ReplaceWithBuiltinCall(node, callable, flags);
487   } else {
488     node->InsertInput(zone(), 1, jsgraph()->Constant(p.name(broker())));
489     node->InsertInput(zone(), 3,
490                       jsgraph()->TaggedIndexConstant(p.feedback().index()));
491     Callable callable = CodeFactory::DefineNamedOwnICInOptimizedCode(isolate());
492     ReplaceWithBuiltinCall(node, callable, flags);
493   }
494 }
495 
LowerJSStoreGlobal(Node * node)496 void JSGenericLowering::LowerJSStoreGlobal(Node* node) {
497   JSStoreGlobalNode n(node);
498   const StoreGlobalParameters& p = n.Parameters();
499   FrameState frame_state = n.frame_state();
500   Node* outer_state = frame_state.outer_frame_state();
501   STATIC_ASSERT(n.FeedbackVectorIndex() == 1);
502   if (outer_state->opcode() != IrOpcode::kFrameState) {
503     n->RemoveInput(n.FeedbackVectorIndex());
504     node->InsertInput(zone(), 0, jsgraph()->Constant(p.name(broker())));
505     node->InsertInput(zone(), 2,
506                       jsgraph()->TaggedIndexConstant(p.feedback().index()));
507     ReplaceWithBuiltinCall(node, Builtin::kStoreGlobalICTrampoline);
508   } else {
509     node->InsertInput(zone(), 0, jsgraph()->Constant(p.name(broker())));
510     node->InsertInput(zone(), 2,
511                       jsgraph()->TaggedIndexConstant(p.feedback().index()));
512     ReplaceWithBuiltinCall(node, Builtin::kStoreGlobalIC);
513   }
514 }
515 
LowerJSDefineKeyedOwnPropertyInLiteral(Node * node)516 void JSGenericLowering::LowerJSDefineKeyedOwnPropertyInLiteral(Node* node) {
517   JSDefineKeyedOwnPropertyInLiteralNode n(node);
518   FeedbackParameter const& p = n.Parameters();
519   STATIC_ASSERT(n.FeedbackVectorIndex() == 4);
520   RelaxControls(node);
521   node->InsertInput(zone(), 5,
522                     jsgraph()->TaggedIndexConstant(p.feedback().index()));
523   ReplaceWithRuntimeCall(node, Runtime::kDefineKeyedOwnPropertyInLiteral);
524 }
525 
LowerJSStoreInArrayLiteral(Node * node)526 void JSGenericLowering::LowerJSStoreInArrayLiteral(Node* node) {
527   JSStoreInArrayLiteralNode n(node);
528   FeedbackParameter const& p = n.Parameters();
529   STATIC_ASSERT(n.FeedbackVectorIndex() == 3);
530   RelaxControls(node);
531   node->InsertInput(zone(), 3,
532                     jsgraph()->TaggedIndexConstant(p.feedback().index()));
533   ReplaceWithBuiltinCall(node, Builtin::kStoreInArrayLiteralIC);
534 }
535 
LowerJSDeleteProperty(Node * node)536 void JSGenericLowering::LowerJSDeleteProperty(Node* node) {
537   ReplaceWithBuiltinCall(node, Builtin::kDeleteProperty);
538 }
539 
LowerJSGetSuperConstructor(Node * node)540 void JSGenericLowering::LowerJSGetSuperConstructor(Node* node) {
541   Node* active_function = NodeProperties::GetValueInput(node, 0);
542   Node* effect = NodeProperties::GetEffectInput(node);
543   Node* control = NodeProperties::GetControlInput(node);
544 
545   Node* function_map = effect = graph()->NewNode(
546       jsgraph()->simplified()->LoadField(AccessBuilder::ForMap()),
547       active_function, effect, control);
548 
549   RelaxControls(node);
550   node->ReplaceInput(0, function_map);
551   node->ReplaceInput(1, effect);
552   node->ReplaceInput(2, control);
553   node->TrimInputCount(3);
554   NodeProperties::ChangeOp(node, jsgraph()->simplified()->LoadField(
555                                      AccessBuilder::ForMapPrototype()));
556 }
557 
LowerJSHasInPrototypeChain(Node * node)558 void JSGenericLowering::LowerJSHasInPrototypeChain(Node* node) {
559   ReplaceWithRuntimeCall(node, Runtime::kHasInPrototypeChain);
560 }
561 
LowerJSOrdinaryHasInstance(Node * node)562 void JSGenericLowering::LowerJSOrdinaryHasInstance(Node* node) {
563   ReplaceWithBuiltinCall(node, Builtin::kOrdinaryHasInstance);
564 }
565 
LowerJSHasContextExtension(Node * node)566 void JSGenericLowering::LowerJSHasContextExtension(Node* node) {
567   UNREACHABLE();  // Eliminated in typed lowering.
568 }
569 
LowerJSLoadContext(Node * node)570 void JSGenericLowering::LowerJSLoadContext(Node* node) {
571   UNREACHABLE();  // Eliminated in typed lowering.
572 }
573 
574 
LowerJSStoreContext(Node * node)575 void JSGenericLowering::LowerJSStoreContext(Node* node) {
576   UNREACHABLE();  // Eliminated in typed lowering.
577 }
578 
579 
LowerJSCreate(Node * node)580 void JSGenericLowering::LowerJSCreate(Node* node) {
581   ReplaceWithBuiltinCall(node, Builtin::kFastNewObject);
582 }
583 
584 
LowerJSCreateArguments(Node * node)585 void JSGenericLowering::LowerJSCreateArguments(Node* node) {
586   CreateArgumentsType const type = CreateArgumentsTypeOf(node->op());
587   switch (type) {
588     case CreateArgumentsType::kMappedArguments:
589       ReplaceWithRuntimeCall(node, Runtime::kNewSloppyArguments);
590       break;
591     case CreateArgumentsType::kUnmappedArguments:
592       ReplaceWithRuntimeCall(node, Runtime::kNewStrictArguments);
593       break;
594     case CreateArgumentsType::kRestParameter:
595       ReplaceWithRuntimeCall(node, Runtime::kNewRestParameter);
596       break;
597   }
598 }
599 
600 
LowerJSCreateArray(Node * node)601 void JSGenericLowering::LowerJSCreateArray(Node* node) {
602   CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
603   int const arity = static_cast<int>(p.arity());
604   auto interface_descriptor = ArrayConstructorDescriptor{};
605   auto call_descriptor = Linkage::GetStubCallDescriptor(
606       zone(), interface_descriptor, arity + 1, CallDescriptor::kNeedsFrameState,
607       node->op()->properties());
608   // If this fails, we might need to update the parameter reordering code
609   // to ensure that the additional arguments passed via stack are pushed
610   // between top of stack and JS arguments.
611   DCHECK_EQ(interface_descriptor.GetStackParameterCount(), 0);
612   Node* stub_code = jsgraph()->ArrayConstructorStubConstant();
613   Node* stub_arity = jsgraph()->Int32Constant(JSParameterCount(arity));
614   base::Optional<AllocationSiteRef> const site = p.site(broker());
615   Node* type_info = site.has_value() ? jsgraph()->Constant(site.value())
616                                      : jsgraph()->UndefinedConstant();
617   Node* receiver = jsgraph()->UndefinedConstant();
618   node->InsertInput(zone(), 0, stub_code);
619   node->InsertInput(zone(), 3, stub_arity);
620   node->InsertInput(zone(), 4, type_info);
621   node->InsertInput(zone(), 5, receiver);
622   NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
623 }
624 
LowerJSCreateArrayIterator(Node * node)625 void JSGenericLowering::LowerJSCreateArrayIterator(Node* node) {
626   UNREACHABLE();  // Eliminated in typed lowering.
627 }
628 
LowerJSCreateAsyncFunctionObject(Node * node)629 void JSGenericLowering::LowerJSCreateAsyncFunctionObject(Node* node) {
630   UNREACHABLE();  // Eliminated in typed lowering.
631 }
632 
LowerJSCreateCollectionIterator(Node * node)633 void JSGenericLowering::LowerJSCreateCollectionIterator(Node* node) {
634   UNREACHABLE();  // Eliminated in typed lowering.
635 }
636 
LowerJSCreateBoundFunction(Node * node)637 void JSGenericLowering::LowerJSCreateBoundFunction(Node* node) {
638   UNREACHABLE();  // Eliminated in typed lowering.
639 }
640 
LowerJSObjectIsArray(Node * node)641 void JSGenericLowering::LowerJSObjectIsArray(Node* node) {
642   UNREACHABLE();  // Eliminated in typed lowering.
643 }
644 
LowerJSCreateObject(Node * node)645 void JSGenericLowering::LowerJSCreateObject(Node* node) {
646   ReplaceWithBuiltinCall(node, Builtin::kCreateObjectWithoutProperties);
647 }
648 
LowerJSParseInt(Node * node)649 void JSGenericLowering::LowerJSParseInt(Node* node) {
650   ReplaceWithBuiltinCall(node, Builtin::kParseInt);
651 }
652 
LowerJSRegExpTest(Node * node)653 void JSGenericLowering::LowerJSRegExpTest(Node* node) {
654   ReplaceWithBuiltinCall(node, Builtin::kRegExpPrototypeTestFast);
655 }
656 
LowerJSCreateClosure(Node * node)657 void JSGenericLowering::LowerJSCreateClosure(Node* node) {
658   JSCreateClosureNode n(node);
659   CreateClosureParameters const& p = n.Parameters();
660   SharedFunctionInfoRef shared_info = p.shared_info(broker());
661   STATIC_ASSERT(n.FeedbackCellIndex() == 0);
662   node->InsertInput(zone(), 0, jsgraph()->Constant(shared_info));
663   node->RemoveInput(4);  // control
664 
665   // Use the FastNewClosure builtin only for functions allocated in new space.
666   if (p.allocation() == AllocationType::kYoung) {
667     ReplaceWithBuiltinCall(node, Builtin::kFastNewClosure);
668   } else {
669     ReplaceWithRuntimeCall(node, Runtime::kNewClosure_Tenured);
670   }
671 }
672 
LowerJSCreateFunctionContext(Node * node)673 void JSGenericLowering::LowerJSCreateFunctionContext(Node* node) {
674   const CreateFunctionContextParameters& parameters =
675       CreateFunctionContextParametersOf(node->op());
676   ScopeInfoRef scope_info = parameters.scope_info(broker());
677   int slot_count = parameters.slot_count();
678   ScopeType scope_type = parameters.scope_type();
679   CallDescriptor::Flags flags = FrameStateFlagForCall(node);
680 
681   if (slot_count <= ConstructorBuiltins::MaximumFunctionContextSlots()) {
682     Callable callable =
683         CodeFactory::FastNewFunctionContext(isolate(), scope_type);
684     node->InsertInput(zone(), 0, jsgraph()->Constant(scope_info));
685     node->InsertInput(zone(), 1, jsgraph()->Int32Constant(slot_count));
686     ReplaceWithBuiltinCall(node, callable, flags);
687   } else {
688     node->InsertInput(zone(), 0, jsgraph()->Constant(scope_info));
689     ReplaceWithRuntimeCall(node, Runtime::kNewFunctionContext);
690   }
691 }
692 
LowerJSCreateGeneratorObject(Node * node)693 void JSGenericLowering::LowerJSCreateGeneratorObject(Node* node) {
694   node->RemoveInput(4);  // control
695   ReplaceWithBuiltinCall(node, Builtin::kCreateGeneratorObject);
696 }
697 
LowerJSCreateIterResultObject(Node * node)698 void JSGenericLowering::LowerJSCreateIterResultObject(Node* node) {
699   ReplaceWithBuiltinCall(node, Builtin::kCreateIterResultObject);
700 }
701 
LowerJSCreateStringIterator(Node * node)702 void JSGenericLowering::LowerJSCreateStringIterator(Node* node) {
703   UNREACHABLE();  // Eliminated in typed lowering.
704 }
705 
LowerJSCreateKeyValueArray(Node * node)706 void JSGenericLowering::LowerJSCreateKeyValueArray(Node* node) {
707   UNREACHABLE();  // Eliminated in typed lowering.
708 }
709 
LowerJSCreatePromise(Node * node)710 void JSGenericLowering::LowerJSCreatePromise(Node* node) {
711   UNREACHABLE();  // Eliminated in typed lowering.
712 }
713 
LowerJSCreateTypedArray(Node * node)714 void JSGenericLowering::LowerJSCreateTypedArray(Node* node) {
715   ReplaceWithBuiltinCall(node, Builtin::kCreateTypedArray);
716 }
717 
LowerJSCreateLiteralArray(Node * node)718 void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) {
719   JSCreateLiteralArrayNode n(node);
720   CreateLiteralParameters const& p = n.Parameters();
721   STATIC_ASSERT(n.FeedbackVectorIndex() == 0);
722   node->InsertInput(zone(), 1,
723                     jsgraph()->TaggedIndexConstant(p.feedback().index()));
724   node->InsertInput(zone(), 2, jsgraph()->Constant(p.constant(broker())));
725   node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
726 
727   // Use the CreateShallowArrayLiteral builtin only for shallow boilerplates
728   // without properties up to the number of elements that the stubs can handle.
729   if ((p.flags() & AggregateLiteral::kIsShallow) != 0 &&
730       p.length() < ConstructorBuiltins::kMaximumClonedShallowArrayElements) {
731     ReplaceWithBuiltinCall(node, Builtin::kCreateShallowArrayLiteral);
732   } else {
733     ReplaceWithRuntimeCall(node, Runtime::kCreateArrayLiteral);
734   }
735 }
736 
LowerJSGetTemplateObject(Node * node)737 void JSGenericLowering::LowerJSGetTemplateObject(Node* node) {
738   JSGetTemplateObjectNode n(node);
739   GetTemplateObjectParameters const& p = n.Parameters();
740   SharedFunctionInfoRef shared = p.shared(broker());
741   TemplateObjectDescriptionRef description = p.description(broker());
742 
743   DCHECK_EQ(node->op()->ControlInputCount(), 1);
744   node->RemoveInput(NodeProperties::FirstControlIndex(node));
745 
746   STATIC_ASSERT(JSGetTemplateObjectNode::FeedbackVectorIndex() == 0);
747   node->InsertInput(zone(), 0, jsgraph()->Constant(shared));
748   node->InsertInput(zone(), 1, jsgraph()->Constant(description));
749   node->InsertInput(zone(), 2,
750                     jsgraph()->UintPtrConstant(p.feedback().index()));
751 
752   ReplaceWithBuiltinCall(node, Builtin::kGetTemplateObject);
753 }
754 
LowerJSCreateEmptyLiteralArray(Node * node)755 void JSGenericLowering::LowerJSCreateEmptyLiteralArray(Node* node) {
756   JSCreateEmptyLiteralArrayNode n(node);
757   FeedbackParameter const& p = n.Parameters();
758   STATIC_ASSERT(n.FeedbackVectorIndex() == 0);
759   node->InsertInput(zone(), 1,
760                     jsgraph()->TaggedIndexConstant(p.feedback().index()));
761   node->RemoveInput(4);  // control
762   ReplaceWithBuiltinCall(node, Builtin::kCreateEmptyArrayLiteral);
763 }
764 
LowerJSCreateArrayFromIterable(Node * node)765 void JSGenericLowering::LowerJSCreateArrayFromIterable(Node* node) {
766   ReplaceWithBuiltinCall(node, Builtin::kIterableToListWithSymbolLookup);
767 }
768 
LowerJSCreateLiteralObject(Node * node)769 void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) {
770   JSCreateLiteralObjectNode n(node);
771   CreateLiteralParameters const& p = n.Parameters();
772   STATIC_ASSERT(n.FeedbackVectorIndex() == 0);
773   node->InsertInput(zone(), 1,
774                     jsgraph()->TaggedIndexConstant(p.feedback().index()));
775   node->InsertInput(zone(), 2, jsgraph()->Constant(p.constant(broker())));
776   node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
777 
778   // Use the CreateShallowObjectLiteratal builtin only for shallow boilerplates
779   // without elements up to the number of properties that the stubs can handle.
780   if ((p.flags() & AggregateLiteral::kIsShallow) != 0 &&
781       p.length() <=
782           ConstructorBuiltins::kMaximumClonedShallowObjectProperties) {
783     ReplaceWithBuiltinCall(node, Builtin::kCreateShallowObjectLiteral);
784   } else {
785     ReplaceWithRuntimeCall(node, Runtime::kCreateObjectLiteral);
786   }
787 }
788 
LowerJSCloneObject(Node * node)789 void JSGenericLowering::LowerJSCloneObject(Node* node) {
790   JSCloneObjectNode n(node);
791   CloneObjectParameters const& p = n.Parameters();
792   STATIC_ASSERT(n.FeedbackVectorIndex() == 1);
793   node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.flags()));
794   node->InsertInput(zone(), 2,
795                     jsgraph()->TaggedIndexConstant(p.feedback().index()));
796   ReplaceWithBuiltinCall(node, Builtin::kCloneObjectIC);
797 }
798 
LowerJSCreateEmptyLiteralObject(Node * node)799 void JSGenericLowering::LowerJSCreateEmptyLiteralObject(Node* node) {
800   ReplaceWithBuiltinCall(node, Builtin::kCreateEmptyLiteralObject);
801 }
802 
LowerJSCreateLiteralRegExp(Node * node)803 void JSGenericLowering::LowerJSCreateLiteralRegExp(Node* node) {
804   JSCreateLiteralRegExpNode n(node);
805   CreateLiteralParameters const& p = n.Parameters();
806   STATIC_ASSERT(n.FeedbackVectorIndex() == 0);
807   node->InsertInput(zone(), 1,
808                     jsgraph()->TaggedIndexConstant(p.feedback().index()));
809   node->InsertInput(zone(), 2, jsgraph()->Constant(p.constant(broker())));
810   node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
811   ReplaceWithBuiltinCall(node, Builtin::kCreateRegExpLiteral);
812 }
813 
814 
LowerJSCreateCatchContext(Node * node)815 void JSGenericLowering::LowerJSCreateCatchContext(Node* node) {
816   ScopeInfoRef scope_info = ScopeInfoOf(broker(), node->op());
817   node->InsertInput(zone(), 1, jsgraph()->Constant(scope_info));
818   ReplaceWithRuntimeCall(node, Runtime::kPushCatchContext);
819 }
820 
LowerJSCreateWithContext(Node * node)821 void JSGenericLowering::LowerJSCreateWithContext(Node* node) {
822   ScopeInfoRef scope_info = ScopeInfoOf(broker(), node->op());
823   node->InsertInput(zone(), 1, jsgraph()->Constant(scope_info));
824   ReplaceWithRuntimeCall(node, Runtime::kPushWithContext);
825 }
826 
LowerJSCreateBlockContext(Node * node)827 void JSGenericLowering::LowerJSCreateBlockContext(Node* node) {
828   ScopeInfoRef scope_info = ScopeInfoOf(broker(), node->op());
829   node->InsertInput(zone(), 0, jsgraph()->Constant(scope_info));
830   ReplaceWithRuntimeCall(node, Runtime::kPushBlockContext);
831 }
832 
833 // TODO(jgruber,v8:8888): Should this collect feedback?
LowerJSConstructForwardVarargs(Node * node)834 void JSGenericLowering::LowerJSConstructForwardVarargs(Node* node) {
835   ConstructForwardVarargsParameters p =
836       ConstructForwardVarargsParametersOf(node->op());
837   int const arg_count = static_cast<int>(p.arity() - 2);
838   CallDescriptor::Flags flags = FrameStateFlagForCall(node);
839   Callable callable = CodeFactory::ConstructForwardVarargs(isolate());
840   // If this fails, we might need to update the parameter reordering code
841   // to ensure that the additional arguments passed via stack are pushed
842   // between top of stack and JS arguments.
843   DCHECK_EQ(callable.descriptor().GetStackParameterCount(), 0);
844   auto call_descriptor = Linkage::GetStubCallDescriptor(
845       zone(), callable.descriptor(), arg_count + 1, flags);
846   Node* stub_code = jsgraph()->HeapConstant(callable.code());
847   Node* stub_arity = jsgraph()->Int32Constant(JSParameterCount(arg_count));
848   Node* start_index = jsgraph()->Uint32Constant(p.start_index());
849   Node* receiver = jsgraph()->UndefinedConstant();
850   node->InsertInput(zone(), 0, stub_code);
851   node->InsertInput(zone(), 3, stub_arity);
852   node->InsertInput(zone(), 4, start_index);
853   node->InsertInput(zone(), 5, receiver);
854   NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
855 }
856 
LowerJSConstruct(Node * node)857 void JSGenericLowering::LowerJSConstruct(Node* node) {
858   JSConstructNode n(node);
859   ConstructParameters const& p = n.Parameters();
860   int const arg_count = p.arity_without_implicit_args();
861   CallDescriptor::Flags flags = FrameStateFlagForCall(node);
862 
863   static constexpr int kReceiver = 1;
864 
865   const int stack_argument_count = arg_count + kReceiver;
866   Callable callable = Builtins::CallableFor(isolate(), Builtin::kConstruct);
867   auto call_descriptor = Linkage::GetStubCallDescriptor(
868       zone(), callable.descriptor(), stack_argument_count, flags);
869   Node* stub_code = jsgraph()->HeapConstant(callable.code());
870   Node* stub_arity = jsgraph()->Int32Constant(JSParameterCount(arg_count));
871   Node* receiver = jsgraph()->UndefinedConstant();
872   node->RemoveInput(n.FeedbackVectorIndex());
873   node->InsertInput(zone(), 0, stub_code);
874   node->InsertInput(zone(), 3, stub_arity);
875   node->InsertInput(zone(), 4, receiver);
876 
877   // After: {code, target, new_target, arity, receiver, ...args}.
878 
879   NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
880 }
881 
LowerJSConstructWithArrayLike(Node * node)882 void JSGenericLowering::LowerJSConstructWithArrayLike(Node* node) {
883   JSConstructWithArrayLikeNode n(node);
884   ConstructParameters const& p = n.Parameters();
885   CallDescriptor::Flags flags = FrameStateFlagForCall(node);
886   const int arg_count = p.arity_without_implicit_args();
887   DCHECK_EQ(arg_count, 1);
888 
889   static constexpr int kReceiver = 1;
890   static constexpr int kArgumentList = 1;
891 
892   const int stack_argument_count = arg_count - kArgumentList + kReceiver;
893   Callable callable =
894       Builtins::CallableFor(isolate(), Builtin::kConstructWithArrayLike);
895   // If this fails, we might need to update the parameter reordering code
896   // to ensure that the additional arguments passed via stack are pushed
897   // between top of stack and JS arguments.
898   DCHECK_EQ(callable.descriptor().GetStackParameterCount(), 0);
899   auto call_descriptor = Linkage::GetStubCallDescriptor(
900       zone(), callable.descriptor(), stack_argument_count, flags);
901   Node* stub_code = jsgraph()->HeapConstant(callable.code());
902   Node* receiver = jsgraph()->UndefinedConstant();
903   node->RemoveInput(n.FeedbackVectorIndex());
904   node->InsertInput(zone(), 0, stub_code);
905   node->InsertInput(zone(), 4, receiver);
906 
907   // After: {code, target, new_target, arguments_list, receiver}.
908 
909   NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
910 }
911 
LowerJSConstructWithSpread(Node * node)912 void JSGenericLowering::LowerJSConstructWithSpread(Node* node) {
913   JSConstructWithSpreadNode n(node);
914   ConstructParameters const& p = n.Parameters();
915   int const arg_count = p.arity_without_implicit_args();
916   DCHECK_GE(arg_count, 1);
917   CallDescriptor::Flags flags = FrameStateFlagForCall(node);
918 
919   static constexpr int kReceiver = 1;
920   static constexpr int kTheSpread = 1;  // Included in `arg_count`.
921 
922   const int stack_argument_count = arg_count + kReceiver - kTheSpread;
923   Callable callable = CodeFactory::ConstructWithSpread(isolate());
924   // If this fails, we might need to update the parameter reordering code
925   // to ensure that the additional arguments passed via stack are pushed
926   // between top of stack and JS arguments.
927   DCHECK_EQ(callable.descriptor().GetStackParameterCount(), 0);
928   auto call_descriptor = Linkage::GetStubCallDescriptor(
929       zone(), callable.descriptor(), stack_argument_count, flags);
930   Node* stub_code = jsgraph()->HeapConstant(callable.code());
931 
932   // We pass the spread in a register, not on the stack.
933   Node* stub_arity =
934       jsgraph()->Int32Constant(JSParameterCount(arg_count - kTheSpread));
935   Node* receiver = jsgraph()->UndefinedConstant();
936   DCHECK(n.FeedbackVectorIndex() > n.LastArgumentIndex());
937   node->RemoveInput(n.FeedbackVectorIndex());
938   Node* spread = node->RemoveInput(n.LastArgumentIndex());
939 
940   node->InsertInput(zone(), 0, stub_code);
941   node->InsertInput(zone(), 3, stub_arity);
942   node->InsertInput(zone(), 4, spread);
943   node->InsertInput(zone(), 5, receiver);
944 
945   // After: {code, target, new_target, arity, spread, receiver, ...args}.
946 
947   NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
948 }
949 
LowerJSCallForwardVarargs(Node * node)950 void JSGenericLowering::LowerJSCallForwardVarargs(Node* node) {
951   CallForwardVarargsParameters p = CallForwardVarargsParametersOf(node->op());
952   int const arg_count = static_cast<int>(p.arity() - 2);
953   CallDescriptor::Flags flags = FrameStateFlagForCall(node);
954   Callable callable = CodeFactory::CallForwardVarargs(isolate());
955   auto call_descriptor = Linkage::GetStubCallDescriptor(
956       zone(), callable.descriptor(), arg_count + 1, flags);
957   Node* stub_code = jsgraph()->HeapConstant(callable.code());
958   Node* stub_arity = jsgraph()->Int32Constant(JSParameterCount(arg_count));
959   Node* start_index = jsgraph()->Uint32Constant(p.start_index());
960   node->InsertInput(zone(), 0, stub_code);
961   node->InsertInput(zone(), 2, stub_arity);
962   node->InsertInput(zone(), 3, start_index);
963   NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
964 }
965 
LowerJSCall(Node * node)966 void JSGenericLowering::LowerJSCall(Node* node) {
967   JSCallNode n(node);
968   CallParameters const& p = n.Parameters();
969   int const arg_count = p.arity_without_implicit_args();
970   ConvertReceiverMode const mode = p.convert_mode();
971 
972   node->RemoveInput(n.FeedbackVectorIndex());
973 
974   Callable callable = CodeFactory::Call(isolate(), mode);
975   CallDescriptor::Flags flags = FrameStateFlagForCall(node);
976   auto call_descriptor = Linkage::GetStubCallDescriptor(
977       zone(), callable.descriptor(), arg_count + 1, flags);
978   Node* stub_code = jsgraph()->HeapConstant(callable.code());
979   Node* stub_arity = jsgraph()->Int32Constant(JSParameterCount(arg_count));
980   node->InsertInput(zone(), 0, stub_code);
981   node->InsertInput(zone(), 2, stub_arity);
982   NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
983 }
984 
LowerJSCallWithArrayLike(Node * node)985 void JSGenericLowering::LowerJSCallWithArrayLike(Node* node) {
986   JSCallWithArrayLikeNode n(node);
987   CallParameters const& p = n.Parameters();
988   const int arg_count = p.arity_without_implicit_args();
989   DCHECK_EQ(arg_count, 1);  // The arraylike object.
990   CallDescriptor::Flags flags = FrameStateFlagForCall(node);
991 
992   static constexpr int kArgumentsList = 1;
993   static constexpr int kReceiver = 1;
994 
995   const int stack_argument_count = arg_count - kArgumentsList + kReceiver;
996   Callable callable = CodeFactory::CallWithArrayLike(isolate());
997   auto call_descriptor = Linkage::GetStubCallDescriptor(
998       zone(), callable.descriptor(), stack_argument_count, flags);
999   Node* stub_code = jsgraph()->HeapConstant(callable.code());
1000   Node* receiver = n.receiver();
1001   Node* arguments_list = n.Argument(0);
1002 
1003   // Shuffling inputs.
1004   // Before: {target, receiver, arguments_list, vector}.
1005 
1006   node->RemoveInput(n.FeedbackVectorIndex());
1007   node->InsertInput(zone(), 0, stub_code);
1008   node->ReplaceInput(2, arguments_list);
1009   node->ReplaceInput(3, receiver);
1010 
1011   // After: {code, target, arguments_list, receiver}.
1012 
1013   NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
1014 }
1015 
LowerJSCallWithSpread(Node * node)1016 void JSGenericLowering::LowerJSCallWithSpread(Node* node) {
1017   JSCallWithSpreadNode n(node);
1018   CallParameters const& p = n.Parameters();
1019   int const arg_count = p.arity_without_implicit_args();
1020   DCHECK_GE(arg_count, 1);  // At least the spread.
1021   CallDescriptor::Flags flags = FrameStateFlagForCall(node);
1022 
1023   static constexpr int kReceiver = 1;
1024   static constexpr int kTheSpread = 1;
1025 
1026   const int stack_argument_count = arg_count - kTheSpread + kReceiver;
1027   Callable callable = CodeFactory::CallWithSpread(isolate());
1028   // If this fails, we might need to update the parameter reordering code
1029   // to ensure that the additional arguments passed via stack are pushed
1030   // between top of stack and JS arguments.
1031   DCHECK_EQ(callable.descriptor().GetStackParameterCount(), 0);
1032   auto call_descriptor = Linkage::GetStubCallDescriptor(
1033       zone(), callable.descriptor(), stack_argument_count, flags);
1034   Node* stub_code = jsgraph()->HeapConstant(callable.code());
1035 
1036   // We pass the spread in a register, not on the stack.
1037   Node* stub_arity =
1038       jsgraph()->Int32Constant(JSParameterCount(arg_count - kTheSpread));
1039 
1040   // Shuffling inputs.
1041   // Before: {target, receiver, ...args, spread, vector}.
1042 
1043   node->RemoveInput(n.FeedbackVectorIndex());
1044   Node* spread = node->RemoveInput(n.LastArgumentIndex());
1045 
1046   node->InsertInput(zone(), 0, stub_code);
1047   node->InsertInput(zone(), 2, stub_arity);
1048   node->InsertInput(zone(), 3, spread);
1049 
1050   // After: {code, target, arity, spread, receiver, ...args}.
1051 
1052   NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
1053 }
1054 
LowerJSCallRuntime(Node * node)1055 void JSGenericLowering::LowerJSCallRuntime(Node* node) {
1056   const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op());
1057   ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity()));
1058 }
1059 
1060 #if V8_ENABLE_WEBASSEMBLY
1061 // Will be lowered in SimplifiedLowering.
LowerJSWasmCall(Node * node)1062 void JSGenericLowering::LowerJSWasmCall(Node* node) {}
1063 #endif  // V8_ENABLE_WEBASSEMBLY
1064 
LowerJSForInPrepare(Node * node)1065 void JSGenericLowering::LowerJSForInPrepare(Node* node) {
1066   JSForInPrepareNode n(node);
1067   Effect effect(node);            // {node} is kept in the effect chain.
1068   Control control = n.control();  // .. but not in the control chain.
1069   Node* enumerator = n.enumerator();
1070   Node* slot =
1071       jsgraph()->UintPtrConstant(n.Parameters().feedback().slot.ToInt());
1072 
1073   std::vector<Edge> use_edges;
1074   for (Edge edge : node->use_edges()) use_edges.push_back(edge);
1075 
1076   // {node} will be changed to a builtin call (see below). The returned value
1077   // is a fixed array containing {cache_array} and {cache_length}.
1078   // TODO(jgruber): This is awkward; what we really want is two return values,
1079   // the {cache_array} and {cache_length}, or better yet three return values
1080   // s.t. we can avoid the graph rewrites below. Builtin support for multiple
1081   // return types is unclear though.
1082 
1083   Node* result_fixed_array = node;
1084   Node* cache_type = enumerator;  // Just to clarify the rename.
1085   Node* cache_array;
1086   Node* cache_length;
1087 
1088   cache_array = effect = graph()->NewNode(
1089       machine()->Load(MachineType::AnyTagged()), result_fixed_array,
1090       jsgraph()->IntPtrConstant(FixedArray::OffsetOfElementAt(0) -
1091                                 kHeapObjectTag),
1092       effect, control);
1093   cache_length = effect = graph()->NewNode(
1094       machine()->Load(MachineType::AnyTagged()), result_fixed_array,
1095       jsgraph()->IntPtrConstant(FixedArray::OffsetOfElementAt(1) -
1096                                 kHeapObjectTag),
1097       effect, control);
1098 
1099   // Update the uses of {node}.
1100   for (Edge edge : use_edges) {
1101     Node* const user = edge.from();
1102     if (NodeProperties::IsEffectEdge(edge)) {
1103       edge.UpdateTo(effect);
1104     } else if (NodeProperties::IsControlEdge(edge)) {
1105       edge.UpdateTo(control);
1106     } else {
1107       DCHECK(NodeProperties::IsValueEdge(edge));
1108       switch (ProjectionIndexOf(user->op())) {
1109         case 0:
1110           Replace(user, cache_type);
1111           break;
1112         case 1:
1113           Replace(user, cache_array);
1114           break;
1115         case 2:
1116           Replace(user, cache_length);
1117           break;
1118         default:
1119           UNREACHABLE();
1120       }
1121     }
1122   }
1123 
1124   // Finally, change the original node into a builtin call. This happens here,
1125   // after graph rewrites, since the Call does not have a control output and
1126   // thus must not have any control uses. Any previously existing control
1127   // outputs have been replaced by the graph rewrite above.
1128   node->InsertInput(zone(), n.FeedbackVectorIndex(), slot);
1129   ReplaceWithBuiltinCall(node, Builtin::kForInPrepare);
1130 }
1131 
LowerJSForInNext(Node * node)1132 void JSGenericLowering::LowerJSForInNext(Node* node) {
1133   JSForInNextNode n(node);
1134   node->InsertInput(
1135       zone(), 0,
1136       jsgraph()->UintPtrConstant(n.Parameters().feedback().slot.ToInt()));
1137   ReplaceWithBuiltinCall(node, Builtin::kForInNext);
1138 }
1139 
LowerJSLoadMessage(Node * node)1140 void JSGenericLowering::LowerJSLoadMessage(Node* node) {
1141   UNREACHABLE();  // Eliminated in typed lowering.
1142 }
1143 
1144 
LowerJSStoreMessage(Node * node)1145 void JSGenericLowering::LowerJSStoreMessage(Node* node) {
1146   UNREACHABLE();  // Eliminated in typed lowering.
1147 }
1148 
LowerJSLoadModule(Node * node)1149 void JSGenericLowering::LowerJSLoadModule(Node* node) {
1150   UNREACHABLE();  // Eliminated in typed lowering.
1151 }
1152 
LowerJSStoreModule(Node * node)1153 void JSGenericLowering::LowerJSStoreModule(Node* node) {
1154   UNREACHABLE();  // Eliminated in typed lowering.
1155 }
1156 
LowerJSGetImportMeta(Node * node)1157 void JSGenericLowering::LowerJSGetImportMeta(Node* node) {
1158   ReplaceWithRuntimeCall(node, Runtime::kGetImportMetaObject);
1159 }
1160 
LowerJSGeneratorStore(Node * node)1161 void JSGenericLowering::LowerJSGeneratorStore(Node* node) {
1162   UNREACHABLE();  // Eliminated in typed lowering.
1163 }
1164 
LowerJSGeneratorRestoreContinuation(Node * node)1165 void JSGenericLowering::LowerJSGeneratorRestoreContinuation(Node* node) {
1166   UNREACHABLE();  // Eliminated in typed lowering.
1167 }
1168 
LowerJSGeneratorRestoreContext(Node * node)1169 void JSGenericLowering::LowerJSGeneratorRestoreContext(Node* node) {
1170   UNREACHABLE();  // Eliminated in typed lowering.
1171 }
1172 
LowerJSGeneratorRestoreInputOrDebugPos(Node * node)1173 void JSGenericLowering::LowerJSGeneratorRestoreInputOrDebugPos(Node* node) {
1174   UNREACHABLE();  // Eliminated in typed lowering.
1175 }
1176 
LowerJSGeneratorRestoreRegister(Node * node)1177 void JSGenericLowering::LowerJSGeneratorRestoreRegister(Node* node) {
1178   UNREACHABLE();  // Eliminated in typed lowering.
1179 }
1180 
1181 namespace {
1182 
StackCheckKindOfJSStackCheck(const Operator * op)1183 StackCheckKind StackCheckKindOfJSStackCheck(const Operator* op) {
1184   DCHECK(op->opcode() == IrOpcode::kJSStackCheck);
1185   return OpParameter<StackCheckKind>(op);
1186 }
1187 
1188 }  // namespace
1189 
LowerJSStackCheck(Node * node)1190 void JSGenericLowering::LowerJSStackCheck(Node* node) {
1191   Node* effect = NodeProperties::GetEffectInput(node);
1192   Node* control = NodeProperties::GetControlInput(node);
1193 
1194   Node* limit = effect =
1195       graph()->NewNode(machine()->Load(MachineType::Pointer()),
1196                        jsgraph()->ExternalConstant(
1197                            ExternalReference::address_of_jslimit(isolate())),
1198                        jsgraph()->IntPtrConstant(0), effect, control);
1199 
1200   StackCheckKind stack_check_kind = StackCheckKindOfJSStackCheck(node->op());
1201   Node* check = effect = graph()->NewNode(
1202       machine()->StackPointerGreaterThan(stack_check_kind), limit, effect);
1203   Node* branch =
1204       graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1205 
1206   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1207   Node* etrue = effect;
1208 
1209   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1210   NodeProperties::ReplaceControlInput(node, if_false);
1211   NodeProperties::ReplaceEffectInput(node, effect);
1212   Node* efalse = if_false = node;
1213 
1214   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
1215   Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
1216 
1217   // Wire the new diamond into the graph, {node} can still throw.
1218   NodeProperties::ReplaceUses(node, node, ephi, merge, merge);
1219   NodeProperties::ReplaceControlInput(merge, if_false, 1);
1220   NodeProperties::ReplaceEffectInput(ephi, efalse, 1);
1221 
1222   // This iteration cuts out potential {IfSuccess} or {IfException} projection
1223   // uses of the original node and places them inside the diamond, so that we
1224   // can change the original {node} into the slow-path runtime call.
1225   for (Edge edge : merge->use_edges()) {
1226     if (!NodeProperties::IsControlEdge(edge)) continue;
1227     if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
1228       NodeProperties::ReplaceUses(edge.from(), nullptr, nullptr, merge);
1229       NodeProperties::ReplaceControlInput(merge, edge.from(), 1);
1230       edge.UpdateTo(node);
1231     }
1232     if (edge.from()->opcode() == IrOpcode::kIfException) {
1233       NodeProperties::ReplaceEffectInput(edge.from(), node);
1234       edge.UpdateTo(node);
1235     }
1236   }
1237 
1238   // Turn the stack check into a runtime call. At function entry, the runtime
1239   // function takes an offset argument which is subtracted from the stack
1240   // pointer prior to the stack check (i.e. the check is `sp - offset >=
1241   // limit`).
1242   if (stack_check_kind == StackCheckKind::kJSFunctionEntry) {
1243     node->InsertInput(zone(), 0,
1244                       graph()->NewNode(machine()->LoadStackCheckOffset()));
1245     ReplaceWithRuntimeCall(node, Runtime::kStackGuardWithGap);
1246   } else {
1247     ReplaceWithRuntimeCall(node, Runtime::kStackGuard);
1248   }
1249 }
1250 
LowerJSDebugger(Node * node)1251 void JSGenericLowering::LowerJSDebugger(Node* node) {
1252   ReplaceWithRuntimeCall(node, Runtime::kHandleDebuggerStatement);
1253 }
1254 
zone() const1255 Zone* JSGenericLowering::zone() const { return graph()->zone(); }
1256 
1257 
isolate() const1258 Isolate* JSGenericLowering::isolate() const { return jsgraph()->isolate(); }
1259 
1260 
graph() const1261 Graph* JSGenericLowering::graph() const { return jsgraph()->graph(); }
1262 
1263 
common() const1264 CommonOperatorBuilder* JSGenericLowering::common() const {
1265   return jsgraph()->common();
1266 }
1267 
1268 
machine() const1269 MachineOperatorBuilder* JSGenericLowering::machine() const {
1270   return jsgraph()->machine();
1271 }
1272 
1273 }  // namespace compiler
1274 }  // namespace internal
1275 }  // namespace v8
1276