v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
wasm-linkage.h
Go to the documentation of this file.
1// Copyright 2018 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_WASM_WASM_LINKAGE_H_
6#define V8_WASM_WASM_LINKAGE_H_
7
8#if !V8_ENABLE_WEBASSEMBLY
9#error This header should only be included if WebAssembly is enabled.
10#endif // !V8_ENABLE_WEBASSEMBLY
11
16
17namespace v8 {
18namespace internal {
19namespace wasm {
20
21// TODO(wasm): optimize calling conventions to be both closer to C++ (to
22// reduce adapter costs for fast Wasm <-> C++ calls) and to be more efficient
23// in general.
24
25#if V8_TARGET_ARCH_IA32
26// ===========================================================================
27// == ia32 ===================================================================
28// ===========================================================================
29constexpr Register kGpParamRegisters[] = {esi, eax, edx, ecx};
30constexpr Register kGpReturnRegisters[] = {eax, edx};
31constexpr DoubleRegister kFpParamRegisters[] = {xmm1, xmm2, xmm3,
32 xmm4, xmm5, xmm6};
33constexpr DoubleRegister kFpReturnRegisters[] = {xmm1, xmm2};
34
35#elif V8_TARGET_ARCH_X64
36// ===========================================================================
37// == x64 ====================================================================
38// ===========================================================================
39constexpr Register kGpParamRegisters[] = {rsi, rax, rdx, rcx, rbx, r9};
40constexpr Register kGpReturnRegisters[] = {rax, rdx};
41constexpr DoubleRegister kFpParamRegisters[] = {xmm1, xmm2, xmm3,
42 xmm4, xmm5, xmm6};
43constexpr DoubleRegister kFpReturnRegisters[] = {xmm1, xmm2};
44
45#elif V8_TARGET_ARCH_ARM
46// ===========================================================================
47// == arm ====================================================================
48// ===========================================================================
49constexpr Register kGpParamRegisters[] = {r3, r0, r2, r6};
50constexpr Register kGpReturnRegisters[] = {r0, r1};
51// ARM d-registers must be in even/odd D-register pairs for correct allocation.
52constexpr DoubleRegister kFpParamRegisters[] = {d0, d1, d2, d3, d4, d5, d6, d7};
53constexpr DoubleRegister kFpReturnRegisters[] = {d0, d1};
54
55#elif V8_TARGET_ARCH_ARM64
56// ===========================================================================
57// == arm64 ====================================================================
58// ===========================================================================
59constexpr Register kGpParamRegisters[] = {x7, x0, x2, x3, x4, x5, x6};
60constexpr Register kGpReturnRegisters[] = {x0, x1};
61constexpr DoubleRegister kFpParamRegisters[] = {d0, d1, d2, d3, d4, d5, d6, d7};
62constexpr DoubleRegister kFpReturnRegisters[] = {d0, d1};
63
64#elif V8_TARGET_ARCH_MIPS64
65// ===========================================================================
66// == mips64 =================================================================
67// ===========================================================================
68constexpr Register kGpParamRegisters[] = {a0, a2, a3, a4, a5, a6, a7};
69constexpr Register kGpReturnRegisters[] = {v0, v1};
70constexpr DoubleRegister kFpParamRegisters[] = {f2, f4, f6, f8, f10, f12, f14};
71constexpr DoubleRegister kFpReturnRegisters[] = {f2, f4};
72
73#elif V8_TARGET_ARCH_LOONG64
74// ===========================================================================
75// == LOONG64 ================================================================
76// ===========================================================================
77constexpr Register kGpParamRegisters[] = {a7, a0, a2, a3, a4, a5, a6};
78constexpr Register kGpReturnRegisters[] = {a0, a1};
79constexpr DoubleRegister kFpParamRegisters[] = {f0, f1, f2, f3, f4, f5, f6, f7};
80constexpr DoubleRegister kFpReturnRegisters[] = {f0, f1};
81
82#elif V8_TARGET_ARCH_PPC64
83// ===========================================================================
84// == ppc64 ==================================================================
85// ===========================================================================
86constexpr Register kGpParamRegisters[] = {r10, r3, r5, r6, r7, r8, r9};
87constexpr Register kGpReturnRegisters[] = {r3, r4};
88constexpr DoubleRegister kFpParamRegisters[] = {d1, d2, d3, d4, d5, d6, d7, d8};
89constexpr DoubleRegister kFpReturnRegisters[] = {d1, d2};
90
91#elif V8_TARGET_ARCH_S390X
92// ===========================================================================
93// == s390x ==================================================================
94// ===========================================================================
95constexpr Register kGpParamRegisters[] = {r6, r2, r4, r5};
96constexpr Register kGpReturnRegisters[] = {r2, r3};
97constexpr DoubleRegister kFpParamRegisters[] = {d0, d2, d4, d6};
98constexpr DoubleRegister kFpReturnRegisters[] = {d0, d2};
99
100#elif V8_TARGET_ARCH_RISCV32 || V8_TARGET_ARCH_RISCV64
101// ===========================================================================
102// == riscv64 =================================================================
103// ===========================================================================
104// Note that kGpParamRegisters and kFpParamRegisters are used in
105// Builtins::Generate_WasmCompileLazy (builtins-riscv.cc)
106constexpr Register kGpParamRegisters[] = {a7, a0, a2, a3, a4, a5, a6};
107constexpr Register kGpReturnRegisters[] = {a0, a1};
108constexpr DoubleRegister kFpParamRegisters[] = {fa0, fa1, fa2, fa3,
109 fa4, fa5, fa6, fa7};
110constexpr DoubleRegister kFpReturnRegisters[] = {fa0, fa1};
111
112#else
113// ===========================================================================
114// == unknown ================================================================
115// ===========================================================================
116// Do not use any registers, we will just always use the stack.
121
122#endif
123
124#if V8_TARGET_ARCH_PPC64
125// Platforms where a Floating Point value is represented in Double Precision
126// format in a FP register.
127constexpr bool kIsFpAlwaysDouble = true;
128#else
129constexpr bool kIsFpAlwaysDouble = false;
130#endif
131#if V8_TARGET_BIG_ENDIAN
132constexpr bool kIsBigEndian = true;
133#else
134constexpr bool kIsBigEndian = false;
135#endif
136#if V8_TARGET_ARCH_S390X_LE_SIM
137constexpr bool kIsBigEndianOnSim = true;
138#else
139constexpr bool kIsBigEndianOnSim = false;
140#endif
141
142// The parameter index where the trusted instance data should be placed in wasm
143// call descriptors. This is used by the Int64Lowering::LowerNode method.
145static_assert(kWasmImplicitArgRegister ==
147
149 public:
150 template <size_t kNumGpRegs, size_t kNumFpRegs>
151 constexpr LinkageAllocator(const Register (&gp)[kNumGpRegs],
152 const DoubleRegister (&fp)[kNumFpRegs])
153 : LinkageAllocator(gp, kNumGpRegs, fp, kNumFpRegs) {}
154
155 constexpr LinkageAllocator(const Register* gp, int gpc,
156 const DoubleRegister* fp, int fpc)
157 : gp_count_(gpc), gp_regs_(gp), fp_count_(fpc), fp_regs_(fp) {}
158
159 bool CanAllocateGP() const { return gp_offset_ < gp_count_; }
161#if V8_TARGET_ARCH_ARM
162 switch (rep) {
164 // Get the next D-register (Liftoff only uses the even S-registers).
165 int next = fp_allocator_.NextSlot(2) / 2;
166 // Only the lower 16 D-registers alias S-registers.
167 return next < fp_count_ && fp_regs_[next].code() < 16;
168 }
170 int next = fp_allocator_.NextSlot(2) / 2;
171 return next < fp_count_;
172 }
174 int next = fp_allocator_.NextSlot(4) / 2;
175 return next < fp_count_ - 1; // 2 D-registers are required.
176 }
177 default:
178 UNREACHABLE();
179 return false;
180 }
181#else
182 return fp_offset_ < fp_count_;
183#endif
184 }
185
186 int NextGpReg() {
188 return gp_regs_[gp_offset_++].code();
189 }
190
192 DCHECK(CanAllocateFP(rep));
193#if V8_TARGET_ARCH_ARM
194 switch (rep) {
196 // Liftoff uses only even-numbered S-registers, and encodes them using
197 // the code of the corresponding D-register. This limits the calling
198 // interface to only using the even-numbered S-registers.
200 DCHECK_GT(16, d_reg_code); // D16 - D31 don't alias S-registers.
201 return d_reg_code * 2;
202 }
204 int next = fp_allocator_.Allocate(2) / 2;
205 return fp_regs_[next].code();
206 }
208 int next = fp_allocator_.Allocate(4) / 2;
209 int d_reg_code = fp_regs_[next].code();
210 // Check that result and the next D-register pair.
211 DCHECK_EQ(0, d_reg_code % 2);
212 DCHECK_EQ(d_reg_code + 1, fp_regs_[next + 1].code());
213 return d_reg_code / 2;
214 }
215 default:
216 UNREACHABLE();
217 }
218#else
219 return fp_regs_[fp_offset_++].code();
220#endif
221 }
222
223 // Stackslots are counted upwards starting from 0 (or the offset set by
224 // {SetStackOffset}. If {type} needs more than one stack slot, the lowest
225 // used stack slot is returned.
227 int num_slots =
229 int slot = slot_allocator_.Allocate(num_slots);
230 return slot;
231 }
232
233 // Set an offset for the stack slots returned by {NextStackSlot} and
234 // {NumStackSlots}. Can only be called before any call to {NextStackSlot}.
240
241 int NumStackSlots() const { return slot_allocator_.Size(); }
242
244
245 private:
246 const int gp_count_;
247 int gp_offset_ = 0;
248 const Register* const gp_regs_;
249
250 const int fp_count_;
251#if V8_TARGET_ARCH_ARM
252 // Use an aligned slot allocator to model ARM FP register aliasing. The slots
253 // are 32 bits, so 2 slots are required for a D-register, 4 for a Q-register.
254 AlignedSlotAllocator fp_allocator_;
255#else
256 int fp_offset_ = 0;
257#endif
259
261};
262
263// Helper for allocating either an GP or FP reg, or the next stack slot.
265 public:
266 template <size_t kNumGpRegs, size_t kNumFpRegs>
267 constexpr LinkageLocationAllocator(const Register (&gp)[kNumGpRegs],
268 const DoubleRegister (&fp)[kNumFpRegs],
269 int slot_offset)
270 : allocator_(LinkageAllocator(gp, fp)), slot_offset_(slot_offset) {}
271
274 if (IsFloatingPoint(rep)) {
275 if (allocator_.CanAllocateFP(rep)) {
276 int reg_code = allocator_.NextFpReg(rep);
277 return LinkageLocation::ForRegister(reg_code, type);
278 }
279 } else if (allocator_.CanAllocateGP()) {
280 int reg_code = allocator_.NextGpReg();
281 return LinkageLocation::ForRegister(reg_code, type);
282 }
283 // Cannot use register; use stack slot.
284 int index = -1 - (slot_offset_ + allocator_.NextStackSlot(rep));
285 return LinkageLocation::ForCallerFrameSlot(index, type);
286 }
287
288 int NumStackSlots() const { return allocator_.NumStackSlots(); }
290
291 private:
293 // Since params and returns are in different stack frames, we must allocate
294 // them separately. Parameter slots don't need an offset, but return slots
295 // must be offset to just before the param slots, using this |slot_offset_|.
297};
298} // namespace wasm
299} // namespace internal
300} // namespace v8
301
302#endif // V8_WASM_WASM_LINKAGE_H_
static LinkageLocation ForRegister(int32_t reg, MachineType type=MachineType::None())
static LinkageLocation ForCallerFrameSlot(int32_t slot, MachineType type)
static MachineType TypeForRepresentation(const MachineRepresentation &rep, bool isSigned=true)
const DoubleRegister *const fp_regs_
int NextStackSlot(MachineRepresentation type)
int NextFpReg(MachineRepresentation rep)
constexpr LinkageAllocator(const Register(&gp)[kNumGpRegs], const DoubleRegister(&fp)[kNumFpRegs])
bool CanAllocateFP(MachineRepresentation rep) const
constexpr LinkageAllocator(const Register *gp, int gpc, const DoubleRegister *fp, int fpc)
constexpr LinkageLocationAllocator(const Register(&gp)[kNumGpRegs], const DoubleRegister(&fp)[kNumFpRegs], int slot_offset)
LinkageLocation Next(MachineRepresentation rep)
Handle< Code > code
int32_t offset
constexpr bool kIsFpAlwaysDouble
constexpr DoubleRegister kFpReturnRegisters[]
constexpr Register kGpParamRegisters[]
constexpr DoubleRegister kFpParamRegisters[]
constexpr int kWasmInstanceDataParameterIndex
constexpr bool kIsBigEndianOnSim
uint32_t WasmInterpreterRuntime int64_t r0
constexpr Register kGpReturnRegisters[]
constexpr bool kIsBigEndian
DwVfpRegister DoubleRegister
constexpr bool IsFloatingPoint(MachineRepresentation rep)
constexpr Register kWasmImplicitArgRegister
V8_EXPORT_PRIVATE constexpr int ElementSizeInBytes(MachineRepresentation)
Definition c-api.cc:87
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487