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
ForCallerFrameSlot(int32_t slot,MachineType type)53 static LinkageLocation ForCallerFrameSlot(int32_t slot, MachineType type) {
54 DCHECK(slot < 0);
55 return LinkageLocation(STACK_SLOT, slot, type);
56 }
57
ForCalleeFrameSlot(int32_t slot,MachineType type)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
ForSavedCallerReturnAddress()64 static LinkageLocation ForSavedCallerReturnAddress() {
65 return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
66 StandardFrameConstants::kCallerPCOffset) /
67 kPointerSize,
68 MachineType::Pointer());
69 }
70
ForSavedCallerFramePtr()71 static LinkageLocation ForSavedCallerFramePtr() {
72 return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
73 StandardFrameConstants::kCallerFPOffset) /
74 kPointerSize,
75 MachineType::Pointer());
76 }
77
ForSavedCallerConstantPool()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
ForSavedCallerFunction()86 static LinkageLocation ForSavedCallerFunction() {
87 return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
88 StandardFrameConstants::kFunctionOffset) /
89 kPointerSize,
90 MachineType::AnyTagged());
91 }
92
ConvertToTailCallerLocation(LinkageLocation caller_location,int stack_param_delta)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
LinkageLocation(LocationType type,int32_t location,MachineType machine_type)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
GetType()122 MachineType GetType() const { return machine_type_; }
123
GetSize()124 int GetSize() const {
125 return 1 << ElementSizeLog2Of(GetType().representation());
126 }
127
GetSizeInPointers()128 int GetSizeInPointers() const {
129 // Round up
130 return (GetSize() + kPointerSize - 1) / kPointerSize;
131 }
132
GetLocation()133 int32_t GetLocation() const {
134 return static_cast<int32_t>(bit_field_ & LocationField::kMask) >>
135 LocationField::kShift;
136 }
137
IsRegister()138 bool IsRegister() const { return TypeField::decode(bit_field_) == REGISTER; }
IsAnyRegister()139 bool IsAnyRegister() const {
140 return IsRegister() && GetLocation() == ANY_REGISTER;
141 }
IsCallerFrameSlot()142 bool IsCallerFrameSlot() const { return !IsRegister() && GetLocation() < 0; }
IsCalleeFrameSlot()143 bool IsCalleeFrameSlot() const { return !IsRegister() && GetLocation() >= 0; }
144
AsRegister()145 int32_t AsRegister() const {
146 DCHECK(IsRegister());
147 return GetLocation();
148 }
AsCallerFrameSlot()149 int32_t AsCallerFrameSlot() const {
150 DCHECK(IsCallerFrameSlot());
151 return GetLocation();
152 }
AsCalleeFrameSlot()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
NON_EXPORTED_BASE(ZoneObject)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, [...]
NON_EXPORTED_BASE(ZoneObject)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