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 26namespace v8 { 27namespace internal { 28namespace compiler { 29 30namespace { 31 32CallDescriptor::Flags FrameStateFlagForCall(Node* node) { 33 return OperatorProperties::HasFrameStateInput(node->op()) 34 ? CallDescriptor::kNeedsFrameState 35 : CallDescriptor::kNoFlags; 36} 37 38} // namespace 39 40JSGenericLowering::JSGenericLowering(JSGraph* jsgraph, Editor* editor, 41 JSHeapBroker* broker) 42 : AdvancedReducer(editor), jsgraph_(jsgraph), broker_(broker) {} 43 44JSGenericLowering::~JSGenericLowering() = default; 45 46 47Reduction 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 } 66REPLACE_STUB_CALL(ToLength) 67REPLACE_STUB_CALL(ToNumber) 68REPLACE_STUB_CALL(ToNumberConvertBigInt) 69REPLACE_STUB_CALL(ToNumeric) 70REPLACE_STUB_CALL(ToName) 71REPLACE_STUB_CALL(ToObject) 72REPLACE_STUB_CALL(ToString) 73REPLACE_STUB_CALL(ForInEnumerate) 74REPLACE_STUB_CALL(AsyncFunctionEnter) 75REPLACE_STUB_CALL(AsyncFunctionReject) 76REPLACE_STUB_CALL(AsyncFunctionResolve) 77REPLACE_STUB_CALL(FulfillPromise) 78REPLACE_STUB_CALL(PerformPromiseThen) 79REPLACE_STUB_CALL(PromiseResolve) 80REPLACE_STUB_CALL(RejectPromise) 81REPLACE_STUB_CALL(ResolvePromise) 82#undef REPLACE_STUB_CALL 83 84void 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 90void JSGenericLowering::ReplaceWithBuiltinCall(Node* node, Callable callable, 91 CallDescriptor::Flags flags) { 92 ReplaceWithBuiltinCall(node, callable, flags, node->op()->properties()); 93} 94 95void 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 107void 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 124void 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 } 155DEF_UNARY_LOWERING(BitwiseNot) 156DEF_UNARY_LOWERING(Decrement) 157DEF_UNARY_LOWERING(Increment) 158DEF_UNARY_LOWERING(Negate) 159#undef DEF_UNARY_LOWERING 160 161void 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. 189DEF_BINARY_LOWERING(Add) 190DEF_BINARY_LOWERING(BitwiseAnd) 191DEF_BINARY_LOWERING(BitwiseOr) 192DEF_BINARY_LOWERING(BitwiseXor) 193DEF_BINARY_LOWERING(Divide) 194DEF_BINARY_LOWERING(Exponentiate) 195DEF_BINARY_LOWERING(Modulus) 196DEF_BINARY_LOWERING(Multiply) 197DEF_BINARY_LOWERING(ShiftLeft) 198DEF_BINARY_LOWERING(ShiftRight) 199DEF_BINARY_LOWERING(ShiftRightLogical) 200DEF_BINARY_LOWERING(Subtract) 201// Compare ops. 202DEF_BINARY_LOWERING(Equal) 203DEF_BINARY_LOWERING(GreaterThan) 204DEF_BINARY_LOWERING(GreaterThanOrEqual) 205DEF_BINARY_LOWERING(InstanceOf) 206DEF_BINARY_LOWERING(LessThan) 207DEF_BINARY_LOWERING(LessThanOrEqual) 208#undef DEF_BINARY_LOWERING 209 210void 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 236namespace { 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. 241bool 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 259void 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 273void 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 297void 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 327void 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 354void 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 378void 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 402void 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 426void 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 444void 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 473void 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 496void 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 516void 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 526void 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 536void JSGenericLowering::LowerJSDeleteProperty(Node* node) { 537 ReplaceWithBuiltinCall(node, Builtin::kDeleteProperty); 538} 539 540void 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 558void JSGenericLowering::LowerJSHasInPrototypeChain(Node* node) { 559 ReplaceWithRuntimeCall(node, Runtime::kHasInPrototypeChain); 560} 561 562void JSGenericLowering::LowerJSOrdinaryHasInstance(Node* node) { 563 ReplaceWithBuiltinCall(node, Builtin::kOrdinaryHasInstance); 564} 565 566void JSGenericLowering::LowerJSHasContextExtension(Node* node) { 567 UNREACHABLE(); // Eliminated in typed lowering. 568} 569 570void JSGenericLowering::LowerJSLoadContext(Node* node) { 571 UNREACHABLE(); // Eliminated in typed lowering. 572} 573 574 575void JSGenericLowering::LowerJSStoreContext(Node* node) { 576 UNREACHABLE(); // Eliminated in typed lowering. 577} 578 579 580void JSGenericLowering::LowerJSCreate(Node* node) { 581 ReplaceWithBuiltinCall(node, Builtin::kFastNewObject); 582} 583 584 585void 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 601void 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 625void JSGenericLowering::LowerJSCreateArrayIterator(Node* node) { 626 UNREACHABLE(); // Eliminated in typed lowering. 627} 628 629void JSGenericLowering::LowerJSCreateAsyncFunctionObject(Node* node) { 630 UNREACHABLE(); // Eliminated in typed lowering. 631} 632 633void JSGenericLowering::LowerJSCreateCollectionIterator(Node* node) { 634 UNREACHABLE(); // Eliminated in typed lowering. 635} 636 637void JSGenericLowering::LowerJSCreateBoundFunction(Node* node) { 638 UNREACHABLE(); // Eliminated in typed lowering. 639} 640 641void JSGenericLowering::LowerJSObjectIsArray(Node* node) { 642 UNREACHABLE(); // Eliminated in typed lowering. 643} 644 645void JSGenericLowering::LowerJSCreateObject(Node* node) { 646 ReplaceWithBuiltinCall(node, Builtin::kCreateObjectWithoutProperties); 647} 648 649void JSGenericLowering::LowerJSParseInt(Node* node) { 650 ReplaceWithBuiltinCall(node, Builtin::kParseInt); 651} 652 653void JSGenericLowering::LowerJSRegExpTest(Node* node) { 654 ReplaceWithBuiltinCall(node, Builtin::kRegExpPrototypeTestFast); 655} 656 657void 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 673void 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 693void JSGenericLowering::LowerJSCreateGeneratorObject(Node* node) { 694 node->RemoveInput(4); // control 695 ReplaceWithBuiltinCall(node, Builtin::kCreateGeneratorObject); 696} 697 698void JSGenericLowering::LowerJSCreateIterResultObject(Node* node) { 699 ReplaceWithBuiltinCall(node, Builtin::kCreateIterResultObject); 700} 701 702void JSGenericLowering::LowerJSCreateStringIterator(Node* node) { 703 UNREACHABLE(); // Eliminated in typed lowering. 704} 705 706void JSGenericLowering::LowerJSCreateKeyValueArray(Node* node) { 707 UNREACHABLE(); // Eliminated in typed lowering. 708} 709 710void JSGenericLowering::LowerJSCreatePromise(Node* node) { 711 UNREACHABLE(); // Eliminated in typed lowering. 712} 713 714void JSGenericLowering::LowerJSCreateTypedArray(Node* node) { 715 ReplaceWithBuiltinCall(node, Builtin::kCreateTypedArray); 716} 717 718void 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 737void 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 755void 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 765void JSGenericLowering::LowerJSCreateArrayFromIterable(Node* node) { 766 ReplaceWithBuiltinCall(node, Builtin::kIterableToListWithSymbolLookup); 767} 768 769void 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 789void 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 799void JSGenericLowering::LowerJSCreateEmptyLiteralObject(Node* node) { 800 ReplaceWithBuiltinCall(node, Builtin::kCreateEmptyLiteralObject); 801} 802 803void 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 815void 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 821void 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 827void 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? 834void 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 857void 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 882void 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 912void 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 950void 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 966void 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 985void 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 1016void 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 1055void 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. 1062void JSGenericLowering::LowerJSWasmCall(Node* node) {} 1063#endif // V8_ENABLE_WEBASSEMBLY 1064 1065void 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 1132void 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 1140void JSGenericLowering::LowerJSLoadMessage(Node* node) { 1141 UNREACHABLE(); // Eliminated in typed lowering. 1142} 1143 1144 1145void JSGenericLowering::LowerJSStoreMessage(Node* node) { 1146 UNREACHABLE(); // Eliminated in typed lowering. 1147} 1148 1149void JSGenericLowering::LowerJSLoadModule(Node* node) { 1150 UNREACHABLE(); // Eliminated in typed lowering. 1151} 1152 1153void JSGenericLowering::LowerJSStoreModule(Node* node) { 1154 UNREACHABLE(); // Eliminated in typed lowering. 1155} 1156 1157void JSGenericLowering::LowerJSGetImportMeta(Node* node) { 1158 ReplaceWithRuntimeCall(node, Runtime::kGetImportMetaObject); 1159} 1160 1161void JSGenericLowering::LowerJSGeneratorStore(Node* node) { 1162 UNREACHABLE(); // Eliminated in typed lowering. 1163} 1164 1165void JSGenericLowering::LowerJSGeneratorRestoreContinuation(Node* node) { 1166 UNREACHABLE(); // Eliminated in typed lowering. 1167} 1168 1169void JSGenericLowering::LowerJSGeneratorRestoreContext(Node* node) { 1170 UNREACHABLE(); // Eliminated in typed lowering. 1171} 1172 1173void JSGenericLowering::LowerJSGeneratorRestoreInputOrDebugPos(Node* node) { 1174 UNREACHABLE(); // Eliminated in typed lowering. 1175} 1176 1177void JSGenericLowering::LowerJSGeneratorRestoreRegister(Node* node) { 1178 UNREACHABLE(); // Eliminated in typed lowering. 1179} 1180 1181namespace { 1182 1183StackCheckKind StackCheckKindOfJSStackCheck(const Operator* op) { 1184 DCHECK(op->opcode() == IrOpcode::kJSStackCheck); 1185 return OpParameter<StackCheckKind>(op); 1186} 1187 1188} // namespace 1189 1190void 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 1251void JSGenericLowering::LowerJSDebugger(Node* node) { 1252 ReplaceWithRuntimeCall(node, Runtime::kHandleDebuggerStatement); 1253} 1254 1255Zone* JSGenericLowering::zone() const { return graph()->zone(); } 1256 1257 1258Isolate* JSGenericLowering::isolate() const { return jsgraph()->isolate(); } 1259 1260 1261Graph* JSGenericLowering::graph() const { return jsgraph()->graph(); } 1262 1263 1264CommonOperatorBuilder* JSGenericLowering::common() const { 1265 return jsgraph()->common(); 1266} 1267 1268 1269MachineOperatorBuilder* JSGenericLowering::machine() const { 1270 return jsgraph()->machine(); 1271} 1272 1273} // namespace compiler 1274} // namespace internal 1275} // namespace v8 1276