diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..67fda6a --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.DS_Store +.idea +inkwasm/.DS_Store +inkwasm/inkwasm_js_test.go +inkwasm/inkwasm_js_test.js +inkwasm/inkwasm_js_test.s \ No newline at end of file diff --git a/bind/bind.go b/bind/bind.go index 58da39a..8594558 100644 --- a/bind/bind.go +++ b/bind/bind.go @@ -30,6 +30,7 @@ type BridgeFuncInfo struct { var BridgeFunc = map[ArgumentMode]map[string]BridgeFuncInfo{ ModeStatic: { + "interface{}": {JS: "globalThis.inkwasm.Load.Interface", Size: 16}, "float32": {JS: "globalThis.inkwasm.Load.Float32", Size: 4}, "float64": {JS: "globalThis.inkwasm.Load.Float64", Size: 8}, "uintptr": {JS: "globalThis.inkwasm.Load.UintPtr", Size: 8}, @@ -51,20 +52,21 @@ var BridgeFunc = map[ArgumentMode]map[string]BridgeFuncInfo{ "inkwasm.object": {JS: "globalThis.inkwasm.Load.InkwasmObject", Size: 16}, }, ModeArray: { - "default": {JS: "globalThis.inkwasm.Load.Array", Size: -1}, - "float32": {JS: "globalThis.inkwasm.Load.ArrayFloat32", Size: 4}, - "float64": {JS: "globalThis.inkwasm.Load.ArrayFloat64", Size: 8}, - "uintptr": {JS: "globalThis.inkwasm.Load.ArrayUintPtr", Size: 8}, - "byte": {JS: "globalThis.inkwasm.Load.ArrayByte", Size: 1}, - "uint8": {JS: "globalThis.inkwasm.Load.ArrayUint8", Size: 1}, - "uint16": {JS: "globalThis.inkwasm.Load.ArrayUint16", Size: 2}, - "uint32": {JS: "globalThis.inkwasm.Load.ArrayUint32", Size: 4}, - "uint64": {JS: "globalThis.inkwasm.Load.ArrayUint64", Size: 8}, - "int8": {JS: "globalThis.inkwasm.Load.ArrayInt8", Size: 1}, - "int16": {JS: "globalThis.inkwasm.Load.ArrayInt16", Size: 2}, - "int32": {JS: "globalThis.inkwasm.Load.ArrayInt32", Size: 4}, - "int64": {JS: "globalThis.inkwasm.Load.ArrayInt64", Size: 8}, - "rune": {JS: "globalThis.inkwasm.Load.ArrayRune", Size: 8}, + "default": {JS: "globalThis.inkwasm.Load.Array", Size: -1}, + "interface{}": {JS: "globalThis.inkwasm.Load.ArrayInterface", Size: 16}, + "float32": {JS: "globalThis.inkwasm.Load.ArrayFloat32", Size: 4}, + "float64": {JS: "globalThis.inkwasm.Load.ArrayFloat64", Size: 8}, + "uintptr": {JS: "globalThis.inkwasm.Load.ArrayUintPtr", Size: 8}, + "byte": {JS: "globalThis.inkwasm.Load.ArrayByte", Size: 1}, + "uint8": {JS: "globalThis.inkwasm.Load.ArrayUint8", Size: 1}, + "uint16": {JS: "globalThis.inkwasm.Load.ArrayUint16", Size: 2}, + "uint32": {JS: "globalThis.inkwasm.Load.ArrayUint32", Size: 4}, + "uint64": {JS: "globalThis.inkwasm.Load.ArrayUint64", Size: 8}, + "int8": {JS: "globalThis.inkwasm.Load.ArrayInt8", Size: 1}, + "int16": {JS: "globalThis.inkwasm.Load.ArrayInt16", Size: 2}, + "int32": {JS: "globalThis.inkwasm.Load.ArrayInt32", Size: 4}, + "int64": {JS: "globalThis.inkwasm.Load.ArrayInt64", Size: 8}, + "rune": {JS: "globalThis.inkwasm.Load.ArrayRune", Size: 8}, }, ModeSlice: { "default": {JS: "globalThis.inkwasm.Load.Slice", Size: 24}, diff --git a/inkwasm/args_js.go b/inkwasm/args_js.go index 6c8c487..76abe5d 100644 --- a/inkwasm/args_js.go +++ b/inkwasm/args_js.go @@ -2,123 +2,43 @@ package inkwasm import ( "fmt" - "math/big" - "unsafe" ) -var ( - decodeObject = newBasicDecoder("InkwasmObject") - decodeString = newBasicDecoder("String") - decodeFloat32 = newBasicDecoder("Float32") - decodeFloat64 = newBasicDecoder("Float64") - decodeBool = newBasicDecoder("Bool") - decodeUintptr = newBasicDecoder("UintPtr") - decodeInt = newBasicDecoder("Int") - decodeUint = newBasicDecoder("Uint") - decodeUint8 = newBasicDecoder("Uint8") - decodeInt8 = newBasicDecoder("Int8") - decodeUint16 = newBasicDecoder("Uint16") - decodeInt16 = newBasicDecoder("Int16") - decodeUint32 = newBasicDecoder("Uint32") - decodeInt32 = newBasicDecoder("Int32") - decodeUint64 = newBasicDecoder("Uint64") - decodeInt64 = newBasicDecoder("Int64") - decodeBigInt = newBasicDecoder("BigInt") - decodeUnsafePointer = newBasicDecoder("UnsafePointer") - decodeSliceUint8 = newSliceDecoder("ArrayUint8") - decodeSliceUint16 = newSliceDecoder("ArrayUint16") - decodeSliceUint32 = newSliceDecoder("ArrayUint32") - decodeSliceUint64 = newSliceDecoder("ArrayUint64") - decodeSliceInt8 = newSliceDecoder("ArrayInt8") - decodeSliceInt16 = newSliceDecoder("ArrayInt16") - decodeSliceInt32 = newSliceDecoder("ArrayInt32") - decodeSliceInt64 = newSliceDecoder("ArrayInt64") -) - -func newSliceDecoder(s string) uint64 { - v := getSliceDecoder(getBasicDecoder(s)) - return *(*uint64)(unsafe.Pointer(&v)) -} - -func newBasicDecoder(s string) uint64 { - v := getBasicDecoder(s).value - return *(*uint64)(unsafe.Pointer(&v)) -} - -//inkwasm:get globalThis.inkwasm.Load -func getBasicDecoder(s string) Object - -//inkwasm:func globalThis.inkwasm.Load.SliceOf -func getSliceDecoder(f Object) Object - -// createArgs changes the given interface{}. It is two-word size. To -// avoid allocs, we replace the "type-pointer" to decodeObject. -func createArgs(args []interface{}) ([]int32, error) { - for i, a := range args { - var argDecoder uint64 +// createArgs is now a no-op +// The JS will be responsible to identify the type of the arguments, +// using Go internal structures. +// +// That is used to avoid wrong types of arguments. +func createArgs(args []interface{}) ([]interface{}, error) { + for _, a := range args { switch a.(type) { case Object: - argDecoder = decodeObject case string: - argDecoder = decodeString case float32: - argDecoder = decodeFloat32 case float64: - argDecoder = decodeFloat64 case uintptr: - argDecoder = decodeUintptr case bool: - argDecoder = decodeBool case int: - argDecoder = decodeInt case uint: - argDecoder = decodeUint case uint8: - argDecoder = decodeUint8 case int8: - argDecoder = decodeInt8 case uint16: - argDecoder = decodeUint16 case int16: - argDecoder = decodeInt16 case uint32: - argDecoder = decodeUint32 case int32: - argDecoder = decodeInt32 case uint64: - argDecoder = decodeUint64 case int64: - argDecoder = decodeInt64 - case big.Int: - argDecoder = decodeBigInt - case unsafe.Pointer: - argDecoder = decodeUnsafePointer case []uint8: - argDecoder = decodeSliceUint8 case []int8: - argDecoder = decodeSliceInt8 case []uint16: - argDecoder = decodeSliceUint16 case []int16: - argDecoder = decodeSliceInt16 case []uint32: - argDecoder = decodeSliceUint32 case []int32: - argDecoder = decodeSliceInt32 case []uint64: - argDecoder = decodeSliceUint64 case []int64: - argDecoder = decodeSliceInt64 default: return nil, fmt.Errorf("unsupported argument type of %T", a) } - - // Replace the "type information" from interface{} - // to the Object which decodes current argument. - *(*uint64)(unsafe.Pointer(&args[i])) = argDecoder } - - v := *(*[]int32)(unsafe.Pointer(&args)) - (*[3]uint64)(unsafe.Pointer(&v))[1] *= 4 - return v, nil + return args, nil } diff --git a/inkwasm/inkwasm_js.go b/inkwasm/inkwasm_js.go index cf1507b..86d17f9 100644 --- a/inkwasm/inkwasm_js.go +++ b/inkwasm/inkwasm_js.go @@ -6,25 +6,6 @@ import ( "runtime" ) -func _getBasicDecoder(s string) (_ Object) { - r0 := __getBasicDecoder(s) - runtime.KeepAlive(s) - - return r0 -} - -//go:wasmimport gojs github.com/inkeliz/go_inkwasm/inkwasm.__getBasicDecoder -func __getBasicDecoder(s string) (_ Object) - -func _getSliceDecoder(f Object) (_ Object) { - r0 := __getSliceDecoder(f) - - return r0 -} - -//go:wasmimport gojs github.com/inkeliz/go_inkwasm/inkwasm.__getSliceDecoder -func __getSliceDecoder(f Object) (_ Object) - func _newObjectFromSyscall(i uint32) (_ Object) { r0 := __newObjectFromSyscall(i) @@ -79,7 +60,7 @@ func _free(ref int) { //go:wasmimport gojs github.com/inkeliz/go_inkwasm/inkwasm.__free func __free(ref int) -func _call(o Object, k string, args []int32) (_ Object, _ bool) { +func _call(o Object, k string, args []interface{}) (_ Object, _ bool) { r0, r1 := __call(o, k, args) runtime.KeepAlive(k) runtime.KeepAlive(args) @@ -88,9 +69,9 @@ func _call(o Object, k string, args []int32) (_ Object, _ bool) { } //go:wasmimport gojs github.com/inkeliz/go_inkwasm/inkwasm.__call -func __call(o Object, k string, args []int32) (_ Object, _ bool) +func __call(o Object, k string, args []interface{}) (_ Object, _ bool) -func _callVoid(o Object, k string, args []int32) (_ bool, ok bool) { +func _callVoid(o Object, k string, args []interface{}) (_ bool, ok bool) { r0, r1 := __callVoid(o, k, args) runtime.KeepAlive(k) runtime.KeepAlive(args) @@ -99,9 +80,9 @@ func _callVoid(o Object, k string, args []int32) (_ bool, ok bool) { } //go:wasmimport gojs github.com/inkeliz/go_inkwasm/inkwasm.__callVoid -func __callVoid(o Object, k string, args []int32) (_ bool, ok bool) +func __callVoid(o Object, k string, args []interface{}) (_ bool, ok bool) -func _invoke(o Object, args []int32) (_ Object, _ bool) { +func _invoke(o Object, args []interface{}) (_ Object, _ bool) { r0, r1 := __invoke(o, args) runtime.KeepAlive(args) @@ -109,9 +90,9 @@ func _invoke(o Object, args []int32) (_ Object, _ bool) { } //go:wasmimport gojs github.com/inkeliz/go_inkwasm/inkwasm.__invoke -func __invoke(o Object, args []int32) (_ Object, _ bool) +func __invoke(o Object, args []interface{}) (_ Object, _ bool) -func _invokeVoid(o Object, args []int32) (_ bool, ok bool) { +func _invokeVoid(o Object, args []interface{}) (_ bool, ok bool) { r0, r1 := __invokeVoid(o, args) runtime.KeepAlive(args) @@ -119,9 +100,9 @@ func _invokeVoid(o Object, args []int32) (_ bool, ok bool) { } //go:wasmimport gojs github.com/inkeliz/go_inkwasm/inkwasm.__invokeVoid -func __invokeVoid(o Object, args []int32) (_ bool, ok bool) +func __invokeVoid(o Object, args []interface{}) (_ bool, ok bool) -func _newObj(o Object, args []int32) (_ Object, _ bool) { +func _newObj(o Object, args []interface{}) (_ Object, _ bool) { r0, r1 := __newObj(o, args) runtime.KeepAlive(args) @@ -129,7 +110,7 @@ func _newObj(o Object, args []int32) (_ Object, _ bool) { } //go:wasmimport gojs github.com/inkeliz/go_inkwasm/inkwasm.__newObj -func __newObj(o Object, args []int32) (_ Object, _ bool) +func __newObj(o Object, args []interface{}) (_ Object, _ bool) func _getIndex(o Object, i int) (_ Object) { r0 := __getIndex(o, i) diff --git a/inkwasm/inkwasm_js.js b/inkwasm/inkwasm_js.js index f5e3a36..7db4f41 100644 --- a/inkwasm/inkwasm_js.js +++ b/inkwasm/inkwasm_js.js @@ -9,18 +9,6 @@ (() => { Object.assign(go.importObject.gojs, { - "github.com/inkeliz/go_inkwasm/inkwasm.__getBasicDecoder": (sp) => { - let r = globalThis.inkwasm.Load[globalThis.inkwasm.Load.String(go, sp, 8)] - sp = go._inst.exports.getsp() >>> 0 - globalThis.inkwasm.Set.InkwasmObject(go, sp, 24, r) - }, - - "github.com/inkeliz/go_inkwasm/inkwasm.__getSliceDecoder": (sp) => { - let r = globalThis.inkwasm.Load.SliceOf(globalThis.inkwasm.Load.InkwasmObject(go, sp, 8)) - sp = go._inst.exports.getsp() >>> 0 - globalThis.inkwasm.Set.InkwasmObject(go, sp, 24, r) - }, - "github.com/inkeliz/go_inkwasm/inkwasm.__newObjectFromSyscall": (sp) => { let r = go._values[globalThis.inkwasm.Load.Uint32(go, sp, 8)] sp = go._inst.exports.getsp() >>> 0 @@ -58,7 +46,7 @@ "github.com/inkeliz/go_inkwasm/inkwasm.__call": (sp) => { try { - let r = globalThis.inkwasm.Internal.Call(globalThis.inkwasm.Load.InkwasmObject(go, sp, 8),globalThis.inkwasm.Load.String(go, sp, 24),globalThis.inkwasm.Load.Slice(go, sp, 40, globalThis.inkwasm.Load.ArrayInt32)) + let r = globalThis.inkwasm.Internal.Call(globalThis.inkwasm.Load.InkwasmObject(go, sp, 8),globalThis.inkwasm.Load.String(go, sp, 24),globalThis.inkwasm.Load.Slice(go, sp, 40, globalThis.inkwasm.Load.ArrayInterface)) sp = go._inst.exports.getsp() >>> 0 globalThis.inkwasm.Set.InkwasmObject(go, sp, 64, r) globalThis.inkwasm.Set.Bool(go, sp, 80, true) @@ -70,7 +58,7 @@ "github.com/inkeliz/go_inkwasm/inkwasm.__callVoid": (sp) => { try { - let r = globalThis.inkwasm.Internal.Call(globalThis.inkwasm.Load.InkwasmObject(go, sp, 8),globalThis.inkwasm.Load.String(go, sp, 24),globalThis.inkwasm.Load.Slice(go, sp, 40, globalThis.inkwasm.Load.ArrayInt32)) + let r = globalThis.inkwasm.Internal.Call(globalThis.inkwasm.Load.InkwasmObject(go, sp, 8),globalThis.inkwasm.Load.String(go, sp, 24),globalThis.inkwasm.Load.Slice(go, sp, 40, globalThis.inkwasm.Load.ArrayInterface)) sp = go._inst.exports.getsp() >>> 0 globalThis.inkwasm.Set.Bool(go, sp, 64, r) globalThis.inkwasm.Set.Bool(go, sp, 65, true) @@ -82,7 +70,7 @@ "github.com/inkeliz/go_inkwasm/inkwasm.__invoke": (sp) => { try { - let r = globalThis.inkwasm.Internal.Invoke(globalThis.inkwasm.Load.InkwasmObject(go, sp, 8),globalThis.inkwasm.Load.Slice(go, sp, 24, globalThis.inkwasm.Load.ArrayInt32)) + let r = globalThis.inkwasm.Internal.Invoke(globalThis.inkwasm.Load.InkwasmObject(go, sp, 8),globalThis.inkwasm.Load.Slice(go, sp, 24, globalThis.inkwasm.Load.ArrayInterface)) sp = go._inst.exports.getsp() >>> 0 globalThis.inkwasm.Set.InkwasmObject(go, sp, 48, r) globalThis.inkwasm.Set.Bool(go, sp, 64, true) @@ -94,7 +82,7 @@ "github.com/inkeliz/go_inkwasm/inkwasm.__invokeVoid": (sp) => { try { - let r = globalThis.inkwasm.Internal.Invoke(globalThis.inkwasm.Load.InkwasmObject(go, sp, 8),globalThis.inkwasm.Load.Slice(go, sp, 24, globalThis.inkwasm.Load.ArrayInt32)) + let r = globalThis.inkwasm.Internal.Invoke(globalThis.inkwasm.Load.InkwasmObject(go, sp, 8),globalThis.inkwasm.Load.Slice(go, sp, 24, globalThis.inkwasm.Load.ArrayInterface)) sp = go._inst.exports.getsp() >>> 0 globalThis.inkwasm.Set.Bool(go, sp, 48, r) globalThis.inkwasm.Set.Bool(go, sp, 49, true) @@ -106,7 +94,7 @@ "github.com/inkeliz/go_inkwasm/inkwasm.__newObj": (sp) => { try { - let r = new globalThis.inkwasm.Load.InkwasmObject(go, sp, 8)(globalThis.inkwasm.Load.Slice(go, sp, 24, globalThis.inkwasm.Load.ArrayInt32)) + let r = new globalThis.inkwasm.Load.InkwasmObject(go, sp, 8)(globalThis.inkwasm.Load.Slice(go, sp, 24, globalThis.inkwasm.Load.ArrayInterface)) sp = go._inst.exports.getsp() >>> 0 globalThis.inkwasm.Set.InkwasmObject(go, sp, 48, r) globalThis.inkwasm.Set.Bool(go, sp, 64, true) diff --git a/inkwasm/inkwasm_js.s b/inkwasm/inkwasm_js.s index 850d7e1..7d2ea21 100644 --- a/inkwasm/inkwasm_js.s +++ b/inkwasm/inkwasm_js.s @@ -1,14 +1,6 @@ // Code generated by INKWASM BUILD; DO NOT EDIT #include "textflag.h" -TEXT ·getBasicDecoder(SB), NOSPLIT, $0 - JMP ·_getBasicDecoder(SB) - RET - -TEXT ·getSliceDecoder(SB), NOSPLIT, $0 - JMP ·_getSliceDecoder(SB) - RET - TEXT ·newObjectFromSyscall(SB), NOSPLIT, $0 JMP ·_newObjectFromSyscall(SB) RET diff --git a/inkwasm/tests_js_test.go b/inkwasm/tests_js_test.go index fe45477..899b231 100644 --- a/inkwasm/tests_js_test.go +++ b/inkwasm/tests_js_test.go @@ -11,21 +11,20 @@ import ( ) func testInvoke(t *testing.T, obj Object, args ...interface{}) { - t.Helper() defer obj.Free() objInvoked, err := obj.Invoke(args...) if err != nil { - t.Error(err) + t.Fatal(err) } defer objInvoked.Free() r, err := objInvoked.Bool() if err != nil { - t.Error(err) + t.Fatal(err) } if r != true { - t.Error("not true") + t.Fatal("not true") } } @@ -135,13 +134,10 @@ func TestObjectType_String(t *testing.T) { func gen_nonExistentFunction(s string) (Object, bool) func TestNonExistentFunction(t *testing.T) { - v, ok := gen_nonExistentFunction("Hello, 世界") + _, ok := gen_nonExistentFunction("Hello, 世界") if ok { t.Error("non existent function should return false") } - if v.Truthy() { - t.Error("non existent function should return undefined") - } } //inkwasm:func globalThis.TestObjectType_String @@ -278,6 +274,48 @@ func TestInt64_Static(t *testing.T) { } } +//inkwasm:func globalThis.TestSumFromArray +func gen_TestSumFromArray([]uint32) uint32 + +func TestArgsReuse(t *testing.T) { + args := []interface{}{ + []uint32{1, 2, 3, 4, 5}, + } + + if gen_TestSumFromArray(args[0].([]uint32)) != 15 { + t.Error("args reuse error") + } + + obj := Global().GetProperty("TestSumFromArray") + res, err := obj.Invoke(args...) + if err != nil { + t.Error(err) + } + + v, err := res.Int() + if err != nil { + t.Error(err) + } + + if v != 15 { + t.Error("args reuse error") + } + + resReused, err := obj.Invoke(args...) + if err != nil { + t.Error(err) + } + + v, err = resReused.Int() + if err != nil { + t.Error(err) + } + + if v != 15 { + t.Error("args reuse error") + } +} + //inkwasm:func globalThis.TestObject_Bytes func gen_TestObject_Bytes() []byte @@ -360,13 +398,14 @@ func Benchmark_GetLocalStorage_JS_SYSCALL(b *testing.B) { } //inkwasm:get globalThis.location.hostname -func gen_GetLocationHostname() string +func gen_GetLocationHostname() Object func Benchmark_GetLocationHostname_INKWASM(b *testing.B) { b.ReportAllocs() + fn := gen_GetLocationHostname() for i := 0; i < b.N; i++ { - if gen_GetLocationHostname() == "" { + if r, err := fn.String(); r == "" || err != nil { b.Fail() } } @@ -389,16 +428,26 @@ func gen_createElement(v string) Object //inkwasm:set .innerHTML func gen_setInnerHTML(o Object, v string) -//inkwasm:func globalThis.document.body.appendChild -func gen_appendChild(c Object) +//inkwasm:func .appendChild +func gen_appendChild(o Object, v Object) + +//inkwasm:get globalThis.document.body +func gen_getBody() Object func Benchmark_DOM_INKWASM(b *testing.B) { b.ReportAllocs() + body := gen_getBody() + for i := 0; i < b.N; i++ { div := gen_createElement("div") gen_setInnerHTML(div, "foo bar baz "+strconv.Itoa(i)) - gen_appendChild(div) + gen_appendChild(body, div) + div.Free() + + if i%100 == 0 { + gen_setInnerHTML(body, "") + } } } @@ -407,17 +456,25 @@ func Benchmark_DOM_RUNTIME_INKWASM(b *testing.B) { doc := Global().GetProperty("document") defer doc.Free() + createElement, _ := doc.GetProperty("createElement").Call("bind", doc) defer createElement.Free() + body := doc.GetProperty("body") defer body.Free() + appendChild, _ := body.GetProperty("appendChild").Call("bind", body) defer appendChild.Free() + for i := 0; i < b.N; i++ { div, _ := createElement.Invoke("div") div.SetProperty("innerHTML", "foo bar baz "+strconv.Itoa(i)) appendChild.InvokeVoid(div) div.Free() + + if i%100 == 0 { + body.SetProperty("innerHTML", "") + } } } @@ -425,13 +482,21 @@ func Benchmark_DOM_JS_SYSCALL(b *testing.B) { b.ReportAllocs() doc := js.Global().Get("document") + createElement := doc.Get("createElement").Call("bind", doc) + body := doc.Get("body") + appendChild := body.Get("appendChild").Call("bind", body) + for i := 0; i < b.N; i++ { div := createElement.Invoke("div") div.Set("innerHTML", "foo bar baz "+strconv.Itoa(i)) appendChild.Invoke(div) + + if i%100 == 0 { + body.Set("innerHTML", "") + } } } @@ -439,10 +504,15 @@ func Benchmark_DOM_BAD_JS_SYSCALL(b *testing.B) { b.ReportAllocs() doc := js.Global().Get("document") + for i := 0; i < b.N; i++ { div := doc.Call("createElement", "div") div.Set("innerHTML", "foo bar baz "+strconv.Itoa(i)) doc.Get("body").Call("appendChild", div) + + if i%100 == 0 { + doc.Get("body").Set("innerHTML", "") + } } } @@ -451,10 +521,15 @@ func Benchmark_DOM_BAD_RUNTIME_INKWASM(b *testing.B) { doc := Global().GetProperty("document") defer doc.Free() + for i := 0; i < b.N; i++ { div, _ := doc.Call("createElement", "div") div.SetProperty("innerHTML", "foo bar baz "+strconv.Itoa(i)) doc.GetProperty("body").Call("appendChild", div) div.Free() + + if i%100 == 0 { + doc.GetProperty("body").SetProperty("innerHTML", "") + } } } diff --git a/inkwasm/tests_js_test.js b/inkwasm/tests_js_test.js index 2ecc5be..f30ccd0 100644 --- a/inkwasm/tests_js_test.js +++ b/inkwasm/tests_js_test.js @@ -72,4 +72,11 @@ globalThis.TestUint64_Add = function (e, e2) { return e + e2 } + globalThis.TestSumFromArray = function (e) { + let sum = 0 + for (let i = 0; i < e.length; i++) { + sum += e[i] + } + return sum + } })(); \ No newline at end of file diff --git a/inkwasm/wasm_js.go b/inkwasm/wasm_js.go index 30d26b3..5d741ff 100644 --- a/inkwasm/wasm_js.go +++ b/inkwasm/wasm_js.go @@ -71,7 +71,7 @@ func (o Object) Call(method string, args ...interface{}) (Object, error) { } //inkwasm:func globalThis.inkwasm.Internal.Call -func call(o Object, k string, args []int32) (Object, bool) +func call(o Object, k string, args []interface{}) (Object, bool) // CallVoid is similar to Call, but doesn't return the resulting Object. // Look at Call function for more details. @@ -87,7 +87,7 @@ func (o Object) CallVoid(method string, args ...interface{}) error { } //inkwasm:func globalThis.inkwasm.Internal.Call -func callVoid(o Object, k string, args []int32) (_, ok bool) +func callVoid(o Object, k string, args []interface{}) (_, ok bool) // Invoke invokes the current Object, calling itself with the // provided args as arguments of the function. @@ -108,7 +108,7 @@ func (o Object) Invoke(args ...interface{}) (Object, error) { } //inkwasm:func globalThis.inkwasm.Internal.Invoke -func invoke(o Object, args []int32) (Object, bool) +func invoke(o Object, args []interface{}) (Object, bool) // InvokeVoid is similar to Invoke, but doesn't return the resulting Object. // Look at Invoke function for more details. @@ -124,7 +124,7 @@ func (o Object) InvokeVoid(args ...interface{}) error { } //inkwasm:func globalThis.inkwasm.Internal.Invoke -func invokeVoid(o Object, args []int32) (_, ok bool) +func invokeVoid(o Object, args []interface{}) (_, ok bool) // New uses the "new" operator from Javascript with the current object // as the constructor and the given arg as arguments. @@ -141,7 +141,7 @@ func (o Object) New(args ...interface{}) (Object, error) { } //inkwasm:new . -func newObj(o Object, args []int32) (Object, bool) +func newObj(o Object, args []interface{}) (Object, bool) // GetIndex returns given index of the current Object. func (o Object) GetIndex(index int) Object { diff --git a/inkwasm/wasm_js.js b/inkwasm/wasm_js.js index 300756c..9b600da 100644 --- a/inkwasm/wasm_js.js +++ b/inkwasm/wasm_js.js @@ -40,20 +40,11 @@ }) Object.assign(globalThis.inkwasm.Internal, { - parseArgs: function (args) { - let a = new Array(args.length >> 2); - for (let i = 0; i < args.length; i += 4) { - const k = args[i] + (args[i + 1] * 4294967296); - const v = args[i + 2] + (args[i + 3] * 4294967296); - a[i >> 2] = Objects[k](go, v, 0); - } - return a; - }, Invoke: function (o, args) { if (args === null || args.length === 0) { return o() } - return o(...globalThis.inkwasm.Internal.parseArgs(args)) + return o(...args) }, Free: function (id) { ObjectsUnused.push(id) @@ -62,13 +53,13 @@ if (args === null || args.length === 0) { return o[k]() } - return o[k](...globalThis.inkwasm.Internal.parseArgs(args)) + return o[k](...args) }, New: function (o, args) { if (args === null || args.length === 0) { return new o() } - return new o(...globalThis.inkwasm.Internal.parseArgs(args)) + return new o(...args) }, Make: function (args) { if (args === null || args.length === 0) { @@ -228,6 +219,144 @@ return globalThis.inkwasm.Load.ArrayUint32(go, sp, offset, len) }, + ArrayInterface: function (go, sp, offset, len) { + let result = [] + for (let i = 0; i < len; i++) { + result.push(globalThis.inkwasm.Load.Interface(go, sp, offset + (i * 16))) + } + return result + }, + Interface: function (go, sp, offset) { + let ptr_rtype = globalThis.inkwasm.Load.UintPtr(go, sp, offset) + let ptr_data = globalThis.inkwasm.Load.Int(go, sp, offset + 8) + + let kind = globalThis.inkwasm.Load.Byte(go, ptr_rtype, 8 + 8 + 4 + 1 + 1 + 1) + switch (kind) { + case 0: // Invalid + return undefined + case 1: // Bool + return globalThis.inkwasm.Load.Bool(go, ptr_data, 0) + case 2: // Int + return globalThis.inkwasm.Load.Int(go, ptr_data, 0) + case 3: // Int8 + return globalThis.inkwasm.Load.Int8(go, ptr_data, 0) + case 4: // Int16 + return globalThis.inkwasm.Load.Int16(go, ptr_data, 0) + case 5: // Int32 + return globalThis.inkwasm.Load.Int32(go, ptr_data, 0) + case 6: // Int64 + return globalThis.inkwasm.Load.Int64(go, ptr_data, 0) + case 7: // Uint + return globalThis.inkwasm.Load.Uint(go, ptr_data, 0) + case 8: // Uint8 + return globalThis.inkwasm.Load.Uint8(go, ptr_data, 0) + case 9: // Uint16 + return globalThis.inkwasm.Load.Uint16(go, ptr_data, 0) + case 10: // Uint32 + return globalThis.inkwasm.Load.Uint32(go, ptr_data, 0) + case 11: // Uint64 + return globalThis.inkwasm.Load.Uint64(go, ptr_data, 0) + case 12: // Uintptr + return globalThis.inkwasm.Load.UintPtr(go, ptr_data, 0) + case 13: // Float32 + return globalThis.inkwasm.Load.Float32(go, ptr_data, 0) + case 14: // Float64 + return globalThis.inkwasm.Load.Float64(go, ptr_data, 0) + case 15: // Complex64 + return undefined + case 16: // Complex128 + return undefined + case 17: // Array + return undefined + case 18: // Chan + return undefined + case 19: // Func + return undefined + case 20: // Interface + return undefined + case 21: // Map + return undefined + case 22: // Pointer + return globalThis.inkwasm.Load.UintPtr(go, ptr_data, 0) + case 23: // Slice + let ptr_elem = globalThis.inkwasm.Load.UintPtr(go, ptr_rtype, 48) + let ptr_elem_kind = globalThis.inkwasm.Load.Byte(go, ptr_elem, 8 + 8 + 4 + 1 + 1 + 1) + + let slice_fn = undefined; + switch (ptr_elem_kind) { + case 1: // Bool + slice_fn = globalThis.inkwasm.Load.ArrayByte + break; + case 2: // Int + slice_fn = globalThis.inkwasm.Load.ArrayInt64 + break; + case 3: // Int8 + slice_fn = globalThis.inkwasm.Load.ArrayInt8 + break; + case 4: // Int16 + slice_fn = globalThis.inkwasm.Load.ArrayInt16 + break; + case 5: // Int32 + slice_fn = globalThis.inkwasm.Load.ArrayInt32 + break; + case 6: // Int64 + slice_fn = globalThis.inkwasm.Load.ArrayInt64 + break; + case 7: // Uint + slice_fn = globalThis.inkwasm.Load.ArrayUint64 + break; + case 8: // Uint8 + slice_fn = globalThis.inkwasm.Load.ArrayUint8 + break; + case 9: // Uint16 + slice_fn = globalThis.inkwasm.Load.ArrayUint16 + break; + case 10: // Uint32 + slice_fn = globalThis.inkwasm.Load.ArrayUint32 + break; + case 11: // Uint64 + slice_fn = globalThis.inkwasm.Load.ArrayUint64 + break; + case 12: // Uintptr + slice_fn = globalThis.inkwasm.Load.ArrayUint64 + break; + case 13: // Float32 + slice_fn = globalThis.inkwasm.Load.ArrayFloat32 + break; + case 14: // Float64 + slice_fn = globalThis.inkwasm.Load.ArrayFloat64 + break; + } + + if (slice_fn === undefined) { + return undefined + } + + return globalThis.inkwasm.Load.Slice(go, ptr_data, 0, slice_fn) + case 24: // String + return globalThis.inkwasm.Load.String(go, ptr_data, 0) + case 25: // Struct + const known_path_bytes = StringEncoder.encode("github.com/inkeliz/go_inkwasm/inkwasm") + + let ptr_pkgPath = globalThis.inkwasm.Load.UintPtr(go, ptr_rtype, 48) + let pkgPath = globalThis.inkwasm.Load.ArrayByte(go, ptr_pkgPath, 2, known_path_bytes.length) + + if (known_path_bytes.length !== known_path_bytes.length) { + return undefined + } + + // Compare each element in the arrays + for (let i = 0; i < pkgPath.length; i++) { + if (pkgPath[i] !== known_path_bytes[i]) { + return undefined; + } + } + + return globalThis.inkwasm.Load.InkwasmObject(go, ptr_data, 0) + case 26: // UnsafePointer + return globalThis.inkwasm.Load.UnsafePointer(go, ptr_data, 0) + } + }, Array: function (go, sp, offset, len, f) { return f(go, sp, offset, len).slice(0, len) diff --git a/parser/parser.go b/parser/parser.go index 149788d..f1165ec 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -335,6 +335,10 @@ func parseArray(arg *bind.Argument, t *ast.ArrayType) error { return parseIdent(arg.SubType, tt) case *ast.SelectorExpr: return parseSelector(arg.SubType, tt) + case *ast.InterfaceType: + arg.SubType.ArgType = bind.ModeStatic + arg.SubType.Type = "interface{}" + return nil default: return errors.New("array/slice of pointers isn't supported") }