| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- /*
- * 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)
- 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)
- 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_EXTERNREF) {
- 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:
- fallthrough
- case C.WASM_FUNCREF:
- fallthrough
- case C.WASM_EXTERNREF:
- 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 uint64) (uint64, *uint8) {
- var offset C.uint64_t
- native_addrs := make([]*uint8, 1, 1)
- ptr := unsafe.Pointer(&native_addrs[0])
- offset = C.wasm_runtime_module_malloc(self._instance, (C.uint64_t)(size),
- (*unsafe.Pointer)(ptr))
- return (uint64)(offset), native_addrs[0]
- }
- /* Free memory to the heap of the instance */
- func (self Instance) ModuleFree(offset uint64) {
- C.wasm_runtime_module_free(self._instance, (C.uint64_t)(offset))
- }
- func (self Instance) ValidateAppAddr(app_offset uint64, size uint64) bool {
- ret := C.wasm_runtime_validate_app_addr(self._instance,
- (C.uint64_t)(app_offset),
- (C.uint64_t)(size))
- return (bool)(ret)
- }
- func (self Instance) ValidateStrAddr(app_str_offset uint64) bool {
- ret := C.wasm_runtime_validate_app_str_addr(self._instance,
- (C.uint64_t)(app_str_offset))
- return (bool)(ret)
- }
- func (self Instance) ValidateNativeAddr(native_ptr *uint8, size uint64) bool {
- native_ptr_C := (unsafe.Pointer)(native_ptr)
- ret := C.wasm_runtime_validate_native_addr(self._instance,
- native_ptr_C,
- (C.uint64_t)(size))
- return (bool)(ret)
- }
- func (self Instance) AddrAppToNative(app_offset uint64) *uint8 {
- native_ptr := C.wasm_runtime_addr_app_to_native(self._instance,
- (C.uint64_t)(app_offset))
- return (*uint8)(native_ptr)
- }
- func (self Instance) AddrNativeToApp(native_ptr *uint8) uint64 {
- native_ptr_C := (unsafe.Pointer)(native_ptr)
- offset := C.wasm_runtime_addr_native_to_app(self._instance,
- native_ptr_C)
- return (uint64)(offset)
- }
- func (self Instance) GetAppAddrRange(app_offset uint64) (bool,
- uint64,
- uint64) {
- var start_offset, end_offset C.uint64_t
- ret := C.wasm_runtime_get_app_addr_range(self._instance,
- (C.uint64_t)(app_offset),
- &start_offset, &end_offset)
- return (bool)(ret), (uint64)(start_offset), (uint64)(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)
- }
|