test_advanced.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. # -*- coding: utf-8 -*-
  2. #!/usr/bin/env python3
  3. #
  4. # Copyright (C) 2019 Intel Corporation. All rights reserved.
  5. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. #
  7. # pylint: disable=missing-class-docstring
  8. # pylint: disable=missing-function-docstring
  9. # pylint: disable=missing-module-docstring
  10. import ctypes as c
  11. import math
  12. import unittest
  13. import wamr.wasmcapi.ffi as ffi
  14. # It is a module likes:
  15. # (module
  16. # (import "mod" "g0" (global i32))
  17. # (import "mod" "f0" (func (param f32) (result f64)))
  18. #
  19. # (func (export "f1") (param i32 i64))
  20. # (global (export "g1") (mut f32) (f32.const 3.14))
  21. # (memory (export "m1") 1 2)
  22. # (table (export "t1") 1 funcref)
  23. #
  24. # (func (export "f2") (unreachable))
  25. # )
  26. MODULE_BINARY = (
  27. b"\x00asm\x01\x00\x00\x00\x01\x0e\x03`\x01}\x01|`\x02\x7f~\x00`\x00"
  28. b"\x00\x02\x14\x02\x03mod\x02g0\x03\x7f\x00\x03mod\x02f0\x00\x00\x03\x03"
  29. b"\x02\x01\x02\x04\x04\x01p\x00\x01\x05\x04\x01\x01\x01\x02\x06\t\x01}\x01C"
  30. b"\xc3\xf5H@\x0b\x07\x1a\x05\x02f1\x00\x01\x02g1\x03\x01\x02m1\x02\x00\x02t1"
  31. b"\x01\x00\x02f2\x00\x02\n\x08\x02\x02\x00\x0b\x03\x00\x00\x0b"
  32. )
  33. # False -> True when testing with a library enabling WAMR_BUILD_DUMP_CALL_STACK flag
  34. TEST_WITH_WAMR_BUILD_DUMP_CALL_STACK = False
  35. @ffi.wasm_func_cb_decl
  36. def callback(args, results):
  37. args = ffi.dereference(args)
  38. results = ffi.dereference(results)
  39. arg_v = args.data[0]
  40. result_v = ffi.wasm_f64_val(arg_v.of.f32 * 2.0)
  41. ffi.wasm_val_copy(results.data[0], result_v)
  42. results.num_elems = 1
  43. print(f"\nIn callback: {arg_v} --> {result_v}\n")
  44. @ffi.wasm_func_with_env_cb_decl
  45. def callback_with_env(env, args, results):
  46. # pylint: disable=unused-argument
  47. print("summer")
  48. class AdvancedTestSuite(unittest.TestCase):
  49. @classmethod
  50. def setUpClass(cls):
  51. print("Initializing...")
  52. cls._wasm_engine = ffi.wasm_engine_new()
  53. cls._wasm_store = ffi.wasm_store_new(cls._wasm_engine)
  54. def assertIsNullPointer(self, pointer):
  55. # pylint: disable=invalid-name
  56. if not ffi.is_null_pointer(pointer):
  57. self.fail("not a non-null pointer")
  58. def assertIsNotNullPointer(self, pointer):
  59. # pylint: disable=invalid-name
  60. if ffi.is_null_pointer(pointer):
  61. self.fail("not a non-null pointer")
  62. def load_binary(self, binary_string):
  63. print("Load binary...")
  64. binary = ffi.load_module_file(binary_string)
  65. binary = c.pointer(binary)
  66. self.assertIsNotNullPointer(binary)
  67. return binary
  68. def compile(self, binary):
  69. print("Compile...")
  70. module = ffi.wasm_module_new(self._wasm_store, binary)
  71. self.assertIsNotNullPointer(module)
  72. return module
  73. def prepare_imports_local(self):
  74. print("Prepare imports...")
  75. func_type = ffi.wasm_functype_new_1_1(
  76. ffi.wasm_valtype_new(ffi.WASM_F32),
  77. ffi.wasm_valtype_new(ffi.WASM_F64),
  78. )
  79. func = ffi.wasm_func_new(self._wasm_store, func_type, callback)
  80. self.assertIsNotNullPointer(func)
  81. ffi.wasm_functype_delete(func_type)
  82. glbl_type = ffi.wasm_globaltype_new(ffi.wasm_valtype_new(ffi.WASM_I32), True)
  83. init = ffi.wasm_i32_val(1024)
  84. glbl = ffi.wasm_global_new(self._wasm_store, glbl_type, init)
  85. self.assertIsNotNullPointer(glbl)
  86. ffi.wasm_globaltype_delete(glbl_type)
  87. imports = ffi.wasm_extern_vec_t()
  88. data = ffi.list_to_carray(
  89. c.POINTER(ffi.wasm_extern_t),
  90. ffi.wasm_func_as_extern(func),
  91. ffi.wasm_global_as_extern(glbl),
  92. )
  93. ffi.wasm_extern_vec_new(imports, 2, data)
  94. imports = c.pointer(imports)
  95. self.assertIsNotNullPointer(imports)
  96. return imports
  97. def instantiate(self, module, imports):
  98. print("Instantiate module...")
  99. instance = ffi.wasm_instance_new(
  100. self._wasm_store, module, imports, ffi.create_null_pointer(ffi.wasm_trap_t)
  101. )
  102. self.assertIsNotNone(instance)
  103. self.assertIsNotNullPointer(instance)
  104. return instance
  105. def extract_exports(self, instance):
  106. print("Extracting exports...")
  107. exports = ffi.wasm_extern_vec_t()
  108. ffi.wasm_instance_exports(instance, exports)
  109. exports = c.pointer(exports)
  110. self.assertIsNotNullPointer(exports)
  111. return exports
  112. def setUp(self):
  113. binary = self.load_binary(MODULE_BINARY)
  114. self.module = self.compile(binary)
  115. self.imports = self.prepare_imports_local()
  116. self.instance = self.instantiate(self.module, self.imports)
  117. self.exports = self.extract_exports(self.instance)
  118. ffi.wasm_byte_vec_delete(binary)
  119. def tearDown(self):
  120. if self.imports:
  121. ffi.wasm_extern_vec_delete(self.imports)
  122. if self.exports:
  123. ffi.wasm_extern_vec_delete(self.exports)
  124. ffi.wasm_instance_delete(self.instance)
  125. ffi.wasm_module_delete(self.module)
  126. def test_wasm_func_call_wasm(self):
  127. export_list = ffi.wasm_vec_to_list(self.exports)
  128. print(export_list)
  129. func = ffi.wasm_extern_as_func(export_list[0])
  130. self.assertIsNotNullPointer(func)
  131. # make a call
  132. params = ffi.wasm_val_vec_t()
  133. data = ffi.list_to_carray(
  134. ffi.wasm_val_t,
  135. ffi.wasm_i32_val(1024),
  136. ffi.wasm_i64_val(1024 * 1024),
  137. )
  138. ffi.wasm_val_vec_new(params, 2, data)
  139. results = ffi.wasm_val_vec_t()
  140. ffi.wasm_val_vec_new_empty(results)
  141. ffi.wasm_func_call(func, params, results)
  142. def test_wasm_func_call_native(self):
  143. import_list = ffi.wasm_vec_to_list(self.imports)
  144. func = ffi.wasm_extern_as_func(import_list[0])
  145. self.assertIsNotNullPointer(func)
  146. params = ffi.wasm_val_vec_t()
  147. ffi.wasm_val_vec_new(
  148. params, 1, ffi.list_to_carray(ffi.wasm_val_t, ffi.wasm_f32_val(3.14))
  149. )
  150. results = ffi.wasm_val_vec_t()
  151. ffi.wasm_val_vec_new_uninitialized(results, 1)
  152. ffi.wasm_func_call(func, params, results)
  153. self.assertEqual(params.data[0].of.f32 * 2, results.data[0].of.f64)
  154. def test_wasm_func_call_unlinked(self):
  155. ft = ffi.wasm_functype_new_0_0()
  156. func = ffi.wasm_func_new(self._wasm_store, ft, callback)
  157. params = ffi.wasm_val_vec_t()
  158. ffi.wasm_val_vec_new_empty(params)
  159. results = ffi.wasm_val_vec_t()
  160. ffi.wasm_val_vec_new_empty(results)
  161. trap = ffi.wasm_func_call(func, params, results)
  162. ffi.wasm_func_delete(func)
  163. def test_wasm_global_get_wasm(self):
  164. export_list = ffi.wasm_vec_to_list(self.exports)
  165. glb = ffi.wasm_extern_as_global(export_list[1])
  166. self.assertIsNotNullPointer(glb)
  167. # access the global
  168. val = ffi.wasm_val_t()
  169. ffi.wasm_global_get(glb, val)
  170. self.assertAlmostEqual(val.of.f32, 3.14, places=3)
  171. def test_wasm_global_get_native(self):
  172. import_list = ffi.wasm_vec_to_list(self.imports)
  173. glb = ffi.wasm_extern_as_global(import_list[1])
  174. self.assertIsNotNullPointer(glb)
  175. val = ffi.wasm_val_t()
  176. ffi.wasm_global_get(glb, val)
  177. self.assertEqual(val.of.i32, 1024)
  178. def test_wasm_global_get_unlinked(self):
  179. gt = ffi.wasm_globaltype_new(ffi.wasm_valtype_new(ffi.WASM_I32), True)
  180. init = ffi.wasm_i32_val(32)
  181. glbl = ffi.wasm_global_new(self._wasm_store, gt, init)
  182. val_ret = ffi.wasm_f32_val(3.14)
  183. ffi.wasm_global_get(glbl, val_ret)
  184. ffi.wasm_global_delete(glbl)
  185. # val_ret wasn't touched, keep the original value
  186. self.assertAlmostEqual(val_ret.of.f32, 3.14, 3)
  187. def test_wasm_global_get_null_val(self):
  188. export_list = ffi.wasm_vec_to_list(self.exports)
  189. glb = ffi.wasm_extern_as_global(export_list[1])
  190. ffi.wasm_global_get(glb, ffi.create_null_pointer(ffi.wasm_val_t))
  191. def test_wasm_global_get_null_global(self):
  192. val = ffi.wasm_val_t()
  193. ffi.wasm_global_get(ffi.create_null_pointer(ffi.wasm_global_t), val)
  194. def test_wasm_global_set_wasm(self):
  195. export_list = ffi.wasm_vec_to_list(self.exports)
  196. glb = ffi.wasm_extern_as_global(export_list[1])
  197. self.assertIsNotNullPointer(glb)
  198. # access the global
  199. new_val = ffi.wasm_f32_val(math.e)
  200. ffi.wasm_global_set(glb, new_val)
  201. val = ffi.wasm_val_t()
  202. ffi.wasm_global_get(glb, val)
  203. self.assertNotEqual(val.of.f32, 3.14)
  204. def test_wasm_global_set_native(self):
  205. import_list = ffi.wasm_vec_to_list(self.imports)
  206. glb = ffi.wasm_extern_as_global(import_list[1])
  207. self.assertIsNotNullPointer(glb)
  208. new_val = ffi.wasm_i32_val(2048)
  209. ffi.wasm_global_set(glb, new_val)
  210. val = ffi.wasm_val_t()
  211. ffi.wasm_global_get(glb, val)
  212. self.assertEqual(val, new_val)
  213. def test_wasm_global_set_unlinked(self):
  214. gt = ffi.wasm_globaltype_new(ffi.wasm_valtype_new(ffi.WASM_I32), True)
  215. init = ffi.wasm_i32_val(32)
  216. glbl = ffi.wasm_global_new(self._wasm_store, gt, init)
  217. val_ret = ffi.wasm_f32_val(3.14)
  218. ffi.wasm_global_set(glbl, val_ret)
  219. ffi.wasm_global_delete(glbl)
  220. def test_wasm_global_set_null_v(self):
  221. export_list = ffi.wasm_vec_to_list(self.exports)
  222. glb = ffi.wasm_extern_as_global(export_list[1])
  223. # access the global
  224. ffi.wasm_global_set(glb, ffi.create_null_pointer(ffi.wasm_val_t))
  225. def test_wasm_global_set_null_global(self):
  226. # access the global
  227. new_val = ffi.wasm_f32_val(math.e)
  228. ffi.wasm_global_set(ffi.create_null_pointer(ffi.wasm_global_t), new_val)
  229. def test_wasm_table_size(self):
  230. export_list = ffi.wasm_vec_to_list(self.exports)
  231. tbl = ffi.wasm_extern_as_table(export_list[3])
  232. self.assertIsNotNullPointer(tbl)
  233. tbl_sz = ffi.wasm_table_size(tbl)
  234. self.assertEqual(tbl_sz, 1)
  235. def test_wasm_table_size_unlink(self):
  236. vt = ffi.wasm_valtype_new(ffi.WASM_FUNCREF)
  237. limits = ffi.wasm_limits_new(10, 15)
  238. tt = ffi.wasm_tabletype_new(vt, limits)
  239. tbl = ffi.wasm_table_new(
  240. self._wasm_store, tt, ffi.create_null_pointer(ffi.wasm_ref_t)
  241. )
  242. tbl_sz = ffi.wasm_table_size(tbl)
  243. ffi.wasm_table_delete(tbl)
  244. def test_wasm_table_size_null_table(self):
  245. ffi.wasm_table_size(ffi.create_null_pointer(ffi.wasm_table_t))
  246. def test_wasm_table_get(self):
  247. export_list = ffi.wasm_vec_to_list(self.exports)
  248. tbl = ffi.wasm_extern_as_table(export_list[3])
  249. self.assertIsNotNullPointer(tbl)
  250. ref = ffi.wasm_table_get(tbl, 0)
  251. self.assertIsNullPointer(ref)
  252. ref = ffi.wasm_table_get(tbl, 4096)
  253. self.assertIsNullPointer(ref)
  254. def test_wasm_table_get_unlinked(self):
  255. vt = ffi.wasm_valtype_new(ffi.WASM_FUNCREF)
  256. limits = ffi.wasm_limits_new(10, 15)
  257. tt = ffi.wasm_tabletype_new(vt, limits)
  258. tbl = ffi.wasm_table_new(
  259. self._wasm_store, tt, ffi.create_null_pointer(ffi.wasm_ref_t)
  260. )
  261. ffi.wasm_table_get(tbl, 0)
  262. ffi.wasm_table_delete(tbl)
  263. def test_wasm_table_get_null_table(self):
  264. ffi.wasm_table_get(ffi.create_null_pointer(ffi.wasm_table_t), 0)
  265. def test_wasm_table_get_out_of_bounds(self):
  266. export_list = ffi.wasm_vec_to_list(self.exports)
  267. tbl = ffi.wasm_extern_as_table(export_list[3])
  268. ffi.wasm_table_get(tbl, 1_000_000_000)
  269. def test_wasm_ref(self):
  270. export_list = ffi.wasm_vec_to_list(self.exports)
  271. func = ffi.wasm_extern_as_func(export_list[0])
  272. self.assertIsNotNullPointer(func)
  273. ref = ffi.wasm_func_as_ref(func)
  274. self.assertIsNotNullPointer(ref)
  275. func_from_ref = ffi.wasm_ref_as_func(ref)
  276. self.assertEqual(
  277. ffi.dereference(ffi.wasm_func_type(func)),
  278. ffi.dereference(ffi.wasm_func_type(func_from_ref)),
  279. )
  280. def test_wasm_table_set(self):
  281. export_list = ffi.wasm_vec_to_list(self.exports)
  282. tbl = ffi.wasm_extern_as_table(export_list[3])
  283. self.assertIsNotNullPointer(tbl)
  284. func = ffi.wasm_extern_as_func(export_list[0])
  285. ref = ffi.wasm_func_as_ref(func)
  286. ffi.wasm_table_set(tbl, 0, ref)
  287. ref_ret = ffi.wasm_table_get(tbl, 0)
  288. self.assertIsNotNullPointer(ref_ret)
  289. func_ret = ffi.wasm_ref_as_func(ref_ret)
  290. self.assertEqual(
  291. ffi.dereference(ffi.wasm_func_type(func)),
  292. ffi.dereference(ffi.wasm_func_type(func_ret)),
  293. )
  294. def test_wasm_table_set_unlinked(self):
  295. vt = ffi.wasm_valtype_new(ffi.WASM_FUNCREF)
  296. limits = ffi.wasm_limits_new(10, 15)
  297. tt = ffi.wasm_tabletype_new(vt, limits)
  298. tbl = ffi.wasm_table_new(
  299. self._wasm_store, tt, ffi.create_null_pointer(ffi.wasm_ref_t)
  300. )
  301. export_list = ffi.wasm_vec_to_list(self.exports)
  302. func = ffi.wasm_extern_as_func(export_list[0])
  303. ref = ffi.wasm_func_as_ref(func)
  304. ffi.wasm_table_set(tbl, 0, ref)
  305. ffi.wasm_table_delete(tbl)
  306. def test_wasm_table_set_null_table(self):
  307. export_list = ffi.wasm_vec_to_list(self.exports)
  308. func = ffi.wasm_extern_as_func(export_list[0])
  309. ref = ffi.wasm_func_as_ref(func)
  310. ffi.wasm_table_set(ffi.create_null_pointer(ffi.wasm_table_t), 0, ref)
  311. def test_wasm_table_set_null_ref(self):
  312. export_list = ffi.wasm_vec_to_list(self.exports)
  313. tbl = ffi.wasm_extern_as_table(export_list[3])
  314. ffi.wasm_table_set(tbl, 0, ffi.create_null_pointer(ffi.wasm_ref_t))
  315. def test_wasm_table_set_out_of_bounds(self):
  316. export_list = ffi.wasm_vec_to_list(self.exports)
  317. tbl = ffi.wasm_extern_as_table(export_list[3])
  318. func = ffi.wasm_extern_as_func(export_list[0])
  319. ref = ffi.wasm_func_as_ref(func)
  320. ffi.wasm_table_set(tbl, 1_000_000_000, ref)
  321. def test_wasm_memory_size(self):
  322. export_list = ffi.wasm_vec_to_list(self.exports)
  323. mem = ffi.wasm_extern_as_memory(export_list[2])
  324. self.assertIsNotNullPointer(mem)
  325. pg_sz = ffi.wasm_memory_size(mem)
  326. self.assertEqual(pg_sz, 1)
  327. def test_wasm_memory_size_unlinked(self):
  328. limits = ffi.wasm_limits_new(10, 12)
  329. mt = ffi.wasm_memorytype_new(limits)
  330. mem = ffi.wasm_memory_new(self._wasm_store, mt)
  331. ffi.wasm_memory_size(mem)
  332. ffi.wasm_memory_delete(mem)
  333. def test_wasm_memory_data(self):
  334. export_list = ffi.wasm_vec_to_list(self.exports)
  335. mem = ffi.wasm_extern_as_memory(export_list[2])
  336. self.assertIsNotNullPointer(mem)
  337. data_base = ffi.wasm_memory_data(mem)
  338. self.assertIsNotNone(data_base)
  339. def test_wasm_memory_data_unlinked(self):
  340. limits = ffi.wasm_limits_new(10, 12)
  341. mt = ffi.wasm_memorytype_new(limits)
  342. mem = ffi.wasm_memory_new(self._wasm_store, mt)
  343. ffi.wasm_memory_data(mem)
  344. ffi.wasm_memory_delete(mem)
  345. def test_wasm_memory_data_size(self):
  346. export_list = ffi.wasm_vec_to_list(self.exports)
  347. mem = ffi.wasm_extern_as_memory(export_list[2])
  348. self.assertIsNotNullPointer(mem)
  349. mem_sz = ffi.wasm_memory_data_size(mem)
  350. self.assertGreater(mem_sz, 0)
  351. def test_wasm_memory_data_size_unlinked(self):
  352. limits = ffi.wasm_limits_new(10, 12)
  353. mt = ffi.wasm_memorytype_new(limits)
  354. mem = ffi.wasm_memory_new(self._wasm_store, mt)
  355. ffi.wasm_memory_data_size(mem)
  356. ffi.wasm_memory_delete(mem)
  357. @unittest.skipUnless(
  358. TEST_WITH_WAMR_BUILD_DUMP_CALL_STACK,
  359. "need to enable WAMR_BUILD_DUMP_CALL_STACK",
  360. )
  361. # assertions only works if enabling WAMR_BUILD_DUMP_CALL_STACK
  362. def test_wasm_frame(self):
  363. export_list = ffi.wasm_vec_to_list(self.exports)
  364. func = ffi.wasm_extern_as_func(export_list[4])
  365. # make a call
  366. params = ffi.wasm_val_vec_t()
  367. ffi.wasm_val_vec_new_empty(params)
  368. results = ffi.wasm_val_vec_t()
  369. ffi.wasm_val_vec_new_empty(results)
  370. print("Making a call...")
  371. trap = ffi.wasm_func_call(func, params, results)
  372. message = ffi.wasm_message_t()
  373. ffi.wasm_trap_message(trap, message)
  374. self.assertIsNotNullPointer(c.pointer(message))
  375. print(message)
  376. frame = ffi.wasm_trap_origin(trap)
  377. self.assertIsNotNullPointer(frame)
  378. print(ffi.dereference(frame))
  379. traces = ffi.wasm_frame_vec_t()
  380. ffi.wasm_trap_trace(trap, traces)
  381. self.assertIsNotNullPointer(c.pointer(frame))
  382. instance = ffi.wasm_frame_instance(frame)
  383. self.assertIsNotNullPointer(instance)
  384. module_offset = ffi.wasm_frame_module_offset(frame)
  385. func_index = ffi.wasm_frame_func_index(frame)
  386. self.assertEqual(func_index, 2)
  387. func_offset = ffi.wasm_frame_func_offset(frame)
  388. self.assertGreater(func_offset, 0)
  389. @classmethod
  390. def tearDownClass(cls):
  391. print("Shutting down...")
  392. ffi.wasm_store_delete(cls._wasm_store)
  393. ffi.wasm_engine_delete(cls._wasm_engine)
  394. if __name__ == "__main__":
  395. unittest.main()