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