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
//! Generic Builtin FFI Trampoline
//!
//! A single FFI function that can execute ANY builtin function, eliminating
//! the need for individual FFI wrappers for each of the ~170 builtins.
//!
//! Uses the same static trampoline pattern as async_ops: the VM registers a
//! dispatch function before JIT execution, and the JIT calls it via
//! `jit_generic_builtin`.
use JITContext;
use crateTAG_NULL;
// jit_bits_to_nanboxed / nanboxed_to_jit_bits removed at the import
// site — both decoded/encoded `ValueWord` from raw bits, the deleted
// W-series shape. The trampoline body below now surfaces rather than
// going through that pipeline.
/// Static trampoline function pointer for generic builtin dispatch.
///
/// Signature: `fn(ctx: *mut JITContext, builtin_id: u16, arg_count: u16) -> u64`
///
/// The registered function should:
/// 1. Read `arg_count` values from `ctx.stack` (popping them)
/// 2. Dispatch to the appropriate builtin handler
/// 3. Return the NaN-boxed result
pub static GENERIC_BUILTIN_FN: AtomicPtr =
new;
/// Register the generic builtin dispatch trampoline.
///
/// # Safety
/// The function pointer must be valid for the duration of JIT execution and
/// must have the signature: `extern "C" fn(*mut JITContext, u16, u16) -> u64`
pub unsafe
/// Clear the generic builtin dispatch registration.
/// Execute any builtin function via the registered trampoline.
///
/// Called from JIT-compiled code when a builtin is not handled by a dedicated
/// JIT lowering path. The JIT translator flushes args onto `ctx.stack` before
/// calling this function.
///
/// # Arguments
/// * `ctx` - JIT execution context (args are on ctx.stack)
/// * `builtin_id` - The `BuiltinFunction` discriminant as u16
/// * `arg_count` - Number of arguments on the stack
///
/// # Returns
/// NaN-boxed result, or TAG_NULL on failure.
pub extern "C"
/// Concrete trampoline implementation that dispatches builtins AND opcode-based
/// generic FFI calls through a thread-local VirtualMachine.
///
/// The JIT translator uses two ID ranges:
/// - `0x0000..0x7FFF`: BuiltinFunction discriminants (e.g. Abs, Print)
/// - `0x8000..0xFFFF`: opcode byte OR'd with 0x8000 (e.g. ConvertToNumber)
///
/// Protocol: the JIT translator pushes args onto `ctx.stack`. For builtins,
/// it also pushes arg_count as a NaN-boxed number (VM calling convention).
/// For opcode-based calls, only the raw args are pushed (no count suffix).
/// Concrete trampoline implementation that dispatches builtins via the VM.
///
/// PHASE_2C / SURFACE (ADR-006 §2.7.4 / §2.7.5 / §2.7.7): pre-strict-
/// typing this body popped JIT-stack `u64` bits, decoded each via
/// `jit_bits_to_nanboxed(bits)` (returning a `ValueWord` — deleted),
/// pushed them onto a thread-local `VirtualMachine` via
/// `vm.push_raw_u64(vw)` (deleted — replaced by `push_kinded(bits,
/// kind)` per §2.7.7), invoked `op_builtin_call`, then popped via
/// `vm.pop_raw_u64()` (also deleted) and re-encoded the result via
/// `nanboxed_to_jit_bits`. Both ends are the W-series defection-
/// attractor pipeline (CLAUDE.md "Forbidden Patterns" / "Renames to
/// refuse on sight" — `push_raw_u64` / `pop_raw_u64` are explicitly
/// listed as the §2.7.7 forbidden shim shapes).
///
/// The strict-typing rebuild target threads `(bits: u64, kind:
/// NativeKind)` from the JIT call site, pushes via `vm.push_kinded`,
/// invokes the builtin, pops via the matching kinded API, and returns
/// `(bits, kind)` back to the caller. That requires:
///
/// 1. JIT-stack parallel-kind track at the JIT-FFI boundary (§2.7.7
/// extension to the JIT side; W11 / deeper Phase-2c).
/// 2. Per-builtin known result kind (the bytecode's typed
/// `BuiltinCall` opcode signature; partly landed for the typed
/// builtins in shape-vm, not yet threaded through the JIT
/// trampoline).
///
/// Until both land, the body returns `TAG_NULL` after popping the
/// stack — the caller observes the dispatch as "builtin not handled
/// in JIT, falling back to bytecode interpreter" (the same shape as
/// the existing fallback when `GENERIC_BUILTIN_FN` is unregistered).
pub extern "C"
/// Handle opcode-based generic FFI calls (ConvertToNumber, ConvertToInt, etc.).
///
/// PHASE_2C / SURFACE (ADR-006 §2.7.4 / §2.7.5): pre-strict-typing this
/// function decoded the operand via `jit_bits_to_nanboxed(arg_bits)`
/// (returning a `ValueWord`), classified it via `ValueWord::as_*`
/// methods (every one of which decoded `tag_bits` from the raw bits —
/// the deleted W-series shape), and re-encoded the result via
/// `ValueWord::from_*` constructors plus `nanboxed_to_jit_bits`. The
/// W-series defection-attractor list forbids both ends of that
/// pipeline.
///
/// Strict-typing rebuild target: the ConvertTo* opcodes are kind-typed
/// at JIT-emit time per CLAUDE.md "Type System Rules" — there is no
/// generic `ConvertTo*`; the compiler emits per-source-kind variants
/// (`ConvertI64ToF64`, `ConvertStringToF64`, etc.) where both operand
/// and result `NativeKind` are stamped at JIT compile time. The
/// per-variant body reads a typed scalar from the JIT slot and writes
/// a typed scalar back, no FFI hop, no kind probing. This entry point
/// disappears entirely once the per-kind opcode coverage is complete.
/// CLAUDE.md "Forbidden Patterns" calls out the W4-δ-era Convert<X>
/// To<Y> opcode shape as a wrong-shape opcode added to paper over a
/// kind-tracker gap — the right fix was extending the compiler's kind
/// tracker, which the strict-typing plan does.
///
/// Until the per-kind opcode coverage lands, the body returns
/// `arg_bits` unchanged, surfacing the kind-source gap at the caller
/// rather than fabricating a result via the deleted ValueWord API.