-
Notifications
You must be signed in to change notification settings - Fork 161
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
Begin adding WASI support #72
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,9 +24,11 @@ type cWasmerImportDescriptorsT C.wasmer_import_descriptors_t | |
type cWasmerImportExportKind C.wasmer_import_export_kind | ||
type cWasmerImportExportValue C.wasmer_import_export_value | ||
type cWasmerImportFuncT C.wasmer_import_func_t | ||
type cWasmerImportObjectT C.wasmer_import_object_t | ||
type cWasmerImportT C.wasmer_import_t | ||
type cWasmerInstanceContextT C.wasmer_instance_context_t | ||
type cWasmerInstanceT C.wasmer_instance_t | ||
type cWasmerWasiMapDirEntryT C.wasmer_wasi_map_dir_entry_t | ||
type cWasmerMemoryT C.wasmer_memory_t | ||
type cWasmerModuleT C.wasmer_module_t | ||
type cWasmerResultT C.wasmer_result_t | ||
|
@@ -56,6 +58,109 @@ func cNewWasmerImportT(moduleName string, importName string, function *cWasmerIm | |
return (cWasmerImportT)(importedFunction) | ||
} | ||
|
||
func cGetParamsForImportFunc(function *cWasmerImportFuncT) []cWasmerValueTag { | ||
var arity C.uint32_t = 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
var result = C.wasmer_import_func_params_arity((*C.wasmer_import_func_t)(function), &arity) | ||
|
||
if result != C.WASMER_OK { | ||
return nil | ||
} | ||
|
||
var params = make([]cWasmerValueTag, (int)(arity)) | ||
if arity == 0 { | ||
return params | ||
} | ||
|
||
result = C.wasmer_import_func_params( | ||
(*C.wasmer_import_func_t)(function), | ||
(*C.wasmer_value_tag)(unsafe.Pointer(¶ms[0])), | ||
arity) | ||
if result != C.WASMER_OK { | ||
return nil | ||
} | ||
|
||
return params | ||
} | ||
|
||
func cGetReturnsForImportFunc(function *cWasmerImportFuncT) []cWasmerValueTag { | ||
var arity C.uint32_t = 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
var result = C.wasmer_import_func_returns_arity((*C.wasmer_import_func_t)(function), &arity) | ||
|
||
if result != C.WASMER_OK { | ||
return nil | ||
} | ||
|
||
var returns = make([]cWasmerValueTag, (int)(arity)) | ||
if arity == 0 { | ||
return returns | ||
} | ||
|
||
result = C.wasmer_import_func_returns( | ||
(*C.wasmer_import_func_t)(function), | ||
(*C.wasmer_value_tag)(unsafe.Pointer(&returns[0])), | ||
arity) | ||
if result != C.WASMER_OK { | ||
return nil | ||
} | ||
|
||
return returns | ||
} | ||
|
||
func cNewWasmerDefaultWasiImportObject() *cWasmerImportObjectT { | ||
return (*cWasmerImportObjectT)(C.wasmer_wasi_generate_default_import_object()) | ||
} | ||
|
||
func cNewWasmerWasiImportObject( | ||
args *cWasmerByteArray, argsLen int, | ||
envs *cWasmerByteArray, envsLen int, | ||
preopenedFiles *cWasmerByteArray, preopenFilesLen int, | ||
mappedDirs *cWasmerWasiMapDirEntryT, mappedDirsLen int, | ||
) *cWasmerImportObjectT { | ||
return (*cWasmerImportObjectT)(C.wasmer_wasi_generate_import_object( | ||
(*C.wasmer_byte_array)(args), (C.uint)(argsLen), | ||
(*C.wasmer_byte_array)(envs), (C.uint)(envsLen), | ||
(*C.wasmer_byte_array)(preopenedFiles), (C.uint)(preopenFilesLen), | ||
(*C.wasmer_wasi_map_dir_entry_t)(mappedDirs), (C.uint)(mappedDirsLen), | ||
)) | ||
} | ||
|
||
func cWasmerImportObjectDestroy(importObject *cWasmerImportObjectT) { | ||
C.wasmer_import_object_destroy((*C.wasmer_import_object_t)(importObject)) | ||
} | ||
|
||
func cWasmerImportObjectExtend(importObject *cWasmerImportObjectT, imports *cWasmerImportT, importLen cUint) cWasmerResultT { | ||
return (cWasmerResultT)(C.wasmer_import_object_extend((*C.wasmer_import_object_t)(importObject), | ||
(*C.wasmer_import_t)(imports), | ||
(C.uint)(importLen), | ||
)) | ||
} | ||
|
||
func cNewWasmerImportObject() *cWasmerImportObjectT { | ||
return (*cWasmerImportObjectT)(C.wasmer_import_object_new()) | ||
} | ||
|
||
func cWasmerImportObjectGetFunctions(importObject *cWasmerImportObjectT) []cWasmerImportT { | ||
var iter = C.wasmer_import_object_iterate_functions((*C.wasmer_import_object_t)(importObject)) | ||
if iter == nil { | ||
return nil | ||
} | ||
var imports []cWasmerImportT | ||
|
||
for !C.wasmer_import_object_iter_at_end(iter) { | ||
var imp cWasmerImportT | ||
result := C.wasmer_import_object_iter_next(iter, (*C.wasmer_import_t)(&imp)) | ||
if result != C.WASMER_OK { | ||
C.wasmer_import_object_imports_destroy((*C.wasmer_import_t)(&imports[0]), (C.uint)(len(imports))) | ||
C.wasmer_import_object_iter_destroy(iter) | ||
return nil | ||
break | ||
} | ||
imports = append(imports, imp) | ||
} | ||
|
||
return imports | ||
} | ||
|
||
func cWasmerCompile(module **cWasmerModuleT, wasmBytes *cUchar, wasmBytesLength cUint) cWasmerResultT { | ||
return (cWasmerResultT)(C.wasmer_compile( | ||
(**C.wasmer_module_t)(unsafe.Pointer(module)), | ||
|
@@ -342,6 +447,18 @@ func cWasmerModuleDestroy(module *cWasmerModuleT) { | |
C.wasmer_module_destroy((*C.wasmer_module_t)(module)) | ||
} | ||
|
||
func cWasmerModuleImportInstantiate( | ||
instance **cWasmerInstanceT, | ||
module *cWasmerModuleT, | ||
importObject *cWasmerImportObjectT, | ||
) cWasmerResultT { | ||
return (cWasmerResultT)(C.wasmer_module_import_instantiate( | ||
(**C.wasmer_instance_t)(unsafe.Pointer(instance)), | ||
(*C.wasmer_module_t)(module), | ||
(*C.wasmer_import_object_t)(importObject), | ||
)) | ||
} | ||
|
||
func cWasmerModuleInstantiate( | ||
module *cWasmerModuleT, | ||
instance **cWasmerInstanceT, | ||
|
@@ -421,3 +538,34 @@ func cGoStringToWasmerByteArray(string string) cWasmerByteArray { | |
|
||
return byteArray | ||
} | ||
|
||
func cAliasAndHostPathToWasiDirEntry(alias string, hostPath string) cWasmerWasiMapDirEntryT { | ||
var wasiMappedDir cWasmerWasiMapDirEntryT | ||
wasiMappedDir.alias = (C.wasmer_byte_array)(cGoStringToWasmerByteArray(alias)) | ||
wasiMappedDir.host_file_path = (C.wasmer_byte_array)(cGoStringToWasmerByteArray(hostPath)) | ||
|
||
return wasiMappedDir | ||
} | ||
|
||
// returns the module name and import name for a given import | ||
func cGetInfoFromImport(inner *cWasmerImportT) (string, string) { | ||
moduleName := string(C.GoBytes( | ||
unsafe.Pointer(inner.module_name.bytes), | ||
(C.int)(inner.module_name.bytes_len))) | ||
importName := string(C.GoBytes( | ||
unsafe.Pointer(inner.import_name.bytes), | ||
(C.int)(inner.import_name.bytes_len))) | ||
|
||
return moduleName, importName | ||
} | ||
|
||
// returns the raw pointer to the inner function or nil if it's not a function | ||
func cGetFunctionFromImport(inner *cWasmerImportT) *cWasmerImportFuncT { | ||
if inner.tag == C.WASM_FUNCTION { | ||
var funcPtrBytes [8]byte = inner.value | ||
var funcPtrAddr *byte = &funcPtrBytes[0] | ||
var funcPtrPtr = (**cWasmerImportFuncT)(unsafe.Pointer(funcPtrAddr)) | ||
return *funcPtrPtr | ||
} | ||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,90 @@ type ImportedFunctionError struct { | |
message string | ||
} | ||
|
||
// ImportObjectError represents errors related to `ImportObject`s | ||
type ImportObjectError struct { | ||
message string | ||
} | ||
|
||
// A type that owns a set of imports. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Documentation must start by the name of the type or the name of the function. So it becomes:
It's a Go rule. |
||
// It can be combined with a `Module` to create an `Instance` | ||
type ImportObject struct { | ||
inner *cWasmerImportObjectT | ||
} | ||
|
||
// Creates an empty `ImportObject` | ||
func NewImportObject() *ImportObject { | ||
var inner = cNewWasmerImportObject() | ||
|
||
return &ImportObject{inner} | ||
} | ||
|
||
// Returns `*Imports` for a given `ImportObject` | ||
func (importObject *ImportObject) GetImports() (*Imports, error) { | ||
imports := cWasmerImportObjectGetFunctions(importObject.inner) | ||
if imports == nil { | ||
return nil, NewImportObjectError("Could not get functions from import object") | ||
} | ||
outImports := NewImports() | ||
for _, imp := range imports { | ||
rawFunc := cGetFunctionFromImport(&imp) | ||
if rawFunc == nil { | ||
// this should never happen | ||
continue | ||
} | ||
namespaceName, importName := cGetInfoFromImport(&imp) | ||
|
||
oi, err := outImports.appendRaw(namespaceName, importName, rawFunc) | ||
if err != nil { | ||
return nil, err | ||
} | ||
outImports = oi | ||
} | ||
|
||
return outImports, nil | ||
} | ||
|
||
// Adds the given imports to the exsiting import object | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. - exsiting
+ existing |
||
func (importObject *ImportObject) Extend(imports Imports) error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think to turn this API to: func (importObject *ImportObject) Extend(incomingImportObject ImportObject) error; It will help to slowly deprecate the |
||
var numberOfImports = len(imports.imports) | ||
if numberOfImports == 0 { | ||
return nil | ||
} | ||
var cImports = make([]cWasmerImportT, numberOfImports) | ||
var importFunctionNth = 0 | ||
|
||
for importName, importFunction := range imports.imports { | ||
cImports[importFunctionNth] = *getCWasmerImport(importName, importFunction) | ||
importFunctionNth++ | ||
} | ||
|
||
var extendResult = cWasmerImportObjectExtend(importObject.inner, | ||
(*cWasmerImportT)(unsafe.Pointer(&cImports[0])), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We must check that |
||
(cUint)(len(imports.imports))) | ||
|
||
if extendResult != cWasmerOk { | ||
return NewImportObjectError("Could not extend import object with the given imports") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Frees the `ImportObject` | ||
func (importObject *ImportObject) Close() { | ||
cWasmerImportObjectDestroy(importObject.inner) | ||
} | ||
|
||
// Constructs a new `ImportObjectError` | ||
func NewImportObjectError(message string) *ImportObjectError { | ||
return &ImportObjectError{message} | ||
} | ||
|
||
// ImportedFunctionError is an actual error. The `Error` function | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. - ImportedFunctionError
+ ImportObjectError |
||
// returns the error message. | ||
func (error *ImportObjectError) Error() string { | ||
return fmt.Sprintf(error.message) | ||
} | ||
|
||
// NewImportedFunctionError constructs a new `ImportedFunctionError`, | ||
// where `functionName` is the name of the imported function, and | ||
// `message` is the error message. If the error message contains `%s`, | ||
|
@@ -148,6 +232,29 @@ func (imports *Imports) Append(importName string, implementation interface{}, cg | |
return imports, nil | ||
} | ||
|
||
// Like Append but not for Go imports | ||
func (imports *Imports) appendRaw(namespace string, importName string, wasmerImportFunc *cWasmerImportFuncT) (*Imports, error) { | ||
params := cGetParamsForImportFunc(wasmerImportFunc) | ||
if params == nil { | ||
return imports, NewImportedFunctionError(importName, fmt.Sprintf("could not get parameters for %s %s", namespace, importName)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
fmt.Sprintf("Could not get parameters for `%%s` in namespace `%s`", namespace) |
||
} | ||
returns := cGetParamsForImportFunc(wasmerImportFunc) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Aren't we suppose to use |
||
if returns == nil { | ||
return imports, NewImportedFunctionError(importName, fmt.Sprintf("could not get returns for %s %s", namespace, importName)) | ||
} | ||
|
||
imports.imports[importName] = Import{ | ||
nil, | ||
unsafe.Pointer(wasmerImportFunc), | ||
wasmerImportFunc, | ||
params, | ||
returns, | ||
namespace, | ||
} | ||
|
||
return imports, nil | ||
} | ||
|
||
// Close closes/frees all imported functions that have been registered by Wasmer. | ||
func (imports *Imports) Close() { | ||
for _, importFunction := range imports.imports { | ||
|
@@ -157,6 +264,38 @@ func (imports *Imports) Close() { | |
} | ||
} | ||
|
||
// Helper function: Get a C import for a given import | ||
func getCWasmerImport(importName string, importFunction Import) *cWasmerImportT { | ||
var wasmInputsArity = len(importFunction.wasmInputs) | ||
var wasmOutputsArity = len(importFunction.wasmOutputs) | ||
|
||
var importFunctionInputsCPointer *cWasmerValueTag | ||
var importFunctionOutputsCPointer *cWasmerValueTag | ||
|
||
if wasmInputsArity > 0 { | ||
importFunctionInputsCPointer = (*cWasmerValueTag)(unsafe.Pointer(&importFunction.wasmInputs[0])) | ||
} | ||
|
||
if wasmOutputsArity > 0 { | ||
importFunctionOutputsCPointer = (*cWasmerValueTag)(unsafe.Pointer(&importFunction.wasmOutputs[0])) | ||
} | ||
|
||
importFunction.importedFunctionPointer = cWasmerImportFuncNew( | ||
importFunction.cgoPointer, | ||
importFunctionInputsCPointer, | ||
cUint(wasmInputsArity), | ||
importFunctionOutputsCPointer, | ||
cUint(wasmOutputsArity), | ||
) | ||
var newImport = cNewWasmerImportT( | ||
importFunction.namespace, | ||
importName, | ||
importFunction.importedFunctionPointer, | ||
) | ||
|
||
return &newImport | ||
} | ||
|
||
// InstanceContext represents a way to access instance API from within | ||
// an imported context. | ||
type InstanceContext struct { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can just require wasmer 0.11.0, which has
wasi
as a default feature.