Просмотр исходного кода

Update global initialization process for latest spec cases (#553)

Wenyong Huang 4 лет назад
Родитель
Сommit
fe76ce3b68

+ 19 - 0
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;

+ 95 - 17
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;
         }
 

+ 2 - 0
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));
 }
 

+ 3 - 8
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 {

+ 29 - 2
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) {

+ 4 - 0
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;

+ 70 - 103
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;
-        }
-
-        /**
-         * 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));
+    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;
     }
-    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,

+ 18 - 18
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++;