kawamuray / wasmtime-java

Java or JVM-language binding for Wasmtime
Apache License 2.0
129 stars 29 forks source link

[Help Wanted] Why global variables in wasm cannot be altered? #10

Open SuperIceCN opened 3 years ago

SuperIceCN commented 3 years ago

I have a test and it fails. I don't know why the variable result equals to 0.

String wat = /* a .wat file */;
@Test
public void myTest(){
    Engine engine = new Engine();
    Store store = new Store(engine);
    Module module = new Module(engine,wat.getBytes(StandardCharsets.UTF_8));
    Memory memory = new Memory(store,new MemoryType(new MemoryType.Limit(64)));
    Linker linker = new Linker(store);
    WasiConfig wasiConfig = new WasiConfig(new String[]{},new WasiConfig.PreopenDir[]{});
    Wasi wasi = new Wasi(store,wasiConfig);
    wasi.addToLinker(linker);
    linker.define("env","memory",Extern.fromMemory(memory));
    linker.module("a",module);
    linker.getOneByName("a","_start").func().call();
    int result = linker.getOneByName("a","get").func().call()[0].i32();
    Assert.assertEquals(1,result); //failed, result==0
}

here is the .wat file:

(module
  (type $t0 (func (param i32)))
  (type $t1 (func))
  (type $t2 (func (result i32)))
  (import "env" "memory" (memory $env.memory 2))
  (import "wasi_snapshot_preview1" "proc_exit" (func $__wasi_proc_exit (type $t0)))
  (func $__wasm_call_ctors (type $t1))
  (func $_start (type $t1)
    (local $l0 i32)
    call $__wasm_call_ctors
    call $__original_main
    local.set $l0
    call $__wasm_call_dtors
    block $B0
      local.get $l0
      i32.eqz
      br_if $B0
      local.get $l0
      call $__wasi_proc_exit
      unreachable
    end)
  (func $__original_main (type $t2) (result i32)
    i32.const 0
    i32.const 1
    i32.store offset=1024
    i32.const 0)
  (func $get (type $t2) (result i32)
    i32.const 0
    i32.load offset=1024)
  (func $dummy (type $t1))
  (func $__wasm_call_dtors (type $t1)
    call $dummy
    call $dummy)
  (table $T0 1 1 funcref)
  (global $g0 (mut i32) (i32.const 66576))
  (export "_start" (func $_start))
  (export "get" (func $get))
  (data $d0 (i32.const 1024) "\00\00\00\00"))

this wat file is compiled from a c source code file with wasi-sdk:

volatile int a = 0;
int main(){
    a = 1;
    return 0;
}
__attribute__((export_name("get")))
int get(){
    return a;
}

@kawamuray Could please tell me why this happens? Thanks!

kawamuray commented 3 years ago

I think that's because your wasm module is recognized as a "command" rather than a "reactor". Please read https://github.com/WebAssembly/WASI/blob/2ccb606926bee332a7b0a486e150d1053a493977/design/application-abi.md#current-unstable-abi this document for the detail.

In short, when your wasm module contains the _start function, it is recognized as a command type, and for command type an Instance is created for each function invocation, meaning memory isn't shared between calls of _start and get.

You may want to compile your program as reactor-type (perhaps as a a shared object) if you want to share memory between multiple calls.