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