How to access the WebAssembly memory (shared with JS) with the TeaVM API?

321 views
Skip to first unread message

Bruno Salmon

unread,
Oct 13, 2020, 6:47:10 PM10/13/20
to TeaVM
hi,

I would like to pass some data other than numbers to a WebAssembly function compiled by TeaVM through a serialization in the memory buffer.

So if my Javascript code looks like this:

const memory = new WebAssembly.Memory({initial: 256});
const array = new Int16Array(memory.buffer);
array.set(firstElement, 0);
...
WebAssembly.instantiate(..., {env: {memory: memory}, teavm: {...}}).then(... instance.exports.myWebAssemblyFunction());

How can I read this data located at the beginning of the memory from the Java code that will be compiled by TeaVM?

I tried:

@Export(name = "myWebAssemblyFunction")
public static void myWebAssemblyFunction() {
        Address address = Address.fromInt(0); 
        short firstElement = address.getShort(); // 16 bits type
...
}

Thinking that Address.fromInt(0) will point to the beginning of the memory but when I run this, I'm getting firstElement = 0 instead of my first element set by my JavaScript code, so that's probably not the right way.

What's the correct way to do this with TeaVM API?

Alexey Andreev

unread,
Oct 14, 2020, 7:18:22 AM10/14/20
to TeaVM
Hello. Not sure if it's TeaVM issue. Did you read Wasm spec carefully? Please, learn this thing in detail. May it be due to Wasm rewrites heap data with module initial data? Also, I haven't ever tested Wasm with this way of instantiation of module. TeaVM exports Wasm heap as 'memory', so you can try standard approach to instantiate module and then get heap as instance.exports.memory. Also, please not that before calling exported functions you shoud call `main()` method first, so that VM inside it is propertly initialized.

I should tell that approach you chosen to transfer data between Java and JS is wrong. Please, don't write to random address of Wasm heap, this may corrupt VM heap and application will crash in some unpredictable way. Instead, you should allocate byte array in Java and get its address by Address.ofData function. Also, this approach won't work for the case of calling Java from JS (please, note that using `@Export` annotation is very undesirable from user's code, it was mostly designed for Wasm runtime, there's still no 'official' way to call Java from JS). It won't work since by the time you call Java from JS, VM can relocate array (and it's only guaranteed that VM won't relocate array when you call JS from Java).

So my suggestion is to give up. Wasm was an experiment, but it did not show a good result. Produced binary is much bigger than JS, it's slower and has problems with interacting with JS. So using JavaScript backend is preferred use case for TeaVM, Wasm does not give any significant advantages, since it was not designed to support high-level languages like Java. If you still want to use Wasm for some reason, you should dig into TeaVM code and invent some mechanism to safely call Java from JS and pass something more complex than primitive values.

Bruno Salmon

unread,
Oct 19, 2020, 3:07:44 PM10/19/20
to TeaVM
Thank you Alexey for the trick about exports.memory, that's what I missed. So I managed to pass my data to the WebAssembly instance thanks to it. Just after instantiating the WebAssembly module, my JS code keeps the reference to exports.memory and makes a first preliminary call to the WebAssembly instance so it creates a byte buffer that will receive the data and this call returns to JS the address of the buffer using Address.ofData as you suggested. Then the JS code uses this address as an offset on the exports.memory to serialize the arguments using the typed arrays API (Int8Array, Int16Array, Int32Array, etc...). Then it calls the WebAssembly main function that deserializes these arguments and finally does its job! :)

Right, I'm using @Export to call a specific function of my WebAssembly module (1 for the preliminary function and another 1 for the main function) and it works. If one day there is a more official TeaVM way to achieve this, I'm happy to do it.

You said the exports.memory is the standard approach (so basically memory created by WebAssembly and then passed back to JS) but most of the examples I saw are using the other way (memory created by JS and then passed to WebAssembly). So not sure what the standard approach is (if there is one). This second way (JS -> WebAssembly) is also the only way to create a shared memory between different WebAssembly modules, which can lead to big performance improvements in some cases. So I still would prefer that way, but are you saying this is not possible with TeaVM?

You're right, WebAssembly is not that fast, far behind the JVM performance for example despite the similar approach. But perhaps they will make some progress in the next version. Also there are probably some areas where it can be already faster than JS, for example in heavy computation. The only fact that it has different number primitive types as opposed to JS should lead to better performance. The app I'm currently writing is to test this, so I will let you know when it will be ready, hopefully soon.

ScraM Team

unread,
Oct 23, 2020, 8:06:19 PM10/23/20
to TeaVM
Bruno,

Thank you for testing out WASM with TeaVM.  It seems like there some interest in using it (based on periodic questions posted here), so it's great to monitor progress on performance of WASM in the browser.  While for my purposes the JavaScript backend is great for now, I will become more interested if WASM performance improves.

Jérôme CHOAIN

unread,
Dec 11, 2020, 11:08:41 AM12/11/20
to TeaVM
> there's still no 'official' way to call Java from JS

Hi,
Do you mean "Calling Java from JavaScript" chapter is not to read ? http://teavm.org/docs/runtime/jso.html

I search for solutions to run java code on the client side, with no server calls after loading the what's need to be loaded.

jerome

Alexey Andreev

unread,
Dec 11, 2020, 11:14:01 AM12/11/20
to te...@googlegroups.com
> Do you mean "Calling Java from JavaScript" chapter is not to read ?
> http://teavm.org/docs/runtime/jso.html
> <http://teavm.org/docs/runtime/jso.html>
This chapter only describes JS backend version of TeaVM. JSO is not
available on Wasm BE.


> I search for solutions to run java code on the client side, with no
> server calls after loading the what's need to be loaded.
Then you don't need Wasm. You can use TeaVM JS BE, which is much better
and mature that Wasm BE. Translation of Java to Wasm does not bring any
advantage over translation of Java to JS.

Jérôme CHOAIN

unread,
Dec 11, 2020, 12:09:56 PM12/11/20
to TeaVM
thanks !
I'm a bit lost :) What does mean "BE" please?

Alexey Andreev

unread,
Dec 11, 2020, 12:11:14 PM12/11/20
to te...@googlegroups.com

> thanks !
> I'm a bit lost :) What does mean "BE" please?
>
It means 'back end'. TeaVM has tree back ends: JS, Wasm and C.

Jérôme CHOAIN

unread,
Dec 11, 2020, 12:13:19 PM12/11/20
to TeaVM
ok, thanks!

jerome
Reply all
Reply to author
Forward
0 new messages