Skip to content

Commit

Permalink
Implement module linking proposal (#46)
Browse files Browse the repository at this point in the history
* Implement module linking proposal

This commit binds the support added in bytecodealliance/wasmtime#2472 to
bring support for the module linking to this Go extension. The support
here is similar to bytecodealliance/wasmtime-py#47, which is hooking up
modules/instances to `Extern` as well as adding dedicated
instance/module types.

* Update bazel build

* Try to fix a Windows CI issue
  • Loading branch information
X-leaf7 committed Dec 4, 2020
1 parent cd72111 commit b977304
Show file tree
Hide file tree
Showing 14 changed files with 429 additions and 51 deletions.
3 changes: 3 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@ go_library(
"globaltype.go",
"importtype.go",
"instance.go",
"instancetype.go",
"limits.go",
"linker.go",
"maybe_gc_no.go",
"memory.go",
"memorytype.go",
"module.go",
"moduletype.go",
"shims.c",
"shims.h",
"slab.go",
Expand Down Expand Up @@ -94,6 +96,7 @@ go_test(
"valtype_test.go",
"wasi_test.go",
"wasm2wat_test.go",
"module_linking_test.go",
],
embed = [":go_default_library"],
)
6 changes: 6 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ func (cfg *Config) SetWasmMultiValue(enabled bool) {
runtime.KeepAlive(cfg)
}

// SetWasmModuleLinking configures whether the wasm module linking proposal is enabled
func (cfg *Config) SetWasmModuleLinking(enabled bool) {
C.wasmtime_config_wasm_module_linking_set(cfg.ptr(), C.bool(enabled))
runtime.KeepAlive(cfg)
}

// SetStrategy configures what compilation strategy is used to compile wasm code
func (cfg *Config) SetStrategy(strat Strategy) error {
err := C.wasmtime_config_strategy_set(cfg.ptr(), C.wasmtime_strategy_t(strat))
Expand Down
22 changes: 21 additions & 1 deletion extern.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package wasmtime

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

Expand Down Expand Up @@ -91,6 +91,26 @@ func (e *Extern) Table() *Table {
return mkTable(ret, e.freelist, e.owner())
}

// Module returns a Module if this export is a module or nil otherwise
func (e *Extern) Module() *Module {
ret := C.wasm_extern_as_module(e.ptr())
if ret == nil {
return nil
}

return mkModule(ret, e.owner())
}

// Instance returns a Instance if this export is a module or nil otherwise
func (e *Extern) Instance() *Instance {
ret := C.wasm_extern_as_instance(e.ptr())
if ret == nil {
return nil
}

return mkInstance(ret, e.freelist, e.owner())
}

func (e *Extern) AsExtern() *Extern {
return e
}
12 changes: 9 additions & 3 deletions importtype.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,18 @@ func (ty *ImportType) Module() string {
return ret
}

// Name returns the name in the module this import type is importing
func (ty *ImportType) Name() string {
// Name returns the name in the module this import type is importing.
//
// Note that the returned string may be `nil` with the module linking proposal
// where this field is optional in the import type.
func (ty *ImportType) Name() *string {
ptr := C.wasm_importtype_name(ty.ptr())
if ptr == nil {
return nil
}
ret := C.GoStringN(ptr.data, C.int(ptr.size))
runtime.KeepAlive(ty)
return ret
return &ret
}

// Type returns the type of item this import type expects
Expand Down
4 changes: 2 additions & 2 deletions importtype_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ func TestImportType(t *testing.T) {
if ty.Module() != "a" {
panic("invalid module")
}
if ty.Name() != "b" {
if *ty.Name() != "b" {
panic("invalid name")
}
if ty.Type().FuncType() == nil {
Expand All @@ -20,7 +20,7 @@ func TestImportType(t *testing.T) {
if ty.Module() != "" {
panic("invalid module")
}
if ty.Name() != "" {
if *ty.Name() != "" {
panic("invalid name")
}
if ty.Type().GlobalType() == nil {
Expand Down
65 changes: 48 additions & 17 deletions instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import (
// Instance is an instantiated module instance.
// Once a module has been instantiated as an Instance, any exported function can be invoked externally via its function address funcaddr in the store S and an appropriate list val∗ of argument values.
type Instance struct {
_ptr *C.wasm_instance_t
exports map[string]*Extern
freelist *freeList
_ptr *C.wasm_instance_t
exports map[string]*Extern
exportsPopulated bool
freelist *freeList
_owner interface{}
}

// NewInstance instantiates a WebAssembly `module` with the `imports` provided.
Expand Down Expand Up @@ -52,24 +54,24 @@ func NewInstance(store *Store, module *Module, imports []*Extern) (*Instance, er
if trap != nil {
return nil, mkTrap(trap)
}
return mkInstance(ptr, store, module), nil
return mkInstance(ptr, store.freelist, nil), nil
}

func mkInstance(ptr *C.wasm_instance_t, store *Store, module *Module) *Instance {
func mkInstance(ptr *C.wasm_instance_t, freelist *freeList, owner interface{}) *Instance {
instance := &Instance{
_ptr: ptr,
exports: make(map[string]*Extern),
freelist: store.freelist,
_ptr: ptr,
exports: make(map[string]*Extern),
exportsPopulated: false,
freelist: freelist,
_owner: owner,
}
runtime.SetFinalizer(instance, func(instance *Instance) {
freelist := instance.freelist
freelist.lock.Lock()
defer freelist.lock.Unlock()
freelist.instances = append(freelist.instances, instance._ptr)
})
exports := instance.Exports()
for i, ty := range module.Exports() {
instance.exports[ty.Name()] = exports[i]
if owner == nil {
runtime.SetFinalizer(instance, func(instance *Instance) {
freelist := instance.freelist
freelist.lock.Lock()
defer freelist.lock.Unlock()
freelist.instances = append(freelist.instances, instance._ptr)
})
}
return instance
}
Expand All @@ -80,6 +82,20 @@ func (i *Instance) ptr() *C.wasm_instance_t {
return ret
}

func (i *Instance) owner() interface{} {
if i._owner != nil {
return i._owner
}
return i
}

// Type returns an `InstanceType` that corresponds for this instance.
func (i *Instance) Type() *InstanceType {
ptr := C.wasm_instance_type(i.ptr())
runtime.KeepAlive(i)
return mkInstanceType(ptr, nil)
}

type externList struct {
vec C.wasm_extern_vec_t
}
Expand Down Expand Up @@ -114,5 +130,20 @@ func (i *Instance) Exports() []*Extern {
//
// May return `nil` if this instance has no export named `name`
func (i *Instance) GetExport(name string) *Extern {
if !i.exportsPopulated {
i.populateExports()
}
return i.exports[name]
}

func (i *Instance) populateExports() {
exports := i.Exports()
for j, ty := range i.Type().Exports() {
i.exports[ty.Name()] = exports[j]
}
}

func (i *Instance) AsExtern() *Extern {
ptr := C.wasm_instance_as_extern(i.ptr())
return mkExtern(ptr, i.freelist, i.owner())
}
49 changes: 49 additions & 0 deletions instancetype.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package wasmtime

// #include <wasmtime.h>
import "C"
import "runtime"

// InstanceType describes the exports of an instance.
type InstanceType struct {
_ptr *C.wasm_instancetype_t
_owner interface{}
}

func mkInstanceType(ptr *C.wasm_instancetype_t, owner interface{}) *InstanceType {
instancetype := &InstanceType{_ptr: ptr, _owner: owner}
if owner == nil {
runtime.SetFinalizer(instancetype, func(instancetype *InstanceType) {
C.wasm_instancetype_delete(instancetype._ptr)
})
}
return instancetype
}

func (ty *InstanceType) ptr() *C.wasm_instancetype_t {
ret := ty._ptr
maybeGC()
return ret
}

func (ty *InstanceType) owner() interface{} {
if ty._owner != nil {
return ty._owner
}
return ty
}

// AsExternType converts this type to an instance of `ExternType`
func (ty *InstanceType) AsExternType() *ExternType {
ptr := C.wasm_instancetype_as_externtype_const(ty.ptr())
return mkExternType(ptr, ty.owner())
}

// Exports returns a list of `ExportType` items which are the items that will
// be exported by this instance after instantiation.
func (ty *InstanceType) Exports() []*ExportType {
exports := &exportTypeList{}
C.wasm_instancetype_exports(ty.ptr(), &exports.vec)
runtime.KeepAlive(ty)
return exports.mkGoList()
}
2 changes: 1 addition & 1 deletion linker.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,5 +124,5 @@ func (l *Linker) Instantiate(module *Module) (*Instance, error) {
if trap != nil {
return nil, mkTrap(trap)
}
return mkInstance(ret, l.Store, module), nil
return mkInstance(ret, l.Store.freelist, nil), nil
}
Loading

0 comments on commit b977304

Please sign in to comment.