ffi.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  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 os
  12. from pathlib import Path
  13. import sys
  14. #
  15. # Prologue. Dependencies of binding
  16. #
  17. # how to open the library file of WAMR
  18. if sys.platform == "linux":
  19. BUILDING_DIR = "product-mini/platforms/linux/build"
  20. LIBRARY_NAME = "libiwasm.so"
  21. elif sys.platform == "win32":
  22. BUILDING_DIR = "product-mini/platforms/windows/build"
  23. LIBRARY_NAME = "iwasm.dll"
  24. elif sys.platform == "darwin":
  25. BUILDING_DIR = "product-mini/platforms/darwin/build"
  26. LIBRARY_NAME = "libiwasm.dylib"
  27. else:
  28. raise RuntimeError(f"unsupported platform `{sys.platform}`")
  29. # FIXME: should load libiwasm.so from current system library path
  30. current_file = Path(__file__)
  31. if current_file.is_symlink():
  32. current_file = Path(os.readlink(current_file))
  33. current_dir = current_file.parent.resolve()
  34. root_dir = current_dir.parent.parent.parent.parent.resolve()
  35. wamr_dir = root_dir.joinpath("wasm-micro-runtime").resolve()
  36. if not wamr_dir.exists():
  37. raise RuntimeError(f"not found the repo of wasm-micro-runtime under {root_dir}")
  38. libpath = wamr_dir.joinpath(BUILDING_DIR).joinpath(LIBRARY_NAME).resolve()
  39. if not libpath.exists():
  40. raise RuntimeError(f"not found precompiled wamr library at {libpath}")
  41. print(f"loading WAMR library from {libpath} ...")
  42. libiwasm = c.cdll.LoadLibrary(libpath)
  43. class wasm_ref_t(c.Structure):
  44. # pylint: disable=invalid-name
  45. pass
  46. class wasm_val_union(c.Union):
  47. # pylint: disable=invalid-name
  48. _fields_ = [
  49. ("i32", c.c_int32),
  50. ("i64", c.c_int64),
  51. ("f32", c.c_float),
  52. ("f64", c.c_double),
  53. ("ref", c.POINTER(wasm_ref_t)),
  54. ]
  55. class wasm_val_t(c.Structure):
  56. # pylint: disable=invalid-name
  57. _fields_ = [
  58. ("kind", c.c_uint8),
  59. ("of", wasm_val_union),
  60. ]
  61. def dereference(p):
  62. # pylint: disable=protected-access
  63. if not isinstance(p, c._Pointer):
  64. raise RuntimeError("not a pointer")
  65. return p.contents
  66. # HELPERs
  67. def create_null_pointer(struct_type):
  68. return c.POINTER(struct_type)()
  69. def is_null_pointer(c_pointer):
  70. # pylint: disable=protected-access
  71. if isinstance(c_pointer, c._Pointer):
  72. return False if c_pointer else True
  73. else:
  74. raise RuntimeError("not a pointer")
  75. def wasm_vec_to_list(vec):
  76. """
  77. Converts a vector or a POINTER(vector) to a list
  78. vector of type pointers -> list of type pointers
  79. """
  80. known_vec_type = [
  81. wasm_byte_vec_t,
  82. wasm_valtype_vec_t,
  83. wasm_functype_vec_t,
  84. wasm_globaltype_vec_t,
  85. wasm_tabletype_vec_t,
  86. wasm_memorytype_vec_t,
  87. wasm_externtype_vec_t,
  88. wasm_importtype_vec_t,
  89. wasm_exporttype_vec_t,
  90. wasm_val_vec_t,
  91. wasm_frame_vec_t,
  92. wasm_extern_vec_t,
  93. ]
  94. known_vec_pointer_type = [POINTER(type) for type in known_vec_type]
  95. if any([isinstance(vec, type) for type in known_vec_pointer_type]):
  96. vec = dereference(vec)
  97. return [vec.data[i] for i in range(vec.num_elems)]
  98. elif any([isinstance(vec, type) for type in known_vec_type]):
  99. return [vec.data[i] for i in range(vec.num_elems)]
  100. else:
  101. raise RuntimeError("not a known vector type")
  102. def list_to_carray(elem_type, *args):
  103. """
  104. Converts a python list into a C array
  105. """
  106. data = (elem_type * len(args))(*args)
  107. return data
  108. def load_module_file(wasm_content):
  109. binary = wasm_byte_vec_t()
  110. wasm_byte_vec_new_uninitialized(binary, len(wasm_content))
  111. # has to use malloced memory.
  112. c.memmove(binary.data, wasm_content, len(wasm_content))
  113. binary.num_elems = len(wasm_content)
  114. return binary
  115. #
  116. # Enhancment of binding
  117. #
  118. from .binding import *
  119. # Built-in functions for Structure
  120. wasm_finalizer = CFUNCTYPE(None, c_void_p)
  121. def __repr_wasm_limits_t(self):
  122. return f"{self.min:#x} {self.max:#x}"
  123. # overwrite
  124. wasm_limits_t.__repr__ = __repr_wasm_limits_t
  125. def __compare_wasm_valtype_t(self, other):
  126. if not isinstance(other, wasm_valtype_t):
  127. return False
  128. return wasm_valtype_kind(byref(self)) == wasm_valtype_kind(byref(other))
  129. def __repr_wasm_valtype_t(self):
  130. val_kind = wasm_valtype_kind(byref(self))
  131. if WASM_I32 == val_kind:
  132. return "i32"
  133. elif WASM_I64 == val_kind:
  134. return "i64"
  135. elif WASM_F32 == val_kind:
  136. return "f32"
  137. elif WASM_F64 == val_kind:
  138. return "f64"
  139. elif WASM_FUNCREF == val_kind:
  140. return "funcref"
  141. else:
  142. return "anyref"
  143. wasm_valtype_t.__eq__ = __compare_wasm_valtype_t
  144. wasm_valtype_t.__repr__ = __repr_wasm_valtype_t
  145. def __compare_wasm_byte_vec_t(self, other):
  146. if not isinstance(other, wasm_byte_vec_t):
  147. return False
  148. if self.num_elems != other.num_elems:
  149. return False
  150. self_data = bytes(self.data[: self.num_elems])
  151. other_data = bytes(other.data[: other.num_elems])
  152. return self_data.decode() == other_data.decode()
  153. def __repr_wasm_byte_vec_t(self):
  154. data = bytes(self.data[: self.num_elems])
  155. return data.decode() if self.size else ""
  156. wasm_byte_vec_t.__eq__ = __compare_wasm_byte_vec_t
  157. wasm_byte_vec_t.__repr__ = __repr_wasm_byte_vec_t
  158. def __compare_wasm_functype_t(self, other):
  159. if not isinstance(other, wasm_functype_t):
  160. return False
  161. params1 = dereference(wasm_functype_params(byref(self)))
  162. params2 = dereference(wasm_functype_params(byref(other)))
  163. results1 = dereference(wasm_functype_results(byref(self)))
  164. results2 = dereference(wasm_functype_results(byref(other)))
  165. return params1 == params2 and results1 == results2
  166. def __repr_wasm_functype_t(self):
  167. params = dereference(wasm_functype_params(byref(self)))
  168. results = dereference(wasm_functype_results(byref(self)))
  169. params = f" (params {params})" if params.size else ""
  170. results = f" (results {results})" if results.size else ""
  171. return f"(func{params}{results})"
  172. wasm_functype_t.__eq__ = __compare_wasm_functype_t
  173. wasm_functype_t.__repr__ = __repr_wasm_functype_t
  174. def __compare_wasm_globaltype_t(self, other):
  175. if not isinstance(other, wasm_globaltype_t):
  176. return False
  177. content1 = dereference(wasm_globaltype_content(byref(self)))
  178. content2 = dereference(wasm_globaltype_content(byref(other)))
  179. mutability1 = wasm_globaltype_mutability(byref(self))
  180. mutability2 = wasm_globaltype_mutability(byref(other))
  181. return content1 == content2 and mutability1 == mutability2
  182. def __repr_wasm_globaltype_t(self):
  183. mutability = f"{wasm_globaltype_mutability(byref(self))}"
  184. content = f"{dereference(wasm_globaltype_content(byref(self)))}"
  185. return f"(global{' mut ' if mutability else ' '}{content})"
  186. wasm_globaltype_t.__eq__ = __compare_wasm_globaltype_t
  187. wasm_globaltype_t.__repr__ = __repr_wasm_globaltype_t
  188. def __compare_wasm_tabletype_t(self, other):
  189. if not isinstance(other, wasm_tabletype_t):
  190. return False
  191. element1 = dereference(wasm_tabletype_element(byref(self)))
  192. element2 = dereference(wasm_tabletype_element(byref(other)))
  193. limits1 = dereference(wasm_tabletype_limits(byref(self)))
  194. limits2 = dereference(wasm_tabletype_limits(byref(other)))
  195. return element1 == element2 and limits1 == limits2
  196. def __repr_wasm_tabletype_t(self):
  197. element = dereference(wasm_tabletype_element(byref(self)))
  198. limit = dereference(wasm_tabletype_limits(byref(self)))
  199. return f"(table {limit} {element})"
  200. wasm_tabletype_t.__eq__ = __compare_wasm_tabletype_t
  201. wasm_tabletype_t.__repr__ = __repr_wasm_tabletype_t
  202. def __compare_wasm_memorytype_t(self, other):
  203. if not isinstance(other, wasm_memorytype_t):
  204. return False
  205. limits1 = dereference(wasm_memorytype_limits(byref(self)))
  206. limits2 = dereference(wasm_memorytype_limits(byref(other)))
  207. return limits1 == limits2
  208. def __repr_wasm_memorytype_t(self):
  209. limit = dereference(wasm_memorytype_limits(byref(self)))
  210. return f"(memory {limit})"
  211. wasm_memorytype_t.__eq__ = __compare_wasm_memorytype_t
  212. wasm_memorytype_t.__repr__ = __repr_wasm_memorytype_t
  213. def __compare_wasm_externtype_t(self, other):
  214. if not isinstance(other, wasm_externtype_t):
  215. return False
  216. if wasm_externtype_kind(byref(self)) != wasm_externtype_kind(byref(other)):
  217. return False
  218. extern_kind = wasm_externtype_kind(byref(self))
  219. if WASM_EXTERN_FUNC == extern_kind:
  220. return dereference(wasm_externtype_as_functype(self)) == dereference(
  221. wasm_externtype_as_functype(other)
  222. )
  223. elif WASM_EXTERN_GLOBAL == extern_kind:
  224. return dereference(wasm_externtype_as_globaltype(self)) == dereference(
  225. wasm_externtype_as_globaltype(other)
  226. )
  227. elif WASM_EXTERN_MEMORY == extern_kind:
  228. return dereference(wasm_externtype_as_memorytype(self)) == dereference(
  229. wasm_externtype_as_memorytype(other)
  230. )
  231. elif WASM_EXTERN_TABLE == extern_kind:
  232. return dereference(wasm_externtype_as_tabletype(self)) == dereference(
  233. wasm_externtype_as_tabletype(other)
  234. )
  235. else:
  236. raise RuntimeError("not a valid wasm_externtype_t")
  237. def __repr_wasm_externtype_t(self):
  238. extern_kind = wasm_externtype_kind(byref(self))
  239. if WASM_EXTERN_FUNC == extern_kind:
  240. return str(dereference(wasm_externtype_as_functype(byref(self))))
  241. elif WASM_EXTERN_GLOBAL == extern_kind:
  242. return str(dereference(wasm_externtype_as_globaltype(byref(self))))
  243. elif WASM_EXTERN_MEMORY == extern_kind:
  244. return str(dereference(wasm_externtype_as_memorytype(byref(self))))
  245. elif WASM_EXTERN_TABLE == extern_kind:
  246. return str(dereference(wasm_externtype_as_tabletype(byref(self))))
  247. else:
  248. raise RuntimeError("not a valid wasm_externtype_t")
  249. wasm_externtype_t.__eq__ = __compare_wasm_externtype_t
  250. wasm_externtype_t.__repr__ = __repr_wasm_externtype_t
  251. def __compare_wasm_importtype_t(self, other):
  252. if not isinstance(other, wasm_importtype_t):
  253. return False
  254. if dereference(wasm_importtype_module(self)) != dereference(
  255. wasm_importtype_module(other)
  256. ):
  257. return False
  258. if dereference(wasm_importtype_name(self)) != dereference(
  259. wasm_importtype_name(other)
  260. ):
  261. return False
  262. self_type = dereference(wasm_importtype_type(byref(self)))
  263. other_type = dereference(wasm_importtype_type(byref(other)))
  264. return self_type == other_type
  265. def __repr_wasm_importtype_t(self):
  266. module = wasm_importtype_module(byref(self))
  267. name = wasm_importtype_name(byref(self))
  268. extern_type = wasm_importtype_type(byref(self))
  269. return f'(import "{dereference(module)}" "{dereference(name)}" {dereference(extern_type)})'
  270. wasm_importtype_t.__eq__ = __compare_wasm_importtype_t
  271. wasm_importtype_t.__repr__ = __repr_wasm_importtype_t
  272. def __compare_wasm_exporttype_t(self, other):
  273. if not isinstance(other, wasm_exporttype_t):
  274. return False
  275. self_name = dereference(wasm_exporttype_name(byref(self)))
  276. other_name = dereference(wasm_exporttype_name(byref(other)))
  277. if self_name != other_name:
  278. return False
  279. self_type = dereference(wasm_exporttype_type(byref(self)))
  280. other_type = dereference(wasm_exporttype_type(byref(other)))
  281. return self_type == other_type
  282. def __repr_wasm_exporttype_t(self):
  283. name = wasm_exporttype_name(byref(self))
  284. extern_type = wasm_exporttype_type(byref(self))
  285. return f'(export "{dereference(name)}" {dereference(extern_type)})'
  286. wasm_exporttype_t.__eq__ = __compare_wasm_exporttype_t
  287. wasm_exporttype_t.__repr__ = __repr_wasm_exporttype_t
  288. def __compare_wasm_val_t(self, other):
  289. if not isinstance(other, wasm_val_t):
  290. return False
  291. if self.kind != other.kind:
  292. return False
  293. if WASM_I32 == self.kind:
  294. return self.of.i32 == other.of.i32
  295. elif WASM_I64 == self.kind:
  296. return self.of.i64 == other.of.i64
  297. elif WASM_F32 == self.kind:
  298. return self.of.f32 == other.of.f32
  299. elif WASM_F64 == self.kind:
  300. return self.of.f64 == other.of.f63
  301. elif WASM_ANYREF == self.kind:
  302. raise RuntimeError("FIXME")
  303. else:
  304. raise RuntimeError("not a valid val kind")
  305. def __repr_wasm_val_t(self):
  306. if WASM_I32 == self.kind:
  307. return f"i32 {self.of.i32}"
  308. elif WASM_I64 == self.kind:
  309. return f"i64 {self.of.i64}"
  310. elif WASM_F32 == self.kind:
  311. return f"f32 {self.of.f32}"
  312. elif WASM_F64 == self.kind:
  313. return f"f64 {self.of.f64}"
  314. elif WASM_ANYREF == self.kind:
  315. return f"anyref {self.of.ref}"
  316. else:
  317. raise RuntimeError("not a valid val kind")
  318. wasm_val_t.__repr__ = __repr_wasm_val_t
  319. wasm_val_t.__eq__ = __compare_wasm_val_t
  320. def __repr_wasm_trap_t(self):
  321. message = wasm_message_t()
  322. wasm_trap_message(self, message)
  323. return f'(trap "{str(message)}")'
  324. wasm_trap_t.__repr__ = __repr_wasm_trap_t
  325. def __repr_wasm_frame_t(self):
  326. instance = wasm_frame_instance(self)
  327. module_offset = wasm_frame_module_offset(self)
  328. func_index = wasm_frame_func_index(self)
  329. func_offset = wasm_frame_func_offset(self)
  330. return f"> module:{module_offset:#x} => func#{func_index:#x}.{func_offset:#x}"
  331. wasm_frame_t.__repr__ = __repr_wasm_frame_t
  332. def __repr_wasm_module_t(self):
  333. imports = wasm_importtype_vec_t()
  334. wasm_module_imports(self, imports)
  335. exports = wasm_exporttype_vec_t()
  336. wasm_module_exports(self, exports)
  337. ret = "(module"
  338. ret += str(imports).replace("(import", "\n (import")
  339. ret += str(exports).replace("(export", "\n (export")
  340. ret += "\n)"
  341. return ret
  342. wasm_module_t.__repr__ = __repr_wasm_module_t
  343. def __repr_wasm_instance_t(self):
  344. exports = wasm_extern_vec_t()
  345. wasm_instance_exports(self, exports)
  346. ret = "(instance"
  347. ret += str(exports).replace("(export", "\n (export")
  348. ret += "\n)"
  349. return ret
  350. wasm_instance_t.__repr__ = __repr_wasm_instance_t
  351. def __repr_wasm_func_t(self):
  352. ft = wasm_func_type(self)
  353. return f"{str(dereference(ft))[:-1]} ... )"
  354. wasm_func_t.__repr__ = __repr_wasm_func_t
  355. def __repr_wasm_global_t(self):
  356. gt = wasm_global_type(self)
  357. return f"{str(dereference(gt))[:-1]} ... )"
  358. wasm_global_t.__repr__ = __repr_wasm_global_t
  359. def __repr_wasm_table_t(self):
  360. tt = wasm_table_type(self)
  361. return f"{str(dereference(tt))[:-1]} ... )"
  362. wasm_table_t.__repr__ = __repr_wasm_table_t
  363. def __repr_wasm_memory_t(self):
  364. mt = wasm_memory_type(self)
  365. return f"{str(dereference(mt))[:-1]} ... )"
  366. wasm_memory_t.__repr__ = __repr_wasm_memory_t
  367. def __repr_wasm_extern_t(self):
  368. ext_type = wasm_extern_type(self)
  369. ext_kind = wasm_extern_kind(self)
  370. ret = "(export "
  371. if WASM_EXTERN_FUNC == ext_kind:
  372. ft = wasm_externtype_as_functype(ext_type)
  373. ret += str(dereference(ft))
  374. elif WASM_EXTERN_GLOBAL == ext_kind:
  375. gt = wasm_externtype_as_globaltype(ext_type)
  376. ret += str(dereference(gt))
  377. elif WASM_EXTERN_MEMORY == ext_kind:
  378. mt = wasm_externtype_as_memorytype(ext_type)
  379. ret += str(dereference(mt))
  380. elif WASM_EXTERN_TABLE == ext_kind:
  381. tt = wasm_externtype_as_tabletype(ext_type)
  382. ret += str(dereference(tt))
  383. else:
  384. raise RuntimeError("not a valid extern kind")
  385. ret += ")"
  386. return ret
  387. wasm_extern_t.__repr__ = __repr_wasm_extern_t
  388. # Function Types construction short-hands
  389. def wasm_name_new_from_string(s):
  390. name = wasm_name_t()
  391. data = ((c.c_ubyte) * len(s)).from_buffer_copy(s.encode())
  392. wasm_byte_vec_new(byref(name), len(s), data)
  393. return name
  394. def __wasm_functype_new(param_list, result_list):
  395. def __list_to_wasm_valtype_vec(l):
  396. vec = wasm_valtype_vec_t()
  397. if not l:
  398. wasm_valtype_vec_new_empty(byref(vec))
  399. else:
  400. data_type = POINTER(wasm_valtype_t) * len(l)
  401. data = data_type()
  402. for i in range(len(l)):
  403. data[i] = l[i]
  404. wasm_valtype_vec_new(byref(vec), len(l), data)
  405. return vec
  406. params = __list_to_wasm_valtype_vec(param_list)
  407. results = __list_to_wasm_valtype_vec(result_list)
  408. return wasm_functype_new(byref(params), byref(results))
  409. def wasm_functype_new_0_0():
  410. return __wasm_functype_new([], [])
  411. def wasm_functype_new_1_0(p1):
  412. return __wasm_functype_new([p1], [])
  413. def wasm_functype_new_2_0(p1, p2):
  414. return __wasm_functype_new([p1, p2], [])
  415. def wasm_functype_new_3_0(p1, p2, p3):
  416. return __wasm_functype_new([p1, p2, p3], [])
  417. def wasm_functype_new_0_1(r1):
  418. return __wasm_functype_new([], [r1])
  419. def wasm_functype_new_1_1(p1, r1):
  420. return __wasm_functype_new([p1], [r1])
  421. def wasm_functype_new_2_1(p1, p2, r1):
  422. return __wasm_functype_new([p1, p2], [r1])
  423. def wasm_functype_new_3_1(p1, p2, p3, r1):
  424. return __wasm_functype_new([p1, p2, p3], [r1])
  425. def wasm_limits_new(min, max):
  426. limit = wasm_limits_t()
  427. limit.min = min
  428. limit.max = max
  429. return c.pointer(limit)
  430. def wasm_i32_val(i):
  431. v = wasm_val_t()
  432. v.kind = WASM_I32
  433. v.of.i32 = i
  434. return v
  435. def wasm_i64_val(i):
  436. v = wasm_val_t()
  437. v.kind = WASM_I64
  438. v.of.i64 = i
  439. return v
  440. def wasm_f32_val(z):
  441. v = wasm_val_t()
  442. v.kind = WASM_F32
  443. v.of.f32 = z
  444. return v
  445. def wasm_f64_val(z):
  446. v = wasm_val_t()
  447. v.kind = WASM_F64
  448. v.of.f64 = z
  449. return v
  450. def wasm_func_cb_decl(func):
  451. return wasm_func_callback_t(func)
  452. def wasm_func_with_env_cb_decl(func):
  453. return wasm_func_callback_with_env_t(func)