shape_vm/bytecode/content_addressed.rs
1use super::*;
2use crate::type_tracking::{FrameDescriptor, StorageHint};
3
4#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
5pub struct FunctionHash(pub [u8; 32]);
6
7impl std::fmt::Debug for FunctionHash {
8 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
9 write!(f, "FunctionHash({})", self)
10 }
11}
12
13impl std::fmt::Display for FunctionHash {
14 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15 for byte in &self.0 {
16 write!(f, "{:02x}", byte)?;
17 }
18 Ok(())
19 }
20}
21
22impl FunctionHash {
23 /// The zero hash, used as a sentinel/placeholder.
24 pub const ZERO: Self = Self([0u8; 32]);
25}
26
27/// A self-contained, content-addressed function blob.
28///
29/// Each blob carries its own instructions, constants, and strings (no shared
30/// pools). The `content_hash` is the SHA-256 of the serialized content fields,
31/// making deduplication and caching trivial.
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct FunctionBlob {
34 /// SHA-256 hash of the serialized content (everything below).
35 pub content_hash: FunctionHash,
36
37 // -- metadata --
38 pub name: String,
39 pub arity: u16,
40 pub param_names: Vec<String>,
41 pub locals_count: u16,
42 pub is_closure: bool,
43 pub captures_count: u16,
44 pub is_async: bool,
45 #[serde(default)]
46 pub ref_params: Vec<bool>,
47 #[serde(default)]
48 pub ref_mutates: Vec<bool>,
49 #[serde(default)]
50 pub mutable_captures: Vec<bool>,
51 /// Typed frame layout for this function's locals (propagated from compiler).
52 #[serde(default)]
53 pub frame_descriptor: Option<FrameDescriptor>,
54
55 // -- code --
56 /// This function's bytecode instructions.
57 pub instructions: Vec<Instruction>,
58 /// This function's constant pool.
59 pub constants: Vec<Constant>,
60 /// This function's string pool.
61 pub strings: Vec<String>,
62
63 // -- permissions --
64 /// Permissions required by this function (from capability_tags analysis).
65 #[serde(default = "default_permission_set")]
66 pub required_permissions: PermissionSet,
67
68 // -- dependency graph --
69 /// Content hashes of functions this blob references
70 /// (`Operand::Function(idx)` indexes into this vector).
71 pub dependencies: Vec<FunctionHash>,
72
73 /// Callee names corresponding to each dependency entry.
74 /// Used during compilation to resolve forward references; not serialized.
75 #[serde(skip, default)]
76 pub callee_names: Vec<String>,
77
78 // -- type info --
79 /// Type names this function constructs (schema references).
80 pub type_schemas: Vec<String>,
81
82 // -- foreign function dependencies --
83 /// Content hashes of foreign functions referenced by `CallForeign` opcodes.
84 /// Sorted and deduplicated for deterministic hashing.
85 #[serde(default)]
86 pub foreign_dependencies: Vec<[u8; 32]>,
87
88 // -- debug --
89 /// Source mapping entries local to this blob:
90 /// `(local_instruction_offset, file_id, line)`.
91 pub source_map: Vec<(usize, u32, u32)>,
92}
93
94/// Helper struct for deterministic content hashing.
95/// We serialize exactly the fields that define the function's identity.
96#[derive(Serialize)]
97struct FunctionBlobHashInput<'a> {
98 name: &'a str,
99 arity: u16,
100 param_names: &'a [String],
101 locals_count: u16,
102 is_closure: bool,
103 captures_count: u16,
104 is_async: bool,
105 ref_params: &'a [bool],
106 ref_mutates: &'a [bool],
107 mutable_captures: &'a [bool],
108 instructions: &'a [Instruction],
109 constants: &'a [Constant],
110 strings: &'a [String],
111 dependencies: &'a [FunctionHash],
112 type_schemas: &'a [String],
113 /// Permission names sorted deterministically for stable hashing.
114 required_permission_names: Vec<&'a str>,
115 /// Content hashes of foreign functions referenced by this blob.
116 foreign_dependencies: &'a [[u8; 32]],
117}
118
119impl FunctionBlob {
120 /// Compute the content hash from the blob's fields.
121 /// Call this after populating all fields, then assign the result to `content_hash`.
122 pub fn compute_hash(&self) -> FunctionHash {
123 // Convert PermissionSet to sorted permission names for deterministic hashing.
124 let perm_names: Vec<&str> = self.required_permissions.iter().map(|p| p.name()).collect();
125 let input = FunctionBlobHashInput {
126 name: &self.name,
127 arity: self.arity,
128 param_names: &self.param_names,
129 locals_count: self.locals_count,
130 is_closure: self.is_closure,
131 captures_count: self.captures_count,
132 is_async: self.is_async,
133 ref_params: &self.ref_params,
134 ref_mutates: &self.ref_mutates,
135 mutable_captures: &self.mutable_captures,
136 instructions: &self.instructions,
137 constants: &self.constants,
138 strings: &self.strings,
139 dependencies: &self.dependencies,
140 type_schemas: &self.type_schemas,
141 required_permission_names: perm_names,
142 foreign_dependencies: &self.foreign_dependencies,
143 };
144 // Use bincode-compatible MessagePack for deterministic serialization.
145 // rmp_serde::encode::to_vec uses the struct-as-array format which is
146 // order-preserving and deterministic for the types we use here.
147 let bytes = rmp_serde::encode::to_vec(&input)
148 .expect("FunctionBlob content serialization should not fail");
149 let digest = Sha256::digest(&bytes);
150 let mut hash = [0u8; 32];
151 hash.copy_from_slice(&digest);
152 FunctionHash(hash)
153 }
154
155 /// Build a blob with all fields set, then compute and assign its content hash.
156 pub fn finalize(&mut self) {
157 self.content_hash = self.compute_hash();
158 }
159}
160
161/// A content-addressed program: a set of `FunctionBlob`s plus program-level metadata.
162///
163/// This is the **storage / cache** representation. Before execution the linker
164/// flattens it into a `LinkedProgram`.
165#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct Program {
167 /// Hash of the entry-point function.
168 pub entry: FunctionHash,
169
170 /// All function blobs keyed by content hash.
171 pub function_store: HashMap<FunctionHash, FunctionBlob>,
172
173 /// Number of locals used by top-level code.
174 pub top_level_locals_count: u16,
175
176 /// Storage hints for top-level locals.
177 #[serde(default)]
178 pub top_level_local_storage_hints: Vec<StorageHint>,
179
180 /// Module-binding variable names (index -> name).
181 pub module_binding_names: Vec<String>,
182
183 /// Storage hints for module bindings.
184 #[serde(default)]
185 pub module_binding_storage_hints: Vec<StorageHint>,
186
187 /// Per-function local storage hints.
188 #[serde(default)]
189 pub function_local_storage_hints: Vec<Vec<StorageHint>>,
190
191 /// Typed frame layout for top-level locals.
192 #[serde(default)]
193 pub top_level_frame: Option<FrameDescriptor>,
194
195 /// Per-slot fully-resolved `ConcreteType` for top-level locals.
196 ///
197 /// ADR-006 §2.7.5 conduit (content-addressed mirror of
198 /// `BytecodeProgram.top_level_local_concrete_types`). Survives the
199 /// `Program` → `link()` → `LinkedProgram` → `BytecodeProgram`
200 /// round-trip so JIT compilation of in-memory-compiled programs can
201 /// use the typed-array / TypedObject fast paths. Not serialised —
202 /// `ConcreteType` carries opaque registry IDs that aren't a stable
203 /// wire shape; cached-program loads fall through to the legacy
204 /// NaN-boxed path.
205 #[serde(skip, default)]
206 pub top_level_local_concrete_types: Vec<shape_value::v2::ConcreteType>,
207
208 /// Per-user-function per-MIR-slot `ConcreteType` side-table.
209 ///
210 /// ADR-006 §2.7.5 conduit (W12-jit-aggregate-non-array, 2026-05-12):
211 /// content-addressed mirror of
212 /// `BytecodeProgram.function_local_concrete_types`. Survives the
213 /// `Program` → `link()` → `LinkedProgram` → `BytecodeProgram` round-
214 /// trip so JIT compilation of in-memory-compiled programs can use
215 /// the TypedObject Aggregate short-circuit inside user-function
216 /// bodies (Smoke 1.5 `divide`, Smoke 2 `first_positive`, 28 stdlib
217 /// helpers). Not serialised — same rationale as
218 /// `top_level_local_concrete_types`.
219 #[serde(skip, default)]
220 pub function_local_concrete_types: Vec<Vec<shape_value::v2::ConcreteType>>,
221
222 /// Per-user-function declared `ConcreteType` for the return value.
223 ///
224 /// ADR-006 §2.7.5 conduit (W12-jit-call-return-kind close, 2026-05-12):
225 /// content-addressed mirror of
226 /// `BytecodeProgram.function_return_concrete_types`. Survives the
227 /// `Program` → `link()` → `LinkedProgram` → `BytecodeProgram`
228 /// round-trip so the conduit can stamp Call-terminator destination
229 /// slots from the callee's declared return type. Not serialised —
230 /// same rationale as the sibling `*_concrete_types` side-tables.
231 #[serde(skip, default)]
232 pub function_return_concrete_types: Vec<shape_value::v2::ConcreteType>,
233
234 /// ADR-006 §2.7.5 conduit (V3-S6b-jit-method-monomorph-conduit
235 /// close, 2026-05-15): content-addressed mirror of
236 /// `BytecodeProgram.monomorphized_method_call_sites`. Survives the
237 /// `Program` → `link()` → `LinkedProgram` → `BytecodeProgram`
238 /// round-trip so the conduit producer can lift
239 /// `function_return_concrete_types[specialized_idx]` into the
240 /// destination slot's ConcreteType at `MirConstant::Method` Call-
241 /// terminator sites. Not serialised — opaque per-program FunctionId
242 /// indices aren't a stable wire shape.
243 #[serde(skip, default)]
244 pub monomorphized_method_call_sites:
245 HashMap<(shape_ast::ast::span::Span, Option<usize>), usize>,
246
247 /// ADR-006 §2.7.5 conduit (cluster-2-cw-IB-class-b close, 2026-05-16):
248 /// content-addressed mirror of
249 /// `BytecodeProgram.value_call_return_concrete_types`. Survives the
250 /// `Program` → `link()` → `LinkedProgram` → `BytecodeProgram`
251 /// round-trip so the conduit producer can stamp value-call
252 /// `TerminatorKind::Call` destination slots from the closure-bound
253 /// callee's inferred return `ConcreteType`. Not serialised —
254 /// `ConcreteType` carries opaque registry IDs that aren't a stable
255 /// wire shape.
256 #[serde(skip, default)]
257 pub value_call_return_concrete_types:
258 HashMap<
259 (shape_ast::ast::span::Span, Option<usize>),
260 shape_value::v2::ConcreteType,
261 >,
262
263 /// ADR-006 §2.7.5 conduit (W10 jit-call-method-user-trait-fix close,
264 /// 2026-05-17): content-addressed mirror of
265 /// `BytecodeProgram.operator_trait_dispatch_sites`. Survives the
266 /// `Program` → `link()` → `LinkedProgram` → `BytecodeProgram`
267 /// round-trip so the JIT consumer can re-emit user-type binary/unary
268 /// trait-dispatch as method-call IR. Not serialised — Spans carry
269 /// source-position offsets that aren't a stable wire shape.
270 #[serde(skip, default)]
271 pub operator_trait_dispatch_sites:
272 HashMap<shape_ast::ast::span::Span, (String, u16)>,
273
274 /// DataFrame schema for column name resolution.
275 pub data_schema: Option<DataFrameSchema>,
276
277 /// Type schema registry for TypedObject field resolution.
278 #[serde(default)]
279 pub type_schema_registry: shape_runtime::type_schema::TypeSchemaRegistry,
280
281 /// Trait method dispatch registry.
282 pub trait_method_symbols: HashMap<String, String>,
283
284 /// Foreign function metadata table.
285 #[serde(default)]
286 pub foreign_functions: Vec<ForeignFunctionEntry>,
287
288 /// Native `type C` layout metadata table.
289 #[serde(default)]
290 pub native_struct_layouts: Vec<NativeStructLayoutEntry>,
291
292 /// Debug information (source files, variable names).
293 pub debug_info: DebugInfo,
294
295 /// Closure spec §14.6 (H6.5): per-function-name `ClosureLayout`
296 /// side-table threaded through the content-addressed `Program` so it
297 /// survives the `link()` → `LinkedProgram` → `BytecodeProgram` round-
298 /// trip. Keyed by function name because the content-addressed store
299 /// reorders blobs topologically; the linker remaps to post-link
300 /// function-id positions in `LinkedProgram.closure_function_layouts`.
301 /// Not serialised — programs loaded from disk fall back to the
302 /// legacy `HeapValue::Closure` variant.
303 #[serde(skip, default)]
304 pub closure_function_layouts_by_name: std::collections::HashMap<
305 String,
306 std::sync::Arc<shape_value::v2::closure_layout::ClosureLayout>,
307 >,
308
309 /// ADR-006 §2.7.24 Q25.C trait-object vtable registry. Keyed by
310 /// `"Trait::ConcreteType"` strings (matching the existing
311 /// `trait_method_symbols` key prefix). Built at impl-block
312 /// compilation; consumed at `op_box_trait_object` runtime to build
313 /// `Arc<TraitObjectStorage>`. Not serialised because `Arc<VTable>`
314 /// is not a stable wire shape; in cached-program-load mode the
315 /// vtables are rebuilt at link time from `trait_method_symbols`.
316 #[serde(skip, default)]
317 pub trait_vtables: std::collections::HashMap<
318 String,
319 std::sync::Arc<shape_value::value::VTable>,
320 >,
321
322 /// R8 W8 Cluster A surface-and-stop flag (2026-05-25). Mirror of
323 /// `BytecodeProgram::has_imported_const_inline` for the content-
324 /// addressed Program shape; propagated through the linker so the JIT
325 /// executor can deopt the whole program to the bytecode interpreter
326 /// when imported `pub const` identifiers were inlined-at-use by
327 /// `compile_expr_identifier`. v0.4 root-cause fix per close-summary
328 /// §5.16. NOT serialised — compile-time state.
329 #[serde(skip, default)]
330 pub has_imported_const_inline: bool,
331
332 /// R8 W9 B1 W17-marshal-return surface-and-stop flag (2026-05-25).
333 /// Mirror of `BytecodeProgram::has_w17_marshal_residual` for the
334 /// content-addressed Program shape; propagated through the linker so
335 /// the JIT executor can deopt the whole program to the bytecode
336 /// interpreter when the program contains direct calls to imported
337 /// stdlib functions (which route through `Ptr(HeapKind::ModuleFn)`
338 /// callees that the JIT's `jit_call_value` silently returns
339 /// TAG_NULL for). v0.4 root-cause fix per close-summary §5.16.
340 /// NOT serialised — compile-time state.
341 #[serde(skip, default)]
342 pub has_w17_marshal_residual: bool,
343}
344
345/// A linked function ready for execution in a flat instruction array.
346///
347/// Mirrors `Function` but adds `blob_hash` so the runtime can trace back
348/// to the original content-addressed blob.
349#[derive(Debug, Clone, Serialize, Deserialize)]
350pub struct LinkedFunction {
351 /// Content hash of the `FunctionBlob` this was linked from.
352 pub blob_hash: FunctionHash,
353
354 /// Offset into the flat `LinkedProgram::instructions` array.
355 pub entry_point: usize,
356 /// Number of instructions in this function's body.
357 pub body_length: usize,
358
359 // -- metadata (same as Function) --
360 pub name: String,
361 pub arity: u16,
362 pub param_names: Vec<String>,
363 pub locals_count: u16,
364 pub is_closure: bool,
365 pub captures_count: u16,
366 pub is_async: bool,
367 #[serde(default)]
368 pub ref_params: Vec<bool>,
369 #[serde(default)]
370 pub ref_mutates: Vec<bool>,
371 #[serde(default)]
372 pub mutable_captures: Vec<bool>,
373 /// Typed frame layout for this function's locals.
374 #[serde(default)]
375 pub frame_descriptor: Option<FrameDescriptor>,
376}
377
378/// A linked, execution-ready program with flat instruction/constant/string arrays.
379///
380/// This mirrors today's `BytecodeProgram` layout so the executor can run it
381/// with minimal changes. Produced by the linker from a `Program`.
382#[derive(Debug, Clone, Default, Serialize, Deserialize)]
383pub struct LinkedProgram {
384 /// Hash of the entry-point function for execution.
385 #[serde(default)]
386 pub entry: FunctionHash,
387
388 /// Flat instruction array (all functions concatenated).
389 pub instructions: Vec<Instruction>,
390
391 /// Merged constant pool.
392 pub constants: Vec<Constant>,
393
394 /// Merged string pool.
395 pub strings: Vec<String>,
396
397 /// Linked function table (replaces `Vec<Function>`).
398 pub functions: Vec<LinkedFunction>,
399
400 /// Reverse lookup: content hash -> function index in `functions`.
401 pub hash_to_id: HashMap<FunctionHash, usize>,
402
403 /// Debug information.
404 pub debug_info: DebugInfo,
405
406 /// DataFrame schema for column name resolution.
407 pub data_schema: Option<DataFrameSchema>,
408
409 /// Module-binding variable names.
410 pub module_binding_names: Vec<String>,
411
412 /// Number of locals used by top-level code.
413 pub top_level_locals_count: u16,
414
415 /// Storage hints for top-level locals.
416 #[serde(default)]
417 pub top_level_local_storage_hints: Vec<StorageHint>,
418
419 /// Type schema registry for TypedObject field resolution.
420 #[serde(default)]
421 pub type_schema_registry: shape_runtime::type_schema::TypeSchemaRegistry,
422
423 /// Storage hints for module bindings.
424 #[serde(default)]
425 pub module_binding_storage_hints: Vec<StorageHint>,
426
427 /// Per-function local storage hints.
428 #[serde(default)]
429 pub function_local_storage_hints: Vec<Vec<StorageHint>>,
430
431 /// Typed frame layout for top-level locals.
432 #[serde(default)]
433 pub top_level_frame: Option<FrameDescriptor>,
434
435 /// Per-slot fully-resolved `ConcreteType` for top-level locals.
436 ///
437 /// ADR-006 §2.7.5 conduit (top-level concrete-types side-table):
438 /// propagated from `BytecodeProgram.top_level_local_concrete_types`
439 /// through the linker so JIT compilation of linked programs can use
440 /// the typed-array / TypedObject fast paths. Not serialised — the
441 /// embedded `StructLayoutId` / `EnumLayoutId` are compile-time-local
442 /// registry indices; cached-program loads fall through to the legacy
443 /// NaN-boxed path.
444 #[serde(skip, default)]
445 pub top_level_local_concrete_types: Vec<shape_value::v2::ConcreteType>,
446
447 /// Per-user-function per-MIR-slot `ConcreteType` side-table.
448 ///
449 /// ADR-006 §2.7.5 conduit (W12-jit-aggregate-non-array, 2026-05-12):
450 /// LinkedProgram mirror of `Program.function_local_concrete_types`
451 /// — propagated through the linker so JIT compilation of linked
452 /// programs can use the TypedObject Aggregate short-circuit inside
453 /// user-function bodies. Not serialised — same rationale as
454 /// `top_level_local_concrete_types`.
455 #[serde(skip, default)]
456 pub function_local_concrete_types: Vec<Vec<shape_value::v2::ConcreteType>>,
457
458 /// Per-user-function declared `ConcreteType` for the return value.
459 ///
460 /// ADR-006 §2.7.5 conduit (W12-jit-call-return-kind, 2026-05-12):
461 /// LinkedProgram mirror of
462 /// `Program.function_return_concrete_types` — propagated through
463 /// the linker so the conduit can stamp Call-terminator destination
464 /// slots from the callee's declared return type. Not serialised —
465 /// same rationale.
466 #[serde(skip, default)]
467 pub function_return_concrete_types: Vec<shape_value::v2::ConcreteType>,
468
469 /// ADR-006 §2.7.5 conduit (V3-S6b-jit-method-monomorph-conduit
470 /// close, 2026-05-15): LinkedProgram mirror of
471 /// `Program.monomorphized_method_call_sites` — propagated through
472 /// the linker so the conduit producer can lift
473 /// `function_return_concrete_types[specialized_idx]` into the
474 /// destination slot's ConcreteType at `MirConstant::Method` Call-
475 /// terminator sites. Not serialised — same rationale.
476 #[serde(skip, default)]
477 pub monomorphized_method_call_sites:
478 HashMap<(shape_ast::ast::span::Span, Option<usize>), usize>,
479
480 /// ADR-006 §2.7.5 conduit (cluster-2-cw-IB-class-b close, 2026-05-16):
481 /// LinkedProgram mirror of `Program.value_call_return_concrete_types`
482 /// — propagated through the linker so the conduit producer can stamp
483 /// value-call `TerminatorKind::Call` destination slots from the
484 /// closure-bound callee's inferred return `ConcreteType`. Not
485 /// serialised — same rationale.
486 #[serde(skip, default)]
487 pub value_call_return_concrete_types:
488 HashMap<
489 (shape_ast::ast::span::Span, Option<usize>),
490 shape_value::v2::ConcreteType,
491 >,
492
493 /// ADR-006 §2.7.5 conduit (W10 jit-call-method-user-trait-fix close,
494 /// 2026-05-17): LinkedProgram mirror of
495 /// `Program.operator_trait_dispatch_sites` — propagated through the
496 /// linker so the JIT consumer can re-emit user-type binary/unary
497 /// trait-dispatch as method-call IR. Not serialised — same rationale.
498 #[serde(skip, default)]
499 pub operator_trait_dispatch_sites:
500 HashMap<shape_ast::ast::span::Span, (String, u16)>,
501
502 /// Trait method dispatch registry.
503 pub trait_method_symbols: HashMap<String, String>,
504
505 /// Foreign function metadata table.
506 #[serde(default)]
507 pub foreign_functions: Vec<ForeignFunctionEntry>,
508
509 /// Native `type C` layout metadata table.
510 #[serde(default)]
511 pub native_struct_layouts: Vec<NativeStructLayoutEntry>,
512
513 /// Transitive union of all required permissions across all blobs.
514 /// Computed by the linker during `link()`.
515 #[serde(default = "default_permission_set")]
516 pub total_required_permissions: PermissionSet,
517
518 /// Closure spec §14.6 (H6.5): per-function `ClosureLayout` propagated
519 /// from `BytecodeProgram.closure_function_layouts` so the linked
520 /// program carries enough metadata for `op_make_closure`'s raw
521 /// producer path. `None` entries indicate the function is not a
522 /// closure body or the layout wasn't computed. Not serialised —
523 /// programs loaded from disk fall back to the legacy `HeapValue::
524 /// Closure` variant in the VM producer.
525 #[serde(skip, default)]
526 pub closure_function_layouts:
527 Vec<Option<std::sync::Arc<shape_value::v2::closure_layout::ClosureLayout>>>,
528
529 /// ADR-006 §2.7.24 Q25.C trait-object vtable registry. Keyed by
530 /// `"Trait::ConcreteType"`. Threaded through from the
531 /// content-addressed Program at link time so the VM `op_box_trait_object`
532 /// handler can look up the vtable to build `Arc<TraitObjectStorage>`.
533 /// Not serialised (Arc<VTable> is not a stable wire shape).
534 #[serde(skip, default)]
535 pub trait_vtables: std::collections::HashMap<
536 String,
537 std::sync::Arc<shape_value::value::VTable>,
538 >,
539
540 /// R8 W8 Cluster A surface-and-stop flag (2026-05-25).
541 ///
542 /// Mirrors `BytecodeProgram::has_imported_const_inline`; propagated
543 /// through the linker so the JIT executor (which receives the
544 /// post-link `BytecodeProgram`) can refuse to JIT-compile the program
545 /// when imported `pub const` identifiers were inlined-at-use as
546 /// `PushConst(<value>)` by `compile_expr_identifier`. Triggers W12
547 /// `[jit-fallback]` deopt to bytecode interpreter; root-cause fix in
548 /// JIT identifier-eval lowering is v0.4 per
549 /// `docs/v0.3-close-summary.md` §5.16. NOT serialised — compile-time
550 /// state.
551 #[serde(skip, default)]
552 pub has_imported_const_inline: bool,
553
554 /// R8 W9 B1 W17-marshal-return surface-and-stop flag (2026-05-25).
555 /// Mirror of `Program::has_w17_marshal_residual` propagated through
556 /// the linker so the JIT executor can refuse to JIT-compile programs
557 /// containing direct stdlib-imported function calls. Triggers W12
558 /// `[jit-fallback]` deopt to bytecode interpreter; root-cause fix in
559 /// JIT ModuleFn dispatch (`jit_call_value` arm + `dispatch_module_fn_call`
560 /// `todo!()`) is v0.4 per `docs/v0.3-close-summary.md` §5.16. NOT
561 /// serialised — compile-time state.
562 #[serde(skip, default)]
563 pub has_w17_marshal_residual: bool,
564}