Skip to content

Commit

Permalink
tweak: Support interface directly in Javascript
Browse files Browse the repository at this point in the history
This patch fixes one issue, caused when re-using the same
interface slice multiple times, for multiple calls.

Now, it's possible to use interface{} directly in inkwasm
functions, and it's already used by InkWasm Runtime methods,
such as Call/Invoke.
  • Loading branch information
inkeliz committed May 19, 2024
1 parent ec2d073 commit 1f261e6
Show file tree
Hide file tree
Showing 11 changed files with 290 additions and 186 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -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
30 changes: 16 additions & 14 deletions bind/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand All @@ -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},
Expand Down
96 changes: 8 additions & 88 deletions inkwasm/args_js.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
39 changes: 10 additions & 29 deletions inkwasm/inkwasm_js.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 5 additions & 17 deletions inkwasm/inkwasm_js.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down
8 changes: 0 additions & 8 deletions inkwasm/inkwasm_js.s
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Loading

0 comments on commit 1f261e6

Please sign in to comment.