i-net-software / JWebAssembly

Java bytecode to WebAssembly compiler
Apache License 2.0
985 stars 64 forks source link

Passing parameters into exported functions #48

Closed stackjohn closed 2 years ago

stackjohn commented 2 years ago

Hello, thank you for providing this.

Lets say we have the example code:

public class HelloWorld {

    @Export
    public static void main(String test) {
        Document document = Window.document();
        HTMLElement div = document.createElement("div");
        Text text = document.createTextNode(test + " - this text come from WebAssembly."); 
        div.appendChild( text );
        document.body().appendChild( div );
    }
}

Then in the html we have:

  <script>
    var helloworld = "Hello World!";
    WebAssembly.instantiateStreaming(fetch('HelloWorld.wasm'), wasmImports)
      .then(obj => obj.instance.exports.main(helloworld))
      .catch((err) => document.write(err + '<p>Missing <a href="https://github.com/i-net-software/JWebAssembly/wiki/browser">Browser Support</a>') );
  </script>

If I run this I end up with:

RuntimeError: null function or function signature mismatch. 

In this discussion it's mentioned that https://github.com/WebAssembly/stringref should be used. Would it be possible to provide an example of how this looks in both the Java and JS code(if different to the above) 🙏 ?

Thank you.

Horcrux7 commented 2 years ago

In this discussion I mentioned that the current solution can be change in the future if the stringref will be implemented in the WebAssembly runtime. This is currently not the case.

Until there will be another solution you can only use: JSObject.domString(str) and JSObject.toJavaString(str)

Use Object as signature type and not String.

stackjohn commented 2 years ago

Thanks for replying @Horcrux7.

Forgive me but I can't seem to make it work. Can you give me an example of how the exported function should look?

I've tried:

@Export
    public static void main(String test) {
@Export
    public static void main(Object test) {
@Export
    public static void main(JSObject test) {

It all compiles fine, but each time I try to run it, it fails with the same error:

RuntimeError: null function or function signature mismatch. 

Which I assume means the type I am using for test is not matching what is being passed in via the javascript. I've even tried passing in an object from javascript rather than a string but still get the same error.

I've searched on GitHub for JSObject.toJavaString(str) but can't seem to find any examples of how this is used. I assume that is supposed to be called in the Java code, and converts the passed javascript string into a Java string you can then work with?

If you could provide a working example I would be very grateful 🙇

Horcrux7 commented 2 years ago

Take a look into the JSObject in the method getStr(String).

@Export
public static void main( Object jsstr ) {
    String test = JSObject.toJavaString( jsstr ); 
    ...
}

If you compile with debug=true you should receive a more helpful stacktrace of the error with a line number of the Java code. Can be that the problem is on a different place.

stackjohn commented 2 years ago

Thanks. I've had a look at using:

String test = JSObject.toJavaString( jsstr ); 

However I get:

error: cannot find symbol
         String test = JSObject.toJavaString( jsstr );
                               ^
    symbol: method toJavaString(java.lang.Object)
    location: class de.inetsoftware.jwebassembly.web.JSObject

I'm importing it via:

import de.inetsoftware.jwebassembly.web.JSObject

My build.gradle file looks exactly as it would if you followed the guide here

repositories {
    maven { url 'https://jitpack.io' }
}
dependencies {
    implementation 'com.github.i-net-software:jwebassembly-api:master-SNAPSHOT'
}

wasm {
  //Get more debug information if there are problems.
  logging.level = LogLevel.DEBUG
  //logging.levelInternal = LogLevel.DEBUG
  compilerVersion = 'com.github.i-net-software:jwebassembly:master-SNAPSHOT'
  debugNames = true
}
Horcrux7 commented 2 years ago

If you get java compiler error then this is not a JWebAssembly problem. Then this is a simple Java problem.

Can be that you have a very old Gradle cache. The method was added for 2 month. Clear your caches. You can also force the latest version via ID instead to use the snapshot version.

stackjohn commented 2 years ago

@Horcrux7 are the builds working for the latest commits?

If I go to https://jitpack.io/#i-net-software/jwebassembly-api/

The latest green build is v0.4

That tag in github does not have the toJavaString function.

If you navigate to https://javadoc.jitpack.io/com/github/i-net-software/jwebassembly-api/master-SNAPSHOT/

It redirects you to master-v0.3-gd1a41d3-58, which seems like an older release.

I've cleared my gradle cache and even tried just building in a docker image, still the same.

Horcrux7 commented 2 years ago

Thanks for pointing this problem. I use ever a local build. Now it has build on Jitpack.

stackjohn commented 2 years ago

That's sorted it! It works! 😃

As you said above with this

@Export
public static void main( Object jsstr ) {
    String test = JSObject.toJavaString( jsstr ); 
    ...
}

Thank you for your patience 👍