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