dotnet/runtime · critical · Error
__stack_pointer was not preserved by the linker or optimizer
Error message
__stack_pointer was not preserved by the linker or optimizer
What it means
Thrown by buildWebcilImports() (src/native/libs/Common/JavaScript/host/assets.ts:114) for an R2R webcil asset (tableSize > 0). The host ABI requires the runtime to export __stack_pointer so the R2R image can share the runtime stack; if _ems_.wasmExports.__stack_pointer is falsy, the import cannot be satisfied and instantiation would fail with a confusing link error, so the host throws early.
Source
Thrown at src/native/libs/Common/JavaScript/host/assets.ts:121
}
}
// Builds the `webcil` import object. For R2R images (tableSize > 0) the module imports the runtime's
// stack pointer, exception tag, indirect-call table and base globals; this also grows the table.
// These import names and the webcilVersion/getWebcilPayload/fillWebcilTable handshake in
// finishWebcilInstance are the R2R Webcil-in-Wasm host ABI defined by crossgen's WasmObjectWriter
// (src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs, CreateDefaultGlobalImports/
// WriteExports). Keep in sync with the corerun host
// (src/coreclr/hosts/corerun/wasm/libCorerun.js, BrowserHost_ExternalAssemblyProbe). Unlike corerun,
// which parses data segment 0 for payloadSize/tableSize, this loader receives them from boot config.
function buildWebcilImports(memory: WebAssembly.Memory, payloadPtr: number, tableSize: number): Record<string, WebAssembly.ImportValue> {
const webcilImports: Record<string, WebAssembly.ImportValue> = { memory };
if (tableSize > 0) {
const stackPointer = _ems_.wasmExports?.__stack_pointer;
const rtlRestoreContextTag = _ems_.wasmExports?.__coreclr_wasm_rtlrestorecontext_tag;
const asyncContinuation = _ems_.wasmExports?.__async_continuation;
if (!stackPointer) {
throw new Error("__stack_pointer was not preserved by the linker or optimizer");
}
if (!rtlRestoreContextTag) {
throw new Error("__coreclr_wasm_rtlrestorecontext_tag was not preserved by the linker or optimizer");
}
if (!asyncContinuation) {
throw new Error("__async_continuation was not preserved by the linker or optimizer");
}
const tableStartIndex = _ems_.wasmTable.length;
_ems_.wasmTable.grow(tableSize);
webcilImports.stackPointer = stackPointer;
webcilImports.rtlRestoreContextTag = rtlRestoreContextTag as unknown as WebAssembly.ImportValue;
webcilImports.asyncContinuation = asyncContinuation as unknown as WebAssembly.ImportValue;
webcilImports.table = _ems_.wasmTable;
webcilImports.tableBase = new WebAssembly.Global({ value: "i32", mutable: false }, tableStartIndex);
webcilImports.imageBase = new WebAssembly.Global({ value: "i32", mutable: false }, payloadPtr);
}
return webcilImports;
}View on GitHub (pinned to 60108ba66e)
Solutions
- Rebuild the runtime with the standard linker flags that preserve __stack_pointer (the default emscripten/runtime build does this).
- Ensure the runtime .wasm version matches the toolchain that produced the R2R webcil assembly.
- If customizing the build, add __stack_pointer (and the sibling exports) to the linker --export list.
Example fix
# before: custom linker flags drop internal exports emcc ... -s EXPORTED_FUNCTIONS=[] # after: keep the host-ABI exports emcc ... \ -s EXPORTED_FUNCTIONS=[__stack_pointer,__coreclr_wasm_rtlrestorecontext_tag,__async_continuation]
Defensive patterns
Strategy: validation
Validate before calling
function runtimeExportsStackPointer(): boolean {
return !!((globalThis as any).Module?.wasmExports?.__stack_pointer);
} Type guard
function hasStackPointer(exp: any): exp is { __stack_pointer: WebAssembly.Global } {
return exp && !!exp.__stack_pointer;
} Prevention
- Build the runtime with the default linker flags that preserve __stack_pointer.
- Match the R2R assembly toolchain version to the runtime version.
- Add the host-ABI exports to the linker --export list when customizing the build.
When it happens
Trigger: An R2R (ReadyToRun) webcil assembly is being instantiated, tableSize > 0, and the loaded runtime wasm module does not export __stack_pointer. This means the runtime was built/linked with an optimizer or linker that stripped or renamed the export.
Common situations: Building the runtime with a custom emscripten/linker config that drops --export __stack_pointer; using an R2R assembly produced by a newer toolchain against an older runtime that lacks the export; a misconfigured linker 'export-keep' list.
Related errors
- __coreclr_wasm_rtlrestorecontext_tag was not preserved by th
- __async_continuation was not preserved by the linker or opti
- Unsupported Webcil version: ${webcilVersion}
- Unsupported Webcil version: ${webcilVersion}
- cwrap ${name} not found or not a function
AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10).
Data as JSON: /api/errors/537f907573b9329b.
Report an issue: GitHub.