Skip to content
7 changes: 7 additions & 0 deletions majit/gate-triage.md
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,13 @@ Each entry records its reader, purpose, and retirement condition. `UNRECORDED` m
- What it does: **UNRECORDED** — no doc comment at the read site.
- Retirement condition: **UNRECORDED** — owed by this gate's owner.

### `MAJIT_TRACE_ENTRY_CENSUS`

- Read sites: 1 — `majit/majit-backend-wasm/src/lib.rs`
- Accessor: `trace_entry_census_enabled()`; the wasm guest has no environment, so a host arms the same facility through `trace_entry_census_force()`
- What it does: Counts entries into each emitted trace module per resume key, so a steady state can be attributed to the module and dispatch key it re-enters.
- Retirement condition: Remove when the wasm trace-crossing epic closes and per-key entry counts are no longer the way that budget is attributed.

### `MAJIT_VERIFY`

- Read sites: 1 — `majit/majit-backend-cranelift/src/compiler.rs`
Expand Down
31 changes: 27 additions & 4 deletions majit/majit-backend-wasm/js/jit_glue.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,16 @@ function jitCallTrampoline(framePtr, callAreaOfs = CALL_RESULT_OFS) {
}

export function jit_compile_wasm(bytesPtr, bytesLen) {
const trace = instantiateTrace(bytesPtr, bytesLen);
return registerTrace(trace);
}

function instantiateTrace(bytesPtr, bytesLen) {
if (!mainMemory) {
throw new Error("jit_set_memory() must be called before jit_compile_wasm()");
}
const bytes = new Uint8Array(mainMemory.buffer, bytesPtr, bytesLen).slice();
const module = new WebAssembly.Module(bytes);
const imports = { env: { memory: mainMemory } };

// Check if the module needs jit_call import
// (wasm-encoder adds it when trace has CALL ops)
try {
Expand All @@ -71,13 +74,33 @@ export function jit_compile_wasm(bytesPtr, bytesLen) {
const instance = new WebAssembly.Instance(module, {
env: { memory: mainMemory, jit_call: jitCallTrampoline, jit_call_compact: jitCallTrampoline, __indirect_function_table: mainTable }
});
return registerTrace(instance.exports.trace);
return instance.exports.trace;
} catch (e) {
// Retry without jit_call (for traces without CALL ops)
const instance = new WebAssembly.Instance(module, {
env: { memory: mainMemory }
});
return registerTrace(instance.exports.trace);
return instance.exports.trace;
}
}

// Compile and instantiate a trace, then overwrite an existing shared-table
// slot. A caller already running the old function retains that invocation;
// later indirect calls use the replacement.
export function jit_replace_wasm(funcId, bytesPtr, bytesLen) {
try {
if (!funcTable[funcId]) {
return 0;
}
const trace = instantiateTrace(bytesPtr, bytesLen);
if (mainTable) {
mainTable.set(funcId, trace);
}
funcTable[funcId] = trace;
return funcId;
} catch (e) {
console.error('[jit_replace_wasm] failed:', e);
return 0;
}
}

Expand Down
Loading
Loading