ems_gc_internal.h 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  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_JO = 3,
  17. HMU_VO = 2,
  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_JO_VT_SIZE 27
  106. #define HMU_JO_VT_OFFSET 0
  107. #define HMU_JO_MB_OFFSET 28
  108. #define hmu_mark_jo(hmu) SETBIT((hmu)->header, HMU_JO_MB_OFFSET)
  109. #define hmu_unmark_jo(hmu) CLRBIT((hmu)->header, HMU_JO_MB_OFFSET)
  110. #define hmu_is_jo_marked(hmu) GETBIT((hmu)->header, HMU_JO_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 BH_ENABLE_GC_CORRUPTION_CHECK != 0
  220. /* whether heap is corrupted, e.g. the hmu nodes are modified
  221. by user */
  222. bool is_heap_corrupted;
  223. #endif
  224. gc_size_t init_size;
  225. gc_size_t highmark_size;
  226. gc_size_t total_free_size;
  227. } gc_heap_t;
  228. /**
  229. * MISC internal used APIs
  230. */
  231. bool
  232. gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size);
  233. int
  234. gci_is_heap_valid(gc_heap_t *heap);
  235. /**
  236. * Verify heap integrity
  237. */
  238. void
  239. gci_verify_heap(gc_heap_t *heap);
  240. /**
  241. * Dump heap nodes
  242. */
  243. void
  244. gci_dump(gc_heap_t *heap);
  245. #ifdef __cplusplus
  246. }
  247. #endif
  248. #endif /* end of _EMS_GC_INTERNAL_H */