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,
|
||||
uint8 *orig_file_buf,
|
||||
uint32 orig_file_buf_size,
|
||||
char *error_buf, uint32_t error_buf_size)
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
WASMRegisteredModule *node = NULL;
|
||||
|
||||
|
@ -500,7 +500,7 @@ wasm_runtime_register_module_internal(const char *module_name,
|
|||
|
||||
bool
|
||||
wasm_runtime_register_module(const char *module_name, WASMModuleCommon *module,
|
||||
char *error_buf, uint32_t error_buf_size)
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
if (!error_buf || !error_buf_size) {
|
||||
LOG_ERROR("error buffer is required");
|
||||
|
@ -823,7 +823,7 @@ wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf,
|
|||
|
||||
WASMModuleCommon *
|
||||
wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot,
|
||||
char *error_buf, uint32_t error_buf_size)
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
WASMModuleCommon *module_common;
|
||||
|
||||
|
@ -980,6 +980,23 @@ wasm_runtime_destroy_thread_env(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_runtime_thread_env_inited(void)
|
||||
{
|
||||
#ifdef BH_PLATFORM_WINDOWS
|
||||
if (!os_thread_env_inited())
|
||||
return false;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
#ifdef OS_ENABLE_HW_BOUND_CHECK
|
||||
if (!os_thread_signal_inited())
|
||||
return false;
|
||||
#endif
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#if (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_MEMORY_TRACING != 0)
|
||||
void
|
||||
wasm_runtime_dump_module_mem_consumption(const WASMModuleCommon *module)
|
||||
|
@ -1222,8 +1239,81 @@ wasm_runtime_lookup_function(WASMModuleInstanceCommon *const module_inst,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
uint32
|
||||
wasm_func_get_param_count(WASMFunctionInstanceCommon *const func_inst,
|
||||
WASMModuleInstanceCommon *const module_inst)
|
||||
{
|
||||
WASMType *type =
|
||||
wasm_runtime_get_function_type(func_inst, module_inst->module_type);
|
||||
return type->param_count;
|
||||
}
|
||||
|
||||
uint32
|
||||
wasm_func_get_result_count(WASMFunctionInstanceCommon *const func_inst,
|
||||
WASMModuleInstanceCommon *const module_inst)
|
||||
{
|
||||
WASMType *type =
|
||||
wasm_runtime_get_function_type(func_inst, module_inst->module_type);
|
||||
return type->result_count;
|
||||
}
|
||||
|
||||
static uint8
|
||||
val_type_to_val_kind(uint8 value_type)
|
||||
{
|
||||
switch (value_type) {
|
||||
case VALUE_TYPE_I32:
|
||||
return WASM_I32;
|
||||
case VALUE_TYPE_I64:
|
||||
return WASM_I64;
|
||||
case VALUE_TYPE_F32:
|
||||
return WASM_F32;
|
||||
case VALUE_TYPE_F64:
|
||||
return WASM_F64;
|
||||
case VALUE_TYPE_FUNCREF:
|
||||
return WASM_FUNCREF;
|
||||
case VALUE_TYPE_EXTERNREF:
|
||||
return WASM_ANYREF;
|
||||
default:
|
||||
#if WASM_ENABLE_GC != 0
|
||||
if (wasm_is_type_reftype(value_type))
|
||||
return WASM_ANYREF;
|
||||
#endif
|
||||
bh_assert(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wasm_func_get_param_types(WASMFunctionInstanceCommon *const func_inst,
|
||||
WASMModuleInstanceCommon *const module_inst,
|
||||
wasm_valkind_t *param_types)
|
||||
{
|
||||
WASMType *type =
|
||||
wasm_runtime_get_function_type(func_inst, module_inst->module_type);
|
||||
uint32 i;
|
||||
|
||||
for (i = 0; i < type->param_count; i++) {
|
||||
param_types[i] = val_type_to_val_kind(type->types[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wasm_func_get_result_types(WASMFunctionInstanceCommon *const func_inst,
|
||||
WASMModuleInstanceCommon *const module_inst,
|
||||
wasm_valkind_t *result_types)
|
||||
{
|
||||
WASMType *type =
|
||||
wasm_runtime_get_function_type(func_inst, module_inst->module_type);
|
||||
uint32 i;
|
||||
|
||||
for (i = 0; i < type->result_count; i++) {
|
||||
result_types[i] =
|
||||
val_type_to_val_kind(type->types[type->param_count + i]);
|
||||
}
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
/* (uintptr_t)externref -> (uint32_t)index */
|
||||
/* (uintptr_t)externref -> (uint32)index */
|
||||
/* argv -> *ret_argv */
|
||||
static bool
|
||||
wasm_runtime_prepare_call_function(WASMExecEnv *exec_env,
|
||||
|
@ -1321,7 +1411,7 @@ wasm_runtime_prepare_call_function(WASMExecEnv *exec_env,
|
|||
return true;
|
||||
}
|
||||
|
||||
/* (uintptr_t)externref <- (uint32_t)index */
|
||||
/* (uintptr_t)externref <- (uint32)index */
|
||||
/* argv <- new_argv */
|
||||
static bool
|
||||
wasm_runtime_finalize_call_function(WASMExecEnv *exec_env,
|
||||
|
@ -3952,8 +4042,8 @@ fail:
|
|||
|| defined(BUILD_TARGET_RISCV64_LP64) */
|
||||
|
||||
bool
|
||||
wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32_t element_indices,
|
||||
uint32_t argc, uint32_t argv[])
|
||||
wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices,
|
||||
uint32 argc, uint32 argv[])
|
||||
{
|
||||
if (!wasm_runtime_exec_env_check(exec_env)) {
|
||||
LOG_ERROR("Invalid exec env stack info.");
|
||||
|
|
|
@ -303,6 +303,11 @@ typedef struct WASMModuleCommon {
|
|||
Wasm_Module_AoT, and this structure should be treated as
|
||||
AOTModule structure. */
|
||||
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];
|
||||
} WASMModuleCommon;
|
||||
|
||||
|
@ -314,6 +319,11 @@ typedef struct WASMModuleInstanceCommon {
|
|||
Wasm_Module_AoT, and this structure should be treated as
|
||||
AOTModuleInstance structure. */
|
||||
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];
|
||||
} WASMModuleInstanceCommon;
|
||||
|
||||
|
@ -377,6 +387,11 @@ typedef struct WASMRegisteredModule {
|
|||
|
||||
typedef struct WASMMemoryInstanceCommon {
|
||||
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];
|
||||
} WASMMemoryInstanceCommon;
|
||||
|
||||
|
@ -456,6 +471,28 @@ WASMType *
|
|||
wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function,
|
||||
uint32 module_type);
|
||||
|
||||
/* See wasm_export.h for description */
|
||||
WASM_RUNTIME_API_EXTERN uint32
|
||||
wasm_func_get_param_count(WASMFunctionInstanceCommon *const func_inst,
|
||||
WASMModuleInstanceCommon *const module_inst);
|
||||
|
||||
/* See wasm_export.h for description */
|
||||
WASM_RUNTIME_API_EXTERN uint32
|
||||
wasm_func_get_result_count(WASMFunctionInstanceCommon *const func_inst,
|
||||
WASMModuleInstanceCommon *const module_inst);
|
||||
|
||||
/* See wasm_export.h for description */
|
||||
WASM_RUNTIME_API_EXTERN void
|
||||
wasm_func_get_param_types(WASMFunctionInstanceCommon *const func_inst,
|
||||
WASMModuleInstanceCommon *const module_inst,
|
||||
wasm_valkind_t *param_types);
|
||||
|
||||
/* See wasm_export.h for description */
|
||||
WASM_RUNTIME_API_EXTERN void
|
||||
wasm_func_get_result_types(WASMFunctionInstanceCommon *const func_inst,
|
||||
WASMModuleInstanceCommon *const module_inst,
|
||||
wasm_valkind_t *result_types);
|
||||
|
||||
/* See wasm_export.h for description */
|
||||
WASM_RUNTIME_API_EXTERN WASMExecEnv *
|
||||
wasm_runtime_create_exec_env(WASMModuleInstanceCommon *module_inst,
|
||||
|
|
|
@ -407,6 +407,54 @@ WASM_RUNTIME_API_EXTERN wasm_function_inst_t
|
|||
wasm_runtime_lookup_function(wasm_module_inst_t const module_inst,
|
||||
const char *name, const char *signature);
|
||||
|
||||
/**
|
||||
* Get parameter count of the function instance
|
||||
*
|
||||
* @param func_inst the function instance
|
||||
* @param module_inst the module instance the function instance belongs to
|
||||
*
|
||||
* @return the parameter count of the function instance
|
||||
*/
|
||||
WASM_RUNTIME_API_EXTERN uint32_t
|
||||
wasm_func_get_param_count(wasm_function_inst_t const func_inst,
|
||||
wasm_module_inst_t const module_inst);
|
||||
|
||||
/**
|
||||
* Get result count of the function instance
|
||||
*
|
||||
* @param func_inst the function instance
|
||||
* @param module_inst the module instance the function instance belongs to
|
||||
*
|
||||
* @return the result count of the function instance
|
||||
*/
|
||||
WASM_RUNTIME_API_EXTERN uint32_t
|
||||
wasm_func_get_result_count(wasm_function_inst_t const func_inst,
|
||||
wasm_module_inst_t const module_inst);
|
||||
|
||||
/**
|
||||
* Get parameter types of the function instance
|
||||
*
|
||||
* @param func_inst the function instance
|
||||
* @param module_inst the module instance the function instance belongs to
|
||||
* @param param_types the parameter types returned
|
||||
*/
|
||||
WASM_RUNTIME_API_EXTERN void
|
||||
wasm_func_get_param_types(wasm_function_inst_t const func_inst,
|
||||
wasm_module_inst_t const module_inst,
|
||||
wasm_valkind_t *param_types);
|
||||
|
||||
/**
|
||||
* Get result types of the function instance
|
||||
*
|
||||
* @param func_inst the function instance
|
||||
* @param module_inst the module instance the function instance belongs to
|
||||
* @param result_types the result types returned
|
||||
*/
|
||||
WASM_RUNTIME_API_EXTERN void
|
||||
wasm_func_get_result_types(wasm_function_inst_t const func_inst,
|
||||
wasm_module_inst_t const module_inst,
|
||||
wasm_valkind_t *result_types);
|
||||
|
||||
/**
|
||||
* Create execution environment for a WASM module instance.
|
||||
*
|
||||
|
@ -449,7 +497,7 @@ WASM_RUNTIME_API_EXTERN uint32_t
|
|||
wasm_runtime_start_debug_instance(wasm_exec_env_t exec_env);
|
||||
|
||||
/**
|
||||
* Initialize thread environment.
|
||||
* Initialize the thread environment.
|
||||
* Note:
|
||||
* If developer creates a child thread by himself to call the
|
||||
* the wasm function in that thread, he should call this API
|
||||
|
@ -464,11 +512,17 @@ WASM_RUNTIME_API_EXTERN bool
|
|||
wasm_runtime_init_thread_env(void);
|
||||
|
||||
/**
|
||||
* Destroy thread environment
|
||||
* Destroy the thread environment
|
||||
*/
|
||||
WASM_RUNTIME_API_EXTERN void
|
||||
wasm_runtime_destroy_thread_env(void);
|
||||
|
||||
/**
|
||||
* Whether the thread environment is initialized
|
||||
*/
|
||||
WASM_RUNTIME_API_EXTERN bool
|
||||
wasm_runtime_thread_env_inited(void);
|
||||
|
||||
/**
|
||||
* Get WASM module instance from execution environment
|
||||
*
|
||||
|
|
|
@ -107,6 +107,12 @@ os_thread_env_init();
|
|||
void
|
||||
os_thread_env_destroy();
|
||||
|
||||
/**
|
||||
* Whether the thread environment is initialized
|
||||
*/
|
||||
bool
|
||||
os_thread_env_inited();
|
||||
|
||||
/**
|
||||
* Suspend execution of the calling thread for (at least)
|
||||
* usec microseconds
|
||||
|
|
|
@ -360,6 +360,13 @@ os_thread_env_destroy()
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
os_thread_env_inited()
|
||||
{
|
||||
os_thread_data *thread_data = TlsGetValue(thread_data_key);
|
||||
return thread_data ? true : false;
|
||||
}
|
||||
|
||||
int
|
||||
os_sem_init(korp_sem *sem)
|
||||
{
|
||||
|
|
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