v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
c-linkage.cc
Go to the documentation of this file.
1// Copyright 2015 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
9#include "src/zone/zone.h"
10
11namespace v8 {
12namespace internal {
13namespace compiler {
14
15namespace {
16
17// Platform-specific configuration for C calling convention.
18#if V8_TARGET_ARCH_IA32
19// ===========================================================================
20// == ia32 ===================================================================
21// ===========================================================================
22#define CALLEE_SAVE_REGISTERS esi, edi, ebx
23#define CALLEE_SAVE_FP_REGISTERS
24
25#elif V8_TARGET_ARCH_X64
26// ===========================================================================
27// == x64 ====================================================================
28// ===========================================================================
29
30#ifdef V8_TARGET_OS_WIN
31// == x64 windows ============================================================
32#define STACK_SHADOW_WORDS 4
33#define PARAM_REGISTERS rcx, rdx, r8, r9
34#define FP_PARAM_REGISTERS xmm0, xmm1, xmm2, xmm3
35#define FP_RETURN_REGISTER xmm0
36#define CALLEE_SAVE_REGISTERS rbx, rdi, rsi, r12, r13, r14, r15
37#define CALLEE_SAVE_FP_REGISTERS \
38 xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15
39
40#else // V8_TARGET_OS_WIN
41// == x64 other ==============================================================
42#define PARAM_REGISTERS rdi, rsi, rdx, rcx, r8, r9
43#define FP_PARAM_REGISTERS xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7
44#define FP_RETURN_REGISTER xmm0
45#define CALLEE_SAVE_REGISTERS rbx, r12, r13, r14, r15
46#define CALLEE_SAVE_FP_REGISTERS
47#endif // V8_TARGET_OS_WIN
48
49#elif V8_TARGET_ARCH_ARM
50// ===========================================================================
51// == arm ====================================================================
52// ===========================================================================
53#define PARAM_REGISTERS r0, r1, r2, r3
54#define CALLEE_SAVE_REGISTERS r4, r5, r6, r7, r8, r9, r10
55#define CALLEE_SAVE_FP_REGISTERS d8, d9, d10, d11, d12, d13, d14, d15
56
57#elif V8_TARGET_ARCH_ARM64
58// ===========================================================================
59// == arm64 ====================================================================
60// ===========================================================================
61#define PARAM_REGISTERS x0, x1, x2, x3, x4, x5, x6, x7
62#define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7
63#define FP_RETURN_REGISTER d0
64#define CALLEE_SAVE_REGISTERS x19, x20, x21, x22, x23, x24, x25, x26, x27, x28
65
66#define CALLEE_SAVE_FP_REGISTERS d8, d9, d10, d11, d12, d13, d14, d15
67
68#elif V8_TARGET_ARCH_MIPS64
69// ===========================================================================
70// == mips64 =================================================================
71// ===========================================================================
72#define PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7
73#define FP_PARAM_REGISTERS f12, f13, f14, f15, f16, f17, f18, f19
74#define FP_RETURN_REGISTER f0
75#define CALLEE_SAVE_REGISTERS s0, s1, s2, s3, s4, s5, s6, s7
76#define CALLEE_SAVE_FP_REGISTERS f20, f22, f24, f26, f28, f30
77
78#elif V8_TARGET_ARCH_LOONG64
79// ===========================================================================
80// == loong64 ================================================================
81// ===========================================================================
82#define PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7
83#define FP_PARAM_REGISTERS f0, f1, f2, f3, f4, f5, f6, f7
84#define FP_RETURN_REGISTER f0
85#define CALLEE_SAVE_REGISTERS s0, s1, s2, s3, s4, s5, s6, s7, s8, fp
86#define CALLEE_SAVE_FP_REGISTERS f24, f25, f26, f27, f28, f29, f30, f31
87
88#elif V8_TARGET_ARCH_PPC64
89// ===========================================================================
90// == ppc64 ==================================================================
91// ===========================================================================
92#ifdef V8_TARGET_LITTLE_ENDIAN // ppc64le linux
93#define STACK_SHADOW_WORDS 12
94#else // AIX
95#define STACK_SHADOW_WORDS 14
96#endif
97#define PARAM_REGISTERS r3, r4, r5, r6, r7, r8, r9, r10
98#define CALLEE_SAVE_REGISTERS \
99 r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, \
100 r29, r30
101
102#define CALLEE_SAVE_FP_REGISTERS \
103 d14, d15, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, \
104 d29, d30, d31
105
106#elif V8_TARGET_ARCH_S390X
107// ===========================================================================
108// == s390x ==================================================================
109// ===========================================================================
110#define STACK_SHADOW_WORDS 20
111#define PARAM_REGISTERS r2, r3, r4, r5, r6
112#define CALLEE_SAVE_REGISTERS r6, r7, r8, r9, r10, ip, r13
113#define CALLEE_SAVE_FP_REGISTERS d8, d9, d10, d11, d12, d13, d14, d15
114
115#elif V8_TARGET_ARCH_RISCV32 || V8_TARGET_ARCH_RISCV64
116// ===========================================================================
117// == riscv64 =================================================================
118// ===========================================================================
119#define PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7
120#define FP_PARAM_REGISTERS fa0, fa1, fa2, fa3, fa4, fa5, fa6, fa7
121// fp is not part of CALLEE_SAVE_REGISTERS (similar to how MIPS64 or PPC defines
122// it)
123#define CALLEE_SAVE_REGISTERS s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11
124#define CALLEE_SAVE_FP_REGISTERS \
125 fs0, fs1, fs2, fs3, fs4, fs5, fs6, fs7, fs8, fs9, fs10, fs11
126#else
127// ===========================================================================
128// == unknown ================================================================
129// ===========================================================================
130#define UNSUPPORTED_C_LINKAGE 1
131#endif
132} // namespace
133
134#if (defined(V8_TARGET_OS_WIN) && defined(V8_TARGET_ARCH_X64)) || \
135 defined(V8_TARGET_ARCH_MIPS64)
136// As defined in
137// https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2019#parameter-passing,
138// Windows calling convention doesn't differentiate between GP and FP params
139// when counting how many of them should be placed in registers. That's why
140// we use the same counter {i} for both types here.
141// MIPS is the same, as defined in
142// https://techpubs.jurassic.nl/manuals/0630/developer/Mpro_n32_ABI/sgi_html/ch02.html#id52620.
144 size_t kFPParamRegisterCount,
145 size_t kParamRegisterCount,
146 const DoubleRegister* kFPParamRegisters,
147 const v8::internal::Register* kParamRegisters,
148 LocationSignature::Builder* out_locations) {
149#ifdef STACK_SHADOW_WORDS
150 int stack_offset = STACK_SHADOW_WORDS;
151#else
152 int stack_offset = 0;
153#endif
154 CHECK_EQ(kFPParamRegisterCount, kParamRegisterCount);
155
156 for (size_t i = 0; i < msig->parameter_count(); i++) {
157 MachineType type = msig->GetParam(i);
158 bool spill = (i >= kParamRegisterCount);
159 if (spill) {
160 out_locations->AddParam(
161 LinkageLocation::ForCallerFrameSlot(-1 - stack_offset, type));
162 stack_offset++;
163 } else {
164 if (IsFloatingPoint(type.representation())) {
165 out_locations->AddParam(
166 LinkageLocation::ForRegister(kFPParamRegisters[i].code(), type));
167 } else {
168 out_locations->AddParam(
169 LinkageLocation::ForRegister(kParamRegisters[i].code(), type));
170 }
171 }
172 }
173}
174#elif defined(V8_TARGET_ARCH_LOONG64)
175// As defined in
176// https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html#_procedure_calling_convention
177// Loongarch calling convention uses GP to pass floating-point arguments when no
178// FP is available.
180 size_t kFPParamRegisterCount,
181 size_t kParamRegisterCount,
182 const DoubleRegister* kFPParamRegisters,
183 const v8::internal::Register* kParamRegisters,
184 LocationSignature::Builder* out_locations) {
185#ifdef STACK_SHADOW_WORDS
186 int stack_offset = STACK_SHADOW_WORDS;
187#else
188 int stack_offset = 0;
189#endif
190 size_t num_params = 0;
191 size_t num_fp_params = 0;
192 for (size_t i = 0; i < msig->parameter_count(); i++) {
193 MachineType type = msig->GetParam(i);
194 if (IsFloatingPoint(type.representation())) {
195 if (num_fp_params < kFPParamRegisterCount) {
196 out_locations->AddParam(LinkageLocation::ForRegister(
197 kFPParamRegisters[num_fp_params].code(), type));
198 ++num_fp_params;
199 } else if (num_params < kParamRegisterCount) {
200 // ForNullRegister represents a floating-point param that should be put
201 // into the GPR, and reg_code is the the negative of encoding of the
202 // GPR, and the maximum is -4.
203 out_locations->AddParam(LinkageLocation::ForNullRegister(
204 -kParamRegisters[num_params].code(), type));
205 ++num_params;
206 } else {
207 out_locations->AddParam(
208 LinkageLocation::ForCallerFrameSlot(-1 - stack_offset, type));
209 stack_offset++;
210 }
211 } else {
212 if (num_params < kParamRegisterCount) {
213 out_locations->AddParam(LinkageLocation::ForRegister(
214 kParamRegisters[num_params].code(), type));
215 ++num_params;
216 } else {
217 out_locations->AddParam(
218 LinkageLocation::ForCallerFrameSlot(-1 - stack_offset, type));
219 stack_offset++;
220 }
221 }
222 }
223}
224#else
225// As defined in https://www.agner.org/optimize/calling_conventions.pdf,
226// Section 7, Linux and Mac place parameters in consecutive registers,
227// differentiating between GP and FP params. That's why we maintain two
228// separate counters here. This also applies to Arm systems following
229// the AAPCS and Windows on Arm.
231 size_t kFPParamRegisterCount,
232 size_t kParamRegisterCount,
233 const DoubleRegister* kFPParamRegisters,
234 const v8::internal::Register* kParamRegisters,
235 LocationSignature::Builder* out_locations) {
236#ifdef STACK_SHADOW_WORDS
237 int stack_offset = STACK_SHADOW_WORDS;
238#else
239 int stack_offset = 0;
240#endif
241 size_t num_params = 0;
242 size_t num_fp_params = 0;
243 for (size_t i = 0; i < msig->parameter_count(); i++) {
244 MachineType type = msig->GetParam(i);
245 bool spill = IsFloatingPoint(type.representation())
246 ? (num_fp_params >= kFPParamRegisterCount)
247 : (num_params >= kParamRegisterCount);
248 if (spill) {
249 out_locations->AddParam(
250 LinkageLocation::ForCallerFrameSlot(-1 - stack_offset, type));
251 stack_offset++;
252 } else {
253 if (IsFloatingPoint(type.representation())) {
255 kFPParamRegisters[num_fp_params].code(), type));
256 ++num_fp_params;
257 } else {
259 kParamRegisters[num_params].code(), type));
260 ++num_params;
261 }
262 }
263 }
264}
265#endif // (defined(V8_TARGET_OS_WIN) && defined(V8_TARGET_ARCH_X64)) ||
266 // defined(V8_TARGET_ARCH_MIPS64)
267
268// General code uses the above configuration data.
270 Zone* zone, const MachineSignature* msig, CallDescriptor::Flags flags,
271 Operator::Properties properties) {
272#ifdef UNSUPPORTED_C_LINKAGE
273 // This method should not be called on unknown architectures.
274 FATAL("requested C call descriptor on unsupported architecture");
275 return nullptr;
276#endif
277
278 DCHECK(properties == Operator::kNoThrow || properties == Operator::kPure);
279 DCHECK_LE(msig->parameter_count(), static_cast<size_t>(kMaxCParameters));
280
281 LocationSignature::Builder locations(zone, msig->return_count(),
282 msig->parameter_count());
283
284#ifndef V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
285 // Check the types of the signature.
286 for (size_t i = 0; i < msig->parameter_count(); i++) {
287 MachineType type = msig->GetParam(i);
288 CHECK(!IsFloatingPoint(type.representation()));
289 }
290
291 // Check the return types.
292 for (size_t i = 0; i < locations.return_count_; i++) {
293 MachineType type = msig->GetReturn(i);
294 CHECK(!IsFloatingPoint(type.representation()));
295 }
296#endif
297
298 CHECK_GE(2, locations.return_count_);
299 if (locations.return_count_ > 0) {
300#ifdef FP_RETURN_REGISTER
301 const v8::internal::DoubleRegister kFPReturnRegister = FP_RETURN_REGISTER;
302 auto reg = IsFloatingPoint(msig->GetReturn(0).representation())
303 ? kFPReturnRegister.code()
305#else
306 auto reg = kReturnRegister0.code();
307#endif
308 // TODO(chromium:1052746): Use the correctly sized register here (e.g. "al"
309 // if the return type is kBit), so we don't have to use a hacky bitwise AND
310 // elsewhere.
312 }
313
314 if (locations.return_count_ > 1) {
315 DCHECK(!IsFloatingPoint(msig->GetReturn(0).representation()));
316
318 msig->GetReturn(1)));
319 }
320
321#ifdef PARAM_REGISTERS
322 const v8::internal::Register kParamRegisters[] = {PARAM_REGISTERS};
323 const int kParamRegisterCount = static_cast<int>(arraysize(kParamRegisters));
324#else
325 const v8::internal::Register* kParamRegisters = nullptr;
326 const int kParamRegisterCount = 0;
327#endif
328
329#ifdef FP_PARAM_REGISTERS
330 const DoubleRegister kFPParamRegisters[] = {FP_PARAM_REGISTERS};
331 const size_t kFPParamRegisterCount = arraysize(kFPParamRegisters);
332#else
333 const DoubleRegister* kFPParamRegisters = nullptr;
334 const size_t kFPParamRegisterCount = 0;
335#endif
336
337 // Add register and/or stack parameter(s).
338 BuildParameterLocations(msig, kFPParamRegisterCount, kParamRegisterCount,
339 kFPParamRegisters, kParamRegisters, &locations);
340
341 const RegList kCalleeSaveRegisters = {CALLEE_SAVE_REGISTERS};
342 const DoubleRegList kCalleeSaveFPRegisters = {CALLEE_SAVE_FP_REGISTERS};
343
344 // The target for C calls is always an address (i.e. machine pointer).
345 MachineType target_type = MachineType::Pointer();
346 LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type);
348
349 // TODO(saelo): here we probably want to use a c-call specific tag.
350 return zone->New<CallDescriptor>( // --
353 target_type, // target MachineType
354 target_loc, // target location
355 locations.Get(), // location_sig
356 0, // stack_parameter_count
357 properties, // properties
358 kCalleeSaveRegisters, // callee-saved registers
359 kCalleeSaveFPRegisters, // callee-saved fp regs
360 flags, "c-call");
361}
362
363} // namespace compiler
364} // namespace internal
365} // namespace v8
static LinkageLocation ForRegister(int32_t reg, MachineType type=MachineType::None())
static LinkageLocation ForCallerFrameSlot(int32_t slot, MachineType type)
static LinkageLocation ForAnyRegister(MachineType type=MachineType::None())
static LinkageLocation ForNullRegister(int32_t reg, MachineType type=MachineType::None())
static constexpr MachineType Pointer()
constexpr int8_t code() const
size_t return_count() const
Definition signature.h:93
T GetParam(size_t index) const
Definition signature.h:96
T GetReturn(size_t index=0) const
Definition signature.h:103
SignatureBuilder< Signature< T >, T > Builder
Definition signature.h:130
size_t parameter_count() const
Definition signature.h:94
T * New(Args &&... args)
Definition zone.h:114
static CallDescriptor * GetSimplifiedCDescriptor(Zone *zone, const MachineSignature *sig, CallDescriptor::Flags flags=CallDescriptor::kNoFlags, Operator::Properties properties=Operator::kNoThrow)
Definition c-linkage.cc:269
Handle< Code > code
LiftoffRegister reg
void BuildParameterLocations(const MachineSignature *msig, size_t kFPParamRegisterCount, size_t kParamRegisterCount, const DoubleRegister *kFPParamRegisters, const v8::internal::Register *kParamRegisters, LocationSignature::Builder *out_locations)
Definition c-linkage.cc:230
DwVfpRegister DoubleRegister
Signature< MachineType > MachineSignature
Definition signature.h:151
constexpr Register kReturnRegister1
constexpr bool IsFloatingPoint(MachineRepresentation rep)
static constexpr int kMaxCParameters
constexpr Register kReturnRegister0
#define FATAL(...)
Definition logging.h:47
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK_GE(lhs, rhs)
#define CHECK(condition)
Definition logging.h:124
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define arraysize(array)
Definition macros.h:67