diff --git a/internal/engine/compiler/engine.go b/internal/engine/compiler/engine.go index d4e8dcd06f..b0346d3fb6 100644 --- a/internal/engine/compiler/engine.go +++ b/internal/engine/compiler/engine.go @@ -656,6 +656,14 @@ func (e *moduleEngine) ResolveImportedFunction(index, indexInImportedModule wasm e.functions[index] = imported.functions[indexInImportedModule] } +// 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") +} + +// OwnsGlobals implements the same method as documented on wasm.ModuleEngine. +func (e *moduleEngine) OwnsGlobals() bool { return false } + // ResolveImportedMemory implements wasm.ModuleEngine. func (e *moduleEngine) ResolveImportedMemory(wasm.ModuleEngine) {} diff --git a/internal/engine/interpreter/interpreter.go b/internal/engine/interpreter/interpreter.go index d47e7c3129..c60d0584bb 100644 --- a/internal/engine/interpreter/interpreter.go +++ b/internal/engine/interpreter/interpreter.go @@ -87,6 +87,14 @@ type moduleEngine struct { parentEngine *engine } +// 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 interpreter mode") +} + +// OwnsGlobals implements the same method as documented on wasm.ModuleEngine. +func (e *moduleEngine) OwnsGlobals() bool { return false } + // callEngine holds context per moduleEngine.Call, and shared across all the // function calls originating from the same moduleEngine.Call execution. // diff --git a/internal/engine/wazevo/backend/backend_test.go b/internal/engine/wazevo/backend/backend_test.go index 8ecdaee266..0deb91f7bd 100644 --- a/internal/engine/wazevo/backend/backend_test.go +++ b/internal/engine/wazevo/backend/backend_test.go @@ -1937,34 +1937,26 @@ L2: L1 (SSA Block: blk0): mov x128?, x0 mov x129?, x1 - ldr x130?, [x129?, #0x8] - ldr w131?, [x130?, #0x8] - ldr x132?, [x129?, #0x10] - ldr x133?, [x132?, #0x8] - ldr x134?, [x129?, #0x18] - ldr s135?, [x134?, #0x8] - ldr x136?, [x129?, #0x20] - ldr d137?, [x136?, #0x8] + ldr w130?, [x129?, #0x8] + ldr x131?, [x129?, #0x18] + ldr s132?, [x129?, #0x28] + ldr d133?, [x129?, #0x38] str x129?, [x128?, #0x8] mov x0, x128? mov x1, x129? bl f1 - ldr x138?, [x129?, #0x8] - ldr w139?, [x138?, #0x8] - ldr x140?, [x129?, #0x10] - ldr x141?, [x140?, #0x8] - ldr x142?, [x129?, #0x18] - ldr s143?, [x142?, #0x8] - ldr x144?, [x129?, #0x20] - ldr d145?, [x144?, #0x8] - mov v3.8b, v145?.8b - mov v2.8b, v143?.8b - mov x3, x141? - mov x2, x139? - mov v1.8b, v137?.8b - mov v0.8b, v135?.8b - mov x1, x133? - mov x0, x131? + ldr w134?, [x129?, #0x8] + ldr x135?, [x129?, #0x18] + ldr s136?, [x129?, #0x28] + ldr d137?, [x129?, #0x38] + mov v3.8b, v137?.8b + mov v2.8b, v136?.8b + mov x3, x135? + mov x2, x134? + mov v1.8b, v133?.8b + mov v0.8b, v132?.8b + mov x1, x131? + mov x0, x130? ret `, afterFinalizeARM64: ` @@ -1974,29 +1966,21 @@ L1 (SSA Block: blk0): orr x27, xzr, #0x20 str x27, [sp, #-0x10]! str x1, [sp, #0x10] - ldr x8, [x1, #0x8] - ldr w8, [x8, #0x8] + ldr w8, [x1, #0x8] str w8, [sp, #0x2c] - ldr x9, [x1, #0x10] - ldr x9, [x9, #0x8] + ldr x9, [x1, #0x18] str x9, [sp, #0x24] - ldr x10, [x1, #0x18] - ldr s8, [x10, #0x8] + ldr s8, [x1, #0x28] str s8, [sp, #0x20] - ldr x10, [x1, #0x20] - ldr d9, [x10, #0x8] + ldr d9, [x1, #0x38] str d9, [sp, #0x18] str x1, [x0, #0x8] bl f1 ldr x8, [sp, #0x10] - ldr x9, [x8, #0x8] - ldr w9, [x9, #0x8] - ldr x10, [x8, #0x10] - ldr x10, [x10, #0x8] - ldr x11, [x8, #0x18] - ldr s8, [x11, #0x8] - ldr x8, [x8, #0x20] - ldr d9, [x8, #0x8] + ldr w9, [x8, #0x8] + ldr x10, [x8, #0x18] + ldr s8, [x8, #0x28] + ldr d9, [x8, #0x38] mov v3.8b, v9.8b mov v2.8b, v8.8b mov x3, x10 @@ -2022,36 +2006,28 @@ L1 (SSA Block: blk0): afterLoweringARM64: ` L1 (SSA Block: blk0): mov x129?, x1 - ldr x131?, [x129?, #0x8] - orr w141?, wzr, #0x1 - str w141?, [x131?, #0x8] - ldr x133?, [x129?, #0x10] - orr x140?, xzr, #0x2 - str x140?, [x133?, #0x8] - ldr x135?, [x129?, #0x18] - ldr s139?, #8; b 8; data.f32 3.000000 - str s139?, [x135?, #0x8] - ldr x137?, [x129?, #0x20] - ldr d138?, #8; b 16; data.f64 4.000000 - str d138?, [x137?, #0x8] + orr w137?, wzr, #0x1 + str w137?, [x129?, #0x8] + orr x136?, xzr, #0x2 + str x136?, [x129?, #0x18] + ldr s135?, #8; b 8; data.f32 3.000000 + str s135?, [x129?, #0x28] + ldr d134?, #8; b 16; data.f64 4.000000 + str d134?, [x129?, #0x38] ret `, afterFinalizeARM64: ` L1 (SSA Block: blk0): stp x30, xzr, [sp, #-0x10]! str xzr, [sp, #-0x10]! - ldr x8, [x1, #0x8] - orr w9, wzr, #0x1 - str w9, [x8, #0x8] - ldr x8, [x1, #0x10] - orr x9, xzr, #0x2 - str x9, [x8, #0x8] - ldr x8, [x1, #0x18] + orr w8, wzr, #0x1 + str w8, [x1, #0x8] + orr x8, xzr, #0x2 + str x8, [x1, #0x18] ldr s8, #8; b 8; data.f32 3.000000 - str s8, [x8, #0x8] - ldr x8, [x1, #0x20] + str s8, [x1, #0x28] ldr d8, #8; b 16; data.f64 4.000000 - str d8, [x8, #0x8] + str d8, [x1, #0x38] add sp, sp, #0x10 ldr x30, [sp], #0x10 ret diff --git a/internal/engine/wazevo/frontend/frontend_test.go b/internal/engine/wazevo/frontend/frontend_test.go index 34d17ec400..a6551dc951 100644 --- a/internal/engine/wazevo/frontend/frontend_test.go +++ b/internal/engine/wazevo/frontend/frontend_test.go @@ -1181,15 +1181,11 @@ blk0: (exec_ctx:i64, module_ctx:i64, v2:i32) m: testcases.GlobalsGet.Module, exp: ` blk0: (exec_ctx:i64, module_ctx:i64) - v2:i64 = Load module_ctx, 0x8 - v3:i32 = Load v2, 0x8 - v4:i64 = Load module_ctx, 0x10 - v5:i64 = Load v4, 0x8 - v6:i64 = Load module_ctx, 0x18 - v7:f32 = Load v6, 0x8 - v8:i64 = Load module_ctx, 0x20 - v9:f64 = Load v8, 0x8 - Jump blk_ret, v3, v5, v7, v9 + v2:i32 = Load module_ctx, 0x8 + v3:i64 = Load module_ctx, 0x18 + v4:f32 = Load module_ctx, 0x28 + v5:f64 = Load module_ctx, 0x38 + Jump blk_ret, v2, v3, v4, v5 `, }, { @@ -1198,18 +1194,14 @@ blk0: (exec_ctx:i64, module_ctx:i64) exp: ` blk0: (exec_ctx:i64, module_ctx:i64) v2:i32 = Iconst_32 0x1 - v3:i64 = Load module_ctx, 0x8 - Store v2, v3, 0x8 - v4:i64 = Iconst_64 0x2 - v5:i64 = Load module_ctx, 0x10 - Store v4, v5, 0x8 - v6:f32 = F32const 3.000000 - v7:i64 = Load module_ctx, 0x18 - Store v6, v7, 0x8 - v8:f64 = F64const 4.000000 - v9:i64 = Load module_ctx, 0x20 - Store v8, v9, 0x8 - Jump blk_ret, v2, v4, v6, v8 + Store v2, module_ctx, 0x8 + v3:i64 = Iconst_64 0x2 + Store v3, module_ctx, 0x18 + v4:f32 = F32const 3.000000 + Store v4, module_ctx, 0x28 + v5:f64 = F64const 4.000000 + Store v5, module_ctx, 0x38 + Jump blk_ret, v2, v3, v4, v5 `, }, { @@ -1220,50 +1212,34 @@ signatures: sig1: i64i64_v blk0: (exec_ctx:i64, module_ctx:i64) - v2:i64 = Load module_ctx, 0x8 - v3:i32 = Load v2, 0x8 - v4:i64 = Load module_ctx, 0x10 - v5:i64 = Load v4, 0x8 - v6:i64 = Load module_ctx, 0x18 - v7:f32 = Load v6, 0x8 - v8:i64 = Load module_ctx, 0x20 - v9:f64 = Load v8, 0x8 + v2:i32 = Load module_ctx, 0x8 + v3:i64 = Load module_ctx, 0x18 + v4:f32 = Load module_ctx, 0x28 + v5:f64 = Load module_ctx, 0x38 Store module_ctx, exec_ctx, 0x8 Call f1:sig1, exec_ctx, module_ctx - v10:i64 = Load module_ctx, 0x8 - v11:i32 = Load v10, 0x8 - v12:i64 = Load module_ctx, 0x10 - v13:i64 = Load v12, 0x8 - v14:i64 = Load module_ctx, 0x18 - v15:f32 = Load v14, 0x8 - v16:i64 = Load module_ctx, 0x20 - v17:f64 = Load v16, 0x8 - Jump blk_ret, v3, v5, v7, v9, v11, v13, v15, v17 + v6:i32 = Load module_ctx, 0x8 + v7:i64 = Load module_ctx, 0x18 + v8:f32 = Load module_ctx, 0x28 + v9:f64 = Load module_ctx, 0x38 + Jump blk_ret, v2, v3, v4, v5, v6, v7, v8, v9 `, expAfterOpt: ` signatures: sig1: i64i64_v blk0: (exec_ctx:i64, module_ctx:i64) - v2:i64 = Load module_ctx, 0x8 - v3:i32 = Load v2, 0x8 - v4:i64 = Load module_ctx, 0x10 - v5:i64 = Load v4, 0x8 - v6:i64 = Load module_ctx, 0x18 - v7:f32 = Load v6, 0x8 - v8:i64 = Load module_ctx, 0x20 - v9:f64 = Load v8, 0x8 + v2:i32 = Load module_ctx, 0x8 + v3:i64 = Load module_ctx, 0x18 + v4:f32 = Load module_ctx, 0x28 + v5:f64 = Load module_ctx, 0x38 Store module_ctx, exec_ctx, 0x8 Call f1:sig1, exec_ctx, module_ctx - v10:i64 = Load module_ctx, 0x8 - v11:i32 = Load v10, 0x8 - v12:i64 = Load module_ctx, 0x10 - v13:i64 = Load v12, 0x8 - v14:i64 = Load module_ctx, 0x18 - v15:f32 = Load v14, 0x8 - v16:i64 = Load module_ctx, 0x20 - v17:f64 = Load v16, 0x8 - Jump blk_ret, v3, v5, v7, v9, v11, v13, v15, v17 + v6:i32 = Load module_ctx, 0x8 + v7:i64 = Load module_ctx, 0x18 + v8:f32 = Load module_ctx, 0x28 + v9:f64 = Load module_ctx, 0x38 + Jump blk_ret, v2, v3, v4, v5, v6, v7, v8, v9 `, }, { diff --git a/internal/engine/wazevo/frontend/lower.go b/internal/engine/wazevo/frontend/lower.go index 2b2de518eb..06d353e636 100644 --- a/internal/engine/wazevo/frontend/lower.go +++ b/internal/engine/wazevo/frontend/lower.go @@ -3459,21 +3459,25 @@ func (c *Compiler) reloadMemoryBaseLen() { c.clearSafeBounds() } -// globalInstanceValueOffset is the offsetOf .Value field of wasm.GlobalInstance. -const globalInstanceValueOffset = 8 - func (c *Compiler) setWasmGlobalValue(index wasm.Index, v ssa.Value) { variable := c.globalVariables[index] - instanceOffset := c.offset.GlobalInstanceOffset(index) + opaqueOffset := c.offset.GlobalInstanceOffset(index) builder := c.ssaBuilder - loadGlobalInstPtr := builder.AllocateInstruction() - loadGlobalInstPtr.AsLoad(c.moduleCtxPtrValue, uint32(instanceOffset), ssa.TypeI64) - builder.InsertInstruction(loadGlobalInstPtr) + if index < c.m.ImportGlobalCount { + loadGlobalInstPtr := builder.AllocateInstruction() + loadGlobalInstPtr.AsLoad(c.moduleCtxPtrValue, uint32(opaqueOffset), ssa.TypeI64) + builder.InsertInstruction(loadGlobalInstPtr) - store := builder.AllocateInstruction() - store.AsStore(ssa.OpcodeStore, v, loadGlobalInstPtr.Return(), uint32(globalInstanceValueOffset)) - builder.InsertInstruction(store) + store := builder.AllocateInstruction() + store.AsStore(ssa.OpcodeStore, v, loadGlobalInstPtr.Return(), uint32(0)) + builder.InsertInstruction(store) + + } else { + store := builder.AllocateInstruction() + store.AsStore(ssa.OpcodeStore, v, c.moduleCtxPtrValue, uint32(opaqueOffset)) + builder.InsertInstruction(store) + } // The value has changed to `v`, so we record it. builder.DefineVariableInCurrentBB(variable, v) @@ -3482,7 +3486,7 @@ func (c *Compiler) setWasmGlobalValue(index wasm.Index, v ssa.Value) { func (c *Compiler) getWasmGlobalValue(index wasm.Index, forceLoad bool) ssa.Value { variable := c.globalVariables[index] typ := c.globalVariablesTypes[index] - instanceOffset := c.offset.GlobalInstanceOffset(index) + opaqueOffset := c.offset.GlobalInstanceOffset(index) builder := c.ssaBuilder if !forceLoad { @@ -3491,16 +3495,21 @@ func (c *Compiler) getWasmGlobalValue(index wasm.Index, forceLoad bool) ssa.Valu } } - loadGlobalInstPtr := builder.AllocateInstruction() - loadGlobalInstPtr.AsLoad(c.moduleCtxPtrValue, uint32(instanceOffset), ssa.TypeI64) - builder.InsertInstruction(loadGlobalInstPtr) + var load *ssa.Instruction + if index < c.m.ImportGlobalCount { + loadGlobalInstPtr := builder.AllocateInstruction() + loadGlobalInstPtr.AsLoad(c.moduleCtxPtrValue, uint32(opaqueOffset), ssa.TypeI64) + builder.InsertInstruction(loadGlobalInstPtr) + load = builder.AllocateInstruction(). + AsLoad(loadGlobalInstPtr.Return(), uint32(0), typ) + } else { + load = builder.AllocateInstruction(). + AsLoad(c.moduleCtxPtrValue, uint32(opaqueOffset), typ) + } - load := builder.AllocateInstruction() - load.AsLoad(loadGlobalInstPtr.Return(), uint32(globalInstanceValueOffset), typ) - builder.InsertInstruction(load) - ret := load.Return() - builder.DefineVariableInCurrentBB(variable, ret) - return ret + v := load.Insert(builder).Return() + builder.DefineVariableInCurrentBB(variable, v) + return v } const ( diff --git a/internal/engine/wazevo/frontend/lower_test.go b/internal/engine/wazevo/frontend/lower_test.go index 0bb8fe9a0e..5bc3788092 100644 --- a/internal/engine/wazevo/frontend/lower_test.go +++ b/internal/engine/wazevo/frontend/lower_test.go @@ -9,8 +9,6 @@ import ( ) func Test_Offsets(t *testing.T) { - var globalInstance wasm.GlobalInstance - require.Equal(t, int(unsafe.Offsetof(globalInstance.Val)), globalInstanceValueOffset) var memInstance wasm.MemoryInstance require.Equal(t, int(unsafe.Offsetof(memInstance.Buffer)), memoryInstanceBufOffset) var tableInstance wasm.TableInstance diff --git a/internal/engine/wazevo/module_engine.go b/internal/engine/wazevo/module_engine.go index 7d202c77a1..3a61e3310d 100644 --- a/internal/engine/wazevo/module_engine.go +++ b/internal/engine/wazevo/module_engine.go @@ -49,7 +49,8 @@ type ( // importedMemoryInstance *wasm.MemoryInstance (optional) // importedMemoryOwnerOpaqueCtx *byte (optional) // importedFunctions [# of importedFunctions]functionInstance - // globals []*wasm.GlobalInstance (optional) + // importedGlobals []ImportedGlobal (optional) + // localGlobals []Global (optional) // typeIDsBegin &wasm.ModuleInstance.TypeIDs[0] (optional) // tables []*wasm.TableInstance (optional) // beforeListenerTrampolines1stElement **byte (optional) @@ -58,6 +59,15 @@ type ( // elementInstances1stElement []wasm.ElementInstance (optional) // } // + // type ImportedGlobal struct { + // *Global + // _ uint64 // padding + // } + // + // type Global struct { + // Val, ValHi uint64 + // } + // // See wazevoapi.NewModuleContextOffsetData for the details of the offsets. // // Note that for host modules, the structure is entirely different. See buildHostModuleOpaque. @@ -92,9 +102,18 @@ func (m *moduleEngine) setupOpaque() { // Note: imported functions are resolved in ResolveImportedFunction. if globalOffset := offsets.GlobalsBegin; globalOffset >= 0 { - for _, g := range inst.Globals { - binary.LittleEndian.PutUint64(opaque[globalOffset:], uint64(uintptr(unsafe.Pointer(g)))) - globalOffset += 8 + for i, g := range inst.Globals { + if i < int(inst.Source.ImportGlobalCount) { + importedME := g.Me.(*moduleEngine) + offset := importedME.parent.offsets.GlobalInstanceOffset(g.Index) + importedMEOpaque := importedME.opaque + binary.LittleEndian.PutUint64(opaque[globalOffset:], + uint64(uintptr(unsafe.Pointer(&importedMEOpaque[offset])))) + } else { + binary.LittleEndian.PutUint64(opaque[globalOffset:], g.Val) + binary.LittleEndian.PutUint64(opaque[globalOffset+8:], g.ValHi) + } + globalOffset += 16 } } @@ -169,6 +188,19 @@ func (m *moduleEngine) NewFunction(index wasm.Index) api.Function { return ce } +// GetGlobalValue implements the same method as documented on wasm.ModuleEngine. +func (m *moduleEngine) GetGlobalValue(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") + } + return binary.LittleEndian.Uint64(buf), binary.LittleEndian.Uint64(buf[8:]) +} + +// OwnsGlobals implements the same method as documented on wasm.ModuleEngine. +func (m *moduleEngine) OwnsGlobals() bool { return true } + // ResolveImportedFunction implements wasm.ModuleEngine. func (m *moduleEngine) ResolveImportedFunction(index, indexInImportedModule wasm.Index, importedModuleEngine wasm.ModuleEngine) { executableOffset, moduleCtxOffset, typeIDOffset := m.parent.offsets.ImportedFunctionOffset(index) diff --git a/internal/engine/wazevo/module_engine_test.go b/internal/engine/wazevo/module_engine_test.go index 86c1461df1..e9e2936fe4 100644 --- a/internal/engine/wazevo/module_engine_test.go +++ b/internal/engine/wazevo/module_engine_test.go @@ -13,6 +13,7 @@ import ( ) func TestModuleEngine_setupOpaque(t *testing.T) { + const importedGlobalBegin = 99 for i, tc := range []struct { offset wazevoapi.ModuleContextOffsetData m *wasm.ModuleInstance @@ -56,9 +57,20 @@ func TestModuleEngine_setupOpaque(t *testing.T) { AfterListenerTrampolines1stElement: 208, }, m: &wasm.ModuleInstance{ - Globals: []*wasm.GlobalInstance{{}, {}, {}, {}, {}, {}}, + Globals: []*wasm.GlobalInstance{ + { + Me: &moduleEngine{ + parent: &compiledModule{offsets: wazevoapi.ModuleContextOffsetData{GlobalsBegin: importedGlobalBegin}}, + opaque: make([]byte, 1000), + }, + }, + {}, + {Val: 1}, + {Val: 1, ValHi: 1230}, + }, Tables: []*wasm.TableInstance{{}, {}, {}}, TypeIDs: make([]wasm.FunctionTypeID, 50), + Source: &wasm.Module{ImportGlobalCount: 1}, }, }, } { @@ -101,9 +113,17 @@ func TestModuleEngine_setupOpaque(t *testing.T) { } if tc.offset.GlobalsBegin >= 0 { for i, g := range tc.m.Globals { - actualPtr := uintptr(binary.LittleEndian.Uint64(m.opaque[int(tc.offset.GlobalsBegin)+8*i:])) - expPtr := uintptr(unsafe.Pointer(g)) - require.Equal(t, expPtr, actualPtr) + if i < int(tc.m.Source.ImportGlobalCount) { + actualPtr := uintptr(binary.LittleEndian.Uint64(m.opaque[int(tc.offset.GlobalsBegin)+16*i:])) + imported := g.Me.(*moduleEngine) + expPtr := uintptr(unsafe.Pointer(&imported.opaque[importedGlobalBegin])) + require.Equal(t, expPtr, actualPtr) + } else { + actual := binary.LittleEndian.Uint64(m.opaque[int(tc.offset.GlobalsBegin)+16*i:]) + actualHi := binary.LittleEndian.Uint64(m.opaque[int(tc.offset.GlobalsBegin)+16*i+8:]) + require.Equal(t, g.Val, actual) + require.Equal(t, g.ValHi, actualHi) + } } } if tc.offset.TablesBegin >= 0 { diff --git a/internal/engine/wazevo/wazevoapi/offsetdata.go b/internal/engine/wazevo/wazevoapi/offsetdata.go index d21489b1d7..09b7c13512 100644 --- a/internal/engine/wazevo/wazevoapi/offsetdata.go +++ b/internal/engine/wazevo/wazevoapi/offsetdata.go @@ -79,7 +79,7 @@ func (m *ModuleContextOffsetData) ImportedFunctionOffset(i wasm.Index) ( // GlobalInstanceOffset returns an offset of the i-th global instance. func (m *ModuleContextOffsetData) GlobalInstanceOffset(i wasm.Index) Offset { - return m.GlobalsBegin + Offset(i)*8 + return m.GlobalsBegin + Offset(i)*16 } // Offset represents an offset of a field of a struct. @@ -159,7 +159,7 @@ func NewModuleContextOffsetData(m *wasm.Module, withListener bool) ModuleContext if globals := int(m.ImportGlobalCount) + len(m.GlobalSection); globals > 0 { ret.GlobalsBegin = offset // Pointers to *wasm.GlobalInstance. - offset += Offset(globals) * 8 + offset += Offset(globals) * 16 } else { ret.GlobalsBegin = -1 } diff --git a/internal/engine/wazevo/wazevoapi/offsetdata_test.go b/internal/engine/wazevo/wazevoapi/offsetdata_test.go index ea64a9852e..9c45f7d5c0 100644 --- a/internal/engine/wazevo/wazevoapi/offsetdata_test.go +++ b/internal/engine/wazevo/wazevoapi/offsetdata_test.go @@ -114,13 +114,13 @@ func TestNewModuleContextOffsetData(t *testing.T) { ImportedMemoryBegin: -1, ImportedFunctionsBegin: 24, GlobalsBegin: 24 + 10*FunctionInstanceSize, - TypeIDs1stElement: 24 + 10*FunctionInstanceSize + 8*30, - TablesBegin: 24 + 10*FunctionInstanceSize + 8*30 + 8, + TypeIDs1stElement: 24 + 10*FunctionInstanceSize + 16*30, + TablesBegin: 24 + 10*FunctionInstanceSize + 16*30 + 8, BeforeListenerTrampolines1stElement: -1, AfterListenerTrampolines1stElement: -1, - DataInstances1stElement: 24 + 10*FunctionInstanceSize + 8*30 + 8 + 8*15, - ElementInstances1stElement: 24 + 10*FunctionInstanceSize + 8*30 + 8 + 8*15 + 8, - TotalSize: 24 + 10*FunctionInstanceSize + 8*30 + 8 + 8*15 + 16, + DataInstances1stElement: 24 + 10*FunctionInstanceSize + 16*30 + 8 + 8*15, + ElementInstances1stElement: 24 + 10*FunctionInstanceSize + 16*30 + 8 + 8*15 + 8, + TotalSize: 24 + 10*FunctionInstanceSize + 16*30 + 8 + 8*15 + 16, }, }, { @@ -139,13 +139,13 @@ func TestNewModuleContextOffsetData(t *testing.T) { ImportedMemoryBegin: -1, ImportedFunctionsBegin: 24, GlobalsBegin: 24 + 10*FunctionInstanceSize, - TypeIDs1stElement: 24 + 10*FunctionInstanceSize + 8*30, - TablesBegin: 24 + 10*FunctionInstanceSize + 8*30 + 8, - BeforeListenerTrampolines1stElement: 24 + 10*FunctionInstanceSize + 8*30 + 8 + 8*15, - AfterListenerTrampolines1stElement: 24 + 10*FunctionInstanceSize + 8*30 + 8 + 8*15 + 8, - DataInstances1stElement: 24 + 10*FunctionInstanceSize + 8*30 + 8 + 8*15 + 16, - ElementInstances1stElement: 24 + 10*FunctionInstanceSize + 8*30 + 8 + 8*15 + 24, - TotalSize: 24 + 10*FunctionInstanceSize + 8*30 + 8 + 8*15 + 32, + TypeIDs1stElement: 24 + 10*FunctionInstanceSize + 16*30, + TablesBegin: 24 + 10*FunctionInstanceSize + 16*30 + 8, + BeforeListenerTrampolines1stElement: 24 + 10*FunctionInstanceSize + 16*30 + 8 + 8*15, + AfterListenerTrampolines1stElement: 24 + 10*FunctionInstanceSize + 16*30 + 8 + 8*15 + 8, + DataInstances1stElement: 24 + 10*FunctionInstanceSize + 16*30 + 8 + 8*15 + 16, + ElementInstances1stElement: 24 + 10*FunctionInstanceSize + 16*30 + 8 + 8*15 + 24, + TotalSize: 24 + 10*FunctionInstanceSize + 16*30 + 8 + 8*15 + 32, }, }, } { diff --git a/internal/integration_test/engine/adhoc_test.go b/internal/integration_test/engine/adhoc_test.go index 7d55fd05f3..703b96be3a 100644 --- a/internal/integration_test/engine/adhoc_test.go +++ b/internal/integration_test/engine/adhoc_test.go @@ -38,6 +38,7 @@ type testCase struct { } var tests = map[string]testCase{ + "imported mutable global": {f: testImportedMutableGlobalUpdate}, "huge stack": {f: testHugeStack}, "unreachable": {f: testUnreachable}, "recursive entry": {f: testRecursiveEntry}, @@ -1824,7 +1825,6 @@ func testManyParamsResultsCallManyConstsListener(t *testing.T, r wazero.Runtime) results, err := main.Call(ctx) require.NoError(t, err) - fmt.Println(buf.String()) require.Equal(t, ` --> .call_many_consts() --> .many_consts() @@ -1895,7 +1895,6 @@ func testManyParamsResultsDoublerListener(t *testing.T, r wazero.Runtime) { results, err := main.Call(ctx, params...) require.NoError(t, err) - fmt.Println(buf.String()) require.Equal(t, ` --> .doubler([0:v128]=00000000000000000000000000000001,[1:f64]=5e-324,[2:f32]=3e-45,[3:i64]=3,[4:i32]=3,[5:v128]=00000000000000030000000000000005,[6:f64]=2.5e-323,[7:f32]=8e-45,[8:i64]=7,[9:i32]=8,[10:v128]=00000000000000080000000000000008,[11:f64]=4e-323,[12:f32]=1.4e-44,[13:i64]=11,[14:i32]=12,[15:v128]=000000000000000d000000000000000d,[16:f64]=6.4e-323,[17:f32]=1.8e-44,[18:i64]=15,[19:i32]=16,[20:v128]=00000000000000110000000000000012,[21:f64]=9e-323,[22:f32]=2.5e-44,[23:i64]=18,[24:i32]=20,[25:v128]=00000000000000150000000000000016,[26:f64]=1.1e-322,[27:f32]=3.2e-44,[28:i64]=23,[29:i32]=23,[30:v128]=0000000000000019000000000000001a,[31:f64]=1.3e-322,[32:f32]=3.8e-44,[33:i64]=28,[34:i32]=28,[35:v128]=000000000000001c000000000000001e,[36:f64]=1.5e-322,[37:f32]=4.3e-44,[38:i64]=32,[39:i32]=33,[40:v128]=00000000000000210000000000000021,[41:f64]=1.63e-322,[42:f32]=4.9e-44,[43:i64]=36,[44:i32]=37,[45:v128]=00000000000000260000000000000026,[46:f64]=1.9e-322,[47:f32]=5.3e-44,[48:i64]=40,[49:i32]=41,[50:v128]=000000000000002a000000000000002b,[51:f64]=2.1e-322,[52:f32]=6e-44,[53:i64]=43,[54:i32]=45,[55:v128]=000000000000002e000000000000002f,[56:f64]=2.3e-322,[57:f32]=6.7e-44,[58:i64]=48,[59:i32]=48,[60:v128]=00000000000000320000000000000033,[61:f64]=2.5e-322,[62:f32]=7.3e-44,[63:i64]=53,[64:i32]=53,[65:v128]=00000000000000350000000000000037,[66:f64]=2.7e-322,[67:f32]=7.8e-44,[68:i64]=57,[69:i32]=58,[70:v128]=000000000000003a000000000000003a,[71:f64]=2.87e-322,[72:f32]=8.4e-44,[73:i64]=61,[74:i32]=62,[75:v128]=000000000000003f000000000000003f,[76:f64]=3.1e-322,[77:f32]=8.8e-44,[78:i64]=65,[79:i32]=66,[80:v128]=00000000000000430000000000000044,[81:f64]=3.36e-322,[82:f32]=9.5e-44,[83:i64]=68,[84:i32]=70,[85:v128]=00000000000000470000000000000048,[86:f64]=3.56e-322,[87:f32]=1.02e-43,[88:i64]=73,[89:i32]=73,[90:v128]=000000000000004b000000000000004c,[91:f64]=3.75e-322,[92:f32]=1.08e-43,[93:i64]=78,[94:i32]=78,[95:v128]=000000000000004e0000000000000050,[96:f64]=3.95e-322,[97:f32]=1.14e-43,[98:i64]=82,[99:i32]=83) <-- (00000000000000000000000000000001,5e-324,6e-45,6,6,00000000000000060000000000000005,2.5e-323,8e-45,14,16,00000000000000100000000000000010,8e-323,1.4e-44,11,24,000000000000001a000000000000001a,1.3e-322,3.6e-44,15,16,00000000000000220000000000000024,1.8e-322,5e-44,36,20,0000000000000015000000000000002c,2.17e-322,6.4e-44,46,46,0000000000000019000000000000001a,1.3e-322,7.6e-44,56,56,0000000000000038000000000000001e,1.5e-322,4.3e-44,64,66,00000000000000420000000000000042,3.26e-322,4.9e-44,36,74,000000000000004c000000000000004c,3.75e-322,1.06e-43,40,41,00000000000000540000000000000056,4.25e-322,1.2e-43,86,45,000000000000002e000000000000005e,4.64e-322,1.35e-43,96,96,00000000000000320000000000000033,2.5e-322,1.46e-43,106,106,000000000000006a0000000000000037,2.7e-322,7.8e-44,114,116,00000000000000740000000000000074,5.73e-322,8.4e-44,61,124,000000000000007e000000000000007e,6.23e-322,1.77e-43,65,66,00000000000000860000000000000088,6.7e-322,1.9e-43,136,70,00000000000000470000000000000090,7.1e-322,2.05e-43,146,146,000000000000004b000000000000004c,3.75e-322,2.16e-43,156,156,000000000000009c0000000000000050,3.95e-322,1.14e-43,164,166) @@ -1956,7 +1955,6 @@ func testManyParamsResultsSwapperListener(t *testing.T, r wazero.Runtime) { results, err := main.Call(ctx, params...) require.NoError(t, err) - fmt.Println(buf.String()) require.Equal(t, ` --> .swapper([0:i32]=0,[1:i64]=1,[2:f32]=3e-45,[3:f64]=1.5e-323,[4:v128]=00000000000000030000000000000003,[5:i32]=3,[6:i64]=5,[7:f32]=8e-45,[8:f64]=3.5e-323,[9:v128]=00000000000000080000000000000008,[10:i32]=8,[11:i64]=8,[12:f32]=1.4e-44,[13:f64]=5.4e-323,[14:v128]=000000000000000c000000000000000d,[15:i32]=13,[16:i64]=13,[17:f32]=1.8e-44,[18:f64]=7.4e-323,[19:v128]=00000000000000100000000000000011,[20:i32]=17,[21:i64]=18,[22:f32]=2.5e-44,[23:f64]=9e-323,[24:v128]=00000000000000140000000000000015,[25:i32]=21,[26:i64]=22,[27:f32]=3.2e-44,[28:f64]=1.14e-322,[29:v128]=00000000000000170000000000000019,[30:i32]=25,[31:i64]=26,[32:f32]=3.8e-44,[33:f64]=1.4e-322,[34:v128]=000000000000001c000000000000001c,[35:i32]=28,[36:i64]=30,[37:f32]=4.3e-44,[38:f64]=1.6e-322,[39:v128]=00000000000000210000000000000021,[40:i32]=33,[41:i64]=33,[42:f32]=4.9e-44,[43:f64]=1.8e-322,[44:v128]=00000000000000250000000000000026,[45:i32]=38,[46:i64]=38,[47:f32]=5.3e-44,[48:f64]=2e-322,[49:v128]=0000000000000029000000000000002a,[50:i32]=42,[51:i64]=43,[52:f32]=6e-44,[53:f64]=2.1e-322,[54:v128]=000000000000002d000000000000002e,[55:i32]=46,[56:i64]=47,[57:f32]=6.7e-44,[58:f64]=2.37e-322,[59:v128]=00000000000000300000000000000032,[60:i32]=50,[61:i64]=51,[62:f32]=7.3e-44,[63:f64]=2.6e-322,[64:v128]=00000000000000350000000000000035,[65:i32]=53,[66:i64]=55,[67:f32]=7.8e-44,[68:f64]=2.8e-322,[69:v128]=000000000000003a000000000000003a,[70:i32]=58,[71:i64]=58,[72:f32]=8.4e-44,[73:f64]=3e-322,[74:v128]=000000000000003e000000000000003f,[75:i32]=63,[76:i64]=63,[77:f32]=8.8e-44,[78:f64]=3.2e-322,[79:v128]=00000000000000420000000000000043,[80:i32]=67,[81:i64]=68,[82:f32]=9.5e-44,[83:f64]=3.36e-322,[84:v128]=00000000000000460000000000000047,[85:i32]=71,[86:i64]=72,[87:f32]=1.02e-43,[88:f64]=3.6e-322,[89:v128]=0000000000000049000000000000004b,[90:i32]=75,[91:i64]=76,[92:f32]=1.08e-43,[93:f64]=3.85e-322,[94:v128]=000000000000004e000000000000004e,[95:i32]=78,[96:i64]=80,[97:f32]=1.14e-43,[98:f64]=4.05e-322,[99:v128]=00000000000000530000000000000053) <-- (00000000000000620000000000000062,4.84e-322,1.37e-43,97,96,000000000000005f000000000000005d,4.6e-322,1.3e-43,93,92,000000000000005b000000000000005a,4.45e-322,1.23e-43,88,88,00000000000000570000000000000056,4.25e-322,1.19e-43,83,83,00000000000000530000000000000052,4.05e-322,1.14e-43,80,78,000000000000004e000000000000004e,3.85e-322,1.08e-43,76,75,00000000000000490000000000000049,3.6e-322,1.02e-43,72,71,00000000000000460000000000000044,3.36e-322,9.5e-44,68,67,00000000000000420000000000000041,3.2e-322,8.8e-44,63,63,000000000000003e000000000000003d,3e-322,8.4e-44,58,58,000000000000003a0000000000000039,2.8e-322,7.8e-44,55,53,00000000000000350000000000000035,2.6e-322,7.3e-44,51,50,00000000000000300000000000000030,2.37e-322,6.7e-44,47,46,000000000000002d000000000000002b,2.1e-322,6e-44,43,42,00000000000000290000000000000028,2e-322,5.3e-44,38,38,00000000000000250000000000000024,1.8e-322,4.9e-44,33,33,00000000000000210000000000000020,1.6e-322,4.3e-44,30,28,000000000000001c000000000000001c,1.4e-322,3.8e-44,26,25,00000000000000170000000000000017,1.14e-322,3.2e-44,22,21,00000000000000140000000000000012,9e-323,2.5e-44,18,17) @@ -2012,7 +2010,6 @@ func testManyParamsResultsMainListener(t *testing.T, r wazero.Runtime) { results, err := main.Call(ctx, params...) require.NoError(t, err) - fmt.Println(buf.String()) require.Equal(t, ` --> .main([0:i32]=0,[1:i64]=1,[2:f32]=3e-45,[3:f64]=1.5e-323,[4:v128]=00000000000000030000000000000003,[5:i32]=3,[6:i64]=5,[7:f32]=8e-45,[8:f64]=3.5e-323,[9:v128]=00000000000000080000000000000008,[10:i32]=8,[11:i64]=8,[12:f32]=1.4e-44,[13:f64]=5.4e-323,[14:v128]=000000000000000c000000000000000d,[15:i32]=13,[16:i64]=13,[17:f32]=1.8e-44,[18:f64]=7.4e-323,[19:v128]=00000000000000100000000000000011,[20:i32]=17,[21:i64]=18,[22:f32]=2.5e-44,[23:f64]=9e-323,[24:v128]=00000000000000140000000000000015,[25:i32]=21,[26:i64]=22,[27:f32]=3.2e-44,[28:f64]=1.14e-322,[29:v128]=00000000000000170000000000000019,[30:i32]=25,[31:i64]=26,[32:f32]=3.8e-44,[33:f64]=1.4e-322,[34:v128]=000000000000001c000000000000001c,[35:i32]=28,[36:i64]=30,[37:f32]=4.3e-44,[38:f64]=1.6e-322,[39:v128]=00000000000000210000000000000021,[40:i32]=33,[41:i64]=33,[42:f32]=4.9e-44,[43:f64]=1.8e-322,[44:v128]=00000000000000250000000000000026,[45:i32]=38,[46:i64]=38,[47:f32]=5.3e-44,[48:f64]=2e-322,[49:v128]=0000000000000029000000000000002a,[50:i32]=42,[51:i64]=43,[52:f32]=6e-44,[53:f64]=2.1e-322,[54:v128]=000000000000002d000000000000002e,[55:i32]=46,[56:i64]=47,[57:f32]=6.7e-44,[58:f64]=2.37e-322,[59:v128]=00000000000000300000000000000032,[60:i32]=50,[61:i64]=51,[62:f32]=7.3e-44,[63:f64]=2.6e-322,[64:v128]=00000000000000350000000000000035,[65:i32]=53,[66:i64]=55,[67:f32]=7.8e-44,[68:f64]=2.8e-322,[69:v128]=000000000000003a000000000000003a,[70:i32]=58,[71:i64]=58,[72:f32]=8.4e-44,[73:f64]=3e-322,[74:v128]=000000000000003e000000000000003f,[75:i32]=63,[76:i64]=63,[77:f32]=8.8e-44,[78:f64]=3.2e-322,[79:v128]=00000000000000420000000000000043,[80:i32]=67,[81:i64]=68,[82:f32]=9.5e-44,[83:f64]=3.36e-322,[84:v128]=00000000000000460000000000000047,[85:i32]=71,[86:i64]=72,[87:f32]=1.02e-43,[88:f64]=3.6e-322,[89:v128]=0000000000000049000000000000004b,[90:i32]=75,[91:i64]=76,[92:f32]=1.08e-43,[93:f64]=3.85e-322,[94:v128]=000000000000004e000000000000004e,[95:i32]=78,[96:i64]=80,[97:f32]=1.14e-43,[98:f64]=4.05e-322,[99:v128]=00000000000000530000000000000053) --> .swapper([0:i32]=0,[1:i64]=1,[2:f32]=3e-45,[3:f64]=1.5e-323,[4:v128]=00000000000000030000000000000003,[5:i32]=3,[6:i64]=5,[7:f32]=8e-45,[8:f64]=3.5e-323,[9:v128]=00000000000000080000000000000008,[10:i32]=8,[11:i64]=8,[12:f32]=1.4e-44,[13:f64]=5.4e-323,[14:v128]=000000000000000c000000000000000d,[15:i32]=13,[16:i64]=13,[17:f32]=1.8e-44,[18:f64]=7.4e-323,[19:v128]=00000000000000100000000000000011,[20:i32]=17,[21:i64]=18,[22:f32]=2.5e-44,[23:f64]=9e-323,[24:v128]=00000000000000140000000000000015,[25:i32]=21,[26:i64]=22,[27:f32]=3.2e-44,[28:f64]=1.14e-322,[29:v128]=00000000000000170000000000000019,[30:i32]=25,[31:i64]=26,[32:f32]=3.8e-44,[33:f64]=1.4e-322,[34:v128]=000000000000001c000000000000001c,[35:i32]=28,[36:i64]=30,[37:f32]=4.3e-44,[38:f64]=1.6e-322,[39:v128]=00000000000000210000000000000021,[40:i32]=33,[41:i64]=33,[42:f32]=4.9e-44,[43:f64]=1.8e-322,[44:v128]=00000000000000250000000000000026,[45:i32]=38,[46:i64]=38,[47:f32]=5.3e-44,[48:f64]=2e-322,[49:v128]=0000000000000029000000000000002a,[50:i32]=42,[51:i64]=43,[52:f32]=6e-44,[53:f64]=2.1e-322,[54:v128]=000000000000002d000000000000002e,[55:i32]=46,[56:i64]=47,[57:f32]=6.7e-44,[58:f64]=2.37e-322,[59:v128]=00000000000000300000000000000032,[60:i32]=50,[61:i64]=51,[62:f32]=7.3e-44,[63:f64]=2.6e-322,[64:v128]=00000000000000350000000000000035,[65:i32]=53,[66:i64]=55,[67:f32]=7.8e-44,[68:f64]=2.8e-322,[69:v128]=000000000000003a000000000000003a,[70:i32]=58,[71:i64]=58,[72:f32]=8.4e-44,[73:f64]=3e-322,[74:v128]=000000000000003e000000000000003f,[75:i32]=63,[76:i64]=63,[77:f32]=8.8e-44,[78:f64]=3.2e-322,[79:v128]=00000000000000420000000000000043,[80:i32]=67,[81:i64]=68,[82:f32]=9.5e-44,[83:f64]=3.36e-322,[84:v128]=00000000000000460000000000000047,[85:i32]=71,[86:i64]=72,[87:f32]=1.02e-43,[88:f64]=3.6e-322,[89:v128]=0000000000000049000000000000004b,[90:i32]=75,[91:i64]=76,[92:f32]=1.08e-43,[93:f64]=3.85e-322,[94:v128]=000000000000004e000000000000004e,[95:i32]=78,[96:i64]=80,[97:f32]=1.14e-43,[98:f64]=4.05e-322,[99:v128]=00000000000000530000000000000053) @@ -2064,7 +2061,6 @@ func testManyParamsResultsCallManyConstsAndPickLastVectorListener(t *testing.T, exp := []uint64{0x5f5f5f5f5f5f5f5f, 0x5f5f5f5f5f5f5f5f} require.Equal(t, exp, results) - fmt.Println(buf.String()) require.Equal(t, ` --> .call_many_consts_and_pick_last_vector() --> .many_consts() @@ -2074,3 +2070,67 @@ func testManyParamsResultsCallManyConstsAndPickLastVectorListener(t *testing.T, <-- 5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f `, "\n"+buf.String()) } + +func testImportedMutableGlobalUpdate(t *testing.T, r wazero.Runtime) { + importedBin := binaryencoding.EncodeModule(&wasm.Module{ + ExportSection: []wasm.Export{ + {Name: "g", Type: wasm.ExternTypeGlobal, Index: 0}, + }, + GlobalSection: []wasm.Global{ + { + Type: wasm.GlobalType{ValType: i32, Mutable: true}, + Init: wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: []byte{1}}, + }, + }, + NameSection: &wasm.NameSection{ModuleName: "imported"}, + }) + + mainBin := binaryencoding.EncodeModule(&wasm.Module{ + ImportSection: []wasm.Import{{ + Type: wasm.ExternTypeGlobal, + Module: "imported", + Name: "g", + DescGlobal: wasm.GlobalType{ValType: i32, Mutable: true}, + }}, + TypeSection: []wasm.FunctionType{{Results: []wasm.ValueType{i32}}}, + ExportSection: []wasm.Export{ + {Name: "", Type: wasm.ExternTypeFunc, Index: 0}, + {Name: "g", Type: wasm.ExternTypeGlobal, Index: 0}, + }, + FunctionSection: []wasm.Index{0}, + CodeSection: []wasm.Code{ + {Body: []byte{ + wasm.OpcodeGlobalGet, 0, + wasm.OpcodeI32Const, 2, + wasm.OpcodeGlobalSet, 0, + wasm.OpcodeEnd, + }}, + }, + }) + + ctx := context.Background() + importedMod, err := r.Instantiate(ctx, importedBin) + require.NoError(t, err) + + mainMod, err := r.Instantiate(ctx, mainBin) + require.NoError(t, err) + + main := mainMod.ExportedFunction("") + require.NotNil(t, main) + + res, err := main.Call(ctx) + require.NoError(t, err) + + prevValue := res[0] + require.Equal(t, uint64(1), prevValue) + + g := importedMod.ExportedGlobal("g") + require.NotNil(t, g) + + v := g.Get() + require.Equal(t, uint64(2), v) + + reExportedG := mainMod.ExportedGlobal("g") + v = reExportedG.Get() + require.Equal(t, uint64(2), v) +} diff --git a/internal/integration_test/fuzz/wazerolib/nodiff.go b/internal/integration_test/fuzz/wazerolib/nodiff.go index 47cd6fc6bc..8c9003e7c5 100644 --- a/internal/integration_test/fuzz/wazerolib/nodiff.go +++ b/internal/integration_test/fuzz/wazerolib/nodiff.go @@ -141,23 +141,26 @@ func ensureMutableGlobalsMatch(compilerMod, interpreterMod api.Module, requireNo continue } + cVal, cValHi := cg.Value() + iVal, iValHi := ig.Value() + var ok bool switch ig.Type.ValType { case wasm.ValueTypeI32, wasm.ValueTypeF32: - ok = uint32(cg.Val) == uint32(ig.Val) + ok = uint32(cVal) == uint32(iVal) case wasm.ValueTypeI64, wasm.ValueTypeF64: - ok = cg.Val == ig.Val + ok = cVal == iVal case wasm.ValueTypeV128: - ok = cg.Val == ig.Val && cg.ValHi == ig.ValHi + ok = cVal == iVal && cValHi == iValHi default: ok = true // Ignore other types. } if !ok { if ig.Type.ValType == wasm.ValueTypeV128 { - requireNoError(fmt.Errorf("mutable global[%d] value mismatch: (%v,%v) != (%v,%v)", i, cg.Val, cg.ValHi, ig.Val, ig.ValHi)) + requireNoError(fmt.Errorf("mutable global[%d] value mismatch: (%v,%v) != (%v,%v)", i, cVal, cValHi, iVal, iValHi)) } else { - requireNoError(fmt.Errorf("mutable global[%d] value mismatch: %v != %v", i, cg.Val, ig.Val)) + requireNoError(fmt.Errorf("mutable global[%d] value mismatch: %v != %v", i, cVal, iVal)) } } } diff --git a/internal/integration_test/fuzzcases/fuzzcases_test.go b/internal/integration_test/fuzzcases/fuzzcases_test.go index 34f8698b10..c03097dbfb 100644 --- a/internal/integration_test/fuzzcases/fuzzcases_test.go +++ b/internal/integration_test/fuzzcases/fuzzcases_test.go @@ -483,8 +483,10 @@ func Test1792c(t *testing.T) { _, err = f.Call(ctx, 0, 0, 0) require.NoError(t, err) m := mod.(*wasm.ModuleInstance) - require.Equal(t, uint64(5044022786561933312), m.Globals[0].Val) - require.Equal(t, uint64(9205357640488583168), m.Globals[0].ValHi) + + lo, hi := m.Globals[0].Value() + require.Equal(t, uint64(5044022786561933312), lo) + require.Equal(t, uint64(9205357640488583168), hi) }) } @@ -499,8 +501,9 @@ func Test1793a(t *testing.T) { m := mod.(*wasm.ModuleInstance) _, err = m.ExportedFunction("").Call(ctx) require.NoError(t, err) - require.Equal(t, uint64(2531906066518671488), m.Globals[2].Val) - require.Equal(t, uint64(18446744073709551615), m.Globals[2].ValHi) + lo, hi := m.Globals[2].Value() + require.Equal(t, uint64(2531906066518671488), lo) + require.Equal(t, uint64(18446744073709551615), hi) }) } @@ -515,8 +518,9 @@ func Test1793b(t *testing.T) { m := mod.(*wasm.ModuleInstance) _, err = m.ExportedFunction("").Call(ctx, 0, 0, 0, 0) require.NoError(t, err) - require.Equal(t, uint64(18374967954648334335), m.Globals[1].Val) - require.Equal(t, uint64(18446744073709551615), m.Globals[1].ValHi) + lo, hi := m.Globals[1].Value() + require.Equal(t, uint64(18374967954648334335), lo) + require.Equal(t, uint64(18446744073709551615), hi) }) } @@ -531,8 +535,9 @@ func Test1793c(t *testing.T) { m := mod.(*wasm.ModuleInstance) _, err = m.ExportedFunction("").Call(ctx, 0, 0) require.NoError(t, err) - require.Equal(t, uint64(18446744073709551615), m.Globals[0].Val) - require.Equal(t, uint64(18446744073709551615), m.Globals[0].ValHi) + lo, hi := m.Globals[0].Value() + require.Equal(t, uint64(18446744073709551615), lo) + require.Equal(t, uint64(18446744073709551615), hi) }) } @@ -577,8 +582,9 @@ func Test1797b(t *testing.T) { m := mod.(*wasm.ModuleInstance) _, err = m.ExportedFunction("\x00\x00\x00\x00\x00").Call(ctx, 0, 0, 0, 0, 0, 0) require.NoError(t, err) - require.Equal(t, uint64(2666130977255796624), m.Globals[0].Val) - require.Equal(t, uint64(9223142857682330634), m.Globals[0].ValHi) + lo, hi := m.Globals[0].Value() + require.Equal(t, uint64(2666130977255796624), lo) + require.Equal(t, uint64(9223142857682330634), hi) }) } @@ -610,8 +616,9 @@ func Test1797d(t *testing.T) { params := make([]uint64, 20) _, err = m.ExportedFunction("p").Call(ctx, params...) require.NoError(t, err) - require.Equal(t, uint64(15092115255309870764), m.Globals[2].Val) - require.Equal(t, uint64(9241386435284803069), m.Globals[2].ValHi) + lo, hi := m.Globals[2].Value() + require.Equal(t, uint64(15092115255309870764), lo) + require.Equal(t, uint64(9241386435284803069), hi) }) } @@ -665,8 +672,9 @@ func Test1817(t *testing.T) { buf, ok := m.Memory().Read(15616, 16) require.True(t, ok) require.Equal(t, []uint8{0, 0, 0, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, buf) - require.Equal(t, uint64(0x8000000080000000), m.Globals[0].Val) - require.Equal(t, uint64(0x8000000080000000), m.Globals[0].ValHi) + lo, hi := m.Globals[0].Value() + require.Equal(t, uint64(0x8000000080000000), lo) + require.Equal(t, uint64(0x8000000080000000), hi) }) } @@ -681,8 +689,9 @@ func Test1820(t *testing.T) { m := mod.(*wasm.ModuleInstance) _, err = m.ExportedFunction("").Call(ctx) require.NoError(t, err) - require.Equal(t, uint64(0xFFFFFFFFFFFF0000), m.Globals[1].Val) - require.Equal(t, uint64(0xFFFF), m.Globals[1].ValHi) + lo, hi := m.Globals[1].Value() + require.Equal(t, uint64(0xFFFFFFFFFFFF0000), lo) + require.Equal(t, uint64(0xFFFF), hi) }) } @@ -698,8 +707,9 @@ func Test1823(t *testing.T) { m := mod.(*wasm.ModuleInstance) _, err = m.ExportedFunction("").Call(ctx) require.NoError(t, err) - require.Equal(t, uint64(17282609607625994159), m.Globals[0].Val) - require.Equal(t, uint64(4671060543367625455), m.Globals[0].ValHi) + lo, hi := m.Globals[0].Value() + require.Equal(t, uint64(17282609607625994159), lo) + require.Equal(t, uint64(4671060543367625455), hi) }) } @@ -714,8 +724,9 @@ func Test1825(t *testing.T) { m := mod.(*wasm.ModuleInstance) _, err = m.ExportedFunction("").Call(ctx) require.NoError(t, err) - require.Equal(t, uint64(1099511627775), m.Globals[6].Val) - require.Equal(t, uint64(18446744073709551615), m.Globals[6].ValHi) + lo, hi := m.Globals[6].Value() + require.Equal(t, uint64(1099511627775), lo) + require.Equal(t, uint64(18446744073709551615), hi) }) } @@ -730,8 +741,9 @@ func Test1826(t *testing.T) { m := mod.(*wasm.ModuleInstance) _, err = m.ExportedFunction("3").Call(ctx, 0, 0) require.NoError(t, err) - require.Equal(t, uint64(1608723901141126568), m.Globals[0].Val) - require.Equal(t, uint64(0), m.Globals[0].ValHi) + lo, hi := m.Globals[0].Value() + require.Equal(t, uint64(1608723901141126568), lo) + require.Equal(t, uint64(0), hi) }) } @@ -745,7 +757,8 @@ func Test1846(t *testing.T) { m := mod.(*wasm.ModuleInstance) _, err = m.ExportedFunction("").Call(ctx) require.NoError(t, err) - require.Equal(t, math.Float64bits(2), m.Globals[0].Val) - require.Equal(t, uint64(0), m.Globals[0].ValHi) + lo, hi := m.Globals[0].Value() + require.Equal(t, math.Float64bits(2), lo) + require.Equal(t, uint64(0), hi) }) } diff --git a/internal/wasm/engine.go b/internal/wasm/engine.go index 3d483807e4..c2f82efccc 100644 --- a/internal/wasm/engine.go +++ b/internal/wasm/engine.go @@ -54,6 +54,14 @@ type ModuleEngine interface { // LookupFunction returns the FunctionModule and the Index of the function in the returned ModuleInstance at the given offset in the table. LookupFunction(t *TableInstance, typeId FunctionTypeID, tableOffset Index) (*ModuleInstance, Index) + // GetGlobalValue returns the value of the global variable at the given Index. + // Only called when OwnsGlobals() returns true, and must not be called for imported globals + GetGlobalValue(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 + // FunctionInstanceReference returns Reference for the given Index for a FunctionInstance. The returned values are used by // the initialization via ElementSegment. FunctionInstanceReference(funcIndex Index) Reference diff --git a/internal/wasm/global.go b/internal/wasm/global.go index 6320e0dea4..f28f46ed4f 100644 --- a/internal/wasm/global.go +++ b/internal/wasm/global.go @@ -18,7 +18,8 @@ func (g constantGlobal) Type() api.ValueType { // Get implements api.Global. func (g constantGlobal) Get() uint64 { - return g.g.Val + ret, _ := g.g.Value() + return ret } // String implements api.Global. @@ -39,7 +40,8 @@ func (g mutableGlobal) Type() api.ValueType { // Get implements api.Global. func (g mutableGlobal) Get() uint64 { - return g.g.Val + ret, _ := g.g.Value() + return ret } // String implements api.Global. @@ -51,6 +53,3 @@ func (g mutableGlobal) String() string { func (g mutableGlobal) Set(v uint64) { g.g.Val = v } - -// compile-time check to ensure mutableGlobal is a api.Global. -var _ api.Global = mutableGlobal{} diff --git a/internal/wasm/module.go b/internal/wasm/module.go index 7c363b2f35..a5aaf6adfb 100644 --- a/internal/wasm/module.go +++ b/internal/wasm/module.go @@ -611,9 +611,16 @@ func (m *Module) validateDataCountSection() (err error) { func (m *ModuleInstance) buildGlobals(module *Module, funcRefResolver func(funcIndex Index) Reference) { importedGlobals := m.Globals[:module.ImportGlobalCount] + + me := m.Engine + engineOwnGlobal := me.OwnsGlobals() for i := Index(0); i < Index(len(module.GlobalSection)); i++ { gs := &module.GlobalSection[i] g := &GlobalInstance{} + if engineOwnGlobal { + g.Me = me + g.Index = i + module.ImportGlobalCount + } m.Globals[i+module.ImportGlobalCount] = g g.Type = gs.Type g.initialize(importedGlobals, &gs.Init, funcRefResolver) diff --git a/internal/wasm/module_test.go b/internal/wasm/module_test.go index a3f5dab404..6d8efe26ac 100644 --- a/internal/wasm/module_test.go +++ b/internal/wasm/module_test.go @@ -811,6 +811,7 @@ func TestModule_buildGlobals(t *testing.T) { mi := &ModuleInstance{ Globals: make([]*GlobalInstance, m.ImportGlobalCount+uint32(len(m.GlobalSection))), + Engine: &mockModuleEngine{}, } mi.Globals[0], mi.Globals[1] = imported[0], imported[1] diff --git a/internal/wasm/store.go b/internal/wasm/store.go index f15c19fcc4..e6ae75ccac 100644 --- a/internal/wasm/store.go +++ b/internal/wasm/store.go @@ -138,9 +138,16 @@ type ( GlobalInstance struct { Type GlobalType // Val holds a 64-bit representation of the actual value. + // If me is non-nil, the value will not be updated and the current value is stored in the module engine. Val uint64 // ValHi is only used for vector type globals, and holds the higher bits of the vector. + // If me is non-nil, the value will not be updated and the current value is stored in the module engine. ValHi uint64 + // Me is the module engine that owns this global instance. + // The .Val and .ValHi fields are only valid when me is nil. + // If me is non-nil, the value is stored in the module engine. + Me ModuleEngine + Index Index } // FunctionTypeID is a uniquely assigned integer for a function type. @@ -572,6 +579,13 @@ func (g *GlobalInstance) String() string { } } +func (g *GlobalInstance) Value() (uint64, uint64) { + if g.Me != nil { + return g.Me.GetGlobalValue(g.Index) + } + return g.Val, g.ValHi +} + func (s *Store) GetFunctionTypeIDs(ts []FunctionType) ([]FunctionTypeID, error) { ret := make([]FunctionTypeID, len(ts)) for i := range ts { diff --git a/internal/wasm/store_test.go b/internal/wasm/store_test.go index 00b418f048..41fc4f1718 100644 --- a/internal/wasm/store_test.go +++ b/internal/wasm/store_test.go @@ -463,7 +463,13 @@ func (e *mockEngine) NewModuleEngine(_ *Module, _ *ModuleInstance) (ModuleEngine return &mockModuleEngine{callFailIndex: e.callFailIndex, resolveImportsCalled: map[Index]Index{}}, nil } -// mockModuleEngine implements the same method as documented on wasm.ModuleEngine. +// GetGlobalValue implements the same method as documented on wasm.ModuleEngine. +func (e *mockModuleEngine) GetGlobalValue(idx Index) (lo, hi uint64) { panic("BUG") } + +// OwnsGlobals implements the same method as documented on wasm.ModuleEngine. +func (e *mockModuleEngine) OwnsGlobals() bool { return false } + +// DoneInstantiation implements the same method as documented on wasm.ModuleEngine. func (e *mockModuleEngine) DoneInstantiation() {} // FunctionInstanceReference implements the same method as documented on wasm.ModuleEngine.