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

@ -114,9 +114,9 @@ aot_create_table_init_data_list(const WASMModule *module)
/* Create each table data segment */
for (i = 0; i < module->table_seg_count; i++) {
size =
offsetof(AOTTableInitData, func_indexes)
+ sizeof(uint32) * (uint64)module->table_segments[i].function_count;
size = offsetof(AOTTableInitData, init_values)
+ sizeof(InitializerExpression)
* (uint64)module->table_segments[i].value_count;
if (size >= UINT32_MAX
|| !(data_list[i] = wasm_runtime_malloc((uint32)size))) {
aot_set_last_error("allocate memory failed.");
@ -124,8 +124,7 @@ aot_create_table_init_data_list(const WASMModule *module)
}
data_list[i]->offset = module->table_segments[i].base_offset;
data_list[i]->func_index_count =
module->table_segments[i].function_count;
data_list[i]->value_count = module->table_segments[i].value_count;
data_list[i]->mode = module->table_segments[i].mode;
data_list[i]->elem_type = module->table_segments[i].elem_type;
/* runtime control it */
@ -133,12 +132,16 @@ aot_create_table_init_data_list(const WASMModule *module)
bh_memcpy_s(&data_list[i]->offset, sizeof(AOTInitExpr),
&module->table_segments[i].base_offset,
sizeof(AOTInitExpr));
data_list[i]->func_index_count =
module->table_segments[i].function_count;
bh_memcpy_s(data_list[i]->func_indexes,
sizeof(uint32) * module->table_segments[i].function_count,
module->table_segments[i].func_indexes,
sizeof(uint32) * module->table_segments[i].function_count);
data_list[i]->value_count = module->table_segments[i].value_count;
#if WASM_ENABLE_GC != 0
data_list[i]->elem_ref_type = module->table_segments[i].elem_ref_type;
#endif
bh_memcpy_s(data_list[i]->init_values,
sizeof(InitializerExpression)
* module->table_segments[i].value_count,
module->table_segments[i].init_values,
sizeof(InitializerExpression)
* module->table_segments[i].value_count);
}
return data_list;
@ -148,13 +151,60 @@ fail:
return NULL;
}
static void
get_value_type_size(uint8 value_type, bool gc_enabled, uint32 *p_size_64bit,
uint32 *p_size_32bit)
{
uint32 size_64bit = 0, size_32bit = 0;
if (value_type == VALUE_TYPE_I32 || value_type == VALUE_TYPE_F32)
size_64bit = size_32bit = sizeof(int32);
else if (value_type == VALUE_TYPE_I64 || value_type == VALUE_TYPE_F64)
size_64bit = size_32bit = sizeof(int64);
else if (value_type == VALUE_TYPE_V128)
size_64bit = size_32bit = sizeof(int64) * 2;
else if (!gc_enabled
&& (value_type == VALUE_TYPE_FUNCREF
|| value_type == VALUE_TYPE_EXTERNREF))
size_64bit = size_32bit = sizeof(int32);
else if (gc_enabled
&& ((value_type >= (uint8)REF_TYPE_ARRAYREF
&& value_type <= (uint8)REF_TYPE_NULLFUNCREF)
|| (value_type >= (uint8)REF_TYPE_HT_NULLABLE
&& value_type <= (uint8)REF_TYPE_HT_NON_NULLABLE)
#if WASM_ENABLE_STRINGREF != 0
|| (value_type >= (uint8)REF_TYPE_STRINGVIEWWTF8
&& value_type <= (uint8)REF_TYPE_STRINGREF)
|| (value_type >= (uint8)REF_TYPE_STRINGVIEWITER
&& value_type <= (uint8)REF_TYPE_STRINGVIEWWTF16)
#endif
)) {
size_64bit = sizeof(uint64);
size_32bit = sizeof(uint32);
}
else if (gc_enabled && value_type == PACKED_TYPE_I8) {
size_64bit = size_32bit = sizeof(int8);
}
else if (gc_enabled && value_type == PACKED_TYPE_I16) {
size_64bit = size_32bit = sizeof(int16);
}
else {
bh_assert(0);
}
*p_size_64bit = size_64bit;
*p_size_32bit = size_32bit;
}
static AOTImportGlobal *
aot_create_import_globals(const WASMModule *module,
uint32 *p_import_global_data_size)
aot_create_import_globals(const WASMModule *module, bool gc_enabled,
uint32 *p_import_global_data_size_64bit,
uint32 *p_import_global_data_size_32bit)
{
AOTImportGlobal *import_globals;
uint64 size;
uint32 i, data_offset = 0;
uint32 i, data_offset_64bit = 0, data_offset_32bit = 0;
uint32 value_size_64bit, value_size_32bit;
/* Allocate memory */
size = sizeof(AOTImportGlobal) * (uint64)module->import_global_count;
@ -175,23 +225,37 @@ aot_create_import_globals(const WASMModule *module,
import_globals[i].is_mutable = import_global->is_mutable;
import_globals[i].global_data_linked =
import_global->global_data_linked;
import_globals[i].size = wasm_value_type_size(import_global->type);
/* Calculate data offset */
import_globals[i].data_offset = data_offset;
data_offset += wasm_value_type_size(import_global->type);
import_globals[i].data_offset_64bit = data_offset_64bit;
import_globals[i].data_offset_32bit = data_offset_32bit;
get_value_type_size(import_global->type, gc_enabled, &value_size_64bit,
&value_size_32bit);
import_globals[i].size_64bit = value_size_64bit;
import_globals[i].size_32bit = value_size_32bit;
data_offset_64bit += value_size_64bit;
data_offset_32bit += value_size_32bit;
}
*p_import_global_data_size = data_offset;
*p_import_global_data_size_64bit = data_offset_64bit;
*p_import_global_data_size_32bit = data_offset_32bit;
return import_globals;
}
static AOTGlobal *
aot_create_globals(const WASMModule *module, uint32 global_data_start_offset,
uint32 *p_global_data_size)
aot_create_globals(const WASMModule *module, bool gc_enabled,
uint32 global_data_start_offset_64bit,
uint32 global_data_start_offset_32bit,
uint32 *p_global_data_size_64bit,
uint32 *p_global_data_size_32bit)
{
AOTGlobal *globals;
uint64 size;
uint32 i, data_offset = global_data_start_offset;
uint32 i;
uint32 data_offset_64bit = global_data_start_offset_64bit;
uint32 data_offset_32bit = global_data_start_offset_32bit;
uint32 value_size_64bit, value_size_32bit;
/* Allocate memory */
size = sizeof(AOTGlobal) * (uint64)module->global_count;
@ -207,65 +271,28 @@ aot_create_globals(const WASMModule *module, uint32 global_data_start_offset,
WASMGlobal *global = &module->globals[i];
globals[i].type = global->type;
globals[i].is_mutable = global->is_mutable;
globals[i].size = wasm_value_type_size(global->type);
memcpy(&globals[i].init_expr, &global->init_expr,
sizeof(global->init_expr));
/* Calculate data offset */
globals[i].data_offset = data_offset;
data_offset += wasm_value_type_size(global->type);
globals[i].data_offset_64bit = data_offset_64bit;
globals[i].data_offset_32bit = data_offset_32bit;
get_value_type_size(global->type, gc_enabled, &value_size_64bit,
&value_size_32bit);
globals[i].size_64bit = value_size_64bit;
globals[i].size_32bit = value_size_32bit;
data_offset_64bit += value_size_64bit;
data_offset_32bit += value_size_32bit;
}
*p_global_data_size = data_offset - global_data_start_offset;
*p_global_data_size_64bit =
data_offset_64bit - global_data_start_offset_64bit;
*p_global_data_size_32bit =
data_offset_32bit - global_data_start_offset_32bit;
return globals;
}
static void
aot_destroy_func_types(AOTFuncType **func_types, uint32 count)
{
uint32 i;
for (i = 0; i < count; i++)
if (func_types[i])
wasm_runtime_free(func_types[i]);
wasm_runtime_free(func_types);
}
static AOTFuncType **
aot_create_func_types(const WASMModule *module)
{
AOTFuncType **func_types;
uint64 size;
uint32 i;
/* Allocate memory */
size = sizeof(AOTFuncType *) * (uint64)module->type_count;
if (size >= UINT32_MAX
|| !(func_types = wasm_runtime_malloc((uint32)size))) {
aot_set_last_error("allocate memory failed.");
return NULL;
}
memset(func_types, 0, size);
/* Create each function type */
for (i = 0; i < module->type_count; i++) {
size = offsetof(AOTFuncType, types)
+ (uint64)module->types[i]->param_count
+ (uint64)module->types[i]->result_count;
if (size >= UINT32_MAX
|| !(func_types[i] = wasm_runtime_malloc((uint32)size))) {
aot_set_last_error("allocate memory failed.");
goto fail;
}
memcpy(func_types[i], module->types[i], size);
}
return func_types;
fail:
aot_destroy_func_types(func_types, module->type_count);
return NULL;
}
static AOTImportFunc *
aot_create_import_funcs(const WASMModule *module)
{
@ -295,7 +322,7 @@ aot_create_import_funcs(const WASMModule *module)
import_funcs[i].call_conv_wasm_c_api = false;
/* Resolve function type index */
for (j = 0; j < module->type_count; j++)
if (import_func->func_type == module->types[j]) {
if (import_func->func_type == (WASMFuncType *)module->types[j]) {
import_funcs[i].func_type_index = j;
break;
}
@ -310,13 +337,16 @@ aot_destroy_funcs(AOTFunc **funcs, uint32 count)
uint32 i;
for (i = 0; i < count; i++)
if (funcs[i])
if (funcs[i]) {
if (funcs[i]->local_offsets)
wasm_runtime_free(funcs[i]->local_offsets);
wasm_runtime_free(funcs[i]);
}
wasm_runtime_free(funcs);
}
static AOTFunc **
aot_create_funcs(const WASMModule *module)
aot_create_funcs(const WASMModule *module, uint32 pointer_size)
{
AOTFunc **funcs;
uint64 size;
@ -334,28 +364,70 @@ aot_create_funcs(const WASMModule *module)
/* Create each function */
for (i = 0; i < module->function_count; i++) {
WASMFunction *func = module->functions[i];
AOTFuncType *func_type = NULL;
AOTFunc *aot_func = NULL;
uint64 total_size;
uint32 offset = 0;
size = sizeof(AOTFunc);
if (!(funcs[i] = wasm_runtime_malloc((uint32)size))) {
if (!(aot_func = funcs[i] = wasm_runtime_malloc((uint32)size))) {
aot_set_last_error("allocate memory failed.");
goto fail;
}
memset(aot_func, 0, sizeof(AOTFunc));
func_type = aot_func->func_type = func->func_type;
/* Resolve function type index */
for (j = 0; j < module->type_count; j++) {
if (func_type == (WASMFuncType *)module->types[j]) {
aot_func->func_type_index = j;
break;
}
}
total_size = sizeof(uint16)
* ((uint64)func_type->param_count + func->local_count);
if ((total_size > 0)
&& (total_size >= UINT32_MAX
|| !(aot_func->local_offsets =
wasm_runtime_malloc((uint32)total_size)))) {
aot_set_last_error("allocate memory failed.");
goto fail;
}
funcs[i]->func_type = func->func_type;
/* Resolve function type index */
for (j = 0; j < module->type_count; j++)
if (func->func_type == module->types[j]) {
funcs[i]->func_type_index = j;
break;
}
/* Resolve local variable info and code info */
funcs[i]->local_count = func->local_count;
funcs[i]->local_types = func->local_types;
funcs[i]->param_cell_num = func->param_cell_num;
funcs[i]->local_cell_num = func->local_cell_num;
funcs[i]->code = func->code;
funcs[i]->code_size = func->code_size;
aot_func->local_count = func->local_count;
aot_func->local_types_wp = func->local_types;
aot_func->code = func->code;
aot_func->code_size = func->code_size;
/* Resolve local offsets */
for (j = 0; j < func_type->param_count; j++) {
aot_func->local_offsets[j] = (uint16)offset;
offset += wasm_value_type_cell_num_internal(func_type->types[j],
pointer_size);
}
aot_func->param_cell_num = offset;
for (j = 0; j < func->local_count; j++) {
aot_func->local_offsets[func_type->param_count + j] =
(uint16)offset;
offset += wasm_value_type_cell_num_internal(func->local_types[j],
pointer_size);
}
aot_func->local_cell_num = offset - aot_func->param_cell_num;
aot_func->max_stack_cell_num = func->max_stack_cell_num;
/* We use max_stack_cell_num calculated from wasm_loader, which is based
* on wamrc's target type.
* - If the wamrc is compiled as 64bit, then the number is enough for
* both 32bit and 64bit runtime target
* - If the wamrc is compiled as 32bit, then we multiply this number by
* two to avoid overflow on 64bit runtime target */
if (sizeof(uintptr_t) == 4) {
aot_func->max_stack_cell_num *= 2;
}
}
return funcs;
@ -365,12 +437,94 @@ fail:
return NULL;
}
#if WASM_ENABLE_GC != 0
static void
calculate_struct_field_sizes_offsets(AOTCompData *comp_data, bool is_target_x86,
bool gc_enabled)
{
uint32 i;
for (i = 0; i < comp_data->type_count; i++) {
if (comp_data->types[i]->type_flag == WASM_TYPE_STRUCT) {
WASMStructType *struct_type = (WASMStructType *)comp_data->types[i];
WASMStructFieldType *fields = struct_type->fields;
uint32 field_offset_64bit, field_offset_32bit;
uint32 field_size_64bit, field_size_32bit, j;
/* offsetof(WASMStructObject, field_data) in 64-bit */
field_offset_64bit = sizeof(uint64);
/* offsetof(WASMStructObject, field_data) in 32-bit */
field_offset_32bit = sizeof(uint32);
for (j = 0; j < struct_type->field_count; j++) {
get_value_type_size(fields[j].field_type, gc_enabled,
&field_size_64bit, &field_size_32bit);
fields[j].field_size_64bit = field_size_64bit;
fields[j].field_size_32bit = field_size_32bit;
if (!is_target_x86) {
if (field_size_64bit == 2)
field_offset_64bit = align_uint(field_offset_64bit, 2);
else if (field_size_64bit >= 4)
field_offset_64bit = align_uint(field_offset_64bit, 4);
if (field_size_32bit == 2)
field_offset_32bit = align_uint(field_offset_32bit, 2);
else if (field_size_32bit >= 4)
field_offset_32bit = align_uint(field_offset_32bit, 4);
}
fields[j].field_offset_64bit = field_offset_64bit;
fields[j].field_offset_32bit = field_offset_32bit;
field_offset_64bit += field_size_64bit;
field_offset_32bit += field_size_32bit;
}
}
}
}
#endif
AOTCompData *
aot_create_comp_data(WASMModule *module)
aot_create_comp_data(WASMModule *module, const char *target_arch,
bool gc_enabled)
{
AOTCompData *comp_data;
uint32 import_global_data_size = 0, global_data_size = 0, i, j;
uint32 import_global_data_size_64bit = 0, global_data_size_64bit = 0, i, j;
uint32 import_global_data_size_32bit = 0, global_data_size_32bit = 0;
uint64 size;
bool is_64bit_target = false;
#if WASM_ENABLE_GC != 0
bool is_target_x86 = false;
#endif
#if WASM_ENABLE_GC != 0
if (!target_arch) {
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) \
|| defined(BUILD_TARGET_X86_32)
is_target_x86 = true;
#endif
}
else {
if (!strncmp(target_arch, "x86_64", 6)
|| !strncmp(target_arch, "i386", 4))
is_target_x86 = true;
}
#endif
if (!target_arch) {
#if UINTPTR_MAX == UINT64_MAX
is_64bit_target = true;
#endif
}
else {
/* All 64bit targets contains "64" string in their target name */
if (strstr(target_arch, "64") != NULL) {
is_64bit_target = true;
}
}
/* Allocate memory */
if (!(comp_data = wasm_runtime_malloc(sizeof(AOTCompData)))) {
@ -457,6 +611,10 @@ aot_create_comp_data(WASMModule *module)
module->import_tables[i].u.table.init_size;
comp_data->tables[i].table_max_size =
module->import_tables[i].u.table.max_size;
#if WASM_ENABLE_GC != 0
comp_data->tables[i].elem_ref_type =
module->import_tables[i].u.table.elem_ref_type;
#endif
comp_data->tables[i].possible_grow =
module->import_tables[i].u.table.possible_grow;
}
@ -470,6 +628,16 @@ aot_create_comp_data(WASMModule *module)
module->tables[j].max_size;
comp_data->tables[i].possible_grow =
module->tables[j].possible_grow;
#if WASM_ENABLE_GC != 0
comp_data->tables[j].elem_ref_type =
module->tables[j].elem_ref_type;
/* Note: if the init_expr contains extra data for struct/array
* initialization information (init_expr.u.data), the pointer is
* copied.
* The pointers should still belong to wasm module, so DO NOT
* free the pointers copied to comp_data */
comp_data->tables[j].init_expr = module->tables[j].init_expr;
#endif
}
}
}
@ -484,24 +652,33 @@ aot_create_comp_data(WASMModule *module)
/* Create import globals */
comp_data->import_global_count = module->import_global_count;
if (comp_data->import_global_count > 0
&& !(comp_data->import_globals =
aot_create_import_globals(module, &import_global_data_size)))
&& !(comp_data->import_globals = aot_create_import_globals(
module, gc_enabled, &import_global_data_size_64bit,
&import_global_data_size_32bit)))
goto fail;
/* Create globals */
comp_data->global_count = module->global_count;
if (comp_data->global_count
&& !(comp_data->globals = aot_create_globals(
module, import_global_data_size, &global_data_size)))
module, gc_enabled, import_global_data_size_64bit,
import_global_data_size_32bit, &global_data_size_64bit,
&global_data_size_32bit)))
goto fail;
comp_data->global_data_size = import_global_data_size + global_data_size;
comp_data->global_data_size_64bit =
import_global_data_size_64bit + global_data_size_64bit;
comp_data->global_data_size_32bit =
import_global_data_size_32bit + global_data_size_32bit;
/* Create function types */
comp_data->func_type_count = module->type_count;
if (comp_data->func_type_count
&& !(comp_data->func_types = aot_create_func_types(module)))
goto fail;
/* Create types, they are checked by wasm loader */
comp_data->type_count = module->type_count;
comp_data->types = module->types;
#if WASM_ENABLE_GC != 0
/* Calculate the field sizes and field offsets for 64-bit and 32-bit
targets since they may vary in 32-bit target and 64-bit target */
calculate_struct_field_sizes_offsets(comp_data, is_target_x86, gc_enabled);
#endif
/* Create import functions */
comp_data->import_func_count = module->import_function_count;
@ -511,7 +688,9 @@ aot_create_comp_data(WASMModule *module)
/* Create functions */
comp_data->func_count = module->function_count;
if (comp_data->func_count && !(comp_data->funcs = aot_create_funcs(module)))
if (comp_data->func_count
&& !(comp_data->funcs =
aot_create_funcs(module, is_64bit_target ? 8 : 4)))
goto fail;
#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
@ -534,6 +713,12 @@ aot_create_comp_data(WASMModule *module)
comp_data->free_func_index = module->free_function;
comp_data->retain_func_index = module->retain_function;
#if WASM_ENABLE_STRINGREF != 0
comp_data->string_literal_count = module->string_literal_count;
comp_data->string_literal_ptrs_wp = module->string_literal_ptrs;
comp_data->string_literal_lengths_wp = module->string_literal_lengths;
#endif
comp_data->wasm_module = module;
return comp_data;
@ -576,10 +761,6 @@ aot_destroy_comp_data(AOTCompData *comp_data)
if (comp_data->globals)
wasm_runtime_free(comp_data->globals);
if (comp_data->func_types)
aot_destroy_func_types(comp_data->func_types,
comp_data->func_type_count);
if (comp_data->import_funcs)
wasm_runtime_free(comp_data->import_funcs);

View File

@ -39,7 +39,12 @@ extern const char *aot_stack_sizes_alias_name;
extern const char *aot_stack_sizes_section_name;
typedef InitializerExpression AOTInitExpr;
typedef WASMType AOTFuncType;
typedef WASMType AOTType;
typedef WASMFuncType AOTFuncType;
#if WASM_ENABLE_GC != 0
typedef WASMStructType AOTStructType;
typedef WASMArrayType AOTArrayType;
#endif
typedef WASMExport AOTExport;
#if WASM_ENABLE_DEBUG_AOT != 0
@ -117,22 +122,30 @@ typedef struct AOTMemInitData {
typedef struct AOTImportTable {
char *module_name;
char *table_name;
uint32 elem_type;
uint32 table_flags;
uint8 elem_type;
uint8 table_flags;
bool possible_grow;
uint32 table_init_size;
uint32 table_max_size;
bool possible_grow;
#if WASM_ENABLE_GC != 0
WASMRefType *elem_ref_type;
#endif
} AOTImportTable;
/**
* Table
*/
typedef struct AOTTable {
uint32 elem_type;
uint32 table_flags;
uint8 elem_type;
uint8 table_flags;
bool possible_grow;
uint32 table_init_size;
uint32 table_max_size;
bool possible_grow;
#if WASM_ENABLE_GC != 0
WASMRefType *elem_ref_type;
/* init expr for the whole table */
InitializerExpression init_expr;
#endif
} AOTTable;
/**
@ -143,14 +156,17 @@ typedef struct AOTTableInitData {
uint32 mode;
/* funcref or externref, elemkind will be considered as funcref */
uint32 elem_type;
#if WASM_ENABLE_GC != 0
WASMRefType *elem_ref_type;
#endif
/* optional, only for active */
uint32 table_index;
/* Start address of init data */
AOTInitExpr offset;
/* Function index count */
uint32 func_index_count;
uint32 value_count;
/* Function index array */
uint32 func_indexes[1];
InitializerExpression init_values[1];
} AOTTableInitData;
/**
@ -165,6 +181,19 @@ typedef struct AOTImportGlobal {
uint32 size;
/* The data offset of current global in global data */
uint32 data_offset;
#if WASM_ENABLE_WAMR_COMPILER != 0 || WASM_ENABLE_JIT != 0
/*
* The data size and data offset of a wasm global may vary
* in 32-bit target and 64-bit target, e.g., the size of a
* GC obj is 4 bytes in the former and 8 bytes in the
* latter, the AOT compiler needs to use the correct data
* offset according to the target info.
*/
uint32 size_64bit;
uint32 size_32bit;
uint32 data_offset_64bit;
uint32 data_offset_32bit;
#endif
/* global data after linked */
WASMValue global_data_linked;
bool is_linked;
@ -180,6 +209,13 @@ typedef struct AOTGlobal {
uint32 size;
/* The data offset of current global in global data */
uint32 data_offset;
#if WASM_ENABLE_WAMR_COMPILER != 0 || WASM_ENABLE_JIT != 0
/* See comments in AOTImportGlobal */
uint32 size_64bit;
uint32 size_32bit;
uint32 data_offset_64bit;
uint32 data_offset_32bit;
#endif
AOTInitExpr init_expr;
} AOTGlobal;
@ -209,11 +245,15 @@ typedef struct AOTFunc {
AOTFuncType *func_type;
uint32 func_type_index;
uint32 local_count;
uint8 *local_types;
uint8 *local_types_wp;
uint16 param_cell_num;
uint16 local_cell_num;
uint32 max_stack_cell_num;
uint32 code_size;
uint8 *code;
/* offset of each local, including function parameters
and local variables */
uint16 *local_offsets;
} AOTFunc;
typedef struct AOTCompData {
@ -250,8 +290,8 @@ typedef struct AOTCompData {
AOTGlobal *globals;
/* Function types */
uint32 func_type_count;
AOTFuncType **func_types;
uint32 type_count;
AOTType **types;
/* Import functions */
uint32 import_func_count;
@ -267,7 +307,8 @@ typedef struct AOTCompData {
uint8 *aot_name_section_buf;
uint32 aot_name_section_size;
uint32 global_data_size;
uint32 global_data_size_64bit;
uint32 global_data_size_32bit;
uint32 start_func_index;
uint32 malloc_func_index;
@ -282,6 +323,12 @@ typedef struct AOTCompData {
uint32 aux_stack_bottom;
uint32 aux_stack_size;
#if WASM_ENABLE_STRINGREF != 0
uint32 string_literal_count;
uint32 *string_literal_lengths_wp;
const uint8 **string_literal_ptrs_wp;
#endif
WASMModule *wasm_module;
#if WASM_ENABLE_DEBUG_AOT != 0
dwarf_extractor_handle_t extractor;
@ -295,7 +342,8 @@ typedef struct AOTNativeSymbol {
} AOTNativeSymbol;
AOTCompData *
aot_create_comp_data(WASMModule *module);
aot_create_comp_data(WASMModule *module, const char *target_arch,
bool gc_enabled);
void
aot_destroy_comp_data(AOTCompData *comp_data);

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,8 @@
#include "aot.h"
#include "aot_llvm.h"
#include "../interpreter/wasm_interp.h"
#include "../aot/aot_runtime.h"
#ifdef __cplusplus
extern "C" {
@ -78,8 +80,33 @@ typedef enum FloatArithmetic {
FLOAT_MAX,
} FloatArithmetic;
/**
* Check whether a value type is a GC reference type,
* don't use wasm_is_type_reftype since it requires
* GC feature and may result in compilation error when
* GC feature isn't compiled
*/
static inline bool
check_type_compatible(uint8 src_type, uint8 dst_type)
aot_is_type_gc_reftype(uint8 type)
{
return ((type >= (uint8)REF_TYPE_ARRAYREF
&& type <= (uint8)REF_TYPE_NULLFUNCREF)
|| (type >= (uint8)REF_TYPE_HT_NULLABLE
&& type <= (uint8)REF_TYPE_HT_NON_NULLABLE)
#if WASM_ENABLE_STRINGREF != 0
|| (type >= (uint8)REF_TYPE_STRINGVIEWWTF8
&& type <= (uint8)REF_TYPE_STRINGREF)
|| (type >= (uint8)REF_TYPE_STRINGVIEWITER
&& type <= (uint8)REF_TYPE_STRINGVIEWWTF16)
#endif
)
? true
: false;
}
static inline bool
check_type_compatible(const AOTCompContext *comp_ctx, uint8 src_type,
uint8 dst_type)
{
if (src_type == dst_type) {
return true;
@ -92,20 +119,332 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
/* i32 <==> func.ref, i32 <==> extern.ref */
if (src_type == VALUE_TYPE_I32
&& (dst_type == VALUE_TYPE_EXTERNREF
|| dst_type == VALUE_TYPE_FUNCREF)) {
&& (comp_ctx->enable_ref_types
&& (dst_type == VALUE_TYPE_EXTERNREF
|| dst_type == VALUE_TYPE_FUNCREF))) {
return true;
}
if (dst_type == VALUE_TYPE_I32
&& (src_type == VALUE_TYPE_FUNCREF
|| src_type == VALUE_TYPE_EXTERNREF)) {
&& (comp_ctx->enable_ref_types
&& (src_type == VALUE_TYPE_FUNCREF
|| src_type == VALUE_TYPE_EXTERNREF))) {
return true;
}
return false;
}
/**
* Operations for AOTCompFrame
*/
/**
* Get the offset from frame pointer to the n-th local variable slot.
*
* @param n the index to the local variable array
*
* @return the offset from frame pointer to the local variable slot
*/
static inline uint32
offset_of_local(AOTCompContext *comp_ctx, unsigned n)
{
if (!comp_ctx->is_jit_mode)
/* In AOTFrame, there are 7 pointers before field lp */
return comp_ctx->pointer_size
* (offsetof(AOTFrame, lp) / sizeof(uintptr_t))
+ sizeof(uint32) * n;
else
return offsetof(WASMInterpFrame, lp) + sizeof(uint32) * n;
}
uint32
offset_of_local_in_outs_area(AOTCompContext *comp_ctx, unsigned n);
/**
* Get the offset from frame pointer to the n-th local variable's
* reference flag slot.
*
* @param n the index to the local variable array
*
* @return the offset from frame pointer to the local variable slot
*/
static inline unsigned
offset_of_ref(AOTCompContext *comp_ctx, unsigned n)
{
AOTCompFrame *frame = comp_ctx->aot_frame;
uint32 all_cell_num = frame->max_local_cell_num + frame->max_stack_cell_num;
return offset_of_local(comp_ctx, all_cell_num) + n;
}
/**
* Generate instructions to commit computation result to the frame.
* The general principle is to only commit values that will be used
* through the frame.
*
* @param frame the frame information
*/
bool
aot_gen_commit_values(AOTCompFrame *frame);
/**
* Generate instructions to commit SP and IP pointers to the frame.
*
* @param frame the frame information
*/
bool
aot_gen_commit_sp_ip(AOTCompFrame *frame, bool commit_sp, bool commit_ip);
bool
aot_frame_store_value(AOTCompContext *comp_ctx, LLVMValueRef value,
uint8 value_type, LLVMValueRef cur_frame, uint32 offset);
static inline void
push_32bit(AOTCompFrame *frame, AOTValue *aot_value)
{
frame->sp->value = aot_value->value;
frame->sp->type = aot_value->type;
frame->sp->dirty = 1;
frame->sp++;
}
static inline void
push_64bit(AOTCompFrame *frame, AOTValue *aot_value)
{
push_32bit(frame, aot_value);
push_32bit(frame, aot_value);
}
static inline void
push_i32(AOTCompFrame *frame, AOTValue *aot_value)
{
bh_assert(aot_value->type == VALUE_TYPE_I32
|| aot_value->type == VALUE_TYPE_I1);
push_32bit(frame, aot_value);
}
static inline void
push_i64(AOTCompFrame *frame, AOTValue *aot_value)
{
bh_assert(aot_value->type == VALUE_TYPE_I64);
push_64bit(frame, aot_value);
}
static inline void
push_f32(AOTCompFrame *frame, AOTValue *aot_value)
{
bh_assert(aot_value->type == VALUE_TYPE_F32);
push_32bit(frame, aot_value);
}
static inline void
push_f64(AOTCompFrame *frame, AOTValue *aot_value)
{
bh_assert(aot_value->type == VALUE_TYPE_F64);
push_64bit(frame, aot_value);
}
static inline void
push_v128(AOTCompFrame *frame, AOTValue *aot_value)
{
bh_assert(aot_value->type == VALUE_TYPE_V128);
push_64bit(frame, aot_value);
push_64bit(frame, aot_value);
}
static inline void
push_ref(AOTCompFrame *frame, AOTValue *aot_value)
{
bh_assert(frame->comp_ctx->enable_ref_types);
push_32bit(frame, aot_value);
}
#if WASM_ENABLE_GC != 0
static inline void
push_gc_ref(AOTCompFrame *frame, AOTValue *aot_value)
{
bh_assert(frame->comp_ctx->enable_gc);
bh_assert(aot_value->type == VALUE_TYPE_GC_REF);
if (frame->comp_ctx->pointer_size == sizeof(uint64)) {
push_64bit(frame, aot_value);
(frame->sp - 1)->ref = (frame->sp - 2)->ref = 1;
}
else {
push_32bit(frame, aot_value);
(frame->sp - 1)->ref = 1;
}
}
#endif
/* Clear value slots except ref and committed_ref */
static inline void
clear_frame_value_slots(AOTValueSlot *slots, uint32 n)
{
uint32 i;
for (i = 0; i < n; i++) {
slots[i].value = 0;
slots[i].type = 0;
slots[i].dirty = 0;
}
}
static inline void
pop_i32(AOTCompFrame *frame)
{
bh_assert(frame->sp - frame->lp >= 1);
bh_assert((frame->sp - 1)->type == VALUE_TYPE_I32
|| (frame->sp - 1)->type == VALUE_TYPE_I1);
frame->sp--;
clear_frame_value_slots(frame->sp, 1);
}
static inline void
pop_i64(AOTCompFrame *frame)
{
bh_assert(frame->sp - frame->lp >= 2);
bh_assert((frame->sp - 1)->type == VALUE_TYPE_I64
&& (frame->sp - 2)->type == VALUE_TYPE_I64);
frame->sp -= 2;
clear_frame_value_slots(frame->sp, 2);
}
static inline void
pop_f32(AOTCompFrame *frame)
{
bh_assert(frame->sp - frame->lp >= 1);
bh_assert((frame->sp - 1)->type == VALUE_TYPE_F32);
frame->sp--;
clear_frame_value_slots(frame->sp, 1);
}
static inline void
pop_f64(AOTCompFrame *frame)
{
bh_assert(frame->sp - frame->lp >= 2);
bh_assert((frame->sp - 1)->type == VALUE_TYPE_F64
&& (frame->sp - 2)->type == VALUE_TYPE_F64);
frame->sp -= 2;
clear_frame_value_slots(frame->sp, 2);
}
static inline void
pop_v128(AOTCompFrame *frame)
{
bh_assert(frame->sp - frame->lp >= 4);
bh_assert((frame->sp - 1)->type == VALUE_TYPE_V128
&& (frame->sp - 2)->type == VALUE_TYPE_V128
&& (frame->sp - 3)->type == VALUE_TYPE_V128
&& (frame->sp - 4)->type == VALUE_TYPE_V128);
frame->sp -= 4;
clear_frame_value_slots(frame->sp, 4);
}
static inline void
pop_ref(AOTCompFrame *frame)
{
bh_assert(frame->sp - frame->lp >= 1);
bh_assert((frame->sp - 1)->type == VALUE_TYPE_FUNCREF
|| (frame->sp - 1)->type == VALUE_TYPE_EXTERNREF);
frame->sp -= 1;
clear_frame_value_slots(frame->sp, 1);
}
#if WASM_ENABLE_GC != 0
static inline void
pop_gc_ref(AOTCompFrame *frame)
{
bh_assert(frame->sp - frame->lp >= 1);
bh_assert((frame->sp - 1)->type == VALUE_TYPE_GC_REF);
frame->sp -= 1;
clear_frame_value_slots(frame->sp, 1);
frame->sp->ref = 0;
if (frame->comp_ctx->pointer_size == sizeof(uint64)) {
bh_assert(frame->sp - frame->lp >= 1);
bh_assert((frame->sp - 1)->type == VALUE_TYPE_GC_REF);
frame->sp -= 1;
clear_frame_value_slots(frame->sp, 1);
frame->sp->ref = 0;
}
}
#endif
static inline void
set_local_i32(AOTCompFrame *frame, int n, LLVMValueRef value)
{
frame->lp[n].value = value;
frame->lp[n].type = VALUE_TYPE_I32;
frame->lp[n].dirty = 1;
}
static inline void
set_local_i64(AOTCompFrame *frame, int n, LLVMValueRef value)
{
frame->lp[n].value = value;
frame->lp[n].type = VALUE_TYPE_I64;
frame->lp[n].dirty = 1;
frame->lp[n + 1].value = value;
frame->lp[n + 1].type = VALUE_TYPE_I64;
frame->lp[n + 1].dirty = 1;
}
static inline void
set_local_f32(AOTCompFrame *frame, int n, LLVMValueRef value)
{
frame->lp[n].value = value;
frame->lp[n].type = VALUE_TYPE_F32;
frame->lp[n].dirty = 1;
}
static inline void
set_local_f64(AOTCompFrame *frame, int n, LLVMValueRef value)
{
frame->lp[n].value = value;
frame->lp[n].type = VALUE_TYPE_F64;
frame->lp[n].dirty = 1;
frame->lp[n + 1].value = value;
frame->lp[n + 1].type = VALUE_TYPE_F64;
frame->lp[n + 1].dirty = 1;
}
static inline void
set_local_v128(AOTCompFrame *frame, int n, LLVMValueRef value)
{
uint32 i;
for (i = 0; i < 4; i++) {
frame->lp[n + i].value = value;
frame->lp[n + i].type = VALUE_TYPE_V128;
frame->lp[n + i].dirty = 1;
}
}
static inline void
set_local_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type)
{
bh_assert(frame->comp_ctx->enable_ref_types);
frame->lp[n].value = value;
frame->lp[n].type = ref_type;
frame->lp[n].dirty = 1;
}
#if WASM_ENABLE_GC != 0
static inline void
set_local_gc_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type)
{
bh_assert(frame->comp_ctx->enable_gc);
bh_assert(ref_type == VALUE_TYPE_GC_REF);
frame->lp[n].value = value;
frame->lp[n].type = ref_type;
frame->lp[n].dirty = 1;
frame->lp[n].ref = 1;
if (frame->comp_ctx->pointer_size == sizeof(uint64)) {
frame->lp[n + 1].value = value;
frame->lp[n + 1].type = ref_type;
frame->lp[n + 1].dirty = 1;
frame->lp[n + 1].ref = 1;
}
}
#endif
#define CHECK_STACK() \
do { \
if (!func_ctx->block_stack.block_list_end) { \
@ -119,37 +458,61 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
} \
} while (0)
#if WASM_ENABLE_GC != 0
#define GET_GC_REF_FROM_STACK(llvm_value) \
do { \
AOTValue *aot_value; \
CHECK_STACK(); \
aot_value = \
func_ctx->block_stack.block_list_end->value_stack.value_list_end; \
if (aot_value->type != VALUE_TYPE_GC_REF) { \
aot_set_last_error("WASM stack data type is not reference"); \
goto fail; \
} \
llvm_value = aot_value->value; \
} while (0)
#endif
#define POP(llvm_value, value_type) \
do { \
AOTValue *aot_value; \
uint8 val_type_to_pop = value_type; \
CHECK_STACK(); \
aot_value = aot_value_stack_pop( \
&func_ctx->block_stack.block_list_end->value_stack); \
if (!check_type_compatible(aot_value->type, value_type)) { \
comp_ctx, &func_ctx->block_stack.block_list_end->value_stack); \
if (comp_ctx->enable_gc && aot_is_type_gc_reftype(value_type)) \
val_type_to_pop = VALUE_TYPE_GC_REF; \
if (!check_type_compatible(comp_ctx, aot_value->type, \
val_type_to_pop)) { \
aot_set_last_error("invalid WASM stack data type."); \
wasm_runtime_free(aot_value); \
goto fail; \
} \
if (aot_value->type == value_type) \
if (aot_value->type == val_type_to_pop) \
llvm_value = aot_value->value; \
else { \
if (aot_value->type == VALUE_TYPE_I1) { \
if (!(llvm_value = \
LLVMBuildZExt(comp_ctx->builder, aot_value->value, \
I32_TYPE, "i1toi32"))) { \
aot_set_last_error("invalid WASM stack " \
"data type."); \
aot_set_last_error("invalid WASM stack data type."); \
wasm_runtime_free(aot_value); \
goto fail; \
} \
} \
else { \
bh_assert(aot_value->type == VALUE_TYPE_I32 \
|| aot_value->type == VALUE_TYPE_FUNCREF \
|| aot_value->type == VALUE_TYPE_EXTERNREF); \
bh_assert(value_type == VALUE_TYPE_I32 \
|| value_type == VALUE_TYPE_FUNCREF \
|| value_type == VALUE_TYPE_EXTERNREF); \
bh_assert( \
aot_value->type == VALUE_TYPE_I32 \
|| (comp_ctx->enable_ref_types \
&& (aot_value->type == VALUE_TYPE_FUNCREF \
|| aot_value->type == VALUE_TYPE_EXTERNREF))); \
bh_assert( \
val_type_to_pop == VALUE_TYPE_I32 \
|| (comp_ctx->enable_ref_types \
&& (val_type_to_pop == VALUE_TYPE_FUNCREF \
|| val_type_to_pop == VALUE_TYPE_EXTERNREF))); \
llvm_value = aot_value->value; \
} \
} \
@ -163,13 +526,14 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
#define POP_V128(v) POP(v, VALUE_TYPE_V128)
#define POP_FUNCREF(v) POP(v, VALUE_TYPE_FUNCREF)
#define POP_EXTERNREF(v) POP(v, VALUE_TYPE_EXTERNREF)
#define POP_GC_REF(v) POP(v, VALUE_TYPE_GC_REF)
#define POP_COND(llvm_value) \
do { \
AOTValue *aot_value; \
CHECK_STACK(); \
aot_value = aot_value_stack_pop( \
&func_ctx->block_stack.block_list_end->value_stack); \
comp_ctx, &func_ctx->block_stack.block_list_end->value_stack); \
if (aot_value->type != VALUE_TYPE_I1 \
&& aot_value->type != VALUE_TYPE_I32) { \
aot_set_last_error("invalid WASM stack data type."); \
@ -190,23 +554,27 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
wasm_runtime_free(aot_value); \
} while (0)
#define PUSH(llvm_value, value_type) \
do { \
AOTValue *aot_value; \
if (!func_ctx->block_stack.block_list_end) { \
aot_set_last_error("WASM block stack underflow."); \
goto fail; \
} \
aot_value = wasm_runtime_malloc(sizeof(AOTValue)); \
if (!aot_value) { \
aot_set_last_error("allocate memory failed."); \
goto fail; \
} \
memset(aot_value, 0, sizeof(AOTValue)); \
aot_value->type = value_type; \
aot_value->value = llvm_value; \
aot_value_stack_push( \
&func_ctx->block_stack.block_list_end->value_stack, aot_value); \
#define PUSH(llvm_value, value_type) \
do { \
AOTValue *aot_value; \
if (!func_ctx->block_stack.block_list_end) { \
aot_set_last_error("WASM block stack underflow."); \
goto fail; \
} \
aot_value = wasm_runtime_malloc(sizeof(AOTValue)); \
if (!aot_value) { \
aot_set_last_error("allocate memory failed."); \
goto fail; \
} \
memset(aot_value, 0, sizeof(AOTValue)); \
if (comp_ctx->enable_gc && aot_is_type_gc_reftype(value_type)) \
aot_value->type = VALUE_TYPE_GC_REF; \
else \
aot_value->type = value_type; \
aot_value->value = llvm_value; \
aot_value_stack_push( \
comp_ctx, &func_ctx->block_stack.block_list_end->value_stack, \
aot_value); \
} while (0)
#define PUSH_I32(v) PUSH(v, VALUE_TYPE_I32)
@ -217,9 +585,10 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
#define PUSH_COND(v) PUSH(v, VALUE_TYPE_I1)
#define PUSH_FUNCREF(v) PUSH(v, VALUE_TYPE_FUNCREF)
#define PUSH_EXTERNREF(v) PUSH(v, VALUE_TYPE_EXTERNREF)
#define PUSH_GC_REF(v) PUSH(v, VALUE_TYPE_GC_REF)
#define TO_LLVM_TYPE(wasm_type) \
wasm_type_to_llvm_type(&comp_ctx->basic_types, wasm_type)
wasm_type_to_llvm_type(comp_ctx, &comp_ctx->basic_types, wasm_type)
#define I32_TYPE comp_ctx->basic_types.int32_type
#define I64_TYPE comp_ctx->basic_types.int64_type
@ -229,15 +598,19 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
#define INT1_TYPE comp_ctx->basic_types.int1_type
#define INT8_TYPE comp_ctx->basic_types.int8_type
#define INT16_TYPE comp_ctx->basic_types.int16_type
#define INTPTR_T_TYPE comp_ctx->basic_types.intptr_t_type
#define MD_TYPE comp_ctx->basic_types.meta_data_type
#define INT8_PTR_TYPE comp_ctx->basic_types.int8_ptr_type
#define INT16_PTR_TYPE comp_ctx->basic_types.int16_ptr_type
#define INT32_PTR_TYPE comp_ctx->basic_types.int32_ptr_type
#define INT64_PTR_TYPE comp_ctx->basic_types.int64_ptr_type
#define INTPTR_T_PTR_TYPE comp_ctx->basic_types.intptr_t_ptr_type
#define F32_PTR_TYPE comp_ctx->basic_types.float32_ptr_type
#define F64_PTR_TYPE comp_ctx->basic_types.float64_ptr_type
#define FUNC_REF_TYPE comp_ctx->basic_types.funcref_type
#define EXTERN_REF_TYPE comp_ctx->basic_types.externref_type
#define GC_REF_TYPE comp_ctx->basic_types.gc_ref_type
#define GC_REF_PTR_TYPE comp_ctx->basic_types.gc_ref_ptr_type
#define INT8_PTR_TYPE_GS comp_ctx->basic_types.int8_ptr_type_gs
#define INT16_PTR_TYPE_GS comp_ctx->basic_types.int16_ptr_type_gs
@ -253,7 +626,10 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
#define I8_CONST(v) LLVMConstInt(INT8_TYPE, v, true)
#define LLVM_CONST(name) (comp_ctx->llvm_consts.name)
#define I1_ZERO LLVM_CONST(i1_zero)
#define I1_ONE LLVM_CONST(i1_one)
#define I8_ZERO LLVM_CONST(i8_zero)
#define I8_ONE LLVM_CONST(i8_one)
#define I32_ZERO LLVM_CONST(i32_zero)
#define I64_ZERO LLVM_CONST(i64_zero)
#define F32_ZERO LLVM_CONST(f32_zero)
@ -267,6 +643,9 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
#define I32_SEVEN LLVM_CONST(i32_seven)
#define I32_EIGHT LLVM_CONST(i32_eight)
#define I32_NINE LLVM_CONST(i32_nine)
#define I32_TEN LLVM_CONST(i32_ten)
#define I32_ELEVEN LLVM_CONST(i32_eleven)
#define I32_TWELVE LLVM_CONST(i32_twelve)
#define I32_NEG_ONE LLVM_CONST(i32_neg_one)
#define I64_NEG_ONE LLVM_CONST(i64_neg_one)
#define I32_MIN LLVM_CONST(i32_min)
@ -276,6 +655,8 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
#define I64_63 LLVM_CONST(i64_63)
#define I64_64 LLVM_CONST(i64_64)
#define REF_NULL I32_NEG_ONE
#define GC_REF_NULL LLVM_CONST(gc_ref_null)
#define I8_PTR_NULL LLVM_CONST(i8_ptr_null)
#define V128_TYPE comp_ctx->basic_types.v128_type
#define V128_PTR_TYPE comp_ctx->basic_types.v128_ptr_type

File diff suppressed because it is too large Load Diff

View File

@ -230,3 +230,27 @@ aot_compile_op_f64_compare(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
fail:
return false;
}
bool
aot_compile_op_ref_eq(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
LLVMValueRef gc_obj1 = NULL, gc_obj2 = NULL, res;
POP_GC_REF(gc_obj1);
POP_GC_REF(gc_obj2);
/* LLVM pointer values pointers are compared using LLVMBuildICmp */
res = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, gc_obj1, gc_obj2,
"cmp_gc_obj_eq");
if (!res) {
aot_set_last_error("llvm build compare failed.");
return false;
}
PUSH_COND(res);
return true;
fail:
return false;
}

View File

@ -28,6 +28,13 @@ bool
aot_compile_op_f64_compare(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
FloatCond cond);
#if WASM_ENABLE_GC != 0
bool
aot_compile_op_ref_eq(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
#endif
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View File

@ -6,6 +6,9 @@
#include "aot_emit_control.h"
#include "aot_compiler.h"
#include "aot_emit_exception.h"
#if WASM_ENABLE_GC != 0
#include "aot_emit_gc.h"
#endif
#include "../aot/aot_runtime.h"
#include "../interpreter/wasm_loader.h"
@ -155,12 +158,81 @@ get_target_block(AOTFuncContext *func_ctx, uint32 br_depth)
return block;
}
static void
clear_frame_locals(AOTCompFrame *aot_frame)
{
uint32 i;
for (i = 0; i < aot_frame->max_local_cell_num; i++) {
aot_frame->lp[i].dirty = 0;
aot_frame->lp[i].value = NULL;
if (aot_frame->comp_ctx->enable_gc)
/* Mark the ref flag as committed */
aot_frame->lp[i].committed_ref = aot_frame->lp[i].ref + 1;
}
}
static void
restore_frame_sp_for_op_else(AOTBlock *block, AOTCompFrame *aot_frame)
{
uint32 all_cell_num =
aot_frame->max_local_cell_num + aot_frame->max_stack_cell_num;
AOTValueSlot *p_end = aot_frame->lp + all_cell_num, *p;
/* Reset all the value slots from current frame sp for the else
branch since they be the same as starting to translate the
if branch */
for (p = block->frame_sp_begin; p < p_end; p++) {
p->dirty = 0;
p->value = NULL;
p->type = 0;
if (aot_frame->comp_ctx->enable_gc) {
p->ref = 0;
p->committed_ref = 1;
}
}
bh_assert(aot_frame->sp >= block->frame_sp_begin);
aot_frame->sp = block->frame_sp_begin;
}
static void
restore_frame_sp_for_op_end(AOTBlock *block, AOTCompFrame *aot_frame)
{
uint32 all_cell_num =
aot_frame->max_local_cell_num + aot_frame->max_stack_cell_num;
AOTValueSlot *p_end = aot_frame->lp + all_cell_num, *p;
bh_assert(block->frame_sp_max_reached >= block->frame_sp_begin);
/* Reset all the value slots from current frame sp to be same as
starting to translate this block, except for the frame ref
flags: set the flags to uncommitted before the max frame sp
ever reached, set the flags to committed non-ref after that */
for (p = block->frame_sp_begin; p < p_end; p++) {
p->dirty = 0;
p->value = NULL;
p->type = 0;
if (aot_frame->comp_ctx->enable_gc) {
p->ref = 0;
if (p < block->frame_sp_max_reached)
p->committed_ref = 0;
else
p->committed_ref = 1;
}
}
bh_assert(aot_frame->sp >= block->frame_sp_begin);
aot_frame->sp = block->frame_sp_begin;
}
static bool
handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint8 **p_frame_ip)
{
AOTBlock *block = func_ctx->block_stack.block_list_end;
AOTBlock *block_prev;
AOTCompFrame *aot_frame = comp_ctx->aot_frame;
uint8 *frame_ip = NULL;
uint32 i;
AOTFuncType *func_type;
@ -177,10 +249,22 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
comp_ctx, func_ctx,
(*p_frame_ip - 1) - comp_ctx->comp_data->wasm_module->buf_code);
#endif
if (aot_frame) {
/* Clear frame local variables since they have been committed */
clear_frame_locals(aot_frame);
}
if (block->label_type == LABEL_TYPE_IF && block->llvm_else_block
&& *p_frame_ip <= block->wasm_code_else) {
/* Clear value stack and start to translate else branch */
aot_value_stack_destroy(&block->value_stack);
aot_value_stack_destroy(comp_ctx, &block->value_stack);
if (aot_frame) {
/* Restore the frame sp */
restore_frame_sp_for_op_else(block, aot_frame);
}
/* Recover parameters of else branch */
for (i = 0; i < block->param_count; i++)
PUSH(block->else_param_phis[i], block->param_types[i]);
@ -197,7 +281,13 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
if (block->llvm_else_block && !block->skip_wasm_code_else
&& *p_frame_ip <= block->wasm_code_else) {
/* Clear value stack and start to translate else branch */
aot_value_stack_destroy(&block->value_stack);
aot_value_stack_destroy(comp_ctx, &block->value_stack);
if (aot_frame) {
/* Restore the frame sp */
restore_frame_sp_for_op_else(block, aot_frame);
}
SET_BUILDER_POS(block->llvm_else_block);
*p_frame_ip = block->wasm_code_else + 1;
/* Push back the block */
@ -215,7 +305,7 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
}
frame_ip = block->wasm_code_end;
aot_block_destroy(block);
aot_block_destroy(comp_ctx, block);
block = block_prev;
}
@ -228,7 +318,13 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
&& !block->skip_wasm_code_else
&& *p_frame_ip <= block->wasm_code_else) {
/* Clear value stack and start to translate else branch */
aot_value_stack_destroy(&block->value_stack);
aot_value_stack_destroy(comp_ctx, &block->value_stack);
if (aot_frame) {
/* Restore the frame sp */
restore_frame_sp_for_op_else(block, aot_frame);
}
/* Recover parameters of else branch */
for (i = 0; i < block->param_count; i++)
PUSH(block->else_param_phis[i], block->param_types[i]);
@ -242,6 +338,12 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
/* Pop block, push its return value, and destroy the block */
block = aot_block_stack_pop(&func_ctx->block_stack);
if (aot_frame) {
/* Restore the frame sp */
restore_frame_sp_for_op_end(block, aot_frame);
}
func_type = func_ctx->aot_func->func_type;
for (i = 0; i < block->result_count; i++) {
bh_assert(block->result_phis[i]);
@ -285,7 +387,7 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
#endif
}
}
aot_block_destroy(block);
aot_block_destroy(comp_ctx, block);
return true;
fail:
return false;
@ -381,6 +483,10 @@ push_aot_block_to_stack_and_pass_params(AOTCompContext *comp_ctx,
/* Push the new block to block stack */
aot_block_stack_push(&func_ctx->block_stack, block);
if (comp_ctx->aot_frame) {
block->frame_sp_begin = block->frame_sp_max_reached =
comp_ctx->aot_frame->sp;
}
/* Push param phis to the new block */
for (i = 0; i < block->param_count; i++) {
@ -473,6 +579,13 @@ aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
block->block_index = func_ctx->block_stack.block_index[label_type];
func_ctx->block_stack.block_index[label_type]++;
if (comp_ctx->aot_frame) {
if (label_type != LABEL_TYPE_BLOCK && comp_ctx->enable_gc
&& !aot_gen_commit_values(comp_ctx->aot_frame)) {
goto fail;
}
}
if (label_type == LABEL_TYPE_BLOCK || label_type == LABEL_TYPE_LOOP) {
/* Create block */
format_block_name(name, sizeof(name), block->block_index, label_type,
@ -500,7 +613,7 @@ aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
false, NULL, NULL))) {
goto fail;
}
aot_block_destroy(block);
aot_block_destroy(comp_ctx, block);
return aot_handle_next_reachable_block(comp_ctx, func_ctx,
p_frame_ip);
}
@ -580,7 +693,7 @@ aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
}
else {
/* skip the block */
aot_block_destroy(block);
aot_block_destroy(comp_ctx, block);
*p_frame_ip = end_addr + 1;
}
}
@ -593,7 +706,7 @@ aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
return true;
fail:
aot_block_destroy(block);
aot_block_destroy(comp_ctx, block);
return false;
}
@ -603,6 +716,7 @@ aot_compile_op_else(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
{
AOTBlock *block = func_ctx->block_stack.block_list_end;
LLVMValueRef value;
AOTCompFrame *aot_frame = comp_ctx->aot_frame;
char name[32];
uint32 i, result_index;
@ -638,14 +752,26 @@ aot_compile_op_else(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
ADD_TO_RESULT_PHIS(block, value, result_index);
}
if (aot_frame) {
bh_assert(block->frame_sp_begin == aot_frame->sp);
if (comp_ctx->enable_gc && !aot_gen_commit_values(aot_frame)) {
goto fail;
}
}
/* Jump to end block */
BUILD_BR(block->llvm_end_block);
if (!block->skip_wasm_code_else && block->llvm_else_block) {
/* Clear value stack, recover param values
* and start to translate else branch.
*/
aot_value_stack_destroy(&block->value_stack);
and start to translate else branch. */
aot_value_stack_destroy(comp_ctx, &block->value_stack);
if (comp_ctx->aot_frame) {
clear_frame_locals(aot_frame);
restore_frame_sp_for_op_else(block, aot_frame);
}
for (i = 0; i < block->param_count; i++)
PUSH(block->else_param_phis[i], block->param_types[i]);
SET_BUILDER_POS(block->llvm_else_block);
@ -685,6 +811,13 @@ aot_compile_op_end(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
MOVE_BLOCK_BEFORE(block->llvm_end_block, next_llvm_end_block);
}
if (comp_ctx->aot_frame) {
if (block->label_type != LABEL_TYPE_FUNCTION && comp_ctx->enable_gc
&& !aot_gen_commit_values(comp_ctx->aot_frame)) {
return false;
}
}
/* Handle block result values */
CREATE_RESULT_VALUE_PHIS(block);
for (i = 0; i < block->result_count; i++) {
@ -695,6 +828,10 @@ aot_compile_op_end(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
ADD_TO_RESULT_PHIS(block, value, result_index);
}
if (comp_ctx->aot_frame) {
bh_assert(comp_ctx->aot_frame->sp == block->frame_sp_begin);
}
/* Jump to the end block */
BUILD_BR(block->llvm_end_block);
@ -704,9 +841,9 @@ fail:
return false;
}
#if WASM_ENABLE_THREAD_MGR != 0
bool
check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
bool check_terminate_and_suspend)
{
LLVMValueRef terminate_addr, terminate_flags, flag, offset, res;
LLVMBasicBlockRef terminate_block, non_terminate_block;
@ -774,7 +911,6 @@ check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
fail:
return false;
}
#endif /* End of WASM_ENABLE_THREAD_MGR */
bool
aot_compile_op_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
@ -786,18 +922,35 @@ aot_compile_op_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
char name[32];
uint32 i, param_index, result_index;
#if WASM_ENABLE_THREAD_MGR != 0
/* Insert suspend check point */
if (comp_ctx->enable_thread_mgr) {
if (!check_suspend_flags(comp_ctx, func_ctx))
return false;
}
#endif
if (!(block_dst = get_target_block(func_ctx, br_depth))) {
return false;
}
if (comp_ctx->aot_frame) {
if (comp_ctx->enable_gc && !aot_gen_commit_values(comp_ctx->aot_frame))
return false;
if (block_dst->label_type == LABEL_TYPE_LOOP) {
if (comp_ctx->enable_thread_mgr) {
/* Commit sp when GC is enabled, don't commit ip */
if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame,
comp_ctx->enable_gc, false))
return false;
}
}
else {
if (comp_ctx->aot_frame->sp > block_dst->frame_sp_max_reached)
block_dst->frame_sp_max_reached = comp_ctx->aot_frame->sp;
}
}
/* Terminate or suspend current thread only when this is a backward jump */
if (comp_ctx->enable_thread_mgr
&& block_dst->label_type == LABEL_TYPE_LOOP) {
if (!check_suspend_flags(comp_ctx, func_ctx, true))
return false;
}
if (block_dst->label_type == LABEL_TYPE_LOOP) {
/* Dest block is Loop block */
/* Handle Loop parameters */
@ -838,26 +991,47 @@ fail:
return false;
}
bool
aot_compile_op_br_if(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 br_depth, uint8 **p_frame_ip)
static bool
aot_compile_conditional_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 br_depth, LLVMValueRef value_cmp,
uint8 **p_frame_ip)
{
AOTBlock *block_dst;
LLVMValueRef value_cmp, value, *values = NULL;
LLVMValueRef value, *values = NULL;
LLVMBasicBlockRef llvm_else_block, next_llvm_end_block;
char name[32];
uint32 i, param_index, result_index;
uint64 size;
#if WASM_ENABLE_THREAD_MGR != 0
/* Insert suspend check point */
if (comp_ctx->enable_thread_mgr) {
if (!check_suspend_flags(comp_ctx, func_ctx))
if (!(block_dst = get_target_block(func_ctx, br_depth))) {
return false;
}
if (comp_ctx->aot_frame) {
if (comp_ctx->enable_gc && !aot_gen_commit_values(comp_ctx->aot_frame))
return false;
if (block_dst->label_type == LABEL_TYPE_LOOP) {
if (comp_ctx->enable_thread_mgr) {
/* Commit sp when GC is enabled, don't commit ip */
if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame,
comp_ctx->enable_gc, false))
return false;
}
}
else {
if (comp_ctx->aot_frame->sp > block_dst->frame_sp_max_reached)
block_dst->frame_sp_max_reached = comp_ctx->aot_frame->sp;
}
}
/* Terminate or suspend current thread only when this is
a backward jump */
if (comp_ctx->enable_thread_mgr
&& block_dst->label_type == LABEL_TYPE_LOOP) {
if (!check_suspend_flags(comp_ctx, func_ctx, true))
return false;
}
#endif
POP_COND(value_cmp);
if (LLVMIsUndef(value_cmp)
#if LLVM_VERSION_NUMBER >= 12
@ -873,9 +1047,6 @@ aot_compile_op_br_if(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
if (!LLVMIsEfficientConstInt(value_cmp)) {
/* Compare value is not constant, create condition br IR */
if (!(block_dst = get_target_block(func_ctx, br_depth))) {
return false;
}
/* Create llvm else block */
CREATE_BLOCK(llvm_else_block, "br_if_else");
@ -972,6 +1143,20 @@ fail:
return false;
}
bool
aot_compile_op_br_if(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 br_depth, uint8 **p_frame_ip)
{
LLVMValueRef value_cmp;
POP_COND(value_cmp);
return aot_compile_conditional_br(comp_ctx, func_ctx, br_depth, value_cmp,
p_frame_ip);
fail:
return false;
}
bool
aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 *br_depths, uint32 br_count, uint8 **p_frame_ip)
@ -986,14 +1171,6 @@ aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint64 size;
char name[32];
#if WASM_ENABLE_THREAD_MGR != 0
/* Insert suspend check point */
if (comp_ctx->enable_thread_mgr) {
if (!check_suspend_flags(comp_ctx, func_ctx))
return false;
}
#endif
POP_I32(value_cmp);
if (LLVMIsUndef(value_cmp)
@ -1009,6 +1186,46 @@ aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
}
if (!LLVMIsEfficientConstInt(value_cmp)) {
if (comp_ctx->aot_frame) {
if (comp_ctx->enable_gc
&& !aot_gen_commit_values(comp_ctx->aot_frame))
return false;
if (comp_ctx->enable_thread_mgr) {
/* Commit sp when GC is enabled, don't commit ip */
if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame,
comp_ctx->enable_gc, false))
return false;
}
for (i = 0; i <= br_count; i++) {
target_block = get_target_block(func_ctx, br_depths[i]);
if (!target_block)
return false;
if (target_block->label_type != LABEL_TYPE_LOOP) {
if (comp_ctx->aot_frame->sp
> target_block->frame_sp_max_reached)
target_block->frame_sp_max_reached =
comp_ctx->aot_frame->sp;
}
}
}
if (comp_ctx->enable_thread_mgr) {
for (i = 0; i <= br_count; i++) {
target_block = get_target_block(func_ctx, br_depths[i]);
if (!target_block)
return false;
/* Terminate or suspend current thread only when this is a
backward jump */
if (target_block->label_type == LABEL_TYPE_LOOP) {
if (!check_suspend_flags(comp_ctx, func_ctx, true))
return false;
break;
}
}
}
/* Compare value is not constant, create switch IR */
for (i = 0; i <= br_count; i++) {
target_block = get_target_block(func_ctx, br_depths[i]);
@ -1137,6 +1354,7 @@ aot_compile_op_return(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
comp_ctx, func_ctx,
(*p_frame_ip - 1) - comp_ctx->comp_data->wasm_module->buf_code);
#endif
if (block_func->result_count) {
/* Store extra result values to function parameters */
for (i = 0; i < block_func->result_count - 1; i++) {
@ -1194,3 +1412,284 @@ aot_handle_next_reachable_block(AOTCompContext *comp_ctx,
{
return handle_next_reachable_block(comp_ctx, func_ctx, p_frame_ip);
}
#if WASM_ENABLE_GC != 0
static bool
commit_gc_and_check_suspend_flags(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx, uint32 br_depth)
{
AOTBlock *block_dst;
if (!(block_dst = get_target_block(func_ctx, br_depth))) {
return false;
}
if (comp_ctx->aot_frame) {
/* Note that GC is enabled, no need to check it again */
if (!aot_gen_commit_values(comp_ctx->aot_frame))
return false;
if (block_dst->label_type == LABEL_TYPE_LOOP) {
if (comp_ctx->enable_thread_mgr) {
/* Note that GC is enabled, no need to check it again */
if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, true, false))
return false;
}
}
else {
if (comp_ctx->aot_frame->sp > block_dst->frame_sp_max_reached)
block_dst->frame_sp_max_reached = comp_ctx->aot_frame->sp;
}
}
/* Terminate or suspend current thread only when this is
a backward jump */
if (comp_ctx->enable_thread_mgr
&& block_dst->label_type == LABEL_TYPE_LOOP) {
if (!check_suspend_flags(comp_ctx, func_ctx, true))
return false;
}
return true;
}
static bool
compile_gc_cond_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 br_depth, LLVMValueRef value_cmp)
{
AOTBlock *block_dst;
LLVMValueRef value, *values = NULL;
LLVMBasicBlockRef llvm_else_block, next_llvm_end_block;
char name[32];
uint32 i, param_index, result_index;
uint64 size;
if (!(block_dst = get_target_block(func_ctx, br_depth))) {
return false;
}
/* Create llvm else block */
CREATE_BLOCK(llvm_else_block, "br_if_else");
MOVE_BLOCK_AFTER_CURR(llvm_else_block);
if (block_dst->label_type == LABEL_TYPE_LOOP) {
/* Dest block is Loop block */
/* Handle Loop parameters */
if (block_dst->param_count) {
size = sizeof(LLVMValueRef) * (uint64)block_dst->param_count;
if (size >= UINT32_MAX
|| !(values = wasm_runtime_malloc((uint32)size))) {
aot_set_last_error("allocate memory failed.");
goto fail;
}
for (i = 0; i < block_dst->param_count; i++) {
param_index = block_dst->param_count - 1 - i;
POP(value, block_dst->param_types[param_index]);
ADD_TO_PARAM_PHIS(block_dst, value, param_index);
values[param_index] = value;
}
for (i = 0; i < block_dst->param_count; i++) {
PUSH(values[i], block_dst->param_types[i]);
}
wasm_runtime_free(values);
values = NULL;
}
BUILD_COND_BR(value_cmp, block_dst->llvm_entry_block, llvm_else_block);
/* Move builder to else block */
SET_BUILDER_POS(llvm_else_block);
}
else {
/* Dest block is Block/If/Function block */
/* Create the end block */
if (!block_dst->llvm_end_block) {
format_block_name(name, sizeof(name), block_dst->block_index,
block_dst->label_type, LABEL_END);
CREATE_BLOCK(block_dst->llvm_end_block, name);
if ((next_llvm_end_block = find_next_llvm_end_block(block_dst)))
MOVE_BLOCK_BEFORE(block_dst->llvm_end_block,
next_llvm_end_block);
}
/* Set reachable flag and create condition br IR */
block_dst->is_reachable = true;
/* Handle result values */
if (block_dst->result_count) {
size = sizeof(LLVMValueRef) * (uint64)block_dst->result_count;
if (size >= UINT32_MAX
|| !(values = wasm_runtime_malloc((uint32)size))) {
aot_set_last_error("allocate memory failed.");
goto fail;
}
CREATE_RESULT_VALUE_PHIS(block_dst);
for (i = 0; i < block_dst->result_count; i++) {
result_index = block_dst->result_count - 1 - i;
POP(value, block_dst->result_types[result_index]);
values[result_index] = value;
ADD_TO_RESULT_PHIS(block_dst, value, result_index);
}
for (i = 0; i < block_dst->result_count; i++) {
PUSH(values[i], block_dst->result_types[i]);
}
wasm_runtime_free(values);
values = NULL;
}
/* Condition jump to end block */
BUILD_COND_BR(value_cmp, block_dst->llvm_end_block, llvm_else_block);
/* Move builder to else block */
SET_BUILDER_POS(llvm_else_block);
}
return true;
fail:
if (values)
wasm_runtime_free(values);
return false;
}
bool
aot_compile_op_br_on_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 br_depth, uint8 **p_frame_ip)
{
LLVMValueRef gc_obj, value_cmp;
if (!commit_gc_and_check_suspend_flags(comp_ctx, func_ctx, br_depth)) {
return false;
}
POP_GC_REF(gc_obj);
if (!(value_cmp =
LLVMBuildIsNull(comp_ctx->builder, gc_obj, "cmp_gc_obj"))) {
aot_set_last_error("llvm build isnull failed.");
goto fail;
}
if (!compile_gc_cond_br(comp_ctx, func_ctx, br_depth, value_cmp)) {
goto fail;
}
PUSH_GC_REF(gc_obj);
return true;
fail:
return false;
}
bool
aot_compile_op_br_on_non_null(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx, uint32 br_depth,
uint8 **p_frame_ip)
{
LLVMValueRef gc_obj, value_cmp;
if (!commit_gc_and_check_suspend_flags(comp_ctx, func_ctx, br_depth)) {
return false;
}
GET_GC_REF_FROM_STACK(gc_obj);
if (!(value_cmp =
LLVMBuildIsNotNull(comp_ctx->builder, gc_obj, "cmp_gc_obj"))) {
aot_set_last_error("llvm build isnotnull failed.");
goto fail;
}
if (!compile_gc_cond_br(comp_ctx, func_ctx, br_depth, value_cmp)) {
goto fail;
}
POP_GC_REF(gc_obj);
return true;
fail:
return false;
}
bool
aot_compile_op_br_on_cast(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
int32 heap_type, bool nullable, bool br_on_fail,
uint32 br_depth, uint8 **p_frame_ip)
{
LLVMValueRef gc_obj, is_null, castable, not_castable, br_if_phi;
LLVMBasicBlockRef block_curr, block_non_null, block_br_if;
if (!commit_gc_and_check_suspend_flags(comp_ctx, func_ctx, br_depth)) {
return false;
}
GET_GC_REF_FROM_STACK(gc_obj);
block_curr = CURR_BLOCK();
CREATE_BLOCK(block_non_null, "obj_non_null");
MOVE_BLOCK_AFTER_CURR(block_non_null);
CREATE_BLOCK(block_br_if, "br_if");
MOVE_BLOCK_AFTER(block_br_if, block_non_null);
SET_BUILDER_POS(block_br_if);
if (!(br_if_phi =
LLVMBuildPhi(comp_ctx->builder, INT1_TYPE, "br_if_phi"))) {
aot_set_last_error("llvm build phi failed.");
goto fail;
}
SET_BUILDER_POS(block_curr);
if (!(is_null = LLVMBuildIsNull(comp_ctx->builder, gc_obj, "is_null"))) {
aot_set_last_error("llvm build isnull failed.");
goto fail;
}
BUILD_COND_BR(is_null, block_br_if, block_non_null);
if ((!br_on_fail && nullable) || (br_on_fail && !nullable)) {
LLVMAddIncoming(br_if_phi, &I1_ONE, &block_curr, 1);
}
else { /* (!br_on_fail && !nullable) || (br_on_fail && nullable)) */
LLVMAddIncoming(br_if_phi, &I1_ZERO, &block_curr, 1);
}
SET_BUILDER_POS(block_non_null);
if (heap_type >= 0) {
if (!aot_call_aot_obj_is_instance_of(comp_ctx, func_ctx, gc_obj,
I32_CONST(heap_type), &castable))
goto fail;
}
else {
if (!aot_call_wasm_obj_is_type_of(comp_ctx, func_ctx, gc_obj,
I32_CONST(heap_type), &castable))
goto fail;
}
if (!br_on_fail) {
if (!(castable = LLVMBuildICmp(comp_ctx->builder, LLVMIntNE, castable,
I8_ZERO, "castable"))) {
aot_set_last_error("llvm build icmp failed.");
return false;
}
LLVMAddIncoming(br_if_phi, &castable, &block_non_null, 1);
}
else {
if (!(not_castable = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ,
castable, I8_ZERO, "castable"))) {
aot_set_last_error("llvm build icmp failed.");
return false;
}
LLVMAddIncoming(br_if_phi, &not_castable, &block_non_null, 1);
}
BUILD_BR(block_br_if);
SET_BUILDER_POS(block_br_if);
if (!compile_gc_cond_br(comp_ctx, func_ctx, br_depth, br_if_phi)) {
goto fail;
}
return true;
fail:
return false;
}
#endif /* End of WASM_ENABLE_GC != 0 */

View File

@ -50,9 +50,25 @@ bool
aot_handle_next_reachable_block(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx, uint8 **p_frame_ip);
#if WASM_ENABLE_THREAD_MGR != 0
bool
check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
bool check_terminate_and_suspend);
#if WASM_ENABLE_GC != 0
bool
aot_compile_op_br_on_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 br_depth, uint8 **p_frame_ip);
bool
aot_compile_op_br_on_non_null(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx, uint32 br_depth,
uint8 **p_frame_ip);
bool
aot_compile_op_br_on_cast(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
int32 heap_type, bool nullable, bool br_on_fail,
uint32 br_depth, uint8 **p_frame_ip);
#endif
#ifdef __cplusplus

View File

@ -7,6 +7,46 @@
#include "../interpreter/wasm_runtime.h"
#include "../aot/aot_runtime.h"
static bool
commit_ip(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMValueRef exce_ip, bool is_64bit)
{
LLVMValueRef cur_frame = func_ctx->cur_frame;
LLVMValueRef value_offset, value_addr, value_ptr;
uint32 offset_ip;
if (!comp_ctx->is_jit_mode)
offset_ip = comp_ctx->pointer_size * 4;
else
offset_ip = offsetof(WASMInterpFrame, ip);
if (!(value_offset = I32_CONST(offset_ip))) {
aot_set_last_error("llvm build const failed");
return false;
}
if (!(value_addr =
LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, cur_frame,
&value_offset, 1, "ip_addr"))) {
aot_set_last_error("llvm build in bounds gep failed");
return false;
}
if (!(value_ptr = LLVMBuildBitCast(
comp_ctx->builder, value_addr,
is_64bit ? INT64_PTR_TYPE : INT32_PTR_TYPE, "ip_ptr"))) {
aot_set_last_error("llvm build bit cast failed");
return false;
}
if (!LLVMBuildStore(comp_ctx->builder, exce_ip, value_ptr)) {
aot_set_last_error("llvm build store failed");
return false;
}
return true;
}
bool
aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
int32 exception_id, bool is_cond_br, LLVMValueRef cond_br_if,
@ -16,6 +56,7 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMValueRef exce_id = I32_CONST((uint32)exception_id), func_const, func;
LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
LLVMValueRef param_values[2];
bool is_64bit = (comp_ctx->pointer_size == sizeof(uint64)) ? true : false;
bh_assert(exception_id >= 0 && exception_id < EXCE_NUM);
@ -32,13 +73,23 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMPositionBuilderAtEnd(comp_ctx->builder,
func_ctx->got_exception_block);
/* Create exection id phi */
/* Create exception id phi */
if (!(func_ctx->exception_id_phi = LLVMBuildPhi(
comp_ctx->builder, I32_TYPE, "exception_id_phi"))) {
aot_set_last_error("llvm build phi failed.");
return false;
}
if (comp_ctx->aot_frame) {
/* Create exception ip phi */
if (!(func_ctx->exception_ip_phi = LLVMBuildPhi(
comp_ctx->builder, is_64bit ? I64_TYPE : I32_TYPE,
"exception_ip_phi"))) {
aot_set_last_error("llvm build phi failed.");
return false;
}
}
/* Call aot_set_exception_with_id() to throw exception */
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
@ -103,6 +154,12 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
return false;
}
if (comp_ctx->aot_frame) {
if (!commit_ip(comp_ctx, func_ctx, func_ctx->exception_ip_phi,
is_64bit))
return false;
}
/* Create return IR */
AOTFuncType *aot_func_type = func_ctx->aot_func->func_type;
if (!aot_build_zero_function_ret(comp_ctx, func_ctx, aot_func_type)) {
@ -116,6 +173,35 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
/* Add phi incoming value to got_exception block */
LLVMAddIncoming(func_ctx->exception_id_phi, &exce_id, &block_curr, 1);
if (comp_ctx->aot_frame) {
const uint8 *ip = comp_ctx->aot_frame->frame_ip;
LLVMValueRef exce_ip = NULL;
if (!comp_ctx->is_jit_mode) {
WASMModule *module = comp_ctx->comp_data->wasm_module;
if (is_64bit)
exce_ip =
I64_CONST((uint64)(uintptr_t)(ip - module->load_addr));
else
exce_ip =
I32_CONST((uint32)(uintptr_t)(ip - module->load_addr));
}
else {
if (is_64bit)
exce_ip = I64_CONST((uint64)(uintptr_t)ip);
else
exce_ip = I32_CONST((uint32)(uintptr_t)ip);
}
if (!exce_ip) {
aot_set_last_error("llvm build const failed");
return false;
}
/* Add phi incoming value to got_exception block */
LLVMAddIncoming(func_ctx->exception_ip_phi, &exce_ip, &block_curr, 1);
}
if (!is_cond_br) {
/* not condition br, create br IR */
if (!LLVMBuildBr(comp_ctx->builder, func_ctx->got_exception_block)) {

File diff suppressed because it is too large Load Diff

View File

@ -30,6 +30,12 @@ bool
aot_compile_op_ref_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 func_idx);
#if WASM_ENABLE_GC != 0
bool
aot_compile_op_call_ref(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 type_idx, bool tail_call);
#endif
#ifdef __cplusplus
} /* end of extern "C" */
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,119 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _AOT_EMIT_GC_H_
#define _AOT_EMIT_GC_H_
#include "aot_compiler.h"
#include "aot_runtime.h"
#ifdef __cplusplus
extern "C" {
#endif
#if WASM_ENABLE_GC != 0
bool
aot_call_aot_create_func_obj(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMValueRef func_idx, LLVMValueRef *p_gc_obj);
bool
aot_call_aot_obj_is_instance_of(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx, LLVMValueRef gc_obj,
LLVMValueRef heap_type, LLVMValueRef *castable);
bool
aot_call_wasm_obj_is_type_of(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMValueRef gc_obj, LLVMValueRef heap_type,
LLVMValueRef *castable);
bool
aot_call_aot_rtt_type_new(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMValueRef type_index, LLVMValueRef *rtt_type);
bool
aot_compile_op_ref_as_non_null(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_op_struct_new(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 type_index, bool init_with_default);
bool
aot_compile_op_struct_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 type_index, uint32 field_idx, bool sign);
bool
aot_compile_op_struct_set(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 type_index, uint32 field_idx);
bool
aot_compile_op_array_new(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 type_index, bool init_with_default,
bool fixed_size, uint32 array_len);
bool
aot_compile_op_array_new_data(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx, uint32 type_index,
uint32 data_seg_index);
bool
aot_array_obj_length(AOTCompContext *comp_ctx, LLVMValueRef array_obj,
LLVMValueRef *p_array_len);
bool
aot_array_obj_elem_addr(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMValueRef array_obj, LLVMValueRef elem_idx,
LLVMValueRef *p_elem_data, uint8 array_elem_type);
bool
aot_compile_op_array_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 type_index, bool sign);
bool
aot_compile_op_array_set(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 type_index);
bool
aot_compile_op_array_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 type_index);
bool
aot_compile_op_array_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 type_index, uint32 src_type_index);
bool
aot_compile_op_array_len(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_op_i31_new(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_op_i31_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
bool sign);
bool
aot_compile_op_ref_test(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
int32 heap_type, bool nullable);
bool
aot_compile_op_ref_cast(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
int32 heap_type, bool nullable);
bool
aot_compile_op_extern_internalize(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_op_extern_externalize(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
#endif
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif /* end of _AOT_EMIT_GC_H_ */

View File

@ -338,7 +338,7 @@ fail:
} \
} while (0)
#if WASM_ENABLE_SHARED_MEMORY != 0
#if WASM_ENABLE_SHARED_MEMORY != 0 || WASM_ENABLE_STRINGREF != 0
bool
check_memory_alignment(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMValueRef addr, uint32 align)
@ -376,7 +376,9 @@ check_memory_alignment(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
fail:
return false;
}
#endif /* WASM_ENABLE_SHARED_MEMORY != 0 || WASM_ENABLE_STRINGREF != 0 */
#if WASM_ENABLE_SHARED_MEMORY != 0
#define BUILD_ATOMIC_LOAD(align, data_type) \
do { \
if (!(check_memory_alignment(comp_ctx, func_ctx, maddr, align))) { \
@ -874,9 +876,8 @@ fail:
return false;
}
#if WASM_ENABLE_BULK_MEMORY != 0
static LLVMValueRef
#if WASM_ENABLE_BULK_MEMORY != 0 || WASM_ENABLE_STRINGREF != 0
LLVMValueRef
check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMValueRef offset, LLVMValueRef bytes)
{
@ -971,7 +972,9 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
fail:
return NULL;
}
#endif /* end of WASM_ENABLE_BULK_MEMORY != 0 or WASM_ENABLE_STRINGREF != 0 */
#if WASM_ENABLE_BULK_MEMORY != 0
bool
aot_compile_op_memory_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 seg_index)
@ -1501,13 +1504,11 @@ aot_compile_op_atomic_wait(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
PUSH_I32(ret_value);
#if WASM_ENABLE_THREAD_MGR != 0
/* Insert suspend check point */
if (comp_ctx->enable_thread_mgr) {
if (!check_suspend_flags(comp_ctx, func_ctx))
if (!check_suspend_flags(comp_ctx, func_ctx, false))
return false;
}
#endif
return true;
fail:

View File

@ -61,6 +61,14 @@ aot_compile_op_memory_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
check_memory_alignment(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMValueRef addr, uint32 align);
LLVMValueRef
check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMValueRef offset, LLVMValueRef bytes);
#if WASM_ENABLE_BULK_MEMORY != 0
bool
aot_compile_op_memory_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,

View File

@ -21,8 +21,8 @@ pop_value_from_wasm_stack(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
return false;
}
aot_value =
aot_value_stack_pop(&func_ctx->block_stack.block_list_end->value_stack);
aot_value = aot_value_stack_pop(
comp_ctx, &func_ctx->block_stack.block_list_end->value_stack);
type = aot_value->type;
if (aot_value->type == VALUE_TYPE_I1) {
@ -44,19 +44,34 @@ pop_value_from_wasm_stack(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
wasm_runtime_free(aot_value);
/* is_32: i32, f32, ref.func, ref.extern, v128 */
if (is_32
&& !(type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32
|| type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF
|| type == VALUE_TYPE_V128)) {
aot_set_last_error("invalid WASM stack data type.");
return false;
if (is_32) {
/* is_32: i32, f32, ref.func, ref.extern, v128,
or GC ref types */
if (!(type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32
|| type == VALUE_TYPE_V128
|| (comp_ctx->enable_ref_types
&& (type == VALUE_TYPE_FUNCREF
|| type == VALUE_TYPE_EXTERNREF))
#if WASM_ENABLE_GC != 0
|| (comp_ctx->enable_gc && type == VALUE_TYPE_GC_REF)
#endif
)) {
aot_set_last_error("invalid WASM stack data type.");
return false;
}
}
/* !is_32: i64, f64 */
if (!is_32 && !(type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64)) {
aot_set_last_error("invalid WASM stack data type.");
return false;
else {
/* !is_32: i64, f64, or GC ref types */
if (!(type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64
#if WASM_ENABLE_GC != 0
|| (comp_ctx->enable_gc && type == VALUE_TYPE_GC_REF)
/* may be i32 which denotes funcref/externref */
|| (!comp_ctx->enable_gc && type == VALUE_TYPE_I32)
#endif
)) {
aot_set_last_error("invalid WASM stack data type.");
return false;
}
}
return true;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,112 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _AOT_EMIT_STRINGREF_H_
#define _AOT_EMIT_STRINGREF_H_
#include "aot_compiler.h"
#ifdef __cplusplus
extern "C" {
#endif
bool
aot_compile_op_string_new(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 encoding);
bool
aot_compile_op_string_const(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 contents);
bool
aot_compile_op_string_measure(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx, uint32 encoding);
bool
aot_compile_op_string_encode(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 mem_idx, uint32 encoding);
bool
aot_compile_op_string_concat(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_op_string_eq(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_op_string_is_usv_sequence(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_op_string_as_wtf8(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_op_stringview_wtf8_advance(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_op_stringview_wtf8_encode(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx, uint32 mem_idx,
uint32 encoding);
bool
aot_compile_op_stringview_wtf8_slice(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_op_string_as_wtf16(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_op_stringview_wtf16_length(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_op_stringview_wtf16_get_codeunit(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_op_stringview_wtf16_encode(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 mem_idx);
bool
aot_compile_op_stringview_wtf16_slice(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_op_string_as_iter(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_op_stringview_iter_next(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_op_stringview_iter_advance(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_op_stringview_iter_rewind(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_op_stringview_iter_slice(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
bool
aot_compile_op_string_new_array(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx, uint32 encoding);
bool
aot_compile_op_string_encode_array(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx, uint32 encoding);
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif /* end of _AOT_EMIT_STRINGREF_H_ */

View File

@ -6,6 +6,9 @@
#include "aot_emit_table.h"
#include "aot_emit_exception.h"
#include "../aot/aot_runtime.h"
#if WASM_ENABLE_GC != 0
#include "aot_emit_gc.h"
#endif
uint64
get_tbl_inst_offset(const AOTCompContext *comp_ctx,
@ -18,13 +21,16 @@ get_tbl_inst_offset(const AOTCompContext *comp_ctx,
offset =
offsetof(AOTModuleInstance, global_table_data.bytes)
+ (uint64)comp_ctx->comp_data->memory_count * sizeof(AOTMemoryInstance)
+ comp_ctx->comp_data->global_data_size;
/* Get global data size according to target info */
+ (comp_ctx->pointer_size == sizeof(uint64)
? comp_ctx->comp_data->global_data_size_64bit
: comp_ctx->comp_data->global_data_size_32bit);
while (i < tbl_idx && i < comp_ctx->comp_data->import_table_count) {
offset += offsetof(AOTTableInstance, elems);
/* avoid loading from current AOTTableInstance */
offset +=
sizeof(uint32)
(uint64)comp_ctx->pointer_size
* aot_get_imp_tbl_data_slots(imp_tbls + i, comp_ctx->is_jit_mode);
++i;
}
@ -38,7 +44,7 @@ get_tbl_inst_offset(const AOTCompContext *comp_ctx,
while (i < tbl_idx && i < comp_ctx->comp_data->table_count) {
offset += offsetof(AOTTableInstance, elems);
/* avoid loading from current AOTTableInstance */
offset += sizeof(uint32)
offset += (uint64)comp_ctx->pointer_size
* aot_get_tbl_data_slots(tbls + i, comp_ctx->is_jit_mode);
++i;
}
@ -58,7 +64,7 @@ get_module_inst_extra_offset(AOTCompContext *comp_ctx)
return offset_32;
}
#if WASM_ENABLE_REF_TYPES != 0
#if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0
LLVMValueRef
aot_compile_get_tbl_inst(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
@ -183,7 +189,8 @@ bool
aot_compile_op_table_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMValueRef elem_idx, offset, table_elem, func_idx;
LLVMValueRef elem_idx, offset, func_idx;
LLVMValueRef table_elem_base, table_elem_addr, table_elem;
POP_I32(elem_idx);
@ -198,34 +205,66 @@ aot_compile_op_table_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
goto fail;
}
if (!(table_elem = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
func_ctx->aot_inst, &offset, 1,
"table_elem_i8p"))) {
if (!(table_elem_base = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
func_ctx->aot_inst, &offset,
1, "table_elem_base_i8p"))) {
aot_set_last_error("llvm build add failed.");
goto fail;
}
if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
INT32_PTR_TYPE, "table_elem_i32p"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
/* Load function object reference or function index */
if (comp_ctx->enable_gc) {
if (!(table_elem_base =
LLVMBuildBitCast(comp_ctx->builder, table_elem_base,
GC_REF_PTR_TYPE, "table_elem_base"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
/* Load function index */
if (!(table_elem =
LLVMBuildInBoundsGEP2(comp_ctx->builder, I32_TYPE, table_elem,
&elem_idx, 1, "table_elem"))) {
HANDLE_FAILURE("LLVMBuildNUWAdd");
goto fail;
}
if (!(table_elem_addr = LLVMBuildInBoundsGEP2(
comp_ctx->builder, GC_REF_TYPE, table_elem_base, &elem_idx, 1,
"table_elem_addr"))) {
HANDLE_FAILURE("LLVMBuildNUWAdd");
goto fail;
}
if (!(func_idx = LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, table_elem,
"func_idx"))) {
HANDLE_FAILURE("LLVMBuildLoad");
goto fail;
}
if (!(table_elem = LLVMBuildLoad2(comp_ctx->builder, GC_REF_TYPE,
table_elem_addr, "table_elem"))) {
HANDLE_FAILURE("LLVMBuildLoad");
goto fail;
}
PUSH_I32(func_idx);
PUSH_GC_REF(table_elem);
}
else {
if (!(table_elem_base =
LLVMBuildBitCast(comp_ctx->builder, table_elem_base,
INTPTR_T_PTR_TYPE, "table_elem_base"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
if (!(table_elem_addr = LLVMBuildInBoundsGEP2(
comp_ctx->builder, INTPTR_T_TYPE, table_elem_base, &elem_idx,
1, "table_elem_addr"))) {
HANDLE_FAILURE("LLVMBuildNUWAdd");
goto fail;
}
if (!(table_elem = LLVMBuildLoad2(comp_ctx->builder, INTPTR_T_TYPE,
table_elem_addr, "table_elem"))) {
HANDLE_FAILURE("LLVMBuildLoad");
goto fail;
}
if (!(func_idx = LLVMBuildIntCast2(comp_ctx->builder, table_elem,
I32_TYPE, true, "func_idx"))) {
HANDLE_FAILURE("LLVMBuildIntCast");
goto fail;
}
PUSH_I32(func_idx);
}
return true;
fail:
@ -236,44 +275,72 @@ bool
aot_compile_op_table_set(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMValueRef val, elem_idx, offset, table_elem;
LLVMValueRef val = NULL, elem_idx, offset, table_elem_base, table_elem_addr;
if (comp_ctx->enable_gc)
POP_GC_REF(val);
else {
POP_I32(val);
if (!(val = LLVMBuildIntCast2(comp_ctx->builder, val, INTPTR_T_TYPE,
true, "val_intptr_t"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
}
POP_I32(val);
POP_I32(elem_idx);
if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) {
goto fail;
}
/* load data as i32* */
/* load data as gc_obj_ref* or i32* */
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
+ offsetof(AOTTableInstance, elems)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(table_elem = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
func_ctx->aot_inst, &offset, 1,
"table_elem_i8p"))) {
if (!(table_elem_base = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
func_ctx->aot_inst, &offset,
1, "table_elem_base_i8p"))) {
HANDLE_FAILURE("LLVMBuildInBoundsGEP");
goto fail;
}
if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
INT32_PTR_TYPE, "table_elem_i32p"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
if (comp_ctx->enable_gc) {
if (!(table_elem_base =
LLVMBuildBitCast(comp_ctx->builder, table_elem_base,
GC_REF_PTR_TYPE, "table_elem_base"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
if (!(table_elem_addr = LLVMBuildInBoundsGEP2(
comp_ctx->builder, GC_REF_TYPE, table_elem_base, &elem_idx, 1,
"table_elem_addr"))) {
HANDLE_FAILURE("LLVMBuildInBoundsGEP");
goto fail;
}
}
else {
if (!(table_elem_base =
LLVMBuildBitCast(comp_ctx->builder, table_elem_base,
INTPTR_T_PTR_TYPE, "table_elem_base"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
if (!(table_elem_addr = LLVMBuildInBoundsGEP2(
comp_ctx->builder, INTPTR_T_TYPE, table_elem_base, &elem_idx,
1, "table_elem_addr"))) {
HANDLE_FAILURE("LLVMBuildInBoundsGEP");
goto fail;
}
}
/* Load function index */
if (!(table_elem =
LLVMBuildInBoundsGEP2(comp_ctx->builder, I32_TYPE, table_elem,
&elem_idx, 1, "table_elem"))) {
HANDLE_FAILURE("LLVMBuildInBoundsGEP");
goto fail;
}
if (!(LLVMBuildStore(comp_ctx->builder, val, table_elem))) {
if (!(LLVMBuildStore(comp_ctx->builder, val, table_elem_addr))) {
HANDLE_FAILURE("LLVMBuildStore");
goto fail;
}
@ -434,7 +501,7 @@ aot_compile_op_table_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
param_types[2] = I32_TYPE;
param_types[3] = I32_TYPE;
param_types[3] = INT8_PTR_TYPE;
ret_type = I32_TYPE;
if (comp_ctx->is_jit_mode)
@ -452,7 +519,25 @@ aot_compile_op_table_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
/* n */
POP_I32(param_values[2]);
/* v */
POP_I32(param_values[3]);
if (comp_ctx->enable_gc) {
POP_GC_REF(param_values[3]);
if (!(param_values[3] =
LLVMBuildBitCast(comp_ctx->builder, param_values[3],
INT8_PTR_TYPE, "table_elem_i8p"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
}
else {
POP_I32(param_values[3]);
if (!(param_values[3] =
LLVMBuildIntToPtr(comp_ctx->builder, param_values[3],
INT8_PTR_TYPE, "table_elem_i8p"))) {
HANDLE_FAILURE("LLVMBuildIntToPtr");
goto fail;
}
}
if (!(ret = LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values,
4, "table_grow"))) {
@ -477,7 +562,7 @@ aot_compile_op_table_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
param_types[2] = I32_TYPE;
param_types[3] = I32_TYPE;
param_types[3] = INT8_PTR_TYPE;
param_types[4] = I32_TYPE;
ret_type = VOID_TYPE;
@ -496,7 +581,25 @@ aot_compile_op_table_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
/* n */
POP_I32(param_values[2]);
/* v */
POP_I32(param_values[3]);
if (comp_ctx->enable_gc) {
POP_GC_REF(param_values[3]);
if (!(param_values[3] =
LLVMBuildBitCast(comp_ctx->builder, param_values[3],
INT8_PTR_TYPE, "table_elem_i8p"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
}
else {
POP_I32(param_values[3]);
if (!(param_values[3] =
LLVMBuildIntToPtr(comp_ctx->builder, param_values[3],
INT8_PTR_TYPE, "table_elem_i8p"))) {
HANDLE_FAILURE("LLVMBuildIntToPtr");
goto fail;
}
}
/* i */
POP_I32(param_values[4]);
@ -512,4 +615,4 @@ fail:
return false;
}
#endif /* WASM_ENABLE_REF_TYPES != 0 */
#endif /* WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC !=0 */

View File

@ -17,13 +17,21 @@
} while (0)
static uint8
get_local_type(AOTFuncContext *func_ctx, uint32 local_idx)
get_local_type(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 local_idx)
{
AOTFunc *aot_func = func_ctx->aot_func;
uint32 param_count = aot_func->func_type->param_count;
return local_idx < param_count
? aot_func->func_type->types[local_idx]
: aot_func->local_types[local_idx - param_count];
uint8 local_type;
local_type = local_idx < param_count
? aot_func->func_type->types[local_idx]
: aot_func->local_types_wp[local_idx - param_count];
if (comp_ctx->enable_gc && aot_is_type_gc_reftype(local_type))
local_type = VALUE_TYPE_GC_REF;
return local_type;
}
bool
@ -37,7 +45,7 @@ aot_compile_op_get_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
CHECK_LOCAL(local_idx);
local_type = get_local_type(func_ctx, local_idx);
local_type = get_local_type(comp_ctx, func_ctx, local_idx);
snprintf(name, sizeof(name), "%s%d%s", "local", local_idx, "#");
if (!(value = LLVMBuildLoad2(comp_ctx->builder, TO_LLVM_TYPE(local_type),
@ -58,15 +66,56 @@ fail:
return false;
}
bool
aot_compile_op_set_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 local_idx)
static bool
aot_compile_op_set_or_tee_local(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx, uint32 local_idx,
bool is_tee_local)
{
LLVMValueRef value;
uint8 local_type;
uint32 n;
CHECK_LOCAL(local_idx);
POP(value, get_local_type(func_ctx, local_idx));
local_type = get_local_type(comp_ctx, func_ctx, local_idx);
POP(value, local_type);
if (comp_ctx->aot_frame) {
/* Get the slot index */
n = func_ctx->aot_func->local_offsets[local_idx];
bh_assert(comp_ctx->aot_frame->lp[n].type == local_type);
switch (local_type) {
case VALUE_TYPE_I32:
set_local_i32(comp_ctx->aot_frame, n, value);
break;
case VALUE_TYPE_I64:
set_local_i64(comp_ctx->aot_frame, n, value);
break;
case VALUE_TYPE_F32:
set_local_f32(comp_ctx->aot_frame, n, value);
break;
case VALUE_TYPE_F64:
set_local_f64(comp_ctx->aot_frame, n, value);
break;
case VALUE_TYPE_V128:
set_local_v128(comp_ctx->aot_frame, n, value);
break;
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
set_local_ref(comp_ctx->aot_frame, n, value, local_type);
break;
#if WASM_ENABLE_GC != 0
case VALUE_TYPE_GC_REF:
set_local_gc_ref(comp_ctx->aot_frame, n, value, local_type);
break;
#endif
default:
bh_assert(0);
break;
}
}
if (!LLVMBuildStore(comp_ctx->builder, value,
func_ctx->locals[local_idx])) {
@ -74,6 +123,10 @@ aot_compile_op_set_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
return false;
}
if (is_tee_local) {
PUSH(value, local_type);
}
aot_checked_addr_list_del(func_ctx, local_idx);
return true;
@ -81,31 +134,19 @@ fail:
return false;
}
bool
aot_compile_op_set_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 local_idx)
{
return aot_compile_op_set_or_tee_local(comp_ctx, func_ctx, local_idx,
false);
}
bool
aot_compile_op_tee_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 local_idx)
{
LLVMValueRef value;
uint8 type;
CHECK_LOCAL(local_idx);
type = get_local_type(func_ctx, local_idx);
POP(value, type);
if (!LLVMBuildStore(comp_ctx->builder, value,
func_ctx->locals[local_idx])) {
aot_set_last_error("llvm build store fail");
return false;
}
PUSH(value, type);
aot_checked_addr_list_del(func_ctx, local_idx);
return true;
fail:
return false;
return aot_compile_op_set_or_tee_local(comp_ctx, func_ctx, local_idx, true);
}
static bool
@ -127,17 +168,29 @@ compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
bh_assert(global_idx < import_global_count + comp_data->global_count);
if (global_idx < import_global_count) {
global_offset = global_base_offset
+ comp_data->import_globals[global_idx].data_offset;
global_offset =
global_base_offset
/* Get global data offset according to target info */
+ (comp_ctx->pointer_size == sizeof(uint64)
? comp_data->import_globals[global_idx].data_offset_64bit
: comp_data->import_globals[global_idx].data_offset_32bit);
global_type = comp_data->import_globals[global_idx].type;
}
else {
global_offset =
global_base_offset
+ comp_data->globals[global_idx - import_global_count].data_offset;
/* Get global data offset according to target info */
+ (comp_ctx->pointer_size == sizeof(uint64)
? comp_data->globals[global_idx - import_global_count]
.data_offset_64bit
: comp_data->globals[global_idx - import_global_count]
.data_offset_32bit);
global_type = comp_data->globals[global_idx - import_global_count].type;
}
if (comp_ctx->enable_gc && aot_is_type_gc_reftype(global_type))
global_type = VALUE_TYPE_GC_REF;
offset = I32_CONST(global_offset);
if (!(global_ptr = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
func_ctx->aot_inst, &offset, 1,
@ -150,20 +203,25 @@ compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
case VALUE_TYPE_I32:
case VALUE_TYPE_EXTERNREF:
case VALUE_TYPE_FUNCREF:
ptr_type = comp_ctx->basic_types.int32_ptr_type;
ptr_type = INT32_PTR_TYPE;
break;
case VALUE_TYPE_I64:
ptr_type = comp_ctx->basic_types.int64_ptr_type;
ptr_type = INT64_PTR_TYPE;
break;
case VALUE_TYPE_F32:
ptr_type = comp_ctx->basic_types.float32_ptr_type;
ptr_type = F32_PTR_TYPE;
break;
case VALUE_TYPE_F64:
ptr_type = comp_ctx->basic_types.float64_ptr_type;
ptr_type = F64_PTR_TYPE;
break;
case VALUE_TYPE_V128:
ptr_type = comp_ctx->basic_types.v128_ptr_type;
ptr_type = V128_PTR_TYPE;
break;
#if WASM_ENABLE_GC != 0
case VALUE_TYPE_GC_REF:
ptr_type = GC_REF_PTR_TYPE;
break;
#endif
default:
bh_assert("unknown type");
break;

View File

@ -10,6 +10,7 @@
#include "aot_emit_table.h"
#include "../aot/aot_runtime.h"
#include "../aot/aot_intrinsic.h"
#include "../interpreter/wasm_runtime.h"
#if WASM_ENABLE_DEBUG_AOT != 0
#include "debug/dwarf_extractor.h"
@ -25,13 +26,20 @@ create_native_stack_top_min(const AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
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)
{
switch (wasm_type) {
case VALUE_TYPE_I32:
return llvm_types->int32_type;
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
return llvm_types->int32_type;
if (comp_ctx->enable_ref_types)
return llvm_types->int32_type;
else {
bh_assert(comp_ctx->enable_gc);
return llvm_types->gc_ref_type;
}
case VALUE_TYPE_I64:
return llvm_types->int64_type;
case VALUE_TYPE_F32:
@ -42,9 +50,31 @@ wasm_type_to_llvm_type(const AOTLLVMTypes *llvm_types, uint8 wasm_type)
return llvm_types->i64x2_vec_type;
case VALUE_TYPE_VOID:
return llvm_types->void_type;
case REF_TYPE_NULLFUNCREF:
case REF_TYPE_NULLEXTERNREF:
case REF_TYPE_NULLREF:
/* case REF_TYPE_FUNCREF: */
/* case REF_TYPE_EXTERNREF: */
case REF_TYPE_ANYREF:
case REF_TYPE_EQREF:
case REF_TYPE_HT_NULLABLE:
case REF_TYPE_HT_NON_NULLABLE:
case REF_TYPE_I31REF:
case REF_TYPE_STRUCTREF:
case REF_TYPE_ARRAYREF:
#if WASM_ENABLE_STRINGREF != 0
case REF_TYPE_STRINGREF:
case REF_TYPE_STRINGVIEWWTF8:
case REF_TYPE_STRINGVIEWWTF16:
case REF_TYPE_STRINGVIEWITER:
#endif
case VALUE_TYPE_GC_REF:
bh_assert(comp_ctx->enable_gc);
return llvm_types->gc_ref_type;
default:
break;
}
bh_assert(0);
return NULL;
}
@ -245,18 +275,6 @@ aot_estimate_stack_usage_for_function_call(const AOTCompContext *comp_ctx,
return size;
}
static uint32
get_inst_extra_offset(AOTCompContext *comp_ctx)
{
const AOTCompData *comp_data = comp_ctx->comp_data;
uint32 table_count = comp_data->import_table_count + comp_data->table_count;
uint64 offset = get_tbl_inst_offset(comp_ctx, NULL, table_count);
uint32 offset_32 = (uint32)offset;
bh_assert(offset <= UINT32_MAX);
offset_32 = align_uint((uint32)offset_32, 8);
return offset_32;
}
/*
* a "precheck" function performs a few things before calling wrapped_func.
*
@ -353,7 +371,7 @@ aot_build_precheck_function(AOTCompContext *comp_ctx, LLVMModuleRef module,
LLVMValueRef offset;
LLVMValueRef stack_sizes_p;
offset_u32 = get_inst_extra_offset(comp_ctx);
offset_u32 = get_module_inst_extra_offset(comp_ctx);
offset_u32 += offsetof(AOTModuleInstanceExtra, stack_sizes);
offset = I32_CONST(offset_u32);
if (!offset) {
@ -552,6 +570,44 @@ fail:
return false;
}
static bool
check_wasm_type(AOTCompContext *comp_ctx, uint8 type)
{
if (type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF) {
if (!comp_ctx->enable_ref_types && !comp_ctx->enable_gc) {
aot_set_last_error("funcref or externref type was found, "
"try removing --disable-ref-types option "
"or adding --enable-gc option.");
return false;
}
else
return true;
}
else if (aot_is_type_gc_reftype(type)) {
if (!comp_ctx->enable_gc) {
aot_set_last_error("GC reference type was found, "
"try adding --enable-gc option.");
return false;
}
else
return true;
}
else if (type == VALUE_TYPE_V128) {
if (!comp_ctx->enable_simd) {
aot_set_last_error("SIMD type was found, try removing "
" --disable-simd option.");
return false;
}
return true;
}
else if (type != VALUE_TYPE_I32 && type != VALUE_TYPE_I64
&& type != VALUE_TYPE_F32 && type != VALUE_TYPE_F64) {
bh_assert(0);
}
return true;
}
/**
* Add LLVM function
*/
@ -560,6 +616,8 @@ aot_add_llvm_func(AOTCompContext *comp_ctx, LLVMModuleRef module,
const AOTFuncType *aot_func_type, uint32 func_index,
LLVMTypeRef *p_func_type, LLVMValueRef *p_precheck_func)
{
WASMFunction *aot_func =
comp_ctx->comp_data->wasm_module->functions[func_index];
LLVMValueRef func = NULL;
LLVMTypeRef *param_types, ret_type, func_type;
LLVMTypeRef func_type_wrapper;
@ -570,6 +628,18 @@ aot_add_llvm_func(AOTCompContext *comp_ctx, LLVMModuleRef module,
uint32 i, j = 0, param_count = (uint64)aot_func_type->param_count;
uint32 backend_thread_num, compile_thread_num;
/* Check function parameter types and result types */
for (i = 0; i < aot_func_type->param_count + aot_func_type->result_count;
i++) {
if (!check_wasm_type(comp_ctx, aot_func_type->types[i]))
return NULL;
}
/* Check function local types */
for (i = 0; i < aot_func->local_count; i++) {
if (!check_wasm_type(comp_ctx, aot_func->local_types[i]))
return NULL;
}
/* exec env as first parameter */
param_count++;
@ -921,6 +991,49 @@ create_aux_stack_info(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
return true;
}
static bool
create_aux_stack_frame(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
LLVMValueRef wasm_stack_top_bound_ptr, offset;
offset = I32_ONE;
if (!(func_ctx->cur_frame_ptr = LLVMBuildInBoundsGEP2(
comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->exec_env, &offset, 1,
"cur_frame_ptr"))) {
aot_set_last_error("llvm build in bounds gep failed");
return false;
}
if (!(func_ctx->cur_frame =
LLVMBuildLoad2(comp_ctx->builder, OPQ_PTR_TYPE,
func_ctx->cur_frame_ptr, "cur_frame"))) {
aot_set_last_error("llvm build load failed");
return false;
}
/* Get exec_env->wasm_stack.top_boundary and its address */
offset = I32_TEN;
if (!(wasm_stack_top_bound_ptr = LLVMBuildInBoundsGEP2(
comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->exec_env, &offset, 1,
"wasm_stack_top_bound_ptr"))
|| !(func_ctx->wasm_stack_top_bound = LLVMBuildLoad2(
comp_ctx->builder, INT8_PTR_TYPE, wasm_stack_top_bound_ptr,
"wasm_stack_top_bound"))) {
aot_set_last_error("load wasm_stack.top_boundary failed");
return false;
}
offset = I32_ELEVEN;
if (!(func_ctx->wasm_stack_top_ptr = LLVMBuildInBoundsGEP2(
comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->exec_env, &offset, 1,
"wasm_stack_top_ptr"))) {
aot_set_last_error("llvm build inbounds gep failed");
return false;
}
return true;
}
static bool
create_native_symbol(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
@ -955,7 +1068,8 @@ create_local_variables(const AOTCompData *comp_data,
const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
const AOTFunc *func)
{
AOTFuncType *aot_func_type = comp_data->func_types[func->func_type_index];
AOTFuncType *aot_func_type =
(AOTFuncType *)comp_data->types[func->func_type_index];
char local_name[32];
uint32 i, j = 1;
@ -980,14 +1094,14 @@ create_local_variables(const AOTCompData *comp_data,
LLVMValueRef local_value = NULL;
snprintf(local_name, sizeof(local_name), "l%d",
aot_func_type->param_count + i);
local_type = TO_LLVM_TYPE(func->local_types[i]);
local_type = TO_LLVM_TYPE(func->local_types_wp[i]);
func_ctx->locals[aot_func_type->param_count + i] =
LLVMBuildAlloca(comp_ctx->builder, local_type, local_name);
if (!func_ctx->locals[aot_func_type->param_count + i]) {
aot_set_last_error("llvm build alloca failed.");
return false;
}
switch (func->local_types[i]) {
switch (func->local_types_wp[i]) {
case VALUE_TYPE_I32:
local_value = I32_ZERO;
break;
@ -1005,8 +1119,33 @@ create_local_variables(const AOTCompData *comp_data,
break;
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
local_value = REF_NULL;
if (!comp_ctx->enable_gc)
local_value = REF_NULL;
else
local_value = GC_REF_NULL;
break;
#if WASM_ENABLE_GC != 0
case REF_TYPE_NULLFUNCREF:
case REF_TYPE_NULLEXTERNREF:
case REF_TYPE_NULLREF:
/* case REF_TYPE_FUNCREF: */
/* case REF_TYPE_EXTERNREF: */
case REF_TYPE_ANYREF:
case REF_TYPE_EQREF:
case REF_TYPE_HT_NULLABLE:
case REF_TYPE_HT_NON_NULLABLE:
case REF_TYPE_I31REF:
case REF_TYPE_STRUCTREF:
case REF_TYPE_ARRAYREF:
#if WASM_ENABLE_STRINGREF != 0
case REF_TYPE_STRINGREF:
case REF_TYPE_STRINGVIEWWTF8:
case REF_TYPE_STRINGVIEWWTF16:
case REF_TYPE_STRINGVIEWITER:
#endif
local_value = GC_REF_NULL;
break;
#endif
default:
bh_assert(0);
break;
@ -1539,7 +1678,8 @@ aot_create_func_context(const AOTCompData *comp_data, AOTCompContext *comp_ctx,
AOTFunc *func, uint32 func_index)
{
AOTFuncContext *func_ctx;
AOTFuncType *aot_func_type = comp_data->func_types[func->func_type_index];
AOTFuncType *aot_func_type =
(AOTFuncType *)comp_data->types[func->func_type_index];
WASMModule *module = comp_ctx->comp_data->wasm_module;
WASMFunction *wasm_func = module->functions[func_index];
AOTBlock *aot_block;
@ -1597,6 +1737,11 @@ aot_create_func_context(const AOTCompData *comp_data, AOTCompContext *comp_ctx,
goto fail;
}
if (comp_ctx->enable_aux_stack_frame
&& !create_aux_stack_frame(comp_ctx, func_ctx)) {
goto fail;
}
/* Create local variables */
if (!create_local_variables(comp_data, comp_ctx, func_ctx, func)) {
goto fail;
@ -1634,13 +1779,14 @@ aot_create_func_context(const AOTCompData *comp_data, AOTCompContext *comp_ctx,
fail:
if (func_ctx->mem_info)
wasm_runtime_free(func_ctx->mem_info);
aot_block_stack_destroy(&func_ctx->block_stack);
aot_block_stack_destroy(comp_ctx, &func_ctx->block_stack);
wasm_runtime_free(func_ctx);
return NULL;
}
static void
aot_destroy_func_contexts(AOTFuncContext **func_ctxes, uint32 count)
aot_destroy_func_contexts(AOTCompContext *comp_ctx, AOTFuncContext **func_ctxes,
uint32 count)
{
uint32 i;
@ -1648,7 +1794,7 @@ aot_destroy_func_contexts(AOTFuncContext **func_ctxes, uint32 count)
if (func_ctxes[i]) {
if (func_ctxes[i]->mem_info)
wasm_runtime_free(func_ctxes[i]->mem_info);
aot_block_stack_destroy(&func_ctxes[i]->block_stack);
aot_block_stack_destroy(comp_ctx, &func_ctxes[i]->block_stack);
aot_checked_addr_list_destroy(func_ctxes[i]);
wasm_runtime_free(func_ctxes[i]);
}
@ -1685,7 +1831,8 @@ aot_create_func_contexts(const AOTCompData *comp_data, AOTCompContext *comp_ctx)
AOTFunc *func = comp_data->funcs[i];
if (!(func_ctxes[i] =
aot_create_func_context(comp_data, comp_ctx, func, i))) {
aot_destroy_func_contexts(func_ctxes, comp_data->func_count);
aot_destroy_func_contexts(comp_ctx, func_ctxes,
comp_data->func_count);
return NULL;
}
}
@ -1694,7 +1841,8 @@ aot_create_func_contexts(const AOTCompData *comp_data, AOTCompContext *comp_ctx)
}
static bool
aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context)
aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context,
int pointer_size)
{
basic_types->int1_type = LLVMInt1TypeInContext(context);
basic_types->int8_type = LLVMInt8TypeInContext(context);
@ -1759,15 +1907,29 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context)
basic_types->funcref_type = LLVMInt32TypeInContext(context);
basic_types->externref_type = LLVMInt32TypeInContext(context);
if (pointer_size == 4) {
basic_types->intptr_t_type = basic_types->int32_type;
basic_types->intptr_t_ptr_type = basic_types->int32_ptr_type;
}
else {
basic_types->intptr_t_type = basic_types->int64_type;
basic_types->intptr_t_ptr_type = basic_types->int64_ptr_type;
}
basic_types->gc_ref_type = LLVMPointerType(basic_types->void_type, 0);
basic_types->gc_ref_ptr_type = LLVMPointerType(basic_types->gc_ref_type, 0);
return (basic_types->int8_ptr_type && basic_types->int8_pptr_type
&& basic_types->int16_ptr_type && basic_types->int32_ptr_type
&& basic_types->int64_ptr_type && basic_types->float32_ptr_type
&& basic_types->int64_ptr_type && basic_types->intptr_t_type
&& basic_types->intptr_t_ptr_type && basic_types->float32_ptr_type
&& basic_types->float64_ptr_type && basic_types->i8x16_vec_type
&& basic_types->i16x8_vec_type && basic_types->i32x4_vec_type
&& basic_types->i64x2_vec_type && basic_types->f32x4_vec_type
&& basic_types->f64x2_vec_type && basic_types->i1x2_vec_type
&& basic_types->meta_data_type && basic_types->funcref_type
&& basic_types->externref_type)
&& basic_types->externref_type && basic_types->gc_ref_type
&& basic_types->gc_ref_ptr_type)
? true
: false;
}
@ -1787,6 +1949,9 @@ aot_create_llvm_consts(AOTLLVMConsts *consts, AOTCompContext *comp_ctx)
if (!(consts->i8_zero = I8_CONST(0)))
return false;
if (!(consts->i8_one = I8_CONST(1)))
return false;
if (!(consts->f32_zero = F32_CONST(0)))
return false;
@ -1857,6 +2022,13 @@ aot_create_llvm_consts(AOTLLVMConsts *consts, AOTCompContext *comp_ctx)
CREATE_VEC_ZERO_MASK(2)
#undef CREATE_VEC_ZERO_MASK
if (!(consts->gc_ref_null =
LLVMConstNull(comp_ctx->basic_types.gc_ref_type)))
return false;
if (!(consts->i8_ptr_null =
LLVMConstNull(comp_ctx->basic_types.int8_ptr_type)))
return false;
return true;
}
@ -2369,6 +2541,12 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
if (option->enable_aux_stack_frame)
comp_ctx->enable_aux_stack_frame = true;
if (option->enable_perf_profiling)
comp_ctx->enable_perf_profiling = true;
if (option->enable_memory_profiling)
comp_ctx->enable_memory_profiling = true;
if (option->enable_aux_stack_check)
comp_ctx->enable_aux_stack_check = true;
@ -2399,6 +2577,9 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
if (option->builtin_intrinsics)
comp_ctx->builtin_intrinsics = option->builtin_intrinsics;
if (option->enable_gc)
comp_ctx->enable_gc = true;
comp_ctx->opt_level = option->opt_level;
comp_ctx->size_level = option->size_level;
@ -2885,6 +3066,29 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
}
LLVMDisposeMessage(triple);
#if WASM_ENABLE_WAMR_COMPILER != 0
WASMModule *wasm_module = (WASMModule *)comp_data->wasm_module;
/* Return error if SIMD is disabled by command line but SIMD instructions
* are used */
if (!option->enable_simd && wasm_module->is_simd_used) {
aot_set_last_error("SIMD is disabled by --disable-simd but SIMD "
"instructions are used in this module");
goto fail;
}
/* Disable features when they are not actually used */
if (!wasm_module->is_simd_used) {
option->enable_simd = comp_ctx->enable_simd = false;
}
if (!wasm_module->is_ref_types_used) {
option->enable_ref_types = comp_ctx->enable_ref_types = false;
}
if (!wasm_module->is_bulk_memory_used) {
option->enable_bulk_memory = comp_ctx->enable_bulk_memory = false;
}
#endif
if (option->enable_simd && strcmp(comp_ctx->target_arch, "x86_64") != 0
&& strncmp(comp_ctx->target_arch, "aarch64", 7) != 0) {
/* Disable simd if it isn't supported by target arch */
@ -2935,7 +3139,8 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
goto fail;
}
if (!aot_set_llvm_basic_types(&comp_ctx->basic_types, comp_ctx->context)) {
if (!aot_set_llvm_basic_types(&comp_ctx->basic_types, comp_ctx->context,
comp_ctx->pointer_size)) {
aot_set_last_error("create LLVM basic types failed.");
goto fail;
}
@ -3013,7 +3218,7 @@ aot_destroy_comp_context(AOTCompContext *comp_ctx)
LLVMOrcDisposeLLLazyJIT(comp_ctx->orc_jit);
if (comp_ctx->func_ctxes)
aot_destroy_func_contexts(comp_ctx->func_ctxes,
aot_destroy_func_contexts(comp_ctx, comp_ctx->func_ctxes,
comp_ctx->func_ctx_count);
if (bh_list_length(&comp_ctx->native_symbols) > 0) {
@ -3030,6 +3235,10 @@ aot_destroy_comp_context(AOTCompContext *comp_ctx)
wasm_runtime_free(comp_ctx->target_cpu);
}
if (comp_ctx->aot_frame) {
wasm_runtime_free(comp_ctx->aot_frame);
}
wasm_runtime_free(comp_ctx);
}
@ -3108,7 +3317,8 @@ aot_get_native_symbol_index(AOTCompContext *comp_ctx, const char *symbol)
}
void
aot_value_stack_push(AOTValueStack *stack, AOTValue *value)
aot_value_stack_push(const AOTCompContext *comp_ctx, AOTValueStack *stack,
AOTValue *value)
{
if (!stack->value_list_head)
stack->value_list_head = stack->value_list_end = value;
@ -3117,10 +3327,44 @@ aot_value_stack_push(AOTValueStack *stack, AOTValue *value)
value->prev = stack->value_list_end;
stack->value_list_end = value;
}
if (comp_ctx->aot_frame) {
switch (value->type) {
case VALUE_TYPE_I32:
case VALUE_TYPE_I1:
push_i32(comp_ctx->aot_frame, value);
break;
case VALUE_TYPE_I64:
push_i64(comp_ctx->aot_frame, value);
break;
case VALUE_TYPE_F32:
push_f32(comp_ctx->aot_frame, value);
break;
case VALUE_TYPE_F64:
push_f64(comp_ctx->aot_frame, value);
break;
case VALUE_TYPE_V128:
push_v128(comp_ctx->aot_frame, value);
break;
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
push_ref(comp_ctx->aot_frame, value);
break;
#if WASM_ENABLE_GC != 0
case VALUE_TYPE_GC_REF:
bh_assert(comp_ctx->enable_gc);
push_gc_ref(comp_ctx->aot_frame, value);
break;
#endif
default:
bh_assert(0);
break;
}
}
}
AOTValue *
aot_value_stack_pop(AOTValueStack *stack)
aot_value_stack_pop(const AOTCompContext *comp_ctx, AOTValueStack *stack)
{
AOTValue *value = stack->value_list_end;
@ -3134,11 +3378,49 @@ aot_value_stack_pop(AOTValueStack *stack)
value->prev = NULL;
}
if (comp_ctx->aot_frame) {
bh_assert(value);
bh_assert(value->value == (comp_ctx->aot_frame->sp - 1)->value);
bh_assert(value->type == (comp_ctx->aot_frame->sp - 1)->type);
switch (value->type) {
case VALUE_TYPE_I32:
case VALUE_TYPE_I1:
pop_i32(comp_ctx->aot_frame);
break;
case VALUE_TYPE_I64:
pop_i64(comp_ctx->aot_frame);
break;
case VALUE_TYPE_F32:
pop_f32(comp_ctx->aot_frame);
break;
case VALUE_TYPE_F64:
pop_f64(comp_ctx->aot_frame);
break;
case VALUE_TYPE_V128:
pop_v128(comp_ctx->aot_frame);
break;
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
pop_ref(comp_ctx->aot_frame);
break;
#if WASM_ENABLE_GC != 0
case VALUE_TYPE_GC_REF:
bh_assert(comp_ctx->enable_gc);
pop_gc_ref(comp_ctx->aot_frame);
break;
#endif
default:
bh_assert(0);
break;
}
}
return value;
}
void
aot_value_stack_destroy(AOTValueStack *stack)
aot_value_stack_destroy(AOTCompContext *comp_ctx, AOTValueStack *stack)
{
AOTValue *value = stack->value_list_head, *p;
@ -3183,14 +3465,14 @@ aot_block_stack_pop(AOTBlockStack *stack)
}
void
aot_block_stack_destroy(AOTBlockStack *stack)
aot_block_stack_destroy(AOTCompContext *comp_ctx, AOTBlockStack *stack)
{
AOTBlock *block = stack->block_list_head, *p;
while (block) {
p = block->next;
aot_value_stack_destroy(&block->value_stack);
aot_block_destroy(block);
aot_value_stack_destroy(comp_ctx, &block->value_stack);
aot_block_destroy(comp_ctx, block);
block = p;
}
@ -3199,9 +3481,9 @@ aot_block_stack_destroy(AOTBlockStack *stack)
}
void
aot_block_destroy(AOTBlock *block)
aot_block_destroy(AOTCompContext *comp_ctx, AOTBlock *block)
{
aot_value_stack_destroy(&block->value_stack);
aot_value_stack_destroy(comp_ctx, &block->value_stack);
if (block->param_types)
wasm_runtime_free(block->param_types);
if (block->param_phis)
@ -3316,8 +3598,38 @@ aot_build_zero_function_ret(const AOTCompContext *comp_ctx,
break;
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
ret = LLVMBuildRet(comp_ctx->builder, REF_NULL);
if (comp_ctx->enable_ref_types)
ret = LLVMBuildRet(comp_ctx->builder, REF_NULL);
#if WASM_ENABLE_GC != 0
else if (comp_ctx->enable_gc)
ret = LLVMBuildRet(comp_ctx->builder, GC_REF_NULL);
#endif
else
bh_assert(0);
break;
#if WASM_ENABLE_GC != 0
case REF_TYPE_NULLFUNCREF:
case REF_TYPE_NULLEXTERNREF:
case REF_TYPE_NULLREF:
/* case REF_TYPE_FUNCREF: */
/* case REF_TYPE_EXTERNREF: */
case REF_TYPE_ANYREF:
case REF_TYPE_EQREF:
case REF_TYPE_HT_NULLABLE:
case REF_TYPE_HT_NON_NULLABLE:
case REF_TYPE_I31REF:
case REF_TYPE_STRUCTREF:
case REF_TYPE_ARRAYREF:
#if WASM_ENABLE_STRINGREF != 0
case REF_TYPE_STRINGREF:
case REF_TYPE_STRINGVIEWWTF8:
case REF_TYPE_STRINGVIEWWTF16:
case REF_TYPE_STRINGVIEWITER:
#endif
bh_assert(comp_ctx->enable_gc);
ret = LLVMBuildRet(comp_ctx->builder, GC_REF_NULL);
break;
#endif
default:
bh_assert(0);
}

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,