Line data Source code
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 639693 : if (!caller_location.IsRegister()) {
96 : return LinkageLocation(STACK_SLOT,
97 : caller_location.GetLocation() + stack_param_delta,
98 54594 : 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 4218260 : bit_field_ = TypeField::encode(type) |
118 15399913 : ((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 58153 : return 1 << ElementSizeLog2Of(GetType().representation());
126 : }
127 :
128 : int GetSizeInPointers() const {
129 : // Round up
130 58153 : return (GetSize() + kPointerSize - 1) / kPointerSize;
131 : }
132 :
133 : int32_t GetLocation() const {
134 : return static_cast<int32_t>(bit_field_ & LocationField::kMask) >>
135 44855040 : LocationField::kShift;
136 : }
137 :
138 24412669 : bool IsRegister() const { return TypeField::decode(bit_field_) == REGISTER; }
139 : bool IsAnyRegister() const {
140 39739861 : return IsRegister() && GetLocation() == ANY_REGISTER;
141 : }
142 26584578 : bool IsCallerFrameSlot() const { return !IsRegister() && GetLocation() < 0; }
143 17806866 : 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 4365219 : 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 915856 : bool RequiresFrameAsIncoming() const {
224 915856 : return IsCFunctionCall() || IsJSFunctionCall();
225 : }
226 :
227 : // The number of return values from this call.
228 17508478 : size_t ReturnCount() const { return location_sig_->return_count(); }
229 :
230 : // The number of C parameters to this call.
231 4150867 : 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 20950535 : size_t InputCount() const { return 1 + location_sig_->parameter_count(); }
246 :
247 3510014 : size_t FrameStateCount() const { return NeedsFrameState() ? 1 : 0; }
248 :
249 : Flags flags() const { return flags_; }
250 :
251 277600 : bool NeedsFrameState() const { return flags() & kNeedsFrameState; }
252 0 : bool SupportsTailCalls() const { return flags() & kSupportsTailCalls; }
253 6801738 : 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 4582229 : return location_sig_->GetReturn(index);
261 : }
262 :
263 20919385 : LinkageLocation GetInputLocation(size_t index) const {
264 20919385 : if (index == 0) return target_loc_;
265 20385907 : return location_sig_->GetParam(index - 1);
266 : }
267 :
268 : MachineSignature* GetMachineSignature(Zone* zone) const;
269 :
270 : MachineType GetReturnType(size_t index) const {
271 5752480 : return location_sig_->GetReturn(index).GetType();
272 : }
273 :
274 : MachineType GetInputType(size_t index) const {
275 20937897 : if (index == 0) return target_type_;
276 20910187 : return location_sig_->GetParam(index - 1).GetType();
277 : }
278 :
279 : MachineType GetParameterType(size_t index) const {
280 33724 : 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 915895 : 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 21577355 : 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 3326625 : return incoming_->GetInputLocation(index + 1); // + 1 to skip target.
386 : }
387 :
388 : // Get the machine type of an (incoming) parameter to this function.
389 1791053 : MachineType GetParameterType(int index) const {
390 3582106 : 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 1079272 : 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 0 : 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 598786 : 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 1032180 : 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_
|