Skip to content

Commit

Permalink
Implement Go language binding (#1196)
Browse files Browse the repository at this point in the history
Implement Go binding APIs of runtime, module and instance
Add sample, build scripts and update the document

Co-authored-by: venus-taibai <[email protected]>
  • Loading branch information
wenyongh and venus-taibai authored Jun 1, 2022
1 parent 3d34a91 commit 5b1dcf2
Show file tree
Hide file tree
Showing 25 changed files with 1,482 additions and 9 deletions.
104 changes: 97 additions & 7 deletions core/iwasm/common/wasm_runtime_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ wasm_runtime_register_module_internal(const char *module_name,
WASMModuleCommon *module,
uint8 *orig_file_buf,
uint32 orig_file_buf_size,
char *error_buf, uint32_t error_buf_size)
char *error_buf, uint32 error_buf_size)
{
WASMRegisteredModule *node = NULL;

Expand Down Expand Up @@ -500,7 +500,7 @@ wasm_runtime_register_module_internal(const char *module_name,

bool
wasm_runtime_register_module(const char *module_name, WASMModuleCommon *module,
char *error_buf, uint32_t error_buf_size)
char *error_buf, uint32 error_buf_size)
{
if (!error_buf || !error_buf_size) {
LOG_ERROR("error buffer is required");
Expand Down Expand Up @@ -823,7 +823,7 @@ wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf,

WASMModuleCommon *
wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot,
char *error_buf, uint32_t error_buf_size)
char *error_buf, uint32 error_buf_size)
{
WASMModuleCommon *module_common;

Expand Down Expand Up @@ -980,6 +980,23 @@ wasm_runtime_destroy_thread_env(void)
#endif
}

bool
wasm_runtime_thread_env_inited(void)
{
#ifdef BH_PLATFORM_WINDOWS
if (!os_thread_env_inited())
return false;
#endif

#if WASM_ENABLE_AOT != 0
#ifdef OS_ENABLE_HW_BOUND_CHECK
if (!os_thread_signal_inited())
return false;
#endif
#endif
return true;
}

#if (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_MEMORY_TRACING != 0)
void
wasm_runtime_dump_module_mem_consumption(const WASMModuleCommon *module)
Expand Down Expand Up @@ -1222,8 +1239,81 @@ wasm_runtime_lookup_function(WASMModuleInstanceCommon *const module_inst,
return NULL;
}

uint32
wasm_func_get_param_count(WASMFunctionInstanceCommon *const func_inst,
WASMModuleInstanceCommon *const module_inst)
{
WASMType *type =
wasm_runtime_get_function_type(func_inst, module_inst->module_type);
return type->param_count;
}

uint32
wasm_func_get_result_count(WASMFunctionInstanceCommon *const func_inst,
WASMModuleInstanceCommon *const module_inst)
{
WASMType *type =
wasm_runtime_get_function_type(func_inst, module_inst->module_type);
return type->result_count;
}

static uint8
val_type_to_val_kind(uint8 value_type)
{
switch (value_type) {
case VALUE_TYPE_I32:
return WASM_I32;
case VALUE_TYPE_I64:
return WASM_I64;
case VALUE_TYPE_F32:
return WASM_F32;
case VALUE_TYPE_F64:
return WASM_F64;
case VALUE_TYPE_FUNCREF:
return WASM_FUNCREF;
case VALUE_TYPE_EXTERNREF:
return WASM_ANYREF;
default:
#if WASM_ENABLE_GC != 0
if (wasm_is_type_reftype(value_type))
return WASM_ANYREF;
#endif
bh_assert(0);
return 0;
}
}

void
wasm_func_get_param_types(WASMFunctionInstanceCommon *const func_inst,
WASMModuleInstanceCommon *const module_inst,
wasm_valkind_t *param_types)
{
WASMType *type =
wasm_runtime_get_function_type(func_inst, module_inst->module_type);
uint32 i;

for (i = 0; i < type->param_count; i++) {
param_types[i] = val_type_to_val_kind(type->types[i]);
}
}

void
wasm_func_get_result_types(WASMFunctionInstanceCommon *const func_inst,
WASMModuleInstanceCommon *const module_inst,
wasm_valkind_t *result_types)
{
WASMType *type =
wasm_runtime_get_function_type(func_inst, module_inst->module_type);
uint32 i;

for (i = 0; i < type->result_count; i++) {
result_types[i] =
val_type_to_val_kind(type->types[type->param_count + i]);
}
}

#if WASM_ENABLE_REF_TYPES != 0
/* (uintptr_t)externref -> (uint32_t)index */
/* (uintptr_t)externref -> (uint32)index */
/* argv -> *ret_argv */
static bool
wasm_runtime_prepare_call_function(WASMExecEnv *exec_env,
Expand Down Expand Up @@ -1321,7 +1411,7 @@ wasm_runtime_prepare_call_function(WASMExecEnv *exec_env,
return true;
}

/* (uintptr_t)externref <- (uint32_t)index */
/* (uintptr_t)externref <- (uint32)index */
/* argv <- new_argv */
static bool
wasm_runtime_finalize_call_function(WASMExecEnv *exec_env,
Expand Down Expand Up @@ -3952,8 +4042,8 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
|| defined(BUILD_TARGET_RISCV64_LP64) */

bool
wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32_t element_indices,
uint32_t argc, uint32_t argv[])
wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices,
uint32 argc, uint32 argv[])
{
if (!wasm_runtime_exec_env_check(exec_env)) {
LOG_ERROR("Invalid exec env stack info.");
Expand Down
22 changes: 22 additions & 0 deletions core/iwasm/common/wasm_runtime_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,28 @@ WASMType *
wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function,
uint32 module_type);

/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN uint32
wasm_func_get_param_count(WASMFunctionInstanceCommon *const func_inst,
WASMModuleInstanceCommon *const module_inst);

/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN uint32
wasm_func_get_result_count(WASMFunctionInstanceCommon *const func_inst,
WASMModuleInstanceCommon *const module_inst);

/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN void
wasm_func_get_param_types(WASMFunctionInstanceCommon *const func_inst,
WASMModuleInstanceCommon *const module_inst,
wasm_valkind_t *param_types);

/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN void
wasm_func_get_result_types(WASMFunctionInstanceCommon *const func_inst,
WASMModuleInstanceCommon *const module_inst,
wasm_valkind_t *result_types);

/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN WASMExecEnv *
wasm_runtime_create_exec_env(WASMModuleInstanceCommon *module_inst,
Expand Down
58 changes: 56 additions & 2 deletions core/iwasm/include/wasm_export.h
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,54 @@ WASM_RUNTIME_API_EXTERN wasm_function_inst_t
wasm_runtime_lookup_function(wasm_module_inst_t const module_inst,
const char *name, const char *signature);

/**
* Get parameter count of the function instance
*
* @param func_inst the function instance
* @param module_inst the module instance the function instance belongs to
*
* @return the parameter count of the function instance
*/
WASM_RUNTIME_API_EXTERN uint32_t
wasm_func_get_param_count(wasm_function_inst_t const func_inst,
wasm_module_inst_t const module_inst);

/**
* Get result count of the function instance
*
* @param func_inst the function instance
* @param module_inst the module instance the function instance belongs to
*
* @return the result count of the function instance
*/
WASM_RUNTIME_API_EXTERN uint32_t
wasm_func_get_result_count(wasm_function_inst_t const func_inst,
wasm_module_inst_t const module_inst);

/**
* Get parameter types of the function instance
*
* @param func_inst the function instance
* @param module_inst the module instance the function instance belongs to
* @param param_types the parameter types returned
*/
WASM_RUNTIME_API_EXTERN void
wasm_func_get_param_types(wasm_function_inst_t const func_inst,
wasm_module_inst_t const module_inst,
wasm_valkind_t *param_types);

/**
* Get result types of the function instance
*
* @param func_inst the function instance
* @param module_inst the module instance the function instance belongs to
* @param result_types the result types returned
*/
WASM_RUNTIME_API_EXTERN void
wasm_func_get_result_types(wasm_function_inst_t const func_inst,
wasm_module_inst_t const module_inst,
wasm_valkind_t *result_types);

/**
* Create execution environment for a WASM module instance.
*
Expand Down Expand Up @@ -449,7 +497,7 @@ WASM_RUNTIME_API_EXTERN uint32_t
wasm_runtime_start_debug_instance(wasm_exec_env_t exec_env);

/**
* Initialize thread environment.
* Initialize the thread environment.
* Note:
* If developer creates a child thread by himself to call the
* the wasm function in that thread, he should call this API
Expand All @@ -464,11 +512,17 @@ WASM_RUNTIME_API_EXTERN bool
wasm_runtime_init_thread_env(void);

/**
* Destroy thread environment
* Destroy the thread environment
*/
WASM_RUNTIME_API_EXTERN void
wasm_runtime_destroy_thread_env(void);

/**
* Whether the thread environment is initialized
*/
WASM_RUNTIME_API_EXTERN bool
wasm_runtime_thread_env_inited(void);

/**
* Get WASM module instance from execution environment
*
Expand Down
6 changes: 6 additions & 0 deletions core/shared/platform/include/platform_api_extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ os_thread_env_init();
void
os_thread_env_destroy();

/**
* Whether the thread environment is initialized
*/
bool
os_thread_env_inited();

/**
* Suspend execution of the calling thread for (at least)
* usec microseconds
Expand Down
7 changes: 7 additions & 0 deletions core/shared/platform/windows/win_thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,13 @@ os_thread_env_destroy()
}
}

bool
os_thread_env_inited()
{
os_thread_data *thread_data = TlsGetValue(thread_data_key);
return thread_data ? true : false;
}

int
os_sem_init(korp_sem *sem)
{
Expand Down
104 changes: 104 additions & 0 deletions language-bindings/go/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
WAMR Go binding: Embedding WAMR in Go guideline
===============================================

This Go library uses CGO to consume the runtime APIs of the WAMR project which are defined in [core/iwasm/include/wasm_export.h](../../core/iwasm/include/wasm_export.h). The API details are available in the header files.

## Installation

### Installing from the source code

Installing from local source tree is in _development mode_.

Run `./build.sh` in this folder to build the package, which builds the WAMR runtime library firstly and then builds the Go binding library.

Run `./build.sh` under `samples` folder to build and test the sample.

```bash
cd samples
./build.sh
```

## Supported APIs

All the embedding APIs supported are defined under folder [wamr](./wamr).

### Runtime APIs

```Go
func Runtime() *_Runtime
func (self *_Runtime) FullInit(alloc_with_pool bool, heap_buf []byte,
max_thread_num uint) error
func (self *_Runtime) Init() error
func (self *_Runtime) Destroy()
func (self *_Runtime) SetLogLevel(level LogLevel)
func (self *_Runtime) Malloc(size uint32) *uint8
func (self *_Runtime) Free(ptr *uint8)
```

### Module APIs

```Go
func NewModule(wasmBytes []byte) (*Module, error)
func (self *Module) Destroy()
func (self *Module) SetWasiArgs(dirList [][]byte, mapDirList [][]byte,
env [][]byte, argv[][]byte)
func (self *Module) SetWasiArgsEx(dirList [][]byte, mapDirList [][]byte,
env [][]byte, argv[][]byte,
stdinfd int, stdoutfd int, stderrfd int)
func (self *Module) SetWasiAddrPool(addrPool [][]byte)
```

### Instance APIs

```Go
func NewInstance(module *Module,
stackSize uint, heapSize uint) (*Instance, error)
func (self *Instance) Destroy()
func (self *Instance) CallFunc(funcName string,
argc uint32, args []uint32) error
func (self *Instance) CallFuncV(funcName string,
num_results uint32, results []interface{},
args ... interface{}) error
func (self *Instance) GetException() string
func (self Instance) ModuleMalloc(size uint32) (uint32, *uint8)
func (self Instance) ModuleFree(offset uint32)
func (self Instance) ValidateAppAddr(app_offset uint32, size uint32) bool
func (self Instance) ValidateNativeAddr(native_ptr *uint8, size uint32) bool
func (self Instance) AddrAppToNative(app_offset uint32) *uint8
func (self Instance) AddrNativeToApp(native_ptr *uint8) uint32
func (self Instance) GetAppAddrRange(app_offset uint32) (bool, uint32, uint32)
func (self Instance) GetNativeAddrRange(native_ptr *uint8) (bool, *uint8, *uint8)
func (self Instance) DumpMemoryConsumption()
func (self Instance) DumpCallStack()
```

## Sample codes

```Go
var module *wamr.Module
var instance *wamr.Instance
var results []interface{}
var err error

/* Runtime initialization */
err = wamr.Runtime().FullInit(false, nil, 1)

/* Read WASM/AOT file into a memory buffer */
wasmBytes := read_wasm_binary_to_buffer(...)

/* Load WASM/AOT module from the memory buffer */
module, err = wamr.NewModule(wasmBytes)

/* Create WASM/AOT instance from the module */
instance, err = wamr.NewInstance(module, 16384, 16384)

/* Call the `fib` function */
results = make([]interface{}, 1, 1)
err = instance.CallFuncV("fib", 1, results, (int32)32)
fmt.Printf("fib(32) return: %d\n", results[0].(int32));

/* Destroy runtime */
wamr.Runtime().Destroy()
```

More samples can be found in [test.go](./samples/test.go)
Loading

0 comments on commit 5b1dcf2

Please sign in to comment.