فهرست منبع

Implement most missing wasm-c-api APIs (#303) (#676)

Remove unnecessary functions and implement more APIs:
- wasm_##name##same
- wasm##name##as_ref
- wasm_ref_as##name##
- wasm_ref_delete
- wasm_module_validate
- wasm_table_get/set/size
- wasm_memory_size
- wasm_config_new
- wasm_foreign_new

And add more wasm-c-api samples, update the related documen, add more CI rules.

Signed-off-by: Wenyong Huang <wenyong.huang@intel.com>
Wenyong Huang 4 سال پیش
والد
کامیت
edb184f709

+ 23 - 2
.github/workflows/android.yml

@@ -33,14 +33,14 @@ jobs:
           cmake ..
           make -j $(nproc)
           cd .. && rm -rf build
-      - name: Build iwasm [Classic interp]
+      - name: Build iwasm [classic interp]
         run: |
           cd product-mini/platforms/android
           mkdir build && cd build
           cmake .. -DWAMR_BUILD_FAST_INTERP=0
           make -j $(nproc)
           cd .. && rm -rf build
-      - name: Build iwasm [Multi module]
+      - name: Build iwasm [multi module]
         run: |
           cd product-mini/platforms/android
           mkdir build && cd build
@@ -89,3 +89,24 @@ jobs:
           cmake .. -DWAMR_BUILD_CUSTOM_NAME_SECTION=1
           make -j $(nproc)
           cd .. && rm -rf build
+      - name: Build iwasm [disable hardware boundary check]
+        run: |
+          cd product-mini/platforms/android
+          mkdir build && cd build
+          cmake .. -DWAMR_DISABLE_HW_BOUND_CHECK=1
+          make -j $(nproc)
+          cd .. && rm -rf build
+      - name: Build iwasm [reference types]
+        run: |
+          cd product-mini/platforms/android
+          mkdir build && cd build
+          cmake .. -DWAMR_BUILD_REF_TYPES=1
+          make -j $(nproc)
+          cd .. && rm -rf build
+      - name: Build iwasm [128-bit SIMD]
+        run: |
+          cd product-mini/platforms/android
+          mkdir build && cd build
+          cmake .. -DWAMR_BUILD_SIMD=1
+          make -j $(nproc)
+          cd .. && rm -rf build

+ 39 - 2
.github/workflows/linux.yml

@@ -31,14 +31,14 @@ jobs:
         cmake ..
         make -j $(nproc)
         cd .. && rm -rf build
-    - name: Build iwasm [Classic interp]
+    - name: Build iwasm [classic interp]
       run: |
         cd product-mini/platforms/linux
         mkdir build && cd build
         cmake .. -DWAMR_BUILD_FAST_INTERP=0
         make -j $(nproc)
         cd .. && rm -rf build
-    - name: Build iwasm [Multi module]
+    - name: Build iwasm [multi module]
       run: |
         cd product-mini/platforms/linux
         mkdir build && cd build
@@ -87,6 +87,27 @@ jobs:
         cmake .. -DWAMR_BUILD_CUSTOM_NAME_SECTION=1
         make -j $(nproc)
         cd .. && rm -rf build
+    - name: Build iwasm [disable hardware boundary check]
+      run: |
+        cd product-mini/platforms/linux
+        mkdir build && cd build
+        cmake .. -DWAMR_DISABLE_HW_BOUND_CHECK=1
+        make -j $(nproc)
+        cd .. && rm -rf build
+    - name: Build iwasm [reference types]
+      run: |
+        cd product-mini/platforms/linux
+        mkdir build && cd build
+        cmake .. -DWAMR_BUILD_REF_TYPES=1
+        make -j $(nproc)
+        cd .. && rm -rf build
+    - name: Build iwasm [128-bit SIMD]
+      run: |
+        cd product-mini/platforms/linux
+        mkdir build && cd build
+        cmake .. -DWAMR_BUILD_SIMD=1
+        make -j $(nproc)
+        cd .. && rm -rf build
     - name: Cache LLVM libraries
       uses: actions/cache@v2
       id: cache_llvm
@@ -132,7 +153,10 @@ jobs:
         ./callback_chain
         ./global
         ./hello
+        ./hostref
+        ./memory
         ./reflect
+        ./table
         ./trap
         cd .. && rm -r build
     - name: Build Sample [wasm-c-api] [Jit]
@@ -145,7 +169,10 @@ jobs:
         ./callback_chain
         ./global
         ./hello
+        ./hostref
+        ./memory
         ./reflect
+        ./table
         ./trap
         cd .. && rm -r build
     - name: Build Sample [wasm-c-api] [Aot]
@@ -158,7 +185,10 @@ jobs:
         ./callback_chain
         ./global
         ./hello
+        ./hostref
+        ./memory
         ./reflect
+        ./table
         ./trap
         cd .. && rm -r build
     - name: Build Sample [basic]
@@ -187,3 +217,10 @@ jobs:
         cmake ..
         make -j $(nproc)
         ./spawn_thread
+    - name: Build Sample [ref-types]
+      run: |
+        cd samples/ref-types
+        mkdir build && cd build
+        cmake ..
+        make -j $(nproc)
+        ./hello

+ 40 - 13
.github/workflows/mac.yml

@@ -26,63 +26,84 @@ jobs:
         cd product-mini/platforms/darwin
         mkdir build && cd build
         cmake ..
-        make
+        make -j $(nproc)
         cd .. && rm -rf build
-    - name: Build iwasm [Classic interp]
+    - name: Build iwasm [classic interp]
       run: |
         cd product-mini/platforms/darwin
         mkdir build && cd build
         cmake .. -DWAMR_BUILD_FAST_INTERP=0
-        make
+        make -j $(nproc)
         cd .. && rm -rf build
-    - name: Build iwasm [Multi module]
+    - name: Build iwasm [multi module]
       run: |
         cd product-mini/platforms/darwin
         mkdir build && cd build
         cmake .. -DWAMR_BUILD_MULTI_MODULE=1
-        make
+        make -j $(nproc)
         cd .. && rm -rf build
     - name: Build iwasm [lib-pthread]
       run: |
         cd product-mini/platforms/darwin
         mkdir build && cd build
         cmake .. -DWAMR_BUILD_LIB_PTHREAD=1
-        make
+        make -j $(nproc)
         cd .. && rm -rf build
     - name: Build iwasm [aot only]
       run: |
         cd product-mini/platforms/darwin
         mkdir build && cd build
         cmake .. -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=0
-        make
+        make -j $(nproc)
         cd .. && rm -rf build
     - name: Build iwasm [interp only]
       run: |
         cd product-mini/platforms/darwin
         mkdir build && cd build
         cmake .. -DWAMR_BUILD_AOT=0
-        make
+        make -j $(nproc)
         cd .. && rm -rf build
     - name: Build iwasm [memory profiling]
       run: |
         cd product-mini/platforms/darwin
         mkdir build && cd build
         cmake .. -DWAMR_BUILD_MEMORY_PROFILING=1
-        make
+        make -j $(nproc)
         cd .. && rm -rf build
     - name: Build iwasm [tail call]
       run: |
         cd product-mini/platforms/darwin
         mkdir build && cd build
         cmake .. -DWAMR_BUILD_TAIL_CALL=1
-        make
+        make -j $(nproc)
         cd .. && rm -rf build
     - name: Build iwasm [custom name section]
       run: |
         cd product-mini/platforms/darwin
         mkdir build && cd build
         cmake .. -DWAMR_BUILD_CUSTOM_NAME_SECTION=1
-        make
+        make -j $(nproc)
+        cd .. && rm -rf build
+    - name: Build iwasm [disable hardware boundary check]
+      run: |
+        cd product-mini/platforms/darwin
+        mkdir build && cd build
+        cmake .. -DWAMR_DISABLE_HW_BOUND_CHECK=1
+        make -j $(nproc)
+        cd .. && rm -rf build
+    - name: Build iwasm [ref types]
+      run: |
+        cd product-mini/platforms/darwin
+        mkdir build && cd build
+        cmake .. -DWAMR_BUILD_REF_TYPES=1
+        make -j $(nproc)
+        cd .. && rm -rf build
+    - name: Build iwasm [128-bit SIMD]
+      run: |
+        cd product-mini/platforms/darwin
+        mkdir build && cd build
+        cmake .. -DWAMR_BUILD_SIMD=1
+        make -j $(nproc)
         cd .. && rm -rf build
     - name: download and install wabt
       run: |
@@ -96,6 +117,12 @@ jobs:
         mkdir build && cd build
         cmake ..
         make
-        ./hello
-        ./global
         ./callback
+        ./callback_chain
+        ./global
+        ./hello
+        ./hostref
+        ./memory
+        ./reflect
+        ./table
+        ./trap

+ 21 - 0
.github/workflows/windows.yml

@@ -60,4 +60,25 @@ jobs:
         cmake .. -DWAMR_BUILD_CUSTOM_NAME_SECTION=1
         cmake --build . --config Release
         cd .. && rm -force -r build
+    - name: Build iwasm [disable hardware boundary check]
+      run: |
+        cd product-mini/platforms/windows
+        mkdir build && cd build
+        cmake .. -DWAMR_DISABLE_HW_BOUND_CHECK=1
+        cmake --build . --config Release
+        cd .. && rm -force -r build
+    - name: Build iwasm [reference types]
+      run: |
+        cd product-mini/platforms/windows
+        mkdir build && cd build
+        cmake .. -DWAMR_BUILD_REF_TYPES=1
+        cmake --build . --config Release
+        cd .. && rm -force -r build
+    - name: Build iwasm [128-bit SIMD]
+      run: |
+        cd product-mini/platforms/windows
+        mkdir build && cd build
+        cmake .. -DWAMR_BUILD_SIMD=1
+        cmake --build . --config Release
+        cd .. && rm -force -r build
 

+ 1 - 1
README.md

@@ -132,7 +132,7 @@ The WAMR [samples](./samples) integrate the iwasm VM core, application manager a
 
 Project Technical Steering Committee
 ====================================
-The [WAMR PTSC Charter](./TSC_Charter.md) governs the operations of the project TSC. 
+The [WAMR PTSC Charter](./TSC_Charter.md) governs the operations of the project TSC.
 The current TSC members:
 - [lum1n0us](https://github.com/lum1n0us) - **Liang He**, <liang.he@intel.com>
 - [qinxk-inter](https://github.com/qinxk-inter) - **Xiaokang Qin**, <xiaokang.qxk@antgroup.com>

+ 5 - 5
TSC_Charter.md

@@ -2,9 +2,9 @@
 
 ## Section 1. Guiding Principle
 
-The WebAssembly Micro Runtime (WAMR) project is part of the 
-Bytecode Alliance (BA) which operates transparently, openly, 
-collaboratively, and ethically. Project proposals, timelines, and status 
+The WebAssembly Micro Runtime (WAMR) project is part of the
+Bytecode Alliance (BA) which operates transparently, openly,
+collaboratively, and ethically. Project proposals, timelines, and status
 must not merely be open, but also easily visible to outsiders.
 
 ## Section 2. Project Governance under Bytecode Alliance
@@ -17,8 +17,8 @@ there is misalignment between the project charter and the BA mission and values.
 
 
 
-The PTSC structure described in this document may be overhauled as part of 
-establishing a BA TSC in order to adhere to constraints or requirements that 
+The PTSC structure described in this document may be overhauled as part of
+establishing a BA TSC in order to adhere to constraints or requirements that
 TSC will impose on project-level governance.
 
 ## Section 3. Establishment of the PTSC

+ 5 - 2
core/iwasm/aot/aot_runtime.c

@@ -2822,9 +2822,12 @@ aot_table_grow(AOTModuleInstance *module_inst, uint32 tbl_idx,
         return orig_tbl_sz;
     }
 
+    if (tbl_inst->cur_size > UINT32_MAX - inc_entries) {
+        return (uint32)-1;
+    }
+
     entry_count = tbl_inst->cur_size + inc_entries;
-    /* prevent from integer overflow */
-    if (entry_count < tbl_inst->cur_size || entry_count > tbl_inst->max_size) {
+    if (entry_count > tbl_inst->max_size) {
         return (uint32)-1;
     }
 

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 476 - 159
core/iwasm/common/wasm_c_api.c


+ 73 - 5
core/iwasm/common/wasm_c_api_internal.h

@@ -6,7 +6,7 @@
 #ifndef _WASM_C_API_INTERNAL_H
 #define _WASM_C_API_INTERNAL_H
 
-#include "wasm_c_api.h"
+#include "../include/wasm_c_api.h"
 #include "wasm_runtime_common.h"
 
 #ifndef own
@@ -19,9 +19,9 @@
 /* caller needs to take care resource for the vector itself */
 #define DEFAULT_VECTOR_INIT_LENGTH (64)
 
-WASM_DECLARE_VEC(store, *)
-WASM_DECLARE_VEC(module, *)
 WASM_DECLARE_VEC(instance, *)
+WASM_DECLARE_VEC(module, *)
+WASM_DECLARE_VEC(store, *)
 
 /* Runtime Environment */
 struct wasm_engine_t {
@@ -32,6 +32,7 @@ struct wasm_engine_t {
 struct wasm_store_t {
     wasm_module_vec_t *modules;
     wasm_instance_vec_t *instances;
+    Vector *foreigns;
 };
 
 /* Type Representations */
@@ -82,8 +83,25 @@ struct wasm_exporttype_t {
 };
 
 /* Runtime Objects */
+enum wasm_reference_kind {
+    WASM_REF_foreign,
+    WASM_REF_func,
+    WASM_REF_global,
+    WASM_REF_memory,
+    WASM_REF_table,
+};
+
+struct wasm_host_info {
+    void *info;
+    void (*finalizer)(void *);
+};
+
 struct wasm_ref_t {
-    uint32 obj;
+    wasm_store_t *store;
+    enum wasm_reference_kind kind;
+    struct wasm_host_info host_info;
+    uint32 ref_idx_rt;
+    WASMModuleInstanceCommon *inst_comm_rt;
 };
 
 struct wasm_trap_t {
@@ -91,11 +109,22 @@ struct wasm_trap_t {
     Vector *frames;
 };
 
+struct wasm_foreign_t {
+    wasm_store_t *store;
+    enum wasm_reference_kind kind;
+    struct wasm_host_info host_info;
+    int32 ref_cnt;
+    uint32 foreign_idx_rt;
+    WASMModuleInstanceCommon *inst_comm_rt;
+};
+
 struct wasm_func_t {
+    wasm_store_t *store;
     wasm_name_t *module_name;
     wasm_name_t *name;
     uint16 kind;
 
+    struct wasm_host_info host_info;
     wasm_functype_t *type;
 
     bool with_env;
@@ -117,10 +146,12 @@ struct wasm_func_t {
 };
 
 struct wasm_global_t {
+    wasm_store_t *store;
     wasm_name_t *module_name;
     wasm_name_t *name;
     uint16 kind;
 
+    struct wasm_host_info host_info;
     wasm_globaltype_t *type;
     wasm_val_t *init;
     /*
@@ -132,10 +163,12 @@ struct wasm_global_t {
 };
 
 struct wasm_memory_t {
+    wasm_store_t *store;
     wasm_name_t *module_name;
     wasm_name_t *name;
     uint16 kind;
 
+    struct wasm_host_info host_info;
     wasm_memorytype_t *type;
     /*
      * an index in both memory runtime instance lists
@@ -146,10 +179,12 @@ struct wasm_memory_t {
 };
 
 struct wasm_table_t {
+    wasm_store_t *store;
     wasm_name_t *module_name;
     wasm_name_t *name;
     uint16 kind;
 
+    struct wasm_host_info host_info;
     wasm_tabletype_t *type;
     /*
      * an index in both table runtime instance lists
@@ -160,16 +195,49 @@ struct wasm_table_t {
 };
 
 struct wasm_extern_t {
+    wasm_store_t *store;
     wasm_name_t *module_name;
     wasm_name_t *name;
     wasm_externkind_t kind;
-    uint8 data[1];
+    uint8 data[4];
 };
 
 struct wasm_instance_t {
+    wasm_store_t *store;
     wasm_extern_vec_t *imports;
     wasm_extern_vec_t *exports;
+    struct wasm_host_info host_info;
     WASMModuleInstanceCommon *inst_comm_rt;
 };
 
+wasm_ref_t *
+wasm_ref_new_internal(wasm_store_t *store,
+                      enum wasm_reference_kind kind,
+                      uint32 obj_idx_rt,
+                      WASMModuleInstanceCommon *inst_comm_rt);
+
+wasm_foreign_t *
+wasm_foreign_new_internal(wasm_store_t *store,
+                          uint32 foreign_idx_rt,
+                          WASMModuleInstanceCommon *inst_comm_rt);
+
+wasm_func_t *
+wasm_func_new_internal(wasm_store_t *store,
+                       uint16 func_idx_rt,
+                       WASMModuleInstanceCommon *inst_comm_rt);
+
+wasm_global_t *
+wasm_global_new_internal(wasm_store_t *store,
+                         uint16 global_idx_rt,
+                         WASMModuleInstanceCommon *inst_comm_rt);
+
+wasm_memory_t *
+wasm_memory_new_internal(wasm_store_t *store,
+                         uint16 memory_idx_rt,
+                         WASMModuleInstanceCommon *inst_comm_rt);
+
+wasm_table_t *
+wasm_table_new_internal(wasm_store_t *store,
+                        uint16 table_idx_rt,
+                        WASMModuleInstanceCommon *inst_comm_rt);
 #endif /* _WASM_C_API_INTERNAL_H */

+ 30 - 54
core/iwasm/common/wasm_runtime_common.c

@@ -3977,57 +3977,6 @@ wasm_runtime_get_export_table_type(const WASMModuleCommon *module_comm,
       return false;
 }
 
-uint8 *
-wasm_runtime_get_memory_data(const WASMModuleInstanceCommon *module_inst_comm,
-                             uint32 memory_inst_idx)
-{
-#if WASM_ENABLE_INTERP != 0
-    if (module_inst_comm->module_type == Wasm_Module_Bytecode) {
-        WASMModuleInstance *module_inst =
-          (WASMModuleInstance *)module_inst_comm;
-        WASMMemoryInstance *memory_inst =
-          module_inst->memories[memory_inst_idx];
-        return memory_inst->memory_data;
-    }
-#endif
-
-#if WASM_ENABLE_AOT != 0
-    if (module_inst_comm->module_type == Wasm_Module_AoT) {
-        AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm;
-        AOTMemoryInstance *memory_inst =
-          ((AOTMemoryInstance**)module_inst->memories.ptr)[memory_inst_idx];
-        return memory_inst->memory_data.ptr;
-    }
-#endif
-    return NULL;
-}
-
-uint32
-wasm_runtime_get_memory_data_size(
-  const WASMModuleInstanceCommon *module_inst_comm,
-  uint32 memory_inst_idx)
-{
-#if WASM_ENABLE_INTERP != 0
-    if (module_inst_comm->module_type == Wasm_Module_Bytecode) {
-        WASMModuleInstance *module_inst =
-          (WASMModuleInstance *)module_inst_comm;
-        WASMMemoryInstance *memory_inst =
-          module_inst->memories[memory_inst_idx];
-        return memory_inst->cur_page_count * memory_inst->num_bytes_per_page;
-    }
-#endif
-
-#if WASM_ENABLE_AOT != 0
-    if (module_inst_comm->module_type == Wasm_Module_AoT) {
-        AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm;
-        AOTMemoryInstance *memory_inst =
-          ((AOTMemoryInstance**)module_inst->memories.ptr)[memory_inst_idx];
-        return memory_inst->cur_page_count * memory_inst->num_bytes_per_page;
-    }
-#endif
-    return 0;
-}
-
 static inline bool
 argv_to_params(wasm_val_t *out_params,
                const uint32 *argv,
@@ -4058,6 +4007,23 @@ argv_to_params(wasm_val_t *out_params,
                 u32[0] = *argv++;
                 u32[1] = *argv++;
                 break;
+#if WASM_ENABLE_REF_TYPES != 0
+            case VALUE_TYPE_EXTERNREF:
+                param->kind = WASM_ANYREF;
+
+                if (NULL_REF == *argv) {
+                    param->of.ref = NULL;
+                }
+                else {
+                    if (!wasm_externref_ref2obj(*argv,
+                                                (void **)&param->of.ref)) {
+                        return false;
+                    }
+                }
+
+                argv++;
+                break;
+#endif
             default:
                 return false;
         }
@@ -4067,7 +4033,8 @@ argv_to_params(wasm_val_t *out_params,
 }
 
 static inline bool
-results_to_argv(uint32 *out_argv,
+results_to_argv(WASMModuleInstanceCommon *module_inst,
+                uint32 *out_argv,
                 const wasm_val_t *results,
                 WASMType *func_type)
 {
@@ -4087,6 +4054,15 @@ results_to_argv(uint32 *out_argv,
                 *argv++ = u32[0];
                 *argv++ = u32[1];
                 break;
+#if WASM_ENABLE_REF_TYPES != 0
+            case VALUE_TYPE_EXTERNREF:
+                if (!wasm_externref_obj2ref(module_inst, result->of.ref,
+                                            argv)) {
+                    return false;
+                }
+                argv++;
+                break;
+#endif
             default:
                 return false;
         }
@@ -4134,7 +4110,7 @@ wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst,
             char trap_message[128] = { 0 };
             bh_memcpy_s(
               trap_message, 127, trap->message->data,
-              (trap->message->size < 127 ? trap->message->size : 127));
+              (trap->message->size < 127 ? (uint32)trap->message->size : 127));
             wasm_runtime_set_exception(module_inst, trap_message);
         }
         else {
@@ -4152,7 +4128,7 @@ wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst,
         goto fail;
     }
 
-    if (!results_to_argv(argv, results, func_type)) {
+    if (!results_to_argv(module_inst, argv, results, func_type)) {
         wasm_runtime_set_exception(module_inst, "unsupported result type");
         goto fail;
     }

+ 0 - 8
core/iwasm/common/wasm_runtime_common.h

@@ -796,14 +796,6 @@ wasm_runtime_get_export_table_type(const WASMModuleCommon *module_comm,
                                    uint32 *out_min_size,
                                    uint32 *out_max_size);
 
-uint8 *
-wasm_runtime_get_memory_data(const WASMModuleInstanceCommon *module_inst_comm,
-                             uint32 memory_inst_idx);
-
-uint32
-wasm_runtime_get_memory_data_size(const WASMModuleInstanceCommon *module_inst_comm,
-                                  uint32 memory_inst_idx);
-
 bool
 wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst,
                                  void *func_ptr, WASMType *func_type,

+ 2 - 0
core/iwasm/compilation/aot_emit_table.c

@@ -25,6 +25,7 @@ get_tbl_inst_offset(const AOTCompContext *comp_ctx,
 
     while (i < tbl_idx && i < comp_ctx->comp_data->import_table_count) {
         offset += offsetof(AOTTableInstance, data);
+        /* avoid loading from current AOTTableInstance */
         offset += sizeof(uint32) * aot_get_imp_tbl_data_slots(imp_tbls + i);
         ++i;
     }
@@ -37,6 +38,7 @@ get_tbl_inst_offset(const AOTCompContext *comp_ctx,
     i -= comp_ctx->comp_data->import_table_count;
     while (i < tbl_idx && i < comp_ctx->comp_data->table_count) {
         offset += offsetof(AOTTableInstance, data);
+        /* avoid loading from current AOTTableInstance */
         offset += sizeof(uint32) * aot_get_tbl_data_slots(tbls + i);
         ++i;
     }

+ 7 - 0
core/iwasm/include/wasm_c_api.h

@@ -573,6 +573,12 @@ WASM_API_EXTERN own wasm_instance_t* wasm_instance_new(
   own wasm_trap_t**
 );
 
+// please refer to wasm_runtime_instantiate(...) in core/iwasm/include/wasm_export.h
+WASM_API_EXTERN own wasm_instance_t* wasm_instance_new_with_args(
+  wasm_store_t*, const wasm_module_t*, const wasm_extern_t *const imports[],
+  own wasm_trap_t**, const uint32_t stack_size, const uint32_t heap_size
+);
+
 WASM_API_EXTERN void wasm_instance_exports(const wasm_instance_t*, own wasm_extern_vec_t* out);
 
 
@@ -764,6 +770,7 @@ static inline void* wasm_val_ptr(const wasm_val_t* val) {
 #define WASM_REF_VAL(r) {.kind = WASM_ANYREF, .of = {.ref = r}}
 #define WASM_INIT_VAL {.kind = WASM_ANYREF, .of = {.ref = NULL}}
 
+#define KILOBYTE(n) ((n) * 1024)
 
 ///////////////////////////////////////////////////////////////////////////////
 

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

@@ -7881,7 +7881,7 @@ fail_data_cnt_sec_require:
 #if WASM_ENABLE_REF_TYPES != 0
                 case WASM_OP_TABLE_INIT:
                 {
-                    uint8 seg_ref_type, tbl_ref_type;
+                    uint8 seg_ref_type = 0, tbl_ref_type = 0;
 
                     if (!wasm_get_ref_types_flag()) {
                         goto unsupported_opcode;

+ 25 - 13
core/iwasm/interpreter/wasm_runtime.c

@@ -476,9 +476,11 @@ tables_instantiate(const WASMModule *module,
     /* instantiate tables from import section */
     import = module->import_tables;
     for (i = 0; i < module->import_table_count; i++, import++) {
+        uint32 max_size_fixed = 0;
 #if WASM_ENABLE_MULTI_MODULE != 0
         WASMTableInstance *table_inst_linked = NULL;
         WASMModuleInstance *module_inst_linked = NULL;
+
         if (import->u.table.import_module) {
             if (!(module_inst_linked =
               get_sub_module_inst(module_inst, import->u.table.import_module))) {
@@ -499,12 +501,14 @@ tables_instantiate(const WASMModule *module,
         else
 #endif
         {
+            /* in order to save memory, alloc resource as few as possible */
+            max_size_fixed = import->u.table.possible_grow
+                               ? import->u.table.max_size
+                               : import->u.table.init_size;
+
             /* it is a built-in table, every module has its own */
             total_size = offsetof(WASMTableInstance, base_addr);
-            total_size +=
-              import->u.table.possible_grow
-                ? sizeof(uint32) * (uint64)import->u.table.max_size
-                : sizeof(uint32) * (uint64)import->u.table.init_size;
+            total_size += (uint64)max_size_fixed * sizeof(uint32);
         }
 
         if (!(table = tables[table_index++] = runtime_malloc
@@ -515,6 +519,7 @@ tables_instantiate(const WASMModule *module,
 
         /* Set all elements to -1 to mark them as uninitialized elements */
         memset(table, -1, (uint32)total_size);
+
 #if WASM_ENABLE_MULTI_MODULE != 0
         table->table_inst_linked = table_inst_linked;
         if (table_inst_linked != NULL) {
@@ -527,21 +532,26 @@ tables_instantiate(const WASMModule *module,
         {
             table->elem_type = import->u.table.elem_type;
             table->cur_size = import->u.table.init_size;
-            table->max_size = import->u.table.max_size;
+            table->max_size = max_size_fixed;
         }
     }
 
     /* instantiate tables from table section */
     for (i = 0; i < module->table_count; i++) {
+        uint32 max_size_fixed = 0;
+
         total_size = offsetof(WASMTableInstance, base_addr);
 #if WASM_ENABLE_MULTI_MODULE != 0
         /* in case, a module which imports this table will grow it */
-        total_size += sizeof(uint32) * (uint64)module->tables[i].max_size;
+        max_size_fixed = module->tables[i].max_size;
 #else
-        total_size += module->tables[i].possible_grow
-                        ? sizeof(uint32) * (uint64)module->tables[i].max_size
-                        : sizeof(uint32) * (uint64)module->tables[i].init_size;
+        max_size_fixed =
+          module->tables[i].possible_grow
+            ? module->tables[i].max_size
+            : module->tables[i].init_size;
 #endif
+        total_size += sizeof(uint32) * (uint64)max_size_fixed;
+
         if (!(table = tables[table_index++] = runtime_malloc
                     (total_size, error_buf, error_buf_size))) {
             tables_deinstantiate(tables, table_count);
@@ -552,7 +562,7 @@ tables_instantiate(const WASMModule *module,
         memset(table, -1, (uint32)total_size);
         table->elem_type = module->tables[i].elem_type;
         table->cur_size = module->tables[i].init_size;
-        table->max_size = module->tables[i].max_size;
+        table->max_size = max_size_fixed;
 #if WASM_ENABLE_MULTI_MODULE != 0
         table->table_inst_linked = NULL;
 #endif
@@ -2150,10 +2160,12 @@ wasm_enlarge_table(WASMModuleInstance *module_inst,
         return false;
     }
 
+    if (inc_entries > UINT32_MAX - table_inst->cur_size) {
+        return false;
+    }
+
     entry_count = table_inst->cur_size + inc_entries;
-    /* prevent from integer overflow */
-    if (entry_count < table_inst->cur_size
-        || entry_count > table_inst->max_size) {
+    if (entry_count > table_inst->max_size) {
         return false;
     }
 

+ 0 - 1
core/iwasm/interpreter/wasm_runtime.h

@@ -456,4 +456,3 @@ wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env);
 #endif
 
 #endif /* end of _WASM_RUNTIME_H */
-

+ 7 - 40
doc/wasm_c_api.md

@@ -12,59 +12,26 @@ them in next releases.
 
 a summary of unsupported APIs
 
-- Configuration
-
-``` c
-WASM_API_EXTERN own wasm_config_t* wasm_config_new(void);
-```
-
 - References
 
 ``` c
-WASM_API_EXTERN bool wasm_##name##_same(const wasm_##name##_t*, const wasm_##name##_t*); \
-WASM_API_EXTERN void* wasm_##name##_get_host_info(const wasm_##name##_t*); \
-WASM_API_EXTERN void wasm_##name##_set_host_info(wasm_##name##_t*, void*); \
-WASM_API_EXTERN void wasm_##name##_set_host_info_with_finalizer( \
-WASM_API_EXTERN wasm_ref_t* wasm_##name##_as_ref(wasm_##name##_t*); \
-WASM_API_EXTERN wasm_##name##_t* wasm_ref_as_##name(wasm_ref_t*); \
-WASM_API_EXTERN const wasm_ref_t* wasm_##name##_as_ref_const(const wasm_##name##_t*); \
-WASM_API_EXTERN const wasm_##name##_t* wasm_ref_as_##name##_const(const wasm_ref_t*);
-WASM_API_EXTERN own wasm_shared_##name##_t* wasm_##name##_share(const wasm_##name##_t*); \
+WASM_API_EXTERN own wasm_shared_##name##_t* wasm_##name##_share(const wasm_##name##_t*);
 WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_obtain(wasm_store_t*, const wasm_shared_##name##_t*);
 ```
 
-- Frames
-
-``` c
-WASM_API_EXTERN own wasm_frame_t* wasm_frame_copy(const wasm_frame_t*);
-WASM_API_EXTERN struct wasm_instance_t* wasm_frame_instance(const wasm_frame_t*);
-WASM_API_EXTERN uint32_t wasm_frame_func_index(const wasm_frame_t*);
-WASM_API_EXTERN size_t wasm_frame_func_offset(const wasm_frame_t*);
-WASM_API_EXTERN size_t wasm_frame_module_offset(const wasm_frame_t*);
-WASM_API_EXTERN own wasm_frame_t* wasm_trap_origin(const wasm_trap_t*);
-WASM_API_EXTERN void wasm_trap_trace(const wasm_trap_t*, own wasm_frame_vec_t* out);
-```
-
- Foreign Objects
-
-``` c
-WASM_API_EXTERN own wasm_foreign_t* wasm_foreign_new(wasm_store_t*);
-```
-
 - Several Module APIs
 
 ``` c
-WASM_API_EXTERN bool wasm_module_validate(wasm_store_t*, const wasm_byte_vec_t* binary);
-WASM_API_EXTERN void wasm_module_serialize(const wasm_module_t*, own wasm_byte_vec_t* out);
 WASM_API_EXTERN void wasm_module_serialize(const wasm_module_t*, own wasm_byte_vec_t* out);
+WASM_API_EXTERN own wasm_module_t* wasm_module_deserialize(wasm_store_t*, const wasm_byte_vec_t*);
 ```
 
-- Table Operations APIs
+we tend to grow a table or a memory by opcode only and not support growing both
+by host-side function callings.
+
+- Table Grow APIs
 
 ``` c
-WASM_API_EXTERN own wasm_ref_t* wasm_table_get(const wasm_table_t*, wasm_table_size_t index);
-WASM_API_EXTERN bool wasm_table_set(wasm_table_t*, wasm_table_size_t index, wasm_ref_t*);
-WASM_API_EXTERN wasm_table_size_t wasm_table_size(const wasm_table_t*);
 WASM_API_EXTERN bool wasm_table_grow(wasm_table_t*, wasm_table_size_t delta, wasm_ref_t* init);
 ```
 
@@ -72,4 +39,4 @@ WASM_API_EXTERN bool wasm_table_grow(wasm_table_t*, wasm_table_size_t delta, was
 
 ``` c
 WASM_API_EXTERN bool wasm_memory_grow(wasm_memory_t*, wasm_memory_pages_t delta);
-```
+```

+ 8 - 4
samples/wasm-c-api/CMakeLists.txt

@@ -42,6 +42,7 @@ set(WAMR_BUILD_LIBC_BUILTIN 1)
 set(WAMR_BUILD_LIBC_WASI 0)
 set(WAMR_BUILD_MULTI_MODULE 1)
 set(WAMR_BUILD_DUMP_CALL_STACK 1)
+set(WAMR_BUILD_REF_TYPES 1)
 
 if(NOT DEFINED WAMR_BUILD_FAST_INTERP)
   set(WAMR_BUILD_FAST_INTERP 1)
@@ -101,12 +102,15 @@ include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
 set(MM_UTIL src/utils/multi_module_utils.c)
 # build executable for each .c
 set(EXAMPLES
-  hello
   callback
+  callback_chain
   global
+  hello
+  hostref
+  memory
   reflect
+  table
   trap
-  callback_chain
 )
 
 foreach(EX ${EXAMPLES})
@@ -123,7 +127,7 @@ foreach(EX ${EXAMPLES})
   set(WAT ${CMAKE_CURRENT_LIST_DIR}/src/${EX}.wat)
 
   add_custom_target(${EX}_WASM
-    COMMAND ${WAT2WASM} ${WAT} -o ${PROJECT_BINARY_DIR}/${EX}.wasm
+    COMMAND ${WAT2WASM} ${WAT} --enable-reference-types -o ${PROJECT_BINARY_DIR}/${EX}.wasm
     DEPENDS ${WAT}
     BYPRODUCTS ${PROJECT_BINARY_DIR}/${EX}.wasm
     VERBATIM
@@ -133,7 +137,7 @@ foreach(EX ${EXAMPLES})
   # generate .aot file
   if(${WAMR_BUILD_AOT} EQUAL 1)
     add_custom_target(${EX}_AOT
-      COMMAND ${WAMRC} -o ${PROJECT_BINARY_DIR}/${EX}.aot
+      COMMAND ${WAMRC} --enable-ref-types -o ${PROJECT_BINARY_DIR}/${EX}.aot
         ${PROJECT_BINARY_DIR}/${EX}.wasm
       DEPENDS ${EX}_WASM
       BYPRODUCTS ${PROJECT_BINARY_DIR}/${EX}.aot

+ 263 - 0
samples/wasm-c-api/src/hostref.c

@@ -0,0 +1,263 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "wasm_c_api.h"
+
+#define own
+
+
+// A function to be called from Wasm code.
+own wasm_trap_t* callback(
+  const wasm_val_t args[], wasm_val_t results[]
+) {
+  printf("Calling back...\n> ");
+  printf("> %p\n",
+    args[0].of.ref ? wasm_ref_get_host_info(args[0].of.ref) : NULL);
+  wasm_val_copy(&results[0], &args[0]);
+  return NULL;
+}
+
+
+wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) {
+  if (exports->size <= i || !wasm_extern_as_func(exports->data[i])) {
+    printf("> Error accessing function export %zu!\n", i);
+    exit(1);
+  }
+  return wasm_extern_as_func(exports->data[i]);
+}
+
+wasm_global_t* get_export_global(const wasm_extern_vec_t* exports, size_t i) {
+  if (exports->size <= i || !wasm_extern_as_global(exports->data[i])) {
+    printf("> Error accessing global export %zu!\n", i);
+    exit(1);
+  }
+  return wasm_extern_as_global(exports->data[i]);
+}
+
+wasm_table_t* get_export_table(const wasm_extern_vec_t* exports, size_t i) {
+  if (exports->size <= i || !wasm_extern_as_table(exports->data[i])) {
+    printf("> Error accessing table export %zu!\n", i);
+    exit(1);
+  }
+  return wasm_extern_as_table(exports->data[i]);
+}
+
+
+own wasm_ref_t* call_v_r(const wasm_func_t* func) {
+  printf("call_v_r... "); fflush(stdout);
+  wasm_val_t rs[] = { WASM_INIT_VAL };
+  if (wasm_func_call(func, NULL, rs)) {
+    printf("> Error calling function!\n");
+    exit(1);
+  }
+  printf("okay\n");
+  return rs[0].of.ref;
+}
+
+void call_r_v(const wasm_func_t* func, wasm_ref_t* ref) {
+  printf("call_r_v... "); fflush(stdout);
+  wasm_val_t vs[1] = { WASM_REF_VAL(ref) };
+  if (wasm_func_call(func, vs, NULL)) {
+    printf("> Error calling function!\n");
+    exit(1);
+  }
+  printf("okay\n");
+}
+
+own wasm_ref_t* call_r_r(const wasm_func_t* func, wasm_ref_t* ref) {
+  printf("call_r_r... "); fflush(stdout);
+  wasm_val_t vs[1] = { WASM_REF_VAL(ref) };
+  wasm_val_t rs[1] = { WASM_INIT_VAL };
+  if (wasm_func_call(func, vs, rs)) {
+    printf("> Error calling function!\n");
+    exit(1);
+  }
+  printf("okay\n");
+  return rs[0].of.ref;
+}
+
+void call_ir_v(const wasm_func_t* func, int32_t i, wasm_ref_t* ref) {
+  printf("call_ir_v... "); fflush(stdout);
+  wasm_val_t vs[2] = { WASM_I32_VAL(i), WASM_REF_VAL(ref) };
+  if (wasm_func_call(func, vs, NULL)) {
+    printf("> Error calling function!\n");
+    exit(1);
+  }
+  printf("okay\n");
+}
+
+own wasm_ref_t* call_i_r(const wasm_func_t* func, int32_t i) {
+  printf("call_i_r... "); fflush(stdout);
+  wasm_val_t vs[1] = { WASM_I32_VAL(i) };
+  wasm_val_t rs[1] = { WASM_INIT_VAL };
+  if (wasm_func_call(func, vs, rs)) {
+    printf("> Error calling function!\n");
+    exit(1);
+  }
+  printf("okay\n");
+  return rs[0].of.ref;
+}
+
+void
+check(own wasm_ref_t *actual, const wasm_ref_t *expected, bool release_ref)
+{
+    if (actual != expected
+        && !(actual && expected && wasm_ref_same(actual, expected))) {
+        printf("> Error reading reference, expected %p, got %p\n",
+               expected ? wasm_ref_get_host_info(expected) : NULL,
+               actual ? wasm_ref_get_host_info(actual) : NULL);
+        exit(1);
+    }
+    if (release_ref && actual)
+        wasm_ref_delete(actual);
+}
+
+int main(int argc, const char* argv[]) {
+  // Initialize.
+  printf("Initializing...\n");
+  wasm_engine_t* engine = wasm_engine_new();
+  wasm_store_t* store = wasm_store_new(engine);
+
+  // Load binary.
+  printf("Loading binary...\n");
+#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0
+  FILE* file = fopen("hostref.aot", "rb");
+#else
+  FILE* file = fopen("hostref.wasm", "rb");
+#endif
+  if (!file) {
+    printf("> Error loading module!\n");
+    return 1;
+  }
+  fseek(file, 0L, SEEK_END);
+  size_t file_size = ftell(file);
+  fseek(file, 0L, SEEK_SET);
+  wasm_byte_vec_t binary;
+  wasm_byte_vec_new_uninitialized(&binary, file_size);
+  if (fread(binary.data, file_size, 1, file) != 1) {
+    printf("> Error loading module!\n");
+    fclose(file);
+    return 1;
+  }
+  fclose(file);
+
+  // Compile.
+  printf("Compiling module...\n");
+  own wasm_module_t* module = wasm_module_new(store, &binary);
+  if (!module) {
+    printf("> Error compiling module!\n");
+    return 1;
+  }
+
+  wasm_byte_vec_delete(&binary);
+
+  // Create external callback function.
+  printf("Creating callback...\n");
+  own wasm_functype_t* callback_type = wasm_functype_new_1_1(
+    wasm_valtype_new(WASM_ANYREF), wasm_valtype_new(WASM_ANYREF));
+  own wasm_func_t* callback_func =
+    wasm_func_new(store, callback_type, callback);
+
+  wasm_functype_delete(callback_type);
+
+  // Instantiate.
+  printf("Instantiating module...\n");
+  const wasm_extern_t* imports[] = { wasm_func_as_extern(callback_func) };
+  own wasm_instance_t* instance =
+    wasm_instance_new(store, module, imports, NULL);
+  if (!instance) {
+    printf("> Error instantiating module!\n");
+    return 1;
+  }
+
+  wasm_func_delete(callback_func);
+  wasm_module_delete(module);
+
+  // Extract export.
+  printf("Extracting exports...\n");
+  own wasm_extern_vec_t exports;
+  wasm_instance_exports(instance, &exports);
+  size_t i = 0;
+  wasm_global_t* global = get_export_global(&exports, i++);
+  wasm_table_t* table = get_export_table(&exports, i++);
+  wasm_func_t* global_set = get_export_func(&exports, i++);
+  wasm_func_t* global_get = get_export_func(&exports, i++);
+  wasm_func_t* table_set = get_export_func(&exports, i++);
+  wasm_func_t* table_get = get_export_func(&exports, i++);
+  wasm_func_t* func_call = get_export_func(&exports, i++);
+
+  wasm_instance_delete(instance);
+
+  // Create host references.
+  printf("Creating host references...\n");
+  own wasm_ref_t* host1 = wasm_foreign_as_ref(wasm_foreign_new(store));
+  own wasm_ref_t* host2 = wasm_foreign_as_ref(wasm_foreign_new(store));
+  wasm_ref_set_host_info(host1, (void*)1);
+  wasm_ref_set_host_info(host2, (void*)2);
+
+  // Some sanity checks.
+  check(NULL, NULL, true);
+  check(wasm_ref_copy(host1), host1, true);
+  check(wasm_ref_copy(host2), host2, true);
+
+  own wasm_val_t val;
+  val.kind = WASM_ANYREF;
+  val.of.ref = wasm_ref_copy(host1);
+  check(wasm_ref_copy(val.of.ref), host1, true);
+  own wasm_ref_t* ref = val.of.ref;
+  check(wasm_ref_copy(ref), host1, true);
+  wasm_ref_delete(val.of.ref);
+
+  // Interact.
+  printf("Accessing global...\n");
+  check(call_v_r(global_get), NULL, false);
+  call_r_v(global_set, host1);
+  check(call_v_r(global_get), host1, false);
+  call_r_v(global_set, host2);
+  check(call_v_r(global_get), host2, false);
+  call_r_v(global_set, NULL);
+  check(call_v_r(global_get), NULL, false);
+
+  wasm_global_get(global, &val);
+  assert(val.kind == WASM_ANYREF);
+  check(val.of.ref, NULL, false);
+  val.of.ref = host2;
+  wasm_global_set(global, &val);
+  check(call_v_r(global_get), host2, false);
+  wasm_global_get(global, &val);
+  assert(val.kind == WASM_ANYREF);
+  check(val.of.ref, host2, false);
+
+  printf("Accessing table...\n");
+  check(call_i_r(table_get, 0), NULL, false);
+  check(call_i_r(table_get, 1), NULL, false);
+  call_ir_v(table_set, 0, host1);
+  call_ir_v(table_set, 1, host2);
+  check(call_i_r(table_get, 0), host1, false);
+  check(call_i_r(table_get, 1), host2, false);
+  call_ir_v(table_set, 0, NULL);
+  check(call_i_r(table_get, 0), NULL, false);
+
+  check(wasm_table_get(table, 2), NULL, false);
+
+  printf("Accessing function...\n");
+  check(call_r_r(func_call, NULL), NULL, false);
+  check(call_r_r(func_call, host1), host1, false);
+  check(call_r_r(func_call, host2), host2, false);
+
+  wasm_ref_delete(host1);
+  wasm_ref_delete(host2);
+
+  wasm_extern_vec_delete(&exports);
+
+  // Shut down.
+  printf("Shutting down...\n");
+  wasm_store_delete(store);
+  wasm_engine_delete(engine);
+
+  // All done.
+  printf("Done.\n");
+  return 0;
+}

+ 24 - 0
samples/wasm-c-api/src/hostref.wat

@@ -0,0 +1,24 @@
+(module
+  (import "" "f" (func $fun (param externref) (result externref)))
+
+  (global $glob (export "global") (mut externref) (ref.null extern))
+  (table $tab (export "table") 10 externref)
+
+  (func (export "global.set") (param $r externref)
+    (global.set $glob (local.get $r))
+  )
+  (func (export "global.get") (result externref)
+    (global.get $glob)
+  )
+
+  (func (export "table.set") (param $i i32) (param $r externref)
+    (table.set $tab (local.get $i) (local.get $r))
+  )
+  (func (export "table.get") (param $i i32) (result externref)
+    (table.get $tab (local.get $i))
+  )
+
+  (func (export "func.call") (param $r externref) (result externref)
+    (call $fun (local.get $r))
+  )
+)

+ 209 - 0
samples/wasm-c-api/src/memory.c

@@ -0,0 +1,209 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "wasm_c_api.h"
+
+#define own
+
+
+wasm_memory_t* get_export_memory(const wasm_extern_vec_t* exports, size_t i) {
+  if (exports->size <= i || !wasm_extern_as_memory(exports->data[i])) {
+    printf("> Error accessing memory export %zu!\n", i);
+    exit(1);
+  }
+  return wasm_extern_as_memory(exports->data[i]);
+}
+
+wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) {
+  if (exports->size <= i || !wasm_extern_as_func(exports->data[i])) {
+    printf("> Error accessing function export %zu!\n", i);
+    exit(1);
+  }
+  return wasm_extern_as_func(exports->data[i]);
+}
+
+
+void check(bool success) {
+  if (!success) {
+    printf("> Error, expected success\n");
+    exit(1);
+  }
+}
+
+void check_call(wasm_func_t* func, int i, wasm_val_t args[], int32_t expected) {
+  wasm_val_t results[1] = { WASM_INIT_VAL };
+  if (wasm_func_call(func, args, results) || results[0].of.i32 != expected) {
+    printf("> Error on result\n");
+    exit(1);
+  }
+}
+
+void check_call0(wasm_func_t* func, int32_t expected) {
+  check_call(func, 0, NULL, expected);
+}
+
+void check_call1(wasm_func_t* func, int32_t arg, int32_t expected) {
+  wasm_val_t args[] = { WASM_I32_VAL(arg) };
+  check_call(func, 1, args, expected);
+}
+
+void check_call2(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected) {
+  wasm_val_t args[] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) };
+  check_call(func, 2, args, expected);
+}
+
+void check_ok(wasm_func_t* func, int i, wasm_val_t args[]) {
+  if (wasm_func_call(func, args, NULL)) {
+    printf("> Error on result, expected empty\n");
+    exit(1);
+  }
+}
+
+void check_ok2(wasm_func_t* func, int32_t arg1, int32_t arg2) {
+  wasm_val_t args[] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) };
+  check_ok(func, 2, args);
+}
+
+void check_trap(wasm_func_t* func, int i, wasm_val_t args[]) {
+  wasm_val_t results[1] = { WASM_INIT_VAL };
+  own wasm_trap_t* trap = wasm_func_call(func, args, results);
+  if (! trap) {
+    printf("> Error on result, expected trap\n");
+    exit(1);
+  }
+  wasm_trap_delete(trap);
+}
+
+void check_trap1(wasm_func_t* func, int32_t arg) {
+  wasm_val_t args[] = { WASM_I32_VAL(arg) };
+  check_trap(func, 1, args);
+}
+
+void check_trap2(wasm_func_t* func, int32_t arg1, int32_t arg2) {
+  wasm_val_t args[] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) };
+  check_trap(func, 2, args);
+}
+
+
+int main(int argc, const char* argv[]) {
+  // Initialize.
+  printf("Initializing...\n");
+  wasm_engine_t* engine = wasm_engine_new();
+  wasm_store_t* store = wasm_store_new(engine);
+
+  // Load binary.
+  printf("Loading binary...\n");
+#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0
+  FILE* file = fopen("memory.aot", "rb");
+#else
+  FILE* file = fopen("memory.wasm", "rb");
+#endif
+  if (!file) {
+    printf("> Error loading module!\n");
+    return 1;
+  }
+  fseek(file, 0L, SEEK_END);
+  size_t file_size = ftell(file);
+  fseek(file, 0L, SEEK_SET);
+  wasm_byte_vec_t binary;
+  wasm_byte_vec_new_uninitialized(&binary, file_size);
+  if (fread(binary.data, file_size, 1, file) != 1) {
+    printf("> Error loading module!\n");
+    fclose(file);
+    return 1;
+  }
+  fclose(file);
+
+  // Compile.
+  printf("Compiling module...\n");
+  own wasm_module_t* module = wasm_module_new(store, &binary);
+  if (!module) {
+    printf("> Error compiling module!\n");
+    return 1;
+  }
+
+  wasm_byte_vec_delete(&binary);
+
+  // Instantiate.
+  printf("Instantiating module...\n");
+  own wasm_instance_t* instance =
+    wasm_instance_new_with_args(store, module, NULL, NULL, KILOBYTE(8), 0);
+  if (!instance) {
+    printf("> Error instantiating module!\n");
+    return 1;
+  }
+
+  // Extract export.
+  printf("Extracting exports...\n");
+  own wasm_extern_vec_t exports;
+  wasm_instance_exports(instance, &exports);
+  size_t i = 0;
+  wasm_memory_t* memory = get_export_memory(&exports, i++);
+  wasm_func_t* size_func = get_export_func(&exports, i++);
+  wasm_func_t* load_func = get_export_func(&exports, i++);
+  wasm_func_t* store_func = get_export_func(&exports, i++);
+
+  wasm_module_delete(module);
+
+  if (!memory || !wasm_memory_data(memory)) {
+    printf("> Error getting memory!\n");
+    wasm_extern_vec_delete(&exports);
+    wasm_instance_delete(instance);
+    wasm_store_delete(store);
+    wasm_engine_delete(engine);
+    return 1;
+  }
+
+  // Try cloning.
+  own wasm_memory_t* copy = wasm_memory_copy(memory);
+  assert(wasm_memory_same(memory, copy));
+  wasm_memory_delete(copy);
+
+  // Check initial memory.
+  printf("Checking memory...\n");
+  check(wasm_memory_size(memory) >= 2);
+  check(wasm_memory_data_size(memory) >= 0x20000);
+  check(wasm_memory_data(memory)[0] == 0);
+  check(wasm_memory_data(memory)[0x1000] == 1);
+  check(wasm_memory_data(memory)[0x1003] == 4);
+
+  (void)size_func;
+  check_call1(load_func, 0, 0);
+  check_call1(load_func, 0x1000, 1);
+  check_call1(load_func, 0x1003, 4);
+  check_call1(load_func, 0x1ffff, 0);
+  check_trap1(load_func, 0x20000);
+
+  // Mutate memory.
+  printf("Mutating memory...\n");
+  wasm_memory_data(memory)[0x1003] = 5;
+  check_ok2(store_func, 0x1002, 6);
+  check_trap2(store_func, 0x20000, 0);
+
+  check(wasm_memory_data(memory)[0x1002] == 6);
+  check(wasm_memory_data(memory)[0x1003] == 5);
+  check_call1(load_func, 0x1002, 6);
+  check_call1(load_func, 0x1003, 5);
+
+  // Grow memory.
+  // DO NOT SUPPORT
+  printf("Bypass Growing memory...\n");
+  wasm_extern_vec_delete(&exports);
+  wasm_instance_delete(instance);
+
+  // Create stand-alone memory.
+  // DO NOT SUPPORT
+  // TODO(wasm+): Once Wasm allows multiple memories, turn this into import.
+  printf("Bypass Creating stand-alone memory...\n");
+
+  // Shut down.
+  printf("Shutting down...\n");
+  wasm_store_delete(store);
+  wasm_engine_delete(engine);
+
+  // All done.
+  printf("Done.\n");
+  return 0;
+}

+ 11 - 0
samples/wasm-c-api/src/memory.wat

@@ -0,0 +1,11 @@
+(module
+  (memory (export "memory") 2 3)
+
+  (func (export "size") (result i32) (memory.size))
+  (func (export "load") (param i32) (result i32) (i32.load8_s (local.get 0)))
+  (func (export "store") (param i32 i32)
+    (i32.store8 (local.get 0) (local.get 1))
+  )
+
+  (data (i32.const 0x1000) "\01\02\03\04")
+)

+ 182 - 0
samples/wasm-c-api/src/table.c

@@ -0,0 +1,182 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "wasm_c_api.h"
+
+#define own
+
+// A function to be called from Wasm code.
+own wasm_trap_t* neg_callback(
+  const wasm_val_t args[], wasm_val_t results[]
+) {
+  printf("Calling back...\n");
+  results[0].kind = WASM_I32;
+  results[0].of.i32 = -args[0].of.i32;
+  return NULL;
+}
+
+
+wasm_table_t* get_export_table(const wasm_extern_vec_t* exports, size_t i) {
+  if (exports->size <= i || !wasm_extern_as_table(exports->data[i])) {
+    printf("> Error accessing table export %zu!\n", i);
+    exit(1);
+  }
+  return wasm_extern_as_table(exports->data[i]);
+}
+
+wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) {
+  if (exports->size <= i || !wasm_extern_as_func(exports->data[i])) {
+    printf("> Error accessing function export %zu!\n", i);
+    exit(1);
+  }
+  return wasm_extern_as_func(exports->data[i]);
+}
+
+
+void check(bool success) {
+  if (!success) {
+    printf("> Error, expected success\n");
+    exit(1);
+  }
+}
+
+void check_table(wasm_table_t* table, int32_t i, bool expect_set) {
+  own wasm_ref_t* ref = wasm_table_get(table, i);
+  check((ref != NULL) == expect_set);
+  if (ref) wasm_ref_delete(ref);
+}
+
+void check_call(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected) {
+  wasm_val_t args[2] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) };
+  wasm_val_t results[1] = { WASM_INIT_VAL };
+  if (wasm_func_call(func, args, results) || results[0].of.i32 != expected) {
+    printf("> Error on result\n");
+    exit(1);
+  }
+}
+
+void check_trap(wasm_func_t* func, int32_t arg1, int32_t arg2) {
+  wasm_val_t args[2] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) };
+  wasm_val_t results[1] = { WASM_INIT_VAL };
+  own wasm_trap_t* trap = wasm_func_call(func, args, results);
+  if (! trap) {
+    printf("> Error on result, expected trap\n");
+    exit(1);
+  }
+  wasm_trap_delete(trap);
+}
+
+
+int main(int argc, const char* argv[]) {
+  // Initialize.
+  printf("Initializing...\n");
+  wasm_engine_t* engine = wasm_engine_new();
+  wasm_store_t* store = wasm_store_new(engine);
+
+  // Load binary.
+  printf("Loading binary...\n");
+#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0
+  FILE* file = fopen("table.aot", "rb");
+#else
+  FILE* file = fopen("table.wasm", "rb");
+#endif
+  if (!file) {
+    printf("> Error loading module!\n");
+    return 1;
+  }
+  fseek(file, 0L, SEEK_END);
+  size_t file_size = ftell(file);
+  fseek(file, 0L, SEEK_SET);
+  wasm_byte_vec_t binary;
+  wasm_byte_vec_new_uninitialized(&binary, file_size);
+  if (fread(binary.data, file_size, 1, file) != 1) {
+    printf("> Error loading module!\n");
+    fclose(file);
+    return 1;
+  }
+  fclose(file);
+
+  // Compile.
+  printf("Compiling module...\n");
+  own wasm_module_t* module = wasm_module_new(store, &binary);
+  if (!module) {
+    printf("> Error compiling module!\n");
+    return 1;
+  }
+
+  wasm_byte_vec_delete(&binary);
+
+  // Instantiate.
+  printf("Instantiating module...\n");
+  own wasm_instance_t *instance =
+    wasm_instance_new(store, module, NULL, NULL);
+  if (!instance) {
+    printf("> Error instantiating module!\n");
+    return 1;
+  }
+
+  // Extract export.
+  printf("Extracting exports...\n");
+  own wasm_extern_vec_t exports;
+  wasm_instance_exports(instance, &exports);
+  size_t i = 0;
+  wasm_table_t* table = get_export_table(&exports, i++);
+  wasm_func_t* call_indirect = get_export_func(&exports, i++);
+  wasm_func_t* f = get_export_func(&exports, i++);
+  wasm_func_t* g = get_export_func(&exports, i++);
+
+  wasm_module_delete(module);
+
+  // Create external function.
+  printf("Creating callback...\n");
+  own wasm_functype_t* neg_type = wasm_functype_new_1_1(wasm_valtype_new_i32(), wasm_valtype_new_i32());
+
+  wasm_functype_delete(neg_type);
+
+  // Try cloning.
+  own wasm_table_t* copy = wasm_table_copy(table);
+  assert(wasm_table_same(table, copy));
+  wasm_table_delete(copy);
+
+  // Check initial table.
+  printf("Checking table...\n");
+  check(wasm_table_size(table) == 2);
+  check_table(table, 0, false);
+  check_table(table, 1, true);
+  check_trap(call_indirect, 0, 0);
+  check_call(call_indirect, 7, 1, 7);
+  check_trap(call_indirect, 0, 2);
+
+  // Mutate table.
+  printf("Mutating table...\n");
+  check(wasm_table_set(table, 0, wasm_func_as_ref(g)));
+  check(wasm_table_set(table, 1, NULL));
+  check(! wasm_table_set(table, 2, wasm_func_as_ref(f)));
+  check_table(table, 0, true);
+  check_table(table, 1, false);
+  check_call(call_indirect, 7, 0, 666);
+  check_trap(call_indirect, 0, 1);
+  check_trap(call_indirect, 0, 2);
+
+  // Grow table.
+  // DO NOT SUPPORT
+  printf("Bypass Growing table...\n");
+  wasm_extern_vec_delete(&exports);
+  wasm_instance_delete(instance);
+
+  // Create stand-alone table.
+  // DO NOT SUPPORT
+  // TODO(wasm+): Once Wasm allows multiple tables, turn this into import.
+  printf("Bypass Creating stand-alone table...\n");
+
+  // Shut down.
+  printf("Shutting down...\n");
+  wasm_store_delete(store);
+  wasm_engine_delete(engine);
+
+  // All done.
+  printf("Done.\n");
+  return 0;
+}

+ 12 - 0
samples/wasm-c-api/src/table.wat

@@ -0,0 +1,12 @@
+(module
+  (table (export "table") 2 10 funcref)
+
+  (func (export "call_indirect") (param i32 i32) (result i32)
+    (call_indirect (param i32) (result i32) (local.get 0) (local.get 1))
+  )
+
+  (func $f (export "f") (param i32) (result i32) (local.get 0))
+  (func (export "g") (param i32) (result i32) (i32.const 666))
+
+  (elem (i32.const 1) $f)
+)

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است