diff --git a/current/CHECKPOINT-COMPILER-API.md b/current/CHECKPOINT-COMPILER-API.md index 1c9bba05..38b9b133 100644 --- a/current/CHECKPOINT-COMPILER-API.md +++ b/current/CHECKPOINT-COMPILER-API.md @@ -325,6 +325,21 @@ when reached (sentinels or accessor fns; see the design doc Risks). `List` growth; orthogonal, see `current/CHECKPOINT-METATYPE.md`.) ## Log +- **Phase 3 P3.4 step 1 (VM plan) — lowering-time default context; first blocker cleared (2026-06-18).** + `materializeDefaultContext` now falls back to a ZEROED `Context` (found by name) when the + `__sx_default_context` global is absent — i.e. at LOWERING time, where the global isn't + emitted yet. A type-fn that never touches the allocator now runs past context setup; one + that allocates reads a null `alloc_fn` (zeroed) → `call_indirect` on the null func-ref + bails → legacy fallback (a REAL lowering-time context with the CAllocator thunk func-refs, + so allocating type-fns also run on the VM, is a follow-up). **Measurement: the bail moved + deeper** — metatype `make_enum` now bails at `const_type` (the `Type`-literal op, unported); + `register_type` type-fns bail at the welded write call (declare_type/register_type aren't in + `callCompilerFn`). No table mutation happens before either bail (the write fns bail before + minting), so parity holds: both gates **697/0**, no crashes. **Next blockers (the "model + Type" chunk):** (a) the `const_type` op → a word = `TypeId.index()`; (b) the Type-return + bridge (`regToValue` for a `Type`/`.any` word → `.type_tag`); (c) the VM-native write side + (declare_type/register_type/pointer_to in `callCompilerFn`) + a real lowering-time context. + Only once those land does a type-fn actually run end-to-end on the VM (a HANDLED case). - **Phase 3 P3.4 (VM plan) — wire the VM at the LOWERING-time site + measure (2026-06-18).** Routed `runComptimeTypeFunc` (the type-fn fold — the THIRD comptime call site) through `comptime_vm.tryEval` behind `-Dcomptime-flat`/`SX_COMPTIME_FLAT` with legacy fallback, diff --git a/src/ir/comptime_vm.zig b/src/ir/comptime_vm.zig index befa6870..90959383 100644 --- a/src/ir/comptime_vm.zig +++ b/src/ir/comptime_vm.zig @@ -334,7 +334,19 @@ pub const Vm = struct { if (g.init_val) |iv| try self.layoutConst(table, iv, g.ty, addr); return addr; } - return self.failMsg("comptime VM: no __sx_default_context global to materialize the implicit context"); + // No `__sx_default_context` global yet — this is the LOWERING-time path + // (the global is emitted later, at codegen). Materialize a ZEROED `Context` + // of the right size instead: a type-fn that never touches the allocator + // ignores it; one that DOES allocate reads a null `alloc_fn` (zeroed) and + // `call_indirect` on the null func-ref bails → legacy fallback (which has a + // real default context). A real lowering-time context (with the CAllocator + // thunk func-refs, so allocating type-fns also run on the VM) is a follow-up. + // `internString` of an existing name is idempotent (pool-only, no layout + // change) — the same `@constCast` the reader handlers use on the table. + const ctx_name = @constCast(table).internString("Context"); + const ctx_ty = table.findByName(ctx_name) orelse + return self.failMsg("comptime VM: no Context type to materialize the implicit context"); + return self.machine.allocBytes(table.typeSizeBytes(ctx_ty), table.typeAlignBytes(ctx_ty)); // zeroed } /// Lay a static `ConstantValue` of type `ty` into flat memory at `addr` (the