mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-07-15 16:58:34 +00:00
Merge pull request #549 from bytecodealliance/main
Merge bytecodealliance:main into wenyongh:main
This commit is contained in:
commit
e0bf46aa5c
|
@ -445,7 +445,7 @@ wasm_runtime_register_module_internal(const char *module_name,
|
||||||
WASMModuleCommon *module,
|
WASMModuleCommon *module,
|
||||||
uint8 *orig_file_buf,
|
uint8 *orig_file_buf,
|
||||||
uint32 orig_file_buf_size,
|
uint32 orig_file_buf_size,
|
||||||
char *error_buf, uint32_t error_buf_size)
|
char *error_buf, uint32 error_buf_size)
|
||||||
{
|
{
|
||||||
WASMRegisteredModule *node = NULL;
|
WASMRegisteredModule *node = NULL;
|
||||||
|
|
||||||
|
@ -500,7 +500,7 @@ wasm_runtime_register_module_internal(const char *module_name,
|
||||||
|
|
||||||
bool
|
bool
|
||||||
wasm_runtime_register_module(const char *module_name, WASMModuleCommon *module,
|
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) {
|
if (!error_buf || !error_buf_size) {
|
||||||
LOG_ERROR("error buffer is required");
|
LOG_ERROR("error buffer is required");
|
||||||
|
@ -823,7 +823,7 @@ wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf,
|
||||||
|
|
||||||
WASMModuleCommon *
|
WASMModuleCommon *
|
||||||
wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot,
|
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;
|
WASMModuleCommon *module_common;
|
||||||
|
|
||||||
|
@ -980,6 +980,23 @@ wasm_runtime_destroy_thread_env(void)
|
||||||
#endif
|
#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)
|
#if (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_MEMORY_TRACING != 0)
|
||||||
void
|
void
|
||||||
wasm_runtime_dump_module_mem_consumption(const WASMModuleCommon *module)
|
wasm_runtime_dump_module_mem_consumption(const WASMModuleCommon *module)
|
||||||
|
@ -1222,8 +1239,81 @@ wasm_runtime_lookup_function(WASMModuleInstanceCommon *const module_inst,
|
||||||
return NULL;
|
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
|
#if WASM_ENABLE_REF_TYPES != 0
|
||||||
/* (uintptr_t)externref -> (uint32_t)index */
|
/* (uintptr_t)externref -> (uint32)index */
|
||||||
/* argv -> *ret_argv */
|
/* argv -> *ret_argv */
|
||||||
static bool
|
static bool
|
||||||
wasm_runtime_prepare_call_function(WASMExecEnv *exec_env,
|
wasm_runtime_prepare_call_function(WASMExecEnv *exec_env,
|
||||||
|
@ -1321,7 +1411,7 @@ wasm_runtime_prepare_call_function(WASMExecEnv *exec_env,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (uintptr_t)externref <- (uint32_t)index */
|
/* (uintptr_t)externref <- (uint32)index */
|
||||||
/* argv <- new_argv */
|
/* argv <- new_argv */
|
||||||
static bool
|
static bool
|
||||||
wasm_runtime_finalize_call_function(WASMExecEnv *exec_env,
|
wasm_runtime_finalize_call_function(WASMExecEnv *exec_env,
|
||||||
|
@ -3952,8 +4042,8 @@ fail:
|
||||||
|| defined(BUILD_TARGET_RISCV64_LP64) */
|
|| defined(BUILD_TARGET_RISCV64_LP64) */
|
||||||
|
|
||||||
bool
|
bool
|
||||||
wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32_t element_indices,
|
wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices,
|
||||||
uint32_t argc, uint32_t argv[])
|
uint32 argc, uint32 argv[])
|
||||||
{
|
{
|
||||||
if (!wasm_runtime_exec_env_check(exec_env)) {
|
if (!wasm_runtime_exec_env_check(exec_env)) {
|
||||||
LOG_ERROR("Invalid exec env stack info.");
|
LOG_ERROR("Invalid exec env stack info.");
|
||||||
|
|
|
@ -303,6 +303,11 @@ typedef struct WASMModuleCommon {
|
||||||
Wasm_Module_AoT, and this structure should be treated as
|
Wasm_Module_AoT, and this structure should be treated as
|
||||||
AOTModule structure. */
|
AOTModule structure. */
|
||||||
uint32 module_type;
|
uint32 module_type;
|
||||||
|
|
||||||
|
/* The following uint8[1] member is a dummy just to indicate
|
||||||
|
some module_type dependent members follow.
|
||||||
|
Typically it should be accessed by casting to the corresponding
|
||||||
|
actual module_type dependent structure, not via this member. */
|
||||||
uint8 module_data[1];
|
uint8 module_data[1];
|
||||||
} WASMModuleCommon;
|
} WASMModuleCommon;
|
||||||
|
|
||||||
|
@ -314,6 +319,11 @@ typedef struct WASMModuleInstanceCommon {
|
||||||
Wasm_Module_AoT, and this structure should be treated as
|
Wasm_Module_AoT, and this structure should be treated as
|
||||||
AOTModuleInstance structure. */
|
AOTModuleInstance structure. */
|
||||||
uint32 module_type;
|
uint32 module_type;
|
||||||
|
|
||||||
|
/* The following uint8[1] member is a dummy just to indicate
|
||||||
|
some module_type dependent members follow.
|
||||||
|
Typically it should be accessed by casting to the corresponding
|
||||||
|
actual module_type dependent structure, not via this member. */
|
||||||
uint8 module_inst_data[1];
|
uint8 module_inst_data[1];
|
||||||
} WASMModuleInstanceCommon;
|
} WASMModuleInstanceCommon;
|
||||||
|
|
||||||
|
@ -377,6 +387,11 @@ typedef struct WASMRegisteredModule {
|
||||||
|
|
||||||
typedef struct WASMMemoryInstanceCommon {
|
typedef struct WASMMemoryInstanceCommon {
|
||||||
uint32 module_type;
|
uint32 module_type;
|
||||||
|
|
||||||
|
/* The following uint8[1] member is a dummy just to indicate
|
||||||
|
some module_type dependent members follow.
|
||||||
|
Typically it should be accessed by casting to the corresponding
|
||||||
|
actual module_type dependent structure, not via this member. */
|
||||||
uint8 memory_inst_data[1];
|
uint8 memory_inst_data[1];
|
||||||
} WASMMemoryInstanceCommon;
|
} WASMMemoryInstanceCommon;
|
||||||
|
|
||||||
|
@ -456,6 +471,28 @@ WASMType *
|
||||||
wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function,
|
wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function,
|
||||||
uint32 module_type);
|
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 */
|
/* See wasm_export.h for description */
|
||||||
WASM_RUNTIME_API_EXTERN WASMExecEnv *
|
WASM_RUNTIME_API_EXTERN WASMExecEnv *
|
||||||
wasm_runtime_create_exec_env(WASMModuleInstanceCommon *module_inst,
|
wasm_runtime_create_exec_env(WASMModuleInstanceCommon *module_inst,
|
||||||
|
|
|
@ -407,6 +407,54 @@ WASM_RUNTIME_API_EXTERN wasm_function_inst_t
|
||||||
wasm_runtime_lookup_function(wasm_module_inst_t const module_inst,
|
wasm_runtime_lookup_function(wasm_module_inst_t const module_inst,
|
||||||
const char *name, const char *signature);
|
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.
|
* Create execution environment for a WASM module instance.
|
||||||
*
|
*
|
||||||
|
@ -449,7 +497,7 @@ WASM_RUNTIME_API_EXTERN uint32_t
|
||||||
wasm_runtime_start_debug_instance(wasm_exec_env_t exec_env);
|
wasm_runtime_start_debug_instance(wasm_exec_env_t exec_env);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize thread environment.
|
* Initialize the thread environment.
|
||||||
* Note:
|
* Note:
|
||||||
* If developer creates a child thread by himself to call the
|
* If developer creates a child thread by himself to call the
|
||||||
* the wasm function in that thread, he should call this API
|
* the wasm function in that thread, he should call this API
|
||||||
|
@ -464,11 +512,17 @@ WASM_RUNTIME_API_EXTERN bool
|
||||||
wasm_runtime_init_thread_env(void);
|
wasm_runtime_init_thread_env(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy thread environment
|
* Destroy the thread environment
|
||||||
*/
|
*/
|
||||||
WASM_RUNTIME_API_EXTERN void
|
WASM_RUNTIME_API_EXTERN void
|
||||||
wasm_runtime_destroy_thread_env(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
|
* Get WASM module instance from execution environment
|
||||||
*
|
*
|
||||||
|
|
|
@ -107,6 +107,12 @@ os_thread_env_init();
|
||||||
void
|
void
|
||||||
os_thread_env_destroy();
|
os_thread_env_destroy();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the thread environment is initialized
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
os_thread_env_inited();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Suspend execution of the calling thread for (at least)
|
* Suspend execution of the calling thread for (at least)
|
||||||
* usec microseconds
|
* usec microseconds
|
||||||
|
|
|
@ -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
|
int
|
||||||
os_sem_init(korp_sem *sem)
|
os_sem_init(korp_sem *sem)
|
||||||
{
|
{
|
||||||
|
|
104
language-bindings/go/README.md
Normal file
104
language-bindings/go/README.md
Normal file
|
@ -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)
|
21
language-bindings/go/build.sh
Executable file
21
language-bindings/go/build.sh
Executable file
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
PLATFORM=$(uname -s | tr A-Z a-z)
|
||||||
|
CUR_DIR=$PWD
|
||||||
|
WAMR_DIR=$PWD/../..
|
||||||
|
WAMR_GO_DIR=$PWD/wamr
|
||||||
|
|
||||||
|
cp -a ${WAMR_DIR}/core/iwasm/include/*.h ${WAMR_GO_DIR}/packaged/include
|
||||||
|
|
||||||
|
mkdir -p build && cd build
|
||||||
|
cmake ${WAMR_DIR}/product-mini/platforms/${PLATFORM} \
|
||||||
|
-DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_DUMP_CALL_STACK=1 \
|
||||||
|
-DWAMR_BUILD_MEMORY_PROFILING=1
|
||||||
|
make -j ${nproc}
|
||||||
|
cp -a libvmlib.a ${WAMR_GO_DIR}/packaged/lib/${PLATFORM}-amd64
|
||||||
|
|
||||||
|
cd ${WAMR_GO_DIR}
|
||||||
|
go test
|
5
language-bindings/go/go.mod
Normal file
5
language-bindings/go/go.mod
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module gitlab.alipay-inc.com/TNT_Runtime/ant-runtime/bindings/go
|
||||||
|
|
||||||
|
go 1.15
|
||||||
|
|
||||||
|
require github.com/stretchr/testify v1.7.0
|
10
language-bindings/go/go.sum
Normal file
10
language-bindings/go/go.sum
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
23
language-bindings/go/samples/build.sh
Executable file
23
language-bindings/go/samples/build.sh
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
PLATFORM=$(uname -s | tr A-Z a-z)
|
||||||
|
CUR_DIR=$PWD
|
||||||
|
WAMR_DIR=$PWD/../../..
|
||||||
|
WAMR_GO_DIR=$PWD/../wamr
|
||||||
|
|
||||||
|
cp -a ${WAMR_DIR}/core/iwasm/include/*.h ${WAMR_GO_DIR}/packaged/include
|
||||||
|
|
||||||
|
mkdir -p build && cd build
|
||||||
|
cmake ${WAMR_DIR}/product-mini/platforms/${PLATFORM} \
|
||||||
|
-DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_DUMP_CALL_STACK=1 \
|
||||||
|
-DWAMR_BUILD_MEMORY_PROFILING=1
|
||||||
|
make -j ${nproc}
|
||||||
|
cp -a libvmlib.a ${WAMR_GO_DIR}/packaged/lib/${PLATFORM}-amd64
|
||||||
|
|
||||||
|
cd ${CUR_DIR}
|
||||||
|
rm -f test
|
||||||
|
go build test.go
|
||||||
|
./test
|
7
language-bindings/go/samples/run.sh
Executable file
7
language-bindings/go/samples/run.sh
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
go build test.go
|
||||||
|
./test
|
235
language-bindings/go/samples/test.go
Normal file
235
language-bindings/go/samples/test.go
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitlab.alipay-inc.com/TNT_Runtime/ant-runtime/bindings/go/wamr"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var wasmBytes = []byte {
|
||||||
|
0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x29, 0x07, 0x60,
|
||||||
|
0x01, 0x7F, 0x01, 0x7F, 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x01,
|
||||||
|
0x7F, 0x00, 0x60, 0x04, 0x7F, 0x7E, 0x7D, 0x7C, 0x00, 0x60, 0x02, 0x7E,
|
||||||
|
0x7E, 0x01, 0x7E, 0x60, 0x02, 0x7C, 0x7F, 0x01, 0x7D, 0x60, 0x02, 0x7D,
|
||||||
|
0x7C, 0x01, 0x7C, 0x02, 0x31, 0x04, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x70,
|
||||||
|
0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, 0x04,
|
||||||
|
0x70, 0x75, 0x74, 0x73, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x6D,
|
||||||
|
0x61, 0x6C, 0x6C, 0x6F, 0x63, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x04,
|
||||||
|
0x66, 0x72, 0x65, 0x65, 0x00, 0x02, 0x03, 0x07, 0x06, 0x00, 0x03, 0x04,
|
||||||
|
0x06, 0x05, 0x01, 0x05, 0x03, 0x01, 0x00, 0x01, 0x06, 0x13, 0x03, 0x7F,
|
||||||
|
0x01, 0x41, 0x90, 0x29, 0x0B, 0x7F, 0x00, 0x41, 0x90, 0x09, 0x0B, 0x7F,
|
||||||
|
0x00, 0x41, 0x90, 0x29, 0x0B, 0x07, 0x5F, 0x09, 0x06, 0x6D, 0x65, 0x6D,
|
||||||
|
0x6F, 0x72, 0x79, 0x02, 0x00, 0x04, 0x66, 0x69, 0x62, 0x32, 0x00, 0x04,
|
||||||
|
0x05, 0x74, 0x65, 0x73, 0x74, 0x31, 0x00, 0x05, 0x05, 0x74, 0x65, 0x73,
|
||||||
|
0x74, 0x32, 0x00, 0x06, 0x05, 0x74, 0x65, 0x73, 0x74, 0x33, 0x00, 0x07,
|
||||||
|
0x05, 0x74, 0x65, 0x73, 0x74, 0x34, 0x00, 0x08, 0x10, 0x5F, 0x5F, 0x6D,
|
||||||
|
0x61, 0x69, 0x6E, 0x5F, 0x61, 0x72, 0x67, 0x63, 0x5F, 0x61, 0x72, 0x67,
|
||||||
|
0x76, 0x00, 0x09, 0x0A, 0x5F, 0x5F, 0x64, 0x61, 0x74, 0x61, 0x5F, 0x65,
|
||||||
|
0x6E, 0x64, 0x03, 0x01, 0x0B, 0x5F, 0x5F, 0x68, 0x65, 0x61, 0x70, 0x5F,
|
||||||
|
0x62, 0x61, 0x73, 0x65, 0x03, 0x02, 0x0A, 0xA5, 0x03, 0x06, 0x37, 0x01,
|
||||||
|
0x01, 0x7F, 0x41, 0x01, 0x21, 0x01, 0x20, 0x00, 0x41, 0x02, 0x4F, 0x04,
|
||||||
|
0x7F, 0x41, 0x00, 0x21, 0x01, 0x03, 0x40, 0x20, 0x00, 0x41, 0x02, 0x6B,
|
||||||
|
0x10, 0x04, 0x20, 0x01, 0x6A, 0x21, 0x01, 0x20, 0x00, 0x41, 0x01, 0x6B,
|
||||||
|
0x22, 0x00, 0x41, 0x01, 0x4B, 0x0D, 0x00, 0x0B, 0x20, 0x01, 0x41, 0x01,
|
||||||
|
0x6A, 0x05, 0x41, 0x01, 0x0B, 0x0B, 0x3F, 0x01, 0x01, 0x7F, 0x23, 0x00,
|
||||||
|
0x41, 0x20, 0x6B, 0x22, 0x04, 0x24, 0x00, 0x20, 0x04, 0x41, 0x18, 0x6A,
|
||||||
|
0x20, 0x03, 0x39, 0x03, 0x00, 0x20, 0x04, 0x41, 0x10, 0x6A, 0x20, 0x02,
|
||||||
|
0xBB, 0x39, 0x03, 0x00, 0x20, 0x04, 0x20, 0x01, 0x37, 0x03, 0x08, 0x20,
|
||||||
|
0x04, 0x20, 0x00, 0x36, 0x02, 0x00, 0x41, 0xD0, 0x08, 0x20, 0x04, 0x10,
|
||||||
|
0x00, 0x1A, 0x20, 0x04, 0x41, 0x20, 0x6A, 0x24, 0x00, 0x0B, 0x3B, 0x01,
|
||||||
|
0x01, 0x7F, 0x23, 0x00, 0x41, 0x20, 0x6B, 0x22, 0x02, 0x24, 0x00, 0x20,
|
||||||
|
0x02, 0x20, 0x00, 0x37, 0x03, 0x00, 0x20, 0x02, 0x20, 0x01, 0x37, 0x03,
|
||||||
|
0x08, 0x20, 0x02, 0x41, 0x10, 0x6A, 0x20, 0x00, 0x20, 0x01, 0x7C, 0x22,
|
||||||
|
0x00, 0x37, 0x03, 0x00, 0x41, 0xF6, 0x08, 0x20, 0x02, 0x10, 0x00, 0x1A,
|
||||||
|
0x20, 0x02, 0x41, 0x20, 0x6A, 0x24, 0x00, 0x20, 0x00, 0x0B, 0x40, 0x02,
|
||||||
|
0x01, 0x7F, 0x01, 0x7C, 0x23, 0x00, 0x41, 0x20, 0x6B, 0x22, 0x02, 0x24,
|
||||||
|
0x00, 0x20, 0x02, 0x20, 0x01, 0x39, 0x03, 0x08, 0x20, 0x02, 0x20, 0x00,
|
||||||
|
0xBB, 0x22, 0x03, 0x39, 0x03, 0x00, 0x20, 0x02, 0x41, 0x10, 0x6A, 0x20,
|
||||||
|
0x03, 0x20, 0x01, 0xA2, 0x22, 0x01, 0x39, 0x03, 0x00, 0x41, 0xB4, 0x08,
|
||||||
|
0x20, 0x02, 0x10, 0x00, 0x1A, 0x20, 0x02, 0x41, 0x20, 0x6A, 0x24, 0x00,
|
||||||
|
0x20, 0x01, 0x0B, 0x3D, 0x01, 0x01, 0x7F, 0x23, 0x00, 0x41, 0x20, 0x6B,
|
||||||
|
0x22, 0x02, 0x24, 0x00, 0x20, 0x02, 0x20, 0x00, 0x39, 0x03, 0x00, 0x20,
|
||||||
|
0x02, 0x20, 0x01, 0x36, 0x02, 0x08, 0x20, 0x02, 0x41, 0x10, 0x6A, 0x20,
|
||||||
|
0x00, 0x20, 0x01, 0xB7, 0xA3, 0x22, 0x00, 0x39, 0x03, 0x00, 0x41, 0xC2,
|
||||||
|
0x08, 0x20, 0x02, 0x10, 0x00, 0x1A, 0x20, 0x02, 0x41, 0x20, 0x6A, 0x24,
|
||||||
|
0x00, 0x20, 0x00, 0xB6, 0x0B, 0x70, 0x00, 0x23, 0x00, 0x41, 0x20, 0x6B,
|
||||||
|
0x22, 0x00, 0x24, 0x00, 0x41, 0x9A, 0x08, 0x10, 0x01, 0x1A, 0x02, 0x7F,
|
||||||
|
0x41, 0x80, 0x08, 0x10, 0x02, 0x22, 0x01, 0x45, 0x04, 0x40, 0x41, 0x88,
|
||||||
|
0x08, 0x10, 0x01, 0x1A, 0x41, 0x7F, 0x0C, 0x01, 0x0B, 0x20, 0x00, 0x20,
|
||||||
|
0x01, 0x36, 0x02, 0x10, 0x41, 0xA7, 0x08, 0x20, 0x00, 0x41, 0x10, 0x6A,
|
||||||
|
0x10, 0x00, 0x1A, 0x20, 0x01, 0x41, 0x04, 0x6A, 0x41, 0x8E, 0x09, 0x2F,
|
||||||
|
0x00, 0x00, 0x3B, 0x00, 0x00, 0x20, 0x01, 0x41, 0x8A, 0x09, 0x28, 0x00,
|
||||||
|
0x00, 0x36, 0x00, 0x00, 0x20, 0x00, 0x20, 0x01, 0x36, 0x02, 0x00, 0x41,
|
||||||
|
0x80, 0x08, 0x20, 0x00, 0x10, 0x00, 0x1A, 0x20, 0x01, 0x10, 0x03, 0x41,
|
||||||
|
0x00, 0x0B, 0x20, 0x00, 0x41, 0x20, 0x6A, 0x24, 0x00, 0x0B, 0x0B, 0x97,
|
||||||
|
0x01, 0x01, 0x00, 0x41, 0x80, 0x08, 0x0B, 0x8F, 0x01, 0x62, 0x75, 0x66,
|
||||||
|
0x3A, 0x20, 0x25, 0x73, 0x00, 0x6D, 0x61, 0x6C, 0x6C, 0x6F, 0x63, 0x20,
|
||||||
|
0x62, 0x75, 0x66, 0x20, 0x66, 0x61, 0x69, 0x6C, 0x65, 0x64, 0x00, 0x48,
|
||||||
|
0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x00,
|
||||||
|
0x62, 0x75, 0x66, 0x20, 0x70, 0x74, 0x72, 0x3A, 0x20, 0x25, 0x70, 0x0A,
|
||||||
|
0x00, 0x25, 0x66, 0x20, 0x2A, 0x20, 0x25, 0x66, 0x20, 0x3D, 0x20, 0x25,
|
||||||
|
0x66, 0x0A, 0x00, 0x25, 0x66, 0x20, 0x2F, 0x20, 0x25, 0x64, 0x20, 0x3D,
|
||||||
|
0x20, 0x25, 0x66, 0x0A, 0x00, 0x69, 0x33, 0x32, 0x3A, 0x20, 0x25, 0x64,
|
||||||
|
0x2C, 0x20, 0x69, 0x36, 0x34, 0x3A, 0x20, 0x25, 0x6C, 0x6C, 0x64, 0x2C,
|
||||||
|
0x20, 0x66, 0x33, 0x32, 0x3A, 0x20, 0x25, 0x66, 0x2C, 0x20, 0x66, 0x36,
|
||||||
|
0x34, 0x3A, 0x20, 0x25, 0x66, 0x0A, 0x00, 0x25, 0x6C, 0x6C, 0x64, 0x20,
|
||||||
|
0x2B, 0x20, 0x25, 0x6C, 0x6C, 0x64, 0x20, 0x3D, 0x20, 0x25, 0x6C, 0x6C,
|
||||||
|
0x64, 0x0A, 0x00, 0x31, 0x32, 0x33, 0x34, 0x0A }
|
||||||
|
|
||||||
|
var global_heap []byte = make([]byte, 128 * 1024, 128 * 1024)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var module *wamr.Module
|
||||||
|
var instance *wamr.Instance
|
||||||
|
var argv []uint32
|
||||||
|
var results []interface{}
|
||||||
|
var offset uint32
|
||||||
|
var native_addr *uint8
|
||||||
|
var err error
|
||||||
|
|
||||||
|
fmt.Print("Init wasm runtime with global heap buf\n");
|
||||||
|
err = wamr.Runtime().FullInit(true, global_heap, 1)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Print("Destroy runtime\n");
|
||||||
|
wamr.Runtime().Destroy()
|
||||||
|
|
||||||
|
fmt.Print("Init wasm runtime without global heap buf\n");
|
||||||
|
err = wamr.Runtime().FullInit(false, nil, 1)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
wamr.Runtime().SetLogLevel(wamr.LOG_LEVEL_WARNING)
|
||||||
|
|
||||||
|
fmt.Print("Load wasm module\n");
|
||||||
|
module, err = wamr.NewModule(wasmBytes)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
goto fail
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Print("Instantiate wasm module\n");
|
||||||
|
instance, err = wamr.NewInstance(module, 16384, 16384)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
goto fail
|
||||||
|
}
|
||||||
|
|
||||||
|
results = make([]interface{}, 8, 8)
|
||||||
|
argv = make([]uint32, 8)
|
||||||
|
|
||||||
|
fmt.Print("\nCall func __main_argc_argv with CallFunc:\n");
|
||||||
|
err = instance.CallFunc("__main_argc_argv", 2, argv)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
goto fail
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Print("\nCall func __main_argc_argv with CallFuncV:\n");
|
||||||
|
err = instance.CallFuncV("__main_argc_argv", 2, results,
|
||||||
|
(int32)(0), (int32)(0))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
goto fail
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Print("\nCall func `i32 fib2(i32)` with CallFunc:\n");
|
||||||
|
argv[0] = 32
|
||||||
|
err = instance.CallFunc("fib2", 1, argv)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
goto fail
|
||||||
|
}
|
||||||
|
fmt.Printf("fib2(32) return: %d\n", argv[0]);
|
||||||
|
|
||||||
|
fmt.Print("\nCall func `void test1(i32, i64, f32, f64)` with CallFuncV:\n");
|
||||||
|
err = instance.CallFuncV("test1", 0, nil,
|
||||||
|
(int32)(12345678),
|
||||||
|
(int64)(3344556677889900),
|
||||||
|
(float32)(5678.1234),
|
||||||
|
(float64)(987654321.5678))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
goto fail
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Print("\nCall func `i64 test2(i64, i64)` with CallFuncV:\n");
|
||||||
|
err = instance.CallFuncV("test2", 1, results,
|
||||||
|
(int64)(3344556677889900),
|
||||||
|
(int64)(1122331122110099))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
goto fail
|
||||||
|
}
|
||||||
|
fmt.Printf("test2(3344556677889900, 1122331122110099) return: %d\n",
|
||||||
|
results[0].(int64))
|
||||||
|
|
||||||
|
fmt.Print("\nCall func `f64 test3(f32, f64)` with CallFuncV:\n");
|
||||||
|
err = instance.CallFuncV("test3", 1, results,
|
||||||
|
(float32)(3456.1234),
|
||||||
|
(float64)(7890.4567))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
goto fail
|
||||||
|
}
|
||||||
|
fmt.Printf("test3(3456.1234, 7890.4567) return: %f\n",
|
||||||
|
results[0].(float64))
|
||||||
|
|
||||||
|
fmt.Print("\nCall func `f32 test4(f64, i32)` with CallFuncV:\n");
|
||||||
|
err = instance.CallFuncV("test4", 1, results,
|
||||||
|
(float64)(8912.3456),
|
||||||
|
(int32)(123))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
goto fail
|
||||||
|
}
|
||||||
|
fmt.Printf("test4(8912.3456, 123) return: %f\n",
|
||||||
|
results[0].(float32))
|
||||||
|
|
||||||
|
fmt.Print("\nTest ModuleMalloc")
|
||||||
|
offset, native_addr = instance.ModuleMalloc(1024)
|
||||||
|
fmt.Printf("ModuleMalloc(%d) return offset: %d, native addr: %p\n",
|
||||||
|
1024, offset, native_addr)
|
||||||
|
|
||||||
|
if (!instance.ValidateAppAddr(offset, 1024)) {
|
||||||
|
fmt.Print("Validate app addr failed\n")
|
||||||
|
}
|
||||||
|
if (!instance.ValidateNativeAddr(native_addr, 1024)) {
|
||||||
|
fmt.Print("Validate native addr failed\n")
|
||||||
|
}
|
||||||
|
if (native_addr != instance.AddrAppToNative(offset)) {
|
||||||
|
fmt.Print("Convert app addr to native addr failed\n")
|
||||||
|
}
|
||||||
|
if (offset != instance.AddrNativeToApp(native_addr)) {
|
||||||
|
fmt.Print("Convert app addr to native addr failed\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.ModuleFree(offset)
|
||||||
|
|
||||||
|
/*
|
||||||
|
instance.DumpMemoryConsumption()
|
||||||
|
instance.DumpCallStack()
|
||||||
|
*/
|
||||||
|
|
||||||
|
fmt.Print("\n");
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (instance != nil) {
|
||||||
|
fmt.Print("Destroy instance\n");
|
||||||
|
instance.Destroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (module != nil) {
|
||||||
|
fmt.Print("Destroy module\n");
|
||||||
|
module.Destroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Print("Destroy wasm runtime\n");
|
||||||
|
wamr.Runtime().Destroy()
|
||||||
|
}
|
32
language-bindings/go/samples/wasm-app/build.sh
Executable file
32
language-bindings/go/samples/wasm-app/build.sh
Executable file
|
@ -0,0 +1,32 @@
|
||||||
|
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
WAMR_DIR=${PWD}/../../..
|
||||||
|
|
||||||
|
echo "Build wasm app .."
|
||||||
|
/opt/wasi-sdk/bin/clang -O3 \
|
||||||
|
-z stack-size=4096 -Wl,--initial-memory=65536 \
|
||||||
|
-o test.wasm main.c \
|
||||||
|
-Wl,--export=main -Wl,--export=__main_argc_argv \
|
||||||
|
-Wl,--export=fib2 \
|
||||||
|
-Wl,--export=test1 \
|
||||||
|
-Wl,--export=test2 \
|
||||||
|
-Wl,--export=test3 \
|
||||||
|
-Wl,--export=test4 \
|
||||||
|
-Wl,--export=__data_end -Wl,--export=__heap_base \
|
||||||
|
-Wl,--strip-all,--no-entry \
|
||||||
|
-Wl,--allow-undefined \
|
||||||
|
-nostdlib \
|
||||||
|
|
||||||
|
echo "Build binarydump tool .."
|
||||||
|
rm -fr build && mkdir build && cd build
|
||||||
|
cmake ../../../../../test-tools/binarydump-tool
|
||||||
|
make
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "Generate test_wasm.h .."
|
||||||
|
./build/binarydump -o test_wasm.h -n wasm_test_file test.wasm
|
||||||
|
|
||||||
|
rm -fr build
|
||||||
|
|
||||||
|
echo "Done"
|
65
language-bindings/go/samples/wasm-app/main.c
Normal file
65
language-bindings/go/samples/wasm-app/main.c
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
fib2(unsigned n)
|
||||||
|
{
|
||||||
|
if (n < 2) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return fib2(n - 2) + fib2(n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test1(int32_t i32, int64_t i64, float f32, double f64)
|
||||||
|
{
|
||||||
|
printf("i32: %d, i64: %lld, f32: %f, f64: %f\n", i32, i64, f32, f64);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
test2(int64_t x, int64_t y)
|
||||||
|
{
|
||||||
|
printf("%lld + %lld = %lld\n", x, y, x + y);
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
test3(float x, double y)
|
||||||
|
{
|
||||||
|
printf("%f * %f = %f\n", x, y, x * y);
|
||||||
|
return x * y;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
test4(double x, int32_t y)
|
||||||
|
{
|
||||||
|
printf("%f / %d = %f\n", x, y, x / y);
|
||||||
|
return x / y;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
printf("Hello world!\n");
|
||||||
|
|
||||||
|
buf = malloc(1024);
|
||||||
|
if (!buf) {
|
||||||
|
printf("malloc buf failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("buf ptr: %p\n", buf);
|
||||||
|
|
||||||
|
snprintf(buf, 1024, "%s", "1234\n");
|
||||||
|
printf("buf: %s", buf);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
20
language-bindings/go/wamr/cgo.go
Normal file
20
language-bindings/go/wamr/cgo.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
package wamr
|
||||||
|
|
||||||
|
// #cgo CFLAGS: -I${SRCDIR}/packaged/include
|
||||||
|
// #cgo LDFLAGS: -lvmlib -lm
|
||||||
|
//
|
||||||
|
// #cgo linux,amd64 LDFLAGS: -Wl,-rpath,${SRCDIR}/packaged/lib/linux-amd64 -L${SRCDIR}/packaged/lib/linux-amd64
|
||||||
|
// #cgo linux,arm64 LDFLAGS: -Wl,-rpath,${SRCDIR}/packaged/lib/linux-aarch64 -L${SRCDIR}/packaged/lib/linux-aarch64
|
||||||
|
// #cgo darwin,amd64 LDFLAGS: -Wl,-rpath,${SRCDIR}/packaged/lib/darwin-amd64 -L${SRCDIR}/packaged/lib/darwin-amd64
|
||||||
|
// #cgo darwin,arm64 LDFLAGS: -Wl,-rpath,${SRCDIR}/packaged/lib/darwin-aarch64 -L${SRCDIR}/packaged/lib/darwin-aarch64
|
||||||
|
//
|
||||||
|
// #include <wasm_export.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
)
|
385
language-bindings/go/wamr/instance.go
Normal file
385
language-bindings/go/wamr/instance.go
Normal file
|
@ -0,0 +1,385 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
package wamr
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <wasm_export.h>
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
PUT_I64_TO_ADDR(uint32_t *addr, int64_t value)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
int64_t val;
|
||||||
|
uint32_t parts[2];
|
||||||
|
} u;
|
||||||
|
u.val = value;
|
||||||
|
addr[0] = u.parts[0];
|
||||||
|
addr[1] = u.parts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
PUT_F64_TO_ADDR(uint32_t *addr, double value)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
double val;
|
||||||
|
uint32_t parts[2];
|
||||||
|
} u;
|
||||||
|
u.val = value;
|
||||||
|
addr[0] = u.parts[0];
|
||||||
|
addr[1] = u.parts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int64_t
|
||||||
|
GET_I64_FROM_ADDR(uint32_t *addr)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
int64_t val;
|
||||||
|
uint32_t parts[2];
|
||||||
|
} u;
|
||||||
|
u.parts[0] = addr[0];
|
||||||
|
u.parts[1] = addr[1];
|
||||||
|
return u.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double
|
||||||
|
GET_F64_FROM_ADDR(uint32_t *addr)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
double val;
|
||||||
|
uint32_t parts[2];
|
||||||
|
} u;
|
||||||
|
u.parts[0] = addr[0];
|
||||||
|
u.parts[1] = addr[1];
|
||||||
|
return u.val;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Instance struct {
|
||||||
|
_instance C.wasm_module_inst_t
|
||||||
|
_exec_env C.wasm_exec_env_t
|
||||||
|
_module *Module
|
||||||
|
_exportsCache map[string]C.wasm_function_inst_t
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create instance from the module */
|
||||||
|
func NewInstance(module *Module,
|
||||||
|
stackSize uint, heapSize uint) (*Instance, error) {
|
||||||
|
if (module == nil) {
|
||||||
|
return nil, fmt.Errorf("NewInstance error: invalid input")
|
||||||
|
}
|
||||||
|
|
||||||
|
errorBytes := make([]byte, 128)
|
||||||
|
errorPtr := (*C.char)(unsafe.Pointer(&errorBytes[0]))
|
||||||
|
errorLen := C.uint(len(errorBytes))
|
||||||
|
|
||||||
|
instance := C.wasm_runtime_instantiate(module.module, C.uint(stackSize),
|
||||||
|
C.uint(heapSize), errorPtr, errorLen)
|
||||||
|
if (instance == nil) {
|
||||||
|
return nil, fmt.Errorf("NewInstance Error: %s", string(errorBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
exec_env := C.wasm_runtime_create_exec_env(instance, C.uint(stackSize))
|
||||||
|
if (exec_env == nil) {
|
||||||
|
C.wasm_runtime_deinstantiate(instance)
|
||||||
|
return nil, fmt.Errorf("NewInstance Error: create exec_env failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
self := &Instance{
|
||||||
|
_instance: instance,
|
||||||
|
_exec_env: exec_env,
|
||||||
|
_module: module,
|
||||||
|
_exportsCache: make(map[string]C.wasm_function_inst_t),
|
||||||
|
}
|
||||||
|
|
||||||
|
runtime.SetFinalizer(self, func(self *Instance) {
|
||||||
|
self.Destroy()
|
||||||
|
})
|
||||||
|
|
||||||
|
return self, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Destroy the instance */
|
||||||
|
func (self *Instance) Destroy() {
|
||||||
|
runtime.SetFinalizer(self, nil)
|
||||||
|
if (self._instance != nil) {
|
||||||
|
C.wasm_runtime_deinstantiate(self._instance)
|
||||||
|
}
|
||||||
|
if (self._exec_env != nil) {
|
||||||
|
C.wasm_runtime_destroy_exec_env(self._exec_env)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call the wasm function with argument in the uint32 array, and store
|
||||||
|
the return values back into the array */
|
||||||
|
func (self *Instance) CallFunc(funcName string,
|
||||||
|
argc uint32, args []uint32) error {
|
||||||
|
_func := self._exportsCache[funcName]
|
||||||
|
if _func == nil {
|
||||||
|
cName := C.CString(funcName)
|
||||||
|
defer C.free(unsafe.Pointer(cName))
|
||||||
|
|
||||||
|
_func = C.wasm_runtime_lookup_function(self._instance,
|
||||||
|
cName, (*C.char)(C.NULL))
|
||||||
|
if _func == nil {
|
||||||
|
return fmt.Errorf("CallFunc error: lookup function failed")
|
||||||
|
}
|
||||||
|
self._exportsCache[funcName] = _func
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_env_inited := Runtime().ThreadEnvInited()
|
||||||
|
if (!thread_env_inited) {
|
||||||
|
Runtime().InitThreadEnv()
|
||||||
|
}
|
||||||
|
|
||||||
|
var args_C *C.uint32_t
|
||||||
|
if (argc > 0) {
|
||||||
|
args_C = (*C.uint32_t)(unsafe.Pointer(&args[0]))
|
||||||
|
}
|
||||||
|
if (!C.wasm_runtime_call_wasm(self._exec_env, _func,
|
||||||
|
C.uint(argc), args_C)) {
|
||||||
|
if (!thread_env_inited) {
|
||||||
|
Runtime().DestroyThreadEnv()
|
||||||
|
}
|
||||||
|
return fmt.Errorf("CallFunc error: %s", string(self.GetException()))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!thread_env_inited) {
|
||||||
|
Runtime().DestroyThreadEnv()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call the wasm function with variant arguments, and store the return
|
||||||
|
values back into the results array */
|
||||||
|
func (self *Instance) CallFuncV(funcName string,
|
||||||
|
num_results uint32, results []interface{},
|
||||||
|
args ... interface{}) error {
|
||||||
|
_func := self._exportsCache[funcName]
|
||||||
|
if _func == nil {
|
||||||
|
cName := C.CString(funcName)
|
||||||
|
defer C.free(unsafe.Pointer(cName))
|
||||||
|
|
||||||
|
_func = C.wasm_runtime_lookup_function(self._instance,
|
||||||
|
cName, (*C.char)(C.NULL))
|
||||||
|
if _func == nil {
|
||||||
|
return fmt.Errorf("CallFunc error: lookup function failed")
|
||||||
|
}
|
||||||
|
self._exportsCache[funcName] = _func
|
||||||
|
}
|
||||||
|
|
||||||
|
param_count := uint32(C.wasm_func_get_param_count(_func, self._instance))
|
||||||
|
result_count := uint32(C.wasm_func_get_result_count(_func, self._instance))
|
||||||
|
|
||||||
|
if (num_results < result_count) {
|
||||||
|
str := "CallFunc error: invalid result count %d, " +
|
||||||
|
"must be no smaller than %d"
|
||||||
|
return fmt.Errorf(str, num_results, result_count)
|
||||||
|
}
|
||||||
|
|
||||||
|
param_types := make([]C.uchar, param_count, param_count)
|
||||||
|
result_types := make([]C.uchar, result_count, result_count)
|
||||||
|
if (param_count > 0) {
|
||||||
|
C.wasm_func_get_param_types(_func, self._instance,
|
||||||
|
(*C.uchar)(unsafe.Pointer(¶m_types[0])))
|
||||||
|
}
|
||||||
|
if (result_count > 0) {
|
||||||
|
C.wasm_func_get_result_types(_func, self._instance,
|
||||||
|
(*C.uchar)(unsafe.Pointer(&result_types[0])))
|
||||||
|
}
|
||||||
|
|
||||||
|
argv_size := param_count * 2
|
||||||
|
if (result_count > param_count) {
|
||||||
|
argv_size = result_count * 2
|
||||||
|
}
|
||||||
|
argv := make([]uint32, argv_size, argv_size)
|
||||||
|
|
||||||
|
var i, argc uint32
|
||||||
|
for _, arg := range args {
|
||||||
|
if (i >= param_count) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch arg.(type) {
|
||||||
|
case int32:
|
||||||
|
if (param_types[i] != C.WASM_I32 &&
|
||||||
|
param_types[i] != C.WASM_FUNCREF &&
|
||||||
|
param_types[i] != C.WASM_ANYREF) {
|
||||||
|
str := "CallFunc error: invalid param type %d, " +
|
||||||
|
"expect i32 but got other"
|
||||||
|
return fmt.Errorf(str, param_types[i])
|
||||||
|
}
|
||||||
|
argv[argc] = (uint32)(arg.(int32))
|
||||||
|
argc++
|
||||||
|
break
|
||||||
|
case int64:
|
||||||
|
if (param_types[i] != C.WASM_I64) {
|
||||||
|
str := "CallFunc error: invalid param type %d, " +
|
||||||
|
"expect i64 but got other"
|
||||||
|
return fmt.Errorf(str, param_types[i])
|
||||||
|
}
|
||||||
|
addr := (*C.uint32_t)(unsafe.Pointer(&argv[argc]))
|
||||||
|
C.PUT_I64_TO_ADDR(addr, (C.int64_t)(arg.(int64)))
|
||||||
|
argc += 2
|
||||||
|
break
|
||||||
|
case float32:
|
||||||
|
if (param_types[i] != C.WASM_F32) {
|
||||||
|
str := "CallFunc error: invalid param type %d, " +
|
||||||
|
"expect f32 but got other"
|
||||||
|
return fmt.Errorf(str, param_types[i])
|
||||||
|
}
|
||||||
|
*(*C.float)(unsafe.Pointer(&argv[argc])) = (C.float)(arg.(float32))
|
||||||
|
argc++
|
||||||
|
break
|
||||||
|
case float64:
|
||||||
|
if (param_types[i] != C.WASM_F64) {
|
||||||
|
str := "CallFunc error: invalid param type %d, " +
|
||||||
|
"expect f64 but got other"
|
||||||
|
return fmt.Errorf(str, param_types[i])
|
||||||
|
}
|
||||||
|
addr := (*C.uint32_t)(unsafe.Pointer(&argv[argc]))
|
||||||
|
C.PUT_F64_TO_ADDR(addr, (C.double)(arg.(float64)))
|
||||||
|
argc += 2
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("CallFunc error: unknown param type %d",
|
||||||
|
param_types[i])
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < param_count) {
|
||||||
|
str := "CallFunc error: invalid param count, " +
|
||||||
|
"must be no smaller than %d"
|
||||||
|
return fmt.Errorf(str, param_count)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := self.CallFunc(funcName, argc, argv)
|
||||||
|
if (err != nil) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
argc = 0
|
||||||
|
for i = 0; i < result_count; i++ {
|
||||||
|
switch result_types[i] {
|
||||||
|
case C.WASM_I32:
|
||||||
|
case C.WASM_FUNCREF:
|
||||||
|
case C.WASM_ANYREF:
|
||||||
|
i32 := (int32)(argv[argc])
|
||||||
|
results[i] = i32
|
||||||
|
argc++
|
||||||
|
break
|
||||||
|
case C.WASM_I64:
|
||||||
|
addr := (*C.uint32_t)(unsafe.Pointer(&argv[argc]))
|
||||||
|
results[i] = (int64)(C.GET_I64_FROM_ADDR(addr))
|
||||||
|
argc += 2
|
||||||
|
break
|
||||||
|
case C.WASM_F32:
|
||||||
|
addr := (*C.float)(unsafe.Pointer(&argv[argc]))
|
||||||
|
results[i] = (float32)(*addr)
|
||||||
|
argc++
|
||||||
|
break
|
||||||
|
case C.WASM_F64:
|
||||||
|
addr := (*C.uint32_t)(unsafe.Pointer(&argv[argc]))
|
||||||
|
results[i] = (float64)(C.GET_F64_FROM_ADDR(addr))
|
||||||
|
argc += 2
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get exception info of the instance */
|
||||||
|
func (self *Instance) GetException() string {
|
||||||
|
cStr := C.wasm_runtime_get_exception(self._instance)
|
||||||
|
goStr := C.GoString(cStr)
|
||||||
|
return goStr
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate memory from the heap of the instance */
|
||||||
|
func (self Instance) ModuleMalloc(size uint32) (uint32, *uint8) {
|
||||||
|
var offset C.uint32_t
|
||||||
|
native_addrs := make([]*uint8, 1, 1)
|
||||||
|
ptr := unsafe.Pointer(&native_addrs[0])
|
||||||
|
offset = C.wasm_runtime_module_malloc(self._instance, (C.uint32_t)(size),
|
||||||
|
(*unsafe.Pointer)(ptr))
|
||||||
|
return (uint32)(offset), native_addrs[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free memory to the heap of the instance */
|
||||||
|
func (self Instance) ModuleFree(offset uint32) {
|
||||||
|
C.wasm_runtime_module_free(self._instance, (C.uint32_t)(offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self Instance) ValidateAppAddr(app_offset uint32, size uint32) bool {
|
||||||
|
ret := C.wasm_runtime_validate_app_addr(self._instance,
|
||||||
|
(C.uint32_t)(app_offset),
|
||||||
|
(C.uint32_t)(size))
|
||||||
|
return (bool)(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self Instance) ValidateStrAddr(app_str_offset uint32) bool {
|
||||||
|
ret := C.wasm_runtime_validate_app_str_addr(self._instance,
|
||||||
|
(C.uint32_t)(app_str_offset))
|
||||||
|
return (bool)(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self Instance) ValidateNativeAddr(native_ptr *uint8, size uint32) bool {
|
||||||
|
native_ptr_C := (unsafe.Pointer)(native_ptr)
|
||||||
|
ret := C.wasm_runtime_validate_native_addr(self._instance,
|
||||||
|
native_ptr_C,
|
||||||
|
(C.uint32_t)(size))
|
||||||
|
return (bool)(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self Instance) AddrAppToNative(app_offset uint32) *uint8 {
|
||||||
|
native_ptr := C.wasm_runtime_addr_app_to_native(self._instance,
|
||||||
|
(C.uint32_t)(app_offset))
|
||||||
|
return (*uint8)(native_ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self Instance) AddrNativeToApp(native_ptr *uint8) uint32 {
|
||||||
|
native_ptr_C := (unsafe.Pointer)(native_ptr)
|
||||||
|
offset := C.wasm_runtime_addr_native_to_app(self._instance,
|
||||||
|
native_ptr_C)
|
||||||
|
return (uint32)(offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self Instance) GetAppAddrRange(app_offset uint32) (bool,
|
||||||
|
uint32,
|
||||||
|
uint32) {
|
||||||
|
var start_offset, end_offset C.uint32_t
|
||||||
|
ret := C.wasm_runtime_get_app_addr_range(self._instance,
|
||||||
|
(C.uint32_t)(app_offset),
|
||||||
|
&start_offset, &end_offset)
|
||||||
|
return (bool)(ret), (uint32)(start_offset), (uint32)(end_offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self Instance) GetNativeAddrRange(native_ptr *uint8) (bool,
|
||||||
|
*uint8,
|
||||||
|
*uint8) {
|
||||||
|
var start_addr, end_addr *C.uint8_t
|
||||||
|
native_ptr_C := (*C.uint8_t)((unsafe.Pointer)(native_ptr))
|
||||||
|
ret := C.wasm_runtime_get_native_addr_range(self._instance,
|
||||||
|
native_ptr_C,
|
||||||
|
&start_addr, &end_addr)
|
||||||
|
return (bool)(ret), (*uint8)(start_addr), (*uint8)(end_addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self Instance) DumpMemoryConsumption() {
|
||||||
|
C.wasm_runtime_dump_mem_consumption(self._exec_env)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self Instance) DumpCallStack() {
|
||||||
|
C.wasm_runtime_dump_call_stack(self._exec_env)
|
||||||
|
}
|
19
language-bindings/go/wamr/instance_test.go
Normal file
19
language-bindings/go/wamr/instance_test.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
package wamr
|
||||||
|
|
||||||
|
import (
|
||||||
|
//"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInstance(t *testing.T) {
|
||||||
|
/* TODO */
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCallFunc(t *testing.T) {
|
||||||
|
/* TODO */
|
||||||
|
}
|
134
language-bindings/go/wamr/module.go
Normal file
134
language-bindings/go/wamr/module.go
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
package wamr
|
||||||
|
|
||||||
|
// #include <wasm_export.h>
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
"runtime"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Module struct {
|
||||||
|
module C.wasm_module_t
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create WASM/AOT module from the memory buffer */
|
||||||
|
func NewModule(wasmBytes []byte) (*Module, error) {
|
||||||
|
if (wasmBytes == nil || len(wasmBytes) == 0) {
|
||||||
|
return nil, fmt.Errorf("NewModule error: invalid input")
|
||||||
|
}
|
||||||
|
|
||||||
|
wasmPtr := (*C.uint8_t)(unsafe.Pointer(&wasmBytes[0]))
|
||||||
|
wasmLen := C.uint(len(wasmBytes))
|
||||||
|
|
||||||
|
errorBytes := make([]byte, 128)
|
||||||
|
errorPtr := (*C.char)(unsafe.Pointer(&errorBytes[0]))
|
||||||
|
errorLen := C.uint(len(errorBytes))
|
||||||
|
|
||||||
|
m := C.wasm_runtime_load(wasmPtr, wasmLen, errorPtr, errorLen)
|
||||||
|
if (m == nil) {
|
||||||
|
return nil, fmt.Errorf("NewModule error: %s", string(errorBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
self := &Module{
|
||||||
|
module: m,
|
||||||
|
}
|
||||||
|
|
||||||
|
runtime.SetFinalizer(self, func(self *Module) {
|
||||||
|
self.Destroy()
|
||||||
|
})
|
||||||
|
|
||||||
|
return self, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Destroy the module */
|
||||||
|
func (self *Module) Destroy() {
|
||||||
|
runtime.SetFinalizer(self, nil)
|
||||||
|
if (self.module != nil) {
|
||||||
|
C.wasm_runtime_unload(self.module)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set module's wasi arguments */
|
||||||
|
func (self *Module) SetWasiArgs(dirList [][]byte, mapDirList [][]byte,
|
||||||
|
env [][]byte, argv[][]byte) {
|
||||||
|
var dirPtr, mapDirPtr, envPtr, argvPtr **C.char
|
||||||
|
var dirCount, mapDirCount, envCount C.uint
|
||||||
|
var argc C.int
|
||||||
|
|
||||||
|
if (dirList != nil) {
|
||||||
|
dirPtr = (**C.char)(unsafe.Pointer(&dirList[0]))
|
||||||
|
dirCount = C.uint(len(dirList))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapDirList != nil) {
|
||||||
|
mapDirPtr = (**C.char)(unsafe.Pointer(&mapDirList[0]))
|
||||||
|
mapDirCount = C.uint(len(mapDirList))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env != nil) {
|
||||||
|
envPtr = (**C.char)(unsafe.Pointer(&env[0]))
|
||||||
|
envCount = C.uint(len(env))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argv != nil) {
|
||||||
|
argvPtr = (**C.char)(unsafe.Pointer(&argv[0]))
|
||||||
|
argc = C.int(len(argv))
|
||||||
|
}
|
||||||
|
|
||||||
|
C.wasm_runtime_set_wasi_args(self.module, dirPtr, dirCount,
|
||||||
|
mapDirPtr, mapDirCount,
|
||||||
|
envPtr, envCount, argvPtr, argc)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set module's wasi arguments */
|
||||||
|
func (self *Module) SetWasiArgsEx(dirList [][]byte, mapDirList [][]byte,
|
||||||
|
env [][]byte, argv[][]byte,
|
||||||
|
stdinfd int, stdoutfd int, stderrfd int) {
|
||||||
|
var dirPtr, mapDirPtr, envPtr, argvPtr **C.char
|
||||||
|
var dirCount, mapDirCount, envCount C.uint
|
||||||
|
var argc C.int
|
||||||
|
|
||||||
|
if (dirList != nil) {
|
||||||
|
dirPtr = (**C.char)(unsafe.Pointer(&dirList[0]))
|
||||||
|
dirCount = C.uint(len(dirList))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapDirList != nil) {
|
||||||
|
mapDirPtr = (**C.char)(unsafe.Pointer(&mapDirList[0]))
|
||||||
|
mapDirCount = C.uint(len(mapDirList))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env != nil) {
|
||||||
|
envPtr = (**C.char)(unsafe.Pointer(&env[0]))
|
||||||
|
envCount = C.uint(len(env))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argv != nil) {
|
||||||
|
argvPtr = (**C.char)(unsafe.Pointer(&argv[0]))
|
||||||
|
argc = C.int(len(argv))
|
||||||
|
}
|
||||||
|
|
||||||
|
C.wasm_runtime_set_wasi_args_ex(self.module, dirPtr, dirCount,
|
||||||
|
mapDirPtr, mapDirCount,
|
||||||
|
envPtr, envCount, argvPtr, argc,
|
||||||
|
C.int(stdinfd), C.int(stdoutfd),
|
||||||
|
C.int(stderrfd))
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set module's wasi network address pool */
|
||||||
|
func (self *Module) SetWasiAddrPool(addrPool [][]byte) {
|
||||||
|
var addrPoolPtr **C.char
|
||||||
|
var addrPoolSize C.uint
|
||||||
|
|
||||||
|
if (addrPool != nil) {
|
||||||
|
addrPoolPtr = (**C.char)(unsafe.Pointer(&addrPool[0]))
|
||||||
|
addrPoolSize = C.uint(len(addrPool))
|
||||||
|
}
|
||||||
|
C.wasm_runtime_set_wasi_addr_pool(self.module, addrPoolPtr, addrPoolSize)
|
||||||
|
}
|
15
language-bindings/go/wamr/module_test.go
Normal file
15
language-bindings/go/wamr/module_test.go
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
package wamr
|
||||||
|
|
||||||
|
import (
|
||||||
|
//"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestModule(t *testing.T) {
|
||||||
|
/* TODO */
|
||||||
|
}
|
6
language-bindings/go/wamr/packaged/include/dummy.go
Normal file
6
language-bindings/go/wamr/packaged/include/dummy.go
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
package include
|
|
@ -0,0 +1,6 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
package darwin_amd64
|
6
language-bindings/go/wamr/packaged/lib/dummy.go
Normal file
6
language-bindings/go/wamr/packaged/lib/dummy.go
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
package lib
|
|
@ -0,0 +1,6 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
package linux_amd64
|
153
language-bindings/go/wamr/runtime.go
Normal file
153
language-bindings/go/wamr/runtime.go
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
package wamr
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <wasm_export.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
bh_log_set_verbose_level(uint32_t level);
|
||||||
|
|
||||||
|
bool
|
||||||
|
init_wamr_runtime(bool alloc_with_pool, uint8_t *heap_buf,
|
||||||
|
uint32_t heap_size, uint32_t max_thread_num)
|
||||||
|
{
|
||||||
|
RuntimeInitArgs init_args;
|
||||||
|
|
||||||
|
memset(&init_args, 0, sizeof(RuntimeInitArgs));
|
||||||
|
|
||||||
|
if (alloc_with_pool) {
|
||||||
|
init_args.mem_alloc_type = Alloc_With_Pool;
|
||||||
|
init_args.mem_alloc_option.pool.heap_buf = heap_buf;
|
||||||
|
init_args.mem_alloc_option.pool.heap_size = heap_size;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
init_args.mem_alloc_type = Alloc_With_System_Allocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wasm_runtime_full_init(&init_args);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LogLevel uint32
|
||||||
|
const (
|
||||||
|
LOG_LEVEL_FATAL LogLevel = 0
|
||||||
|
LOG_LEVEL_ERROR LogLevel = 1
|
||||||
|
LOG_LEVEL_WARNING LogLevel = 2
|
||||||
|
LOG_LEVEL_DEBUG LogLevel = 3
|
||||||
|
LOG_LEVEL_VERBOSE LogLevel = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
type NativeSymbol struct {
|
||||||
|
symbol string
|
||||||
|
func_ptr *uint8
|
||||||
|
signature string
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
type _Runtime struct {
|
||||||
|
initialized bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var _runtime_singleton *_Runtime
|
||||||
|
|
||||||
|
/* Return the runtime singleton */
|
||||||
|
func Runtime() *_Runtime {
|
||||||
|
if (_runtime_singleton == nil) {
|
||||||
|
self := &_Runtime{}
|
||||||
|
_runtime_singleton = self
|
||||||
|
}
|
||||||
|
return _runtime_singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the WASM runtime environment */
|
||||||
|
func (self *_Runtime) FullInit(alloc_with_pool bool, heap_buf []byte,
|
||||||
|
max_thread_num uint) error {
|
||||||
|
var heap_buf_C *C.uchar
|
||||||
|
|
||||||
|
if (self.initialized) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alloc_with_pool) {
|
||||||
|
if (heap_buf == nil) {
|
||||||
|
return fmt.Errorf("Failed to init WAMR runtime")
|
||||||
|
}
|
||||||
|
heap_buf_C = (*C.uchar)(unsafe.Pointer(&heap_buf[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!C.init_wamr_runtime((C.bool)(alloc_with_pool), heap_buf_C,
|
||||||
|
(C.uint)(len(heap_buf)),
|
||||||
|
(C.uint)(max_thread_num))) {
|
||||||
|
return fmt.Errorf("Failed to init WAMR runtime")
|
||||||
|
}
|
||||||
|
|
||||||
|
self.initialized = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the WASM runtime environment */
|
||||||
|
func (self *_Runtime) Init() error {
|
||||||
|
return self.FullInit(false, nil, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Destroy the WASM runtime environment */
|
||||||
|
func (self *_Runtime) Destroy() {
|
||||||
|
if (self.initialized) {
|
||||||
|
C.wasm_runtime_destroy()
|
||||||
|
self.initialized = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set log verbose level (0 to 5, default is 2),
|
||||||
|
larger level with more log */
|
||||||
|
func (self *_Runtime) SetLogLevel(level LogLevel) {
|
||||||
|
C.bh_log_set_verbose_level(C.uint32_t(level))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func (self *_Runtime) RegisterNatives(moduleName string,
|
||||||
|
nativeSymbols []NativeSymbol) {
|
||||||
|
}
|
||||||
|
*/ /* TODO */
|
||||||
|
|
||||||
|
func (self *_Runtime) InitThreadEnv() bool {
|
||||||
|
if (!C.wasm_runtime_init_thread_env()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *_Runtime) DestroyThreadEnv() {
|
||||||
|
C.wasm_runtime_destroy_thread_env();
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *_Runtime) ThreadEnvInited() bool {
|
||||||
|
if (!C.wasm_runtime_thread_env_inited()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate memory from runtime memory environment */
|
||||||
|
func (self *_Runtime) Malloc(size uint32) *uint8 {
|
||||||
|
ptr := C.wasm_runtime_malloc((C.uint32_t)(size))
|
||||||
|
return (*uint8)(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free memory to runtime memory environment */
|
||||||
|
func (self *_Runtime) Free(ptr *uint8) {
|
||||||
|
C.wasm_runtime_free((unsafe.Pointer)(ptr))
|
||||||
|
}
|
42
language-bindings/go/wamr/runtime_test.go
Normal file
42
language-bindings/go/wamr/runtime_test.go
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
package wamr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRuntime(t *testing.T) {
|
||||||
|
res := false
|
||||||
|
if (Runtime() != nil) {
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
assert.Equal(t, res, true)
|
||||||
|
|
||||||
|
err := Runtime().Init()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
Runtime().Destroy()
|
||||||
|
|
||||||
|
err = Runtime().FullInit(false, nil, 6)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
Runtime().Destroy()
|
||||||
|
|
||||||
|
err = Runtime().FullInit(false, nil, 0)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
Runtime().Destroy()
|
||||||
|
|
||||||
|
heap_buf := make([]byte, 128 * 1024)
|
||||||
|
err = Runtime().FullInit(true, heap_buf, 4)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
Runtime().Destroy()
|
||||||
|
|
||||||
|
Runtime().FullInit(false, nil, 0)
|
||||||
|
err = Runtime().FullInit(false, nil, 0)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
Runtime().Destroy()
|
||||||
|
Runtime().Destroy()
|
||||||
|
}
|
160
language-bindings/python/.gitignore
vendored
Normal file
160
language-bindings/python/.gitignore
vendored
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
# Refer to https://github.com/github/gitignore/blob/main/Python.gitignore
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# virtual environment
|
||||||
|
Pipfile
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
Pipfile.lock
|
||||||
|
|
||||||
|
# poetry
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||||
|
#poetry.lock
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
|
|
||||||
|
# PyCharm
|
||||||
|
# JetBrains specific template is maintainted in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
#.idea/
|
||||||
|
|
||||||
|
# VSCode settings
|
||||||
|
.vscode/
|
||||||
|
|
1
language-bindings/python/LICENSE
Symbolic link
1
language-bindings/python/LICENSE
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../LICENSE
|
31
language-bindings/python/README.md
Normal file
31
language-bindings/python/README.md
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# wamr-python
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Installing from the source code
|
||||||
|
|
||||||
|
Installing from local source tree is in _development mode_. The package appears to be installed but still is editable from the source tree.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ python -m pip install -e /path/to/wamr-root/binding/python
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```python
|
||||||
|
import wamr.ffi as ffi
|
||||||
|
```
|
||||||
|
|
||||||
|
### Preparation
|
||||||
|
|
||||||
|
The binding will load the shared library _libiwasm.so_ from the WAMR repo. So before running the binding, you need to build the library yourself.
|
||||||
|
|
||||||
|
The default compile options are good enough.
|
||||||
|
|
||||||
|
Please be aware that `wasm_frame_xxx` and `wasm_trap_xxx` only work well when enabling `WAMR_BUILD_DUMP_CALL_STACK`.
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
There is a [simple example](./samples/hello_procedural.py) to show how to use bindings. Actually, the python binding follows C-APIs. There it should be easy if be familiar with _programming with wasm-c-api_.
|
||||||
|
|
||||||
|
Unit test cases under _./tests_ could be another but more complete references.
|
708
language-bindings/python/docs/design.md
Normal file
708
language-bindings/python/docs/design.md
Normal file
|
@ -0,0 +1,708 @@
|
||||||
|
# how to implement a python binding of WAMR
|
||||||
|
|
||||||
|
A python language binding of Wasm runtime allows its users to call a set of APIs of
|
||||||
|
the runtime from the python world. Those APIs maybe implemented in C, C++, or Rust.
|
||||||
|
|
||||||
|
In the WAMR case, a python binding allows APIs in `core/iwasm/include/wasm_c_api.h`
|
||||||
|
to be used in the python scripts. To achieve that, we will create two kinds
|
||||||
|
of stuff: wrappers of structured data types and wrappers of functions under the
|
||||||
|
help of _ctypes_.
|
||||||
|
|
||||||
|
Cyptes is a tool in the standard library for creating Python bindings. It
|
||||||
|
provides a low-level toolset for loading shared libraries and marshaling
|
||||||
|
data between Python and C. Other options include _cffi_, _pybind11_,
|
||||||
|
_cpython_ and so on. Because we tend to make the binding depending on least
|
||||||
|
items. The built-in module, _ctypes_, is a good choice.
|
||||||
|
|
||||||
|
## General rules to marshal
|
||||||
|
|
||||||
|
The core of the idea of a language binding is how to translate different
|
||||||
|
representations of types in different language.
|
||||||
|
|
||||||
|
### load libraries
|
||||||
|
|
||||||
|
The `ctypes` supports locating a dynamic link library in a way similar to the
|
||||||
|
compiler does.
|
||||||
|
|
||||||
|
Currently, `ctypes.LoadLibrary` supports:
|
||||||
|
|
||||||
|
- `CDLL`. Those libraries use the standard C calling conversion.
|
||||||
|
- `OleDLL` and `WinDLL`. Those libraries use the `stdcall` calling conversion on
|
||||||
|
Windows only
|
||||||
|
|
||||||
|
### fundamental datatypes
|
||||||
|
|
||||||
|
_ctypes_ provides [primitive C compatiable data types](https://docs.python.org/3/library/ctypes.html#fundamental-data-types).
|
||||||
|
Like `c_bool`, `c_byte`, `c_int`, `c_long` and so on.
|
||||||
|
|
||||||
|
> `c_int` represents the _C_ `signed int` datatype. On platforms where
|
||||||
|
> `sizeof(int) == sizeof(long)` it is an alias to `c_long`.
|
||||||
|
|
||||||
|
| c datatypes | ctypes |
|
||||||
|
| ------------------- | ----------------------- |
|
||||||
|
| bool | c_bool |
|
||||||
|
| byte_t | c_ubyte |
|
||||||
|
| char | c_char |
|
||||||
|
| float32_t | c_float |
|
||||||
|
| float64_t | c_double |
|
||||||
|
| int32_t | c_int32 |
|
||||||
|
| int64_t | c_int64 |
|
||||||
|
| intptr_t | c_void_p |
|
||||||
|
| size_t | c_size_t |
|
||||||
|
| uint8_t | c_uint8 |
|
||||||
|
| uint32_t | c_uint32 |
|
||||||
|
| void | None |
|
||||||
|
| wasm_byte_t | c_ubyte |
|
||||||
|
| wasm_externkind_t | c_uint8 |
|
||||||
|
| wasm_memory_pages_t | c_uint32 |
|
||||||
|
| wasm_mutability_t | c_bool |
|
||||||
|
| wasm_table_size_t | c_uint32 |
|
||||||
|
| wasm_valkind_t | c_uint8 |
|
||||||
|
| wasm_data_type\* | POINTER(wasm_data_type) |
|
||||||
|
|
||||||
|
- `c_void_p` only represents `void *` only
|
||||||
|
- `None` represents `void` in function parameter lists and return lists
|
||||||
|
|
||||||
|
### structured datatypes
|
||||||
|
|
||||||
|
Create a corresponding concept for every native structured data type includes
|
||||||
|
`enum`, `struct` and `union`, in the python world.
|
||||||
|
|
||||||
|
#### Enum types
|
||||||
|
|
||||||
|
For example, if there is a `enum wams_mutability_enum` in native.
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef uint8_t wams_mutability_t;
|
||||||
|
enum wams_mutability_enum {
|
||||||
|
WASM_CONST,
|
||||||
|
WASM_VAR
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `ctypes.int`(or any integer types in ctypes) to represents its value directly.
|
||||||
|
|
||||||
|
```python
|
||||||
|
# represents enum wams_mutability_enum
|
||||||
|
wasm_mutability_t = c_uint8
|
||||||
|
|
||||||
|
WASM_CONST = 0
|
||||||
|
WASM_VAR = 1
|
||||||
|
```
|
||||||
|
|
||||||
|
> C standard only requires "Each enumerated type shall be compatible with char,
|
||||||
|
> a signed integer type, or an unsigned integer type. The choice of the integer
|
||||||
|
> type is implementation-defined, but shall be capable of representing the
|
||||||
|
> values of all the members of the enumeration.
|
||||||
|
|
||||||
|
#### Struct types
|
||||||
|
|
||||||
|
If there is a `struct wasm_byte_vec_t` in native(in C).
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef struct wasm_byte_vec_t {
|
||||||
|
size_t size;
|
||||||
|
wasm_byte_t *data;
|
||||||
|
size_t num_elems;
|
||||||
|
size_t size_of_elem;
|
||||||
|
} wasm_byte_vec_t;
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `ctypes.Structure` to create its corresponding data type in python.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class wasm_byte_vec_t(ctypes.Structure):
|
||||||
|
_fileds_ = [
|
||||||
|
("size", ctypes.c_size_t),
|
||||||
|
("data", ctypes.POINTER(c_ubyte)),
|
||||||
|
("num_elems", ctypes.c_size_t),
|
||||||
|
("size_of_elem", ctypes.c_size_t),
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
a list of `Structures`
|
||||||
|
|
||||||
|
| name |
|
||||||
|
| ----------------- |
|
||||||
|
| wasm_engine_t |
|
||||||
|
| wasm_store_t |
|
||||||
|
| wasm_limits_t |
|
||||||
|
| wasm_valtype_t |
|
||||||
|
| wasm_functype_t |
|
||||||
|
| wasm_globaltype_t |
|
||||||
|
| wasm_tabletype_t |
|
||||||
|
| wasm_memorytype_t |
|
||||||
|
| wasm_externtype_t |
|
||||||
|
| wasm_importtype_t |
|
||||||
|
| wasm_exporttype_t |
|
||||||
|
| wasm_ref_t |
|
||||||
|
| wasm_ref_t |
|
||||||
|
| wasm_frame_t |
|
||||||
|
| wasm_trap_t |
|
||||||
|
| wasm_foreign_t |
|
||||||
|
| WASMModuleCommon |
|
||||||
|
| WASMModuleCommon |
|
||||||
|
| wasm_func_t |
|
||||||
|
| wasm_global_t |
|
||||||
|
| wasm_table_t |
|
||||||
|
| wasm_memory_t |
|
||||||
|
| wasm_extern_t |
|
||||||
|
| wasm_instance_t |
|
||||||
|
|
||||||
|
not supported `struct`
|
||||||
|
|
||||||
|
- wasm_config_t
|
||||||
|
|
||||||
|
If there is an anonymous `union` in native.
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef struct wasm_val_t {
|
||||||
|
wasm_valkind_t kind;
|
||||||
|
union {
|
||||||
|
int32_t i32;
|
||||||
|
int64_t i64;
|
||||||
|
float32_t f32;
|
||||||
|
float64_t f64;
|
||||||
|
} of;
|
||||||
|
} wasm_val_t;
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `ctypes.Union` to create its corresponding data type in python.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class _OF(ctypes.Union):
|
||||||
|
_fields_ = [
|
||||||
|
("i32", ctypes.c_int32),
|
||||||
|
("i64", ctypes.c_int64),
|
||||||
|
("f32", ctypes.c_float),
|
||||||
|
("f64", ctypes.c_double),
|
||||||
|
]
|
||||||
|
|
||||||
|
class wasm_val_t(ctypes.Structure):
|
||||||
|
_anonymous_ = ("of",)
|
||||||
|
_fields_ = [
|
||||||
|
("kind", ctypes.c_uint8)
|
||||||
|
("of", _OF)
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### wrappers of functions
|
||||||
|
|
||||||
|
Foreign functions (C functions) can be accessed as attributes of loaded shared
|
||||||
|
libraries or an instance of function prototypes. Callback functions(python
|
||||||
|
functions) can only be accessed by instantiating function prototypes.
|
||||||
|
|
||||||
|
For example,
|
||||||
|
|
||||||
|
```c
|
||||||
|
void wasm_name_new(wasm_name_t* out, size_t len, wasm_byte_t [] data);
|
||||||
|
```
|
||||||
|
|
||||||
|
Assume there are:
|
||||||
|
|
||||||
|
- `class wasm_name_t` of python represents `wasm_name_t` of C
|
||||||
|
- `libiwasm` represents loaded _libiwasm.so_
|
||||||
|
|
||||||
|
If to access a c function like an attribute,
|
||||||
|
|
||||||
|
```python
|
||||||
|
def wasm_name_new(out, len, data):
|
||||||
|
_wasm_name_new = libiwasm.wasm_name_new
|
||||||
|
_wasm_name_new.argtypes = (ctypes.POINTER(wasm_name_t), ctypes.c_size_t, ctypes.POINTER(ctypes.c_ubyte))
|
||||||
|
_wasm_name_new.restype = None
|
||||||
|
return _wasm_name_new(out, len, data)
|
||||||
|
```
|
||||||
|
|
||||||
|
Or to instantiate a function prototype,
|
||||||
|
|
||||||
|
```python
|
||||||
|
def wasm_name_new(out, len, data):
|
||||||
|
return ctypes.CFUNCTYPE(None, (ctypes.POINTER(wasm_name_t), ctypes.c_size_t, ctypes.POINTER(ctypes.c_ubyte)))(
|
||||||
|
("wasm_name_new", libiwasm), out, len, data)
|
||||||
|
```
|
||||||
|
|
||||||
|
Now it is able to create a `wasm_name_t` with `wasm_name_new()` in python.
|
||||||
|
|
||||||
|
Sometimes, need to create a python function as a callback of c.
|
||||||
|
|
||||||
|
```c
|
||||||
|
wasm_trap_t* (*wasm_func_callback_t)(wasm_val_vec_t* args, wasm_val_vec_t *results);
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `cyptes.CFUNCTYPE` to create a _pointer of function_
|
||||||
|
|
||||||
|
```python
|
||||||
|
def hello(args, results):
|
||||||
|
print("hello from a callback")
|
||||||
|
|
||||||
|
wasm_func_callback_t = ctypes.CFUNCTYPE(c_size_t, POINTER(wasm_val_vec_t), POINTER(wasm_val_vec_t))
|
||||||
|
hello_callback = wasm_func_callback_t(hello)
|
||||||
|
```
|
||||||
|
|
||||||
|
or with a decorator
|
||||||
|
|
||||||
|
```python
|
||||||
|
def wasm_func_cb_decl(func):
|
||||||
|
return @ctypes.CFUNCTYPE(ctypes.POINTER(wasm_trap_t), (ctypes.POINTER(wasm_val_vec_t), ctypes.POINTER(wasm_val_vec_t)))(func)
|
||||||
|
|
||||||
|
@wasm_func_cb_decl
|
||||||
|
def hello(args, results):
|
||||||
|
print("hello from a callback")
|
||||||
|
```
|
||||||
|
|
||||||
|
### programming tips
|
||||||
|
|
||||||
|
#### `struct` and `ctypes.Structure`
|
||||||
|
|
||||||
|
There are two kinds of `cytes.Structure` in `binding.py`.
|
||||||
|
|
||||||
|
- has `__field__` definition. like `class wasm_byte_vec_t(Structure)`
|
||||||
|
- doesn't have `__field__` definition. like `class wasm_config_t(Structure)`
|
||||||
|
|
||||||
|
Since, `ctypes` will create its C world _mirror_ variable according to `__field__`
|
||||||
|
information, `wasm_config_t()` will only create a python instance without binding
|
||||||
|
to any C variable. `wasm_byte_vec_t()` will return a python instance with an internal
|
||||||
|
C variable.
|
||||||
|
|
||||||
|
That is why `pointer(wasm_config_t())` is a NULL pointer which can not be dereferenced.
|
||||||
|
|
||||||
|
#### deal with pointers
|
||||||
|
|
||||||
|
`byref()` and `pointer()` are two functions can return a pointer.
|
||||||
|
|
||||||
|
```python
|
||||||
|
x = ctypes.c_int(2)
|
||||||
|
|
||||||
|
# use pointer() to creates a new pointer instance which would later be used in Python
|
||||||
|
x_ptr = ctypes.pointer(x)
|
||||||
|
...
|
||||||
|
struct_use_pointer = Mystruct()
|
||||||
|
struct_use_pointer.ptr = x_ptr
|
||||||
|
|
||||||
|
# use byref() pass a pointer to an object to a foreign function call
|
||||||
|
func(ctypes.byref(x))
|
||||||
|
```
|
||||||
|
|
||||||
|
The main difference is that `pointer()` does a lot more work since it
|
||||||
|
constructs a real pointer object. It is faster to use `byref(`) if don't need
|
||||||
|
the pointer object in Python itself(e.g. only use it as an argument to pass
|
||||||
|
to a function).
|
||||||
|
|
||||||
|
There is no doubt that `wasm_xxx_new()` which return type is `ctypes.POINTER`
|
||||||
|
can return a pointer. Plus, the return value of `wasm_xxx_t()` can also be
|
||||||
|
used as a pointer without casting by `byref` or `pointer`.
|
||||||
|
|
||||||
|
#### array
|
||||||
|
|
||||||
|
In [ctypes document](https://docs.python.org/3/library/ctypes.html#arrays),
|
||||||
|
it states that "The recommended way to create array types is by multiplying a
|
||||||
|
data type with a positive integer". So _multiplying a data type_ should be a
|
||||||
|
better way to create arrays
|
||||||
|
|
||||||
|
```python
|
||||||
|
from ctypes import *
|
||||||
|
|
||||||
|
class POINT(Structure):
|
||||||
|
_fields_ = ("x", c_int), ("y", c_int)
|
||||||
|
|
||||||
|
# multiplying a data type
|
||||||
|
# type(TenPointsArrayType) is <class '_ctypes.PyCArrayType'>
|
||||||
|
TenPointsArrayType = POINT * 10
|
||||||
|
|
||||||
|
# Instances are created in the usual way, by calling the class:
|
||||||
|
arr = TenPointsArrayType()
|
||||||
|
arr[0] = POINT(3,2)
|
||||||
|
for pt in arr:
|
||||||
|
print(pt.x, pt.y)
|
||||||
|
```
|
||||||
|
|
||||||
|
On both sides, it is OK to assign an array to a pointer.
|
||||||
|
|
||||||
|
```c
|
||||||
|
char buf[128] = {0};
|
||||||
|
char *ptr = buf;
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
binary = wasm_byte_vec_t()
|
||||||
|
binary.data = (ctypes.c_ubyte * len(wasm)).from_buffer_copy(wasm)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### exceptions and traps
|
||||||
|
|
||||||
|
Interfaces of _wasm-c-api_ have their return values to represent failures.
|
||||||
|
The python binding should just keep and transfer them to callers instead of
|
||||||
|
raising any additional exception.
|
||||||
|
|
||||||
|
The python binding should raise exceptions when the python partial is failed.
|
||||||
|
|
||||||
|
#### readonly buffer
|
||||||
|
|
||||||
|
```python
|
||||||
|
with open("hello.wasm", "rb") as f:
|
||||||
|
wasm = f.read()
|
||||||
|
binary = wasm_byte_vec_t()
|
||||||
|
wasm_byte_vec_new_uninitialized(byref(binary), len(wasm))
|
||||||
|
# create a ctypes instance (byte[] in c) and copy the content
|
||||||
|
# from wasm(bytearray in python)
|
||||||
|
binary.data = (ctypes.c_ubyte * len(wasm)).from_buffer_copy(wasm)
|
||||||
|
```
|
||||||
|
|
||||||
|
in the above example, `wasm` is a python-created readable buffer. It is not
|
||||||
|
writable and needs to be copied into a ctype array.
|
||||||
|
|
||||||
|
#### variable arguments
|
||||||
|
|
||||||
|
A function with _variable arugments_ makes it hard to specify the required
|
||||||
|
argument types for the function prototype. It leaves us one way to call it
|
||||||
|
directly without any arguments type checking.
|
||||||
|
|
||||||
|
```python
|
||||||
|
libc.printf(b"Hello, an int %d, a float %f, a string %s\n", c_int(1), c_doulbe(3.14), "World!")
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Use `c_bool` to represent `wasm_mutability_t `
|
||||||
|
|
||||||
|
- `True` for `WASM_CONST`
|
||||||
|
- `False` for `WASM_VALUE`
|
||||||
|
|
||||||
|
#### customize class builtins
|
||||||
|
|
||||||
|
- `__eq__` for comparation.
|
||||||
|
- `__repr__` for printing.
|
||||||
|
|
||||||
|
### bindgen.py
|
||||||
|
|
||||||
|
`bindge.py` is a tool to create WAMR python binding automatically. `binding.py`
|
||||||
|
is generated. We should avoid modification on it. Additional helpers should go
|
||||||
|
to `ffi.py`.
|
||||||
|
|
||||||
|
`bindgen.py` uses _pycparser_. Visit the AST of `core/iwasm/include/wasm_c_api.h`
|
||||||
|
created by _gcc_ and generate necessary wrappers.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from pycparser import c_ast
|
||||||
|
|
||||||
|
class Visitor(c_ast.NodeVisitor):
|
||||||
|
def visit_Struct(self, node):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def visit_Union(self, node):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def visit_TypeDef(self, node):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def visit_FuncDecl(self, node):
|
||||||
|
pass
|
||||||
|
|
||||||
|
ast = parse_file(...)
|
||||||
|
v = Visitor()
|
||||||
|
v.visit(ast)
|
||||||
|
```
|
||||||
|
|
||||||
|
Before running _bindgen.py_, the shared library _libiwasm.so_ should be generated.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cd /path/to/wamr/repo
|
||||||
|
$ # if it is in linux
|
||||||
|
$ pushd product-mini/platforms/linux/
|
||||||
|
$ cmake -S . -B build ..
|
||||||
|
$ cmake --build build --target iwasm
|
||||||
|
$ popd
|
||||||
|
$ cd binding/python
|
||||||
|
$ python utils/bindgen.py
|
||||||
|
```
|
||||||
|
|
||||||
|
`wasm_frame_xxx` and `wasm_trap_xxx` only work well when enabling `WAMR_BUILD_DUMP_CALL_STACK`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cmake -S . -B build -DWAMR_BUILD_DUMP_CALL_STACK=1 ..
|
||||||
|
```
|
||||||
|
|
||||||
|
## OOP wrappers
|
||||||
|
|
||||||
|
Based on the above general rules, there will be corresponding python
|
||||||
|
APIs for every C API in `wasm_c_api.h` with same name. Users can do procedural
|
||||||
|
programming with those.
|
||||||
|
|
||||||
|
In next phase, we will create OOP APIs. Almost follow the
|
||||||
|
[C++ version of wasm_c_api](https://github.com/WebAssembly/wasm-c-api/blob/master/include/wasm.hh)
|
||||||
|
|
||||||
|
## A big list
|
||||||
|
|
||||||
|
| WASM Concept | Procedural APIs | OOP APIs | OOP APIs methods |
|
||||||
|
| ------------ | ------------------------------ | ---------- | ---------------- |
|
||||||
|
| XXX_vec | wasm_xxx_vec_new | | list |
|
||||||
|
| | wasm_xxx_vec_new_uninitialized | | |
|
||||||
|
| | wasm_xxx_vec_new_empty | | |
|
||||||
|
| | wasm_xxx_vec_copy | | |
|
||||||
|
| | wasm_xxx_vec_delete | | |
|
||||||
|
| valtype | wasm_valtype_new | valtype | \_\_init\_\_ |
|
||||||
|
| | wasm_valtype_delete | | \_\_del\_\_ |
|
||||||
|
| | wasm_valtype_kind | | \_\_eq\_\_ |
|
||||||
|
| | wasm_valtype_copy | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
| functype | wasm_functype_new | functype | |
|
||||||
|
| | wasm_functype_delete | | |
|
||||||
|
| | wasm_functype_params | | |
|
||||||
|
| | wasm_functype_results | | |
|
||||||
|
| | wasm_functype_copy | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
| globaltype | wasm_globaltype_new | globaltype | \_\_init\_\_ |
|
||||||
|
| | wasm_globaltype_delete | | \_\_del\_\_ |
|
||||||
|
| | wasm_globaltype_content | | \_\_eq\_\_ |
|
||||||
|
| | wasm_globaltype_mutability | | |
|
||||||
|
| | wasm_globaltype_copy | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
| tabletype | wasm_tabletype_new | tabletype | \_\_init\_\_ |
|
||||||
|
| | wasm_tabletype_delete | | \_\_del\_\_ |
|
||||||
|
| | wasm_tabletype_element | | \_\_eq\_\_ |
|
||||||
|
| | wasm_tabletype_limits | | |
|
||||||
|
| | wasm_tabletype_copy | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
| memorytype | wasm_memorytype_new | memorytype | \_\_init\_\_ |
|
||||||
|
| | wasm_memorytype_delete | | \_\_del\_\_ |
|
||||||
|
| | wasm_memorytype_limits | | \_\_eq\_\_ |
|
||||||
|
| | wasm_memorytype_copy | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
| externtype | wasm_externtype_as_XXX | externtype | |
|
||||||
|
| | wasm_XXX_as_externtype | | |
|
||||||
|
| | wasm_externtype_copy | | |
|
||||||
|
| | wasm_externtype_delete | | |
|
||||||
|
| | wasm_externtype_kind | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
| importtype | wasm_importtype_new | importtype | |
|
||||||
|
| | wasm_importtype_delete | | |
|
||||||
|
| | wasm_importtype_module | | |
|
||||||
|
| | wasm_importtype_name | | |
|
||||||
|
| | wasm_importtype_type | | |
|
||||||
|
| | wasm_importtype_copy | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
| exportype | wasm_exporttype_new | exporttype | |
|
||||||
|
| | wasm_exporttype_delete | | |
|
||||||
|
| | wasm_exporttype_name | | |
|
||||||
|
| | wasm_exporttype_type | | |
|
||||||
|
| | wasm_exporttype_copy | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
| val | wasm_val_delete | val | |
|
||||||
|
| | wasm_val_copy | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
| frame | wasm_frame_delete | frame | |
|
||||||
|
| | wasm_frame_instance | | |
|
||||||
|
| | wasm_frame_func_index | | |
|
||||||
|
| | wasm_frame_func_offset | | |
|
||||||
|
| | wasm_frame_module_offset | | |
|
||||||
|
| | wasm_frame_copy | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
| trap | wasm_trap_new | trap | |
|
||||||
|
| | wasm_trap_delete | | |
|
||||||
|
| | wasm_trap_message | | |
|
||||||
|
| | wasm_trap_origin | | |
|
||||||
|
| | wasm_trap_trace | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
| foreign | wasm_foreign_new | foreign | |
|
||||||
|
| | wasm_foreign_delete | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
| engine | wasm_engine_new | engine | |
|
||||||
|
| | wasm_engine_new_with_args\* | | |
|
||||||
|
| | wasm_engine_new_with_config | | |
|
||||||
|
| | wasm_engine_delete | | |
|
||||||
|
| store | wasm_store_new | store | |
|
||||||
|
| | wasm_store_delete | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
| module | wasm_module_new | module | |
|
||||||
|
| | wasm_module_delete | | |
|
||||||
|
| | wasm_module_validate | | |
|
||||||
|
| | wasm_module_imports | | |
|
||||||
|
| | wasm_module_exports | | |
|
||||||
|
| instance | wasm_instance_new | instance | |
|
||||||
|
| | wasm_instance_delete | | |
|
||||||
|
| | wasm_instance_new_with_args\* | | |
|
||||||
|
| | wasm_instance_exports | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
| func | wasm_func_new | func | |
|
||||||
|
| | wasm_func_new_with_env | | |
|
||||||
|
| | wasm_func_delete | | |
|
||||||
|
| | wasm_func_type | | |
|
||||||
|
| | wasm_func_call | | |
|
||||||
|
| | wasm_func_param_arity | | |
|
||||||
|
| | wasm_func_result_arity | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
| global | wasm_global_new | global | |
|
||||||
|
| | wasm_global_delete | | |
|
||||||
|
| | wasm_global_type | | |
|
||||||
|
| | wasm_global_get | | |
|
||||||
|
| | wasm_global_set | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
| table | wasm_table_new | table | |
|
||||||
|
| | wasm_table_delete | | |
|
||||||
|
| | wasm_table_type | | |
|
||||||
|
| | wasm_table_get | | |
|
||||||
|
| | wasm_table_set | | |
|
||||||
|
| | wasm_table_size | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
| memory | wasm_memory_new | memory | |
|
||||||
|
| | wasm_memory_delete | | |
|
||||||
|
| | wasm_memory_type | | |
|
||||||
|
| | wasm_memory_data | | |
|
||||||
|
| | wasm_memory_data_size | | |
|
||||||
|
| | wasm_memory_size | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
| extern | wasm_extern_delete | extern | |
|
||||||
|
| | wasm_extern_as_XXX | | |
|
||||||
|
| | wasm_XXX_as_extern | | |
|
||||||
|
| | wasm_extern_kind | | |
|
||||||
|
| | wasm_extern_type | | |
|
||||||
|
| | _vector methods_ | | |
|
||||||
|
|
||||||
|
not supported _functions_
|
||||||
|
|
||||||
|
- wasm_config_XXX
|
||||||
|
- wasm_module_deserialize
|
||||||
|
- wasm_module_serialize
|
||||||
|
- wasm_ref_XXX
|
||||||
|
- wasm_XXX_as_ref
|
||||||
|
- wasm_XXX_as_ref_const
|
||||||
|
- wasm_XXX_copy
|
||||||
|
- wasm_XXX_get_host_info
|
||||||
|
- wasm_XXX_set_host_info
|
||||||
|
|
||||||
|
## test
|
||||||
|
|
||||||
|
there will be two kinds of tests in the project
|
||||||
|
|
||||||
|
- unit test. located in `./tests`. driven by _unittest_. run by
|
||||||
|
`$ python -m unittest` or `$ make test`.
|
||||||
|
- integration test. located in `./samples`.
|
||||||
|
|
||||||
|
The whole project is under test-driven development. Every wrapper function will
|
||||||
|
have two kinds of test cases. The first kind is a positive case. It checks a
|
||||||
|
wrapper function with expected and safe arguments combinations. Its goal is the
|
||||||
|
function should work well with expected inputs. Another kind is a negative
|
||||||
|
case. It feeds unexpected arguments combinations into a wrapper function. Arguments
|
||||||
|
should include but not be limited to `None`. It ensures that the function will
|
||||||
|
gracefully handle invalid input or unexpected behaviors.
|
||||||
|
|
||||||
|
## distribution
|
||||||
|
|
||||||
|
### package
|
||||||
|
|
||||||
|
Create a python package named `wamr`. Users should import it after installation
|
||||||
|
just like any other python module.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from wamr import *
|
||||||
|
```
|
||||||
|
|
||||||
|
### PyPI
|
||||||
|
|
||||||
|
Refer to [tutorial provided by PyPA](https://packaging.python.org/en/latest/tutorials/packaging-projects/).
|
||||||
|
Steps to publish WAMR Python library:
|
||||||
|
|
||||||
|
1. Creating `pyproject.toml` tells build tools (like pip and build) what is
|
||||||
|
required to build a project. An example .toml file uses _setuptools_
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[build-system]
|
||||||
|
requires = [
|
||||||
|
"setuptools>=42",
|
||||||
|
"wheel"
|
||||||
|
]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Configuring metadata tells build tools about a package (such as the name
|
||||||
|
and the version), as well as which code files to include
|
||||||
|
|
||||||
|
- Static metadata (`setup.cfg`): guaranteed to be the same every time.
|
||||||
|
It is simpler, easier to read, and avoids many common errors, like
|
||||||
|
encoding errors.
|
||||||
|
|
||||||
|
- Dynamic metadata (`setup.py`): possibly non-deterministic. Any items that
|
||||||
|
are dynamic or determined at install-time, as well as extension modules
|
||||||
|
or extensions to setuptools, need to go into setup.py.
|
||||||
|
|
||||||
|
**_Static metadata should be preferred_**. Dynamic metadata should be used
|
||||||
|
only as an escape hatch when necessary. setup.py used to be
|
||||||
|
required, but can be omitted with newer versions of setuptools and pip.
|
||||||
|
|
||||||
|
3. Including other files in the distribution
|
||||||
|
|
||||||
|
- For [source distribution](https://packaging.python.org/en/latest/glossary/#term-Source-Distribution-or-sdist):
|
||||||
|
|
||||||
|
It's usually generated using `python setup.py sdist`, providing metadata
|
||||||
|
and the essential source files needed for installing by a tool like pip,
|
||||||
|
or for generating a Built Distribution.
|
||||||
|
|
||||||
|
It includes our Python modules, pyproject.toml, metadata, README.md,
|
||||||
|
LICENSE. If you want to control what goes in this explicitly,
|
||||||
|
see [Including files in source distributions with MANIFEST.in](https://packaging.python.org/en/latest/guides/using-manifest-in/#using-manifest-in).
|
||||||
|
|
||||||
|
- For [final built distribution](https://packaging.python.org/en/latest/glossary/#term-Built-Distribution)
|
||||||
|
|
||||||
|
A Distribution format containing files and metadata that only need to be
|
||||||
|
moved to the correct location on the target system, to be installed.
|
||||||
|
e.g. `Wheel`
|
||||||
|
|
||||||
|
It will have the Python files in the discovered or listed Python packages.
|
||||||
|
If you want to control what goes here, such as to add data files,
|
||||||
|
see [Including Data Files](https://setuptools.pypa.io/en/latest/userguide/datafiles.html) from the [setuptools docs](https://setuptools.pypa.io/en/latest/index.html).
|
||||||
|
|
||||||
|
4. Generating distribution archives. These are archives that are uploaded to
|
||||||
|
the Python Package Index and can be installed by pip.
|
||||||
|
|
||||||
|
example using `setuptools`
|
||||||
|
|
||||||
|
```shell
|
||||||
|
python3 -m pip install --upgrade build
|
||||||
|
python3 -m build
|
||||||
|
```
|
||||||
|
|
||||||
|
generated files:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
dist/
|
||||||
|
WAMR-package-0.0.1-py3-none-any.whl
|
||||||
|
WAMR-package-0.0.1.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
The `tar.gz` file is a _source archive_ whereas the `.whl file` is a
|
||||||
|
_built distribution_. Newer pip versions preferentially install built
|
||||||
|
distributions but will fall back to source archives if needed. You should
|
||||||
|
always upload a source archive and provide built archives for compatibility
|
||||||
|
reasons.
|
||||||
|
|
||||||
|
5. Uploading the distribution archives
|
||||||
|
|
||||||
|
- Register an account on https://pypi.org.
|
||||||
|
- To securely upload your project, you’ll need a
|
||||||
|
[PyPI API token](https://pypi.org/help/#apitoken). It can create at
|
||||||
|
[here](https://pypi.org/manage/account/#api-tokens), and the “Scope”
|
||||||
|
the setting needs to be “Entire account”.
|
||||||
|
- After registration, now twine can be used to upload the distribution packages.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# install twine
|
||||||
|
python3 -m pip install --upgrade twine
|
||||||
|
# --repository is https://pypi.org/ by default.
|
||||||
|
# You will be prompted for a username and password. For the username, use __token__. For the password, use the token value, including the pypi- prefix.
|
||||||
|
twine upload dist/*
|
||||||
|
```
|
||||||
|
|
||||||
|
after all, the python binding will be installed with
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ pip install wamr
|
||||||
|
```
|
||||||
|
|
||||||
|
PS: A example lifecycle of a python package
|
||||||
|

|
||||||
|
|
||||||
|
## CI
|
||||||
|
|
||||||
|
There are several parts:
|
||||||
|
|
||||||
|
- code format check.
|
||||||
|
- test. include running all unit test cases and examples.
|
||||||
|
- publish built distribution.
|
Binary file not shown.
After Width: | Height: | Size: 75 KiB |
12
language-bindings/python/docs/setup_dev_env.md
Normal file
12
language-bindings/python/docs/setup_dev_env.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Use a python virtual environment tool to create an environment for development. All necessary packages are in _../requirements.txt_.
|
||||||
|
|
||||||
|
python code formatter is provided by _black_.
|
||||||
|
|
||||||
|
python code linter is provided by _pylint_ and default configuration.
|
||||||
|
|
||||||
|
Unit tests are driven by _unittest_.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ python -m unittest -v tests/test_basics.py
|
||||||
|
$ python -m unittest -v tests/test_advanced.py
|
||||||
|
```
|
3
language-bindings/python/pyproject.toml
Normal file
3
language-bindings/python/pyproject.toml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=42"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
5
language-bindings/python/requirements.txt
Normal file
5
language-bindings/python/requirements.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
black
|
||||||
|
nose
|
||||||
|
pycparser
|
||||||
|
pylint
|
||||||
|
|
4
language-bindings/python/samples/hello.wat
Normal file
4
language-bindings/python/samples/hello.wat
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
(module
|
||||||
|
(func $hello (import "" "hello"))
|
||||||
|
(func (export "run") (call $hello))
|
||||||
|
)
|
41
language-bindings/python/samples/hello_oop.py
Normal file
41
language-bindings/python/samples/hello_oop.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
#
|
||||||
|
import ctypes
|
||||||
|
from wamr import *
|
||||||
|
|
||||||
|
|
||||||
|
def hello_callback():
|
||||||
|
print("Calling back...")
|
||||||
|
print("> Hello World!")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("Initializing...")
|
||||||
|
engine = Engine()
|
||||||
|
store = Store(engine)
|
||||||
|
|
||||||
|
print("Loading binary...")
|
||||||
|
print("Compiling module...")
|
||||||
|
module = Module.from_file(engine, "./hello.wasm")
|
||||||
|
|
||||||
|
print("Creating callback...")
|
||||||
|
hello = Func(store, FuncType([], []), hello_callback)
|
||||||
|
|
||||||
|
print("Instantiating module...")
|
||||||
|
instance = Instance(store, module, [hello])
|
||||||
|
|
||||||
|
print("Extracting export...")
|
||||||
|
run = instance.exports(store)["run"]
|
||||||
|
|
||||||
|
print("Calling export...")
|
||||||
|
run(store)
|
||||||
|
|
||||||
|
print("Shutting down...")
|
||||||
|
print("Done.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
93
language-bindings/python/samples/hello_procedural.py
Normal file
93
language-bindings/python/samples/hello_procedural.py
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
#
|
||||||
|
import ctypes
|
||||||
|
import wamr.ffi as ffi
|
||||||
|
|
||||||
|
WAMS_BINARY_CONTENT = (
|
||||||
|
b"\x00asm\x01\x00\x00\x00\x01\x84\x80\x80\x80\x00\x01`\x00\x00\x02\x8a\x80"
|
||||||
|
b"\x80\x80\x00\x01\x00\x05hello\x00\x00\x03\x82\x80\x80\x80\x00\x01\x00"
|
||||||
|
b"\x07\x87\x80\x80\x80\x00\x01\x03run\x00\x01\n\x8a\x80\x80\x80\x00\x01"
|
||||||
|
b"\x84\x80\x80\x80\x00\x00\x10\x00\x0b"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.wasm_func_cb_decl
|
||||||
|
def hello_callback(args, results):
|
||||||
|
print("Calling back...")
|
||||||
|
print("> Hello World!")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("Initializing...")
|
||||||
|
engine = ffi.wasm_engine_new()
|
||||||
|
store = ffi.wasm_store_new(engine)
|
||||||
|
|
||||||
|
print("Loading binary...")
|
||||||
|
|
||||||
|
# for convenience, use binary content instead of open file
|
||||||
|
# with open("./hello.wasm", "rb") as f:
|
||||||
|
# wasm = f.read()
|
||||||
|
wasm = WAMS_BINARY_CONTENT
|
||||||
|
binary = ffi.wasm_byte_vec_t()
|
||||||
|
ffi.wasm_byte_vec_new_uninitialized(binary, len(wasm))
|
||||||
|
# underlying buffer is not writable
|
||||||
|
binary.data = (ctypes.c_ubyte * len(wasm)).from_buffer_copy(wasm)
|
||||||
|
|
||||||
|
print("Compiling module...")
|
||||||
|
module = ffi.wasm_module_new(store, binary)
|
||||||
|
if not module:
|
||||||
|
raise RuntimeError("Compiling module failed")
|
||||||
|
|
||||||
|
binary.data = None
|
||||||
|
ffi.wasm_byte_vec_delete(binary)
|
||||||
|
|
||||||
|
print("Creating callback...")
|
||||||
|
hello_type = ffi.wasm_functype_new_0_0()
|
||||||
|
hello_func = ffi.wasm_func_new(
|
||||||
|
store,
|
||||||
|
hello_type,
|
||||||
|
hello_callback,
|
||||||
|
)
|
||||||
|
|
||||||
|
ffi.wasm_functype_delete(hello_type)
|
||||||
|
|
||||||
|
print("Instantiating module...")
|
||||||
|
|
||||||
|
imports = ffi.wasm_extern_vec_t()
|
||||||
|
ffi.wasm_extern_vec_new((imports), 1, ffi.wasm_func_as_extern(hello_func))
|
||||||
|
instance = ffi.wasm_instance_new(store, module, imports, None)
|
||||||
|
|
||||||
|
ffi.wasm_func_delete(hello_func)
|
||||||
|
|
||||||
|
print("Extracting export...")
|
||||||
|
exports = ffi.wasm_extern_vec_t()
|
||||||
|
ffi.wasm_instance_exports(instance, exports)
|
||||||
|
|
||||||
|
run_func = ffi.wasm_extern_as_func(exports.data[0])
|
||||||
|
if not run_func:
|
||||||
|
raise RuntimeError("can not extract exported function")
|
||||||
|
|
||||||
|
ffi.wasm_instance_delete(instance)
|
||||||
|
ffi.wasm_module_delete(module)
|
||||||
|
|
||||||
|
print("Calling export...")
|
||||||
|
args = ffi.wasm_val_vec_t()
|
||||||
|
results = ffi.wasm_val_vec_t()
|
||||||
|
|
||||||
|
ffi.wasm_val_vec_new_empty(args)
|
||||||
|
ffi.wasm_val_vec_new_empty(results)
|
||||||
|
ffi.wasm_func_call(run_func, args, results)
|
||||||
|
|
||||||
|
print("Shutting down...")
|
||||||
|
ffi.wasm_store_delete(store)
|
||||||
|
ffi.wasm_engine_delete(engine)
|
||||||
|
|
||||||
|
print("Done.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
30
language-bindings/python/setup.py
Executable file
30
language-bindings/python/setup.py
Executable file
|
@ -0,0 +1,30 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
#
|
||||||
|
# pylint: disable=missing-class-docstring
|
||||||
|
# pylint: disable=missing-function-docstring
|
||||||
|
# pylint: disable=missing-module-docstring
|
||||||
|
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
|
||||||
|
with open("README.md") as f:
|
||||||
|
readme = f.read()
|
||||||
|
|
||||||
|
with open("LICENSE") as f:
|
||||||
|
license = f.read()
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="wamr-python",
|
||||||
|
version="0.1.0",
|
||||||
|
description="A WebAssembly runtime powered by WAMR",
|
||||||
|
long_description=readme,
|
||||||
|
author="The WAMR Project Developers",
|
||||||
|
author_email="hello@bytecodealliance.org",
|
||||||
|
url="https://github.com/bytecodealliance/wamr-python",
|
||||||
|
license=license,
|
||||||
|
packages=["wamr"],
|
||||||
|
)
|
7
language-bindings/python/tests/__init__.py
Normal file
7
language-bindings/python/tests/__init__.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
#
|
||||||
|
__all__ = ["test_basic", "test_advanced"]
|
13
language-bindings/python/tests/context.py
Normal file
13
language-bindings/python/tests/context.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
#
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||||
|
|
||||||
|
import wamr
|
525
language-bindings/python/tests/test_advanced.py
Normal file
525
language-bindings/python/tests/test_advanced.py
Normal file
|
@ -0,0 +1,525 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
#
|
||||||
|
# pylint: disable=missing-class-docstring
|
||||||
|
# pylint: disable=missing-function-docstring
|
||||||
|
# pylint: disable=missing-module-docstring
|
||||||
|
|
||||||
|
import ctypes as c
|
||||||
|
import math
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
import wamr.ffi as ffi
|
||||||
|
|
||||||
|
|
||||||
|
# It is a module likes:
|
||||||
|
# (module
|
||||||
|
# (import "mod" "g0" (global i32))
|
||||||
|
# (import "mod" "f0" (func (param f32) (result f64)))
|
||||||
|
#
|
||||||
|
# (func (export "f1") (param i32 i64))
|
||||||
|
# (global (export "g1") (mut f32) (f32.const 3.14))
|
||||||
|
# (memory (export "m1") 1 2)
|
||||||
|
# (table (export "t1") 1 funcref)
|
||||||
|
#
|
||||||
|
# (func (export "f2") (unreachable))
|
||||||
|
# )
|
||||||
|
MODULE_BINARY = (
|
||||||
|
b"\x00asm\x01\x00\x00\x00\x01\x0e\x03`\x01}\x01|`\x02\x7f~\x00`\x00"
|
||||||
|
b"\x00\x02\x14\x02\x03mod\x02g0\x03\x7f\x00\x03mod\x02f0\x00\x00\x03\x03"
|
||||||
|
b"\x02\x01\x02\x04\x04\x01p\x00\x01\x05\x04\x01\x01\x01\x02\x06\t\x01}\x01C"
|
||||||
|
b"\xc3\xf5H@\x0b\x07\x1a\x05\x02f1\x00\x01\x02g1\x03\x01\x02m1\x02\x00\x02t1"
|
||||||
|
b"\x01\x00\x02f2\x00\x02\n\x08\x02\x02\x00\x0b\x03\x00\x00\x0b"
|
||||||
|
)
|
||||||
|
|
||||||
|
# False -> True when testing with a library enabling WAMR_BUILD_DUMP_CALL_STACK flag
|
||||||
|
TEST_WITH_WAMR_BUILD_DUMP_CALL_STACK = False
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.wasm_func_cb_decl
|
||||||
|
def callback(args, results):
|
||||||
|
args = ffi.dereference(args)
|
||||||
|
results = ffi.dereference(results)
|
||||||
|
|
||||||
|
arg_v = args.data[0]
|
||||||
|
|
||||||
|
result_v = ffi.wasm_f64_val(arg_v.of.f32 * 2.0)
|
||||||
|
ffi.wasm_val_copy(results.data[0], result_v)
|
||||||
|
results.num_elems = 1
|
||||||
|
|
||||||
|
print(f"\nIn callback: {arg_v} --> {result_v}\n")
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.wasm_func_with_env_cb_decl
|
||||||
|
def callback_with_env(env, args, results):
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
print("summer")
|
||||||
|
|
||||||
|
|
||||||
|
class AdvancedTestSuite(unittest.TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
print("Initializing...")
|
||||||
|
cls._wasm_engine = ffi.wasm_engine_new()
|
||||||
|
cls._wasm_store = ffi.wasm_store_new(cls._wasm_engine)
|
||||||
|
|
||||||
|
def assertIsNullPointer(self, pointer):
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
if not ffi.is_null_pointer(pointer):
|
||||||
|
self.fail("not a non-null pointer")
|
||||||
|
|
||||||
|
def assertIsNotNullPointer(self, pointer):
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
if ffi.is_null_pointer(pointer):
|
||||||
|
self.fail("not a non-null pointer")
|
||||||
|
|
||||||
|
def load_binary(self, binary_string):
|
||||||
|
print("Load binary...")
|
||||||
|
binary = ffi.load_module_file(binary_string)
|
||||||
|
binary = c.pointer(binary)
|
||||||
|
self.assertIsNotNullPointer(binary)
|
||||||
|
return binary
|
||||||
|
|
||||||
|
def compile(self, binary):
|
||||||
|
print("Compile...")
|
||||||
|
module = ffi.wasm_module_new(self._wasm_store, binary)
|
||||||
|
self.assertIsNotNullPointer(module)
|
||||||
|
return module
|
||||||
|
|
||||||
|
def prepare_imports_local(self):
|
||||||
|
print("Prepare imports...")
|
||||||
|
func_type = ffi.wasm_functype_new_1_1(
|
||||||
|
ffi.wasm_valtype_new(ffi.WASM_F32),
|
||||||
|
ffi.wasm_valtype_new(ffi.WASM_F64),
|
||||||
|
)
|
||||||
|
func = ffi.wasm_func_new(self._wasm_store, func_type, callback)
|
||||||
|
self.assertIsNotNullPointer(func)
|
||||||
|
ffi.wasm_functype_delete(func_type)
|
||||||
|
|
||||||
|
glbl_type = ffi.wasm_globaltype_new(ffi.wasm_valtype_new(ffi.WASM_I32), True)
|
||||||
|
init = ffi.wasm_i32_val(1024)
|
||||||
|
glbl = ffi.wasm_global_new(self._wasm_store, glbl_type, init)
|
||||||
|
self.assertIsNotNullPointer(glbl)
|
||||||
|
ffi.wasm_globaltype_delete(glbl_type)
|
||||||
|
|
||||||
|
imports = ffi.wasm_extern_vec_t()
|
||||||
|
data = ffi.list_to_carray(
|
||||||
|
c.POINTER(ffi.wasm_extern_t),
|
||||||
|
ffi.wasm_func_as_extern(func),
|
||||||
|
ffi.wasm_global_as_extern(glbl),
|
||||||
|
)
|
||||||
|
ffi.wasm_extern_vec_new(imports, 2, data)
|
||||||
|
imports = c.pointer(imports)
|
||||||
|
self.assertIsNotNullPointer(imports)
|
||||||
|
return imports
|
||||||
|
|
||||||
|
def instantiate(self, module, imports):
|
||||||
|
print("Instantiate module...")
|
||||||
|
instance = ffi.wasm_instance_new(
|
||||||
|
self._wasm_store, module, imports, ffi.create_null_pointer(ffi.wasm_trap_t)
|
||||||
|
)
|
||||||
|
self.assertIsNotNone(instance)
|
||||||
|
self.assertIsNotNullPointer(instance)
|
||||||
|
return instance
|
||||||
|
|
||||||
|
def extract_exports(self, instance):
|
||||||
|
print("Extracting exports...")
|
||||||
|
exports = ffi.wasm_extern_vec_t()
|
||||||
|
ffi.wasm_instance_exports(instance, exports)
|
||||||
|
exports = c.pointer(exports)
|
||||||
|
self.assertIsNotNullPointer(exports)
|
||||||
|
return exports
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
binary = self.load_binary(MODULE_BINARY)
|
||||||
|
self.module = self.compile(binary)
|
||||||
|
self.imports = self.prepare_imports_local()
|
||||||
|
self.instance = self.instantiate(self.module, self.imports)
|
||||||
|
self.exports = self.extract_exports(self.instance)
|
||||||
|
|
||||||
|
ffi.wasm_byte_vec_delete(binary)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
if self.imports:
|
||||||
|
ffi.wasm_extern_vec_delete(self.imports)
|
||||||
|
|
||||||
|
if self.exports:
|
||||||
|
ffi.wasm_extern_vec_delete(self.exports)
|
||||||
|
|
||||||
|
ffi.wasm_instance_delete(self.instance)
|
||||||
|
ffi.wasm_module_delete(self.module)
|
||||||
|
|
||||||
|
def test_wasm_func_call_wasm(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
print(export_list)
|
||||||
|
|
||||||
|
func = ffi.wasm_extern_as_func(export_list[0])
|
||||||
|
self.assertIsNotNullPointer(func)
|
||||||
|
|
||||||
|
# make a call
|
||||||
|
params = ffi.wasm_val_vec_t()
|
||||||
|
data = ffi.list_to_carray(
|
||||||
|
ffi.wasm_val_t,
|
||||||
|
ffi.wasm_i32_val(1024),
|
||||||
|
ffi.wasm_i64_val(1024 * 1024),
|
||||||
|
)
|
||||||
|
ffi.wasm_val_vec_new(params, 2, data)
|
||||||
|
|
||||||
|
results = ffi.wasm_val_vec_t()
|
||||||
|
ffi.wasm_val_vec_new_empty(results)
|
||||||
|
|
||||||
|
ffi.wasm_func_call(func, params, results)
|
||||||
|
|
||||||
|
def test_wasm_func_call_native(self):
|
||||||
|
import_list = ffi.wasm_vec_to_list(self.imports)
|
||||||
|
|
||||||
|
func = ffi.wasm_extern_as_func(import_list[0])
|
||||||
|
self.assertIsNotNullPointer(func)
|
||||||
|
|
||||||
|
params = ffi.wasm_val_vec_t()
|
||||||
|
ffi.wasm_val_vec_new(
|
||||||
|
params, 1, ffi.list_to_carray(ffi.wasm_val_t, ffi.wasm_f32_val(3.14))
|
||||||
|
)
|
||||||
|
results = ffi.wasm_val_vec_t()
|
||||||
|
ffi.wasm_val_vec_new_uninitialized(results, 1)
|
||||||
|
ffi.wasm_func_call(func, params, results)
|
||||||
|
self.assertEqual(params.data[0].of.f32 * 2, results.data[0].of.f64)
|
||||||
|
|
||||||
|
def test_wasm_func_call_wrong_params(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
func = ffi.wasm_extern_as_func(export_list[0])
|
||||||
|
# make a call
|
||||||
|
params = ffi.wasm_val_vec_t()
|
||||||
|
ffi.wasm_val_vec_new_empty(params)
|
||||||
|
results = ffi.wasm_val_vec_t()
|
||||||
|
ffi.wasm_val_vec_new_empty(results)
|
||||||
|
trap = ffi.wasm_func_call(func, params, results)
|
||||||
|
|
||||||
|
self.assertIsNotNullPointer(trap)
|
||||||
|
|
||||||
|
def test_wasm_func_call_unlinked(self):
|
||||||
|
ft = ffi.wasm_functype_new_0_0()
|
||||||
|
func = ffi.wasm_func_new(self._wasm_store, ft, callback)
|
||||||
|
params = ffi.wasm_val_vec_t()
|
||||||
|
ffi.wasm_val_vec_new_empty(params)
|
||||||
|
results = ffi.wasm_val_vec_t()
|
||||||
|
ffi.wasm_val_vec_new_empty(results)
|
||||||
|
trap = ffi.wasm_func_call(func, params, results)
|
||||||
|
ffi.wasm_func_delete(func)
|
||||||
|
|
||||||
|
def test_wasm_global_get_wasm(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
glb = ffi.wasm_extern_as_global(export_list[1])
|
||||||
|
self.assertIsNotNullPointer(glb)
|
||||||
|
|
||||||
|
# access the global
|
||||||
|
val = ffi.wasm_val_t()
|
||||||
|
ffi.wasm_global_get(glb, val)
|
||||||
|
self.assertAlmostEqual(val.of.f32, 3.14, places=3)
|
||||||
|
|
||||||
|
def test_wasm_global_get_native(self):
|
||||||
|
import_list = ffi.wasm_vec_to_list(self.imports)
|
||||||
|
|
||||||
|
glb = ffi.wasm_extern_as_global(import_list[1])
|
||||||
|
self.assertIsNotNullPointer(glb)
|
||||||
|
|
||||||
|
val = ffi.wasm_val_t()
|
||||||
|
ffi.wasm_global_get(glb, val)
|
||||||
|
self.assertEqual(val.of.i32, 1024)
|
||||||
|
|
||||||
|
def test_wasm_global_get_unlinked(self):
|
||||||
|
gt = ffi.wasm_globaltype_new(ffi.wasm_valtype_new(ffi.WASM_I32), True)
|
||||||
|
init = ffi.wasm_i32_val(32)
|
||||||
|
glbl = ffi.wasm_global_new(self._wasm_store, gt, init)
|
||||||
|
val_ret = ffi.wasm_f32_val(3.14)
|
||||||
|
ffi.wasm_global_get(glbl, val_ret)
|
||||||
|
ffi.wasm_global_delete(glbl)
|
||||||
|
|
||||||
|
# val_ret wasn't touched, keep the original value
|
||||||
|
self.assertAlmostEqual(val_ret.of.f32, 3.14, 3)
|
||||||
|
|
||||||
|
def test_wasm_global_get_null_val(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
glb = ffi.wasm_extern_as_global(export_list[1])
|
||||||
|
ffi.wasm_global_get(glb, ffi.create_null_pointer(ffi.wasm_val_t))
|
||||||
|
|
||||||
|
def test_wasm_global_get_null_global(self):
|
||||||
|
val = ffi.wasm_val_t()
|
||||||
|
ffi.wasm_global_get(ffi.create_null_pointer(ffi.wasm_global_t), val)
|
||||||
|
|
||||||
|
def test_wasm_global_set_wasm(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
glb = ffi.wasm_extern_as_global(export_list[1])
|
||||||
|
self.assertIsNotNullPointer(glb)
|
||||||
|
|
||||||
|
# access the global
|
||||||
|
new_val = ffi.wasm_f32_val(math.e)
|
||||||
|
ffi.wasm_global_set(glb, new_val)
|
||||||
|
|
||||||
|
val = ffi.wasm_val_t()
|
||||||
|
ffi.wasm_global_get(glb, val)
|
||||||
|
self.assertNotEqual(val.of.f32, 3.14)
|
||||||
|
|
||||||
|
def test_wasm_global_set_native(self):
|
||||||
|
import_list = ffi.wasm_vec_to_list(self.imports)
|
||||||
|
|
||||||
|
glb = ffi.wasm_extern_as_global(import_list[1])
|
||||||
|
self.assertIsNotNullPointer(glb)
|
||||||
|
|
||||||
|
new_val = ffi.wasm_i32_val(2048)
|
||||||
|
ffi.wasm_global_set(glb, new_val)
|
||||||
|
|
||||||
|
val = ffi.wasm_val_t()
|
||||||
|
ffi.wasm_global_get(glb, val)
|
||||||
|
self.assertEqual(val, new_val)
|
||||||
|
|
||||||
|
def test_wasm_global_set_unlinked(self):
|
||||||
|
gt = ffi.wasm_globaltype_new(ffi.wasm_valtype_new(ffi.WASM_I32), True)
|
||||||
|
init = ffi.wasm_i32_val(32)
|
||||||
|
glbl = ffi.wasm_global_new(self._wasm_store, gt, init)
|
||||||
|
val_ret = ffi.wasm_f32_val(3.14)
|
||||||
|
ffi.wasm_global_set(glbl, val_ret)
|
||||||
|
ffi.wasm_global_delete(glbl)
|
||||||
|
|
||||||
|
def test_wasm_global_set_null_v(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
glb = ffi.wasm_extern_as_global(export_list[1])
|
||||||
|
# access the global
|
||||||
|
ffi.wasm_global_set(glb, ffi.create_null_pointer(ffi.wasm_val_t))
|
||||||
|
|
||||||
|
def test_wasm_global_set_null_global(self):
|
||||||
|
# access the global
|
||||||
|
new_val = ffi.wasm_f32_val(math.e)
|
||||||
|
ffi.wasm_global_set(ffi.create_null_pointer(ffi.wasm_global_t), new_val)
|
||||||
|
|
||||||
|
def test_wasm_table_size(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
tbl = ffi.wasm_extern_as_table(export_list[3])
|
||||||
|
self.assertIsNotNullPointer(tbl)
|
||||||
|
|
||||||
|
tbl_sz = ffi.wasm_table_size(tbl)
|
||||||
|
self.assertEqual(tbl_sz, 1)
|
||||||
|
|
||||||
|
def test_wasm_table_size_unlink(self):
|
||||||
|
vt = ffi.wasm_valtype_new(ffi.WASM_FUNCREF)
|
||||||
|
limits = ffi.wasm_limits_new(10, 15)
|
||||||
|
tt = ffi.wasm_tabletype_new(vt, limits)
|
||||||
|
tbl = ffi.wasm_table_new(
|
||||||
|
self._wasm_store, tt, ffi.create_null_pointer(ffi.wasm_ref_t)
|
||||||
|
)
|
||||||
|
tbl_sz = ffi.wasm_table_size(tbl)
|
||||||
|
ffi.wasm_table_delete(tbl)
|
||||||
|
|
||||||
|
def test_wasm_table_size_null_table(self):
|
||||||
|
ffi.wasm_table_size(ffi.create_null_pointer(ffi.wasm_table_t))
|
||||||
|
|
||||||
|
def test_wasm_table_get(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
tbl = ffi.wasm_extern_as_table(export_list[3])
|
||||||
|
self.assertIsNotNullPointer(tbl)
|
||||||
|
|
||||||
|
ref = ffi.wasm_table_get(tbl, 0)
|
||||||
|
self.assertIsNullPointer(ref)
|
||||||
|
|
||||||
|
ref = ffi.wasm_table_get(tbl, 4096)
|
||||||
|
self.assertIsNullPointer(ref)
|
||||||
|
|
||||||
|
def test_wasm_table_get_unlinked(self):
|
||||||
|
vt = ffi.wasm_valtype_new(ffi.WASM_FUNCREF)
|
||||||
|
limits = ffi.wasm_limits_new(10, 15)
|
||||||
|
tt = ffi.wasm_tabletype_new(vt, limits)
|
||||||
|
tbl = ffi.wasm_table_new(
|
||||||
|
self._wasm_store, tt, ffi.create_null_pointer(ffi.wasm_ref_t)
|
||||||
|
)
|
||||||
|
ffi.wasm_table_get(tbl, 0)
|
||||||
|
ffi.wasm_table_delete(tbl)
|
||||||
|
|
||||||
|
def test_wasm_table_get_null_table(self):
|
||||||
|
ffi.wasm_table_get(ffi.create_null_pointer(ffi.wasm_table_t), 0)
|
||||||
|
|
||||||
|
def test_wasm_table_get_out_of_bounds(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
tbl = ffi.wasm_extern_as_table(export_list[3])
|
||||||
|
ffi.wasm_table_get(tbl, 1_000_000_000)
|
||||||
|
|
||||||
|
def test_wasm_ref(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
func = ffi.wasm_extern_as_func(export_list[0])
|
||||||
|
self.assertIsNotNullPointer(func)
|
||||||
|
|
||||||
|
ref = ffi.wasm_func_as_ref(func)
|
||||||
|
self.assertIsNotNullPointer(ref)
|
||||||
|
|
||||||
|
func_from_ref = ffi.wasm_ref_as_func(ref)
|
||||||
|
self.assertEqual(
|
||||||
|
ffi.dereference(ffi.wasm_func_type(func)),
|
||||||
|
ffi.dereference(ffi.wasm_func_type(func_from_ref)),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_wasm_table_set(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
tbl = ffi.wasm_extern_as_table(export_list[3])
|
||||||
|
self.assertIsNotNullPointer(tbl)
|
||||||
|
|
||||||
|
func = ffi.wasm_extern_as_func(export_list[0])
|
||||||
|
ref = ffi.wasm_func_as_ref(func)
|
||||||
|
|
||||||
|
ffi.wasm_table_set(tbl, 0, ref)
|
||||||
|
|
||||||
|
ref_ret = ffi.wasm_table_get(tbl, 0)
|
||||||
|
self.assertIsNotNullPointer(ref_ret)
|
||||||
|
func_ret = ffi.wasm_ref_as_func(ref_ret)
|
||||||
|
self.assertEqual(
|
||||||
|
ffi.dereference(ffi.wasm_func_type(func)),
|
||||||
|
ffi.dereference(ffi.wasm_func_type(func_ret)),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_wasm_table_set_unlinked(self):
|
||||||
|
vt = ffi.wasm_valtype_new(ffi.WASM_FUNCREF)
|
||||||
|
limits = ffi.wasm_limits_new(10, 15)
|
||||||
|
tt = ffi.wasm_tabletype_new(vt, limits)
|
||||||
|
tbl = ffi.wasm_table_new(
|
||||||
|
self._wasm_store, tt, ffi.create_null_pointer(ffi.wasm_ref_t)
|
||||||
|
)
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
func = ffi.wasm_extern_as_func(export_list[0])
|
||||||
|
ref = ffi.wasm_func_as_ref(func)
|
||||||
|
ffi.wasm_table_set(tbl, 0, ref)
|
||||||
|
ffi.wasm_table_delete(tbl)
|
||||||
|
|
||||||
|
def test_wasm_table_set_null_table(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
func = ffi.wasm_extern_as_func(export_list[0])
|
||||||
|
ref = ffi.wasm_func_as_ref(func)
|
||||||
|
ffi.wasm_table_set(ffi.create_null_pointer(ffi.wasm_table_t), 0, ref)
|
||||||
|
|
||||||
|
def test_wasm_table_set_null_ref(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
tbl = ffi.wasm_extern_as_table(export_list[3])
|
||||||
|
ffi.wasm_table_set(tbl, 0, ffi.create_null_pointer(ffi.wasm_ref_t))
|
||||||
|
|
||||||
|
def test_wasm_table_set_out_of_bounds(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
tbl = ffi.wasm_extern_as_table(export_list[3])
|
||||||
|
func = ffi.wasm_extern_as_func(export_list[0])
|
||||||
|
ref = ffi.wasm_func_as_ref(func)
|
||||||
|
ffi.wasm_table_set(tbl, 1_000_000_000, ref)
|
||||||
|
|
||||||
|
def test_wasm_memory_size(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
mem = ffi.wasm_extern_as_memory(export_list[2])
|
||||||
|
self.assertIsNotNullPointer(mem)
|
||||||
|
|
||||||
|
pg_sz = ffi.wasm_memory_size(mem)
|
||||||
|
self.assertEqual(pg_sz, 1)
|
||||||
|
|
||||||
|
def test_wasm_memory_size_unlinked(self):
|
||||||
|
limits = ffi.wasm_limits_new(10, 12)
|
||||||
|
mt = ffi.wasm_memorytype_new(limits)
|
||||||
|
mem = ffi.wasm_memory_new(self._wasm_store, mt)
|
||||||
|
ffi.wasm_memory_size(mem)
|
||||||
|
ffi.wasm_memory_delete(mem)
|
||||||
|
|
||||||
|
def test_wasm_memory_data(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
mem = ffi.wasm_extern_as_memory(export_list[2])
|
||||||
|
self.assertIsNotNullPointer(mem)
|
||||||
|
|
||||||
|
data_base = ffi.wasm_memory_data(mem)
|
||||||
|
self.assertIsNotNone(data_base)
|
||||||
|
|
||||||
|
def test_wasm_memory_data_unlinked(self):
|
||||||
|
limits = ffi.wasm_limits_new(10, 12)
|
||||||
|
mt = ffi.wasm_memorytype_new(limits)
|
||||||
|
mem = ffi.wasm_memory_new(self._wasm_store, mt)
|
||||||
|
ffi.wasm_memory_data(mem)
|
||||||
|
ffi.wasm_memory_delete(mem)
|
||||||
|
|
||||||
|
def test_wasm_memory_data_size(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
mem = ffi.wasm_extern_as_memory(export_list[2])
|
||||||
|
self.assertIsNotNullPointer(mem)
|
||||||
|
|
||||||
|
mem_sz = ffi.wasm_memory_data_size(mem)
|
||||||
|
self.assertGreater(mem_sz, 0)
|
||||||
|
|
||||||
|
def test_wasm_memory_data_size_unlinked(self):
|
||||||
|
limits = ffi.wasm_limits_new(10, 12)
|
||||||
|
mt = ffi.wasm_memorytype_new(limits)
|
||||||
|
mem = ffi.wasm_memory_new(self._wasm_store, mt)
|
||||||
|
ffi.wasm_memory_data_size(mem)
|
||||||
|
ffi.wasm_memory_delete(mem)
|
||||||
|
|
||||||
|
def test_wasm_trap(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
func = ffi.wasm_extern_as_func(export_list[0])
|
||||||
|
# make a call
|
||||||
|
params = ffi.wasm_val_vec_t()
|
||||||
|
ffi.wasm_val_vec_new_empty(params)
|
||||||
|
results = ffi.wasm_val_vec_t()
|
||||||
|
ffi.wasm_val_vec_new_empty(results)
|
||||||
|
|
||||||
|
trap = ffi.wasm_func_call(func, params, results)
|
||||||
|
self.assertIsNotNullPointer(trap)
|
||||||
|
|
||||||
|
message = ffi.wasm_message_t()
|
||||||
|
ffi.wasm_trap_message(trap, message)
|
||||||
|
self.assertIsNotNullPointer(c.pointer(message))
|
||||||
|
|
||||||
|
# not a function internal exception
|
||||||
|
frame = ffi.wasm_trap_origin(trap)
|
||||||
|
self.assertIsNullPointer(frame)
|
||||||
|
|
||||||
|
@unittest.skipUnless(
|
||||||
|
TEST_WITH_WAMR_BUILD_DUMP_CALL_STACK,
|
||||||
|
"need to enable WAMR_BUILD_DUMP_CALL_STACK",
|
||||||
|
)
|
||||||
|
# assertions only works if enabling WAMR_BUILD_DUMP_CALL_STACK
|
||||||
|
def test_wasm_frame(self):
|
||||||
|
export_list = ffi.wasm_vec_to_list(self.exports)
|
||||||
|
func = ffi.wasm_extern_as_func(export_list[4])
|
||||||
|
# make a call
|
||||||
|
params = ffi.wasm_val_vec_t()
|
||||||
|
ffi.wasm_val_vec_new_empty(params)
|
||||||
|
results = ffi.wasm_val_vec_t()
|
||||||
|
ffi.wasm_val_vec_new_empty(results)
|
||||||
|
|
||||||
|
print("Making a call...")
|
||||||
|
trap = ffi.wasm_func_call(func, params, results)
|
||||||
|
|
||||||
|
message = ffi.wasm_message_t()
|
||||||
|
ffi.wasm_trap_message(trap, message)
|
||||||
|
self.assertIsNotNullPointer(c.pointer(message))
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
frame = ffi.wasm_trap_origin(trap)
|
||||||
|
self.assertIsNotNullPointer(frame)
|
||||||
|
print(ffi.dereference(frame))
|
||||||
|
|
||||||
|
traces = ffi.wasm_frame_vec_t()
|
||||||
|
ffi.wasm_trap_trace(trap, traces)
|
||||||
|
self.assertIsNotNullPointer(c.pointer(frame))
|
||||||
|
|
||||||
|
instance = ffi.wasm_frame_instance(frame)
|
||||||
|
self.assertIsNotNullPointer(instance)
|
||||||
|
|
||||||
|
module_offset = ffi.wasm_frame_module_offset(frame)
|
||||||
|
|
||||||
|
func_index = ffi.wasm_frame_func_index(frame)
|
||||||
|
self.assertEqual(func_index, 2)
|
||||||
|
|
||||||
|
func_offset = ffi.wasm_frame_func_offset(frame)
|
||||||
|
self.assertGreater(func_offset, 0)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
print("Shutting down...")
|
||||||
|
ffi.wasm_store_delete(cls._wasm_store)
|
||||||
|
ffi.wasm_engine_delete(cls._wasm_engine)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
1588
language-bindings/python/tests/test_basic.py
Normal file
1588
language-bindings/python/tests/test_basic.py
Normal file
File diff suppressed because it is too large
Load Diff
386
language-bindings/python/utils/bindgen.py
Normal file
386
language-bindings/python/utils/bindgen.py
Normal file
|
@ -0,0 +1,386 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
#
|
||||||
|
# pylint: disable=missing-class-docstring
|
||||||
|
# pylint: disable=missing-function-docstring
|
||||||
|
# pylint: disable=missing-module-docstring
|
||||||
|
|
||||||
|
"""
|
||||||
|
- Need to run *download_wamr.py* firstly.
|
||||||
|
- Parse *./wasm-micro-runtime/core/iwasm/include/wasm_c_api.h* and generate
|
||||||
|
*wamr/binding.py*
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from pycparser import c_ast, parse_file
|
||||||
|
|
||||||
|
WASM_C_API_HEADER = "core/iwasm/include/wasm_c_api.h"
|
||||||
|
BINDING_PATH = "wamr/binding.py"
|
||||||
|
# 4 spaces as default indent
|
||||||
|
INDENT = " "
|
||||||
|
|
||||||
|
IGNORE_SYMOLS = (
|
||||||
|
"wasm_engine_new_with_args",
|
||||||
|
"wasm_valkind_is_num",
|
||||||
|
"wasm_valkind_is_ref",
|
||||||
|
"wasm_valtype_is_num",
|
||||||
|
"wasm_valtype_is_ref",
|
||||||
|
"wasm_valtype_new_i32",
|
||||||
|
"wasm_valtype_new_i64",
|
||||||
|
"wasm_valtype_new_f32",
|
||||||
|
"wasm_valtype_new_f64",
|
||||||
|
"wasm_valtype_new_anyref",
|
||||||
|
"wasm_valtype_new_funcref",
|
||||||
|
"wasm_functype_new_0_0",
|
||||||
|
"wasm_functype_new_0_0",
|
||||||
|
"wasm_functype_new_1_0",
|
||||||
|
"wasm_functype_new_2_0",
|
||||||
|
"wasm_functype_new_3_0",
|
||||||
|
"wasm_functype_new_0_1",
|
||||||
|
"wasm_functype_new_1_1",
|
||||||
|
"wasm_functype_new_2_1",
|
||||||
|
"wasm_functype_new_3_1",
|
||||||
|
"wasm_functype_new_0_2",
|
||||||
|
"wasm_functype_new_1_2",
|
||||||
|
"wasm_functype_new_2_2",
|
||||||
|
"wasm_functype_new_3_2",
|
||||||
|
"wasm_val_init_ptr",
|
||||||
|
"wasm_val_ptr",
|
||||||
|
"wasm_val_t",
|
||||||
|
"wasm_ref_t",
|
||||||
|
"wasm_name_new_from_string",
|
||||||
|
"wasm_name_new_from_string_nt",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Visitor(c_ast.NodeVisitor):
|
||||||
|
def __init__(self):
|
||||||
|
self.type_map = {
|
||||||
|
"_Bool": "c_bool",
|
||||||
|
"byte_t": "c_ubyte",
|
||||||
|
"char": "c_char",
|
||||||
|
"errno_t": "c_int",
|
||||||
|
"int": "c_int",
|
||||||
|
"long": "c_long",
|
||||||
|
"size_t": "c_size_t",
|
||||||
|
"uint32_t": "c_uint32",
|
||||||
|
"uint8_t": "c_uint8",
|
||||||
|
"void": "None",
|
||||||
|
}
|
||||||
|
self.ret = (
|
||||||
|
"# -*- coding: utf-8 -*-\n"
|
||||||
|
"#!/usr/bin/env python3\n"
|
||||||
|
"#\n"
|
||||||
|
"# Copyright (C) 2019 Intel Corporation. All rights reserved.\n"
|
||||||
|
"# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
|
||||||
|
"#\n"
|
||||||
|
"#It is a generated file. DO NOT EDIT.\n"
|
||||||
|
"#\n"
|
||||||
|
"from ctypes import *\n"
|
||||||
|
"\n"
|
||||||
|
"from .ffi import dereference, libiwasm, wasm_ref_t, wasm_val_t\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_type_name(self, c_type):
|
||||||
|
if isinstance(c_type, c_ast.TypeDecl):
|
||||||
|
return self.get_type_name(c_type.type)
|
||||||
|
elif isinstance(c_type, c_ast.PtrDecl):
|
||||||
|
pointed_type = self.get_type_name(c_type.type)
|
||||||
|
|
||||||
|
if isinstance(c_type.type, c_ast.FuncDecl):
|
||||||
|
# CFUCNTYPE is a pointer of function
|
||||||
|
return pointed_type
|
||||||
|
|
||||||
|
if "None" == pointed_type:
|
||||||
|
return "c_void_p"
|
||||||
|
|
||||||
|
return f"POINTER({pointed_type})"
|
||||||
|
|
||||||
|
elif isinstance(c_type, c_ast.ArrayDecl):
|
||||||
|
return f"POINTER({self.get_type_name(c_type.type)})"
|
||||||
|
elif isinstance(c_type, c_ast.IdentifierType):
|
||||||
|
if len(c_type.names) > 1:
|
||||||
|
raise RuntimeError(f"unexpected type with a long names: {c_type}")
|
||||||
|
|
||||||
|
type_name = c_type.names[0]
|
||||||
|
|
||||||
|
if type_name.startswith("wasm_"):
|
||||||
|
return type_name
|
||||||
|
|
||||||
|
if not type_name in self.type_map:
|
||||||
|
raise RuntimeError(f"a new type should be in type_map: {type_name}")
|
||||||
|
|
||||||
|
return self.type_map.get(type_name)
|
||||||
|
elif isinstance(c_type, c_ast.Union):
|
||||||
|
if not c_type.name:
|
||||||
|
raise RuntimeError(f"found an anonymous union {c_type}")
|
||||||
|
|
||||||
|
return c_type.name
|
||||||
|
elif isinstance(c_type, c_ast.Struct):
|
||||||
|
if not c_type.name:
|
||||||
|
raise RuntimeError(f"found an anonymous union {c_type}")
|
||||||
|
|
||||||
|
return c_type.name
|
||||||
|
elif isinstance(c_type, c_ast.FuncDecl):
|
||||||
|
content = "CFUNCTYPE("
|
||||||
|
if isinstance(c_type.type, c_ast.PtrDecl):
|
||||||
|
# there is a bug in CFUNCTYPE if the result type is a pointer
|
||||||
|
content += "c_void_p"
|
||||||
|
else:
|
||||||
|
content += f"{self.get_type_name(c_type.type)}"
|
||||||
|
content += f",{self.get_type_name(c_type.args)}" if c_type.args else ""
|
||||||
|
content += ")"
|
||||||
|
return content
|
||||||
|
elif isinstance(c_type, c_ast.Decl):
|
||||||
|
return self.get_type_name(c_type.type)
|
||||||
|
elif isinstance(c_type, c_ast.ParamList):
|
||||||
|
content = ",".join(
|
||||||
|
[self.get_type_name(param.type) for param in c_type.params]
|
||||||
|
)
|
||||||
|
return content
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"unexpected type: {c_type.show()}")
|
||||||
|
|
||||||
|
def visit_Struct(self, node):
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
def gen_fields(info, indent):
|
||||||
|
content = ""
|
||||||
|
for k, v in info.items():
|
||||||
|
content += f'{indent}("{k}", {v}),\n'
|
||||||
|
return content[:-1]
|
||||||
|
|
||||||
|
def gen_equal(info, indent):
|
||||||
|
content = f"{indent}return"
|
||||||
|
for k, v in info.items():
|
||||||
|
# not compare pointer value in __eq__
|
||||||
|
if v.startswith("POINTER") or v.startswith("c_void_p"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
content += f" self.{k} == other.{k} and"
|
||||||
|
return content[:-4]
|
||||||
|
|
||||||
|
def gen_repr(info, indent):
|
||||||
|
content = f'{indent}return f"{{{{'
|
||||||
|
for k, _ in info.items():
|
||||||
|
content += f"{k}={{self.{k}}}, "
|
||||||
|
content = content[:-2] + '}}"'
|
||||||
|
return content
|
||||||
|
|
||||||
|
def gen_vector_repr(info, indent):
|
||||||
|
content = f'{indent}ret = ""\n'
|
||||||
|
content += f"{indent}for i in range(self.num_elems):\n"
|
||||||
|
|
||||||
|
if 1 == info["data"].count("POINTER"):
|
||||||
|
# pointer
|
||||||
|
content += f"{2*indent}ret += str(self.data[i])\n"
|
||||||
|
else:
|
||||||
|
# pointer of pointer
|
||||||
|
content += f"{2*indent}ret += str(dereference(self.data[i]))\n"
|
||||||
|
|
||||||
|
content += f'{2*indent}ret += " "\n'
|
||||||
|
content += f"{indent}return ret\n"
|
||||||
|
return content
|
||||||
|
|
||||||
|
if not node.name or not node.name.lower().startswith("wasm"):
|
||||||
|
return
|
||||||
|
|
||||||
|
if node.name in IGNORE_SYMOLS:
|
||||||
|
return
|
||||||
|
|
||||||
|
name = node.name
|
||||||
|
|
||||||
|
info = {}
|
||||||
|
if node.decls:
|
||||||
|
for decl in node.decls:
|
||||||
|
info[decl.name] = self.get_type_name(decl.type)
|
||||||
|
|
||||||
|
if info:
|
||||||
|
self.ret += (
|
||||||
|
f"class {name}(Structure):\n"
|
||||||
|
f"{INDENT}_fields_ = [\n"
|
||||||
|
f"{gen_fields(info, INDENT*2)}\n"
|
||||||
|
f"{INDENT}]\n"
|
||||||
|
f"\n"
|
||||||
|
f"{INDENT}def __eq__(self, other):\n"
|
||||||
|
f"{INDENT*2}if not isinstance(other, {name}):\n"
|
||||||
|
f"{INDENT*3}return False\n"
|
||||||
|
f"{gen_equal(info, INDENT*2)}\n"
|
||||||
|
f"\n"
|
||||||
|
f"{INDENT}def __repr__(self):\n"
|
||||||
|
)
|
||||||
|
self.ret += (
|
||||||
|
f"{gen_vector_repr(info, INDENT*2)}\n"
|
||||||
|
if name.endswith("_vec_t")
|
||||||
|
else f"{gen_repr(info, INDENT*2)}\n"
|
||||||
|
)
|
||||||
|
self.ret += "\n"
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.ret += f"class {name}(Structure):\n{INDENT}pass\n"
|
||||||
|
|
||||||
|
self.ret += "\n"
|
||||||
|
|
||||||
|
def visit_Union(self, node):
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
print(f"Union: {node.show()}")
|
||||||
|
|
||||||
|
def visit_Typedef(self, node):
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
# system defined
|
||||||
|
if not node.name:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not node.name.startswith("wasm_"):
|
||||||
|
return
|
||||||
|
|
||||||
|
if node.name in IGNORE_SYMOLS:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.visit(node.type)
|
||||||
|
|
||||||
|
if node.name == self.get_type_name(node.type):
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.ret += f"{node.name} = {self.get_type_name(node.type)}\n"
|
||||||
|
self.ret += "\n"
|
||||||
|
|
||||||
|
def visit_FuncDecl(self, node):
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
restype = self.get_type_name(node.type)
|
||||||
|
|
||||||
|
if isinstance(node.type, c_ast.TypeDecl):
|
||||||
|
func_name = node.type.declname
|
||||||
|
elif isinstance(node.type, c_ast.PtrDecl):
|
||||||
|
func_name = node.type.type.declname
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"unexpected type in FuncDecl: {type}")
|
||||||
|
|
||||||
|
if not func_name.startswith("wasm_") or func_name.endswith("_t"):
|
||||||
|
return
|
||||||
|
|
||||||
|
if func_name in IGNORE_SYMOLS:
|
||||||
|
return
|
||||||
|
|
||||||
|
params_len = 0
|
||||||
|
for arg in node.args.params:
|
||||||
|
# ignore void but not void*
|
||||||
|
if isinstance(arg.type, c_ast.TypeDecl):
|
||||||
|
type_name = self.get_type_name(arg.type)
|
||||||
|
if "None" == type_name:
|
||||||
|
continue
|
||||||
|
|
||||||
|
params_len += 1
|
||||||
|
|
||||||
|
args = (
|
||||||
|
"" if not params_len else ",".join([f"arg{i}" for i in range(params_len)])
|
||||||
|
)
|
||||||
|
argtypes = f"[{self.get_type_name(node.args)}]" if params_len else "None"
|
||||||
|
|
||||||
|
self.ret += (
|
||||||
|
f"def {func_name}({args}):\n"
|
||||||
|
f"{INDENT}_{func_name} = libiwasm.{func_name}\n"
|
||||||
|
f"{INDENT}_{func_name}.restype = {restype}\n"
|
||||||
|
f"{INDENT}_{func_name}.argtypes = {argtypes}\n"
|
||||||
|
f"{INDENT}return _{func_name}({args})\n"
|
||||||
|
)
|
||||||
|
self.ret += "\n"
|
||||||
|
|
||||||
|
def visit_Enum(self, node):
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
elem_value = 0
|
||||||
|
# generate enum elementes directly as consts with values
|
||||||
|
for i, elem in enumerate(node.values.enumerators):
|
||||||
|
self.ret += f"{elem.name}"
|
||||||
|
|
||||||
|
if elem.value:
|
||||||
|
elem_value = int(elem.value.value)
|
||||||
|
else:
|
||||||
|
if 0 == i:
|
||||||
|
elem_value = 0
|
||||||
|
else:
|
||||||
|
elem_value += 1
|
||||||
|
|
||||||
|
self.ret += f" = {elem_value}\n"
|
||||||
|
|
||||||
|
self.ret += "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def preflight_check(workspace):
|
||||||
|
wamr_repo = workspace.joinpath("wasm-micro-runtime")
|
||||||
|
file_check_list = [
|
||||||
|
wamr_repo.exists(),
|
||||||
|
wamr_repo.joinpath(WASM_C_API_HEADER).exists(),
|
||||||
|
]
|
||||||
|
|
||||||
|
if not all(file_check_list):
|
||||||
|
print(
|
||||||
|
"please run utils/download_wamr.py to download the repo, or re-download the repo"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not shutil.which("gcc"):
|
||||||
|
print("please install gcc")
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def do_parse(workspace):
|
||||||
|
filename = workspace.joinpath(WASM_C_API_HEADER)
|
||||||
|
filename = str(filename)
|
||||||
|
|
||||||
|
ast = parse_file(
|
||||||
|
filename,
|
||||||
|
use_cpp=True,
|
||||||
|
cpp_path="gcc",
|
||||||
|
cpp_args=[
|
||||||
|
"-E",
|
||||||
|
"-D__attribute__(x)=",
|
||||||
|
"-D__asm__(x)=",
|
||||||
|
"-D__asm(x)=",
|
||||||
|
"-D__builtin_va_list=int",
|
||||||
|
"-D__extension__=",
|
||||||
|
"-D__inline__=",
|
||||||
|
"-D__restrict=",
|
||||||
|
"-D__restrict__=",
|
||||||
|
"-D_Static_assert(x, y)=",
|
||||||
|
"-D__signed=",
|
||||||
|
"-D__volatile__(x)=",
|
||||||
|
"-Dstatic_assert(x, y)=",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
ast_visitor = Visitor()
|
||||||
|
ast_visitor.visit(ast)
|
||||||
|
return ast_visitor.ret
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
current_file = pathlib.Path(__file__)
|
||||||
|
if current_file.is_symlink():
|
||||||
|
current_file = pathlib.Path(os.readlink(current_file))
|
||||||
|
|
||||||
|
current_dir = current_file.parent.resolve()
|
||||||
|
root_dir = current_dir.joinpath("..").resolve()
|
||||||
|
|
||||||
|
if not preflight_check(root_dir):
|
||||||
|
return False
|
||||||
|
|
||||||
|
wamr_repo = root_dir.joinpath("wasm-micro-runtime")
|
||||||
|
binding_file_path = root_dir.joinpath(BINDING_PATH)
|
||||||
|
with open(binding_file_path, "wt", encoding="utf-8") as binding_file:
|
||||||
|
binding_file.write(do_parse(wamr_repo))
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(0 if main() else 1)
|
7
language-bindings/python/wamr/__init__.py
Normal file
7
language-bindings/python/wamr/__init__.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
#
|
||||||
|
__all__ = ["ffi"]
|
2020
language-bindings/python/wamr/binding.py
Normal file
2020
language-bindings/python/wamr/binding.py
Normal file
File diff suppressed because it is too large
Load Diff
642
language-bindings/python/wamr/ffi.py
Normal file
642
language-bindings/python/wamr/ffi.py
Normal file
|
@ -0,0 +1,642 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
#
|
||||||
|
# pylint: disable=missing-class-docstring
|
||||||
|
# pylint: disable=missing-function-docstring
|
||||||
|
# pylint: disable=missing-module-docstring
|
||||||
|
|
||||||
|
import ctypes as c
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
#
|
||||||
|
# Prologue. Dependencies of binding
|
||||||
|
#
|
||||||
|
|
||||||
|
# how to open the library file of WAMR
|
||||||
|
|
||||||
|
if sys.platform == "linux":
|
||||||
|
BUILDING_DIR = "product-mini/platforms/linux/build"
|
||||||
|
LIBRARY_NAME = "libiwasm.so"
|
||||||
|
elif sys.platform == "win32":
|
||||||
|
BUILDING_DIR = "product-mini/platforms/windows/build"
|
||||||
|
LIBRARY_NAME = "iwasm.dll"
|
||||||
|
elif sys.platform == "darwin":
|
||||||
|
BUILDING_DIR = "product-mini/platforms/darwin/build"
|
||||||
|
LIBRARY_NAME = "libiwasm.dylib"
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"unsupported platform `{sys.platform}`")
|
||||||
|
|
||||||
|
# FIXME: should load libiwasm.so from current system library path
|
||||||
|
current_file = Path(__file__)
|
||||||
|
if current_file.is_symlink():
|
||||||
|
current_file = Path(os.readlink(current_file))
|
||||||
|
current_dir = current_file.parent.resolve()
|
||||||
|
root_dir = current_dir.parent.parent.parent.parent.resolve()
|
||||||
|
wamr_dir = root_dir.joinpath("wasm-micro-runtime").resolve()
|
||||||
|
if not wamr_dir.exists():
|
||||||
|
raise RuntimeError(f"not found the repo of wasm-micro-runtime under {root_dir}")
|
||||||
|
|
||||||
|
libpath = wamr_dir.joinpath(BUILDING_DIR).joinpath(LIBRARY_NAME).resolve()
|
||||||
|
if not libpath.exists():
|
||||||
|
raise RuntimeError(f"not found precompiled wamr library at {libpath}")
|
||||||
|
|
||||||
|
print(f"loading WAMR library from {libpath} ...")
|
||||||
|
libiwasm = c.cdll.LoadLibrary(libpath)
|
||||||
|
|
||||||
|
|
||||||
|
class wasm_ref_t(c.Structure):
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class wasm_val_union(c.Union):
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
_fields_ = [
|
||||||
|
("i32", c.c_int32),
|
||||||
|
("i64", c.c_int64),
|
||||||
|
("f32", c.c_float),
|
||||||
|
("f64", c.c_double),
|
||||||
|
("ref", c.POINTER(wasm_ref_t)),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class wasm_val_t(c.Structure):
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
_fields_ = [
|
||||||
|
("kind", c.c_uint8),
|
||||||
|
("of", wasm_val_union),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def dereference(p):
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
if not isinstance(p, c._Pointer):
|
||||||
|
raise RuntimeError("not a pointer")
|
||||||
|
return p.contents
|
||||||
|
|
||||||
|
|
||||||
|
# HELPERs
|
||||||
|
def create_null_pointer(struct_type):
|
||||||
|
return c.POINTER(struct_type)()
|
||||||
|
|
||||||
|
|
||||||
|
def is_null_pointer(c_pointer):
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
if isinstance(c_pointer, c._Pointer):
|
||||||
|
return False if c_pointer else True
|
||||||
|
else:
|
||||||
|
raise RuntimeError("not a pointer")
|
||||||
|
|
||||||
|
|
||||||
|
def wasm_vec_to_list(vec):
|
||||||
|
"""
|
||||||
|
Converts a vector or a POINTER(vector) to a list
|
||||||
|
vector of type pointers -> list of type pointers
|
||||||
|
"""
|
||||||
|
known_vec_type = [
|
||||||
|
wasm_byte_vec_t,
|
||||||
|
wasm_valtype_vec_t,
|
||||||
|
wasm_functype_vec_t,
|
||||||
|
wasm_globaltype_vec_t,
|
||||||
|
wasm_tabletype_vec_t,
|
||||||
|
wasm_memorytype_vec_t,
|
||||||
|
wasm_externtype_vec_t,
|
||||||
|
wasm_importtype_vec_t,
|
||||||
|
wasm_exporttype_vec_t,
|
||||||
|
wasm_val_vec_t,
|
||||||
|
wasm_frame_vec_t,
|
||||||
|
wasm_extern_vec_t,
|
||||||
|
]
|
||||||
|
known_vec_pointer_type = [POINTER(type) for type in known_vec_type]
|
||||||
|
|
||||||
|
if any([isinstance(vec, type) for type in known_vec_pointer_type]):
|
||||||
|
vec = dereference(vec)
|
||||||
|
return [vec.data[i] for i in range(vec.num_elems)]
|
||||||
|
elif any([isinstance(vec, type) for type in known_vec_type]):
|
||||||
|
return [vec.data[i] for i in range(vec.num_elems)]
|
||||||
|
else:
|
||||||
|
raise RuntimeError("not a known vector type")
|
||||||
|
|
||||||
|
|
||||||
|
def list_to_carray(elem_type, *args):
|
||||||
|
"""
|
||||||
|
Converts a python list into a C array
|
||||||
|
"""
|
||||||
|
data = (elem_type * len(args))(*args)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def load_module_file(wasm_content):
|
||||||
|
binary = wasm_byte_vec_t()
|
||||||
|
wasm_byte_vec_new_uninitialized(binary, len(wasm_content))
|
||||||
|
# has to use malloced memory.
|
||||||
|
c.memmove(binary.data, wasm_content, len(wasm_content))
|
||||||
|
binary.num_elems = len(wasm_content)
|
||||||
|
return binary
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Enhancment of binding
|
||||||
|
#
|
||||||
|
|
||||||
|
from .binding import *
|
||||||
|
|
||||||
|
# Built-in functions for Structure
|
||||||
|
|
||||||
|
|
||||||
|
wasm_finalizer = CFUNCTYPE(None, c_void_p)
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_limits_t(self):
|
||||||
|
return f"{self.min:#x} {self.max:#x}"
|
||||||
|
|
||||||
|
|
||||||
|
# overwrite
|
||||||
|
wasm_limits_t.__repr__ = __repr_wasm_limits_t
|
||||||
|
|
||||||
|
|
||||||
|
def __compare_wasm_valtype_t(self, other):
|
||||||
|
if not isinstance(other, wasm_valtype_t):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return wasm_valtype_kind(byref(self)) == wasm_valtype_kind(byref(other))
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_valtype_t(self):
|
||||||
|
val_kind = wasm_valtype_kind(byref(self))
|
||||||
|
if WASM_I32 == val_kind:
|
||||||
|
return "i32"
|
||||||
|
elif WASM_I64 == val_kind:
|
||||||
|
return "i64"
|
||||||
|
elif WASM_F32 == val_kind:
|
||||||
|
return "f32"
|
||||||
|
elif WASM_F64 == val_kind:
|
||||||
|
return "f64"
|
||||||
|
elif WASM_FUNCREF == val_kind:
|
||||||
|
return "funcref"
|
||||||
|
else:
|
||||||
|
return "anyref"
|
||||||
|
|
||||||
|
|
||||||
|
wasm_valtype_t.__eq__ = __compare_wasm_valtype_t
|
||||||
|
wasm_valtype_t.__repr__ = __repr_wasm_valtype_t
|
||||||
|
|
||||||
|
|
||||||
|
def __compare_wasm_byte_vec_t(self, other):
|
||||||
|
if not isinstance(other, wasm_byte_vec_t):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self.num_elems != other.num_elems:
|
||||||
|
return False
|
||||||
|
|
||||||
|
self_data = bytes(self.data[: self.num_elems])
|
||||||
|
other_data = bytes(other.data[: other.num_elems])
|
||||||
|
return self_data.decode() == other_data.decode()
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_byte_vec_t(self):
|
||||||
|
data = bytes(self.data[: self.num_elems])
|
||||||
|
return data.decode() if self.size else ""
|
||||||
|
|
||||||
|
|
||||||
|
wasm_byte_vec_t.__eq__ = __compare_wasm_byte_vec_t
|
||||||
|
wasm_byte_vec_t.__repr__ = __repr_wasm_byte_vec_t
|
||||||
|
|
||||||
|
|
||||||
|
def __compare_wasm_functype_t(self, other):
|
||||||
|
if not isinstance(other, wasm_functype_t):
|
||||||
|
return False
|
||||||
|
|
||||||
|
params1 = dereference(wasm_functype_params(byref(self)))
|
||||||
|
params2 = dereference(wasm_functype_params(byref(other)))
|
||||||
|
results1 = dereference(wasm_functype_results(byref(self)))
|
||||||
|
results2 = dereference(wasm_functype_results(byref(other)))
|
||||||
|
return params1 == params2 and results1 == results2
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_functype_t(self):
|
||||||
|
params = dereference(wasm_functype_params(byref(self)))
|
||||||
|
results = dereference(wasm_functype_results(byref(self)))
|
||||||
|
params = f" (params {params})" if params.size else ""
|
||||||
|
results = f" (results {results})" if results.size else ""
|
||||||
|
return f"(func{params}{results})"
|
||||||
|
|
||||||
|
|
||||||
|
wasm_functype_t.__eq__ = __compare_wasm_functype_t
|
||||||
|
wasm_functype_t.__repr__ = __repr_wasm_functype_t
|
||||||
|
|
||||||
|
|
||||||
|
def __compare_wasm_globaltype_t(self, other):
|
||||||
|
if not isinstance(other, wasm_globaltype_t):
|
||||||
|
return False
|
||||||
|
|
||||||
|
content1 = dereference(wasm_globaltype_content(byref(self)))
|
||||||
|
content2 = dereference(wasm_globaltype_content(byref(other)))
|
||||||
|
mutability1 = wasm_globaltype_mutability(byref(self))
|
||||||
|
mutability2 = wasm_globaltype_mutability(byref(other))
|
||||||
|
return content1 == content2 and mutability1 == mutability2
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_globaltype_t(self):
|
||||||
|
mutability = f"{wasm_globaltype_mutability(byref(self))}"
|
||||||
|
content = f"{dereference(wasm_globaltype_content(byref(self)))}"
|
||||||
|
return f"(global{' mut ' if mutability else ' '}{content})"
|
||||||
|
|
||||||
|
|
||||||
|
wasm_globaltype_t.__eq__ = __compare_wasm_globaltype_t
|
||||||
|
wasm_globaltype_t.__repr__ = __repr_wasm_globaltype_t
|
||||||
|
|
||||||
|
|
||||||
|
def __compare_wasm_tabletype_t(self, other):
|
||||||
|
if not isinstance(other, wasm_tabletype_t):
|
||||||
|
return False
|
||||||
|
|
||||||
|
element1 = dereference(wasm_tabletype_element(byref(self)))
|
||||||
|
element2 = dereference(wasm_tabletype_element(byref(other)))
|
||||||
|
limits1 = dereference(wasm_tabletype_limits(byref(self)))
|
||||||
|
limits2 = dereference(wasm_tabletype_limits(byref(other)))
|
||||||
|
return element1 == element2 and limits1 == limits2
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_tabletype_t(self):
|
||||||
|
element = dereference(wasm_tabletype_element(byref(self)))
|
||||||
|
limit = dereference(wasm_tabletype_limits(byref(self)))
|
||||||
|
return f"(table {limit} {element})"
|
||||||
|
|
||||||
|
|
||||||
|
wasm_tabletype_t.__eq__ = __compare_wasm_tabletype_t
|
||||||
|
wasm_tabletype_t.__repr__ = __repr_wasm_tabletype_t
|
||||||
|
|
||||||
|
|
||||||
|
def __compare_wasm_memorytype_t(self, other):
|
||||||
|
if not isinstance(other, wasm_memorytype_t):
|
||||||
|
return False
|
||||||
|
|
||||||
|
limits1 = dereference(wasm_memorytype_limits(byref(self)))
|
||||||
|
limits2 = dereference(wasm_memorytype_limits(byref(other)))
|
||||||
|
return limits1 == limits2
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_memorytype_t(self):
|
||||||
|
limit = dereference(wasm_memorytype_limits(byref(self)))
|
||||||
|
return f"(memory {limit})"
|
||||||
|
|
||||||
|
|
||||||
|
wasm_memorytype_t.__eq__ = __compare_wasm_memorytype_t
|
||||||
|
wasm_memorytype_t.__repr__ = __repr_wasm_memorytype_t
|
||||||
|
|
||||||
|
|
||||||
|
def __compare_wasm_externtype_t(self, other):
|
||||||
|
if not isinstance(other, wasm_externtype_t):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if wasm_externtype_kind(byref(self)) != wasm_externtype_kind(byref(other)):
|
||||||
|
return False
|
||||||
|
|
||||||
|
extern_kind = wasm_externtype_kind(byref(self))
|
||||||
|
if WASM_EXTERN_FUNC == extern_kind:
|
||||||
|
return dereference(wasm_externtype_as_functype(self)) == dereference(
|
||||||
|
wasm_externtype_as_functype(other)
|
||||||
|
)
|
||||||
|
elif WASM_EXTERN_GLOBAL == extern_kind:
|
||||||
|
return dereference(wasm_externtype_as_globaltype(self)) == dereference(
|
||||||
|
wasm_externtype_as_globaltype(other)
|
||||||
|
)
|
||||||
|
elif WASM_EXTERN_MEMORY == extern_kind:
|
||||||
|
return dereference(wasm_externtype_as_memorytype(self)) == dereference(
|
||||||
|
wasm_externtype_as_memorytype(other)
|
||||||
|
)
|
||||||
|
elif WASM_EXTERN_TABLE == extern_kind:
|
||||||
|
return dereference(wasm_externtype_as_tabletype(self)) == dereference(
|
||||||
|
wasm_externtype_as_tabletype(other)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise RuntimeError("not a valid wasm_externtype_t")
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_externtype_t(self):
|
||||||
|
extern_kind = wasm_externtype_kind(byref(self))
|
||||||
|
if WASM_EXTERN_FUNC == extern_kind:
|
||||||
|
return str(dereference(wasm_externtype_as_functype(byref(self))))
|
||||||
|
elif WASM_EXTERN_GLOBAL == extern_kind:
|
||||||
|
return str(dereference(wasm_externtype_as_globaltype(byref(self))))
|
||||||
|
elif WASM_EXTERN_MEMORY == extern_kind:
|
||||||
|
return str(dereference(wasm_externtype_as_memorytype(byref(self))))
|
||||||
|
elif WASM_EXTERN_TABLE == extern_kind:
|
||||||
|
return str(dereference(wasm_externtype_as_tabletype(byref(self))))
|
||||||
|
else:
|
||||||
|
raise RuntimeError("not a valid wasm_externtype_t")
|
||||||
|
|
||||||
|
|
||||||
|
wasm_externtype_t.__eq__ = __compare_wasm_externtype_t
|
||||||
|
wasm_externtype_t.__repr__ = __repr_wasm_externtype_t
|
||||||
|
|
||||||
|
|
||||||
|
def __compare_wasm_importtype_t(self, other):
|
||||||
|
if not isinstance(other, wasm_importtype_t):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if dereference(wasm_importtype_module(self)) != dereference(
|
||||||
|
wasm_importtype_module(other)
|
||||||
|
):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if dereference(wasm_importtype_name(self)) != dereference(
|
||||||
|
wasm_importtype_name(other)
|
||||||
|
):
|
||||||
|
return False
|
||||||
|
|
||||||
|
self_type = dereference(wasm_importtype_type(byref(self)))
|
||||||
|
other_type = dereference(wasm_importtype_type(byref(other)))
|
||||||
|
return self_type == other_type
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_importtype_t(self):
|
||||||
|
module = wasm_importtype_module(byref(self))
|
||||||
|
name = wasm_importtype_name(byref(self))
|
||||||
|
extern_type = wasm_importtype_type(byref(self))
|
||||||
|
return f'(import "{dereference(module)}" "{dereference(name)}" {dereference(extern_type)})'
|
||||||
|
|
||||||
|
|
||||||
|
wasm_importtype_t.__eq__ = __compare_wasm_importtype_t
|
||||||
|
wasm_importtype_t.__repr__ = __repr_wasm_importtype_t
|
||||||
|
|
||||||
|
|
||||||
|
def __compare_wasm_exporttype_t(self, other):
|
||||||
|
if not isinstance(other, wasm_exporttype_t):
|
||||||
|
return False
|
||||||
|
|
||||||
|
self_name = dereference(wasm_exporttype_name(byref(self)))
|
||||||
|
other_name = dereference(wasm_exporttype_name(byref(other)))
|
||||||
|
if self_name != other_name:
|
||||||
|
return False
|
||||||
|
|
||||||
|
self_type = dereference(wasm_exporttype_type(byref(self)))
|
||||||
|
other_type = dereference(wasm_exporttype_type(byref(other)))
|
||||||
|
return self_type == other_type
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_exporttype_t(self):
|
||||||
|
name = wasm_exporttype_name(byref(self))
|
||||||
|
extern_type = wasm_exporttype_type(byref(self))
|
||||||
|
return f'(export "{dereference(name)}" {dereference(extern_type)})'
|
||||||
|
|
||||||
|
|
||||||
|
wasm_exporttype_t.__eq__ = __compare_wasm_exporttype_t
|
||||||
|
wasm_exporttype_t.__repr__ = __repr_wasm_exporttype_t
|
||||||
|
|
||||||
|
|
||||||
|
def __compare_wasm_val_t(self, other):
|
||||||
|
if not isinstance(other, wasm_val_t):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self.kind != other.kind:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if WASM_I32 == self.kind:
|
||||||
|
return self.of.i32 == other.of.i32
|
||||||
|
elif WASM_I64 == self.kind:
|
||||||
|
return self.of.i64 == other.of.i64
|
||||||
|
elif WASM_F32 == self.kind:
|
||||||
|
return self.of.f32 == other.of.f32
|
||||||
|
elif WASM_F64 == self.kind:
|
||||||
|
return self.of.f64 == other.of.f63
|
||||||
|
elif WASM_ANYREF == self.kind:
|
||||||
|
raise RuntimeError("FIXME")
|
||||||
|
else:
|
||||||
|
raise RuntimeError("not a valid val kind")
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_val_t(self):
|
||||||
|
if WASM_I32 == self.kind:
|
||||||
|
return f"i32 {self.of.i32}"
|
||||||
|
elif WASM_I64 == self.kind:
|
||||||
|
return f"i64 {self.of.i64}"
|
||||||
|
elif WASM_F32 == self.kind:
|
||||||
|
return f"f32 {self.of.f32}"
|
||||||
|
elif WASM_F64 == self.kind:
|
||||||
|
return f"f64 {self.of.f64}"
|
||||||
|
elif WASM_ANYREF == self.kind:
|
||||||
|
return f"anyref {self.of.ref}"
|
||||||
|
else:
|
||||||
|
raise RuntimeError("not a valid val kind")
|
||||||
|
|
||||||
|
|
||||||
|
wasm_val_t.__repr__ = __repr_wasm_val_t
|
||||||
|
wasm_val_t.__eq__ = __compare_wasm_val_t
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_trap_t(self):
|
||||||
|
message = wasm_message_t()
|
||||||
|
wasm_trap_message(self, message)
|
||||||
|
return f'(trap "{str(message)}")'
|
||||||
|
|
||||||
|
|
||||||
|
wasm_trap_t.__repr__ = __repr_wasm_trap_t
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_frame_t(self):
|
||||||
|
instance = wasm_frame_instance(self)
|
||||||
|
module_offset = wasm_frame_module_offset(self)
|
||||||
|
func_index = wasm_frame_func_index(self)
|
||||||
|
func_offset = wasm_frame_func_offset(self)
|
||||||
|
return f"> module:{module_offset:#x} => func#{func_index:#x}.{func_offset:#x}"
|
||||||
|
|
||||||
|
|
||||||
|
wasm_frame_t.__repr__ = __repr_wasm_frame_t
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_module_t(self):
|
||||||
|
imports = wasm_importtype_vec_t()
|
||||||
|
wasm_module_imports(self, imports)
|
||||||
|
|
||||||
|
exports = wasm_exporttype_vec_t()
|
||||||
|
wasm_module_exports(self, exports)
|
||||||
|
|
||||||
|
ret = "(module"
|
||||||
|
ret += str(imports).replace("(import", "\n (import")
|
||||||
|
ret += str(exports).replace("(export", "\n (export")
|
||||||
|
ret += "\n)"
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
wasm_module_t.__repr__ = __repr_wasm_module_t
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_instance_t(self):
|
||||||
|
exports = wasm_extern_vec_t()
|
||||||
|
wasm_instance_exports(self, exports)
|
||||||
|
|
||||||
|
ret = "(instance"
|
||||||
|
ret += str(exports).replace("(export", "\n (export")
|
||||||
|
ret += "\n)"
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
wasm_instance_t.__repr__ = __repr_wasm_instance_t
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_func_t(self):
|
||||||
|
ft = wasm_func_type(self)
|
||||||
|
return f"{str(dereference(ft))[:-1]} ... )"
|
||||||
|
|
||||||
|
|
||||||
|
wasm_func_t.__repr__ = __repr_wasm_func_t
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_global_t(self):
|
||||||
|
gt = wasm_global_type(self)
|
||||||
|
return f"{str(dereference(gt))[:-1]} ... )"
|
||||||
|
|
||||||
|
|
||||||
|
wasm_global_t.__repr__ = __repr_wasm_global_t
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_table_t(self):
|
||||||
|
tt = wasm_table_type(self)
|
||||||
|
return f"{str(dereference(tt))[:-1]} ... )"
|
||||||
|
|
||||||
|
|
||||||
|
wasm_table_t.__repr__ = __repr_wasm_table_t
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_memory_t(self):
|
||||||
|
mt = wasm_memory_type(self)
|
||||||
|
return f"{str(dereference(mt))[:-1]} ... )"
|
||||||
|
|
||||||
|
|
||||||
|
wasm_memory_t.__repr__ = __repr_wasm_memory_t
|
||||||
|
|
||||||
|
|
||||||
|
def __repr_wasm_extern_t(self):
|
||||||
|
ext_type = wasm_extern_type(self)
|
||||||
|
ext_kind = wasm_extern_kind(self)
|
||||||
|
|
||||||
|
ret = "(export "
|
||||||
|
if WASM_EXTERN_FUNC == ext_kind:
|
||||||
|
ft = wasm_externtype_as_functype(ext_type)
|
||||||
|
ret += str(dereference(ft))
|
||||||
|
elif WASM_EXTERN_GLOBAL == ext_kind:
|
||||||
|
gt = wasm_externtype_as_globaltype(ext_type)
|
||||||
|
ret += str(dereference(gt))
|
||||||
|
elif WASM_EXTERN_MEMORY == ext_kind:
|
||||||
|
mt = wasm_externtype_as_memorytype(ext_type)
|
||||||
|
ret += str(dereference(mt))
|
||||||
|
elif WASM_EXTERN_TABLE == ext_kind:
|
||||||
|
tt = wasm_externtype_as_tabletype(ext_type)
|
||||||
|
ret += str(dereference(tt))
|
||||||
|
else:
|
||||||
|
raise RuntimeError("not a valid extern kind")
|
||||||
|
ret += ")"
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
wasm_extern_t.__repr__ = __repr_wasm_extern_t
|
||||||
|
|
||||||
|
|
||||||
|
# Function Types construction short-hands
|
||||||
|
def wasm_name_new_from_string(s):
|
||||||
|
name = wasm_name_t()
|
||||||
|
data = ((c.c_ubyte) * len(s)).from_buffer_copy(s.encode())
|
||||||
|
wasm_byte_vec_new(byref(name), len(s), data)
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
def __wasm_functype_new(param_list, result_list):
|
||||||
|
def __list_to_wasm_valtype_vec(l):
|
||||||
|
vec = wasm_valtype_vec_t()
|
||||||
|
|
||||||
|
if not l:
|
||||||
|
wasm_valtype_vec_new_empty(byref(vec))
|
||||||
|
else:
|
||||||
|
data_type = POINTER(wasm_valtype_t) * len(l)
|
||||||
|
data = data_type()
|
||||||
|
for i in range(len(l)):
|
||||||
|
data[i] = l[i]
|
||||||
|
wasm_valtype_vec_new(byref(vec), len(l), data)
|
||||||
|
|
||||||
|
return vec
|
||||||
|
|
||||||
|
params = __list_to_wasm_valtype_vec(param_list)
|
||||||
|
results = __list_to_wasm_valtype_vec(result_list)
|
||||||
|
return wasm_functype_new(byref(params), byref(results))
|
||||||
|
|
||||||
|
|
||||||
|
def wasm_functype_new_0_0():
|
||||||
|
return __wasm_functype_new([], [])
|
||||||
|
|
||||||
|
|
||||||
|
def wasm_functype_new_1_0(p1):
|
||||||
|
return __wasm_functype_new([p1], [])
|
||||||
|
|
||||||
|
|
||||||
|
def wasm_functype_new_2_0(p1, p2):
|
||||||
|
return __wasm_functype_new([p1, p2], [])
|
||||||
|
|
||||||
|
|
||||||
|
def wasm_functype_new_3_0(p1, p2, p3):
|
||||||
|
return __wasm_functype_new([p1, p2, p3], [])
|
||||||
|
|
||||||
|
|
||||||
|
def wasm_functype_new_0_1(r1):
|
||||||
|
return __wasm_functype_new([], [r1])
|
||||||
|
|
||||||
|
|
||||||
|
def wasm_functype_new_1_1(p1, r1):
|
||||||
|
return __wasm_functype_new([p1], [r1])
|
||||||
|
|
||||||
|
|
||||||
|
def wasm_functype_new_2_1(p1, p2, r1):
|
||||||
|
return __wasm_functype_new([p1, p2], [r1])
|
||||||
|
|
||||||
|
|
||||||
|
def wasm_functype_new_3_1(p1, p2, p3, r1):
|
||||||
|
return __wasm_functype_new([p1, p2, p3], [r1])
|
||||||
|
|
||||||
|
|
||||||
|
def wasm_limits_new(min, max):
|
||||||
|
limit = wasm_limits_t()
|
||||||
|
limit.min = min
|
||||||
|
limit.max = max
|
||||||
|
return c.pointer(limit)
|
||||||
|
|
||||||
|
|
||||||
|
def wasm_i32_val(i):
|
||||||
|
v = wasm_val_t()
|
||||||
|
v.kind = WASM_I32
|
||||||
|
v.of.i32 = i
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
|
def wasm_i64_val(i):
|
||||||
|
v = wasm_val_t()
|
||||||
|
v.kind = WASM_I64
|
||||||
|
v.of.i64 = i
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
|
def wasm_f32_val(z):
|
||||||
|
v = wasm_val_t()
|
||||||
|
v.kind = WASM_F32
|
||||||
|
v.of.f32 = z
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
|
def wasm_f64_val(z):
|
||||||
|
v = wasm_val_t()
|
||||||
|
v.kind = WASM_F64
|
||||||
|
v.of.f64 = z
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
|
def wasm_func_cb_decl(func):
|
||||||
|
return wasm_func_callback_t(func)
|
||||||
|
|
||||||
|
|
||||||
|
def wasm_func_with_env_cb_decl(func):
|
||||||
|
return wasm_func_callback_with_env_t(func)
|
Loading…
Reference in New Issue
Block a user