Repository: tetratelabs/wazero
Pull request #2129 (2024-03-07 03:02:49)

wazevo: implements MutableGlobal.Set, fixes emscripten test


Patch:
diff --git a/internal/engine/compiler/engine.go b/internal/engine/compiler/engine.go
index 6f46cb4f..70c16d3e 100644
--- a/internal/engine/compiler/engine.go
+++ b/internal/engine/compiler/engine.go
@@ -662,6 +662,11 @@ func (e *moduleEngine) ResolveImportedFunction(index, indexInImportedModule wasm
 	e.functions[index] = imported.functions[indexInImportedModule]
 }
 
+// SetGlobalValue implements the same method as documented on wasm.ModuleEngine.
+func (e *moduleEngine) SetGlobalValue(idx wasm.Index, lo, hi uint64) {
+	panic("BUG: SetGlobalValue should never be called on compiler mode")
+}
+
 // GetGlobalValue implements the same method as documented on wasm.ModuleEngine.
 func (e *moduleEngine) GetGlobalValue(wasm.Index) (lo, hi uint64) {
 	panic("BUG: GetGlobalValue should never be called on compiler mode")
diff --git a/internal/engine/interpreter/interpreter.go b/internal/engine/interpreter/interpreter.go
index caecfee3..be27f7e9 100644
--- a/internal/engine/interpreter/interpreter.go
+++ b/internal/engine/interpreter/interpreter.go
@@ -92,6 +92,11 @@ func (e *moduleEngine) GetGlobalValue(wasm.Index) (lo, hi uint64) {
 	panic("BUG: GetGlobalValue should never be called on interpreter mode")
 }
 
+// SetGlobalValue implements the same method as documented on wasm.ModuleEngine.
+func (e *moduleEngine) SetGlobalValue(idx wasm.Index, lo, hi uint64) {
+	panic("BUG: SetGlobalValue should never be called on interpreter mode")
+}
+
 // OwnsGlobals implements the same method as documented on wasm.ModuleEngine.
 func (e *moduleEngine) OwnsGlobals() bool { return false }
 
diff --git a/internal/engine/wazevo/module_engine.go b/internal/engine/wazevo/module_engine.go
index b72ac2b1..ba8f546c 100644
--- a/internal/engine/wazevo/module_engine.go
+++ b/internal/engine/wazevo/module_engine.go
@@ -213,6 +213,17 @@ func (m *moduleEngine) GetGlobalValue(i wasm.Index) (lo, hi uint64) {
 	return binary.LittleEndian.Uint64(buf), binary.LittleEndian.Uint64(buf[8:])
 }
 
+// SetGlobalValue implements the same method as documented on wasm.ModuleEngine.
+func (m *moduleEngine) SetGlobalValue(i wasm.Index, lo, hi uint64) {
+	offset := m.parent.offsets.GlobalInstanceOffset(i)
+	buf := m.opaque[offset:]
+	if i < m.module.Source.ImportGlobalCount {
+		panic("GetGlobalValue should not be called for imported globals")
+	}
+	binary.LittleEndian.PutUint64(buf, lo)
+	binary.LittleEndian.PutUint64(buf[8:], hi)
+}
+
 // OwnsGlobals implements the same method as documented on wasm.ModuleEngine.
 func (m *moduleEngine) OwnsGlobals() bool { return true }
 
diff --git a/internal/wasm/engine.go b/internal/wasm/engine.go
index c2f82efc..58a45821 100644
--- a/internal/wasm/engine.go
+++ b/internal/wasm/engine.go
@@ -58,6 +58,10 @@ type ModuleEngine interface {
 	// Only called when OwnsGlobals() returns true, and must not be called for imported globals
 	GetGlobalValue(idx Index) (lo, hi uint64)
 
+	// SetGlobalValue sets the value of the global variable at the given Index.
+	// Only called when OwnsGlobals() returns true, and must not be called for imported globals
+	SetGlobalValue(idx Index, lo, hi uint64)
+
 	// OwnsGlobals returns true if this ModuleEngine owns the global variables. If true, wasm.GlobalInstance's Val,ValHi should
 	// not be accessed directly.
 	OwnsGlobals() bool
diff --git a/internal/wasm/global.go b/internal/wasm/global.go
index f28f46ed..abaa2d1f 100644
--- a/internal/wasm/global.go
+++ b/internal/wasm/global.go
@@ -51,5 +51,5 @@ func (g mutableGlobal) String() string {
 
 // Set implements the same method as documented on api.MutableGlobal.
 func (g mutableGlobal) Set(v uint64) {
-	g.g.Val = v
+	g.g.SetValue(v, 0)
 }
diff --git a/internal/wasm/store.go b/internal/wasm/store.go
index fe9d6d15..e643348d 100644
--- a/internal/wasm/store.go
+++ b/internal/wasm/store.go
@@ -585,6 +585,14 @@ func (g *GlobalInstance) Value() (uint64, uint64) {
 	return g.Val, g.ValHi
 }
 
+func (g *GlobalInstance) SetValue(lo, hi uint64) {
+	if g.Me != nil {
+		g.Me.SetGlobalValue(g.Index, lo, hi)
+	} else {
+		g.Val, g.ValHi = lo, hi
+	}
+}
+
 func (s *Store) GetFunctionTypeIDs(ts []FunctionType) ([]FunctionTypeID, error) {
 	ret := make([]FunctionTypeID, len(ts))
 	for i := range ts {


Test patch:
diff --git a/imports/emscripten/emscripten_test.go b/imports/emscripten/emscripten_test.go
index 8a5e9bfb..131709f7 100644
--- a/imports/emscripten/emscripten_test.go
+++ b/imports/emscripten/emscripten_test.go
@@ -10,6 +10,7 @@ import (
 	"github.com/tetratelabs/wazero/api"
 	"github.com/tetratelabs/wazero/experimental"
 	"github.com/tetratelabs/wazero/experimental/logging"
+	"github.com/tetratelabs/wazero/experimental/opt"
 	"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
 	internal "github.com/tetratelabs/wazero/internal/emscripten"
 	"github.com/tetratelabs/wazero/internal/testing/binaryencoding"
@@ -346,7 +347,7 @@ func TestInstantiateForModule(t *testing.T) {
 	// Set context to one that has an experimental listener
 	ctx := context.WithValue(testCtx, experimental.FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&log))
 
-	r := wazero.NewRuntime(ctx)
+	r := wazero.NewRuntimeWithConfig(ctx, opt.NewRuntimeConfigOptimizingCompiler())
 	defer r.Close(ctx)
 
 	compiled, err := r.CompileModule(ctx, invokeWasm)
@@ -548,7 +549,11 @@ func TestInstantiateForModule(t *testing.T) {
 
 			results, err := mod.ExportedFunction(tc.funcName).Call(testCtx, params...)
 			require.NoError(t, err)
-			require.Equal(t, tc.expectedResults, results)
+			l := len(tc.expectedResults)
+			require.Equal(t, l, len(results))
+			if l > 0 {
+				require.Equal(t, tc.expectedResults, results)
+			}
 
 			// We expect to see the dynamic function call target
 			require.Equal(t, tc.expectedLog, log.String())
diff --git a/internal/wasm/store_test.go b/internal/wasm/store_test.go
index 41fc4f17..5a7021dc 100644
--- a/internal/wasm/store_test.go
+++ b/internal/wasm/store_test.go
@@ -466,6 +466,9 @@ func (e *mockEngine) NewModuleEngine(_ *Module, _ *ModuleInstance) (ModuleEngine
 // GetGlobalValue implements the same method as documented on wasm.ModuleEngine.
 func (e *mockModuleEngine) GetGlobalValue(idx Index) (lo, hi uint64) { panic("BUG") }
 
+// SetGlobalValue implements the same method as documented on wasm.ModuleEngine.
+func (e *mockModuleEngine) SetGlobalValue(idx Index, lo, hi uint64) { panic("BUG") }
+
 // OwnsGlobals implements the same method as documented on wasm.ModuleEngine.
 func (e *mockModuleEngine) OwnsGlobals() bool { return false }
 
diff --git a/runtime_test.go b/runtime_test.go
index b7fce389..6441a870 100644
--- a/runtime_test.go
+++ b/runtime_test.go
@@ -296,7 +296,9 @@ func TestModule_Global(t *testing.T) {
 		tc := tt
 
 		t.Run(tc.name, func(t *testing.T) {
-			r := NewRuntime(testCtx).(*runtime)
+			cfg := NewRuntimeConfig().(*runtimeConfig)
+			cfg.EnableOptimizingCompiler()
+			r := NewRuntimeWithConfig(testCtx, cfg).(*runtime)
 			defer r.Close(testCtx)
 
 			code := &compiledModule{module: tc.module}