Implement GC (Garbage Collection) feature for interpreter, AOT and LLVM-JIT (#3125)

Implement the GC (Garbage Collection) feature for interpreter mode,
AOT mode and LLVM-JIT mode, and support most features of the latest
spec proposal, and also enable the stringref feature.

Use `cmake -DWAMR_BUILD_GC=1/0` to enable/disable the feature,
and `wamrc --enable-gc` to generate the AOT file with GC supported.

And update the AOT file version from 2 to 3 since there are many AOT
ABI breaks, including the changes of AOT file format, the changes of
AOT module/memory instance layouts, the AOT runtime APIs for the
AOT code to invoke and so on.
This commit is contained in:
Wenyong Huang
2024-02-06 20:47:11 +08:00
committed by GitHub
parent 5931aaacbe
commit 16a4d71b34
98 changed files with 33469 additions and 3159 deletions

View File

@ -19,9 +19,27 @@
extern "C" {
#endif
#ifndef GC_STAT_DATA
#define GC_STAT_DATA 0
#endif
#ifndef GC_STAT_SHOW
#define GC_STAT_SHOW 0
#endif
#ifndef GC_IN_EVERY_ALLOCATION
#define GC_IN_EVERY_ALLOCATION 0
#endif
#ifndef GC_MANUALLY
#define GC_MANUALLY 0
#endif
#define GC_HEAD_PADDING 4
#ifndef NULL_REF
#define NULL_REF ((gc_object_t)NULL)
#endif
#define GC_SUCCESS (0)
#define GC_ERROR (-1)
@ -33,6 +51,7 @@ extern "C" {
typedef void *gc_handle_t;
typedef void *gc_object_t;
typedef uint64 gc_uint64;
typedef int64 gc_int64;
typedef uint32 gc_uint32;
typedef int32 gc_int32;
@ -46,8 +65,24 @@ typedef enum {
GC_STAT_TOTAL = 0,
GC_STAT_FREE,
GC_STAT_HIGHMARK,
GC_STAT_COUNT,
GC_STAT_TIME,
GC_STAT_MAX
} GC_STAT_INDEX;
typedef void (*gc_finalizer_t)(void *obj, void *data);
#ifndef EXTRA_INFO_NORMAL_NODE_CNT
#define EXTRA_INFO_NORMAL_NODE_CNT 32
#endif
/* extra information attached to specific object */
typedef struct extra_info_node {
gc_object_t obj;
gc_finalizer_t finalizer;
void *data;
} extra_info_node_t;
/**
* GC initialization from a buffer, which is separated into
* two parts: the beginning of the buffer is used to create
@ -87,6 +122,28 @@ gc_init_with_struct_and_pool(char *struct_buf, gc_size_t struct_buf_size,
int
gc_destroy_with_pool(gc_handle_t handle);
#if WASM_ENABLE_GC != 0
/**
* Enable or disable GC reclaim for a heap
*
* @param handle handle of the heap
* @param exec_env the exec_env of current module instance
*/
#if WASM_ENABLE_THREAD_MGR == 0
void
gc_enable_gc_reclaim(gc_handle_t handle, void *exec_env);
#else
/**
* Enable or disable GC reclaim for a heap
*
* @param handle handle of the heap
* @param cluster the tread cluster of current module instance
*/
void
gc_enable_gc_reclaim(gc_handle_t handle, void *cluster);
#endif
#endif
/**
* Return heap struct size
*/
@ -136,6 +193,14 @@ gc_realloc_vo(void *heap, void *ptr, gc_size_t size);
int
gc_free_vo(void *heap, gc_object_t obj);
#if WASM_ENABLE_GC != 0
gc_object_t
gc_alloc_wo(void *heap, gc_size_t size);
void
gc_free_wo(void *vheap, void *ptr);
#endif
#else /* else of BH_ENABLE_GC_VERIFY */
gc_object_t
@ -148,6 +213,14 @@ gc_realloc_vo_internal(void *heap, void *ptr, gc_size_t size, const char *file,
int
gc_free_vo_internal(void *heap, gc_object_t obj, const char *file, int line);
#if WASM_ENABLE_GC != 0
gc_object_t
gc_alloc_wo_internal(void *heap, gc_size_t size, const char *file, int line);
void
gc_free_wo_internal(void *vheap, void *ptr, const char *file, int line);
#endif
/* clang-format off */
#define gc_alloc_vo(heap, size) \
gc_alloc_vo_internal(heap, size, __FILE__, __LINE__)
@ -157,10 +230,116 @@ gc_free_vo_internal(void *heap, gc_object_t obj, const char *file, int line);
#define gc_free_vo(heap, obj) \
gc_free_vo_internal(heap, obj, __FILE__, __LINE__)
#if WASM_ENABLE_GC != 0
#define gc_alloc_wo(heap, size) \
gc_alloc_wo_internal(heap, size, __FILE__, __LINE__)
#define gc_free_wo(heap, obj) \
gc_free_wo_internal(heap, obj, __FILE__, __LINE__)
#endif
/* clang-format on */
#endif /* end of BH_ENABLE_GC_VERIFY */
#if WASM_ENABLE_GC != 0
/**
* Add gc object ref to the rootset of a gc heap.
*
* @param heap the heap to add the gc object to its rootset
* @param obj pointer to a valid WASM object managed by the gc heap.
*
* @return GC_SUCCESS if success, GC_ERROR otherwise
*/
int
gc_add_root(void *heap, gc_object_t obj);
int
gci_gc_heap(void *heap);
extra_info_node_t *
gc_search_extra_info_node(gc_handle_t handle, gc_object_t obj,
gc_size_t *p_index);
/**
* Set finalizer to the given object, if another finalizer is set to the same
* object, the previous one will be cancelled
*
* @param handle handle of the heap
* @param obj object to set finalizer
* @param cb finalizer function to be called before this object is freed
* @param data custom data to be passed to finalizer function
*
* @return true if success, false otherwise
*/
bool
gc_set_finalizer(gc_handle_t handle, gc_object_t obj, gc_finalizer_t cb,
void *data);
/**
* Unset finalizer to the given object
*
* @param handle handle of the heap
* @param obj object to unset finalizer
*/
void
gc_unset_finalizer(gc_handle_t handle, gc_object_t obj);
#if WASM_ENABLE_THREAD_MGR == 0
bool
wasm_runtime_traverse_gc_rootset(void *exec_env, void *heap);
#else
bool
wasm_runtime_traverse_gc_rootset(void *cluster, void *heap);
#endif
bool
wasm_runtime_get_wasm_object_ref_list(gc_object_t obj, bool *p_is_compact_mode,
gc_uint32 *p_ref_num,
gc_uint16 **p_ref_list,
gc_uint32 *p_ref_start_offset);
bool
wasm_runtime_get_wasm_object_extra_info_flag(gc_object_t obj);
void
wasm_runtime_set_wasm_object_extra_info_flag(gc_object_t obj, bool set);
void
wasm_runtime_gc_prepare();
void
wasm_runtime_gc_finalize();
#endif /* end of WASM_ENABLE_GC != 0 */
#define GC_HEAP_STAT_SIZE (128 / 4)
typedef struct {
int usage;
int usage_block;
int vo_usage;
int wo_usage;
int free;
int free_block;
int vo_free;
int wo_free;
int usage_sizes[GC_HEAP_STAT_SIZE];
int free_sizes[GC_HEAP_STAT_SIZE];
} gc_stat_t;
void
gc_show_stat(gc_handle_t handle);
#if WASM_ENABLE_GC != 0
void
gc_show_fragment(gc_handle_t handle);
#if WASM_ENABLE_GC_PERF_PROFILING != 0
void
gc_dump_perf_profiling(gc_handle_t *handle);
#endif
#endif
#ifdef __cplusplus
}
#endif