Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

engine, interp: simplify ExternalReferences implementation #14

Merged
merged 1 commit into from
Mar 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions engine/references.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,46 @@ package engine

import (
"math/rand"
"unsafe"
)

// ExternalReferences manages external references to be used by the Interpreter
// to store references that can be passed to guest modules.
type ExternalReferences struct {
refs map[int32]uintptr
refs map[int32]any
}

// NewReferences creates a new ExternalReferences store.
func NewReferences() ExternalReferences {
return ExternalReferences{
refs: make(map[int32]uintptr),
refs: make(map[int32]any),
}
}

// Add adds a reference to the ExternalReferences store and returns the new reference id.
func (r *ExternalReferences) Add(thing unsafe.Pointer) int32 {
func (r *ExternalReferences) Add(thing any) int32 {
id := r.newReferenceId()
r.refs[id] = uintptr(thing)
r.refs[id] = thing
return id
}

// Get returns the reference for the given id.
func (r *ExternalReferences) Get(id int32) uintptr {
return r.refs[id]
func (r *ExternalReferences) Get(id int32) any {
if val, ok := r.refs[id]; ok {
return val
}
return nil
}

// Remove removes the reference for the given id.
func (r *ExternalReferences) Remove(id int32) {
delete(r.refs, id)
}

// Remove removes the reference for the given id.
func (r *ExternalReferences) Clear() {
clear(r.refs)
}

// generates a random reference id that is not already in use.
func (r *ExternalReferences) newReferenceId() int32 {
for {
Expand Down
21 changes: 10 additions & 11 deletions engine/references_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package engine

import (
"testing"
"unsafe"
)

type testingType struct {
Expand All @@ -13,41 +12,41 @@ type testingType struct {
func TestExternalReferences(t *testing.T) {
refs := NewReferences()
var id1, id2 int32
thing1 := &testingType{
thing1 := testingType{
val1: "hello",
val2: "world",
}
thing2 := &testingType{
thing2 := testingType{
val1: "hola",
val2: "mundo",
}

t.Run("add references", func(t *testing.T) {
id1 = refs.Add(unsafe.Pointer(&thing1))
id2 = refs.Add(unsafe.Pointer(&thing2))
id1 = refs.Add(&thing1)
id2 = refs.Add(&thing2)

if id1 == id2 {
t.Errorf("id1 and id2 should not be the same")
}
})

t.Run("get references", func(t *testing.T) {
if refs.Get(id1) != uintptr(unsafe.Pointer(&thing1)) {
t.Errorf("refs.Get(id1) failed")
if refs.Get(id1).(*testingType).val1 != thing1.val1 {
t.Errorf("refs.Get(id1) %d failed %v %v", id1, refs.Get(id1).(*testingType).val1, thing1.val1)
}
if refs.Get(id2) != uintptr(unsafe.Pointer(&thing2)) {
t.Errorf("refs.Get(id2) failed")
if refs.Get(id2).(*testingType).val2 != thing2.val2 {
t.Errorf("refs.Get(id2) %d failed %v %v", id2, refs.Get(id2).(*testingType).val2, thing1.val2)
}
})

t.Run("remove references", func(t *testing.T) {
refs.Remove(id1)
refs.Remove(id2)

if refs.Get(id1) != uintptr(0) {
if refs.Get(id1) != nil {
t.Errorf("refs.Get(id1) failed")
}
if refs.Get(id2) != uintptr(0) {
if refs.Get(id2) != nil {
t.Errorf("refs.Get(id2) failed")
}
})
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.22.0
replace github.com/tetratelabs/wazero => github.com/orsinium-forks/wazero v0.0.0-20240217173836-b12c024bcbe4

require (
github.com/hybridgroup/wasman v0.0.0-20240229144219-f3288962ab34
github.com/hybridgroup/wasman v0.0.0-20240303155228-bc96a1c9a2cc
github.com/tetratelabs/wazero v1.6.0
github.com/urfave/cli/v2 v2.27.1
tinygo.org/x/tinyfs v0.3.1-0.20231212053859-32ae3f6bbad9
Expand Down
6 changes: 2 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/hybridgroup/wasman v0.0.0-20240228124029-ecd9fd3f900a h1:6q1Gn1MR643sBn4PnvgX40jCCXmAyjuNXFfk8wirpds=
github.com/hybridgroup/wasman v0.0.0-20240228124029-ecd9fd3f900a/go.mod h1:rLavUo4P0xVcDeDnViYEpPQPoACmp1py9UTLPY/R7Lg=
github.com/hybridgroup/wasman v0.0.0-20240229144219-f3288962ab34 h1:XGX7Qt+ylSTF7VrwfXePwXAy2cK2iB6At+Ni/PcaNok=
github.com/hybridgroup/wasman v0.0.0-20240229144219-f3288962ab34/go.mod h1:rLavUo4P0xVcDeDnViYEpPQPoACmp1py9UTLPY/R7Lg=
github.com/hybridgroup/wasman v0.0.0-20240303155228-bc96a1c9a2cc h1:Ld9ng9AdthISNNd5JYTK2HGx/shBtAWNZdz9Gu/Z25k=
github.com/hybridgroup/wasman v0.0.0-20240303155228-bc96a1c9a2cc/go.mod h1:rLavUo4P0xVcDeDnViYEpPQPoACmp1py9UTLPY/R7Lg=
github.com/orsinium-forks/wazero v0.0.0-20240217173836-b12c024bcbe4 h1:MUh9e2izck9aROiwDsDm24UU7kHieYM2911U1t+NASs=
github.com/orsinium-forks/wazero v0.0.0-20240217173836-b12c024bcbe4/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
Expand Down
21 changes: 10 additions & 11 deletions interp/tester/interp.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package tester

import (
"testing"
"unsafe"

"github.com/hybridgroup/mechanoid/engine"
)
Expand Down Expand Up @@ -71,41 +70,41 @@ func ReferencesTest(t *testing.T, i engine.Interpreter) {
}

var id1, id2 int32
thing1 := &testingType{
thing1 := testingType{
val1: "hello",
val2: "world",
}
thing2 := &testingType{
thing2 := testingType{
val1: "hola",
val2: "mundo",
}

t.Run("add references", func(t *testing.T) {
id1 = i.References().Add(unsafe.Pointer(&thing1))
id2 = i.References().Add(unsafe.Pointer(&thing2))
id1 = i.References().Add(&thing1)
id2 = i.References().Add(&thing2)

if id1 == id2 {
t.Errorf("id1 and id2 should not be the same")
}
})

t.Run("get references", func(t *testing.T) {
if i.References().Get(id1) != uintptr(unsafe.Pointer(&thing1)) {
t.Errorf("refs.Get(id1) failed")
if i.References().Get(id1).(*testingType).val1 != thing1.val1 {
t.Errorf("refs.Get(id1) %d failed %v %v", id1, i.References().Get(id1).(*testingType).val1, thing1.val1)
}
if i.References().Get(id2) != uintptr(unsafe.Pointer(&thing2)) {
t.Errorf("refs.Get(id2) failed")
if i.References().Get(id2).(*testingType).val2 != thing2.val2 {
t.Errorf("refs.Get(id2) %d failed %v %v", id2, i.References().Get(id2).(*testingType).val2, thing1.val2)
}
})

t.Run("remove references", func(t *testing.T) {
i.References().Remove(id1)
i.References().Remove(id2)

if i.References().Get(id1) != uintptr(0) {
if i.References().Get(id1) != nil {
t.Errorf("refs.Get(id1) failed")
}
if i.References().Get(id2) != uintptr(0) {
if i.References().Get(id2) != nil {
t.Errorf("refs.Get(id2) failed")
}
})
Expand Down
22 changes: 22 additions & 0 deletions interp/wasman/interp.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package wasman

import (
"runtime"

"github.com/hybridgroup/mechanoid"
"github.com/hybridgroup/mechanoid/engine"

Expand Down Expand Up @@ -57,6 +59,11 @@ func (i *Interpreter) Load(code []byte) error {
}

func (i *Interpreter) Run() (engine.Instance, error) {
ms := runtime.MemStats{}

runtime.ReadMemStats(&ms)
println("Heap start Run Used: ", ms.HeapInuse, " Free: ", ms.HeapIdle, " Meta: ", ms.GCSys)

var err error
i.instance, err = i.linker.Instantiate(i.module)
if err != nil {
Expand All @@ -75,7 +82,22 @@ func (i *Interpreter) Run() (engine.Instance, error) {
}

func (i *Interpreter) Halt() error {
ms := runtime.MemStats{}

runtime.ReadMemStats(&ms)
println("Heap start Halt Used: ", ms.HeapInuse, " Free: ", ms.HeapIdle, " Meta: ", ms.GCSys)

// clean up extern refs
i.references.Clear()
i.instance = nil
i.module = nil

// force a garbage collection to free memory
runtime.GC()

runtime.ReadMemStats(&ms)
println("Heap start Halt after gc: ", ms.HeapInuse, " Free: ", ms.HeapIdle, " Meta: ", ms.GCSys)

return nil
}

Expand Down