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
ForCallerFrameSlot(int32_t slot,MachineType type)55 static LinkageLocation ForCallerFrameSlot(int32_t slot, MachineType type) {
56 DCHECK_GT(0, slot);
57 return LinkageLocation(STACK_SLOT, slot, type);
58 }
59
ForCalleeFrameSlot(int32_t slot,MachineType type)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
ForSavedCallerReturnAddress()66 static LinkageLocation ForSavedCallerReturnAddress() {
67 return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
68 StandardFrameConstants::kCallerPCOffset) /
69 kPointerSize,
70 MachineType::Pointer());
71 }
72
ForSavedCallerFramePtr()73 static LinkageLocation ForSavedCallerFramePtr() {
74 return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
75 StandardFrameConstants::kCallerFPOffset) /
76 kPointerSize,
77 MachineType::Pointer());
78 }
79
ForSavedCallerConstantPool()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
ForSavedCallerFunction()88 static LinkageLocation ForSavedCallerFunction() {
89 return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
90 StandardFrameConstants::kFunctionOffset) /
91 kPointerSize,
92 MachineType::AnyTagged());
93 }
94
ConvertToTailCallerLocation(LinkageLocation caller_location,int stack_param_delta)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
GetType()105 MachineType GetType() const { return machine_type_; }
106
GetSize()107 int GetSize() const {
108 return 1 << ElementSizeLog2Of(GetType().representation());
109 }
110
GetSizeInPointers()111 int GetSizeInPointers() const {
112 // Round up
113 return (GetSize() + kPointerSize - 1) / kPointerSize;
114 }
115
GetLocation()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
IsRegister()123 bool IsRegister() const { return TypeField::decode(bit_field_) == REGISTER; }
IsAnyRegister()124 bool IsAnyRegister() const {
125 return IsRegister() && GetLocation() == ANY_REGISTER;
126 }
IsCallerFrameSlot()127 bool IsCallerFrameSlot() const { return !IsRegister() && GetLocation() < 0; }
IsCalleeFrameSlot()128 bool IsCalleeFrameSlot() const { return !IsRegister() && GetLocation() >= 0; }
129
AsRegister()130 int32_t AsRegister() const {
131 DCHECK(IsRegister());
132 return GetLocation();
133 }
AsCallerFrameSlot()134 int32_t AsCallerFrameSlot() const {
135 DCHECK(IsCallerFrameSlot());
136 return GetLocation();
137 }
AsCalleeFrameSlot()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
LinkageLocation(LocationType type,int32_t location,MachineType machine_type)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
NON_EXPORTED_BASE(ZoneObject)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, [...]
NON_EXPORTED_BASE(ZoneObject)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