return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len));
}
+ const testCallExport = (a, b) => {
+ return this._inst.exports.testExport(a, b);
+ }
+
const timeOrigin = Date.now() - performance.now();
this.importObject = {
_gotest: {
add: (a, b) => a + b,
+ callExport: testCallExport,
},
gojs: {
// Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
ctxt.Out.WriteByte(0x02) // mem export
writeUleb128(ctxt.Out, 0) // memidx
case "js":
- writeUleb128(ctxt.Out, 4) // number of exports
+ writeUleb128(ctxt.Out, uint64(4+len(ldr.WasmExports))) // number of exports
for _, name := range []string{"run", "resume", "getsp"} {
s := ldr.Lookup("wasm_export_"+name, 0)
if s == 0 {
ctxt.Out.WriteByte(0x00) // func export
writeUleb128(ctxt.Out, uint64(idx)) // funcidx
}
+ for _, s := range ldr.WasmExports {
+ idx := uint32(lenHostImports) + uint32(ldr.SymValue(s)>>16) - funcValueOffset
+ writeName(ctxt.Out, ldr.SymName(s))
+ ctxt.Out.WriteByte(0x00) // func export
+ writeUleb128(ctxt.Out, uint64(idx)) // funcidx
+ }
writeName(ctxt.Out, "mem") // inst.exports.mem in wasm_exec.js
ctxt.Out.WriteByte(0x02) // mem export
writeUleb128(ctxt.Out, 0) // memidx
}
}
+// testCallExport is imported from host (wasm_exec.js), which calls testExport.
+//
+//go:wasmimport _gotest callExport
+func testCallExport(a int32, b int64) int64
+
+//go:wasmexport testExport
+func testExport(a int32, b int64) int64 {
+ testExportCalled = true
+ // test stack growth
+ growStack(1000)
+ // force a goroutine switch
+ ch := make(chan int64)
+ go func() {
+ ch <- int64(a)
+ ch <- b
+ }()
+ return <-ch + <-ch
+}
+
+var testExportCalled bool
+
+func growStack(n int64) {
+ if n > 0 {
+ growStack(n - 1)
+ }
+}
+
+func TestWasmExport(t *testing.T) {
+ testExportCalled = false
+ a := int32(123)
+ b := int64(456)
+ want := int64(a) + b
+ if got := testCallExport(a, b); got != want {
+ t.Errorf("got %v, want %v", got, want)
+ }
+ if !testExportCalled {
+ t.Error("testExport not called")
+ }
+}
+
func TestBool(t *testing.T) {
want := true
o := dummys.Get("someBool")
// Note: All JavaScript functions return a JavaScript array, which will cause
// one allocation to be created to track the Value.gcPtr for the Value finalizer.
var allocTests = []struct {
- argLen int // The number of arguments to use for the syscall
+ argLen int // The number of arguments to use for the syscall
expected int // The expected number of allocations
}{
// For less than or equal to 16 arguments, we expect 1 allocation:
// - makeValue new(ref)
- {0, 1},
- {2, 1},
+ {0, 1},
+ {2, 1},
{15, 1},
{16, 1},
// For greater than 16 arguments, we expect 3 allocation:
tmpArray := js.Global().Get("Array").New(0)
numAllocs := testing.AllocsPerRun(100, func() {
tmpArray.Call("concat", args...)
- });
+ })
if numAllocs != float64(test.expected) {
t.Errorf("got numAllocs %#v, want %#v", numAllocs, test.expected)
concatFunc := tmpArray.Get("concat").Call("bind", tmpArray)
numAllocs := testing.AllocsPerRun(100, func() {
concatFunc.Invoke(args...)
- });
+ })
if numAllocs != float64(test.expected) {
t.Errorf("got numAllocs %#v, want %#v", numAllocs, test.expected)
numAllocs := testing.AllocsPerRun(100, func() {
arrayConstructor.New(args...)
- });
+ })
if numAllocs != float64(test.expected) {
t.Errorf("got numAllocs %#v, want %#v", numAllocs, test.expected)