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/ast/scopes.h" 6 #include "src/code-stubs.h" 7 #include "src/compiler.h" 8 #include "src/compiler/common-operator.h" 9 #include "src/compiler/frame.h" 10 #include "src/compiler/linkage.h" 11 #include "src/compiler/node.h" 12 #include "src/compiler/osr.h" 13 #include "src/compiler/pipeline.h" 14 15 namespace v8 { 16 namespace internal { 17 namespace compiler { 18 19 namespace { 20 LinkageLocation regloc(Register reg) { 21 return LinkageLocation::ForRegister(reg.code()); 22 } 23 24 25 MachineType reptyp(Representation representation) { 26 switch (representation.kind()) { 27 case Representation::kInteger8: 28 return MachineType::Int8(); 29 case Representation::kUInteger8: 30 return MachineType::Uint8(); 31 case Representation::kInteger16: 32 return MachineType::Int16(); 33 case Representation::kUInteger16: 34 return MachineType::Uint16(); 35 case Representation::kInteger32: 36 return MachineType::Int32(); 37 case Representation::kSmi: 38 case Representation::kTagged: 39 case Representation::kHeapObject: 40 return MachineType::AnyTagged(); 41 case Representation::kDouble: 42 return MachineType::Float64(); 43 case Representation::kExternal: 44 return MachineType::Pointer(); 45 case Representation::kNone: 46 case Representation::kNumRepresentations: 47 break; 48 } 49 UNREACHABLE(); 50 return MachineType::None(); 51 } 52 } // namespace 53 54 55 std::ostream& operator<<(std::ostream& os, const CallDescriptor::Kind& k) { 56 switch (k) { 57 case CallDescriptor::kCallCodeObject: 58 os << "Code"; 59 break; 60 case CallDescriptor::kCallJSFunction: 61 os << "JS"; 62 break; 63 case CallDescriptor::kCallAddress: 64 os << "Addr"; 65 break; 66 } 67 return os; 68 } 69 70 71 std::ostream& operator<<(std::ostream& os, const CallDescriptor& d) { 72 // TODO(svenpanne) Output properties etc. and be less cryptic. 73 return os << d.kind() << ":" << d.debug_name() << ":r" << d.ReturnCount() 74 << "s" << d.StackParameterCount() << "i" << d.InputCount() << "f" 75 << d.FrameStateCount() << "t" << d.SupportsTailCalls(); 76 } 77 78 79 bool CallDescriptor::HasSameReturnLocationsAs( 80 const CallDescriptor* other) const { 81 if (ReturnCount() != other->ReturnCount()) return false; 82 for (size_t i = 0; i < ReturnCount(); ++i) { 83 if (GetReturnLocation(i) != other->GetReturnLocation(i)) return false; 84 } 85 return true; 86 } 87 88 89 bool CallDescriptor::CanTailCall(const Node* node, 90 int* stack_param_delta) const { 91 CallDescriptor const* other = CallDescriptorOf(node->op()); 92 size_t current_input = 0; 93 size_t other_input = 0; 94 *stack_param_delta = 0; 95 bool more_other = true; 96 bool more_this = true; 97 while (more_other || more_this) { 98 if (other_input < other->InputCount()) { 99 if (!other->GetInputLocation(other_input).IsRegister()) { 100 (*stack_param_delta)--; 101 } 102 } else { 103 more_other = false; 104 } 105 if (current_input < InputCount()) { 106 if (!GetInputLocation(current_input).IsRegister()) { 107 (*stack_param_delta)++; 108 } 109 } else { 110 more_this = false; 111 } 112 ++current_input; 113 ++other_input; 114 } 115 return HasSameReturnLocationsAs(CallDescriptorOf(node->op())); 116 } 117 118 119 CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) { 120 DCHECK(!info->IsStub()); 121 if (!info->closure().is_null()) { 122 // If we are compiling a JS function, use a JS call descriptor, 123 // plus the receiver. 124 SharedFunctionInfo* shared = info->closure()->shared(); 125 return GetJSCallDescriptor(zone, info->is_osr(), 126 1 + shared->internal_formal_parameter_count(), 127 CallDescriptor::kNoFlags); 128 } 129 return nullptr; // TODO(titzer): ? 130 } 131 132 133 // static 134 bool Linkage::NeedsFrameStateInput(Runtime::FunctionId function) { 135 // Most runtime functions need a FrameState. A few chosen ones that we know 136 // not to call into arbitrary JavaScript, not to throw, and not to deoptimize 137 // are blacklisted here and can be called without a FrameState. 138 switch (function) { 139 case Runtime::kAbort: 140 case Runtime::kAllocateInTargetSpace: 141 case Runtime::kCreateIterResultObject: 142 case Runtime::kDefineGetterPropertyUnchecked: // TODO(jarin): Is it safe? 143 case Runtime::kDefineSetterPropertyUnchecked: // TODO(jarin): Is it safe? 144 case Runtime::kForInDone: 145 case Runtime::kForInStep: 146 case Runtime::kGeneratorGetContinuation: 147 case Runtime::kGetSuperConstructor: 148 case Runtime::kIsFunction: 149 case Runtime::kNewClosure: 150 case Runtime::kNewClosure_Tenured: 151 case Runtime::kNewFunctionContext: 152 case Runtime::kPushBlockContext: 153 case Runtime::kPushCatchContext: 154 case Runtime::kReThrow: 155 case Runtime::kStringCompare: 156 case Runtime::kStringEqual: 157 case Runtime::kStringNotEqual: 158 case Runtime::kStringLessThan: 159 case Runtime::kStringLessThanOrEqual: 160 case Runtime::kStringGreaterThan: 161 case Runtime::kStringGreaterThanOrEqual: 162 case Runtime::kToFastProperties: // TODO(conradw): Is it safe? 163 case Runtime::kTraceEnter: 164 case Runtime::kTraceExit: 165 return false; 166 case Runtime::kInlineCall: 167 case Runtime::kInlineDeoptimizeNow: 168 case Runtime::kInlineGetPrototype: 169 case Runtime::kInlineNewObject: 170 case Runtime::kInlineRegExpConstructResult: 171 case Runtime::kInlineRegExpExec: 172 case Runtime::kInlineSubString: 173 case Runtime::kInlineThrowNotDateError: 174 case Runtime::kInlineToInteger: 175 case Runtime::kInlineToLength: 176 case Runtime::kInlineToName: 177 case Runtime::kInlineToNumber: 178 case Runtime::kInlineToObject: 179 case Runtime::kInlineToPrimitive: 180 case Runtime::kInlineToPrimitive_Number: 181 case Runtime::kInlineToPrimitive_String: 182 case Runtime::kInlineToString: 183 return true; 184 default: 185 break; 186 } 187 188 // Most inlined runtime functions (except the ones listed above) can be called 189 // without a FrameState or will be lowered by JSIntrinsicLowering internally. 190 const Runtime::Function* const f = Runtime::FunctionForId(function); 191 if (f->intrinsic_type == Runtime::IntrinsicType::INLINE) return false; 192 193 return true; 194 } 195 196 197 bool CallDescriptor::UsesOnlyRegisters() const { 198 for (size_t i = 0; i < InputCount(); ++i) { 199 if (!GetInputLocation(i).IsRegister()) return false; 200 } 201 for (size_t i = 0; i < ReturnCount(); ++i) { 202 if (!GetReturnLocation(i).IsRegister()) return false; 203 } 204 return true; 205 } 206 207 208 CallDescriptor* Linkage::GetRuntimeCallDescriptor( 209 Zone* zone, Runtime::FunctionId function_id, int js_parameter_count, 210 Operator::Properties properties, CallDescriptor::Flags flags) { 211 const size_t function_count = 1; 212 const size_t num_args_count = 1; 213 const size_t context_count = 1; 214 const size_t parameter_count = function_count + 215 static_cast<size_t>(js_parameter_count) + 216 num_args_count + context_count; 217 218 const Runtime::Function* function = Runtime::FunctionForId(function_id); 219 const size_t return_count = static_cast<size_t>(function->result_size); 220 221 LocationSignature::Builder locations(zone, return_count, parameter_count); 222 MachineSignature::Builder types(zone, return_count, parameter_count); 223 224 // Add returns. 225 if (locations.return_count_ > 0) { 226 locations.AddReturn(regloc(kReturnRegister0)); 227 } 228 if (locations.return_count_ > 1) { 229 locations.AddReturn(regloc(kReturnRegister1)); 230 } 231 if (locations.return_count_ > 2) { 232 locations.AddReturn(regloc(kReturnRegister2)); 233 } 234 for (size_t i = 0; i < return_count; i++) { 235 types.AddReturn(MachineType::AnyTagged()); 236 } 237 238 // All parameters to the runtime call go on the stack. 239 for (int i = 0; i < js_parameter_count; i++) { 240 locations.AddParam( 241 LinkageLocation::ForCallerFrameSlot(i - js_parameter_count)); 242 types.AddParam(MachineType::AnyTagged()); 243 } 244 // Add runtime function itself. 245 locations.AddParam(regloc(kRuntimeCallFunctionRegister)); 246 types.AddParam(MachineType::AnyTagged()); 247 248 // Add runtime call argument count. 249 locations.AddParam(regloc(kRuntimeCallArgCountRegister)); 250 types.AddParam(MachineType::Pointer()); 251 252 // Add context. 253 locations.AddParam(regloc(kContextRegister)); 254 types.AddParam(MachineType::AnyTagged()); 255 256 if (!Linkage::NeedsFrameStateInput(function_id)) { 257 flags = static_cast<CallDescriptor::Flags>( 258 flags & ~CallDescriptor::kNeedsFrameState); 259 } 260 261 // The target for runtime calls is a code object. 262 MachineType target_type = MachineType::AnyTagged(); 263 LinkageLocation target_loc = LinkageLocation::ForAnyRegister(); 264 return new (zone) CallDescriptor( // -- 265 CallDescriptor::kCallCodeObject, // kind 266 target_type, // target MachineType 267 target_loc, // target location 268 types.Build(), // machine_sig 269 locations.Build(), // location_sig 270 js_parameter_count, // stack_parameter_count 271 properties, // properties 272 kNoCalleeSaved, // callee-saved 273 kNoCalleeSaved, // callee-saved fp 274 flags, // flags 275 function->name); // debug name 276 } 277 278 279 CallDescriptor* Linkage::GetJSCallDescriptor(Zone* zone, bool is_osr, 280 int js_parameter_count, 281 CallDescriptor::Flags flags) { 282 const size_t return_count = 1; 283 const size_t context_count = 1; 284 const size_t new_target_count = 1; 285 const size_t num_args_count = 1; 286 const size_t parameter_count = 287 js_parameter_count + new_target_count + num_args_count + context_count; 288 289 LocationSignature::Builder locations(zone, return_count, parameter_count); 290 MachineSignature::Builder types(zone, return_count, parameter_count); 291 292 // All JS calls have exactly one return value. 293 locations.AddReturn(regloc(kReturnRegister0)); 294 types.AddReturn(MachineType::AnyTagged()); 295 296 // All parameters to JS calls go on the stack. 297 for (int i = 0; i < js_parameter_count; i++) { 298 int spill_slot_index = i - js_parameter_count; 299 locations.AddParam(LinkageLocation::ForCallerFrameSlot(spill_slot_index)); 300 types.AddParam(MachineType::AnyTagged()); 301 } 302 303 // Add JavaScript call new target value. 304 locations.AddParam(regloc(kJavaScriptCallNewTargetRegister)); 305 types.AddParam(MachineType::AnyTagged()); 306 307 // Add JavaScript call argument count. 308 locations.AddParam(regloc(kJavaScriptCallArgCountRegister)); 309 types.AddParam(MachineType::Int32()); 310 311 // Add context. 312 locations.AddParam(regloc(kContextRegister)); 313 types.AddParam(MachineType::AnyTagged()); 314 315 // The target for JS function calls is the JSFunction object. 316 MachineType target_type = MachineType::AnyTagged(); 317 // When entering into an OSR function from unoptimized code the JSFunction 318 // is not in a register, but it is on the stack in the marker spill slot. 319 LinkageLocation target_loc = is_osr 320 ? LinkageLocation::ForSavedCallerFunction() 321 : regloc(kJSFunctionRegister); 322 return new (zone) CallDescriptor( // -- 323 CallDescriptor::kCallJSFunction, // kind 324 target_type, // target MachineType 325 target_loc, // target location 326 types.Build(), // machine_sig 327 locations.Build(), // location_sig 328 js_parameter_count, // stack_parameter_count 329 Operator::kNoProperties, // properties 330 kNoCalleeSaved, // callee-saved 331 kNoCalleeSaved, // callee-saved fp 332 CallDescriptor::kCanUseRoots | // flags 333 flags, // flags 334 "js-call"); 335 } 336 337 // TODO(all): Add support for return representations/locations to 338 // CallInterfaceDescriptor. 339 // TODO(turbofan): cache call descriptors for code stub calls. 340 CallDescriptor* Linkage::GetStubCallDescriptor( 341 Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor, 342 int stack_parameter_count, CallDescriptor::Flags flags, 343 Operator::Properties properties, MachineType return_type, 344 size_t return_count) { 345 const int register_parameter_count = descriptor.GetRegisterParameterCount(); 346 const int js_parameter_count = 347 register_parameter_count + stack_parameter_count; 348 const int context_count = 1; 349 const size_t parameter_count = 350 static_cast<size_t>(js_parameter_count + context_count); 351 352 LocationSignature::Builder locations(zone, return_count, parameter_count); 353 MachineSignature::Builder types(zone, return_count, parameter_count); 354 355 // Add returns. 356 if (locations.return_count_ > 0) { 357 locations.AddReturn(regloc(kReturnRegister0)); 358 } 359 if (locations.return_count_ > 1) { 360 locations.AddReturn(regloc(kReturnRegister1)); 361 } 362 if (locations.return_count_ > 2) { 363 locations.AddReturn(regloc(kReturnRegister2)); 364 } 365 for (size_t i = 0; i < return_count; i++) { 366 types.AddReturn(return_type); 367 } 368 369 // Add parameters in registers and on the stack. 370 for (int i = 0; i < js_parameter_count; i++) { 371 if (i < register_parameter_count) { 372 // The first parameters go in registers. 373 Register reg = descriptor.GetRegisterParameter(i); 374 Representation rep = 375 RepresentationFromType(descriptor.GetParameterType(i)); 376 locations.AddParam(regloc(reg)); 377 types.AddParam(reptyp(rep)); 378 } else { 379 // The rest of the parameters go on the stack. 380 int stack_slot = i - register_parameter_count - stack_parameter_count; 381 locations.AddParam(LinkageLocation::ForCallerFrameSlot(stack_slot)); 382 types.AddParam(MachineType::AnyTagged()); 383 } 384 } 385 // Add context. 386 locations.AddParam(regloc(kContextRegister)); 387 types.AddParam(MachineType::AnyTagged()); 388 389 // The target for stub calls is a code object. 390 MachineType target_type = MachineType::AnyTagged(); 391 LinkageLocation target_loc = LinkageLocation::ForAnyRegister(); 392 return new (zone) CallDescriptor( // -- 393 CallDescriptor::kCallCodeObject, // kind 394 target_type, // target MachineType 395 target_loc, // target location 396 types.Build(), // machine_sig 397 locations.Build(), // location_sig 398 stack_parameter_count, // stack_parameter_count 399 properties, // properties 400 kNoCalleeSaved, // callee-saved registers 401 kNoCalleeSaved, // callee-saved fp 402 CallDescriptor::kCanUseRoots | // flags 403 flags, // flags 404 descriptor.DebugName(isolate)); 405 } 406 407 // static 408 CallDescriptor* Linkage::GetAllocateCallDescriptor(Zone* zone) { 409 LocationSignature::Builder locations(zone, 1, 1); 410 MachineSignature::Builder types(zone, 1, 1); 411 412 locations.AddParam(regloc(kAllocateSizeRegister)); 413 types.AddParam(MachineType::Int32()); 414 415 locations.AddReturn(regloc(kReturnRegister0)); 416 types.AddReturn(MachineType::AnyTagged()); 417 418 // The target for allocate calls is a code object. 419 MachineType target_type = MachineType::AnyTagged(); 420 LinkageLocation target_loc = LinkageLocation::ForAnyRegister(); 421 return new (zone) CallDescriptor( // -- 422 CallDescriptor::kCallCodeObject, // kind 423 target_type, // target MachineType 424 target_loc, // target location 425 types.Build(), // machine_sig 426 locations.Build(), // location_sig 427 0, // stack_parameter_count 428 Operator::kNoThrow, // properties 429 kNoCalleeSaved, // callee-saved registers 430 kNoCalleeSaved, // callee-saved fp 431 CallDescriptor::kCanUseRoots, // flags 432 "Allocate"); 433 } 434 435 // static 436 CallDescriptor* Linkage::GetBytecodeDispatchCallDescriptor( 437 Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor, 438 int stack_parameter_count) { 439 const int register_parameter_count = descriptor.GetRegisterParameterCount(); 440 const int parameter_count = register_parameter_count + stack_parameter_count; 441 442 LocationSignature::Builder locations(zone, 0, parameter_count); 443 MachineSignature::Builder types(zone, 0, parameter_count); 444 445 // Add parameters in registers and on the stack. 446 for (int i = 0; i < parameter_count; i++) { 447 if (i < register_parameter_count) { 448 // The first parameters go in registers. 449 Register reg = descriptor.GetRegisterParameter(i); 450 Representation rep = 451 RepresentationFromType(descriptor.GetParameterType(i)); 452 locations.AddParam(regloc(reg)); 453 types.AddParam(reptyp(rep)); 454 } else { 455 // The rest of the parameters go on the stack. 456 int stack_slot = i - register_parameter_count - stack_parameter_count; 457 locations.AddParam(LinkageLocation::ForCallerFrameSlot(stack_slot)); 458 types.AddParam(MachineType::AnyTagged()); 459 } 460 } 461 462 // The target for interpreter dispatches is a code entry address. 463 MachineType target_type = MachineType::Pointer(); 464 LinkageLocation target_loc = LinkageLocation::ForAnyRegister(); 465 return new (zone) CallDescriptor( // -- 466 CallDescriptor::kCallAddress, // kind 467 target_type, // target MachineType 468 target_loc, // target location 469 types.Build(), // machine_sig 470 locations.Build(), // location_sig 471 stack_parameter_count, // stack_parameter_count 472 Operator::kNoProperties, // properties 473 kNoCalleeSaved, // callee-saved registers 474 kNoCalleeSaved, // callee-saved fp 475 CallDescriptor::kCanUseRoots | // flags 476 CallDescriptor::kSupportsTailCalls, // flags 477 descriptor.DebugName(isolate)); 478 } 479 480 LinkageLocation Linkage::GetOsrValueLocation(int index) const { 481 CHECK(incoming_->IsJSFunctionCall()); 482 int parameter_count = static_cast<int>(incoming_->JSParameterCount() - 1); 483 int first_stack_slot = OsrHelper::FirstStackSlotIndex(parameter_count); 484 485 if (index == kOsrContextSpillSlotIndex) { 486 // Context. Use the parameter location of the context spill slot. 487 // Parameter (arity + 2) is special for the context of the function frame. 488 // >> context_index = target + receiver + params + new_target + #args 489 int context_index = 1 + 1 + parameter_count + 1 + 1; 490 return incoming_->GetInputLocation(context_index); 491 } else if (index >= first_stack_slot) { 492 // Local variable stored in this (callee) stack. 493 int spill_index = 494 index - first_stack_slot + StandardFrameConstants::kFixedSlotCount; 495 return LinkageLocation::ForCalleeFrameSlot(spill_index); 496 } else { 497 // Parameter. Use the assigned location from the incoming call descriptor. 498 int parameter_index = 1 + index; // skip index 0, which is the target. 499 return incoming_->GetInputLocation(parameter_index); 500 } 501 } 502 503 504 bool Linkage::ParameterHasSecondaryLocation(int index) const { 505 if (!incoming_->IsJSFunctionCall()) return false; 506 LinkageLocation loc = GetParameterLocation(index); 507 return (loc == regloc(kJSFunctionRegister) || 508 loc == regloc(kContextRegister)); 509 } 510 511 LinkageLocation Linkage::GetParameterSecondaryLocation(int index) const { 512 DCHECK(ParameterHasSecondaryLocation(index)); 513 LinkageLocation loc = GetParameterLocation(index); 514 515 if (loc == regloc(kJSFunctionRegister)) { 516 return LinkageLocation::ForCalleeFrameSlot(Frame::kJSFunctionSlot); 517 } else { 518 DCHECK(loc == regloc(kContextRegister)); 519 return LinkageLocation::ForCalleeFrameSlot(Frame::kContextSlot); 520 } 521 } 522 523 524 } // namespace compiler 525 } // namespace internal 526 } // namespace v8 527