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, cName)
  115. if _func == nil {
  116. return fmt.Errorf("CallFunc error: lookup function failed")
  117. }
  118. self._exportsCache[funcName] = _func
  119. }
  120. thread_env_inited := Runtime().ThreadEnvInited()
  121. if (!thread_env_inited) {
  122. Runtime().InitThreadEnv()
  123. }
  124. var args_C *C.uint32_t
  125. if (argc > 0) {
  126. args_C = (*C.uint32_t)(unsafe.Pointer(&args[0]))
  127. }
  128. if (!C.wasm_runtime_call_wasm(self._exec_env, _func,
  129. C.uint(argc), args_C)) {
  130. if (!thread_env_inited) {
  131. Runtime().DestroyThreadEnv()
  132. }
  133. return fmt.Errorf("CallFunc error: %s", string(self.GetException()))
  134. }
  135. if (!thread_env_inited) {
  136. Runtime().DestroyThreadEnv()
  137. }
  138. return nil
  139. }
  140. /* Call the wasm function with variant arguments, and store the return
  141. values back into the results array */
  142. func (self *Instance) CallFuncV(funcName string,
  143. num_results uint32, results []interface{},
  144. args ... interface{}) error {
  145. _func := self._exportsCache[funcName]
  146. if _func == nil {
  147. cName := C.CString(funcName)
  148. defer C.free(unsafe.Pointer(cName))
  149. _func = C.wasm_runtime_lookup_function(self._instance, cName)
  150. if _func == nil {
  151. return fmt.Errorf("CallFunc error: lookup function failed")
  152. }
  153. self._exportsCache[funcName] = _func
  154. }
  155. param_count := uint32(C.wasm_func_get_param_count(_func, self._instance))
  156. result_count := uint32(C.wasm_func_get_result_count(_func, self._instance))
  157. if (num_results < result_count) {
  158. str := "CallFunc error: invalid result count %d, " +
  159. "must be no smaller than %d"
  160. return fmt.Errorf(str, num_results, result_count)
  161. }
  162. param_types := make([]C.uchar, param_count, param_count)
  163. result_types := make([]C.uchar, result_count, result_count)
  164. if (param_count > 0) {
  165. C.wasm_func_get_param_types(_func, self._instance,
  166. (*C.uchar)(unsafe.Pointer(&param_types[0])))
  167. }
  168. if (result_count > 0) {
  169. C.wasm_func_get_result_types(_func, self._instance,
  170. (*C.uchar)(unsafe.Pointer(&result_types[0])))
  171. }
  172. argv_size := param_count * 2
  173. if (result_count > param_count) {
  174. argv_size = result_count * 2
  175. }
  176. argv := make([]uint32, argv_size, argv_size)
  177. var i, argc uint32
  178. for _, arg := range args {
  179. if (i >= param_count) {
  180. break;
  181. }
  182. switch arg.(type) {
  183. case int32:
  184. if (param_types[i] != C.WASM_I32 &&
  185. param_types[i] != C.WASM_FUNCREF &&
  186. param_types[i] != C.WASM_EXTERNREF) {
  187. str := "CallFunc error: invalid param type %d, " +
  188. "expect i32 but got other"
  189. return fmt.Errorf(str, param_types[i])
  190. }
  191. argv[argc] = (uint32)(arg.(int32))
  192. argc++
  193. break
  194. case int64:
  195. if (param_types[i] != C.WASM_I64) {
  196. str := "CallFunc error: invalid param type %d, " +
  197. "expect i64 but got other"
  198. return fmt.Errorf(str, param_types[i])
  199. }
  200. addr := (*C.uint32_t)(unsafe.Pointer(&argv[argc]))
  201. C.PUT_I64_TO_ADDR(addr, (C.int64_t)(arg.(int64)))
  202. argc += 2
  203. break
  204. case float32:
  205. if (param_types[i] != C.WASM_F32) {
  206. str := "CallFunc error: invalid param type %d, " +
  207. "expect f32 but got other"
  208. return fmt.Errorf(str, param_types[i])
  209. }
  210. *(*C.float)(unsafe.Pointer(&argv[argc])) = (C.float)(arg.(float32))
  211. argc++
  212. break
  213. case float64:
  214. if (param_types[i] != C.WASM_F64) {
  215. str := "CallFunc error: invalid param type %d, " +
  216. "expect f64 but got other"
  217. return fmt.Errorf(str, param_types[i])
  218. }
  219. addr := (*C.uint32_t)(unsafe.Pointer(&argv[argc]))
  220. C.PUT_F64_TO_ADDR(addr, (C.double)(arg.(float64)))
  221. argc += 2
  222. break
  223. default:
  224. return fmt.Errorf("CallFunc error: unknown param type %d",
  225. param_types[i])
  226. }
  227. i++
  228. }
  229. if (i < param_count) {
  230. str := "CallFunc error: invalid param count, " +
  231. "must be no smaller than %d"
  232. return fmt.Errorf(str, param_count)
  233. }
  234. err := self.CallFunc(funcName, argc, argv)
  235. if (err != nil) {
  236. return err
  237. }
  238. argc = 0
  239. for i = 0; i < result_count; i++ {
  240. switch result_types[i] {
  241. case C.WASM_I32:
  242. fallthrough
  243. case C.WASM_FUNCREF:
  244. fallthrough
  245. case C.WASM_EXTERNREF:
  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 uint64) (uint64, *uint8) {
  277. var offset C.uint64_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.uint64_t)(size),
  281. (*unsafe.Pointer)(ptr))
  282. return (uint64)(offset), native_addrs[0]
  283. }
  284. /* Free memory to the heap of the instance */
  285. func (self Instance) ModuleFree(offset uint64) {
  286. C.wasm_runtime_module_free(self._instance, (C.uint64_t)(offset))
  287. }
  288. func (self Instance) ValidateAppAddr(app_offset uint64, size uint64) bool {
  289. ret := C.wasm_runtime_validate_app_addr(self._instance,
  290. (C.uint64_t)(app_offset),
  291. (C.uint64_t)(size))
  292. return (bool)(ret)
  293. }
  294. func (self Instance) ValidateStrAddr(app_str_offset uint64) bool {
  295. ret := C.wasm_runtime_validate_app_str_addr(self._instance,
  296. (C.uint64_t)(app_str_offset))
  297. return (bool)(ret)
  298. }
  299. func (self Instance) ValidateNativeAddr(native_ptr *uint8, size uint64) 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.uint64_t)(size))
  304. return (bool)(ret)
  305. }
  306. func (self Instance) AddrAppToNative(app_offset uint64) *uint8 {
  307. native_ptr := C.wasm_runtime_addr_app_to_native(self._instance,
  308. (C.uint64_t)(app_offset))
  309. return (*uint8)(native_ptr)
  310. }
  311. func (self Instance) AddrNativeToApp(native_ptr *uint8) uint64 {
  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 (uint64)(offset)
  316. }
  317. func (self Instance) GetAppAddrRange(app_offset uint64) (bool,
  318. uint64,
  319. uint64) {
  320. var start_offset, end_offset C.uint64_t
  321. ret := C.wasm_runtime_get_app_addr_range(self._instance,
  322. (C.uint64_t)(app_offset),
  323. &start_offset, &end_offset)
  324. return (bool)(ret), (uint64)(start_offset), (uint64)(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. }