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/compiler/frame.h" 11 #include "src/compiler/operator.h" 12 #include "src/globals.h" 13 #include "src/interface-descriptors.h" 14 #include "src/machine-type.h" 15 #include "src/reglist.h" 16 #include "src/runtime/runtime.h" 17 #include "src/signature.h" 18 #include "src/zone/zone.h" 19 20 namespace v8 { 21 namespace internal { 22 23 class CallInterfaceDescriptor; 24 class OptimizedCompilationInfo; 25 26 namespace compiler { 27 28 const RegList kNoCalleeSaved = 0; 29 30 class Node; 31 class OsrHelper; 32 33 // Describes the location for a parameter or a return value to a call. 34 class LinkageLocation { 35 public: 36 bool operator==(const LinkageLocation& other) const { 37 return bit_field_ == other.bit_field_; 38 } 39 40 bool operator!=(const LinkageLocation& other) const { 41 return !(*this == other); 42 } 43 44 static LinkageLocation ForAnyRegister( 45 MachineType type = MachineType::None()) { 46 return LinkageLocation(REGISTER, ANY_REGISTER, type); 47 } 48 49 static LinkageLocation ForRegister(int32_t reg, 50 MachineType type = MachineType::None()) { 51 DCHECK_LE(0, reg); 52 return LinkageLocation(REGISTER, reg, type); 53 } 54 55 static LinkageLocation ForCallerFrameSlot(int32_t slot, MachineType type) { 56 DCHECK_GT(0, slot); 57 return LinkageLocation(STACK_SLOT, slot, type); 58 } 59 60 static LinkageLocation ForCalleeFrameSlot(int32_t slot, MachineType type) { 61 // TODO(titzer): bailout instead of crashing here. 62 DCHECK(slot >= 0 && slot < LinkageLocation::MAX_STACK_SLOT); 63 return LinkageLocation(STACK_SLOT, slot, type); 64 } 65 66 static LinkageLocation ForSavedCallerReturnAddress() { 67 return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset - 68 StandardFrameConstants::kCallerPCOffset) / 69 kPointerSize, 70 MachineType::Pointer()); 71 } 72 73 static LinkageLocation ForSavedCallerFramePtr() { 74 return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset - 75 StandardFrameConstants::kCallerFPOffset) / 76 kPointerSize, 77 MachineType::Pointer()); 78 } 79 80 static LinkageLocation ForSavedCallerConstantPool() { 81 DCHECK(V8_EMBEDDED_CONSTANT_POOL); 82 return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset - 83 StandardFrameConstants::kConstantPoolOffset) / 84 kPointerSize, 85 MachineType::AnyTagged()); 86 } 87 88 static LinkageLocation ForSavedCallerFunction() { 89 return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset - 90 StandardFrameConstants::kFunctionOffset) / 91 kPointerSize, 92 MachineType::AnyTagged()); 93 } 94 95 static LinkageLocation ConvertToTailCallerLocation( 96 LinkageLocation caller_location, int stack_param_delta) { 97 if (!caller_location.IsRegister()) { 98 return LinkageLocation(STACK_SLOT, 99 caller_location.GetLocation() + stack_param_delta, 100 caller_location.GetType()); 101 } 102 return caller_location; 103 } 104 105 MachineType GetType() const { return machine_type_; } 106 107 int GetSize() const { 108 return 1 << ElementSizeLog2Of(GetType().representation()); 109 } 110 111 int GetSizeInPointers() const { 112 // Round up 113 return (GetSize() + kPointerSize - 1) / kPointerSize; 114 } 115 116 int32_t GetLocation() const { 117 // We can't use LocationField::decode here because it doesn't work for 118 // negative values! 119 return static_cast<int32_t>(bit_field_ & LocationField::kMask) >> 120 LocationField::kShift; 121 } 122 123 bool IsRegister() const { return TypeField::decode(bit_field_) == REGISTER; } 124 bool IsAnyRegister() const { 125 return IsRegister() && GetLocation() == ANY_REGISTER; 126 } 127 bool IsCallerFrameSlot() const { return !IsRegister() && GetLocation() < 0; } 128 bool IsCalleeFrameSlot() const { return !IsRegister() && GetLocation() >= 0; } 129 130 int32_t AsRegister() const { 131 DCHECK(IsRegister()); 132 return GetLocation(); 133 } 134 int32_t AsCallerFrameSlot() const { 135 DCHECK(IsCallerFrameSlot()); 136 return GetLocation(); 137 } 138 int32_t AsCalleeFrameSlot() const { 139 DCHECK(IsCalleeFrameSlot()); 140 return GetLocation(); 141 } 142 143 private: 144 enum LocationType { REGISTER, STACK_SLOT }; 145 146 class TypeField : public BitField<LocationType, 0, 1> {}; 147 class LocationField : public BitField<int32_t, TypeField::kNext, 31> {}; 148 149 static constexpr int32_t ANY_REGISTER = -1; 150 static constexpr int32_t MAX_STACK_SLOT = 32767; 151 152 LinkageLocation(LocationType type, int32_t location, 153 MachineType machine_type) { 154 bit_field_ = TypeField::encode(type) | 155 ((location << LocationField::kShift) & LocationField::kMask); 156 machine_type_ = machine_type; 157 } 158 159 int32_t bit_field_; 160 MachineType machine_type_; 161 }; 162 163 typedef Signature<LinkageLocation> LocationSignature; 164 165 // Describes a call to various parts of the compiler. Every call has the notion 166 // of a "target", which is the first input to the call. 167 class V8_EXPORT_PRIVATE CallDescriptor final 168 : public NON_EXPORTED_BASE(ZoneObject) { 169 public: 170 // Describes the kind of this call, which determines the target. 171 enum Kind { 172 kCallCodeObject, // target is a Code object 173 kCallJSFunction, // target is a JSFunction object 174 kCallAddress, // target is a machine pointer 175 kCallWasmFunction // target is a wasm function 176 }; 177 178 enum Flag { 179 kNoFlags = 0u, 180 kNeedsFrameState = 1u << 0, 181 kHasExceptionHandler = 1u << 1, 182 kCanUseRoots = 1u << 2, 183 // Causes the code generator to initialize the root register. 184 kInitializeRootRegister = 1u << 3, 185 // Does not ever try to allocate space on our heap. 186 kNoAllocate = 1u << 4, 187 // Push argument count as part of function prologue. 188 kPushArgumentCount = 1u << 5, 189 // Use retpoline for this call if indirect. 190 kRetpoline = 1u << 6, 191 // Use the kJavaScriptCallCodeStartRegister (fixed) register for the 192 // indirect target address when calling. 193 kFixedTargetRegister = 1u << 7 194 }; 195 typedef base::Flags<Flag> Flags; 196 197 CallDescriptor(Kind kind, MachineType target_type, LinkageLocation target_loc, 198 LocationSignature* location_sig, size_t stack_param_count, 199 Operator::Properties properties, 200 RegList callee_saved_registers, 201 RegList callee_saved_fp_registers, Flags flags, 202 const char* debug_name = "", 203 const RegList allocatable_registers = 0, 204 size_t stack_return_count = 0) 205 : kind_(kind), 206 target_type_(target_type), 207 target_loc_(target_loc), 208 location_sig_(location_sig), 209 stack_param_count_(stack_param_count), 210 stack_return_count_(stack_return_count), 211 properties_(properties), 212 callee_saved_registers_(callee_saved_registers), 213 callee_saved_fp_registers_(callee_saved_fp_registers), 214 allocatable_registers_(allocatable_registers), 215 flags_(flags), 216 debug_name_(debug_name) {} 217 218 // Returns the kind of this call. 219 Kind kind() const { return kind_; } 220 221 // Returns {true} if this descriptor is a call to a C function. 222 bool IsCFunctionCall() const { return kind_ == kCallAddress; } 223 224 // Returns {true} if this descriptor is a call to a JSFunction. 225 bool IsJSFunctionCall() const { return kind_ == kCallJSFunction; } 226 227 // Returns {true} if this descriptor is a call to a WebAssembly function. 228 bool IsWasmFunctionCall() const { return kind_ == kCallWasmFunction; } 229 230 bool RequiresFrameAsIncoming() const { 231 return IsCFunctionCall() || IsJSFunctionCall() || IsWasmFunctionCall(); 232 } 233 234 // The number of return values from this call. 235 size_t ReturnCount() const { return location_sig_->return_count(); } 236 237 // The number of C parameters to this call. 238 size_t ParameterCount() const { return location_sig_->parameter_count(); } 239 240 // The number of stack parameters to the call. 241 size_t StackParameterCount() const { return stack_param_count_; } 242 243 // The number of stack return values from the call. 244 size_t StackReturnCount() const { return stack_return_count_; } 245 246 // The number of parameters to the JS function call. 247 size_t JSParameterCount() const { 248 DCHECK(IsJSFunctionCall()); 249 return stack_param_count_; 250 } 251 252 // The total number of inputs to this call, which includes the target, 253 // receiver, context, etc. 254 // TODO(titzer): this should input the framestate input too. 255 size_t InputCount() const { return 1 + location_sig_->parameter_count(); } 256 257 size_t FrameStateCount() const { return NeedsFrameState() ? 1 : 0; } 258 259 Flags flags() const { return flags_; } 260 261 bool NeedsFrameState() const { return flags() & kNeedsFrameState; } 262 bool PushArgumentCount() const { return flags() & kPushArgumentCount; } 263 bool InitializeRootRegister() const { 264 return flags() & kInitializeRootRegister; 265 } 266 267 LinkageLocation GetReturnLocation(size_t index) const { 268 return location_sig_->GetReturn(index); 269 } 270 271 LinkageLocation GetInputLocation(size_t index) const { 272 if (index == 0) return target_loc_; 273 return location_sig_->GetParam(index - 1); 274 } 275 276 MachineSignature* GetMachineSignature(Zone* zone) const; 277 278 MachineType GetReturnType(size_t index) const { 279 return location_sig_->GetReturn(index).GetType(); 280 } 281 282 MachineType GetInputType(size_t index) const { 283 if (index == 0) return target_type_; 284 return location_sig_->GetParam(index - 1).GetType(); 285 } 286 287 MachineType GetParameterType(size_t index) const { 288 return location_sig_->GetParam(index).GetType(); 289 } 290 291 // Operator properties describe how this call can be optimized, if at all. 292 Operator::Properties properties() const { return properties_; } 293 294 // Get the callee-saved registers, if any, across this call. 295 RegList CalleeSavedRegisters() const { return callee_saved_registers_; } 296 297 // Get the callee-saved FP registers, if any, across this call. 298 RegList CalleeSavedFPRegisters() const { return callee_saved_fp_registers_; } 299 300 const char* debug_name() const { return debug_name_; } 301 302 bool UsesOnlyRegisters() const; 303 304 bool HasSameReturnLocationsAs(const CallDescriptor* other) const; 305 306 // Returns the first stack slot that is not used by the stack parameters. 307 int GetFirstUnusedStackSlot() const; 308 309 int GetStackParameterDelta(const CallDescriptor* tail_caller) const; 310 311 bool CanTailCall(const Node* call) const; 312 313 int CalculateFixedFrameSize() const; 314 315 RegList AllocatableRegisters() const { return allocatable_registers_; } 316 317 bool HasRestrictedAllocatableRegisters() const { 318 return allocatable_registers_ != 0; 319 } 320 321 void set_save_fp_mode(SaveFPRegsMode mode) { save_fp_mode_ = mode; } 322 323 SaveFPRegsMode get_save_fp_mode() const { return save_fp_mode_; } 324 325 private: 326 friend class Linkage; 327 SaveFPRegsMode save_fp_mode_ = kSaveFPRegs; 328 329 const Kind kind_; 330 const MachineType target_type_; 331 const LinkageLocation target_loc_; 332 const LocationSignature* const location_sig_; 333 const size_t stack_param_count_; 334 const size_t stack_return_count_; 335 const Operator::Properties properties_; 336 const RegList callee_saved_registers_; 337 const RegList callee_saved_fp_registers_; 338 // Non-zero value means restricting the set of allocatable registers for 339 // register allocator to use. 340 const RegList allocatable_registers_; 341 const Flags flags_; 342 const char* const debug_name_; 343 344 DISALLOW_COPY_AND_ASSIGN(CallDescriptor); 345 }; 346 347 DEFINE_OPERATORS_FOR_FLAGS(CallDescriptor::Flags) 348 349 std::ostream& operator<<(std::ostream& os, const CallDescriptor& d); 350 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, 351 const CallDescriptor::Kind& k); 352 353 // Defines the linkage for a compilation, including the calling conventions 354 // for incoming parameters and return value(s) as well as the outgoing calling 355 // convention for any kind of call. Linkage is generally architecture-specific. 356 // 357 // Can be used to translate {arg_index} (i.e. index of the call node input) as 358 // well as {param_index} (i.e. as stored in parameter nodes) into an operator 359 // representing the architecture-specific location. The following call node 360 // layouts are supported (where {n} is the number of value inputs): 361 // 362 // #0 #1 #2 [...] #n 363 // Call[CodeStub] code, arg 1, arg 2, [...], context 364 // Call[JSFunction] function, rcvr, arg 1, [...], new, #arg, context 365 // Call[Runtime] CEntry, arg 1, arg 2, [...], fun, #arg, context 366 // Call[BytecodeDispatch] address, arg 1, arg 2, [...] 367 class V8_EXPORT_PRIVATE Linkage : public NON_EXPORTED_BASE(ZoneObject) { 368 public: 369 explicit Linkage(CallDescriptor* incoming) : incoming_(incoming) {} 370 371 static CallDescriptor* ComputeIncoming(Zone* zone, 372 OptimizedCompilationInfo* info); 373 374 // The call descriptor for this compilation unit describes the locations 375 // of incoming parameters and the outgoing return value(s). 376 CallDescriptor* GetIncomingDescriptor() const { return incoming_; } 377 static CallDescriptor* GetJSCallDescriptor(Zone* zone, bool is_osr, 378 int parameter_count, 379 CallDescriptor::Flags flags); 380 381 static CallDescriptor* GetRuntimeCallDescriptor( 382 Zone* zone, Runtime::FunctionId function, int js_parameter_count, 383 Operator::Properties properties, CallDescriptor::Flags flags); 384 385 static CallDescriptor* GetCEntryStubCallDescriptor( 386 Zone* zone, int return_count, int js_parameter_count, 387 const char* debug_name, Operator::Properties properties, 388 CallDescriptor::Flags flags); 389 390 static CallDescriptor* GetStubCallDescriptor( 391 Zone* zone, const CallInterfaceDescriptor& descriptor, 392 int stack_parameter_count, CallDescriptor::Flags flags, 393 Operator::Properties properties = Operator::kNoProperties, 394 StubCallMode stub_mode = StubCallMode::kCallOnHeapBuiltin); 395 396 static CallDescriptor* GetBytecodeDispatchCallDescriptor( 397 Zone* zone, const CallInterfaceDescriptor& descriptor, 398 int stack_parameter_count); 399 400 // Creates a call descriptor for simplified C calls that is appropriate 401 // for the host platform. This simplified calling convention only supports 402 // integers and pointers of one word size each, i.e. no floating point, 403 // structs, pointers to members, etc. 404 static CallDescriptor* GetSimplifiedCDescriptor( 405 Zone* zone, const MachineSignature* sig, 406 bool set_initialize_root_flag = false); 407 408 // Get the location of an (incoming) parameter to this function. 409 LinkageLocation GetParameterLocation(int index) const { 410 return incoming_->GetInputLocation(index + 1); // + 1 to skip target. 411 } 412 413 // Get the machine type of an (incoming) parameter to this function. 414 MachineType GetParameterType(int index) const { 415 return incoming_->GetInputType(index + 1); // + 1 to skip target. 416 } 417 418 // Get the location where this function should place its return value. 419 LinkageLocation GetReturnLocation(size_t index = 0) const { 420 return incoming_->GetReturnLocation(index); 421 } 422 423 // Get the machine type of this function's return value. 424 MachineType GetReturnType(size_t index = 0) const { 425 return incoming_->GetReturnType(index); 426 } 427 428 bool ParameterHasSecondaryLocation(int index) const; 429 LinkageLocation GetParameterSecondaryLocation(int index) const; 430 431 static bool NeedsFrameStateInput(Runtime::FunctionId function); 432 433 // Get the location where an incoming OSR value is stored. 434 LinkageLocation GetOsrValueLocation(int index) const; 435 436 // A special {Parameter} index for Stub Calls that represents context. 437 static int GetStubCallContextParamIndex(int parameter_count) { 438 return parameter_count + 0; // Parameter (arity + 0) is special. 439 } 440 441 // A special {Parameter} index for JSCalls that represents the new target. 442 static int GetJSCallNewTargetParamIndex(int parameter_count) { 443 return parameter_count + 0; // Parameter (arity + 0) is special. 444 } 445 446 // A special {Parameter} index for JSCalls that represents the argument count. 447 static int GetJSCallArgCountParamIndex(int parameter_count) { 448 return parameter_count + 1; // Parameter (arity + 1) is special. 449 } 450 451 // A special {Parameter} index for JSCalls that represents the context. 452 static int GetJSCallContextParamIndex(int parameter_count) { 453 return parameter_count + 2; // Parameter (arity + 2) is special. 454 } 455 456 // A special {Parameter} index for JSCalls that represents the closure. 457 static const int kJSCallClosureParamIndex = -1; 458 459 // A special {OsrValue} index to indicate the context spill slot. 460 static const int kOsrContextSpillSlotIndex = -1; 461 462 // A special {OsrValue} index to indicate the accumulator register. 463 static const int kOsrAccumulatorRegisterIndex = -1; 464 465 private: 466 CallDescriptor* const incoming_; 467 468 DISALLOW_COPY_AND_ASSIGN(Linkage); 469 }; 470 471 } // namespace compiler 472 } // namespace internal 473 } // namespace v8 474 475 #endif // V8_COMPILER_LINKAGE_H_ 476