test_advanced.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  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.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_wrong_params(self):
  155. export_list = ffi.wasm_vec_to_list(self.exports)
  156. func = ffi.wasm_extern_as_func(export_list[0])
  157. # make a call
  158. params = ffi.wasm_val_vec_t()
  159. ffi.wasm_val_vec_new_empty(params)
  160. results = ffi.wasm_val_vec_t()
  161. ffi.wasm_val_vec_new_empty(results)
  162. trap = ffi.wasm_func_call(func, params, results)
  163. self.assertIsNotNullPointer(trap)
  164. def test_wasm_func_call_unlinked(self):
  165. ft = ffi.wasm_functype_new_0_0()
  166. func = ffi.wasm_func_new(self._wasm_store, ft, callback)
  167. params = ffi.wasm_val_vec_t()
  168. ffi.wasm_val_vec_new_empty(params)
  169. results = ffi.wasm_val_vec_t()
  170. ffi.wasm_val_vec_new_empty(results)
  171. trap = ffi.wasm_func_call(func, params, results)
  172. ffi.wasm_func_delete(func)
  173. def test_wasm_global_get_wasm(self):
  174. export_list = ffi.wasm_vec_to_list(self.exports)
  175. glb = ffi.wasm_extern_as_global(export_list[1])
  176. self.assertIsNotNullPointer(glb)
  177. # access the global
  178. val = ffi.wasm_val_t()
  179. ffi.wasm_global_get(glb, val)
  180. self.assertAlmostEqual(val.of.f32, 3.14, places=3)
  181. def test_wasm_global_get_native(self):
  182. import_list = ffi.wasm_vec_to_list(self.imports)
  183. glb = ffi.wasm_extern_as_global(import_list[1])
  184. self.assertIsNotNullPointer(glb)
  185. val = ffi.wasm_val_t()
  186. ffi.wasm_global_get(glb, val)
  187. self.assertEqual(val.of.i32, 1024)
  188. def test_wasm_global_get_unlinked(self):
  189. gt = ffi.wasm_globaltype_new(ffi.wasm_valtype_new(ffi.WASM_I32), True)
  190. init = ffi.wasm_i32_val(32)
  191. glbl = ffi.wasm_global_new(self._wasm_store, gt, init)
  192. val_ret = ffi.wasm_f32_val(3.14)
  193. ffi.wasm_global_get(glbl, val_ret)
  194. ffi.wasm_global_delete(glbl)
  195. # val_ret wasn't touched, keep the original value
  196. self.assertAlmostEqual(val_ret.of.f32, 3.14, 3)
  197. def test_wasm_global_get_null_val(self):
  198. export_list = ffi.wasm_vec_to_list(self.exports)
  199. glb = ffi.wasm_extern_as_global(export_list[1])
  200. ffi.wasm_global_get(glb, ffi.create_null_pointer(ffi.wasm_val_t))
  201. def test_wasm_global_get_null_global(self):
  202. val = ffi.wasm_val_t()
  203. ffi.wasm_global_get(ffi.create_null_pointer(ffi.wasm_global_t), val)
  204. def test_wasm_global_set_wasm(self):
  205. export_list = ffi.wasm_vec_to_list(self.exports)
  206. glb = ffi.wasm_extern_as_global(export_list[1])
  207. self.assertIsNotNullPointer(glb)
  208. # access the global
  209. new_val = ffi.wasm_f32_val(math.e)
  210. ffi.wasm_global_set(glb, new_val)
  211. val = ffi.wasm_val_t()
  212. ffi.wasm_global_get(glb, val)
  213. self.assertNotEqual(val.of.f32, 3.14)
  214. def test_wasm_global_set_native(self):
  215. import_list = ffi.wasm_vec_to_list(self.imports)
  216. glb = ffi.wasm_extern_as_global(import_list[1])
  217. self.assertIsNotNullPointer(glb)
  218. new_val = ffi.wasm_i32_val(2048)
  219. ffi.wasm_global_set(glb, new_val)
  220. val = ffi.wasm_val_t()
  221. ffi.wasm_global_get(glb, val)
  222. self.assertEqual(val, new_val)
  223. def test_wasm_global_set_unlinked(self):
  224. gt = ffi.wasm_globaltype_new(ffi.wasm_valtype_new(ffi.WASM_I32), True)
  225. init = ffi.wasm_i32_val(32)
  226. glbl = ffi.wasm_global_new(self._wasm_store, gt, init)
  227. val_ret = ffi.wasm_f32_val(3.14)
  228. ffi.wasm_global_set(glbl, val_ret)
  229. ffi.wasm_global_delete(glbl)
  230. def test_wasm_global_set_null_v(self):
  231. export_list = ffi.wasm_vec_to_list(self.exports)
  232. glb = ffi.wasm_extern_as_global(export_list[1])
  233. # access the global
  234. ffi.wasm_global_set(glb, ffi.create_null_pointer(ffi.wasm_val_t))
  235. def test_wasm_global_set_null_global(self):
  236. # access the global
  237. new_val = ffi.wasm_f32_val(math.e)
  238. ffi.wasm_global_set(ffi.create_null_pointer(ffi.wasm_global_t), new_val)
  239. def test_wasm_table_size(self):
  240. export_list = ffi.wasm_vec_to_list(self.exports)
  241. tbl = ffi.wasm_extern_as_table(export_list[3])
  242. self.assertIsNotNullPointer(tbl)
  243. tbl_sz = ffi.wasm_table_size(tbl)
  244. self.assertEqual(tbl_sz, 1)
  245. def test_wasm_table_size_unlink(self):
  246. vt = ffi.wasm_valtype_new(ffi.WASM_FUNCREF)
  247. limits = ffi.wasm_limits_new(10, 15)
  248. tt = ffi.wasm_tabletype_new(vt, limits)
  249. tbl = ffi.wasm_table_new(
  250. self._wasm_store, tt, ffi.create_null_pointer(ffi.wasm_ref_t)
  251. )
  252. tbl_sz = ffi.wasm_table_size(tbl)
  253. ffi.wasm_table_delete(tbl)
  254. def test_wasm_table_size_null_table(self):
  255. ffi.wasm_table_size(ffi.create_null_pointer(ffi.wasm_table_t))
  256. def test_wasm_table_get(self):
  257. export_list = ffi.wasm_vec_to_list(self.exports)
  258. tbl = ffi.wasm_extern_as_table(export_list[3])
  259. self.assertIsNotNullPointer(tbl)
  260. ref = ffi.wasm_table_get(tbl, 0)
  261. self.assertIsNullPointer(ref)
  262. ref = ffi.wasm_table_get(tbl, 4096)
  263. self.assertIsNullPointer(ref)
  264. def test_wasm_table_get_unlinked(self):
  265. vt = ffi.wasm_valtype_new(ffi.WASM_FUNCREF)
  266. limits = ffi.wasm_limits_new(10, 15)
  267. tt = ffi.wasm_tabletype_new(vt, limits)
  268. tbl = ffi.wasm_table_new(
  269. self._wasm_store, tt, ffi.create_null_pointer(ffi.wasm_ref_t)
  270. )
  271. ffi.wasm_table_get(tbl, 0)
  272. ffi.wasm_table_delete(tbl)
  273. def test_wasm_table_get_null_table(self):
  274. ffi.wasm_table_get(ffi.create_null_pointer(ffi.wasm_table_t), 0)
  275. def test_wasm_table_get_out_of_bounds(self):
  276. export_list = ffi.wasm_vec_to_list(self.exports)
  277. tbl = ffi.wasm_extern_as_table(export_list[3])
  278. ffi.wasm_table_get(tbl, 1_000_000_000)
  279. def test_wasm_ref(self):
  280. export_list = ffi.wasm_vec_to_list(self.exports)
  281. func = ffi.wasm_extern_as_func(export_list[0])
  282. self.assertIsNotNullPointer(func)
  283. ref = ffi.wasm_func_as_ref(func)
  284. self.assertIsNotNullPointer(ref)
  285. func_from_ref = ffi.wasm_ref_as_func(ref)
  286. self.assertEqual(
  287. ffi.dereference(ffi.wasm_func_type(func)),
  288. ffi.dereference(ffi.wasm_func_type(func_from_ref)),
  289. )
  290. def test_wasm_table_set(self):
  291. export_list = ffi.wasm_vec_to_list(self.exports)
  292. tbl = ffi.wasm_extern_as_table(export_list[3])
  293. self.assertIsNotNullPointer(tbl)
  294. func = ffi.wasm_extern_as_func(export_list[0])
  295. ref = ffi.wasm_func_as_ref(func)
  296. ffi.wasm_table_set(tbl, 0, ref)
  297. ref_ret = ffi.wasm_table_get(tbl, 0)
  298. self.assertIsNotNullPointer(ref_ret)
  299. func_ret = ffi.wasm_ref_as_func(ref_ret)
  300. self.assertEqual(
  301. ffi.dereference(ffi.wasm_func_type(func)),
  302. ffi.dereference(ffi.wasm_func_type(func_ret)),
  303. )
  304. def test_wasm_table_set_unlinked(self):
  305. vt = ffi.wasm_valtype_new(ffi.WASM_FUNCREF)
  306. limits = ffi.wasm_limits_new(10, 15)
  307. tt = ffi.wasm_tabletype_new(vt, limits)
  308. tbl = ffi.wasm_table_new(
  309. self._wasm_store, tt, ffi.create_null_pointer(ffi.wasm_ref_t)
  310. )
  311. export_list = ffi.wasm_vec_to_list(self.exports)
  312. func = ffi.wasm_extern_as_func(export_list[0])
  313. ref = ffi.wasm_func_as_ref(func)
  314. ffi.wasm_table_set(tbl, 0, ref)
  315. ffi.wasm_table_delete(tbl)
  316. def test_wasm_table_set_null_table(self):
  317. export_list = ffi.wasm_vec_to_list(self.exports)
  318. func = ffi.wasm_extern_as_func(export_list[0])
  319. ref = ffi.wasm_func_as_ref(func)
  320. ffi.wasm_table_set(ffi.create_null_pointer(ffi.wasm_table_t), 0, ref)
  321. def test_wasm_table_set_null_ref(self):
  322. export_list = ffi.wasm_vec_to_list(self.exports)
  323. tbl = ffi.wasm_extern_as_table(export_list[3])
  324. ffi.wasm_table_set(tbl, 0, ffi.create_null_pointer(ffi.wasm_ref_t))
  325. def test_wasm_table_set_out_of_bounds(self):
  326. export_list = ffi.wasm_vec_to_list(self.exports)
  327. tbl = ffi.wasm_extern_as_table(export_list[3])
  328. func = ffi.wasm_extern_as_func(export_list[0])
  329. ref = ffi.wasm_func_as_ref(func)
  330. ffi.wasm_table_set(tbl, 1_000_000_000, ref)
  331. def test_wasm_memory_size(self):
  332. export_list = ffi.wasm_vec_to_list(self.exports)
  333. mem = ffi.wasm_extern_as_memory(export_list[2])
  334. self.assertIsNotNullPointer(mem)
  335. pg_sz = ffi.wasm_memory_size(mem)
  336. self.assertEqual(pg_sz, 1)
  337. def test_wasm_memory_size_unlinked(self):
  338. limits = ffi.wasm_limits_new(10, 12)
  339. mt = ffi.wasm_memorytype_new(limits)
  340. mem = ffi.wasm_memory_new(self._wasm_store, mt)
  341. ffi.wasm_memory_size(mem)
  342. ffi.wasm_memory_delete(mem)
  343. def test_wasm_memory_data(self):
  344. export_list = ffi.wasm_vec_to_list(self.exports)
  345. mem = ffi.wasm_extern_as_memory(export_list[2])
  346. self.assertIsNotNullPointer(mem)
  347. data_base = ffi.wasm_memory_data(mem)
  348. self.assertIsNotNone(data_base)
  349. def test_wasm_memory_data_unlinked(self):
  350. limits = ffi.wasm_limits_new(10, 12)
  351. mt = ffi.wasm_memorytype_new(limits)
  352. mem = ffi.wasm_memory_new(self._wasm_store, mt)
  353. ffi.wasm_memory_data(mem)
  354. ffi.wasm_memory_delete(mem)
  355. def test_wasm_memory_data_size(self):
  356. export_list = ffi.wasm_vec_to_list(self.exports)
  357. mem = ffi.wasm_extern_as_memory(export_list[2])
  358. self.assertIsNotNullPointer(mem)
  359. mem_sz = ffi.wasm_memory_data_size(mem)
  360. self.assertGreater(mem_sz, 0)
  361. def test_wasm_memory_data_size_unlinked(self):
  362. limits = ffi.wasm_limits_new(10, 12)
  363. mt = ffi.wasm_memorytype_new(limits)
  364. mem = ffi.wasm_memory_new(self._wasm_store, mt)
  365. ffi.wasm_memory_data_size(mem)
  366. ffi.wasm_memory_delete(mem)
  367. def test_wasm_trap(self):
  368. export_list = ffi.wasm_vec_to_list(self.exports)
  369. func = ffi.wasm_extern_as_func(export_list[0])
  370. # make a call
  371. params = ffi.wasm_val_vec_t()
  372. ffi.wasm_val_vec_new_empty(params)
  373. results = ffi.wasm_val_vec_t()
  374. ffi.wasm_val_vec_new_empty(results)
  375. trap = ffi.wasm_func_call(func, params, results)
  376. self.assertIsNotNullPointer(trap)
  377. message = ffi.wasm_message_t()
  378. ffi.wasm_trap_message(trap, message)
  379. self.assertIsNotNullPointer(c.pointer(message))
  380. # not a function internal exception
  381. frame = ffi.wasm_trap_origin(trap)
  382. self.assertIsNullPointer(frame)
  383. @unittest.skipUnless(
  384. TEST_WITH_WAMR_BUILD_DUMP_CALL_STACK,
  385. "need to enable WAMR_BUILD_DUMP_CALL_STACK",
  386. )
  387. # assertions only works if enabling WAMR_BUILD_DUMP_CALL_STACK
  388. def test_wasm_frame(self):
  389. export_list = ffi.wasm_vec_to_list(self.exports)
  390. func = ffi.wasm_extern_as_func(export_list[4])
  391. # make a call
  392. params = ffi.wasm_val_vec_t()
  393. ffi.wasm_val_vec_new_empty(params)
  394. results = ffi.wasm_val_vec_t()
  395. ffi.wasm_val_vec_new_empty(results)
  396. print("Making a call...")
  397. trap = ffi.wasm_func_call(func, params, results)
  398. message = ffi.wasm_message_t()
  399. ffi.wasm_trap_message(trap, message)
  400. self.assertIsNotNullPointer(c.pointer(message))
  401. print(message)
  402. frame = ffi.wasm_trap_origin(trap)
  403. self.assertIsNotNullPointer(frame)
  404. print(ffi.dereference(frame))
  405. traces = ffi.wasm_frame_vec_t()
  406. ffi.wasm_trap_trace(trap, traces)
  407. self.assertIsNotNullPointer(c.pointer(frame))
  408. instance = ffi.wasm_frame_instance(frame)
  409. self.assertIsNotNullPointer(instance)
  410. module_offset = ffi.wasm_frame_module_offset(frame)
  411. func_index = ffi.wasm_frame_func_index(frame)
  412. self.assertEqual(func_index, 2)
  413. func_offset = ffi.wasm_frame_func_offset(frame)
  414. self.assertGreater(func_offset, 0)
  415. @classmethod
  416. def tearDownClass(cls):
  417. print("Shutting down...")
  418. ffi.wasm_store_delete(cls._wasm_store)
  419. ffi.wasm_engine_delete(cls._wasm_engine)
  420. if __name__ == "__main__":
  421. unittest.main()