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

@ -35,6 +35,7 @@
#endif
#include "aot_orc_extra.h"
#include "aot_comp_option.h"
#ifdef __cplusplus
extern "C" {
@ -64,6 +65,8 @@ extern "C" {
#undef DUMP_MODULE
#endif
struct AOTValueSlot;
/**
* Value in the WASM operation stack, each stack element
* is an LLVM value
@ -86,6 +89,53 @@ typedef struct AOTValueStack {
AOTValue *value_list_end;
} AOTValueStack;
/* Record information of a value slot of local variable or stack
during translation */
typedef struct AOTValueSlot {
/* The LLVM value of this slot */
LLVMValueRef value;
/* The value type of this slot */
uint8 type;
/* The dirty bit of the value slot. It's set if the value in
register is newer than the value in memory. */
uint32 dirty : 1;
/* Whether the new value in register is a reference, which is valid
only when the dirty bit is set. */
uint32 ref : 1;
/* Committed reference flag:
0: uncommitted, 1: not-reference, 2: reference */
uint32 committed_ref : 2;
} AOTValueSlot;
/* Frame information for translation */
typedef struct AOTCompFrame {
/* The current compilation context */
struct AOTCompContext *comp_ctx;
/* The current function context */
struct AOTFuncContext *func_ctx;
/* The current instruction pointer which is being compiled */
const uint8 *frame_ip;
/* Max local slot number */
uint32 max_local_cell_num;
/* Max operand stack slot number */
uint32 max_stack_cell_num;
/* Size of current AOTFrame/WASMInterpFrame */
uint32 cur_frame_size;
/* Stack top pointer */
AOTValueSlot *sp;
/* Local variables + stack operands */
AOTValueSlot lp[1];
} AOTCompFrame;
typedef struct AOTBlock {
struct AOTBlock *next;
struct AOTBlock *prev;
@ -124,6 +174,12 @@ typedef struct AOTBlock {
uint32 result_count;
uint8 *result_types;
LLVMValueRef *result_phis;
/* The begin frame stack pointer of this block */
AOTValueSlot *frame_sp_begin;
/* The max frame stack pointer that br/br_if/br_table/br_on_xxx
opcodes ever reached when they jumped to the end this block */
AOTValueSlot *frame_sp_max_reached;
} AOTBlock;
/**
@ -176,12 +232,19 @@ typedef struct AOTFuncContext {
LLVMValueRef cur_exception;
LLVMValueRef cur_frame;
LLVMValueRef cur_frame_ptr;
LLVMValueRef wasm_stack_top_bound;
LLVMValueRef wasm_stack_top_ptr;
bool mem_space_unchanged;
AOTCheckedAddrList checked_addr_list;
LLVMBasicBlockRef got_exception_block;
LLVMBasicBlockRef func_return_block;
LLVMValueRef exception_id_phi;
/* current ip when exception is thrown */
LLVMValueRef exception_ip_phi;
LLVMValueRef func_type_indexes;
#if WASM_ENABLE_DEBUG_AOT != 0
LLVMMetadataRef debug_func;
@ -198,6 +261,7 @@ typedef struct AOTLLVMTypes {
LLVMTypeRef int16_type;
LLVMTypeRef int32_type;
LLVMTypeRef int64_type;
LLVMTypeRef intptr_t_type;
LLVMTypeRef float32_type;
LLVMTypeRef float64_type;
LLVMTypeRef void_type;
@ -207,6 +271,7 @@ typedef struct AOTLLVMTypes {
LLVMTypeRef int16_ptr_type;
LLVMTypeRef int32_ptr_type;
LLVMTypeRef int64_ptr_type;
LLVMTypeRef intptr_t_ptr_type;
LLVMTypeRef float32_ptr_type;
LLVMTypeRef float64_ptr_type;
@ -233,12 +298,15 @@ typedef struct AOTLLVMTypes {
LLVMTypeRef funcref_type;
LLVMTypeRef externref_type;
LLVMTypeRef gc_ref_type;
LLVMTypeRef gc_ref_ptr_type;
} AOTLLVMTypes;
typedef struct AOTLLVMConsts {
LLVMValueRef i1_zero;
LLVMValueRef i1_one;
LLVMValueRef i8_zero;
LLVMValueRef i8_one;
LLVMValueRef i32_zero;
LLVMValueRef i64_zero;
LLVMValueRef f32_zero;
@ -282,6 +350,8 @@ typedef struct AOTLLVMConsts {
LLVMValueRef i32x8_zero;
LLVMValueRef i32x4_zero;
LLVMValueRef i32x2_zero;
LLVMValueRef gc_ref_null;
LLVMValueRef i8_ptr_null;
} AOTLLVMConsts;
/**
@ -339,6 +409,12 @@ typedef struct AOTCompContext {
/* Generate auxiliary stack frame */
bool enable_aux_stack_frame;
/* Function performance profiling */
bool enable_perf_profiling;
/* Memory usage profiling */
bool enable_memory_profiling;
/* Thread Manager */
bool enable_thread_mgr;
@ -380,6 +456,11 @@ typedef struct AOTCompContext {
/* Whether optimize the JITed code */
bool optimize;
bool emit_frame_pointer;
/* Enable GC */
bool enable_gc;
uint32 opt_level;
uint32 size_level;
@ -403,7 +484,6 @@ typedef struct AOTCompContext {
AOTLLVMConsts llvm_consts;
/* Function contexts */
/* TODO: */
AOTFuncContext **func_ctxes;
uint32 func_ctx_count;
char **custom_sections_wp;
@ -428,7 +508,8 @@ typedef struct AOTCompContext {
const char *llvm_passes;
const char *builtin_intrinsics;
bool emit_frame_pointer;
/* Current frame information for translation */
AOTCompFrame *aot_frame;
} AOTCompContext;
enum {
@ -438,41 +519,6 @@ enum {
AOT_LLVMIR_OPT_FILE,
};
/* always sync it with AOTCompOption in aot_export.h */
typedef struct AOTCompOption {
bool is_jit_mode;
bool is_indirect_mode;
char *target_arch;
char *target_abi;
char *target_cpu;
char *cpu_features;
bool is_sgx_platform;
bool enable_bulk_memory;
bool enable_thread_mgr;
bool enable_tail_call;
bool enable_simd;
bool enable_ref_types;
bool enable_aux_stack_check;
bool enable_aux_stack_frame;
bool disable_llvm_intrinsics;
bool disable_llvm_lto;
bool enable_llvm_pgo;
bool enable_stack_estimation;
bool quick_invoke_c_api_import;
char *use_prof_file;
uint32 opt_level;
uint32 size_level;
uint32 output_format;
uint32 bounds_checks;
uint32 stack_bounds_checks;
uint32 segue_flags;
char **custom_sections;
uint32 custom_sections_count;
const char *stack_usage_file;
const char *llvm_passes;
const char *builtin_intrinsics;
} AOTCompOption, *aot_comp_option_t;
bool
aot_compiler_init(void);
@ -498,13 +544,14 @@ void
aot_destroy_elf_file(uint8 *elf_file);
void
aot_value_stack_push(AOTValueStack *stack, AOTValue *value);
aot_value_stack_push(const AOTCompContext *comp_ctx, AOTValueStack *stack,
AOTValue *value);
AOTValue *
aot_value_stack_pop(AOTValueStack *stack);
aot_value_stack_pop(const AOTCompContext *comp_ctx, AOTValueStack *stack);
void
aot_value_stack_destroy(AOTValueStack *stack);
aot_value_stack_destroy(AOTCompContext *comp_ctx, AOTValueStack *stack);
void
aot_block_stack_push(AOTBlockStack *stack, AOTBlock *block);
@ -513,13 +560,14 @@ AOTBlock *
aot_block_stack_pop(AOTBlockStack *stack);
void
aot_block_stack_destroy(AOTBlockStack *stack);
aot_block_stack_destroy(AOTCompContext *comp_ctx, AOTBlockStack *stack);
void
aot_block_destroy(AOTBlock *block);
aot_block_destroy(AOTCompContext *comp_ctx, AOTBlock *block);
LLVMTypeRef
wasm_type_to_llvm_type(const AOTLLVMTypes *llvm_types, uint8 wasm_type);
wasm_type_to_llvm_type(const AOTCompContext *comp_ctx,
const AOTLLVMTypes *llvm_types, uint8 wasm_type);
bool
aot_checked_addr_list_add(AOTFuncContext *func_ctx, uint32 local_idx,