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
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
//! JIT-FFI bits ↔ runtime-tier carrier conversions (ADR-006 §2.7.5).
//!
//! Pre-strict-typing this module bridged the JIT's NaN-boxed `u64`
//! representation and the VM's `ValueWord` (the v1 dynamic tagged word).
//! The Phase-2 bulldozer deleted both the `ValueWord` type and the
//! `tag_bits::*` discriminator family.
//!
//! ## Carrier shape (§2.7.5 stamp-at-compile-time)
//!
//! Per ADR-006 §2.7.5 the JIT-FFI surface is `(u64, NativeKind)` — raw
//! bits plus a parallel kind companion. The kind is stamped at JIT
//! compile time from the call signature; it is **never decoded from the
//! bits**. Consumers that need a runtime-tier carrier wrap the pair as
//! `KindedSlot::new(ValueSlot::from_raw(bits), kind)` per §2.7.6/Q7 when
//! crossing into runtime-tier dispatch.
//!
//! ## What this module does (W11-jit-carrier-conversion close)
//!
//! These functions are the bookkeeping layer between the JIT call
//! signature's separate `bits: u64` and `kind: NativeKind` parameters
//! (the §2.7.5 stable-FFI raw-pair shape) and the in-Rust `JitFfiCarrier`
//! tuple alias `(u64, NativeKind)`. The body is intentionally trivial —
//! per §2.7.5 the conversion is *identity*: raw bits stay raw bits, and
//! the kind companion is whatever the caller's static stamp passed in.
//! No decode, no probe, no `is_heap()` classification — the kind is
//! authoritative because the caller proved it at JIT compile time.
//!
//! ## What is forbidden
//!
//! - **Decoding kind from `bits`** (CLAUDE.md "Forbidden Patterns" #4,
//! ADR-006 §2.7.7 #4 — the deleted `tag_bits` dispatch).
//! - **`is_heap()` / `is_tagged()` probe** to classify (§2.7.7 #7).
//! - **Bool-default fallback** when the caller didn't supply a kind
//! (forbidden #9 — surface-and-stop instead).
//! - **`ValueWord` resurrection under any name** — the body's
//! pre-bulldozer shape decoded `Arc<HeapValue>` from raw bits via
//! `ValueWord::clone_from_bits` and re-encoded per-arm via
//! `ValueWord::as_heap_ref` / `tag_bits::TAG_HEAP`; all deleted.
//!
//! ## Historical context (pre-bulldozer body, what's gone)
//!
//! The deleted pipeline ran:
//! 1. `nanboxed_to_jit_bits(&ValueWord)` decoded `ValueWord` per arm
//! (each arm a `tag_bits::TAG_*` discriminator), produced JIT bits.
//! 2. `jit_bits_to_nanboxed(bits)` re-decoded raw bits via the same
//! `tag_bits` machinery, constructed a `ValueWord` via
//! `ValueWord::from_*` constructors, returned it.
//! 3. The `UNIFIED_HEAP_REFS` thread-local accumulator captured retained
//! `Arc<HeapValue>` shares for `drain_unified_heap_refs()` to release
//! at the end of each JIT call.
//!
//! All three steps are gone. The retain/release path now flows through
//! `clone_with_kind` / `drop_with_kind` at the producing call site
//! (ADR-006 §2.7.7), driven by the parallel-kind track — no global
//! drain accumulator.
use crateJitFfiCarrier;
use NativeKind;
/// Per-JIT-call ref-drain hook. Retained as a named export for the JIT
/// executor's per-call epilogue (`executor.rs`). The pre-bulldozer body
/// drained the deleted `UNIFIED_HEAP_REFS` thread-local that the deleted
/// `nanboxed_to_jit_bits` pushed `Arc<HeapValue>` retain-shares into.
///
/// Per ADR-006 §2.7.5 the post-call lifecycle is dispatched through
/// `clone_with_kind` / `drop_with_kind` at the producing call site (the
/// parallel-kind track in `crates/shape-vm/src/executor/vm_impl/stack.rs`),
/// not via a global accumulator. The hook is a no-op — there is nothing
/// to drain.
// ============================================================================
// JIT-FFI bits → runtime-tier carrier (`(u64, NativeKind)` pair)
// ============================================================================
/// Pack raw JIT-FFI bits + their static `NativeKind` stamp into a
/// `JitFfiCarrier` per ADR-006 §2.7.5.
///
/// The kind comes from the JIT call signature's stamp — the caller's
/// emitter proved it at JIT compile time. This function does **not**
/// decode the kind from `bits`: per §2.7.7 #4 / #7, runtime kind
/// discrimination from a raw bit pattern is the deleted ValueWord
/// `tag_bits` shape and is forbidden.
///
/// Consumers assemble a `KindedSlot` from the returned pair via
/// `KindedSlot::new(ValueSlot::from_raw(bits), kind)` per §2.7.6/Q7
/// when they need a runtime-tier carrier.
/// Variant of `jit_bits_to_nanboxed` with `JITContext` access, retained
/// for downstream call sites (`async_ops`, `control`, `generic_builtin`,
/// `data_access`, etc.) that need function-name resolution from the
/// JIT context. The ctx pointer is plumbing for caller-side lookups
/// (function table, function names) — the carrier itself is the same
/// `(bits, kind)` pair.
// ============================================================================
// TypedScalar ↔ JIT bits Conversion (still kind-flat — no carrier change)
// ============================================================================
/// Convert JIT NaN-boxed bits to a `TypedScalar` with an optional type hint.
///
/// `TypedScalar` is a kind-tagged scalar carrier (`ScalarKind` field) that
/// the producing site populates from the `NativeKind` hint per ADR-006
/// §2.7.5; this is the carrier shape for scalar-FFI returns and does not
/// participate in the deleted `ValueWord` dispatch. The hint comes from
/// the JIT-emitted `FrameDescriptor`'s slot-kind track per §2.7.7/Q9.
/// Convert a `TypedScalar` to JIT NaN-boxed bits. Integer kinds box as
/// `box_number(value as f64)` since the JIT's Cranelift IR uses f64 for
/// all numeric operations internally — this is JIT-internal scalar
/// encoding, not `tag_bits` dispatch.
// ============================================================================
// Runtime-tier carrier → JIT NaN-boxed bits
// ============================================================================
/// Unpack a `JitFfiCarrier` back to raw JIT-FFI bits per ADR-006 §2.7.5.
///
/// The carrier is `(bits, kind)` — the bits are already in the JIT's
/// raw 8-byte slot form per §2.7.5 stable-FFI rule. Unpacking is a
/// projection, not a re-encoding: the producing caller (the one that
/// constructed the carrier via `jit_bits_to_nanboxed`) already supplied
/// the canonical JIT-side bit pattern. The kind companion is consumed
/// by the caller's dispatch shell at the JIT-internal call site
/// (`op_get_prop` / `op_call_method` / etc. emitter), not re-decoded
/// here.
///
/// **Forbidden alternatives**:
/// - Per-arm re-encoding via `tag_bits::TAG_HEAP` / `make_tagged` on the
/// `NativeKind::Ptr(HeapKind::*)` arms — that is the deleted ValueWord
/// pipeline (CLAUDE.md "Forbidden Patterns" #4).
/// - `is_heap()` probe on `bits` to classify before re-encoding —
/// §2.7.7 #7 forbidden.
/// - Stamping kind from a side-table keyed by `bits` — same forbidden
/// shape; kind is on the carrier struct, not derived from the bits.