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#ifndef V8_COMPILER_LINKAGE_H_ 6#define V8_COMPILER_LINKAGE_H_ 7 8#include "src/base/compiler-specific.h" 9#include "src/base/flags.h" 10#include "src/codegen/interface-descriptors.h" 11#include "src/codegen/machine-type.h" 12#include "src/codegen/register.h" 13#include "src/codegen/reglist.h" 14#include "src/codegen/signature.h" 15#include "src/common/globals.h" 16#include "src/compiler/frame.h" 17#include "src/compiler/operator.h" 18#include "src/execution/encoded-c-signature.h" 19#include "src/runtime/runtime.h" 20#include "src/zone/zone.h" 21 22#if !defined(__clang__) && defined(_M_ARM64) 23// _M_ARM64 is an MSVC-specific macro that clang-cl emulates. 24#define NO_INLINE_FOR_ARM64_MSVC __declspec(noinline) 25#else 26#define NO_INLINE_FOR_ARM64_MSVC 27#endif 28 29namespace v8 { 30class CFunctionInfo; 31 32namespace internal { 33 34class CallInterfaceDescriptor; 35class OptimizedCompilationInfo; 36 37namespace compiler { 38 39constexpr RegList kNoCalleeSaved; 40constexpr DoubleRegList kNoCalleeSavedFp; 41 42class OsrHelper; 43 44// Describes the location for a parameter or a return value to a call. 45class LinkageLocation { 46 public: 47 bool operator==(const LinkageLocation& other) const { 48 return bit_field_ == other.bit_field_ && 49 machine_type_ == other.machine_type_; 50 } 51 52 bool operator!=(const LinkageLocation& other) const { 53 return !(*this == other); 54 } 55 56 static bool IsSameLocation(const LinkageLocation& a, 57 const LinkageLocation& b) { 58 // Different MachineTypes may end up at the same physical location. With the 59 // sub-type check we make sure that types like {AnyTagged} and 60 // {TaggedPointer} which would end up with the same physical location are 61 // considered equal here. 62 return (a.bit_field_ == b.bit_field_) && 63 (IsSubtype(a.machine_type_.representation(), 64 b.machine_type_.representation()) || 65 IsSubtype(b.machine_type_.representation(), 66 a.machine_type_.representation())); 67 } 68 69 static LinkageLocation ForAnyRegister( 70 MachineType type = MachineType::None()) { 71 return LinkageLocation(REGISTER, ANY_REGISTER, type); 72 } 73 74 static LinkageLocation ForRegister(int32_t reg, 75 MachineType type = MachineType::None()) { 76 DCHECK_LE(0, reg); 77 return LinkageLocation(REGISTER, reg, type); 78 } 79 80 static LinkageLocation ForCallerFrameSlot(int32_t slot, MachineType type) { 81 DCHECK_GT(0, slot); 82 return LinkageLocation(STACK_SLOT, slot, type); 83 } 84 85 static LinkageLocation ForCalleeFrameSlot(int32_t slot, MachineType type) { 86 // TODO(titzer): bailout instead of crashing here. 87 DCHECK(slot >= 0 && slot < LinkageLocation::MAX_STACK_SLOT); 88 return LinkageLocation(STACK_SLOT, slot, type); 89 } 90 91 static LinkageLocation ForSavedCallerReturnAddress() { 92 return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset - 93 StandardFrameConstants::kCallerPCOffset) / 94 kSystemPointerSize, 95 MachineType::Pointer()); 96 } 97 98 static LinkageLocation ForSavedCallerFramePtr() { 99 return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset - 100 StandardFrameConstants::kCallerFPOffset) / 101 kSystemPointerSize, 102 MachineType::Pointer()); 103 } 104 105 static LinkageLocation ForSavedCallerConstantPool() { 106 DCHECK(V8_EMBEDDED_CONSTANT_POOL); 107 return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset - 108 StandardFrameConstants::kConstantPoolOffset) / 109 kSystemPointerSize, 110 MachineType::AnyTagged()); 111 } 112 113 static LinkageLocation ForSavedCallerFunction() { 114 return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset - 115 StandardFrameConstants::kFunctionOffset) / 116 kSystemPointerSize, 117 MachineType::AnyTagged()); 118 } 119 120 static LinkageLocation ConvertToTailCallerLocation( 121 LinkageLocation caller_location, int stack_param_delta) { 122 if (!caller_location.IsRegister()) { 123 return LinkageLocation(STACK_SLOT, 124 caller_location.GetLocation() + stack_param_delta, 125 caller_location.GetType()); 126 } 127 return caller_location; 128 } 129 130 MachineType GetType() const { return machine_type_; } 131 132 int GetSizeInPointers() const { 133 return ElementSizeInPointers(GetType().representation()); 134 } 135 136 int32_t GetLocation() const { 137 // We can't use LocationField::decode here because it doesn't work for 138 // negative values! 139 return static_cast<int32_t>(bit_field_ & LocationField::kMask) >> 140 LocationField::kShift; 141 } 142 143 NO_INLINE_FOR_ARM64_MSVC bool IsRegister() const { 144 return TypeField::decode(bit_field_) == REGISTER; 145 } 146 bool IsAnyRegister() const { 147 return IsRegister() && GetLocation() == ANY_REGISTER; 148 } 149 bool IsCallerFrameSlot() const { return !IsRegister() && GetLocation() < 0; } 150 bool IsCalleeFrameSlot() const { return !IsRegister() && GetLocation() >= 0; } 151 152 int32_t AsRegister() const { 153 DCHECK(IsRegister()); 154 return GetLocation(); 155 } 156 int32_t AsCallerFrameSlot() const { 157 DCHECK(IsCallerFrameSlot()); 158 return GetLocation(); 159 } 160 int32_t AsCalleeFrameSlot() const { 161 DCHECK(IsCalleeFrameSlot()); 162 return GetLocation(); 163 } 164 165 private: 166 enum LocationType { REGISTER, STACK_SLOT }; 167 168 using TypeField = base::BitField<LocationType, 0, 1>; 169 using LocationField = TypeField::Next<int32_t, 31>; 170 171 static constexpr int32_t ANY_REGISTER = -1; 172 static constexpr int32_t MAX_STACK_SLOT = 32767; 173 174 LinkageLocation(LocationType type, int32_t location, 175 MachineType machine_type) { 176 bit_field_ = TypeField::encode(type) | 177 // {location} can be -1 (ANY_REGISTER). 178 ((static_cast<uint32_t>(location) << LocationField::kShift) & 179 LocationField::kMask); 180 machine_type_ = machine_type; 181 } 182 183 int32_t bit_field_; 184 MachineType machine_type_; 185}; 186 187using LocationSignature = Signature<LinkageLocation>; 188 189// Describes a call to various parts of the compiler. Every call has the notion 190// of a "target", which is the first input to the call. 191class V8_EXPORT_PRIVATE CallDescriptor final 192 : public NON_EXPORTED_BASE(ZoneObject) { 193 public: 194 // Describes the kind of this call, which determines the target. 195 enum Kind { 196 kCallCodeObject, // target is a Code object 197 kCallJSFunction, // target is a JSFunction object 198 kCallAddress, // target is a machine pointer 199#if V8_ENABLE_WEBASSEMBLY // ↓ WebAssembly only 200 kCallWasmCapiFunction, // target is a Wasm C API function 201 kCallWasmFunction, // target is a wasm function 202 kCallWasmImportWrapper, // target is a wasm import wrapper 203#endif // ↑ WebAssembly only 204 kCallBuiltinPointer, // target is a builtin pointer 205 }; 206 207 // NOTE: The lowest 10 bits of the Flags field are encoded in InstructionCode 208 // (for use in the code generator). All higher bits are lost. 209 static constexpr int kFlagsBitsEncodedInInstructionCode = 10; 210 enum Flag { 211 kNoFlags = 0u, 212 kNeedsFrameState = 1u << 0, 213 kHasExceptionHandler = 1u << 1, 214 kCanUseRoots = 1u << 2, 215 // Causes the code generator to initialize the root register. 216 kInitializeRootRegister = 1u << 3, 217 // Does not ever try to allocate space on our heap. 218 kNoAllocate = 1u << 4, 219 // Use the kJavaScriptCallCodeStartRegister (fixed) register for the 220 // indirect target address when calling. 221 kFixedTargetRegister = 1u << 5, 222 kCallerSavedRegisters = 1u << 6, 223 // The kCallerSavedFPRegisters only matters (and set) when the more general 224 // flag for kCallerSavedRegisters above is also set. 225 kCallerSavedFPRegisters = 1u << 7, 226 // Tail calls for tier up are special (in fact they are different enough 227 // from normal tail calls to warrant a dedicated opcode; but they also have 228 // enough similar aspects that reusing the TailCall opcode is pragmatic). 229 // Specifically: 230 // 231 // 1. Caller and callee are both JS-linkage Code objects. 232 // 2. JS runtime arguments are passed unchanged from caller to callee. 233 // 3. JS runtime arguments are not attached as inputs to the TailCall node. 234 // 4. Prior to the tail call, frame and register state is torn down to just 235 // before the caller frame was constructed. 236 // 5. Unlike normal tail calls, arguments adaptor frames (if present) are 237 // *not* torn down. 238 // 239 // In other words, behavior is identical to a jmp instruction prior caller 240 // frame construction. 241 kIsTailCallForTierUp = 1u << 8, 242 243 // AIX has a function descriptor by default but it can be disabled for a 244 // certain CFunction call (only used for Kind::kCallAddress). 245 kNoFunctionDescriptor = 1u << 9, 246 247 // Flags past here are *not* encoded in InstructionCode and are thus not 248 // accessible from the code generator. See also 249 // kFlagsBitsEncodedInInstructionCode. 250 }; 251 using Flags = base::Flags<Flag>; 252 253 CallDescriptor(Kind kind, MachineType target_type, LinkageLocation target_loc, 254 LocationSignature* location_sig, size_t param_slot_count, 255 Operator::Properties properties, 256 RegList callee_saved_registers, 257 DoubleRegList callee_saved_fp_registers, Flags flags, 258 const char* debug_name = "", 259 StackArgumentOrder stack_order = StackArgumentOrder::kDefault, 260#if V8_ENABLE_WEBASSEMBLY 261 const wasm::FunctionSig* wasm_sig = nullptr, 262#endif 263 const RegList allocatable_registers = {}, 264 size_t return_slot_count = 0) 265 : kind_(kind), 266 target_type_(target_type), 267 target_loc_(target_loc), 268 location_sig_(location_sig), 269 param_slot_count_(param_slot_count), 270 return_slot_count_(return_slot_count), 271 properties_(properties), 272 callee_saved_registers_(callee_saved_registers), 273 callee_saved_fp_registers_(callee_saved_fp_registers), 274 allocatable_registers_(allocatable_registers), 275 flags_(flags), 276 stack_order_(stack_order), 277#if V8_ENABLE_WEBASSEMBLY 278 wasm_sig_(wasm_sig), 279#endif 280 debug_name_(debug_name) { 281 } 282 283 CallDescriptor(const CallDescriptor&) = delete; 284 CallDescriptor& operator=(const CallDescriptor&) = delete; 285 286 // Returns the kind of this call. 287 Kind kind() const { return kind_; } 288 289 // Returns {true} if this descriptor is a call to a C function. 290 bool IsCFunctionCall() const { return kind_ == kCallAddress; } 291 292 // Returns {true} if this descriptor is a call to a JSFunction. 293 bool IsJSFunctionCall() const { return kind_ == kCallJSFunction; } 294 295#if V8_ENABLE_WEBASSEMBLY 296 // Returns {true} if this descriptor is a call to a WebAssembly function. 297 bool IsWasmFunctionCall() const { return kind_ == kCallWasmFunction; } 298 299 // Returns {true} if this descriptor is a call to a WebAssembly function. 300 bool IsWasmImportWrapper() const { return kind_ == kCallWasmImportWrapper; } 301 302 // Returns {true} if this descriptor is a call to a Wasm C API function. 303 bool IsWasmCapiFunction() const { return kind_ == kCallWasmCapiFunction; } 304 305 // Returns the wasm signature for this call based on the real parameter types. 306 const wasm::FunctionSig* wasm_sig() const { return wasm_sig_; } 307#endif // V8_ENABLE_WEBASSEMBLY 308 309 bool RequiresFrameAsIncoming() const { 310 if (IsCFunctionCall() || IsJSFunctionCall()) return true; 311#if V8_ENABLE_WEBASSEMBLY 312 if (IsWasmFunctionCall()) return true; 313#endif // V8_ENABLE_WEBASSEMBLY 314 if (CalleeSavedRegisters() != kNoCalleeSaved) return true; 315 return false; 316 } 317 318 // The number of return values from this call. 319 size_t ReturnCount() const { return location_sig_->return_count(); } 320 321 // The number of C parameters to this call. The following invariant 322 // should hold true: 323 // ParameterCount() == GPParameterCount() + FPParameterCount() 324 size_t ParameterCount() const { return location_sig_->parameter_count(); } 325 326 // The number of general purpose C parameters to this call. 327 size_t GPParameterCount() const { 328 if (!gp_param_count_) { 329 ComputeParamCounts(); 330 } 331 return gp_param_count_.value(); 332 } 333 334 // The number of floating point C parameters to this call. 335 size_t FPParameterCount() const { 336 if (!fp_param_count_) { 337 ComputeParamCounts(); 338 } 339 return fp_param_count_.value(); 340 } 341 342 // The number of stack parameter slots to the call. 343 size_t ParameterSlotCount() const { return param_slot_count_; } 344 345 // The number of stack return value slots from the call. 346 size_t ReturnSlotCount() const { return return_slot_count_; } 347 348 // The number of parameters to the JS function call. 349 size_t JSParameterCount() const { 350 DCHECK(IsJSFunctionCall()); 351 return param_slot_count_; 352 } 353 354 int GetStackIndexFromSlot(int slot_index) const { 355 switch (GetStackArgumentOrder()) { 356 case StackArgumentOrder::kDefault: 357 return -slot_index - 1; 358 case StackArgumentOrder::kJS: 359 return slot_index + static_cast<int>(ParameterSlotCount()); 360 } 361 } 362 363 // The total number of inputs to this call, which includes the target, 364 // receiver, context, etc. 365 // TODO(titzer): this should input the framestate input too. 366 size_t InputCount() const { return 1 + location_sig_->parameter_count(); } 367 368 size_t FrameStateCount() const { return NeedsFrameState() ? 1 : 0; } 369 370 Flags flags() const { return flags_; } 371 372 bool NeedsFrameState() const { return flags() & kNeedsFrameState; } 373 bool InitializeRootRegister() const { 374 return flags() & kInitializeRootRegister; 375 } 376 bool NeedsCallerSavedRegisters() const { 377 return flags() & kCallerSavedRegisters; 378 } 379 bool NeedsCallerSavedFPRegisters() const { 380 return flags() & kCallerSavedFPRegisters; 381 } 382 bool IsTailCallForTierUp() const { return flags() & kIsTailCallForTierUp; } 383 bool NoFunctionDescriptor() const { return flags() & kNoFunctionDescriptor; } 384 385 LinkageLocation GetReturnLocation(size_t index) const { 386 return location_sig_->GetReturn(index); 387 } 388 389 LinkageLocation GetInputLocation(size_t index) const { 390 if (index == 0) return target_loc_; 391 return location_sig_->GetParam(index - 1); 392 } 393 394 MachineSignature* GetMachineSignature(Zone* zone) const; 395 396 MachineType GetReturnType(size_t index) const { 397 return location_sig_->GetReturn(index).GetType(); 398 } 399 400 MachineType GetInputType(size_t index) const { 401 if (index == 0) return target_type_; 402 return location_sig_->GetParam(index - 1).GetType(); 403 } 404 405 MachineType GetParameterType(size_t index) const { 406 return location_sig_->GetParam(index).GetType(); 407 } 408 409 StackArgumentOrder GetStackArgumentOrder() const { return stack_order_; } 410 411 // Operator properties describe how this call can be optimized, if at all. 412 Operator::Properties properties() const { return properties_; } 413 414 // Get the callee-saved registers, if any, across this call. 415 RegList CalleeSavedRegisters() const { return callee_saved_registers_; } 416 417 // Get the callee-saved FP registers, if any, across this call. 418 DoubleRegList CalleeSavedFPRegisters() const { 419 return callee_saved_fp_registers_; 420 } 421 422 const char* debug_name() const { return debug_name_; } 423 424 // Difference between the number of parameter slots of *this* and 425 // *tail_caller* (callee minus caller). 426 int GetStackParameterDelta(const CallDescriptor* tail_caller) const; 427 428 // Returns the offset to the area below the parameter slots on the stack, 429 // relative to callee slot 0, the return address. If there are no parameter 430 // slots, returns +1. 431 int GetOffsetToFirstUnusedStackSlot() const; 432 433 // Returns the offset to the area above the return slots on the stack, 434 // relative to callee slot 0, the return address. If there are no return 435 // slots, returns the offset to the lowest slot of the parameter area. 436 // If there are no parameter slots, returns 0. 437 int GetOffsetToReturns() const; 438 439 // Returns two 16-bit numbers packed together: (first slot << 16) | num_slots. 440 uint32_t GetTaggedParameterSlots() const; 441 442 bool CanTailCall(const CallDescriptor* callee) const; 443 444 int CalculateFixedFrameSize(CodeKind code_kind) const; 445 446 RegList AllocatableRegisters() const { return allocatable_registers_; } 447 448 bool HasRestrictedAllocatableRegisters() const { 449 return !allocatable_registers_.is_empty(); 450 } 451 452 EncodedCSignature ToEncodedCSignature() const; 453 454 private: 455 void ComputeParamCounts() const; 456 457 friend class Linkage; 458 459 const Kind kind_; 460 const MachineType target_type_; 461 const LinkageLocation target_loc_; 462 const LocationSignature* const location_sig_; 463 const size_t param_slot_count_; 464 const size_t return_slot_count_; 465 const Operator::Properties properties_; 466 const RegList callee_saved_registers_; 467 const DoubleRegList callee_saved_fp_registers_; 468 // Non-zero value means restricting the set of allocatable registers for 469 // register allocator to use. 470 const RegList allocatable_registers_; 471 const Flags flags_; 472 const StackArgumentOrder stack_order_; 473#if V8_ENABLE_WEBASSEMBLY 474 const wasm::FunctionSig* wasm_sig_; 475#endif 476 const char* const debug_name_; 477 478 mutable base::Optional<size_t> gp_param_count_; 479 mutable base::Optional<size_t> fp_param_count_; 480}; 481 482DEFINE_OPERATORS_FOR_FLAGS(CallDescriptor::Flags) 483 484std::ostream& operator<<(std::ostream& os, const CallDescriptor& d); 485V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, 486 const CallDescriptor::Kind& k); 487 488// Defines the linkage for a compilation, including the calling conventions 489// for incoming parameters and return value(s) as well as the outgoing calling 490// convention for any kind of call. Linkage is generally architecture-specific. 491// 492// Can be used to translate {arg_index} (i.e. index of the call node input) as 493// well as {param_index} (i.e. as stored in parameter nodes) into an operator 494// representing the architecture-specific location. The following call node 495// layouts are supported (where {n} is the number of value inputs): 496// 497// #0 #1 #2 [...] #n 498// Call[CodeStub] code, arg 1, arg 2, [...], context 499// Call[JSFunction] function, rcvr, arg 1, [...], new, #arg, context 500// Call[Runtime] CEntry, arg 1, arg 2, [...], fun, #arg, context 501// Call[BytecodeDispatch] address, arg 1, arg 2, [...] 502class V8_EXPORT_PRIVATE Linkage : public NON_EXPORTED_BASE(ZoneObject) { 503 public: 504 explicit Linkage(CallDescriptor* incoming) : incoming_(incoming) {} 505 Linkage(const Linkage&) = delete; 506 Linkage& operator=(const Linkage&) = delete; 507 508 static CallDescriptor* ComputeIncoming(Zone* zone, 509 OptimizedCompilationInfo* info); 510 511 // The call descriptor for this compilation unit describes the locations 512 // of incoming parameters and the outgoing return value(s). 513 CallDescriptor* GetIncomingDescriptor() const { return incoming_; } 514 static CallDescriptor* GetJSCallDescriptor(Zone* zone, bool is_osr, 515 int parameter_count, 516 CallDescriptor::Flags flags); 517 518 static CallDescriptor* GetRuntimeCallDescriptor( 519 Zone* zone, Runtime::FunctionId function, int js_parameter_count, 520 Operator::Properties properties, CallDescriptor::Flags flags); 521 522 static CallDescriptor* GetCEntryStubCallDescriptor( 523 Zone* zone, int return_count, int js_parameter_count, 524 const char* debug_name, Operator::Properties properties, 525 CallDescriptor::Flags flags, 526 StackArgumentOrder stack_order = StackArgumentOrder::kDefault); 527 528 static CallDescriptor* GetStubCallDescriptor( 529 Zone* zone, const CallInterfaceDescriptor& descriptor, 530 int stack_parameter_count, CallDescriptor::Flags flags, 531 Operator::Properties properties = Operator::kNoProperties, 532 StubCallMode stub_mode = StubCallMode::kCallCodeObject); 533 534 static CallDescriptor* GetBytecodeDispatchCallDescriptor( 535 Zone* zone, const CallInterfaceDescriptor& descriptor, 536 int stack_parameter_count); 537 538 // Creates a call descriptor for simplified C calls that is appropriate 539 // for the host platform. This simplified calling convention only supports 540 // integers and pointers of one word size each, i.e. no floating point, 541 // structs, pointers to members, etc. 542 static CallDescriptor* GetSimplifiedCDescriptor( 543 Zone* zone, const MachineSignature* sig, 544 CallDescriptor::Flags flags = CallDescriptor::kNoFlags); 545 546 // Get the location of an (incoming) parameter to this function. 547 LinkageLocation GetParameterLocation(int index) const { 548 return incoming_->GetInputLocation(index + 1); // + 1 to skip target. 549 } 550 551 // Get the machine type of an (incoming) parameter to this function. 552 MachineType GetParameterType(int index) const { 553 return incoming_->GetInputType(index + 1); // + 1 to skip target. 554 } 555 556 // Get the location where this function should place its return value. 557 LinkageLocation GetReturnLocation(size_t index = 0) const { 558 return incoming_->GetReturnLocation(index); 559 } 560 561 // Get the machine type of this function's return value. 562 MachineType GetReturnType(size_t index = 0) const { 563 return incoming_->GetReturnType(index); 564 } 565 566 bool ParameterHasSecondaryLocation(int index) const; 567 LinkageLocation GetParameterSecondaryLocation(int index) const; 568 569 static bool NeedsFrameStateInput(Runtime::FunctionId function); 570 571 // Get the location where an incoming OSR value is stored. 572 LinkageLocation GetOsrValueLocation(int index) const; 573 574 // A special {Parameter} index for Stub Calls that represents context. 575 static int GetStubCallContextParamIndex(int parameter_count) { 576 return parameter_count + 0; // Parameter (arity + 0) is special. 577 } 578 579 // A special {Parameter} index for JSCalls that represents the new target. 580 static constexpr int GetJSCallNewTargetParamIndex(int parameter_count) { 581 return parameter_count + 0; // Parameter (arity + 0) is special. 582 } 583 584 // A special {Parameter} index for JSCalls that represents the argument count. 585 static constexpr int GetJSCallArgCountParamIndex(int parameter_count) { 586 return parameter_count + 1; // Parameter (arity + 1) is special. 587 } 588 589 // A special {Parameter} index for JSCalls that represents the context. 590 static constexpr int GetJSCallContextParamIndex(int parameter_count) { 591 return parameter_count + 2; // Parameter (arity + 2) is special. 592 } 593 594 // A special {Parameter} index for JSCalls that represents the closure. 595 static constexpr int kJSCallClosureParamIndex = -1; 596 597 // A special {OsrValue} index to indicate the context spill slot. 598 static const int kOsrContextSpillSlotIndex = -1; 599 600 // A special {OsrValue} index to indicate the accumulator register. 601 static const int kOsrAccumulatorRegisterIndex = -1; 602 603 private: 604 CallDescriptor* const incoming_; 605}; 606 607} // namespace compiler 608} // namespace internal 609} // namespace v8 610#undef NO_INLINE_FOR_ARM64_MSVC 611 612#endif // V8_COMPILER_LINKAGE_H_ 613