Skip to content

Commit

Permalink
Bind new support for tables (bytecodealliance#12)
Browse files Browse the repository at this point in the history
Binds functions added in
bytecodealliance#1654

Closes bytecodealliance#5
  • Loading branch information
alexcrichton committed May 14, 2020
1 parent 55cf565 commit 75bf9e9
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 2 deletions.
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")
}
}

0 comments on commit 75bf9e9

Please sign in to comment.