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:
@ -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);
|
||||
|
||||
|
||||
@ -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
@ -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
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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, ¬_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 */
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
@ -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
|
||||
|
||||
2144
core/iwasm/compilation/aot_emit_gc.c
Normal file
2144
core/iwasm/compilation/aot_emit_gc.c
Normal file
File diff suppressed because it is too large
Load Diff
119
core/iwasm/compilation/aot_emit_gc.h
Normal file
119
core/iwasm/compilation/aot_emit_gc.h
Normal 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_ */
|
||||
@ -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:
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
1443
core/iwasm/compilation/aot_emit_stringref.c
Normal file
1443
core/iwasm/compilation/aot_emit_stringref.c
Normal file
File diff suppressed because it is too large
Load Diff
112
core/iwasm/compilation/aot_emit_stringref.h
Normal file
112
core/iwasm/compilation/aot_emit_stringref.h
Normal 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_ */
|
||||
@ -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 */
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
Reference in New Issue
Block a user