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