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

Bind new support for tables #12

Merged
merged 1 commit into from
May 14, 2020
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
89 changes: 87 additions & 2 deletions table.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,38 @@
package wasmtime

// #include <wasm.h>
// #include <wasmtime.h>
import "C"
import "runtime"
import (
"errors"
"runtime"
)

type Table struct {
_ptr *C.wasm_table_t
_owner interface{}
freelist *freeList
}

// Creates a new `Table` in the given `Store` with the specified `ty`.
//
// The `ty` must be a `funcref` table and `init` is the initial value for all
// table slots, and is allowed to be `nil`.
func NewTable(store *Store, ty *TableType, init *Func) (*Table, error) {
var init_ptr *C.wasm_func_t
if init != nil {
init_ptr = init.ptr()
}
var ptr *C.wasm_table_t
err := C.wasmtime_funcref_table_new(store.ptr(), ty.ptr(), init_ptr, &ptr)
runtime.KeepAlive(store)
runtime.KeepAlive(ty)
runtime.KeepAlive(init)
if err != nil {
return nil, mkError(err)
}
return mkTable(ptr, store.freelist, nil), nil
}

func mkTable(ptr *C.wasm_table_t, freelist *freeList, owner interface{}) *Table {
f := &Table{_ptr: ptr, _owner: owner, freelist: freelist}
if owner == nil {
Expand All @@ -35,12 +58,74 @@ func (t *Table) owner() interface{} {
return t
}

// Returns the size of this table in units of elements.
func (t *Table) Size() uint32 {
ret := C.wasm_table_size(t.ptr())
runtime.KeepAlive(t)
return uint32(ret)
}

// Grows this funcref table by the number of units specified, using the
// specified initializer value for new slots.
//
// Note that `init` is allowed to be `nil`.
//
// Returns an error if the table failed to grow, or the previous size of the
// table if growth was successful.
func (t *Table) Grow(delta uint32, init *Func) (uint32, error) {
var init_ptr *C.wasm_func_t
if init != nil {
init_ptr = init.ptr()
}
var prev C.uint32_t
err := C.wasmtime_funcref_table_grow(t.ptr(), C.uint32_t(delta), init_ptr, &prev)
runtime.KeepAlive(t)
runtime.KeepAlive(init)
if err == nil {
return uint32(prev), nil
} else {
return 0, mkError(err)
}
}

// Gets an item from this table from the specified index.
//
// Returns an error if the index is out of bounds, or returns a function (which
// may be `nil`) if the index is in bounds corresponding to the entry at the
// specified index.
func (t *Table) Get(idx uint32) (*Func, error) {
var func_ptr *C.wasm_func_t
ok := C.wasmtime_funcref_table_get(t.ptr(), C.uint32_t(idx), &func_ptr)
runtime.KeepAlive(t)
if ok {
if func_ptr == nil {
return nil, nil
}
return mkFunc(func_ptr, t.freelist, nil), nil
} else {
return nil, errors.New("index out of bounds")
}
}

// Sets an item in this table at the specified index.
//
// Returns an error if the index is out of bounds.
func (t *Table) Set(idx uint32, val *Func) error {
var func_ptr *C.wasm_func_t
if val != nil {
func_ptr = val.ptr()
}
err := C.wasmtime_funcref_table_set(t.ptr(), C.uint32_t(idx), func_ptr)
runtime.KeepAlive(t)
runtime.KeepAlive(val)
if err == nil {
return nil
} else {
return mkError(err)
}
}

// Returns the underlying type of this table
func (t *Table) Type() *TableType {
ptr := C.wasm_table_type(t.ptr())
runtime.KeepAlive(t)
Expand Down
88 changes: 88 additions & 0 deletions table_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package wasmtime

import "testing"

func TestTable(t *testing.T) {
store := NewStore(NewEngine())
ty := NewTableType(NewValType(KindFuncref), Limits{Min: 1, Max: 3})
table, err := NewTable(store, ty, nil)
if err != nil {
panic(err)
}
if table.Size() != 1 {
panic("wrong size")
}

f, err := table.Get(0)
if err != nil {
panic(err)
}
if f != nil {
panic("expected nil")
}
f, err = table.Get(1)
if err == nil {
panic("expected error")
}
if f != nil {
panic("expected nil")
}

err = table.Set(0, nil)
if err != nil {
panic(err)
}
err = table.Set(1, nil)
if err == nil {
panic("expected error")
}
err = table.Set(0, WrapFunc(store, func() {}))
if err != nil {
panic(nil)
}
f, err = table.Get(0)
if err != nil {
panic(err)
}
if f == nil {
panic("expected not nil")
}

prev_size, err := table.Grow(1, nil)
if err != nil {
panic(err)
}
if prev_size != 1 {
print(prev_size)
panic("bad prev")
}
f, err = table.Get(1)
if err != nil {
panic(err)
}
if f != nil {
panic("expected nil")
}

called := false
_, err = table.Grow(1, WrapFunc(store, func() {
called = true
}))
if err != nil {
panic(err)
}
f, err = table.Get(2)
if err != nil {
panic(err)
}
if called {
panic("called already?")
}
_, err = f.Call()
if err != nil {
panic(err)
}
if !called {
panic("should have called")
}
}