I'm sorry for asking so many questions, but I have...
# webassembly
l
I'm sorry for asking so many questions, but I have a question that I haven't seen answered in the Kotlin documentation (since it's alpha, I guess). I ported all my kotlin JS code over to webassembly, but I'm having trouble loading the wasm. I can't use the generated js file, since it refers to
document
internally, and my code runs in a webworker. What is the correct way to instantiate and run the
.wasm
file that I compiled? I'm getting error that suggest that I need a specific
importObject
when I call
WebAssembly.instantiateStreaming
, but it's not clear what that should contain.
a
just for clarity, do you need to run your wasm in a Web Worker?
l
@andylamax Yes, exactly. The frontend is regular Kotlin compiled to JS, but the webworker is wasm.
Or rather, I want the webworker to be wasm, but I haven't been able to load the wasm file in the webworker due to the issues noted above.
Basically, the software is a language interpreter, and it's implemented as a multiplatform project. The JS implementation runs the computation engine in a webworker. However, if I can run it in wasm instead, that'll increase the performance of the language noticeably.
The project is open source: https://codeberg.org/loke/array
a
I haven't tried running wasm in a web worker, but I think instantiating it from the browser is okay because it wont be executed in the browser's thread anyway
l
I'm not too familiar with wasm, but in my case the appication is designed to run in a webworker (the UI is designed to send requests to the webworker for evaluating expressions).
Is there any information how to directly load the wasm?
a
you can read here how to directly load the wasm. https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/instantiateStreaming_static And even with wasm, the UI will still be sending the requests to the wasm modules for evaluating expressions
l
Yes, I read that. But the wasm generated by Kotlin has some particular requirements regarding the
importObject
that doesn't appear to be documented.
a
Perhaps I do not fully understand your problem then. Are you failing to load the wasm binary generated by kotlin??
Can we jump on a quick call if that's okay with you?
l
Sorry. I'm only looking at this with one eye (at work now, and this is for my personal open source project). Thank you very much for paying attention though. 🙂 When I come home tonight, I'll try it again and post the actual errors I'm getting, along with an explanation of what I believe to be the issue.
Again, thanks a lot for your help.
a
No worries at all
l
OK, I've done some research:
The documentation states that the second argument to
instantiateStreaming
is optional, but that: "There must be one matching property for each declared import of the compiled module or else a WebAssembly.LinkError is thrown". This is what happens when I skip the importObject argument altogether:
This is what by resulting webworker file looks like:
Copy code
WebAssembly.instantiateStreaming(fetch("array-clientweb2-webworker-wasmjs.wasm")).then(
    (results) => {
        console.log("Result = " + results)
    },
);
This gives me this error:
Copy code
TypeError: second argument must be an object
OK, fine, let's pass an empty object to see if it tells us anything else. Now we're getting this:
Copy code
TypeError: import object field 'js_code' is not an Object
At this point I started looking at what the generated wrapper script from the compiler looks like. Surely it must specify a
js_code
somewhere. Turns out that it does, and it's a lot. One of the intermediary files is called
array-clientweb2-webworker-wasmjs.uninstantiated.mjs
and contains the definition for this argument. It's a huge list of functions, listing every entry point into normal js code that can be called from the wasm). It actually makes sense, since wasm doesn't havr arbitrary access to the surrounding js environment. So the compiler prepares entry points for everything that will need to be called.
The problem is that this is all compiled down to the actual entry point, which is a file called
compute-queue-worker-wasm.js
in my case, which handles all of this magic. The issue is that this generated file refers to `document`because it assumes it's being loaded in a regular browser environment. I don't fully understand what it's trying to do, but it does check the document for a
<script>
tag and some other things that is completely unnecessary in a webworker.
@ephemient I'm sorry for pinging you directly. But based on your comments in a different thread, you seem to be familiar with the wasm wrapper. I have an issue where the wasm wrapper references
docuemnt
which is not available in a webworker. Do you know if there is a way to use the wrapper in such a was that
document
is not used, so I can load it from a webworker?
e
I also tried loading wasmJs in a worker recently, and came to the conclusion that you'd have to re-implement the wrapper. which isn't impossible, but was more work than I wanted to do
l
@ephemient Thanks. That's the same conclusion I had. I am not going to reimplemnet it, but I was thinking of an alternative: Would it be possible to somehow create a wrapper around that wrapper that provides a stub implementation of
document
that returns empty results for whatever it is that the wrapper expects?
e
basically, polyfill
document
? possibly
I don't see that as being less work, but I guess it's possible to do without modifying Kotlin
l
I'm not sure how to do that technically though. You'd need some kind of blocking "include" from the wrapper's wrapper?
The proper solution would be to fix kotlin so it doesn't try to access
document
if it's not defined. Perhaps a better approach would be to file a bug report and wait for things to be fixed. 🙂
I tried modifying the wrapper to add the stub
document
, but it's complicated. It tried to call
document.createElement
to create a new
<script>
element and then put stuff in there. It's a mess, and not very easy.
@ephemient I will create a bug report for this.