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

Implement module linking proposal #46

Merged
merged 3 commits into from
Dec 4, 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
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