From fe76ce3b685abf2ea214f7f93f2aa98194b6882b Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 2 Mar 2021 04:24:15 -0600 Subject: [PATCH] Update global initialization process for latest spec cases (#553) --- core/iwasm/aot/aot_loader.c | 19 ++ core/iwasm/aot/aot_runtime.c | 112 ++++++++++-- core/iwasm/common/wasm_runtime_common.c | 2 + core/iwasm/interpreter/wasm.h | 11 +- core/iwasm/interpreter/wasm_loader.c | 31 +++- core/iwasm/interpreter/wasm_mini_loader.c | 4 + core/iwasm/interpreter/wasm_runtime.c | 173 +++++++----------- .../libc-builtin/libc_builtin_wrapper.c | 36 ++-- 8 files changed, 240 insertions(+), 148 deletions(-) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 769e47d62..4faa89b67 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -722,6 +722,9 @@ load_import_globals(const uint8 **p_buf, const uint8 *buf_end, AOTImportGlobal *import_globals; uint64 size; uint32 i, data_offset = 0; +#if WASM_ENABLE_LIBC_BUILTIN != 0 + WASMGlobalImport tmp_global; +#endif /* Allocate memory */ size = sizeof(AOTImportGlobal) * (uint64)module->import_global_count; @@ -738,6 +741,22 @@ load_import_globals(const uint8 **p_buf, const uint8 *buf_end, read_string(buf, buf_end, import_globals[i].module_name); read_string(buf, buf_end, import_globals[i].global_name); +#if WASM_ENABLE_LIBC_BUILTIN != 0 + if (wasm_native_lookup_libc_builtin_global( + import_globals[i].module_name, + import_globals[i].global_name, + &tmp_global)) { + if (tmp_global.type != import_globals[i].type + || tmp_global.is_mutable != import_globals[i].is_mutable) { + set_error_buf(error_buf, error_buf_size, + "incompatible import type"); + return false; + } + import_globals[i].global_data_linked = + tmp_global.global_data_linked; + } +#endif + import_globals[i].size = wasm_value_type_size(import_globals[i].type); import_globals[i].data_offset = data_offset; data_offset += import_globals[i].size; diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 55c266e38..38c91d58e 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -6,6 +6,7 @@ #include "aot_runtime.h" #include "bh_log.h" #include "mem_alloc.h" +#include "../common/wasm_runtime_common.h" #if WASM_ENABLE_SHARED_MEMORY != 0 #include "../common/wasm_shared_memory.h" #endif @@ -19,6 +20,22 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) } } +static void +set_error_buf_v(char *error_buf, uint32 error_buf_size, + const char *format, ...) +{ + va_list args; + char buf[128]; + + if (error_buf != NULL) { + va_start(args, format); + vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + snprintf(error_buf, error_buf_size, + "AOT module instantiate failed: %s", buf); + } +} + static void * runtime_malloc(uint64 size, char *error_buf, uint32 error_buf_size) { @@ -35,6 +52,58 @@ runtime_malloc(uint64 size, char *error_buf, uint32 error_buf_size) return mem; } +static bool +check_global_init_expr(const AOTModule *module, uint32 global_index, + char *error_buf, uint32 error_buf_size) +{ + if (global_index >= module->import_global_count + module->global_count) { + set_error_buf_v(error_buf, error_buf_size, + "unknown global %d", global_index); + return false; + } + + /** + * Currently, constant expressions occurring as initializers of + * globals are further constrained in that contained global.get + * instructions are only allowed to refer to imported globals. + * + * And initializer expression cannot reference a mutable global. + */ + if (global_index >= module->import_global_count + || module->import_globals->is_mutable) { + set_error_buf(error_buf, error_buf_size, + "constant expression required"); + return false; + } + + return true; +} + +static void +init_global_data(uint8 *global_data, uint8 type, + WASMValue *initial_value) +{ + switch (type) { + case VALUE_TYPE_I32: + case VALUE_TYPE_F32: + *(int32*)global_data = initial_value->i32; + break; + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + bh_memcpy_s(global_data, sizeof(int64), + &initial_value->i64, sizeof(int64)); + break; +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + bh_memcpy_s(global_data, sizeof(V128), + &initial_value->i64, sizeof(V128)); + break; +#endif + default: + bh_assert(0); + } +} + static bool global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, char *error_buf, uint32 error_buf_size) @@ -49,7 +118,8 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, for (i = 0; i < module->import_global_count; i++, import_global++) { bh_assert(import_global->data_offset == (uint32)(p - (uint8*)module_inst->global_data.ptr)); - memcpy(p, &import_global->global_data_linked, import_global->size); + init_global_data(p, import_global->type, + &import_global->global_data_linked); p += import_global->size; } @@ -60,18 +130,21 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, init_expr = &global->init_expr; switch (init_expr->init_expr_type) { case INIT_EXPR_TYPE_GET_GLOBAL: - if (init_expr->u.global_index >= module->import_global_count + i) { - set_error_buf(error_buf, error_buf_size, "unknown global"); + { + if (!check_global_init_expr(module, init_expr->u.global_index, + error_buf, error_buf_size)) { return false; } - memcpy(p, - &module->import_globals[init_expr->u.global_index].global_data_linked, - global->size); + init_global_data(p, global->type, + &module->import_globals[init_expr->u.global_index] + .global_data_linked); break; + } default: - /* TODO: check whether global type and init_expr type are matching */ - memcpy(p, &init_expr->u, global->size); + { + init_global_data(p, global->type, &init_expr->u); break; + } } p += global->size; } @@ -98,10 +171,12 @@ table_instantiate(AOTModuleInstance *module_inst, AOTModule *module, /* Resolve table data base offset */ if (table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { global_index = table_seg->offset.u.global_index; - bh_assert(global_index < - module->import_global_count + module->global_count); - /* TODO: && globals[table_seg->offset.u.global_index].type == - VALUE_TYPE_I32*/ + + if (!check_global_init_expr(module, global_index, + error_buf, error_buf_size)) { + return false; + } + if (global_index < module->import_global_count) global_data_offset = module->import_globals[global_index].data_offset; @@ -487,10 +562,12 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module, /* Resolve memory data base offset */ if (data_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { global_index = data_seg->offset.u.global_index; - bh_assert(global_index < - module->import_global_count + module->global_count); - /* TODO: && globals[data_seg->offset.u.global_index].type == - VALUE_TYPE_I32*/ + + if (!check_global_init_expr(module, global_index, + error_buf, error_buf_size)) { + return false; + } + if (global_index < module->import_global_count) global_data_offset = module->import_globals[global_index].data_offset; @@ -501,7 +578,8 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module, base_offset = *(uint32*) ((uint8*)module_inst->global_data.ptr + global_data_offset); - } else { + } + else { base_offset = (uint32)data_seg->offset.u.i32; } diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 7b1f7de12..1e7e363dc 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -545,7 +545,9 @@ wasm_runtime_is_built_in_module(const char *module_name) return (!strcmp("env", module_name) || !strcmp("wasi_unstable", module_name) || !strcmp("wasi_snapshot_preview1", module_name) +#if WASM_ENABLE_SPEC_TEST != 0 || !strcmp("spectest", module_name) +#endif || !strcmp("", module_name)); } diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index c8ab721de..ab3476c0f 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -93,6 +93,8 @@ typedef union V128 { typedef union WASMValue { int32 i32; uint32 u32; + uint32 global_index; + uint32 ref_index; int64 i64; uint64 u64; float32 f32; @@ -104,14 +106,7 @@ typedef union WASMValue { typedef struct InitializerExpression { /* type of INIT_EXPR_TYPE_XXX */ uint8 init_expr_type; - union { - int32 i32; - int64 i64; - float32 f32; - float64 f64; - uint32 global_index; - V128 v128; - } u; + WASMValue u; } InitializerExpression; typedef struct WASMType { diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 3f24101c0..aa798ae3a 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -1276,6 +1276,14 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end, #if WASM_ENABLE_LIBC_BUILTIN != 0 global->is_linked = wasm_native_lookup_libc_builtin_global( sub_module_name, global_name, global); + if (global->is_linked) { + if (global->type != declare_type + || global->is_mutable != declare_mutable) { + set_error_buf(error_buf, error_buf_size, + "incompatible import type"); + return false; + } + } #endif #if WASM_ENABLE_MULTI_MODULE != 0 if (!global->is_linked @@ -1324,6 +1332,7 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, p_org = p; read_leb_uint32(p, p_end, table->flags); +#if WASM_ENABLE_SHARED_MEMORY == 0 if (p - p_org > 1) { set_error_buf(error_buf, error_buf_size, "integer representation too long"); @@ -1333,6 +1342,20 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, set_error_buf(error_buf, error_buf_size, "integer too large"); return false; } +#else + if (p - p_org > 1) { + set_error_buf(error_buf, error_buf_size, "invalid limits flags"); + return false; + } + if (table->flags == 2) { + set_error_buf(error_buf, error_buf_size, "tables cannot be shared"); + return false; + } + if (table->flags > 1) { + set_error_buf(error_buf, error_buf_size, "invalid limits flags"); + return false; + } +#endif read_leb_uint32(p, p_end, table->init_size); if (table->flags == 0) { @@ -1366,19 +1389,23 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, p_org = p; read_leb_uint32(p, p_end, memory->flags); +#if WASM_ENABLE_SHARED_MEMORY == 0 if (p - p_org > 1) { set_error_buf(error_buf, error_buf_size, "integer representation too long"); return false; } -#if WASM_ENABLE_SHARED_MEMORY == 0 if (memory->flags > 1) { set_error_buf(error_buf, error_buf_size, "integer too large"); return false; } #else + if (p - p_org > 1) { + set_error_buf(error_buf, error_buf_size, "invalid limits flags"); + return false; + } if (memory->flags > 3) { - set_error_buf(error_buf, error_buf_size, "integer too large"); + set_error_buf(error_buf, error_buf_size, "invalid limits flags"); return false; } else if (memory->flags == 2) { diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 478b3cc34..bdbc36b88 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -477,6 +477,10 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end, /* check built-in modules */ ret = wasm_native_lookup_libc_builtin_global(sub_module_name, global_name, global); + if (ret) { + bh_assert(global->type == declare_type + && global->is_mutable != declare_mutable); + } #endif /* WASM_ENABLE_LIBC_BUILTIN */ global->is_linked = ret; diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 6ffe90b32..005822bdd 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -23,6 +23,22 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) } } +static void +set_error_buf_v(char *error_buf, uint32 error_buf_size, + const char *format, ...) +{ + va_list args; + char buf[128]; + + if (error_buf != NULL) { + va_start(args, format); + vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + snprintf(error_buf, error_buf_size, + "WASM module instantiate failed: %s", buf); + } +} + WASMModule* wasm_load(const uint8 *buf, uint32 size, char *error_buf, uint32 error_buf_size) @@ -635,40 +651,30 @@ globals_deinstantiate(WASMGlobalInstance *globals) wasm_runtime_free(globals); } -/** - * init_expr->u ==> init_val - */ static bool -parse_init_expr(const InitializerExpression *init_expr, - const WASMGlobalInstance *global_inst_array, - uint32 boundary, WASMValue *init_val) +check_global_init_expr(const WASMModule *module, uint32 global_index, + char *error_buf, uint32 error_buf_size) { - if (init_expr->init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { - uint32 target_global_index = init_expr->u.global_index; - /** - * a global gets the init value of another global - */ - if (target_global_index >= boundary) { - LOG_DEBUG("unknown target global, %d", target_global_index); - return false; - } + if (global_index >= module->import_global_count + module->global_count) { + set_error_buf_v(error_buf, error_buf_size, + "unknown global %d", global_index); + return false; + } - /** - * it will work if using WASMGlobalImport and WASMGlobal in - * WASMModule, but will have to face complicated cases - * - * but we still have no sure the target global has been - * initialized before - */ - WASMValue target_value = - global_inst_array[target_global_index].initial_value; - bh_memcpy_s(init_val, sizeof(WASMValue), &target_value, - sizeof(target_value)); - } - else { - bh_memcpy_s(init_val, sizeof(WASMValue), &init_expr->u, - sizeof(init_expr->u)); + /** + * Currently, constant expressions occurring as initializers of + * globals are further constrained in that contained global.get + * instructions are only allowed to refer to imported globals. + * + * And initializer expression cannot reference a mutable global. + */ + if (global_index >= module->import_global_count + || (module->import_globals + global_index)->u.global.is_mutable) { + set_error_buf(error_buf, error_buf_size, + "constant expression required"); + return false; } + return true; } @@ -714,26 +720,19 @@ globals_instantiate(const WASMModule *module, return NULL; } - /** - * although, actually don't need initial_value for an imported - * global, we keep it here like a place holder because of - * global-data and - * (global $g2 i32 (global.get $g1)) - */ - if (!parse_init_expr( - &(global_import->import_global_linked->init_expr), - global->import_module_inst->globals, - global->import_module_inst->global_count, - &(global->initial_value))) { - set_error_buf(error_buf, error_buf_size, "unknown global"); - return NULL; - } + /* The linked global instance has been initialized, we + just need to copy the value. */ + bh_memcpy_s(&(global->initial_value), sizeof(WASMValue), + &(global_import->import_global_linked->init_expr), + sizeof(WASMValue)); } else #endif { /* native globals share their initial_values in one module */ - global->initial_value = global_import->global_data_linked; + bh_memcpy_s(&(global->initial_value), sizeof(WASMValue), + &(global_import->global_data_linked), + sizeof(WASMValue)); } global->data_offset = global_data_offset; global_data_offset += wasm_value_type_size(global->type); @@ -743,9 +742,6 @@ globals_instantiate(const WASMModule *module, /* instantiate globals from global section */ for (i = 0; i < module->global_count; i++) { - bool ret = false; - uint32 global_count = - module->import_global_count + module->global_count; InitializerExpression *init_expr = &(module->globals[i].init_expr); global->type = module->globals[i].type; @@ -754,18 +750,20 @@ globals_instantiate(const WASMModule *module, global_data_offset += wasm_value_type_size(global->type); - /** - * first init, it might happen that the target global instance - * has not been initialize yet - */ - if (init_expr->init_expr_type != INIT_EXPR_TYPE_GET_GLOBAL) { - ret = - parse_init_expr(init_expr, globals, global_count, - &(global->initial_value)); - if (!ret) { - set_error_buf(error_buf, error_buf_size, "unknown global"); + if (init_expr->init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { + if (!check_global_init_expr(module, init_expr->u.global_index, + error_buf, error_buf_size)) { return NULL; } + + bh_memcpy_s( + &(global->initial_value), sizeof(WASMValue), + &(globals[init_expr->u.global_index].initial_value), + sizeof(globals[init_expr->u.global_index].initial_value)); + } + else { + bh_memcpy_s(&(global->initial_value), sizeof(WASMValue), + &(init_expr->u), sizeof(init_expr->u)); } global++; } @@ -776,39 +774,6 @@ globals_instantiate(const WASMModule *module, return globals; } -static bool -globals_instantiate_fix(WASMGlobalInstance *globals, - const WASMModule *module, - char *error_buf, uint32 error_buf_size) -{ - WASMGlobalInstance *global = globals; - uint32 i; - uint32 global_count = module->import_global_count + module->global_count; - - /** - * second init, only target global instances from global - * (ignore import_global) - * to fix skipped init_value in the previous round - * hope two rounds are enough but how about a chain ? - */ - for (i = 0; i < module->global_count; i++) { - bool ret = false; - InitializerExpression *init_expr = &module->globals[i].init_expr; - - if (init_expr->init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { - ret = parse_init_expr(init_expr, globals, global_count, - &global->initial_value); - if (!ret) { - set_error_buf(error_buf, error_buf_size, "unknown global"); - return false; - } - } - - global++; - } - return true; -} - /** * Return export function count in module export section. */ @@ -1240,15 +1205,6 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, } if (global_count > 0) { - /** - * since there might be some globals are not instantiate the first - * instantiate round - */ - if (!globals_instantiate_fix(globals, module, - error_buf, error_buf_size)) { - goto fail; - } - /* Initialize the global data */ global_data = module_inst->global_data; global_data_end = global_data + global_data_size; @@ -1307,14 +1263,20 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, if (data_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { + if (!check_global_init_expr(module, + data_seg->base_offset.u.global_index, + error_buf, error_buf_size)) { + goto fail; + } + if (!globals - || data_seg->base_offset.u.global_index >= global_count || globals[data_seg->base_offset.u.global_index].type - != VALUE_TYPE_I32) { + != VALUE_TYPE_I32) { set_error_buf(error_buf, error_buf_size, "data segment does not fit"); goto fail; } + data_seg->base_offset.u.i32 = globals[data_seg->base_offset.u.global_index] .initial_value.i32; @@ -1371,8 +1333,13 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, if (table_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { + if (!check_global_init_expr(module, + table_seg->base_offset.u.global_index, + error_buf, error_buf_size)) { + goto fail; + } + if (!globals - || table_seg->base_offset.u.global_index >= global_count || globals[table_seg->base_offset.u.global_index].type != VALUE_TYPE_I32) { set_error_buf(error_buf, error_buf_size, diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index b1a20b1d2..23d982485 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -1167,26 +1167,24 @@ get_spectest_export_apis(NativeSymbol **p_libc_builtin_apis) typedef struct WASMNativeGlobalDef { const char *module_name; const char *global_name; - WASMValue global_data; + uint8 type; + bool is_mutable; + WASMValue value; } WASMNativeGlobalDef; static WASMNativeGlobalDef native_global_defs[] = { - { "spectest", "global_i32", .global_data.i32 = 666 }, - { "spectest", "global_f32", .global_data.f32 = 666.6 }, - { "spectest", "global_f64", .global_data.f64 = 666.6 }, - { "test", "global-i32", .global_data.i32 = 0 }, - { "test", "global-f32", .global_data.f32 = 0 }, - { "env", "STACKTOP", .global_data.u32 = 0 }, - { "env", "STACK_MAX", .global_data.u32 = 0 }, - { "env", "ABORT", .global_data.u32 = 0 }, - { "env", "memoryBase", .global_data.u32 = 0 }, - { "env", "__memory_base", .global_data.u32 = 0 }, - { "env", "tableBase", .global_data.u32 = 0 }, - { "env", "__table_base", .global_data.u32 = 0 }, - { "env", "DYNAMICTOP_PTR", .global_data.addr = 0 }, - { "env", "tempDoublePtr", .global_data.addr = 0 }, - { "global", "NaN", .global_data.u64 = 0x7FF8000000000000LL }, - { "global", "Infinity", .global_data.u64 = 0x7FF0000000000000LL } +#if WASM_ENABLE_SPEC_TEST != 0 + { "spectest", "global_i32", VALUE_TYPE_I32, false, .value.i32 = 666 }, + { "spectest", "global_i64", VALUE_TYPE_I64, false, .value.i64 = 666 }, + { "spectest", "global_f32", VALUE_TYPE_F32, false, .value.f32 = 666.6 }, + { "spectest", "global_f64", VALUE_TYPE_F64, false, .value.f64 = 666.6 }, + { "test", "global-i32", VALUE_TYPE_I32, false, .value.i32 = 0 }, + { "test", "global-f32", VALUE_TYPE_F32, false, .value.f32 = 0 }, + { "test", "global-mut-i32", VALUE_TYPE_I32, true, .value.i32 = 0 }, + { "test", "global-mut-i64", VALUE_TYPE_I64, true, .value.i64 = 0 }, +#endif + { "global", "NaN", VALUE_TYPE_F64, .value.u64 = 0x7FF8000000000000LL }, + { "global", "Infinity", VALUE_TYPE_F64, .value.u64 = 0x7FF0000000000000LL } }; bool @@ -1205,7 +1203,9 @@ wasm_native_lookup_libc_builtin_global(const char *module_name, while (global_def < global_def_end) { if (!strcmp(global_def->module_name, module_name) && !strcmp(global_def->global_name, global_name)) { - global->global_data_linked = global_def->global_data; + global->type = global_def->type; + global->is_mutable = global_def->is_mutable; + global->global_data_linked = global_def->value; return true; } global_def++;