Hi, while testing wit-bindgen for Kotlin guests, I noticed that jco transpile
d program fails to construct imported resource when the corresponding [resource-drop]
function is not imported (it is sometimes removed by the compiler DCE when calls to it are proven unreachable).
Looking through the code, jco transpile
doesn't initialise handleTables
for such resource in trampoline_bindgen.rs. Then on runtime, when calling imported resource constructor
, generated JS function ...
function resourceTransferOwn(handle, fromRid, toRid) {
const { rep } = rscTableRemove(handleTables[fromRid], handle);
return rscTableCreateOwn(handleTables[toRid], rep);
}
... evaluates handleTables[toRid]
to undefined
, causing the construction to crash.
Forcing "[resource-drop]..."
import to stay alive solves the issue. Is this is a requirement for binding generators to keep resource-drops imports alive or a jco transpile
issue?
@Slava Kuzmich this sounds like a Jco bug to me, are you able to share the binary that is causing the issue? Does the resource have no functions at all then that it's table isn't being initialized by its functions?
@Guy Bedford I've attached binaries for both cases: with and without "[resource-drop]x"
(never actually called). Testing setup requires swapping one core module in the final artefact (due to WasmGC). I've included these core files and README with repro steps.
Resource is
resource x {
constructor(a: s32);
get-a: func() -> s32;
set-a: func(a: s32);
add: static func(x: x, a: s32) -> x;
}
But only constructor
and get-a
are actually called.
jco_repro.zip
I've traced that ensure_resource_table
is called for this resource with RID 18 only in "ok" case and only when handling Trampoline::ResourceDrop
@Slava Kuzmich thanks for sharing this - I tried running the replication but it doesn't seem to match the expectation. In the fail case I get a GC error, even when copying the core Wasm, while in the ok case I get a Wasm core erro, and when running --tracing
in Jco transpile I can't see any other calls at all, or any resource calls. The core Wasms might not be lining up properly in the replication I think for the GC copy.
Can you confirm which version of Jco you are using? I'm just releasing Jco 1.2.0, it would be great to ensure the replication is fully working on that one.
Thanks for looking into it! I've checked with jco 1.2.1, the problem reproduced in the same way:
file:///Users/skuzmich/Downloads/jco_repro/fail/out/kco-wasm-wasi.mjs:81
const free = table[0] & ~T_FLAG;
^
TypeError: Cannot read properties of undefined (reading '0')
at rscTableCreateOwn (file:///Users/skuzmich/Downloads/jco_repro/fail/out/kco-wasm-wasi.mjs:81:21)
at resourceTransferOwn (file:///Users/skuzmich/Downloads/jco_repro/fail/out/kco-wasm-wasi.mjs:114:10)
at wasm://wasm/437a0c32:wasm-function[10]:0x1c3
at <kco>.Jsiface.constructorX (wasm://wasm/<kco>-00082e3e:wasm-function[536]:0xb6be)
at <kco>.TestExportsImpl.test (wasm://wasm/<kco>-00082e3e:wasm-function[515]:0xb07e)
at <kco>.__wasm_export_test (wasm://wasm/<kco>-00082e3e:wasm-function[607]:0xe230)
at Object.test (file:///Users/skuzmich/Downloads/jco_repro/fail/out/kco-wasm-wasi.mjs:4080:35)
at [eval]:1:54
What kind of GC errors do you get? Note that Node.js v22.0.0 is needed, as previous versions don't have the final GC support.
The core Wasms might not be lining up properly in the replication I think for the GC copy.
It lines up for me. Note that both ok and fail cases have separate respective core files. Also, jco needs to run with --base-cutoff 0
, otherwise core files could be named differently.
when I follow the steps exactly I get this in the failing case:
wasm://wasm/952a0726:1
RuntimeError: unreachable
at wasm://wasm/952a0726:wasm-function[30]:0x517
at Object.test (file:///Users/gbedford/Projects/jco/out/kco-wasm-wasi.js:4173:35)
at file:///Users/gbedford/Projects/jco/test.mjs:3:6
Node.js v22.0.0
where the unreachable is the call at
function test() {
exports9['cm:example/test#test']();
}
no other calls happen
ohh wait I finally got it to work, yeah the base64 cutoff and Node.js versions were quite specific
looking into it now
So on further thought here I think the crash is actually valid
If you have a resource that is never dropped, that's not valid
Now certainly, there should be a better error
but from a component model perspective, creating a resource and never disposing it seems odd
I've posted a fix in https://github.com/bytecodealliance/jco/pull/430, but I can't land it without properly understanding what is going on here
specifically, what is the composition scenario here that results in an own transfer but not a drop?
After further thought, if this component works in Wasmtime it has to work in Jco, so I've gone ahead and published the fix in jco@1.2.2.
Thanks a lot for the fix!
In the attached example resource is leaked by accident.
I haven't found any indication that leaking resource is not valid in the spec. Also, there could be programs that don't leak resources, but also never drop. For example, constructing a resource and processing it in an infinite loop:
var resource = new R();
while (true) {
resource.tick();
}
We can't call the drop here, as the resource is needed "forever".
Slava Kuzmich has marked this topic as resolved.
thanks for clarifying, yes a singleton resource is similar to the component lifetime itself, and there may be use cases there
Last updated: Dec 23 2024 at 12:05 UTC