Przeglądaj źródła

Add --enable-gc option to wamrc (#2190)

The runtime instance memory layout changed when GC was enabled. With this patch
the GC is enabled for wamrc, but it keeps the compatibility with iwasm no matter GC
is enabled for it or not.

It may waste some memory for iwasm without GC support since the GC relative fields
for the table instance are always here, let's optimization it after AOT fully supports GC.
Huang Qi 2 lat temu
rodzic
commit
035cca062f

+ 19 - 17
core/iwasm/compilation/aot.c

@@ -152,7 +152,7 @@ fail:
 
 static AOTImportGlobal *
 aot_create_import_globals(const WASMModule *module,
-                          uint32 *p_import_global_data_size)
+                          uint32 *p_import_global_data_size, bool gc_enabled)
 {
     AOTImportGlobal *import_globals;
     uint64 size;
@@ -177,10 +177,11 @@ 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);
+        import_globals[i].size =
+            wasm_value_type_size_ex(import_global->type, gc_enabled);
         /* Calculate data offset */
         import_globals[i].data_offset = data_offset;
-        data_offset += wasm_value_type_size(import_global->type);
+        data_offset += wasm_value_type_size_ex(import_global->type, gc_enabled);
     }
 
     *p_import_global_data_size = data_offset;
@@ -189,7 +190,7 @@ aot_create_import_globals(const WASMModule *module,
 
 static AOTGlobal *
 aot_create_globals(const WASMModule *module, uint32 global_data_start_offset,
-                   uint32 *p_global_data_size)
+                   uint32 *p_global_data_size, bool gc_enabled)
 {
     AOTGlobal *globals;
     uint64 size;
@@ -209,12 +210,12 @@ 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);
+        globals[i].size = wasm_value_type_size_ex(global->type, gc_enabled);
         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);
+        data_offset += wasm_value_type_size_ex(global->type, gc_enabled);
     }
 
     *p_global_data_size = data_offset - global_data_start_offset;
@@ -250,15 +251,15 @@ aot_create_func_types(const WASMModule *module)
 
     /* 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;
+        AOTFuncType *func_type = (AOTFuncType *)module->types[i];
+        size = offsetof(AOTFuncType, types) + (uint64)func_type->param_count
+               + (uint64)func_type->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);
+        memcpy(func_types[i], func_type, size);
     }
 
     return func_types;
@@ -297,7 +298,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;
             }
@@ -346,7 +347,7 @@ aot_create_funcs(const WASMModule *module)
 
         /* Resolve function type index */
         for (j = 0; j < module->type_count; j++)
-            if (func->func_type == module->types[j]) {
+            if (func->func_type == (WASMFuncType *)module->types[j]) {
                 funcs[i]->func_type_index = j;
                 break;
             }
@@ -368,7 +369,7 @@ fail:
 }
 
 AOTCompData *
-aot_create_comp_data(WASMModule *module)
+aot_create_comp_data(WASMModule *module, bool gc_enabled)
 {
     AOTCompData *comp_data;
     uint32 import_global_data_size = 0, global_data_size = 0, i, j;
@@ -486,15 +487,16 @@ 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, &import_global_data_size, gc_enabled)))
         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)))
+        && !(comp_data->globals =
+                 aot_create_globals(module, import_global_data_size,
+                                    &global_data_size, gc_enabled)))
         goto fail;
 
     comp_data->global_data_size = import_global_data_size + global_data_size;

+ 1 - 1
core/iwasm/compilation/aot.h

@@ -277,7 +277,7 @@ typedef struct AOTNativeSymbol {
 } AOTNativeSymbol;
 
 AOTCompData *
-aot_create_comp_data(WASMModule *module);
+aot_create_comp_data(WASMModule *module, bool gc_enabled);
 
 void
 aot_destroy_comp_data(AOTCompData *comp_data);

+ 3 - 0
core/iwasm/compilation/aot_llvm.c

@@ -1657,6 +1657,9 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option)
     if (option->enable_stack_estimation)
         comp_ctx->enable_stack_estimation = true;
 
+    if (option->enable_gc)
+        comp_ctx->enable_gc = true;
+
     comp_ctx->opt_level = option->opt_level;
     comp_ctx->size_level = option->size_level;
 

+ 4 - 0
core/iwasm/compilation/aot_llvm.h

@@ -346,6 +346,9 @@ typedef struct AOTCompContext {
     /* Whether optimize the JITed code */
     bool optimize;
 
+    /* Enable GC */
+    bool enable_gc;
+
     uint32 opt_level;
     uint32 size_level;
 
@@ -410,6 +413,7 @@ typedef struct AOTCompOption {
     bool disable_llvm_intrinsics;
     bool disable_llvm_lto;
     bool enable_stack_estimation;
+    bool enable_gc;
     uint32 opt_level;
     uint32 size_level;
     uint32 output_format;

+ 2 - 1
core/iwasm/include/aot_export.h

@@ -20,7 +20,7 @@ struct AOTCompContext;
 typedef struct AOTCompContext *aot_comp_context_t;
 
 aot_comp_data_t
-aot_create_comp_data(void *wasm_module);
+aot_create_comp_data(void *wasm_module, bool gc_enabled);
 
 void
 aot_destroy_comp_data(aot_comp_data_t comp_data);
@@ -56,6 +56,7 @@ typedef struct AOTCompOption {
     bool disable_llvm_intrinsics;
     bool disable_llvm_lto;
     bool enable_stack_estimation;
+    bool enable_gc;
     uint32_t opt_level;
     uint32_t size_level;
     uint32_t output_format;

+ 17 - 5
core/iwasm/interpreter/wasm.h

@@ -979,7 +979,7 @@ wasm_string_equal(const char *s1, const char *s2)
  * Return the byte size of value type.
  */
 inline static uint32
-wasm_value_type_size(uint8 value_type)
+wasm_value_type_size_ex(uint8 value_type, bool gc_enabled)
 {
     if (value_type == VALUE_TYPE_VOID)
         return 0;
@@ -992,21 +992,33 @@ wasm_value_type_size(uint8 value_type)
     else if (value_type == VALUE_TYPE_V128)
         return sizeof(int64) * 2;
 #endif
-#if WASM_ENABLE_GC != 0
     else if (value_type >= (uint8)REF_TYPE_NULLREF /* 0x65 */
-             && value_type <= (uint8)REF_TYPE_FUNCREF /* 0x70 */)
+             && value_type <= (uint8)REF_TYPE_FUNCREF /* 0x70 */ && gc_enabled)
         return sizeof(uintptr_t);
-#elif WASM_ENABLE_REF_TYPES != 0
     else if (value_type == VALUE_TYPE_FUNCREF
              || value_type == VALUE_TYPE_EXTERNREF)
         return sizeof(uint32);
-#endif
     else {
         bh_assert(0);
     }
     return 0;
 }
 
+/**
+ * Return the byte size of value type.
+ */
+inline static uint32
+wasm_value_type_size(uint8 value_type)
+{
+    return wasm_value_type_size_ex(value_type,
+#if WASM_ENABLE_GC != 0
+                                   true
+#else
+                                   false
+#endif
+    );
+}
+
 inline static uint16
 wasm_value_type_cell_num(uint8 value_type)
 {

+ 8 - 1
core/iwasm/interpreter/wasm_loader.c

@@ -4112,6 +4112,13 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
     AOTCompOption option = { 0 };
     char *aot_last_error;
     uint64 size;
+    bool gc_enabled =
+#if WASM_ENABLE_GC != 0
+        true
+#else
+        false
+#endif
+        ;
 
     if (module->function_count == 0)
         return true;
@@ -4138,7 +4145,7 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
         (bool *)((uint8 *)module->func_ptrs
                  + sizeof(void *) * module->function_count);
 
-    module->comp_data = aot_create_comp_data(module);
+    module->comp_data = aot_create_comp_data(module, gc_enabled);
     if (!module->comp_data) {
         aot_last_error = aot_get_last_error();
         bh_assert(aot_last_error != NULL);

+ 8 - 1
core/iwasm/interpreter/wasm_mini_loader.c

@@ -1839,6 +1839,13 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
     AOTCompOption option = { 0 };
     char *aot_last_error;
     uint64 size;
+    bool gc_enabled =
+#if WASM_ENABLE_GC != 0
+        true
+#else
+        false
+#endif
+        ;
 
     if (module->function_count == 0)
         return true;
@@ -1865,7 +1872,7 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
         (bool *)((uint8 *)module->func_ptrs
                  + sizeof(void *) * module->function_count);
 
-    module->comp_data = aot_create_comp_data(module);
+    module->comp_data = aot_create_comp_data(module, gc_enabled);
     if (!module->comp_data) {
         aot_last_error = aot_get_last_error();
         bh_assert(aot_last_error != NULL);

+ 9 - 9
core/iwasm/interpreter/wasm_runtime.c

@@ -613,7 +613,7 @@ tables_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
         {
 #if WASM_ENABLE_GC != 0
             table->elem_type = import->u.table.elem_type;
-            table->elem_ref_type = import->u.table.elem_ref_type;
+            table->elem_ref_type.elem_ref_type = import->u.table.elem_ref_type;
 #endif
             table->cur_size = import->u.table.init_size;
             table->max_size = max_size_fixed;
@@ -657,7 +657,7 @@ tables_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
 #endif
 #if WASM_ENABLE_GC != 0
         table->elem_type = module->tables[i].elem_type;
-        table->elem_ref_type = module->tables[i].elem_ref_type;
+        table->elem_ref_type.elem_ref_type = module->tables[i].elem_ref_type;
 #endif
         table->cur_size = module->tables[i].init_size;
         table->max_size = max_size_fixed;
@@ -2210,8 +2210,8 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst,
         if (!wasm_elem_is_declarative(table_seg->mode)
             && !wasm_reftype_is_subtype_of(
                 table_seg->elem_type, table_seg->elem_ref_type,
-                table->elem_type, table->elem_ref_type, module->types,
-                module->type_count)) {
+                table->elem_type, table->elem_ref_type.elem_ref_type,
+                module->types, module->type_count)) {
             set_error_buf(error_buf, error_buf_size,
                           "elements segment does not fit");
             goto fail;
@@ -3464,7 +3464,7 @@ llvm_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
     module = module_inst->module;
     func_type_indexes = module_inst->func_type_indexes;
     func_type_idx = func_type_indexes[func_idx];
-    func_type = module->types[func_type_idx];
+    func_type = (AOTFuncType *)module->types[func_type_idx];
     func_ptr = module_inst->func_ptrs[func_idx];
 
     bh_assert(func_idx < module->import_function_count);
@@ -3676,7 +3676,7 @@ llvm_jit_table_copy(WASMModuleInstance *module_inst, uint32 src_tbl_idx,
 
 void
 llvm_jit_table_fill(WASMModuleInstance *module_inst, uint32 tbl_idx,
-                    uint32 length, uint32 val, uint32 data_offset)
+                    uint32 length, uintptr_t val, uint32 data_offset)
 {
     WASMTableInstance *tbl_inst;
 
@@ -3696,13 +3696,13 @@ llvm_jit_table_fill(WASMModuleInstance *module_inst, uint32 tbl_idx,
     }
 
     for (; length != 0; data_offset++, length--) {
-        tbl_inst->elems[data_offset] = val;
+        tbl_inst->elems[data_offset] = (table_elem_type_t *)val;
     }
 }
 
 uint32
 llvm_jit_table_grow(WASMModuleInstance *module_inst, uint32 tbl_idx,
-                    uint32 inc_size, uint32 init_val)
+                    uint32 inc_size, uintptr_t init_val)
 {
     WASMTableInstance *tbl_inst;
     uint32 i, orig_size, total_size;
@@ -3735,7 +3735,7 @@ llvm_jit_table_grow(WASMModuleInstance *module_inst, uint32 tbl_idx,
 
     /* fill in */
     for (i = 0; i < inc_size; ++i) {
-        tbl_inst->elems[tbl_inst->cur_size + i] = init_val;
+        tbl_inst->elems[tbl_inst->cur_size + i] = (table_elem_type_t *)init_val;
     }
 
     tbl_inst->cur_size = total_size;

+ 17 - 4
core/iwasm/interpreter/wasm_runtime.h

@@ -116,12 +116,25 @@ struct WASMMemoryInstance {
 #endif
 };
 
+/* WASMTableInstance is used to represent table instance in
+ * runtime, to compute the table element address with index
+ * we need to know the element type and the element ref type.
+ * For pointer type, it's 32-bit or 64-bit, align up to 8 bytes
+ * to simplify the computation.
+ * And each struct member should be 4-byte or 8-byte aligned.
+ */
 struct WASMTableInstance {
-#if WASM_ENABLE_GC != 0
     /* The element type */
     uint8 elem_type;
-    WASMRefType *elem_ref_type;
+    uint8 __padding__[7];
+    union {
+#if WASM_ENABLE_GC != 0
+        WASMRefType *elem_ref_type;
+#else
+        uintptr_t elem_ref_type;
 #endif
+        uint64 __padding__;
+    } elem_ref_type;
     /* Current size */
     uint32 cur_size;
     /* Maximum size */
@@ -664,11 +677,11 @@ llvm_jit_table_copy(WASMModuleInstance *module_inst, uint32 src_tbl_idx,
 
 void
 llvm_jit_table_fill(WASMModuleInstance *module_inst, uint32 tbl_idx,
-                    uint32 length, uint32 val, uint32 data_offset);
+                    uint32 length, uintptr_t val, uint32 data_offset);
 
 uint32
 llvm_jit_table_grow(WASMModuleInstance *module_inst, uint32 tbl_idx,
-                    uint32 inc_entries, uint32 init_val);
+                    uint32 inc_entries, uintptr_t init_val);
 #endif
 
 #if WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_PERF_PROFILING != 0

+ 9 - 1
wamr-compiler/CMakeLists.txt

@@ -46,6 +46,12 @@ add_definitions(-DWASM_ENABLE_PERF_PROFILING=1)
 add_definitions(-DWASM_ENABLE_LOAD_CUSTOM_SECTION=1)
 add_definitions(-DWASM_ENABLE_LIB_WASI_THREADS=1)
 
+if (WAMR_BUILD_GC_BINARYEN EQUAL 1)
+  add_definitions (-DWASM_ENABLE_GC_BINARYEN=1)
+else ()
+  add_definitions (-DWASM_ENABLE_GC=1)
+endif ()
+
 if (WAMR_BUILD_LLVM_LEGACY_PM EQUAL 1)
   add_definitions(-DWASM_ENABLE_LLVM_LEGACY_PM=1)
 endif()
@@ -213,6 +219,7 @@ endif()
 include (${IWASM_DIR}/libraries/lib-pthread/lib_pthread.cmake)
 include (${IWASM_DIR}/libraries/lib-wasi-threads/lib_wasi_threads.cmake)
 include (${IWASM_DIR}/common/iwasm_common.cmake)
+include (${IWASM_DIR}/common/gc/iwasm_gc.cmake)
 include (${IWASM_DIR}/interpreter/iwasm_interp.cmake)
 include (${IWASM_DIR}/aot/iwasm_aot.cmake)
 include (${IWASM_DIR}/compilation/iwasm_compl.cmake)
@@ -269,7 +276,8 @@ add_library (vmlib
              ${LIB_WASI_THREADS_SOURCE}
              ${IWASM_COMMON_SOURCE}
              ${IWASM_INTERP_SOURCE}
-             ${IWASM_AOT_SOURCE})
+             ${IWASM_AOT_SOURCE}
+             ${IWASM_GC_SOURCE})
 
 add_library (aotclib ${IWASM_COMPL_SOURCE})
 

+ 12 - 2
wamr-compiler/main.c

@@ -57,12 +57,14 @@ print_help()
     printf("  --disable-simd            Disable the post-MVP 128-bit SIMD feature:\n");
     printf("                              currently 128-bit SIMD is supported for x86-64 and aarch64 targets,\n");
     printf("                              and by default it is enabled in them and disabled in other targets\n");
-    printf("  --disable-ref-types       Disable the MVP reference types feature\n");
+    printf("  --disable-ref-types       Disable the MVP reference types feature, it will be disabled forcibly if\n");
+    printf("                              GC is enabled\n");
     printf("  --disable-aux-stack-check Disable auxiliary stack overflow/underflow check\n");
     printf("  --enable-dump-call-stack  Enable stack trace feature\n");
     printf("  --enable-perf-profiling   Enable function performance profiling\n");
     printf("  --enable-memory-profiling Enable memory usage profiling\n");
     printf("  --enable-indirect-mode    Enalbe call function through symbol table but not direct call\n");
+    printf("  --enable-gc               Enalbe GC (Garbage Collection) feature\n");
     printf("  --disable-llvm-intrinsics Disable the LLVM built-in intrinsics\n");
     printf("  --disable-llvm-lto        Disable the LLVM link time optimization\n");
     printf("  --emit-custom-sections=<section names>\n");
@@ -153,6 +155,7 @@ main(int argc, char *argv[])
     option.enable_aux_stack_check = true;
     option.enable_bulk_memory = true;
     option.enable_ref_types = true;
+    option.enable_gc = false;
 
     /* Process options */
     for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
@@ -266,6 +269,9 @@ main(int argc, char *argv[])
         else if (!strcmp(argv[0], "--enable-indirect-mode")) {
             option.is_indirect_mode = true;
         }
+        else if (!strcmp(argv[0], "--enable-gc")) {
+            option.enable_gc = true;
+        }
         else if (!strcmp(argv[0], "--disable-llvm-intrinsics")) {
             option.disable_llvm_intrinsics = true;
         }
@@ -325,6 +331,10 @@ main(int argc, char *argv[])
         option.is_sgx_platform = true;
     }
 
+    if (option.enable_gc) {
+        option.enable_ref_types = false;
+    }
+
     wasm_file_name = argv[0];
 
     if (!strcmp(wasm_file_name, out_file_name)) {
@@ -366,7 +376,7 @@ main(int argc, char *argv[])
         goto fail2;
     }
 
-    if (!(comp_data = aot_create_comp_data(wasm_module))) {
+    if (!(comp_data = aot_create_comp_data(wasm_module, option.enable_gc))) {
         printf("%s\n", aot_get_last_error());
         goto fail3;
     }