Skip to content

Commit

Permalink
Complete reference types proposal (#531)
Browse files Browse the repository at this point in the history
This commit completes the reference-types proposal implementation.

Notably, this adds support for 
* `ref.is_null`, `ref.func`, `ref.is_null` instructions
* `table.get`, `table.set`, `table.grow`, `table.size` and `table.fill` instructions
* `Externref` and `Funcref` types (including invocation via uint64 encoding).

part of #484

Signed-off-by: Takeshi Yoneda <[email protected]>
  • Loading branch information
mathetake authored May 10, 2022
1 parent 03bfa31 commit 20e46a9
Show file tree
Hide file tree
Showing 63 changed files with 3,255 additions and 251 deletions.
17 changes: 16 additions & 1 deletion api/wasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ func ExternTypeName(et ExternType) string {
// * ValueTypeI64 - uint64(int64)
// * ValueTypeF32 - EncodeF32 DecodeF32 from float32
// * ValueTypeF64 - EncodeF64 DecodeF64 from float64
// * ValueTypeExternref - unintptr(unsafe.Pointer(p)) where p is any pointer type in Go (e.g. *string)
//
// Ex. Given a Text Format type use (param i64) (result i64), no conversion is necessary.
//
Expand All @@ -81,8 +82,20 @@ const (
ValueTypeI64 ValueType = 0x7e
// ValueTypeF32 is a 32-bit floating point number.
ValueTypeF32 ValueType = 0x7d
// ValueTypeF64 is a 32-bit floating point number.
// ValueTypeF64 is a 64-bit floating point number.
ValueTypeF64 ValueType = 0x7c
// ValueTypeExternref is a externref type.
//
// Note: in wazero, externref type value are opaque raw 64-bit pointers, and the ValueTypeExternref type
// in the signature will be translated as uintptr in wazero's API level.
// For example, the import function `(func (import "env" "f") (param externref) (result externref))` can be defined in Go as:
//
// r.NewModuleBuilder("env").ExportFunctions(map[string]interface{}{
// "f": func(externref uintptr) (resultExternRef uintptr) { return },
// })
//
// Note: The usage of this type is toggled with WithFeatureBulkMemoryOperations.
ValueTypeExternref ValueType = 0x6f
)

// ValueTypeName returns the type name of the given ValueType as a string.
Expand All @@ -99,6 +112,8 @@ func ValueTypeName(t ValueType) string {
return "f32"
case ValueTypeF64:
return "f64"
case ValueTypeExternref:
return "externref"
}
return "unknown"
}
Expand Down
52 changes: 42 additions & 10 deletions internal/integration_test/engine/adhoc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"math"
"strconv"
"testing"
"unsafe"

"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
Expand All @@ -31,16 +32,17 @@ var compileConfig = wazero.NewCompileConfig().
var moduleConfig = wazero.NewModuleConfig()

var tests = map[string]func(t *testing.T, r wazero.Runtime){
"huge stack": testHugeStack,
"unreachable": testUnreachable,
"recursive entry": testRecursiveEntry,
"imported-and-exported func": testImportedAndExportedFunc,
"host function with context parameter": testHostFunctionContextParameter,
"host function with nested context": testNestedGoContext,
"host function with numeric parameter": testHostFunctionNumericParameter,
"close module with in-flight calls": testCloseInFlight,
"multiple instantiation from same source": testMultipleInstantiation,
"exported function that grows memory": testMemOps,
"huge stack": testHugeStack,
"unreachable": testUnreachable,
"recursive entry": testRecursiveEntry,
"imported-and-exported func": testImportedAndExportedFunc,
"host function with context parameter": testHostFunctionContextParameter,
"host function with nested context": testNestedGoContext,
"host function with numeric parameter": testHostFunctionNumericParameter,
"close module with in-flight calls": testCloseInFlight,
"multiple instantiation from same source": testMultipleInstantiation,
"exported function that grows memory": testMemOps,
"import functions with reference type in signature": testReftypeImports,
}

func TestEngineJIT(t *testing.T) {
Expand All @@ -55,6 +57,7 @@ func TestEngineInterpreter(t *testing.T) {
}

func runAllTests(t *testing.T, tests map[string]func(t *testing.T, r wazero.Runtime), config wazero.RuntimeConfig) {
config = config.WithFeatureReferenceTypes(true)
for name, testf := range tests {
name := name // pin
testf := testf // pin
Expand All @@ -72,8 +75,37 @@ var (
recursiveWasm []byte
//go:embed testdata/hugestack.wasm
hugestackWasm []byte
//go:embed testdata/reftype_imports.wasm
reftypeImportsWasm []byte
)

func testReftypeImports(t *testing.T, r wazero.Runtime) {
type dog struct {
name string
}

hostObj := &dog{name: "hello"}
host, err := r.NewModuleBuilder("host").
ExportFunctions(map[string]interface{}{
"externref": func(externrefFromRefNull uintptr) uintptr {
require.Zero(t, externrefFromRefNull)
return uintptr(unsafe.Pointer(hostObj))
},
}).Instantiate(testCtx)
require.NoError(t, err)
defer host.Close(testCtx)

module, err := r.InstantiateModuleFromCode(testCtx, reftypeImportsWasm)
require.NoError(t, err)
defer module.Close(testCtx)

actual, err := module.ExportedFunction("get_externref_by_host").Call(testCtx)
require.NoError(t, err)

// Verifies that the returned raw uintptr is the same as the one for the host object.
require.Equal(t, uintptr(unsafe.Pointer(hostObj)), uintptr(actual[0]))
}

func testHugeStack(t *testing.T, r wazero.Runtime) {
module, err := r.InstantiateModuleFromCode(testCtx, hugestackWasm)
require.NoError(t, err)
Expand Down
Binary file not shown.
8 changes: 8 additions & 0 deletions internal/integration_test/engine/testdata/reftype_imports.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
(module
(func $host_externref (import "host" "externref") (param externref) (result externref))

(func (export "get_externref_by_host") (result externref)
(ref.null extern)
(call $host_externref)
)
)
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ func requireErrorOnBulkMemoryFeatureDisabled(t *testing.T, newRuntimeConfig func

func testTableCopy(t *testing.T, newRuntimeConfig func() wazero.RuntimeConfig) {
t.Run("table.copy", func(t *testing.T) {

requireErrorOnBulkMemoryFeatureDisabled(t, newRuntimeConfig, tableCopyWasm)

r := wazero.NewRuntimeWithConfig(newRuntimeConfig().WithFeatureBulkMemoryOperations(true))
Expand Down
Loading

0 comments on commit 20e46a9

Please sign in to comment.