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
//! γ-CP3 jit-array-builder regression tests (v0.3 NO-KNOWN-INCORRECTNESS).
//!
//! Pre-γ-CP3 the MIR-JIT codegen had no codegen for the array-builder /
//! slice constructs that the bytecode VM surfaces cleanly (the V3-S5
//! ckpt-5 `op_new_array` / `SliceAccess` consumer-cascade). Instead of
//! bailing, the JIT compiled the function ANYWAY and produced garbage:
//!
//! * array-spread `let b = [...a, 4, 5]` — the spread element (an
//! `*mut TypedArray<T>` heap pointer) was pushed into the destination
//! scalar array as a raw `Int64` element. `b.sum()` then read the
//! pointer integer + uninitialized memory — NON-DETERMINISTIC garbage.
//! VM cleanly errors (`op_new_array(0): SURFACE`); JIT printed garbage
//! with exit-code 0.
//!
//! * destructure-rest `let [a, ...rest] = [1, 2, 3, 4]` — the MIR
//! lowering projected the `...rest` binding as the plain element
//! `Place::Index(source, 1)`, a SINGLE-element scalar read. The JIT
//! compiled `rest = source[1]` and `rest` silently became the scalar
//! `2` instead of the sub-array `[2, 3, 4]`. The bytecode VM emits a
//! distinct `OpCode::SliceAccess` for the same binding and surfaces.
//!
//! The γ-CP3 fix is honest surface-and-stop (NOT partial array-builder
//! codegen — that would create a NEW VM/JIT divergence, since the VM
//! side still surfaces `op_new_array`):
//!
//! 1. MIR producer (`crates/shape-vm/src/mir/lowering/stmt.rs`
//! `rest_slice_place`): a `...rest` array-destructure binding is the
//! slice `source[index..]`, so it is lowered as the slice-shape
//! `Rvalue::Aggregate([Copy(source), Int(index)])` — the same
//! 2-operand carrier the MIR already emits for an open-range index
//! `xs[2..]` — rather than a wrong scalar `Place::Index`.
//!
//! 2. JIT consumer (`crates/shape-jit/src/mir_compiler/v2_array.rs`
//! `emit_v2_array_aggregate`): the scalar-element-kind arm rejects
//! any operand whose proven `NativeKind` is a heap pointer. A
//! scalar-element typed array structurally cannot be built from a
//! heap-pointer operand — that operand is a spread element or the
//! source array of a slice. The JIT returns a structured `Err`
//! (the W12 surface-and-stop pattern), which the W12 fall-through
//! routes to the bytecode interpreter — which produces the VM's
//! clean error.
//!
//! Net result: VM == JIT — both cleanly error, NEITHER produces garbage.
//!
//! Gated behind `deep-tests` per the `closure_dispatch_regression_tests`
//! / `short_circuit_regression_tests` precedent — `JITExecutor::
//! execute_program` JIT-compiles the stdlib on every test, so default-
//! parallelism CI runs would race the JIT code cache.
use crateJITExecutor;
use ;
use initialize_shared_runtime;
use BytecodeExecutor;
/// Outcome of running a program through one executor: `Ok(wire-debug)` on
/// success, `Err(message)` on a clean surfaced error. Garbage from the
/// JIT manifests as an `Ok` with a different payload than the VM's.
/// Assert VM and JIT agree on the program: either both surface a clean
/// error, or both succeed with byte-identical results. A JIT garbage
/// miscompile manifests as the JIT returning `Ok(garbage)` while the VM
/// returns `Err` — this helper fails on exactly that divergence.
// ── array-spread builder (`Rvalue::Aggregate` heap-pointer operand) ────
/// The canonical array-spread reproducer. Pre-γ-CP3: VM cleanly errors
/// (`op_new_array SURFACE`); JIT printed non-deterministic garbage.
/// Post-fix: the `emit_v2_array_aggregate` scalar arm rejects the
/// `Ptr(TypedArray)` spread operand → JIT compile bails → fall-through →
/// interpreter → VM's clean error. VM == JIT.
/// Spread of a `number` array — the `Float64` scalar element arm of
/// `emit_v2_array_aggregate` must reject the heap-pointer spread operand
/// for the same reason as the `Int64` arm.
/// Spread in the middle of an array literal — the heap-pointer operand
/// is not necessarily the first operand. The detector scans every
/// operand, so a mid-literal spread bails identically.
// ── destructure-rest (MIR slice-shape lowering) ────────────────────────
/// The canonical destructure-rest reproducer. Pre-γ-CP3 the MIR lowered
/// `...rest` as the scalar `Place::Index(source, 1)`; the JIT compiled
/// `rest = source[1]` and silently bound the scalar `2`. Post-fix the
/// MIR lowers `...rest` as the slice-shape `Aggregate([source, 1])` →
/// JIT compile bails (heap-pointer operand, or `Rvalue::Aggregate`
/// Route A surface-and-stop) → fall-through → VM error. VM == JIT.
/// Destructure-rest where only the head element is consumed afterwards.
/// Pre-γ-CP3 the JIT compiled past the broken rest binding and printed
/// the head scalar with exit-code 0 while the VM surfaced. The MIR
/// slice-shape lowering of the rest binding makes the JIT bail.
/// Destructure-rest followed by a method call on the rest binding.
// ── ordinary array codegen must NOT be over-broadly bailed ─────────────
/// A plain scalar `Array<int>` literal has only `Int64`-kind operands —
/// the heap-pointer detector must NOT fire. The v2 typed-array fast path
/// compiles this normally; VM == JIT == 6.
/// The canonical s2 smoke shape — `map`/`sum` over an array literal —
/// must keep working. The `[1,2,3,4,5]` literal is an all-scalar
/// `Aggregate`; the detector does not fire.
/// A bounded slice `xs[1..3]` is a working construct (the v2
/// `SliceAccess` path resolves it). VM == JIT must hold here too — the
/// fix must not regress working slices.