instance.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. package wamr
  6. /*
  7. #include <stdlib.h>
  8. #include <wasm_export.h>
  9. static inline void
  10. PUT_I64_TO_ADDR(uint32_t *addr, int64_t value)
  11. {
  12. union {
  13. int64_t val;
  14. uint32_t parts[2];
  15. } u;
  16. u.val = value;
  17. addr[0] = u.parts[0];
  18. addr[1] = u.parts[1];
  19. }
  20. static inline void
  21. PUT_F64_TO_ADDR(uint32_t *addr, double value)
  22. {
  23. union {
  24. double val;
  25. uint32_t parts[2];
  26. } u;
  27. u.val = value;
  28. addr[0] = u.parts[0];
  29. addr[1] = u.parts[1];
  30. }
  31. static inline int64_t
  32. GET_I64_FROM_ADDR(uint32_t *addr)
  33. {
  34. union {
  35. int64_t val;
  36. uint32_t parts[2];
  37. } u;
  38. u.parts[0] = addr[0];
  39. u.parts[1] = addr[1];
  40. return u.val;
  41. }
  42. static inline double
  43. GET_F64_FROM_ADDR(uint32_t *addr)
  44. {
  45. union {
  46. double val;
  47. uint32_t parts[2];
  48. } u;
  49. u.parts[0] = addr[0];
  50. u.parts[1] = addr[1];
  51. return u.val;
  52. }
  53. */
  54. import "C"
  55. import (
  56. "runtime"
  57. "unsafe"
  58. "fmt"
  59. )
  60. type Instance struct {
  61. _instance C.wasm_module_inst_t
  62. _exec_env C.wasm_exec_env_t
  63. _module *Module
  64. _exportsCache map[string]C.wasm_function_inst_t
  65. }
  66. /* Create instance from the module */
  67. func NewInstance(module *Module,
  68. stackSize uint, heapSize uint) (*Instance, error) {
  69. if (module == nil) {
  70. return nil, fmt.Errorf("NewInstance error: invalid input")
  71. }
  72. errorBytes := make([]byte, 128)
  73. errorPtr := (*C.char)(unsafe.Pointer(&errorBytes[0]))
  74. errorLen := C.uint(len(errorBytes))
  75. instance := C.wasm_runtime_instantiate(module.module, C.uint(stackSize),
  76. C.uint(heapSize), errorPtr, errorLen)
  77. if (instance == nil) {
  78. return nil, fmt.Errorf("NewInstance Error: %s", string(errorBytes))
  79. }
  80. exec_env := C.wasm_runtime_create_exec_env(instance, C.uint(stackSize))
  81. if (exec_env == nil) {
  82. C.wasm_runtime_deinstantiate(instance)
  83. return nil, fmt.Errorf("NewInstance Error: create exec_env failed")
  84. }
  85. self := &Instance{
  86. _instance: instance,
  87. _exec_env: exec_env,
  88. _module: module,
  89. _exportsCache: make(map[string]C.wasm_function_inst_t),
  90. }
  91. runtime.SetFinalizer(self, func(self *Instance) {
  92. self.Destroy()
  93. })
  94. return self, nil
  95. }
  96. /* Destroy the instance */
  97. func (self *Instance) Destroy() {
  98. runtime.SetFinalizer(self, nil)
  99. if (self._instance != nil) {
  100. C.wasm_runtime_deinstantiate(self._instance)
  101. }
  102. if (self._exec_env != nil) {
  103. C.wasm_runtime_destroy_exec_env(self._exec_env)
  104. }
  105. }
  106. /* Call the wasm function with argument in the uint32 array, and store
  107. the return values back into the array */
  108. func (self *Instance) CallFunc(funcName string,
  109. argc uint32, args []uint32) error {
  110. _func := self._exportsCache[funcName]
  111. if _func == nil {
  112. cName := C.CString(funcName)
  113. defer C.free(unsafe.Pointer(cName))
  114. _func = C.wasm_runtime_lookup_function(self._instance,
  115. cName, (*C.char)(C.NULL))
  116. if _func == nil {
  117. return fmt.Errorf("CallFunc error: lookup function failed")
  118. }
  119. self._exportsCache[funcName] = _func
  120. }
  121. thread_env_inited := Runtime().ThreadEnvInited()
  122. if (!thread_env_inited) {
  123. Runtime().InitThreadEnv()
  124. }
  125. var args_C *C.uint32_t
  126. if (argc > 0) {
  127. args_C = (*C.uint32_t)(unsafe.Pointer(&args[0]))
  128. }
  129. if (!C.wasm_runtime_call_wasm(self._exec_env, _func,
  130. C.uint(argc), args_C)) {
  131. if (!thread_env_inited) {
  132. Runtime().DestroyThreadEnv()
  133. }
  134. return fmt.Errorf("CallFunc error: %s", string(self.GetException()))
  135. }
  136. if (!thread_env_inited) {
  137. Runtime().DestroyThreadEnv()
  138. }
  139. return nil
  140. }
  141. /* Call the wasm function with variant arguments, and store the return
  142. values back into the results array */
  143. func (self *Instance) CallFuncV(funcName string,
  144. num_results uint32, results []interface{},
  145. args ... interface{}) error {
  146. _func := self._exportsCache[funcName]
  147. if _func == nil {
  148. cName := C.CString(funcName)
  149. defer C.free(unsafe.Pointer(cName))
  150. _func = C.wasm_runtime_lookup_function(self._instance,
  151. cName, (*C.char)(C.NULL))
  152. if _func == nil {
  153. return fmt.Errorf("CallFunc error: lookup function failed")
  154. }
  155. self._exportsCache[funcName] = _func
  156. }
  157. param_count := uint32(C.wasm_func_get_param_count(_func, self._instance))
  158. result_count := uint32(C.wasm_func_get_result_count(_func, self._instance))
  159. if (num_results < result_count) {
  160. str := "CallFunc error: invalid result count %d, " +
  161. "must be no smaller than %d"
  162. return fmt.Errorf(str, num_results, result_count)
  163. }
  164. param_types := make([]C.uchar, param_count, param_count)
  165. result_types := make([]C.uchar, result_count, result_count)
  166. if (param_count > 0) {
  167. C.wasm_func_get_param_types(_func, self._instance,
  168. (*C.uchar)(unsafe.Pointer(&param_types[0])))
  169. }
  170. if (result_count > 0) {
  171. C.wasm_func_get_result_types(_func, self._instance,
  172. (*C.uchar)(unsafe.Pointer(&result_types[0])))
  173. }
  174. argv_size := param_count * 2
  175. if (result_count > param_count) {
  176. argv_size = result_count * 2
  177. }
  178. argv := make([]uint32, argv_size, argv_size)
  179. var i, argc uint32
  180. for _, arg := range args {
  181. if (i >= param_count) {
  182. break;
  183. }
  184. switch arg.(type) {
  185. case int32:
  186. if (param_types[i] != C.WASM_I32 &&
  187. param_types[i] != C.WASM_FUNCREF &&
  188. param_types[i] != C.WASM_ANYREF) {
  189. str := "CallFunc error: invalid param type %d, " +
  190. "expect i32 but got other"
  191. return fmt.Errorf(str, param_types[i])
  192. }
  193. argv[argc] = (uint32)(arg.(int32))
  194. argc++
  195. break
  196. case int64:
  197. if (param_types[i] != C.WASM_I64) {
  198. str := "CallFunc error: invalid param type %d, " +
  199. "expect i64 but got other"
  200. return fmt.Errorf(str, param_types[i])
  201. }
  202. addr := (*C.uint32_t)(unsafe.Pointer(&argv[argc]))
  203. C.PUT_I64_TO_ADDR(addr, (C.int64_t)(arg.(int64)))
  204. argc += 2
  205. break
  206. case float32:
  207. if (param_types[i] != C.WASM_F32) {
  208. str := "CallFunc error: invalid param type %d, " +
  209. "expect f32 but got other"
  210. return fmt.Errorf(str, param_types[i])
  211. }
  212. *(*C.float)(unsafe.Pointer(&argv[argc])) = (C.float)(arg.(float32))
  213. argc++
  214. break
  215. case float64:
  216. if (param_types[i] != C.WASM_F64) {
  217. str := "CallFunc error: invalid param type %d, " +
  218. "expect f64 but got other"
  219. return fmt.Errorf(str, param_types[i])
  220. }
  221. addr := (*C.uint32_t)(unsafe.Pointer(&argv[argc]))
  222. C.PUT_F64_TO_ADDR(addr, (C.double)(arg.(float64)))
  223. argc += 2
  224. break
  225. default:
  226. return fmt.Errorf("CallFunc error: unknown param type %d",
  227. param_types[i])
  228. }
  229. i++
  230. }
  231. if (i < param_count) {
  232. str := "CallFunc error: invalid param count, " +
  233. "must be no smaller than %d"
  234. return fmt.Errorf(str, param_count)
  235. }
  236. err := self.CallFunc(funcName, argc, argv)
  237. if (err != nil) {
  238. return err
  239. }
  240. argc = 0
  241. for i = 0; i < result_count; i++ {
  242. switch result_types[i] {
  243. case C.WASM_I32:
  244. case C.WASM_FUNCREF:
  245. case C.WASM_ANYREF:
  246. i32 := (int32)(argv[argc])
  247. results[i] = i32
  248. argc++
  249. break
  250. case C.WASM_I64:
  251. addr := (*C.uint32_t)(unsafe.Pointer(&argv[argc]))
  252. results[i] = (int64)(C.GET_I64_FROM_ADDR(addr))
  253. argc += 2
  254. break
  255. case C.WASM_F32:
  256. addr := (*C.float)(unsafe.Pointer(&argv[argc]))
  257. results[i] = (float32)(*addr)
  258. argc++
  259. break
  260. case C.WASM_F64:
  261. addr := (*C.uint32_t)(unsafe.Pointer(&argv[argc]))
  262. results[i] = (float64)(C.GET_F64_FROM_ADDR(addr))
  263. argc += 2
  264. break
  265. }
  266. }
  267. return nil
  268. }
  269. /* Get exception info of the instance */
  270. func (self *Instance) GetException() string {
  271. cStr := C.wasm_runtime_get_exception(self._instance)
  272. goStr := C.GoString(cStr)
  273. return goStr
  274. }
  275. /* Allocate memory from the heap of the instance */
  276. func (self Instance) ModuleMalloc(size uint32) (uint32, *uint8) {
  277. var offset C.uint32_t
  278. native_addrs := make([]*uint8, 1, 1)
  279. ptr := unsafe.Pointer(&native_addrs[0])
  280. offset = C.wasm_runtime_module_malloc(self._instance, (C.uint32_t)(size),
  281. (*unsafe.Pointer)(ptr))
  282. return (uint32)(offset), native_addrs[0]
  283. }
  284. /* Free memory to the heap of the instance */
  285. func (self Instance) ModuleFree(offset uint32) {
  286. C.wasm_runtime_module_free(self._instance, (C.uint32_t)(offset))
  287. }
  288. func (self Instance) ValidateAppAddr(app_offset uint32, size uint32) bool {
  289. ret := C.wasm_runtime_validate_app_addr(self._instance,
  290. (C.uint32_t)(app_offset),
  291. (C.uint32_t)(size))
  292. return (bool)(ret)
  293. }
  294. func (self Instance) ValidateStrAddr(app_str_offset uint32) bool {
  295. ret := C.wasm_runtime_validate_app_str_addr(self._instance,
  296. (C.uint32_t)(app_str_offset))
  297. return (bool)(ret)
  298. }
  299. func (self Instance) ValidateNativeAddr(native_ptr *uint8, size uint32) bool {
  300. native_ptr_C := (unsafe.Pointer)(native_ptr)
  301. ret := C.wasm_runtime_validate_native_addr(self._instance,
  302. native_ptr_C,
  303. (C.uint32_t)(size))
  304. return (bool)(ret)
  305. }
  306. func (self Instance) AddrAppToNative(app_offset uint32) *uint8 {
  307. native_ptr := C.wasm_runtime_addr_app_to_native(self._instance,
  308. (C.uint32_t)(app_offset))
  309. return (*uint8)(native_ptr)
  310. }
  311. func (self Instance) AddrNativeToApp(native_ptr *uint8) uint32 {
  312. native_ptr_C := (unsafe.Pointer)(native_ptr)
  313. offset := C.wasm_runtime_addr_native_to_app(self._instance,
  314. native_ptr_C)
  315. return (uint32)(offset)
  316. }
  317. func (self Instance) GetAppAddrRange(app_offset uint32) (bool,
  318. uint32,
  319. uint32) {
  320. var start_offset, end_offset C.uint32_t
  321. ret := C.wasm_runtime_get_app_addr_range(self._instance,
  322. (C.uint32_t)(app_offset),
  323. &start_offset, &end_offset)
  324. return (bool)(ret), (uint32)(start_offset), (uint32)(end_offset)
  325. }
  326. func (self Instance) GetNativeAddrRange(native_ptr *uint8) (bool,
  327. *uint8,
  328. *uint8) {
  329. var start_addr, end_addr *C.uint8_t
  330. native_ptr_C := (*C.uint8_t)((unsafe.Pointer)(native_ptr))
  331. ret := C.wasm_runtime_get_native_addr_range(self._instance,
  332. native_ptr_C,
  333. &start_addr, &end_addr)
  334. return (bool)(ret), (*uint8)(start_addr), (*uint8)(end_addr)
  335. }
  336. func (self Instance) DumpMemoryConsumption() {
  337. C.wasm_runtime_dump_mem_consumption(self._exec_env)
  338. }
  339. func (self Instance) DumpCallStack() {
  340. C.wasm_runtime_dump_call_stack(self._exec_env)
  341. }