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