1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
//! Typed function call ABI for the Shape v2 runtime.
//!
//! The v1 ABI passes all arguments as NaN-boxed `I64` values and returns
//! results through `ctx.stack[0]`. This module defines a v2 ABI where
//! compile-time-proven types are passed in their native Cranelift
//! representation:
//!
//! | NativeKind | Cranelift type | Register class | Notes |
//! |---------------|---------------|----------------|-----------------------------|
//! | Float64 | F64 | XMM (x86) | Plain double |
//! | NullableFloat64 | F64 | XMM | NaN sentinel = null |
//! | Int64/IntSize | I64 | GPR | Native int, NOT NaN-boxed |
//! | Int32/UInt32 | I32 | GPR | 32-bit integer |
//! | Int16/UInt16 | I16 | GPR | 16-bit integer |
//! | Int8/UInt8 | I8 | GPR | 8-bit integer |
//! | Bool | I8 | GPR | 0 = false, 1 = true |
//! | Unknown/other | I64 | GPR | NaN-boxed fallback |
//!
//! The v2 signature still starts with `ctx_ptr: I64` as the first parameter
//! (same as v1) and returns `I32` as a signal code (same as v1 direct calls).
//! The difference is that *user arguments* following `ctx_ptr` use native
//! types instead of uniformly boxing to `I64`.
//!
//! # Integration plan
//!
//! This module provides signature-building primitives. The call site in
//! `translator/opcodes/functions.rs` (`compile_direct_call`) and the
//! function declaration in `compiler/program.rs` (`compile_program`,
//! `compile_function_with_user_funcs`) will be updated in a follow-up
//! change to use `build_cranelift_signature` instead of the current
//! uniform `AbiParam::new(types::I64)` loop.
use *;
use Function;
use NativeKind;
// ---------------------------------------------------------------------------
// TypedFunctionSignature
// ---------------------------------------------------------------------------
/// A typed function signature that describes the native representation of
/// each parameter and the return value.
///
/// Unlike the v1 ABI where every slot is `I64` (NaN-boxed), this signature
/// carries per-slot type information extracted from the compiler's
/// `FrameDescriptor`.
/// True when a slot kind would produce the same representation as the v1
/// NaN-boxed ABI (I64 GPR). Per ADR-006 the deleted
/// `NativeKind::Unknown`/`Dynamic` placeholders are gone — kind-tracked
/// signatures are exhaustive at call signature build time, so
/// `is_fully_untyped` only fires when *every* signature slot already has
/// a typed kind that happens to map to I64 (Int64/UInt64/IntSize/etc.).
// ---------------------------------------------------------------------------
// NativeKind -> Cranelift type mapping
// ---------------------------------------------------------------------------
/// Map a single `NativeKind` to the Cranelift IR type that should be used in
/// the function signature.
///
/// The mapping follows the native-width convention:
/// - Floating-point kinds -> `F64` (passed in XMM registers on x86-64)
/// - Integer kinds -> `I64`, `I32`, `I16`, or `I8` depending on width
/// - Bool -> `I8`
/// - String / Unknown / Dynamic -> `I64` (dynamic fallback)
// ---------------------------------------------------------------------------
// Signature builders
// ---------------------------------------------------------------------------
/// Build a Cranelift `Signature` from a `TypedFunctionSignature`.
///
/// The emitted signature has the form:
///
/// ```text
/// fn(ctx_ptr: I64, arg0: <native>, arg1: <native>, ...) -> I32
/// ```
///
/// - The first parameter is always `ctx_ptr` (pointer-width integer)
/// regardless of the typed signature. This matches the v1 ABI contract
/// that every JIT-compiled function receives a `*mut JITContext`.
/// - The return type is `I32` (signal code: >= 0 means success, < 0 means
/// deopt). The *semantic* return value is written to `ctx.stack[0]` by
/// the callee, matching the existing convention. A future v2 extension
/// may promote the return value into a native register as well.
// ---------------------------------------------------------------------------
// Resolving a TypedFunctionSignature from bytecode metadata
// ---------------------------------------------------------------------------
/// Extract a `TypedFunctionSignature` from a bytecode `Function`.
///
/// When the function carries a `FrameDescriptor`, the first `arity` slots
/// are the parameter types and `return_kind` is the return type. When no
/// descriptor is present (legacy code), all slots default to `Unknown`
/// which produces a v1-compatible all-I64 signature.
///
/// `slot_kinds_override` is an optional caller-provided slice that takes
/// precedence over the frame descriptor. This is useful when the JIT's
/// own type inference (e.g., feedback-guided profiling) has refined the
/// types beyond what the bytecode compiler emitted.