Calling JS object member functions from Wasm

The pong tutorial (https://labs.leaningtech.com/cheerp/tutorials/pong) shows how to handle interactions between JS and Wasm using static functions and global instances. What is the recommended approach for accessing member functions of dynamically created JS objects from Wasm? Example code:
struct [[cheerp::genericjs]] Foo {
client::HTMLElement* span;
Foo() {
span = client::document.createElement("span");
span->set_textContent("Foo");
client::document.get_body()->appendChild(span);
}
void makeBar() {
span->set_textContent("Bar");
}
}

struct [[cheerp::wasm]] Bar {
Foo* foo; // obviously does not compile
Bar() {
foo = new Foo();
foo->makeBar();
}
}

[[cheerp::wasm]]
void webMain() {
Bar* bar = new Bar();
}
struct [[cheerp::genericjs]] Foo {
client::HTMLElement* span;
Foo() {
span = client::document.createElement("span");
span->set_textContent("Foo");
client::document.get_body()->appendChild(span);
}
void makeBar() {
span->set_textContent("Bar");
}
}

struct [[cheerp::wasm]] Bar {
Foo* foo; // obviously does not compile
Bar() {
foo = new Foo();
foo->makeBar();
}
}

[[cheerp::wasm]]
void webMain() {
Bar* bar = new Bar();
}
Leaning Technologies Developer
Pong with Cheerp - Cheerp Documentation
C/C++ compiler targeting WebAssembly and JavaScript.
apignotti
apignotti53d ago
WebAssembly provides very little access to JavaScript object. This applies to the standard itself, not to the Cheerp compiler. The most common solution is to use indexes into a global [[cheerp::genericjs]] array or table, then use a global or static [[cheerp::genericjs]] method to invoke the method from the array The indexes can be indirectly stored as integers inside any [[cheerp::wasm]] data structure This might sound convoluted, but it's what WebAssembly structurally can allow Some amount of interoperability can be achieved with WasmGC, and we have plans to support than in the short/medium term, but it will come with other side effects, so it's no silver bullet
Pedro
Pedro53d ago
Thank you! I will try it
Pedro
Pedro53d ago
Also, earlier I found this article by @Yuri (https://medium.com/leaningtech/adding-anyref-support-in-a-c-to-webassembly-compiler-2bba3fac707f). Enabling externref made it possible to bring Foo entirely to the Wasm world with a couple of changes to that example code. The generated JS+Wasm seems not to be working, though. Maybe I forgot something? Even then, it seems like this feature could be helpful in some use cases. Is it still being supported/developed?
Medium
Yuri
Yuri52d ago
@Pedro could you post your code? The feature is supported, although a bit limited at the moment. We plan to expand it in the future, also in connection with WasmGC support.
apignotti
apignotti52d ago
@Pedro Anyref allows to pass javascript objects as arguments and use them as return types. There is no support for storing them in a linear memory structure, which is what your code tries to achieve. WebAssembly linear memory is just a large array of bytes, and externref is something that does not have a user-visible representation in bytes.
Pedro
Pedro52d ago
Pedro
Pedro52d ago
main.cpp:
#include <cheerp/client.h>
#include <cheerp/clientlib.h>

struct [[cheerp::wasm]] Foo {
Foo() {
client::HTMLElement* span;
span = client::document.createElement("span");
span->set_textContent("Foo");
client::document.get_body()->appendChild(span);
}
void makeBar() {
client::HTMLElement* span;
span = (client::HTMLElement*) client::document.querySelector("span");
span->set_textContent("Bar");
}
};

struct [[cheerp::wasm]] Bar {
Foo* foo; // now it does compile
Bar() {
Foo* foo = new Foo();
foo->makeBar();
}
};

[[cheerp::wasm]]
void webMain() {
Bar* bar = new Bar();
}
#include <cheerp/client.h>
#include <cheerp/clientlib.h>

struct [[cheerp::wasm]] Foo {
Foo() {
client::HTMLElement* span;
span = client::document.createElement("span");
span->set_textContent("Foo");
client::document.get_body()->appendChild(span);
}
void makeBar() {
client::HTMLElement* span;
span = (client::HTMLElement*) client::document.querySelector("span");
span->set_textContent("Bar");
}
};

struct [[cheerp::wasm]] Bar {
Foo* foo; // now it does compile
Bar() {
Foo* foo = new Foo();
foo->makeBar();
}
};

[[cheerp::wasm]]
void webMain() {
Bar* bar = new Bar();
}
Makefile:
all: main.wasm

main.wasm: main.cpp
/opt/cheerp/bin/clang++ -target cheerp-wasm main.cpp -o main.js -cheerp-wasm-externref -cheerp-pretty-code

serve:
python3 -m http.server 8000

open:
firefox localhost:8000

clean:
rm main.js main.wasm

.PHONY: all, serve, open, clean
all: main.wasm

main.wasm: main.cpp
/opt/cheerp/bin/clang++ -target cheerp-wasm main.cpp -o main.js -cheerp-wasm-externref -cheerp-pretty-code

serve:
python3 -m http.server 8000

open:
firefox localhost:8000

clean:
rm main.js main.wasm

.PHONY: all, serve, open, clean
Oh, I see, thank you for the explanation! Yuri did mention it in his article. Also, I indeed had to make some changes to the code to make it work, more specifically, now I get a reference to the span element every time I want to access it.
Pedro
Pedro52d ago
It still doesn't seem to work, though, despite compiling. I reckon I may have done something wrong. The browser complains of an invalid character in the string that is passed to document.createElement in the generated JS.
No description
Yuri
Yuri51d ago
I think that there is a compiler bug happening here. We need to investigate this further. As a general advice, to solve the issue of storing js data and use it from wasm: instead of trying to convert everything to wasm, try to have the "top-level" of your code in js, and call into a wasm function with the state it needs as parameters. You cannot store pointers to js memory in a [[cheerp::wasm]] struct, but you CAN do the opposite.
DutChen18
DutChen1845d ago
Hi @Pedro, we have fixed several bugs related to externref in the latest nightly build of cheerp. Please try again with the new build and let us know if you encounter any more issues.
Pedro
Pedro19d ago
Hello, thank you! Will try it
Want results from more Discord servers?
Add your server
More Posts
How to start CheerojI hadn't learned any java. How to use Cheerpj step by step?Options for running Java versions more recent than Java 8I'm a doctoral researcher, and part of my tasks is providing technical support for grading student pCheerpJ missing functionality of original Jar fileI am trying to get my java swing projects in the browser, but the program is not working fully (it wI'd like to run NASA's Rocket Modeler on my laptop.I see from the NASA webpage https://www1.grc.nasa.gov/wp-content/plugins/cheerpj-integration/lib/appAccessing Java class / object attributes in CheerpJ based PWAI'm new to CheerpJ and I am working on creating a React Native module for ImageJ.js (CheerpJ translaInt ConversionThere is a function in Java, that calls a native function with string argument, like `setContentViewState of the C++ modules supportWhen the new C++ modules are expected to be supported?Cheerpj hangs after "Jar is loaded,main is starting"I am trying to use cheerpj to run my Java Swing app in a browser. I can run the example SwingSet3.jaStretch to Fit Height IssueRunning a basic application in the example html provided on the CheerpJ website. My html code is efProblems with CheerpjHello, I am trying to get my Java app running in CheerPJ - I was successful in creating a simple "HeCache Results for Faster Startup?Hello new user here. Performing initial research into potential commercial application usage. 1) AmUnknownHostException happened when the Java application connect to serverUnknownHostException happened when the Java application connect to server. The host name is the sameHTTP server returned compressed partial data. That should not happen. CheerpJ cannot run.Browser shows error "HTTP server returned compressed partial data. That should not happen. CheerpJ cAccesing the standard out and standard error stream from the Java processHow do I from javascript access the output streams from the started Java process?Any plan on adding internet access without Tailscale?Hi there ! Do you plan on adding internet access without the need to install Tailscale etc, that wour[((0 + c) | 0)] is not a function when instantiating objectHello, thank you all for developing CheerpJ, it is an impressive tool! I am playing around with tryiI'm always looking for the URL of the latest build of cj3loader.js by searching articlesI'm always looking for the URL of the latest build of cj3loader.js by searching articles, but is theDifferent behavior between extension and cj3loaderWe have a java applet that runs perfectly when using the CheerpJ browser extension, but fails to fulCan I try CheerpX?I know it's not fully ready yet, but I think it's fine for my use cases in its current staterunning java decompiler in browser, weird error(copy-pasting from #cheerpj3 since i noticed this channel existed) i'm trying to run the procyon jav