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