ems_gc_internal.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #ifndef _EMS_GC_INTERNAL_H
  6. #define _EMS_GC_INTERNAL_H
  7. #ifdef __cplusplus
  8. extern "C" {
  9. #endif
  10. #include "bh_platform.h"
  11. #include "ems_gc.h"
  12. /* HMU (heap memory unit) basic block type */
  13. typedef enum hmu_type_enum {
  14. HMU_TYPE_MIN = 0,
  15. HMU_TYPE_MAX = 3,
  16. HMU_WO = 3, /* WASM Object */
  17. HMU_VO = 2, /* VM Object */
  18. HMU_FC = 1,
  19. HMU_FM = 0
  20. } hmu_type_t;
  21. typedef struct hmu_struct {
  22. gc_uint32 header;
  23. } hmu_t;
  24. #if BH_ENABLE_GC_VERIFY != 0
  25. #if UINTPTR_MAX > UINT32_MAX
  26. /* 2 prefix paddings for 64-bit pointer */
  27. #define GC_OBJECT_PREFIX_PADDING_CNT 2
  28. #else
  29. /* 3 prefix paddings for 32-bit pointer */
  30. #define GC_OBJECT_PREFIX_PADDING_CNT 3
  31. #endif
  32. #define GC_OBJECT_SUFFIX_PADDING_CNT 4
  33. #define GC_OBJECT_PADDING_VALUE (0x12345678)
  34. typedef struct gc_object_prefix {
  35. const char *file_name;
  36. gc_int32 line_no;
  37. gc_int32 size;
  38. gc_uint32 padding[GC_OBJECT_PREFIX_PADDING_CNT];
  39. } gc_object_prefix_t;
  40. typedef struct gc_object_suffix {
  41. gc_uint32 padding[GC_OBJECT_SUFFIX_PADDING_CNT];
  42. } gc_object_suffix_t;
  43. #define OBJ_PREFIX_SIZE (sizeof(gc_object_prefix_t))
  44. #define OBJ_SUFFIX_SIZE (sizeof(gc_object_suffix_t))
  45. void
  46. hmu_init_prefix_and_suffix(hmu_t *hmu, gc_size_t tot_size,
  47. const char *file_name, int line_no);
  48. void
  49. hmu_verify(void *vheap, hmu_t *hmu);
  50. #define SKIP_OBJ_PREFIX(p) ((void *)((gc_uint8 *)(p) + OBJ_PREFIX_SIZE))
  51. #define SKIP_OBJ_SUFFIX(p) ((void *)((gc_uint8 *)(p) + OBJ_SUFFIX_SIZE))
  52. #define OBJ_EXTRA_SIZE (HMU_SIZE + OBJ_PREFIX_SIZE + OBJ_SUFFIX_SIZE)
  53. #else /* else of BH_ENABLE_GC_VERIFY */
  54. #define OBJ_PREFIX_SIZE 0
  55. #define OBJ_SUFFIX_SIZE 0
  56. #define SKIP_OBJ_PREFIX(p) ((void *)((gc_uint8 *)(p) + OBJ_PREFIX_SIZE))
  57. #define SKIP_OBJ_SUFFIX(p) ((void *)((gc_uint8 *)(p) + OBJ_SUFFIX_SIZE))
  58. #define OBJ_EXTRA_SIZE (HMU_SIZE + OBJ_PREFIX_SIZE + OBJ_SUFFIX_SIZE)
  59. #endif /* end of BH_ENABLE_GC_VERIFY */
  60. #define hmu_obj_size(s) ((s)-OBJ_EXTRA_SIZE)
  61. #define GC_ALIGN_8(s) (((uint32)(s) + 7) & (uint32)~7)
  62. #define GC_SMALLEST_SIZE \
  63. GC_ALIGN_8(HMU_SIZE + OBJ_PREFIX_SIZE + OBJ_SUFFIX_SIZE + 8)
  64. #define GC_GET_REAL_SIZE(x) \
  65. GC_ALIGN_8(HMU_SIZE + OBJ_PREFIX_SIZE + OBJ_SUFFIX_SIZE \
  66. + (((x) > 8) ? (x) : 8))
  67. /**
  68. * hmu bit operation
  69. */
  70. #define SETBIT(v, offset) (v) |= ((uint32)1 << (offset))
  71. #define GETBIT(v, offset) ((v) & ((uint32)1 << (offset)) ? 1 : 0)
  72. #define CLRBIT(v, offset) (v) &= (~((uint32)1 << (offset)))
  73. /* clang-format off */
  74. #define SETBITS(v, offset, size, value) \
  75. do { \
  76. (v) &= ~((((uint32)1 << size) - 1) << offset); \
  77. (v) |= ((uint32)value << offset); \
  78. } while (0)
  79. #define CLRBITS(v, offset, size) \
  80. (v) &= ~((((uint32)1 << size) - 1) << offset)
  81. #define GETBITS(v, offset, size) \
  82. (((v) & (((((uint32)1 << size) - 1) << offset))) >> offset)
  83. /* clang-format on */
  84. /**
  85. * gc object layout definition
  86. */
  87. #define HMU_SIZE (sizeof(hmu_t))
  88. #define hmu_to_obj(hmu) (gc_object_t)(SKIP_OBJ_PREFIX((hmu_t *)(hmu) + 1))
  89. #define obj_to_hmu(obj) ((hmu_t *)((gc_uint8 *)(obj)-OBJ_PREFIX_SIZE) - 1)
  90. #define HMU_UT_SIZE 2
  91. #define HMU_UT_OFFSET 30
  92. /* clang-format off */
  93. #define hmu_get_ut(hmu) \
  94. GETBITS((hmu)->header, HMU_UT_OFFSET, HMU_UT_SIZE)
  95. #define hmu_set_ut(hmu, type) \
  96. SETBITS((hmu)->header, HMU_UT_OFFSET, HMU_UT_SIZE, type)
  97. #define hmu_is_ut_valid(tp) \
  98. (tp >= HMU_TYPE_MIN && tp <= HMU_TYPE_MAX)
  99. /* clang-format on */
  100. /* P in use bit means the previous chunk is in use */
  101. #define HMU_P_OFFSET 29
  102. #define hmu_mark_pinuse(hmu) SETBIT((hmu)->header, HMU_P_OFFSET)
  103. #define hmu_unmark_pinuse(hmu) CLRBIT((hmu)->header, HMU_P_OFFSET)
  104. #define hmu_get_pinuse(hmu) GETBIT((hmu)->header, HMU_P_OFFSET)
  105. #define HMU_WO_VT_SIZE 27
  106. #define HMU_WO_VT_OFFSET 0
  107. #define HMU_WO_MB_OFFSET 28
  108. #define hmu_mark_wo(hmu) SETBIT((hmu)->header, HMU_WO_MB_OFFSET)
  109. #define hmu_unmark_wo(hmu) CLRBIT((hmu)->header, HMU_WO_MB_OFFSET)
  110. #define hmu_is_wo_marked(hmu) GETBIT((hmu)->header, HMU_WO_MB_OFFSET)
  111. /**
  112. * The hmu size is divisible by 8, its lowest 3 bits are 0, so we only
  113. * store its higher bits of bit [29..3], and bit [2..0] are not stored.
  114. * After that, the maximal heap size can be enlarged from (1<<27) = 128MB
  115. * to (1<<27) * 8 = 1GB.
  116. */
  117. #define HMU_SIZE_SIZE 27
  118. #define HMU_SIZE_OFFSET 0
  119. #define HMU_VO_FB_OFFSET 28
  120. #define hmu_is_vo_freed(hmu) GETBIT((hmu)->header, HMU_VO_FB_OFFSET)
  121. #define hmu_unfree_vo(hmu) CLRBIT((hmu)->header, HMU_VO_FB_OFFSET)
  122. #define hmu_get_size(hmu) \
  123. (GETBITS((hmu)->header, HMU_SIZE_OFFSET, HMU_SIZE_SIZE) << 3)
  124. #define hmu_set_size(hmu, size) \
  125. SETBITS((hmu)->header, HMU_SIZE_OFFSET, HMU_SIZE_SIZE, ((size) >> 3))
  126. /**
  127. * HMU free chunk management
  128. */
  129. #ifndef HMU_NORMAL_NODE_CNT
  130. #define HMU_NORMAL_NODE_CNT 32
  131. #endif
  132. #define HMU_FC_NORMAL_MAX_SIZE ((HMU_NORMAL_NODE_CNT - 1) << 3)
  133. #define HMU_IS_FC_NORMAL(size) ((size) < HMU_FC_NORMAL_MAX_SIZE)
  134. #if HMU_FC_NORMAL_MAX_SIZE >= GC_MAX_HEAP_SIZE
  135. #error "Too small GC_MAX_HEAP_SIZE"
  136. #endif
  137. typedef struct hmu_normal_node {
  138. hmu_t hmu_header;
  139. gc_int32 next_offset;
  140. } hmu_normal_node_t;
  141. typedef struct hmu_normal_list {
  142. hmu_normal_node_t *next;
  143. } hmu_normal_list_t;
  144. static inline hmu_normal_node_t *
  145. get_hmu_normal_node_next(hmu_normal_node_t *node)
  146. {
  147. return node->next_offset
  148. ? (hmu_normal_node_t *)((uint8 *)node + node->next_offset)
  149. : NULL;
  150. }
  151. static inline void
  152. set_hmu_normal_node_next(hmu_normal_node_t *node, hmu_normal_node_t *next)
  153. {
  154. if (next) {
  155. bh_assert((uint8 *)next - (uint8 *)node < INT32_MAX);
  156. node->next_offset = (gc_int32)(intptr_t)((uint8 *)next - (uint8 *)node);
  157. }
  158. else {
  159. node->next_offset = 0;
  160. }
  161. }
  162. /**
  163. * Define hmu_tree_node as a packed struct, since it is at the 4-byte
  164. * aligned address and the size of hmu_head is 4, so in 64-bit target,
  165. * the left/right/parent fields will be at 8-byte aligned address,
  166. * we can access them directly.
  167. */
  168. #if UINTPTR_MAX == UINT64_MAX
  169. #if defined(_MSC_VER)
  170. __pragma(pack(push, 1));
  171. #define __attr_packed
  172. #define __attr_aligned(a)
  173. #elif defined(__GNUC__) || defined(__clang__)
  174. #define __attr_packed __attribute__((packed))
  175. #define __attr_aligned(a) __attribute__((aligned(a)))
  176. #else
  177. #error "packed attribute isn't used to define struct hmu_tree_node"
  178. #endif
  179. #else /* else of UINTPTR_MAX == UINT64_MAX */
  180. #define __attr_packed
  181. #define __attr_aligned(a)
  182. #endif
  183. typedef struct hmu_tree_node {
  184. hmu_t hmu_header;
  185. struct hmu_tree_node *left;
  186. struct hmu_tree_node *right;
  187. struct hmu_tree_node *parent;
  188. gc_size_t size;
  189. } __attr_packed __attr_aligned(4) hmu_tree_node_t;
  190. #if UINTPTR_MAX == UINT64_MAX
  191. #if defined(_MSC_VER)
  192. __pragma(pack(pop));
  193. #endif
  194. #endif
  195. bh_static_assert(sizeof(hmu_tree_node_t) == 8 + 3 * sizeof(void *));
  196. bh_static_assert(offsetof(hmu_tree_node_t, left) == 4);
  197. #define ASSERT_TREE_NODE_ALIGNED_ACCESS(tree_node) \
  198. do { \
  199. bh_assert((((uintptr_t)&tree_node->left) & (sizeof(uintptr_t) - 1)) \
  200. == 0); \
  201. } while (0)
  202. typedef struct gc_heap_struct {
  203. /* for double checking*/
  204. gc_handle_t heap_id;
  205. gc_uint8 *base_addr;
  206. gc_size_t current_size;
  207. korp_mutex lock;
  208. hmu_normal_list_t kfc_normal_list[HMU_NORMAL_NODE_CNT];
  209. #if UINTPTR_MAX == UINT64_MAX
  210. /* make kfc_tree_root_buf 4-byte aligned and not 8-byte aligned,
  211. so kfc_tree_root's left/right/parent fields are 8-byte aligned
  212. and we can access them directly */
  213. uint32 __padding;
  214. #endif
  215. uint8 kfc_tree_root_buf[sizeof(hmu_tree_node_t)];
  216. /* point to kfc_tree_root_buf, the order in kfc_tree is:
  217. size[left] <= size[cur] < size[right] */
  218. hmu_tree_node_t *kfc_tree_root;
  219. #if WASM_ENABLE_GC != 0
  220. /* for rootset enumeration of private heap*/
  221. void *root_set;
  222. #if WASM_ENABLE_THREAD_MGR == 0
  223. /* exec_env of current wasm module instance */
  224. void *exec_env;
  225. #else
  226. /* thread cluster of current module instances */
  227. void *cluster;
  228. #endif
  229. /* whether the fast mode of marking process that requires
  230. additional memory fails. When the fast mode fails, the
  231. marking process can still be done in the slow mode, which
  232. doesn't need additional memory (by walking through all
  233. blocks and marking sucessors of marked nodes until no new
  234. node is marked). TODO: slow mode is not implemented. */
  235. unsigned is_fast_marking_failed : 1;
  236. /* whether the heap is doing reclaim */
  237. unsigned is_doing_reclaim : 1;
  238. /* Whether the heap can do reclaim */
  239. unsigned is_reclaim_enabled : 1;
  240. #endif
  241. #if BH_ENABLE_GC_CORRUPTION_CHECK != 0
  242. /* whether heap is corrupted, e.g. the hmu nodes are modified
  243. by user */
  244. bool is_heap_corrupted;
  245. #endif
  246. gc_size_t init_size;
  247. gc_size_t highmark_size;
  248. gc_size_t total_free_size;
  249. #if WASM_ENABLE_GC != 0
  250. gc_size_t gc_threshold;
  251. gc_size_t gc_threshold_factor;
  252. gc_size_t total_gc_count;
  253. gc_size_t total_gc_time;
  254. gc_size_t max_gc_time;
  255. /* Usually there won't be too many extra info node, so we try to use a fixed
  256. * array to store them, if the fixed array don't have enough space to store
  257. * the nodes, a new space will be allocated from heap */
  258. extra_info_node_t *extra_info_normal_nodes[EXTRA_INFO_NORMAL_NODE_CNT];
  259. /* Used to store extra information such as finalizer for specified nodes, we
  260. * introduce a seperate space to store these information so only nodes who
  261. * really require extra information will occupy additional memory spaces. */
  262. extra_info_node_t **extra_info_nodes;
  263. gc_size_t extra_info_node_cnt;
  264. gc_size_t extra_info_node_capacity;
  265. #endif
  266. #if GC_STAT_DATA != 0
  267. gc_uint64 total_size_allocated;
  268. gc_uint64 total_size_freed;
  269. #endif
  270. } gc_heap_t;
  271. #if WASM_ENABLE_GC != 0
  272. #define GC_DEFAULT_THRESHOLD_FACTOR 300
  273. static inline void
  274. gc_update_threshold(gc_heap_t *heap)
  275. {
  276. heap->gc_threshold =
  277. heap->total_free_size * heap->gc_threshold_factor / 1000;
  278. }
  279. #define gct_vm_mutex_init os_mutex_init
  280. #define gct_vm_mutex_destroy os_mutex_destroy
  281. #define gct_vm_mutex_lock os_mutex_lock
  282. #define gct_vm_mutex_unlock os_mutex_unlock
  283. #define gct_vm_gc_prepare wasm_runtime_gc_prepare
  284. #define gct_vm_gc_finished wasm_runtime_gc_finalize
  285. #define gct_vm_begin_rootset_enumeration wasm_runtime_traverse_gc_rootset
  286. #define gct_vm_get_wasm_object_ref_list wasm_runtime_get_wasm_object_ref_list
  287. #define gct_vm_get_extra_info_flag wasm_runtime_get_wasm_object_extra_info_flag
  288. #define gct_vm_set_extra_info_flag wasm_runtime_set_wasm_object_extra_info_flag
  289. #endif /* end of WAMS_ENABLE_GC != 0 */
  290. /**
  291. * MISC internal used APIs
  292. */
  293. bool
  294. gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size);
  295. int
  296. gci_is_heap_valid(gc_heap_t *heap);
  297. /**
  298. * Verify heap integrity
  299. */
  300. void
  301. gci_verify_heap(gc_heap_t *heap);
  302. /**
  303. * Dump heap nodes
  304. */
  305. void
  306. gci_dump(gc_heap_t *heap);
  307. #ifdef __cplusplus
  308. }
  309. #endif
  310. #endif /* end of _EMS_GC_INTERNAL_H */