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