Quellcode durchsuchen

Merge branch main into dev/wasi_threads

Wenyong Huang vor 3 Jahren
Ursprung
Commit
c7141894fb
52 geänderte Dateien mit 1146 neuen und 336 gelöschten Zeilen
  1. 3 0
      .github/workflows/build_wamr_vscode_ext.yml
  2. 10 4
      .github/workflows/compilation_on_android_ubuntu.yml
  3. 1 0
      .github/workflows/release_process.yml
  4. 155 39
      core/app-framework/app-native-shared/attr_container.c
  5. 176 4
      core/app-framework/app-native-shared/bi-inc/attr_container.h
  6. 3 0
      core/iwasm/aot/aot_loader.c
  7. 29 35
      core/iwasm/aot/aot_runtime.c
  8. 1 0
      core/iwasm/common/wasm_c_api.c
  9. 3 0
      core/iwasm/common/wasm_exec_env.c
  10. 58 8
      core/iwasm/common/wasm_runtime_common.c
  11. 1 0
      core/iwasm/compilation/aot.h
  12. 39 60
      core/iwasm/compilation/aot_emit_conversion.c
  13. 1 33
      core/iwasm/interpreter/wasm_interp_classic.c
  14. 1 1
      core/iwasm/interpreter/wasm_interp_fast.c
  15. 14 25
      core/iwasm/interpreter/wasm_runtime.c
  16. 1 3
      core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c
  17. 1 3
      core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c
  18. 154 55
      core/iwasm/libraries/thread-mgr/thread_manager.c
  19. 13 7
      core/iwasm/libraries/thread-mgr/thread_manager.h
  20. 110 4
      core/shared/platform/nuttx/nuttx_platform.c
  21. 1 0
      core/shared/platform/windows/platform_internal.h
  22. 29 17
      core/shared/platform/windows/win_thread.c
  23. 135 0
      doc/memory_usage.md
  24. 7 1
      language-bindings/go/build.sh
  25. 1 0
      language-bindings/go/go.sum
  26. 6 0
      language-bindings/go/wamr/packaged/lib/darwin-aarch64/dummy.go
  27. 3 3
      samples/gui/wasm-apps/increase/Makefile
  28. 3 0
      samples/multi-thread/wasm-apps/CMakeLists.txt
  29. 36 0
      samples/multi-thread/wasm-apps/main_thread_exception.c
  30. 2 2
      test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/help.html
  31. 25 9
      test-tools/IoT-APP-Store-Demo/wasm_django/server/wasm_server.py
  32. BIN
      test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/connection.wasm
  33. BIN
      test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/event_publisher.wasm
  34. BIN
      test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/event_subscriber.wasm
  35. BIN
      test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/request_handler.wasm
  36. BIN
      test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/request_sender.wasm
  37. BIN
      test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sensor.wasm
  38. BIN
      test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/simple
  39. BIN
      test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/connection.wasm
  40. BIN
      test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/event_publisher.wasm
  41. BIN
      test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/event_subscriber.wasm
  42. BIN
      test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/request_handler.wasm
  43. BIN
      test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/request_sender.wasm
  44. BIN
      test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/timer.wasm
  45. BIN
      test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/timer.wasm
  46. BIN
      test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/ui_app.wasm
  47. BIN
      test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/vgl_wasm_runtime
  48. BIN
      test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/wasm_runtime_wgl
  49. 42 18
      test-tools/host-tool/src/host_tool_utils.c
  50. 1 1
      test-tools/wamr-ide/VSCode-Extension/package.json
  51. 37 1
      tests/wamr-test-suites/test_wamr.sh
  52. 44 3
      wamr-sdk/app/libc-builtin-sysroot/include/stdint.h

+ 3 - 0
.github/workflows/build_wamr_vscode_ext.yml

@@ -32,11 +32,14 @@ jobs:
         working-directory: test-tools/wamr-ide/VSCode-Extension
 
       - name: generate wamr ide vscode extension
+        env: 
+          credentials: ${{ secrets.TOKEN }}
         run: |
           npm install -g vsce
           rm -rf node_modules
           npm install
           vsce package
+          vsce publish -p ${{ secrets.TOKEN }}
         working-directory: test-tools/wamr-ide/VSCode-Extension
 
       - name: compress the vscode extension

+ 10 - 4
.github/workflows/compilation_on_android_ubuntu.yml

@@ -61,6 +61,7 @@ env:
   SIMD_TEST_OPTIONS: "-s spec -b -S -P"
   THREADS_TEST_OPTIONS: "-s spec -b -p -P"
   X86_32_TARGET_TEST_OPTIONS: "-m x86_32 -P"
+  WASI_TEST_OPTIONS: "-s wasi_certification"
 
 jobs:
   build_llvm_libraries:
@@ -395,7 +396,7 @@ jobs:
           cmake --build . --config Release --parallel 4
           ./iwasm wasm-apps/no_pthread.wasm
 
-  spec_test:
+  test:
     needs: [build_iwasm, build_llvm_libraries, build_wamrc]
     runs-on: ubuntu-20.04
     strategy:
@@ -408,6 +409,7 @@ jobs:
             $MULTI_MODULES_TEST_OPTIONS,
             $SIMD_TEST_OPTIONS,
             $THREADS_TEST_OPTIONS,
+            $WASI_TEST_OPTIONS,
           ]
         exclude:
           # uncompatiable modes and features
@@ -419,6 +421,9 @@ jobs:
           # aot and jit don't support multi module
           - running_mode: "aot"
             test_option: $MULTI_MODULES_TEST_OPTIONS
+          # aot is WAMR-specific while wasi-testsuite is generic
+          - running_mode: "aot"
+            test_option: $WASI_TEST_OPTIONS
           - running_mode: "jit"
             test_option: $MULTI_MODULES_TEST_OPTIONS
           # fast-jit is only tested on default mode, exclude other three
@@ -438,7 +443,8 @@ jobs:
 
       - name: set env variable(if x86_32 test needed)
         if: >
-          (matrix.test_option == '$DEFAULT_TEST_OPTIONS' || matrix.test_option == '$THREADS_TEST_OPTIONS')
+          (matrix.test_option == '$DEFAULT_TEST_OPTIONS' || matrix.test_option == '$THREADS_TEST_OPTIONS'
+           || matrix.test_option == '$WASI_TEST_OPTIONS')
           && matrix.running_mode != 'fast-jit' && matrix.running_mode != 'jit'
         run: echo "TEST_ON_X86_32=true" >> $GITHUB_ENV
 
@@ -460,7 +466,7 @@ jobs:
         if: env.USE_LLVM == 'true' && steps.cache_llvm.outputs.cache-hit != 'true'
         run: echo "::error::can not get prebuilt llvm libraries" && exit 1
 
-      - name: run spec tests default and extra
+      - name: run tests
         run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
         working-directory: ./tests/wamr-test-suites
 
@@ -475,7 +481,7 @@ jobs:
           sudo apt-get update &&
           sudo apt install -y g++-multilib lib32gcc-9-dev
 
-      - name: run spec tests x86_32
+      - name: run tests x86_32
         if: env.TEST_ON_X86_32 == 'true'
         run: ./test_wamr.sh ${{ env.X86_32_TARGET_TEST_OPTIONS }} ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
         working-directory: ./tests/wamr-test-suites

+ 1 - 0
.github/workflows/release_process.yml

@@ -150,6 +150,7 @@ jobs:
   release_wamr_ide_vscode_ext:
     needs: [create_tag, create_release]
     uses: ./.github/workflows/build_wamr_vscode_ext.yml
+    secrets: inherit
     with:
       upload_url: ${{ needs.create_release.outputs.upload_url }}
       ver_num: ${{ needs.create_tag.outputs.new_ver }}

+ 155 - 39
core/app-framework/app-native-shared/attr_container.c

@@ -7,11 +7,14 @@
 
 typedef union jvalue {
     bool z;
-    int8_t b;
-    uint16_t c;
-    int16_t s;
-    int32_t i;
-    int64_t j;
+    int8_t i8;
+    uint8_t u8;
+    int16_t i16;
+    uint16_t u16;
+    int32_t i32;
+    uint32_t u32;
+    int64_t i64;
+    uint64_t u64;
     float f;
     double d;
 } jvalue;
@@ -27,7 +30,9 @@ get_int16(const char *buf)
 static inline uint16_t
 get_uint16(const char *buf)
 {
-    return get_int16(buf);
+    uint16_t ret;
+    bh_memcpy_s(&ret, sizeof(uint16_t), buf, sizeof(uint16_t));
+    return ret;
 }
 
 static inline int32_t
@@ -41,7 +46,9 @@ get_int32(const char *buf)
 static inline uint32_t
 get_uint32(const char *buf)
 {
-    return get_int32(buf);
+    uint32_t ret;
+    bh_memcpy_s(&ret, sizeof(uint32_t), buf, sizeof(uint32_t));
+    return ret;
 }
 
 static inline int64_t
@@ -55,7 +62,9 @@ get_int64(const char *buf)
 static inline uint64_t
 get_uint64(const char *buf)
 {
-    return get_int64(buf);
+    uint64_t ret;
+    bh_memcpy_s(&ret, sizeof(uint64_t), buf, sizeof(uint64_t));
+    return ret;
 }
 
 static inline void
@@ -145,8 +154,8 @@ attr_container_get_attr_next(const char *curr_attr)
     p += sizeof(uint16_t) + get_uint16(p);
     type = *p++;
 
-    /* Short type to Boolean type */
-    if (type >= ATTR_TYPE_SHORT && type <= ATTR_TYPE_BOOLEAN) {
+    /* Byte type to Boolean type */
+    if (type >= ATTR_TYPE_BYTE && type <= ATTR_TYPE_BOOLEAN) {
         p += 1 << (type & 3);
         return p;
     }
@@ -342,7 +351,7 @@ attr_container_set_attr(attr_container_t **p_attr_cont, const char *key,
 
     /* key len + key + '\0' + type */
     attr_len = sizeof(uint16_t) + strlen(key) + 1 + 1;
-    if (type >= ATTR_TYPE_SHORT && type <= ATTR_TYPE_BOOLEAN)
+    if (type >= ATTR_TYPE_BYTE && type <= ATTR_TYPE_BOOLEAN)
         attr_len += 1 << (type & 3);
     else if (type == ATTR_TYPE_STRING)
         attr_len += sizeof(uint16_t) + value_length;
@@ -362,7 +371,7 @@ attr_container_set_attr(attr_container_t **p_attr_cont, const char *key,
     p += str_len;
 
     *p++ = type;
-    if (type >= ATTR_TYPE_SHORT && type <= ATTR_TYPE_BOOLEAN)
+    if (type >= ATTR_TYPE_BYTE && type <= ATTR_TYPE_BOOLEAN)
         bh_memcpy_s(p, 1 << (type & 3), value, 1 << (type & 3));
     else if (type == ATTR_TYPE_STRING) {
         set_uint16(p, value_length);
@@ -460,6 +469,14 @@ attr_container_set_short(attr_container_t **p_attr_cont, const char *key,
                                    2);
 }
 
+bool
+attr_container_set_int16(attr_container_t **p_attr_cont, const char *key,
+                         int16_t value)
+{
+    return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_INT16, &value,
+                                   2);
+}
+
 bool
 attr_container_set_int(attr_container_t **p_attr_cont, const char *key,
                        int value)
@@ -467,6 +484,22 @@ attr_container_set_int(attr_container_t **p_attr_cont, const char *key,
     return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_INT, &value, 4);
 }
 
+bool
+attr_container_set_int32(attr_container_t **p_attr_cont, const char *key,
+                         int32_t value)
+{
+    return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_INT32, &value,
+                                   4);
+}
+
+bool
+attr_container_set_uint32(attr_container_t **p_attr_cont, const char *key,
+                          uint32_t value)
+{
+    return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_UINT32, &value,
+                                   4);
+}
+
 bool
 attr_container_set_int64(attr_container_t **p_attr_cont, const char *key,
                          int64_t value)
@@ -475,6 +508,14 @@ attr_container_set_int64(attr_container_t **p_attr_cont, const char *key,
                                    8);
 }
 
+bool
+attr_container_set_uint64(attr_container_t **p_attr_cont, const char *key,
+                          uint64_t value)
+{
+    return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_UINT64, &value,
+                                   8);
+}
+
 bool
 attr_container_set_byte(attr_container_t **p_attr_cont, const char *key,
                         int8_t value)
@@ -482,6 +523,21 @@ attr_container_set_byte(attr_container_t **p_attr_cont, const char *key,
     return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_BYTE, &value, 1);
 }
 
+bool
+attr_container_set_int8(attr_container_t **p_attr_cont, const char *key,
+                        int8_t value)
+{
+    return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_INT8, &value, 1);
+}
+
+bool
+attr_container_set_uint8(attr_container_t **p_attr_cont, const char *key,
+                         uint8_t value)
+{
+    return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_UINT8, &value,
+                                   1);
+}
+
 bool
 attr_container_set_uint16(attr_container_t **p_attr_cont, const char *key,
                           uint16_t value)
@@ -552,7 +608,7 @@ attr_container_get_attr(const attr_container_t *attr_cont, const char *key)
 
     if (!(attr_addr = attr_container_find_attr(attr_cont, key))) {
         attr_container_printf("Get attribute failed: lookup key failed.\r\n");
-        return false;
+        return NULL;
     }
 
     /* key len + key + '\0' */
@@ -566,14 +622,17 @@ attr_container_get_attr(const attr_container_t *attr_cont, const char *key)
         uint8_t type;                                                        \
         if (!addr)                                                           \
             return 0;                                                        \
-        val.j = 0;                                                           \
+        val.i64 = 0;                                                         \
         type = *(uint8_t *)addr++;                                           \
         switch (type) {                                                      \
-            case ATTR_TYPE_SHORT:                                            \
-            case ATTR_TYPE_INT:                                              \
+            case ATTR_TYPE_BYTE:  /* = ATTR_TYPE_INT8 */                     \
+            case ATTR_TYPE_SHORT: /* = ATTR_TYPE_INT16 */                    \
+            case ATTR_TYPE_INT:   /* = ATTR_TYPE_INT32 */                    \
             case ATTR_TYPE_INT64:                                            \
-            case ATTR_TYPE_BYTE:                                             \
+            case ATTR_TYPE_UINT8:                                            \
             case ATTR_TYPE_UINT16:                                           \
+            case ATTR_TYPE_UINT32:                                           \
+            case ATTR_TYPE_UINT64:                                           \
             case ATTR_TYPE_FLOAT:                                            \
             case ATTR_TYPE_DOUBLE:                                           \
             case ATTR_TYPE_BOOLEAN:                                          \
@@ -608,31 +667,67 @@ attr_container_get_attr(const attr_container_t *attr_cont, const char *key)
 short
 attr_container_get_as_short(const attr_container_t *attr_cont, const char *key)
 {
-    TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, s);
+    TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, i16);
+}
+
+int16_t
+attr_container_get_as_int16(const attr_container_t *attr_cont, const char *key)
+{
+    return (int16_t)attr_container_get_as_short(attr_cont, key);
 }
 
 int
 attr_container_get_as_int(const attr_container_t *attr_cont, const char *key)
 {
-    TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, i);
+    TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, i32);
+}
+
+int32_t
+attr_container_get_as_int32(const attr_container_t *attr_cont, const char *key)
+{
+    return (int32_t)attr_container_get_as_int(attr_cont, key);
+}
+
+uint32_t
+attr_container_get_as_uint32(const attr_container_t *attr_cont, const char *key)
+{
+    return (uint32_t)attr_container_get_as_int(attr_cont, key);
 }
 
 int64_t
 attr_container_get_as_int64(const attr_container_t *attr_cont, const char *key)
 {
-    TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, j);
+    TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, i64);
+}
+
+uint64_t
+attr_container_get_as_uint64(const attr_container_t *attr_cont, const char *key)
+{
+    return (uint64_t)attr_container_get_as_int64(attr_cont, key);
 }
 
 int8_t
 attr_container_get_as_byte(const attr_container_t *attr_cont, const char *key)
 {
-    TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, b);
+    TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, i8);
+}
+
+int8_t
+attr_container_get_as_int8(const attr_container_t *attr_cont, const char *key)
+{
+    return attr_container_get_as_byte(attr_cont, key);
+}
+
+uint8_t
+attr_container_get_as_uint8(const attr_container_t *attr_cont, const char *key)
+{
+    return (uint8_t)attr_container_get_as_byte(attr_cont, key);
 }
 
 uint16_t
 attr_container_get_as_uint16(const attr_container_t *attr_cont, const char *key)
 {
-    TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, s);
+    return (uint16_t)attr_container_get_as_short(attr_cont, key);
 }
 
 float
@@ -671,11 +766,14 @@ attr_container_get_as_bytearray(const attr_container_t *attr_cont,
 
     type = *(uint8_t *)addr++;
     switch (type) {
-        case ATTR_TYPE_SHORT:
-        case ATTR_TYPE_INT:
+        case ATTR_TYPE_BYTE:  /* = ATTR_TYPE_INT8 */
+        case ATTR_TYPE_SHORT: /* = ATTR_TYPE_INT16 */
+        case ATTR_TYPE_INT:   /* = ATTR_TYPE_INT32 */
         case ATTR_TYPE_INT64:
-        case ATTR_TYPE_BYTE:
+        case ATTR_TYPE_UINT8:
         case ATTR_TYPE_UINT16:
+        case ATTR_TYPE_UINT32:
+        case ATTR_TYPE_UINT64:
         case ATTR_TYPE_FLOAT:
         case ATTR_TYPE_DOUBLE:
         case ATTR_TYPE_BOOLEAN:
@@ -807,34 +905,52 @@ attr_container_dump(const attr_container_t *attr_cont)
         attr_container_printf("  key: %s", key);
 
         switch (type) {
-            case ATTR_TYPE_SHORT:
-                bh_memcpy_s(&value.s, sizeof(int16_t), p, sizeof(int16_t));
+            case ATTR_TYPE_BYTE: /* = ATTR_TYPE_INT8 */
+                bh_memcpy_s(&value.i8, 1, p, 1);
+                attr_container_printf(", type: byte, value: 0x%x\n",
+                                      value.i8 & 0xFF);
+                p++;
+                break;
+            case ATTR_TYPE_SHORT: /* = ATTR_TYPE_INT16 */
+                bh_memcpy_s(&value.i16, sizeof(int16_t), p, sizeof(int16_t));
                 attr_container_printf(", type: short, value: 0x%x\n",
-                                      value.s & 0xFFFF);
+                                      value.i16 & 0xFFFF);
                 p += 2;
                 break;
-            case ATTR_TYPE_INT:
-                bh_memcpy_s(&value.i, sizeof(int32_t), p, sizeof(int32_t));
-                attr_container_printf(", type: int, value: 0x%x\n", value.i);
+            case ATTR_TYPE_INT: /* = ATTR_TYPE_INT32 */
+                bh_memcpy_s(&value.i32, sizeof(int32_t), p, sizeof(int32_t));
+                attr_container_printf(", type: int, value: 0x%x\n", value.i32);
                 p += 4;
                 break;
             case ATTR_TYPE_INT64:
-                bh_memcpy_s(&value.j, sizeof(uint64_t), p, sizeof(uint64_t));
+                bh_memcpy_s(&value.i64, sizeof(int64_t), p, sizeof(int64_t));
                 attr_container_printf(", type: int64, value: 0x%llx\n",
-                                      (long long unsigned int)(value.j));
+                                      (long long unsigned int)(value.i64));
                 p += 8;
                 break;
-            case ATTR_TYPE_BYTE:
-                bh_memcpy_s(&value.b, 1, p, 1);
-                attr_container_printf(", type: byte, value: 0x%x\n",
-                                      value.b & 0xFF);
+            case ATTR_TYPE_UINT8:
+                bh_memcpy_s(&value.u8, 1, p, 1);
+                attr_container_printf(", type: uint8, value: 0x%x\n", value.u8);
                 p++;
                 break;
             case ATTR_TYPE_UINT16:
-                bh_memcpy_s(&value.c, sizeof(uint16_t), p, sizeof(uint16_t));
-                attr_container_printf(", type: uint16, value: 0x%x\n", value.c);
+                bh_memcpy_s(&value.u16, sizeof(uint16_t), p, sizeof(uint16_t));
+                attr_container_printf(", type: uint16, value: 0x%x\n",
+                                      value.u16);
                 p += 2;
                 break;
+            case ATTR_TYPE_UINT32:
+                bh_memcpy_s(&value.u32, sizeof(uint32_t), p, sizeof(uint32_t));
+                attr_container_printf(", type: uint32, value: 0x%x\n",
+                                      value.u32);
+                p += 4;
+                break;
+            case ATTR_TYPE_UINT64:
+                bh_memcpy_s(&value.u64, sizeof(uint64_t), p, sizeof(uint64_t));
+                attr_container_printf(", type: int64, value: 0x%llx\n",
+                                      (long long unsigned int)(value.u64));
+                p += 8;
+                break;
             case ATTR_TYPE_FLOAT:
                 bh_memcpy_s(&value.f, sizeof(float), p, sizeof(float));
                 attr_container_printf(", type: float, value: %f\n", value.f);

+ 176 - 4
core/app-framework/app-native-shared/bi-inc/attr_container.h

@@ -20,13 +20,27 @@ extern "C" {
 
 /* Attribute type */
 enum {
-    ATTR_TYPE_BEGIN = 1,
-    ATTR_TYPE_SHORT = ATTR_TYPE_BEGIN,
+    ATTR_TYPE_BEGIN = 0,
+    ATTR_TYPE_BYTE = ATTR_TYPE_BEGIN,
+    ATTR_TYPE_INT8 = ATTR_TYPE_BYTE,
+    ATTR_TYPE_SHORT,
+    ATTR_TYPE_INT16 = ATTR_TYPE_SHORT,
     ATTR_TYPE_INT,
+    ATTR_TYPE_INT32 = ATTR_TYPE_INT,
     ATTR_TYPE_INT64,
-    ATTR_TYPE_BYTE,
+    ATTR_TYPE_UINT8,
     ATTR_TYPE_UINT16,
-    ATTR_TYPE_FLOAT,
+    ATTR_TYPE_UINT32,
+    ATTR_TYPE_UINT64,
+    /**
+     * Why ATTR_TYPE_FLOAT = 10?
+     * We determine the number of bytes that should be copied through 1<<(type &
+     * 3). ATTR_TYPE_BYTE = 0, so the number of bytes is 1 << 0  = 1.
+     * ATTR_TYPE_UINT64 = 7, so the number of bytes is 1 << 3 = 8.
+     * Since the float type takes up 4 bytes, ATTR_TYPE_FLOAT should be 10.
+     * Calculation: (1 << (10&3)) = (1 << 2) = 4
+     */
+    ATTR_TYPE_FLOAT = 10,
     ATTR_TYPE_DOUBLE,
     ATTR_TYPE_BOOLEAN,
     ATTR_TYPE_STRING,
@@ -89,6 +103,20 @@ bool
 attr_container_set_short(attr_container_t **p_attr_cont, const char *key,
                          short value);
 
+/**
+ * Set int16 attribute in attribute container
+ *
+ * @param p_attr_cont pointer to attribute container to set attribute, and
+ * return the new attribute container if it is re-created
+ * @param key the attribute key
+ * @param value the attribute value
+ *
+ * @return true if success, false otherwise
+ */
+bool
+attr_container_set_int16(attr_container_t **p_attr_cont, const char *key,
+                         int16_t value);
+
 /**
  * Set int attribute in attribute container
  *
@@ -103,6 +131,34 @@ bool
 attr_container_set_int(attr_container_t **p_attr_cont, const char *key,
                        int value);
 
+/**
+ * Set int32 attribute in attribute container
+ *
+ * @param p_attr_cont pointer to attribute container to set attribute, and
+ * return the new attribute container if it is re-created
+ * @param key the attribute key
+ * @param value the attribute value
+ *
+ * @return true if success, false otherwise
+ */
+bool
+attr_container_set_int32(attr_container_t **p_attr_cont, const char *key,
+                         int32_t value);
+
+/**
+ * Set uint32 attribute in attribute container
+ *
+ * @param p_attr_cont pointer to attribute container to set attribute, and
+ * return the new attribute container if it is re-created
+ * @param key the attribute key
+ * @param value the attribute value
+ *
+ * @return true if success, false otherwise
+ */
+bool
+attr_container_set_uint32(attr_container_t **p_attr_cont, const char *key,
+                          uint32_t value);
+
 /**
  * Set int64 attribute in attribute container
  *
@@ -117,6 +173,20 @@ bool
 attr_container_set_int64(attr_container_t **p_attr_cont, const char *key,
                          int64_t value);
 
+/**
+ * Set uint64 attribute in attribute container
+ *
+ * @param p_attr_cont pointer to attribute container to set attribute, and
+ * return the new attribute container if it is re-created
+ * @param key the attribute key
+ * @param value the attribute value
+ *
+ * @return true if success, false otherwise
+ */
+bool
+attr_container_set_uint64(attr_container_t **p_attr_cont, const char *key,
+                          uint64_t value);
+
 /**
  * Set byte attribute in attribute container
  *
@@ -131,6 +201,34 @@ bool
 attr_container_set_byte(attr_container_t **p_attr_cont, const char *key,
                         int8_t value);
 
+/**
+ * Set int8 attribute in attribute container
+ *
+ * @param p_attr_cont pointer to attribute container to set attribute, and
+ * return the new attribute container if it is re-created
+ * @param key the attribute key
+ * @param value the attribute value
+ *
+ * @return true if success, false otherwise
+ */
+bool
+attr_container_set_int8(attr_container_t **p_attr_cont, const char *key,
+                        int8_t value);
+
+/**
+ * Set uint8 attribute in attribute container
+ *
+ * @param p_attr_cont pointer to attribute container to set attribute, and
+ * return the new attribute container if it is re-created
+ * @param key the attribute key
+ * @param value the attribute value
+ *
+ * @return true if success, false otherwise
+ */
+bool
+attr_container_set_uint8(attr_container_t **p_attr_cont, const char *key,
+                         uint8_t value);
+
 /**
  * Set uint16 attribute in attribute container
  *
@@ -259,6 +357,18 @@ attr_container_contain_key(const attr_container_t *attr_cont, const char *key);
 short
 attr_container_get_as_short(const attr_container_t *attr_cont, const char *key);
 
+/**
+ * Get attribute from attribute container and return it as int16 value,
+ * return 0 if attribute isn't found in message.
+ *
+ * @param attr_cont the attribute container
+ * @param key the attribute key
+ *
+ * @return the short value of the attribute, 0 if key isn't found
+ */
+int16_t
+attr_container_get_as_int16(const attr_container_t *attr_cont, const char *key);
+
 /**
  * Get attribute from attribute container and return it as int value,
  * return 0 if attribute isn't found in message.
@@ -271,6 +381,31 @@ attr_container_get_as_short(const attr_container_t *attr_cont, const char *key);
 int
 attr_container_get_as_int(const attr_container_t *attr_cont, const char *key);
 
+/**
+ * Get attribute from attribute container and return it as int32 value,
+ * return 0 if attribute isn't found in message.
+ *
+ * @param attr_cont the attribute container
+ * @param key the attribute key
+ *
+ * @return the int value of the attribute, 0 if key isn't found
+ */
+int32_t
+attr_container_get_as_int32(const attr_container_t *attr_cont, const char *key);
+
+/**
+ * Get attribute from attribute container and return it as uint32 value,
+ * return 0 if attribute isn't found in message.
+ *
+ * @param attr_cont the attribute container
+ * @param key the attribute key
+ *
+ * @return the unsigned int value of the attribute, 0 if key isn't found
+ */
+uint32_t
+attr_container_get_as_uint32(const attr_container_t *attr_cont,
+                             const char *key);
+
 /**
  * Get attribute from attribute container and return it as int64 value,
  * return 0 if attribute isn't found in attribute container.
@@ -283,6 +418,19 @@ attr_container_get_as_int(const attr_container_t *attr_cont, const char *key);
 int64_t
 attr_container_get_as_int64(const attr_container_t *attr_cont, const char *key);
 
+/**
+ * Get attribute from attribute container and return it as uint64 value,
+ * return 0 if attribute isn't found in attribute container.
+ *
+ * @param attr_cont the attribute container
+ * @param key the attribute key
+ *
+ * @return the unsigned long value of the attribute, 0 if key isn't found
+ */
+uint64_t
+attr_container_get_as_uint64(const attr_container_t *attr_cont,
+                             const char *key);
+
 /**
  * Get attribute from attribute container and return it as byte value,
  * return 0 if attribute isn't found in attribute container.
@@ -295,6 +443,30 @@ attr_container_get_as_int64(const attr_container_t *attr_cont, const char *key);
 int8_t
 attr_container_get_as_byte(const attr_container_t *attr_cont, const char *key);
 
+/**
+ * Get attribute from attribute container and return it as int8 value,
+ * return 0 if attribute isn't found in attribute container.
+ *
+ * @param attr_cont the attribute container
+ * @param key the attribute key
+ *
+ * @return the byte value of the attribute, 0 if key isn't found
+ */
+int8_t
+attr_container_get_as_int8(const attr_container_t *attr_cont, const char *key);
+
+/**
+ * Get attribute from attribute container and return it as uint8 value,
+ * return 0 if attribute isn't found in attribute container.
+ *
+ * @param attr_cont the attribute container
+ * @param key the attribute key
+ *
+ * @return the uint8 value of the attribute, 0 if key isn't found
+ */
+uint8_t
+attr_container_get_as_uint8(const attr_container_t *attr_cont, const char *key);
+
 /**
  * Get attribute from attribute container and return it as uint16 value,
  * return 0 if attribute isn't found in attribute container.

+ 3 - 0
core/iwasm/aot/aot_loader.c

@@ -1226,7 +1226,10 @@ load_import_globals(const uint8 **p_buf, const uint8 *buf_end,
             }
             import_globals[i].global_data_linked =
                 tmp_global.global_data_linked;
+            import_globals[i].is_linked = true;
         }
+#else
+        import_globals[i].is_linked = false;
 #endif
 
         import_globals[i].size = wasm_value_type_size(import_globals[i].type);

+ 29 - 35
core/iwasm/aot/aot_runtime.c

@@ -899,24 +899,6 @@ create_exports(AOTModuleInstance *module_inst, AOTModule *module,
     return create_export_funcs(module_inst, module, error_buf, error_buf_size);
 }
 
-static bool
-clear_wasi_proc_exit_exception(AOTModuleInstance *module_inst)
-{
-#if WASM_ENABLE_LIBC_WASI != 0
-    const char *exception = aot_get_exception(module_inst);
-    if (exception && !strcmp(exception, "Exception: wasi proc exit")) {
-        /* The "wasi proc exit" exception is thrown by native lib to
-           let wasm app exit, which is a normal behavior, we clear
-           the exception here. */
-        aot_set_exception(module_inst, NULL);
-        return true;
-    }
-    return false;
-#else
-    return false;
-#endif
-}
-
 static bool
 execute_post_inst_function(AOTModuleInstance *module_inst)
 {
@@ -956,7 +938,6 @@ execute_start_function(AOTModuleInstance *module_inst)
     u.f(exec_env);
 
     wasm_exec_env_destroy(exec_env);
-    (void)clear_wasi_proc_exit_exception(module_inst);
     return !aot_get_exception(module_inst);
 }
 
@@ -976,6 +957,26 @@ execute_memory_init_function(AOTModuleInstance *module_inst)
 }
 #endif
 
+static bool
+check_linked_symbol(AOTModule *module, char *error_buf, uint32 error_buf_size)
+{
+    uint32 i;
+
+    /* init_func_ptrs() will go through import functions */
+
+    for (i = 0; i < module->import_global_count; i++) {
+        AOTImportGlobal *global = module->import_globals + i;
+        if (!global->is_linked) {
+            set_error_buf_v(error_buf, error_buf_size,
+                            "failed to link import global (%s, %s)",
+                            global->module_name, global->global_name);
+            return false;
+        }
+    }
+
+    return true;
+}
+
 AOTModuleInstance *
 aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size,
                 uint32 heap_size, char *error_buf, uint32 error_buf_size)
@@ -1059,6 +1060,9 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size,
     if (!init_func_type_indexes(module_inst, module, error_buf, error_buf_size))
         goto fail;
 
+    if (!check_linked_symbol(module, error_buf, error_buf_size))
+        goto fail;
+
     if (!create_exports(module_inst, module, error_buf, error_buf_size))
         goto fail;
 
@@ -1384,13 +1388,6 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
         ret = invoke_native_internal(exec_env, function->u.func.func_ptr,
                                      func_type, NULL, NULL, argv1, argc, argv);
 
-        if (!ret || aot_get_exception(module_inst)) {
-            if (clear_wasi_proc_exit_exception(module_inst))
-                ret = true;
-            else
-                ret = false;
-        }
-
 #if WASM_ENABLE_DUMP_CALL_STACK != 0
         if (!ret) {
             if (aot_create_call_stack(exec_env)) {
@@ -1450,9 +1447,6 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
         ret = invoke_native_internal(exec_env, function->u.func.func_ptr,
                                      func_type, NULL, NULL, argv, argc, argv);
 
-        if (clear_wasi_proc_exit_exception(module_inst))
-            ret = true;
-
 #if WASM_ENABLE_DUMP_CALL_STACK != 0
         if (aot_get_exception(module_inst)) {
             if (aot_create_call_stack(exec_env)) {
@@ -1493,7 +1487,7 @@ aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst,
         }
     }
 
-    ret = aot_call_function(exec_env, func, argc, argv);
+    ret = wasm_runtime_call_wasm(exec_env, func, argc, argv);
 
     /* don't destroy the exec_env if it isn't created in this function */
     if (!existing_exec_env)
@@ -1764,7 +1758,9 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
     AOTModuleInstanceExtra *module_inst_extra =
         (AOTModuleInstanceExtra *)module_inst->e;
     CApiFuncImport *c_api_func_import =
-        module_inst_extra->c_api_func_imports + func_idx;
+        module_inst_extra->c_api_func_imports
+            ? module_inst_extra->c_api_func_imports + func_idx
+            : NULL;
     uint32 *func_type_indexes = module_inst->func_type_indexes;
     uint32 func_type_idx = func_type_indexes[func_idx];
     AOTFuncType *func_type = aot_module->func_types[func_type_idx];
@@ -1780,7 +1776,8 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
 
     import_func = aot_module->import_funcs + func_idx;
     if (import_func->call_conv_wasm_c_api)
-        func_ptr = c_api_func_import->func_ptr_linked;
+        func_ptr =
+            c_api_func_import ? c_api_func_import->func_ptr_linked : NULL;
 
     if (!func_ptr) {
         snprintf(buf, sizeof(buf),
@@ -1980,9 +1977,6 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx,
     }
 
 fail:
-    if (clear_wasi_proc_exit_exception(module_inst))
-        return true;
-
 #ifdef OS_ENABLE_HW_BOUND_CHECK
     wasm_runtime_access_exce_check_guard_page();
 #endif

+ 1 - 0
core/iwasm/common/wasm_c_api.c

@@ -4555,6 +4555,7 @@ aot_link_global(const AOTModule *module_aot, uint16 global_idx_rt,
     }
 
     import->global_idx_rt = global_idx_rt;
+    import_aot_global->is_linked = true;
     return true;
 
 failed:

+ 3 - 0
core/iwasm/common/wasm_exec_env.c

@@ -181,6 +181,9 @@ wasm_exec_env_destroy(WASMExecEnv *exec_env)
            the stopped thread will be overrided by other threads */
         wasm_cluster_thread_exited(exec_env);
 #endif
+        /* We have terminated other threads, this is the only alive thread, so
+         * we don't acquire cluster->lock because the cluster will be destroyed
+         * inside this function */
         wasm_cluster_del_exec_env(cluster, exec_env);
     }
 #endif /* end of WASM_ENABLE_THREAD_MGR */

+ 58 - 8
core/iwasm/common/wasm_runtime_common.c

@@ -1743,6 +1743,30 @@ wasm_runtime_finalize_call_function(WASMExecEnv *exec_env,
 }
 #endif
 
+static bool
+clear_wasi_proc_exit_exception(WASMModuleInstanceCommon *module_inst_comm)
+{
+#if WASM_ENABLE_LIBC_WASI != 0
+    const char *exception;
+    WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm;
+
+    bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
+              || module_inst_comm->module_type == Wasm_Module_AoT);
+
+    exception = wasm_get_exception(module_inst);
+    if (exception && !strcmp(exception, "Exception: wasi proc exit")) {
+        /* The "wasi proc exit" exception is thrown by native lib to
+           let wasm app exit, which is a normal behavior, we clear
+           the exception here. */
+        wasm_set_exception(module_inst, NULL);
+        return true;
+    }
+    return false;
+#else
+    return false;
+#endif
+}
+
 bool
 wasm_runtime_call_wasm(WASMExecEnv *exec_env,
                        WASMFunctionInstanceCommon *function, uint32 argc,
@@ -1783,10 +1807,15 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env,
                                 param_argc, new_argv);
 #endif
     if (!ret) {
-        if (new_argv != argv) {
-            wasm_runtime_free(new_argv);
+        if (clear_wasi_proc_exit_exception(exec_env->module_inst)) {
+            ret = true;
+        }
+        else {
+            if (new_argv != argv) {
+                wasm_runtime_free(new_argv);
+            }
+            return false;
         }
-        return false;
     }
 
 #if WASM_ENABLE_REF_TYPES != 0
@@ -2150,11 +2179,25 @@ wasm_runtime_get_exec_env_singleton(WASMModuleInstanceCommon *module_inst_comm)
 void
 wasm_set_exception(WASMModuleInstance *module_inst, const char *exception)
 {
-    if (exception)
+    WASMExecEnv *exec_env = NULL;
+
+    if (exception) {
         snprintf(module_inst->cur_exception, sizeof(module_inst->cur_exception),
                  "Exception: %s", exception);
-    else
+    }
+    else {
         module_inst->cur_exception[0] = '\0';
+    }
+
+#if WASM_ENABLE_THREAD_MGR != 0
+    exec_env =
+        wasm_clusters_search_exec_env((WASMModuleInstanceCommon *)module_inst);
+    if (exec_env) {
+        wasm_cluster_spread_exception(exec_env, exception ? false : true);
+    }
+#else
+    (void)exec_env;
+#endif
 }
 
 /* clang-format off */
@@ -4179,6 +4222,8 @@ bool
 wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices,
                            uint32 argc, uint32 argv[])
 {
+    bool ret = false;
+
     if (!wasm_runtime_exec_env_check(exec_env)) {
         LOG_ERROR("Invalid exec env stack info.");
         return false;
@@ -4190,13 +4235,18 @@ wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices,
 
 #if WASM_ENABLE_INTERP != 0
     if (exec_env->module_inst->module_type == Wasm_Module_Bytecode)
-        return wasm_call_indirect(exec_env, 0, element_indices, argc, argv);
+        ret = wasm_call_indirect(exec_env, 0, element_indices, argc, argv);
 #endif
 #if WASM_ENABLE_AOT != 0
     if (exec_env->module_inst->module_type == Wasm_Module_AoT)
-        return aot_call_indirect(exec_env, 0, element_indices, argc, argv);
+        ret = aot_call_indirect(exec_env, 0, element_indices, argc, argv);
 #endif
-    return false;
+
+    if (!ret && clear_wasi_proc_exit_exception(exec_env->module_inst)) {
+        ret = true;
+    }
+
+    return ret;
 }
 
 static void

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

@@ -149,6 +149,7 @@ typedef struct AOTImportGlobal {
     uint32 data_offset;
     /* global data after linked */
     WASMValue global_data_linked;
+    bool is_linked;
 } AOTImportGlobal;
 
 /**

+ 39 - 60
core/iwasm/compilation/aot_emit_conversion.c

@@ -9,35 +9,47 @@
 #include "../aot/aot_intrinsic.h"
 #include "../aot/aot_runtime.h"
 
-static bool
-trunc_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                   LLVMValueRef operand, LLVMTypeRef src_type,
-                   LLVMTypeRef dest_type, LLVMValueRef min_value,
-                   LLVMValueRef max_value, char *name, bool sign)
+static LLVMValueRef
+call_fcmp_intrinsic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                    enum AOTFloatCond cond, LLVMRealPredicate op,
+                    LLVMValueRef lhs, LLVMValueRef rhs, LLVMTypeRef src_type,
+                    const char *name)
 {
-    LLVMBasicBlockRef check_nan_succ, check_overflow_succ;
-    LLVMValueRef is_less, is_greater, res;
-
+    LLVMValueRef res = NULL;
     if (comp_ctx->disable_llvm_intrinsics
         && aot_intrinsic_check_capability(
             comp_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp")) {
         LLVMTypeRef param_types[3];
-        LLVMValueRef opcond = LLVMConstInt(I32_TYPE, FLOAT_UNO, true);
+        LLVMValueRef opcond = LLVMConstInt(I32_TYPE, cond, true);
         param_types[0] = I32_TYPE;
         param_types[1] = src_type;
         param_types[2] = src_type;
         res = aot_call_llvm_intrinsic(
             comp_ctx, func_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp",
-            I32_TYPE, param_types, 3, opcond, operand, operand);
+            I32_TYPE, param_types, 3, opcond, lhs, rhs);
         if (!res) {
             goto fail;
         }
         res = LLVMBuildIntCast(comp_ctx->builder, res, INT1_TYPE, "bit_cast");
     }
     else {
-        res = LLVMBuildFCmp(comp_ctx->builder, LLVMRealUNO, operand, operand,
-                            "fcmp_is_nan");
+        res = LLVMBuildFCmp(comp_ctx->builder, op, lhs, rhs, name);
     }
+fail:
+    return res;
+}
+
+static bool
+trunc_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                   LLVMValueRef operand, LLVMTypeRef src_type,
+                   LLVMTypeRef dest_type, LLVMValueRef min_value,
+                   LLVMValueRef max_value, char *name, bool sign)
+{
+    LLVMBasicBlockRef check_nan_succ, check_overflow_succ;
+    LLVMValueRef is_less, is_greater, res;
+
+    res = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_UNO, LLVMRealUNO,
+                              operand, operand, src_type, "fcmp_is_nan");
 
     if (!res) {
         aot_set_last_error("llvm build fcmp failed.");
@@ -58,54 +70,18 @@ trunc_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                              check_nan_succ)))
         goto fail;
 
-    if (comp_ctx->disable_llvm_intrinsics
-        && aot_intrinsic_check_capability(
-            comp_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp")) {
-        LLVMTypeRef param_types[3];
-        LLVMValueRef opcond = LLVMConstInt(I32_TYPE, FLOAT_LE, true);
-        param_types[0] = I32_TYPE;
-        param_types[1] = src_type;
-        param_types[2] = src_type;
-        is_less = aot_call_llvm_intrinsic(
-            comp_ctx, func_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp",
-            I32_TYPE, param_types, 3, opcond, operand, min_value);
-        if (!is_less) {
-            goto fail;
-        }
-        is_less =
-            LLVMBuildIntCast(comp_ctx->builder, is_less, INT1_TYPE, "bit_cast");
-    }
-    else {
-        is_less = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOLE, operand,
-                                min_value, "fcmp_min_value");
-    }
+    is_less =
+        call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_LE, LLVMRealOLE, operand,
+                            min_value, src_type, "fcmp_min_value");
 
     if (!is_less) {
         aot_set_last_error("llvm build fcmp failed.");
         goto fail;
     }
 
-    if (comp_ctx->disable_llvm_intrinsics
-        && aot_intrinsic_check_capability(
-            comp_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp")) {
-        LLVMTypeRef param_types[3];
-        LLVMValueRef opcond = LLVMConstInt(I32_TYPE, FLOAT_GE, true);
-        param_types[0] = I32_TYPE;
-        param_types[1] = src_type;
-        param_types[2] = src_type;
-        is_greater = aot_call_llvm_intrinsic(
-            comp_ctx, func_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp",
-            I32_TYPE, param_types, 3, opcond, operand, max_value);
-        if (!is_greater) {
-            goto fail;
-        }
-        is_greater = LLVMBuildIntCast(comp_ctx->builder, is_greater, INT1_TYPE,
-                                      "bit_cast");
-    }
-    else {
-        is_greater = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOGE, operand,
-                                   max_value, "fcmp_min_value");
-    }
+    is_greater =
+        call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_GE, LLVMRealOGE, operand,
+                            max_value, src_type, "fcmp_min_value");
 
     if (!is_greater) {
         aot_set_last_error("llvm build fcmp failed.");
@@ -183,8 +159,9 @@ trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     LLVMValueRef zero = (dest_type == I32_TYPE) ? I32_ZERO : I64_ZERO;
     LLVMValueRef vmin, vmax;
 
-    if (!(res = LLVMBuildFCmp(comp_ctx->builder, LLVMRealUNO, operand, operand,
-                              "fcmp_is_nan"))) {
+    if (!(res =
+              call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_UNO, LLVMRealUNO,
+                                  operand, operand, src_type, "fcmp_is_nan"))) {
         aot_set_last_error("llvm build fcmp failed.");
         goto fail;
     }
@@ -212,8 +189,9 @@ trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     /* Start to translate check_nan_succ block */
     LLVMPositionBuilderAtEnd(comp_ctx->builder, check_nan_succ);
-    if (!(is_less = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOLE, operand,
-                                  min_value, "fcmp_min_value"))) {
+    if (!(is_less = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_LE,
+                                        LLVMRealOLE, operand, min_value,
+                                        src_type, "fcmp_min_value"))) {
         aot_set_last_error("llvm build fcmp failed.");
         goto fail;
     }
@@ -232,8 +210,9 @@ trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     /* Start to translate check_less_succ block */
     LLVMPositionBuilderAtEnd(comp_ctx->builder, check_less_succ);
-    if (!(is_greater = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOGE, operand,
-                                     max_value, "fcmp_max_value"))) {
+    if (!(is_greater = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_GE,
+                                           LLVMRealOGE, operand, max_value,
+                                           src_type, "fcmp_max_value"))) {
         aot_set_last_error("llvm build fcmp failed.");
         goto fail;
     }

+ 1 - 33
core/iwasm/interpreter/wasm_interp_classic.c

@@ -891,7 +891,7 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
     if (!func_import->call_conv_wasm_c_api) {
         native_func_pointer = module_inst->import_func_ptrs[cur_func_index];
     }
-    else {
+    else if (module_inst->e->c_api_func_imports) {
         c_api_func_import = module_inst->e->c_api_func_imports + cur_func_index;
         native_func_pointer = c_api_func_import->func_ptr_linked;
     }
@@ -1041,7 +1041,6 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
         }                                                              \
         if (IS_WAMR_STOP_SIG(exec_env->current_status->signal_flag)) { \
             SYNC_ALL_TO_FRAME();                                       \
-            wasm_cluster_thread_stopped(exec_env);                     \
             wasm_cluster_thread_waiting_run(exec_env);                 \
         }                                                              \
     } while (0)
@@ -1077,7 +1076,6 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
                && exec_env->current_status->step_count++ == 1) {          \
             exec_env->current_status->step_count = 0;                     \
             SYNC_ALL_TO_FRAME();                                          \
-            wasm_cluster_thread_stopped(exec_env);                        \
             wasm_cluster_thread_waiting_run(exec_env);                    \
         }                                                                 \
         goto *handle_table[*frame_ip++];                                  \
@@ -1094,7 +1092,6 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
         && exec_env->current_status->step_count++ == 2) {          \
         exec_env->current_status->step_count = 0;                  \
         SYNC_ALL_TO_FRAME();                                       \
-        wasm_cluster_thread_stopped(exec_env);                     \
         wasm_cluster_thread_waiting_run(exec_env);                 \
     }                                                              \
     continue
@@ -4022,24 +4019,6 @@ fast_jit_call_func_bytecode(WASMModuleInstance *module_inst,
 #endif /* end of WASM_ENABLE_FAST_JIT != 0 */
 
 #if WASM_ENABLE_JIT != 0
-static bool
-clear_wasi_proc_exit_exception(WASMModuleInstance *module_inst)
-{
-#if WASM_ENABLE_LIBC_WASI != 0
-    const char *exception = wasm_get_exception(module_inst);
-    if (exception && !strcmp(exception, "Exception: wasi proc exit")) {
-        /* The "wasi proc exit" exception is thrown by native lib to
-           let wasm app exit, which is a normal behavior, we clear
-           the exception here. */
-        wasm_set_exception(module_inst, NULL);
-        return true;
-    }
-    return false;
-#else
-    return false;
-#endif
-}
-
 static bool
 llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
                             WASMExecEnv *exec_env,
@@ -4099,14 +4078,6 @@ llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
         ret = wasm_runtime_invoke_native(
             exec_env, module_inst->func_ptrs[func_idx], func_type, NULL, NULL,
             argv1, argc, argv);
-
-        if (!ret || wasm_get_exception(module_inst)) {
-            if (clear_wasi_proc_exit_exception(module_inst))
-                ret = true;
-            else
-                ret = false;
-        }
-
         if (!ret) {
             if (argv1 != argv1_buf)
                 wasm_runtime_free(argv1);
@@ -4151,9 +4122,6 @@ llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
             exec_env, module_inst->func_ptrs[func_idx], func_type, NULL, NULL,
             argv, argc, argv);
 
-        if (clear_wasi_proc_exit_exception(module_inst))
-            ret = true;
-
         return ret && !wasm_get_exception(module_inst) ? true : false;
     }
 }

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

@@ -925,7 +925,7 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
     if (!func_import->call_conv_wasm_c_api) {
         native_func_pointer = module_inst->import_func_ptrs[cur_func_index];
     }
-    else {
+    else if (module_inst->e->c_api_func_imports) {
         c_api_func_import = module_inst->e->c_api_func_imports + cur_func_index;
         native_func_pointer = c_api_func_import->func_ptr_linked;
     }

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

@@ -1235,6 +1235,7 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf,
 #if WASM_ENABLE_WAMR_COMPILER == 0
             LOG_WARNING("warning: failed to link import function (%s, %s)",
                         func->module_name, func->field_name);
+            /* will throw exception only if calling */
 #else
             /* do nothing to avoid confused message */
 #endif /* WASM_ENABLE_WAMR_COMPILER == 0 */
@@ -1250,8 +1251,10 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf,
             return false;
 #else
 #if WASM_ENABLE_WAMR_COMPILER == 0
-            LOG_DEBUG("warning: failed to link import global (%s, %s)",
-                      global->module_name, global->field_name);
+            set_error_buf_v(error_buf, error_buf_size,
+                            "failed to link import global (%s, %s)",
+                            global->module_name, global->field_name);
+            return false;
 #else
             /* do nothing to avoid confused message */
 #endif /* WASM_ENABLE_WAMR_COMPILER == 0 */
@@ -2030,24 +2033,6 @@ wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name)
 }
 #endif
 
-static bool
-clear_wasi_proc_exit_exception(WASMModuleInstance *module_inst)
-{
-#if WASM_ENABLE_LIBC_WASI != 0
-    const char *exception = wasm_get_exception(module_inst);
-    if (exception && !strcmp(exception, "Exception: wasi proc exit")) {
-        /* The "wasi proc exit" exception is thrown by native lib to
-           let wasm app exit, which is a normal behavior, we clear
-           the exception here. */
-        wasm_set_exception(module_inst, NULL);
-        return true;
-    }
-    return false;
-#else
-    return false;
-#endif
-}
-
 #ifdef OS_ENABLE_HW_BOUND_CHECK
 
 static void
@@ -2157,7 +2142,6 @@ wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function,
     wasm_exec_env_set_thread_info(exec_env);
 
     interp_call_wasm(module_inst, exec_env, function, argc, argv);
-    (void)clear_wasi_proc_exit_exception(module_inst);
     return !wasm_get_exception(module_inst) ? true : false;
 }
 
@@ -2185,7 +2169,7 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst,
         }
     }
 
-    ret = wasm_call_function(exec_env, func, argc, argv);
+    ret = wasm_runtime_call_wasm(exec_env, func, argc, argv);
 
     /* don't destroy the exec_env if it isn't created in this function */
     if (!existing_exec_env)
@@ -2455,7 +2439,6 @@ call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx,
 
     interp_call_wasm(module_inst, exec_env, func_inst, argc, argv);
 
-    (void)clear_wasi_proc_exit_exception(module_inst);
     return !wasm_get_exception(module_inst) ? true : false;
 
 got_exception:
@@ -2907,8 +2890,14 @@ llvm_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
 
     import_func = &module->import_functions[func_idx].u.function;
     if (import_func->call_conv_wasm_c_api) {
-        c_api_func_import = module_inst->e->c_api_func_imports + func_idx;
-        func_ptr = c_api_func_import->func_ptr_linked;
+        if (module_inst->e->c_api_func_imports) {
+            c_api_func_import = module_inst->e->c_api_func_imports + func_idx;
+            func_ptr = c_api_func_import->func_ptr_linked;
+        }
+        else {
+            c_api_func_import = NULL;
+            func_ptr = NULL;
+        }
     }
 
     if (!func_ptr) {

+ 1 - 3
core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c

@@ -494,7 +494,6 @@ pthread_start_routine(void *arg)
 {
     wasm_exec_env_t exec_env = (wasm_exec_env_t)arg;
     wasm_exec_env_t parent_exec_env;
-    wasm_module_inst_t module_inst = get_module_inst(exec_env);
     ThreadRoutineArgs *routine_args = exec_env->thread_arg;
     ThreadInfoNode *info_node = routine_args->info_node;
     uint32 argv[1];
@@ -519,8 +518,7 @@ pthread_start_routine(void *arg)
 
     if (!wasm_runtime_call_indirect(exec_env, routine_args->elem_index, 1,
                                     argv)) {
-        if (wasm_runtime_get_exception(module_inst))
-            wasm_cluster_spread_exception(exec_env);
+        /* Exception has already been spread during throwing */
     }
 
     /* destroy pthread key values */

+ 1 - 3
core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c

@@ -50,7 +50,6 @@ static void *
 thread_start(void *arg)
 {
     wasm_exec_env_t exec_env = (wasm_exec_env_t)arg;
-    wasm_module_inst_t module_inst = get_module_inst(exec_env);
     ThreadStartArg *thread_arg = exec_env->thread_arg;
     uint32 argv[2];
 
@@ -59,8 +58,7 @@ thread_start(void *arg)
     argv[1] = thread_arg->arg;
 
     if (!wasm_runtime_call_wasm(exec_env, thread_arg->start_func, 2, argv)) {
-        if (wasm_runtime_get_exception(module_inst))
-            wasm_cluster_spread_exception(exec_env);
+        /* Exception has already been spread during throwing */
     }
 
     // Routine exit

+ 154 - 55
core/iwasm/libraries/thread-mgr/thread_manager.c

@@ -76,6 +76,7 @@ traverse_list(bh_list *l, list_visitor visitor, void *user_data)
     }
 }
 
+/* The caller must lock cluster->lock */
 static bool
 allocate_aux_stack(WASMExecEnv *exec_env, uint32 *start, uint32 *size)
 {
@@ -99,7 +100,6 @@ allocate_aux_stack(WASMExecEnv *exec_env, uint32 *start, uint32 *size)
     if (!cluster->stack_segment_occupied)
         return false;
 
-    os_mutex_lock(&cluster->lock);
     for (i = 0; i < cluster_max_thread_num; i++) {
         if (!cluster->stack_segment_occupied[i]) {
             if (start)
@@ -107,15 +107,15 @@ allocate_aux_stack(WASMExecEnv *exec_env, uint32 *start, uint32 *size)
             if (size)
                 *size = cluster->stack_size;
             cluster->stack_segment_occupied[i] = true;
-            os_mutex_unlock(&cluster->lock);
             return true;
         }
     }
-    os_mutex_unlock(&cluster->lock);
+
     return false;
 #endif
 }
 
+/* The caller must lock cluster->lock */
 static bool
 free_aux_stack(WASMExecEnv *exec_env, uint32 start)
 {
@@ -139,9 +139,7 @@ free_aux_stack(WASMExecEnv *exec_env, uint32 start)
 
     for (i = 0; i < cluster_max_thread_num; i++) {
         if (start == cluster->stack_tops[i]) {
-            os_mutex_lock(&cluster->lock);
             cluster->stack_segment_occupied[i] = false;
-            os_mutex_unlock(&cluster->lock);
             return true;
         }
     }
@@ -304,14 +302,14 @@ wasm_exec_env_get_cluster(WASMExecEnv *exec_env)
     return exec_env->cluster;
 }
 
-bool
+/* The caller must lock cluster->lock */
+static bool
 wasm_cluster_add_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env)
 {
     bool ret = true;
 
     exec_env->cluster = cluster;
 
-    os_mutex_lock(&cluster->lock);
     if (cluster->exec_env_list.len == cluster_max_thread_num + 1) {
         LOG_ERROR("thread manager error: "
                   "maximum number of threads exceeded");
@@ -320,10 +318,11 @@ wasm_cluster_add_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env)
 
     if (ret && bh_list_insert(&cluster->exec_env_list, exec_env) != 0)
         ret = false;
-    os_mutex_unlock(&cluster->lock);
+
     return ret;
 }
 
+/* The caller should lock cluster->lock for thread safety */
 bool
 wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env)
 {
@@ -346,10 +345,8 @@ wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env)
     }
 #endif
 
-    os_mutex_lock(&cluster->lock);
     if (bh_list_remove(&cluster->exec_env_list, exec_env) != 0)
         ret = false;
-    os_mutex_unlock(&cluster->lock);
 
     if (cluster->exec_env_list.len == 0) {
         /* exec_env_list empty, destroy the cluster */
@@ -419,6 +416,12 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env)
         return NULL;
     }
 
+    os_mutex_lock(&cluster->lock);
+
+    if (cluster->has_exception || cluster->processing) {
+        goto fail1;
+    }
+
 #if WASM_ENABLE_INTERP != 0
     if (module_inst->module_type == Wasm_Module_Bytecode) {
         stack_size =
@@ -435,7 +438,7 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env)
 
     if (!(new_module_inst = wasm_runtime_instantiate_internal(
               module, true, stack_size, 0, NULL, 0))) {
-        return NULL;
+        goto fail1;
     }
 
     /* Set custom_data to new module instance */
@@ -450,32 +453,36 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env)
     new_exec_env = wasm_exec_env_create_internal(new_module_inst,
                                                  exec_env->wasm_stack_size);
     if (!new_exec_env)
-        goto fail1;
+        goto fail2;
 
     if (!allocate_aux_stack(exec_env, &aux_stack_start, &aux_stack_size)) {
         LOG_ERROR("thread manager error: "
                   "failed to allocate aux stack space for new thread");
-        goto fail2;
+        goto fail3;
     }
 
     /* Set aux stack for current thread */
     if (!wasm_exec_env_set_aux_stack(new_exec_env, aux_stack_start,
                                      aux_stack_size)) {
-        goto fail3;
+        goto fail4;
     }
 
     if (!wasm_cluster_add_exec_env(cluster, new_exec_env))
-        goto fail3;
+        goto fail4;
+
+    os_mutex_unlock(&cluster->lock);
 
     return new_exec_env;
 
-fail3:
+fail4:
     /* free the allocated aux stack space */
     free_aux_stack(exec_env, aux_stack_start);
-fail2:
+fail3:
     wasm_exec_env_destroy(new_exec_env);
-fail1:
+fail2:
     wasm_runtime_deinstantiate_internal(new_module_inst, true);
+fail1:
+    os_mutex_unlock(&cluster->lock);
 
     return NULL;
 }
@@ -488,8 +495,10 @@ wasm_cluster_destroy_spawned_exec_env(WASMExecEnv *exec_env)
     bh_assert(cluster != NULL);
 
     /* Free aux stack space */
+    os_mutex_lock(&cluster->lock);
     free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom);
     wasm_cluster_del_exec_env(cluster, exec_env);
+    os_mutex_unlock(&cluster->lock);
     wasm_exec_env_destroy_internal(exec_env);
 
     wasm_runtime_deinstantiate_internal(module_inst, true);
@@ -517,19 +526,23 @@ thread_manager_start_routine(void *arg)
 #endif
 
     /* Routine exit */
-    /* Free aux stack space */
-    free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom);
-
-    /* routine exit, destroy instance */
-    wasm_runtime_deinstantiate_internal(module_inst, true);
 
     /* Detach the native thread here to ensure the resources are freed */
     wasm_cluster_detach_thread(exec_env);
 #if WASM_ENABLE_DEBUG_INTERP != 0
     wasm_cluster_thread_exited(exec_env);
 #endif
-    /* Remove and destroy exec_env */
+
+    os_mutex_lock(&cluster->lock);
+    /* Free aux stack space */
+    free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom);
+    /* routine exit, destroy instance */
+    wasm_runtime_deinstantiate_internal(module_inst, true);
+    /* Remove and exec_env */
     wasm_cluster_del_exec_env(cluster, exec_env);
+    os_mutex_unlock(&cluster->lock);
+
+    /* destroy exec_env */
     wasm_exec_env_destroy_internal(exec_env);
 
     os_thread_exit(ret);
@@ -543,33 +556,39 @@ wasm_cluster_create_thread(WASMExecEnv *exec_env,
 {
     WASMCluster *cluster;
     WASMExecEnv *new_exec_env;
-    uint32 aux_stack_start, aux_stack_size;
+    uint32 aux_stack_start = 0, aux_stack_size;
     korp_tid tid;
 
     cluster = wasm_exec_env_get_cluster(exec_env);
     bh_assert(cluster);
 
+    os_mutex_lock(&cluster->lock);
+
+    if (cluster->has_exception || cluster->processing) {
+        goto fail1;
+    }
+
     new_exec_env =
         wasm_exec_env_create_internal(module_inst, exec_env->wasm_stack_size);
     if (!new_exec_env)
-        return -1;
+        goto fail1;
 
     if (alloc_aux_stack) {
         if (!allocate_aux_stack(exec_env, &aux_stack_start, &aux_stack_size)) {
             LOG_ERROR("thread manager error: "
                       "failed to allocate aux stack space for new thread");
-            goto fail1;
+            goto fail2;
         }
 
         /* Set aux stack for current thread */
         if (!wasm_exec_env_set_aux_stack(new_exec_env, aux_stack_start,
                                          aux_stack_size)) {
-            goto fail2;
+            goto fail3;
         }
     }
 
     if (!wasm_cluster_add_exec_env(cluster, new_exec_env))
-        goto fail2;
+        goto fail3;
 
     new_exec_env->thread_start_routine = thread_routine;
     new_exec_env->thread_arg = arg;
@@ -578,19 +597,24 @@ wasm_cluster_create_thread(WASMExecEnv *exec_env,
         != os_thread_create(&tid, thread_manager_start_routine,
                             (void *)new_exec_env,
                             APP_THREAD_STACK_SIZE_DEFAULT)) {
-        goto fail3;
+        goto fail4;
     }
 
+    os_mutex_unlock(&cluster->lock);
+
     return 0;
 
-fail3:
+fail4:
     wasm_cluster_del_exec_env(cluster, new_exec_env);
-fail2:
+fail3:
     /* free the allocated aux stack space */
     if (alloc_aux_stack)
         free_aux_stack(exec_env, aux_stack_start);
-fail1:
+fail2:
     wasm_exec_env_destroy(new_exec_env);
+fail1:
+    os_mutex_unlock(&cluster->lock);
+
     return -1;
 }
 
@@ -666,16 +690,16 @@ notify_debug_instance_exit(WASMExecEnv *exec_env)
 }
 
 void
-wasm_cluster_thread_stopped(WASMExecEnv *exec_env)
+wasm_cluster_thread_waiting_run(WASMExecEnv *exec_env)
 {
+    os_mutex_lock(&exec_env->wait_lock);
+
+    /* Wake up debugger thread after we get the lock, otherwise we may miss the
+     * signal from debugger thread, see
+     * https://github.com/bytecodealliance/wasm-micro-runtime/issues/1860 */
     exec_env->current_status->running_status = STATUS_STOP;
     notify_debug_instance(exec_env);
-}
 
-void
-wasm_cluster_thread_waiting_run(WASMExecEnv *exec_env)
-{
-    os_mutex_lock(&exec_env->wait_lock);
     while (!wasm_cluster_thread_is_running(exec_env)) {
         os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock);
     }
@@ -702,16 +726,20 @@ wasm_cluster_thread_exited(WASMExecEnv *exec_env)
 void
 wasm_cluster_thread_continue(WASMExecEnv *exec_env)
 {
+    os_mutex_lock(&exec_env->wait_lock);
     wasm_cluster_clear_thread_signal(exec_env);
     exec_env->current_status->running_status = STATUS_RUNNING;
     os_cond_signal(&exec_env->wait_cond);
+    os_mutex_unlock(&exec_env->wait_lock);
 }
 
 void
 wasm_cluster_thread_step(WASMExecEnv *exec_env)
 {
+    os_mutex_lock(&exec_env->wait_lock);
     exec_env->current_status->running_status = STATUS_STEP;
     os_cond_signal(&exec_env->wait_cond);
+    os_mutex_unlock(&exec_env->wait_lock);
 }
 
 void
@@ -817,17 +845,30 @@ wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval)
     wasm_cluster_thread_exited(exec_env);
 #endif
     /* App exit the thread, free the resources before exit native thread */
-    /* Free aux stack space */
-    free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom);
     /* Detach the native thread here to ensure the resources are freed */
     wasm_cluster_detach_thread(exec_env);
+    os_mutex_lock(&cluster->lock);
+    /* Free aux stack space */
+    free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom);
     /* Remove and destroy exec_env */
     wasm_cluster_del_exec_env(cluster, exec_env);
+    os_mutex_unlock(&cluster->lock);
     wasm_exec_env_destroy_internal(exec_env);
 
     os_thread_exit(retval);
 }
 
+static void
+set_thread_cancel_flags(WASMExecEnv *exec_env)
+{
+    /* Set the termination flag */
+#if WASM_ENABLE_DEBUG_INTERP != 0
+    wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM);
+#else
+    exec_env->suspend_flags.flags |= 0x01;
+#endif
+}
+
 int32
 wasm_cluster_cancel_thread(WASMExecEnv *exec_env)
 {
@@ -839,12 +880,8 @@ wasm_cluster_cancel_thread(WASMExecEnv *exec_env)
     }
     os_mutex_unlock(&cluster_list_lock);
 
-    /* Set the termination flag */
-#if WASM_ENABLE_DEBUG_INTERP != 0
-    wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM);
-#else
-    exec_env->suspend_flags.flags |= 0x01;
-#endif
+    set_thread_cancel_flags(exec_env);
+
     return 0;
 }
 
@@ -864,15 +901,31 @@ terminate_thread_visitor(void *node, void *user_data)
 void
 wasm_cluster_terminate_all(WASMCluster *cluster)
 {
+    os_mutex_lock(&cluster->lock);
+    cluster->processing = true;
+    os_mutex_unlock(&cluster->lock);
+
     traverse_list(&cluster->exec_env_list, terminate_thread_visitor, NULL);
+
+    os_mutex_lock(&cluster->lock);
+    cluster->processing = false;
+    os_mutex_unlock(&cluster->lock);
 }
 
 void
 wasm_cluster_terminate_all_except_self(WASMCluster *cluster,
                                        WASMExecEnv *exec_env)
 {
+    os_mutex_lock(&cluster->lock);
+    cluster->processing = true;
+    os_mutex_unlock(&cluster->lock);
+
     traverse_list(&cluster->exec_env_list, terminate_thread_visitor,
                   (void *)exec_env);
+
+    os_mutex_lock(&cluster->lock);
+    cluster->processing = false;
+    os_mutex_unlock(&cluster->lock);
 }
 
 static void
@@ -890,15 +943,31 @@ wait_for_thread_visitor(void *node, void *user_data)
 void
 wams_cluster_wait_for_all(WASMCluster *cluster)
 {
+    os_mutex_lock(&cluster->lock);
+    cluster->processing = true;
+    os_mutex_unlock(&cluster->lock);
+
     traverse_list(&cluster->exec_env_list, wait_for_thread_visitor, NULL);
+
+    os_mutex_lock(&cluster->lock);
+    cluster->processing = false;
+    os_mutex_unlock(&cluster->lock);
 }
 
 void
 wasm_cluster_wait_for_all_except_self(WASMCluster *cluster,
                                       WASMExecEnv *exec_env)
 {
+    os_mutex_lock(&cluster->lock);
+    cluster->processing = true;
+    os_mutex_unlock(&cluster->lock);
+
     traverse_list(&cluster->exec_env_list, wait_for_thread_visitor,
                   (void *)exec_env);
+
+    os_mutex_lock(&cluster->lock);
+    cluster->processing = false;
+    os_mutex_unlock(&cluster->lock);
 }
 
 bool
@@ -937,15 +1006,19 @@ suspend_thread_visitor(void *node, void *user_data)
 void
 wasm_cluster_suspend_all(WASMCluster *cluster)
 {
+    os_mutex_lock(&cluster->lock);
     traverse_list(&cluster->exec_env_list, suspend_thread_visitor, NULL);
+    os_mutex_unlock(&cluster->lock);
 }
 
 void
 wasm_cluster_suspend_all_except_self(WASMCluster *cluster,
                                      WASMExecEnv *exec_env)
 {
+    os_mutex_lock(&cluster->lock);
     traverse_list(&cluster->exec_env_list, suspend_thread_visitor,
                   (void *)exec_env);
+    os_mutex_unlock(&cluster->lock);
 }
 
 void
@@ -966,7 +1039,9 @@ resume_thread_visitor(void *node, void *user_data)
 void
 wasm_cluster_resume_all(WASMCluster *cluster)
 {
+    os_mutex_lock(&cluster->lock);
     traverse_list(&cluster->exec_env_list, resume_thread_visitor, NULL);
+    os_mutex_unlock(&cluster->lock);
 }
 
 static void
@@ -975,24 +1050,46 @@ set_exception_visitor(void *node, void *user_data)
     WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
     WASMExecEnv *exec_env = (WASMExecEnv *)user_data;
     WASMModuleInstanceCommon *module_inst = get_module_inst(exec_env);
-    WASMModuleInstanceCommon *curr_module_inst = get_module_inst(curr_exec_env);
-    const char *exception = wasm_runtime_get_exception(module_inst);
-    /* skip "Exception: " */
-    exception += 11;
+    WASMModuleInstance *wasm_inst = (WASMModuleInstance *)module_inst;
+
+    if (curr_exec_env != exec_env) {
+        WASMModuleInstance *curr_wasm_inst =
+            (WASMModuleInstance *)get_module_inst(curr_exec_env);
+
+        bh_memcpy_s(curr_wasm_inst->cur_exception,
+                    sizeof(curr_wasm_inst->cur_exception),
+                    wasm_inst->cur_exception, sizeof(wasm_inst->cur_exception));
+        /* Terminate the thread so it can exit from dead loops */
+        set_thread_cancel_flags(curr_exec_env);
+    }
+}
+
+static void
+clear_exception_visitor(void *node, void *user_data)
+{
+    WASMExecEnv *exec_env = (WASMExecEnv *)user_data;
+    WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
 
     if (curr_exec_env != exec_env) {
-        curr_module_inst = get_module_inst(curr_exec_env);
-        wasm_runtime_set_exception(curr_module_inst, exception);
+        WASMModuleInstance *curr_wasm_inst =
+            (WASMModuleInstance *)get_module_inst(curr_exec_env);
+
+        curr_wasm_inst->cur_exception[0] = '\0';
     }
 }
 
 void
-wasm_cluster_spread_exception(WASMExecEnv *exec_env)
+wasm_cluster_spread_exception(WASMExecEnv *exec_env, bool clear)
 {
     WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
     bh_assert(cluster);
 
-    traverse_list(&cluster->exec_env_list, set_exception_visitor, exec_env);
+    os_mutex_lock(&cluster->lock);
+    cluster->has_exception = !clear;
+    traverse_list(&cluster->exec_env_list,
+                  clear ? clear_exception_visitor : set_exception_visitor,
+                  exec_env);
+    os_mutex_unlock(&cluster->lock);
 }
 
 static void
@@ -1020,7 +1117,9 @@ wasm_cluster_spread_custom_data(WASMModuleInstanceCommon *module_inst,
         cluster = wasm_exec_env_get_cluster(exec_env);
         bh_assert(cluster);
 
+        os_mutex_lock(&cluster->lock);
         traverse_list(&cluster->exec_env_list, set_custom_data_visitor,
                       custom_data);
+        os_mutex_unlock(&cluster->lock);
     }
 }

+ 13 - 7
core/iwasm/libraries/thread-mgr/thread_manager.h

@@ -36,6 +36,18 @@ struct WASMCluster {
 #endif
     /* Size of every stack segment */
     uint32 stack_size;
+    /* When has_exception == true, this cluster should refuse any spawn thread
+     * requests, this flag can be cleared by calling
+     * wasm_runtime_clear_exception on instances of any threads of this cluster
+     */
+    bool has_exception;
+    /* When processing is true, this cluster should refuse any spawn thread
+     * requests. This is a short-lived state, must be cleared immediately once
+     * the processing finished.
+     * This is used to avoid dead lock when one thread waiting another thread
+     * with lock, see wams_cluster_wait_for_all and wasm_cluster_terminate_all
+     */
+    bool processing;
 #if WASM_ENABLE_DEBUG_INTERP != 0
     WASMDebugInstance *debug_inst;
 #endif
@@ -115,9 +127,6 @@ void
 wasm_cluster_wait_for_all_except_self(WASMCluster *cluster,
                                       WASMExecEnv *exec_env);
 
-bool
-wasm_cluster_add_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env);
-
 bool
 wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env);
 
@@ -125,7 +134,7 @@ WASMExecEnv *
 wasm_clusters_search_exec_env(WASMModuleInstanceCommon *module_inst);
 
 void
-wasm_cluster_spread_exception(WASMExecEnv *exec_env);
+wasm_cluster_spread_exception(WASMExecEnv *exec_env, bool clear);
 
 WASMExecEnv *
 wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env);
@@ -168,9 +177,6 @@ wasm_cluster_destroy_exenv_status(WASMCurrentEnvStatus *status);
 void
 wasm_cluster_send_signal_all(WASMCluster *cluster, uint32 signo);
 
-void
-wasm_cluster_thread_stopped(WASMExecEnv *exec_env);
-
 void
 wasm_cluster_thread_waiting_run(WASMExecEnv *exec_env);
 

+ 110 - 4
core/shared/platform/nuttx/nuttx_platform.c

@@ -145,9 +145,115 @@ utimensat(int fd, const char *path, const struct timespec ts[2], int flag)
 
 #endif /* !defined(AT_FDCWD) */
 
-DIR *
-fdopendir(int fd)
+#ifndef CONFIG_NET
+
+#include <netdb.h>
+
+int
+accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen)
 {
-    errno = ENOSYS;
-    return NULL;
+    errno = ENOTSUP;
+    return -1;
+}
+
+int
+bind(int sockfd, FAR const struct sockaddr *addr, socklen_t addrlen)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+int
+listen(int sockfd, int backlog)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+int
+connect(int sockfd, FAR const struct sockaddr *addr, socklen_t addrlen)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+ssize_t
+recvfrom(int sockfd, FAR void *buf, size_t len, int flags,
+         FAR struct sockaddr *from, FAR socklen_t *fromlen)
+{
+    errno = ENOTSUP;
+    return -1;
 }
+
+ssize_t
+send(int sockfd, FAR const void *buf, size_t len, int flags)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+ssize_t
+sendto(int sockfd, FAR const void *buf, size_t len, int flags,
+       FAR const struct sockaddr *to, socklen_t tolen)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+int
+socket(int domain, int type, int protocol)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+int
+shutdown(int sockfd, int how)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+int
+getaddrinfo(FAR const char *nodename, FAR const char *servname,
+            FAR const struct addrinfo *hints, FAR struct addrinfo **res)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+void
+freeaddrinfo(FAR struct addrinfo *ai)
+{}
+
+int
+setsockopt(int sockfd, int level, int option, FAR const void *value,
+           socklen_t value_len)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+int
+getsockopt(int sockfd, int level, int option, FAR void *value,
+           FAR socklen_t *value_len)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+int
+getpeername(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+int
+getsockname(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+#endif

+ 1 - 0
core/shared/platform/windows/platform_internal.h

@@ -72,6 +72,7 @@ typedef struct os_thread_wait_node *os_thread_wait_list;
 typedef struct korp_cond {
     korp_mutex wait_list_lock;
     os_thread_wait_list thread_wait_list;
+    struct os_thread_wait_node *thread_wait_list_end;
 } korp_cond;
 
 #define bh_socket_t SOCKET

+ 29 - 17
core/shared/platform/windows/win_thread.c

@@ -37,6 +37,8 @@ typedef struct os_thread_data {
     korp_mutex wait_lock;
     /* Waiting list of other threads who are joining this thread */
     os_thread_wait_list thread_wait_list;
+    /* End node of the waiting list */
+    os_thread_wait_node *thread_wait_list_end;
     /* Whether the thread has exited */
     bool thread_exited;
     /* Thread return value */
@@ -174,7 +176,8 @@ os_thread_cleanup(void *retval)
             os_sem_signal(&head->sem);
             head = next;
         }
-        thread_data->thread_wait_list = NULL;
+        thread_data->thread_wait_list = thread_data->thread_wait_list_end =
+            NULL;
     }
     /* Set thread status and thread return value */
     thread_data->thread_exited = true;
@@ -313,14 +316,14 @@ os_thread_join(korp_tid thread, void **p_retval)
     }
 
     /* Thread is running */
-    if (!thread_data->thread_wait_list)
-        thread_data->thread_wait_list = &curr_thread_data->wait_node;
-    else {
+    if (!thread_data->thread_wait_list) { /* Waiting list is empty */
+        thread_data->thread_wait_list = thread_data->thread_wait_list_end =
+            &curr_thread_data->wait_node;
+    }
+    else { /* Waiting list isn't empty */
         /* Add to end of waiting list */
-        os_thread_wait_node *p = thread_data->thread_wait_list;
-        while (p->next)
-            p = p->next;
-        p->next = &curr_thread_data->wait_node;
+        thread_data->thread_wait_list_end->next = &curr_thread_data->wait_node;
+        thread_data->thread_wait_list_end = &curr_thread_data->wait_node;
     }
 
     os_mutex_unlock(&thread_data->wait_lock);
@@ -545,7 +548,7 @@ os_cond_init(korp_cond *cond)
     if (os_mutex_init(&cond->wait_list_lock) != BHT_OK)
         return BHT_ERROR;
 
-    cond->thread_wait_list = NULL;
+    cond->thread_wait_list = cond->thread_wait_list_end = NULL;
     return BHT_OK;
 }
 
@@ -568,14 +571,13 @@ os_cond_wait_internal(korp_cond *cond, korp_mutex *mutex, bool timed,
     bh_assert(cond);
     bh_assert(mutex);
     os_mutex_lock(&cond->wait_list_lock);
-    if (!cond->thread_wait_list)
-        cond->thread_wait_list = node;
-    else {
+    if (!cond->thread_wait_list) { /* Waiting list is empty */
+        cond->thread_wait_list = cond->thread_wait_list_end = node;
+    }
+    else { /* Waiting list isn't empty */
         /* Add to end of wait list */
-        os_thread_wait_node *p = cond->thread_wait_list;
-        while (p->next)
-            p = p->next;
-        p->next = node;
+        cond->thread_wait_list_end->next = node;
+        cond->thread_wait_list_end = node;
     }
     os_mutex_unlock(&cond->wait_list_lock);
 
@@ -590,14 +592,24 @@ os_cond_wait_internal(korp_cond *cond, korp_mutex *mutex, bool timed,
 
     /* Remove wait node from wait list */
     os_mutex_lock(&cond->wait_list_lock);
-    if (cond->thread_wait_list == node)
+    if (cond->thread_wait_list == node) {
         cond->thread_wait_list = node->next;
+
+        if (cond->thread_wait_list_end == node) {
+            bh_assert(node->next == NULL);
+            cond->thread_wait_list_end = NULL;
+        }
+    }
     else {
         /* Remove from the wait list */
         os_thread_wait_node *p = cond->thread_wait_list;
         while (p->next != node)
             p = p->next;
         p->next = node->next;
+
+        if (cond->thread_wait_list_end == node) {
+            cond->thread_wait_list_end = p;
+        }
     }
     os_mutex_unlock(&cond->wait_list_lock);
 

+ 135 - 0
doc/memory_usage.md

@@ -0,0 +1,135 @@
+Memory usage estimation for a module
+====================================
+
+This document aims to provide information useful to make a rough estimation
+of necessary memory to execute a WASM module.
+
+Instead of trying to cover every possible configurations,
+the following configuration is assumed in this document:
+
+* Module is built with `wasi-sdk`
+* Module is loaded with `wasm_runtime_load`
+* AOT is used
+* WASI is used
+* libc heap is used
+* app heap is not used
+* The pthread implementation in `wasi-libc`, which is based on `wasi-threads`
+  (`WASM_ENABLE_LIB_WASI_THREADS`, which is not available on `main` branch
+  yet) might be used
+* The another pthread implementation (`WASM_ENABLE_LIB_PTHREAD`) is not used
+
+Module
+------
+
+The memory to store the module binary is allocated by the embedder and
+passed to `wasm_runtime_load`.
+While WAMR owns the buffer, WAMR might make in-place modifications to
+its contents.
+
+Loaded module and its instances
+-------------------------------
+
+Many of data structures for module and instances are allocated from
+the global heap. (aka. `wasm_runtime_malloc`)
+
+AOT code section
+----------------
+
+Memory to load AOT machine code section.
+
+Because this memory needs to be executable, depending on platforms,
+it's allocated from a separate allocator.
+For example, `mmap` and `mprotect` are used on POSIX-like platforms.
+
+Linear memory
+-------------
+
+A WASM linear memory is either shared or non-shared.
+
+A WASM linear memory has `min` and `max` sizes.
+(They correspond to `wasm-ld`'s `--init-memory` and `--max-memory` options.)
+They are in the number of WASM pages, each of which is of 65536 bytes.
+The `max` is optional for non-shared memory. When omitted, it effectivily
+means unlimited.
+
+If `OS_ENABLE_HW_BOUND_CHECK` is enabled, the memory is allocated via
+`os_mmap` and `os_mem_commit`/`os_mprotect`.
+Otherwise, it's allocated from the global heap.
+
+If the memory is shared and `OS_ENABLE_HW_BOUND_CHECK` is not enabled,
+the `max` size of memory is allocated on instantiation.
+
+Otherwise, the `min` size of memory is allocated on instantiation.
+It can later grow up to the `max` size via the `memory.grow` instruction.
+
+Libc heap
+---------
+
+The libc heap is the last (highest address) part of linear memory,
+which might be dynamically grown with `memory.grow` instruction, when
+necessary to serve memory allocations within the module.
+
+App heap
+--------
+
+Not used for the above mentioned configuration.
+
+You can safely disable the app heap creation by specifying `0` for
+the `heap_size` argument of `wasm_runtime_instantiate`.
+(It's automatically disabled if malloc/free are exported from the module.)
+
+WASM stack
+----------
+
+Operand stack is not used for AOT.
+
+However, a small amount of WASM stack is used for call frames when
+certain features are enabled.
+(`WASM_ENABLE_DUMP_CALL_STACK` or `WASM_ENABLE_PERF_PROFILING`)
+
+It's allocated from the global heap.
+
+You can specify its size with the `stack_size` argument of
+`wasm_runtime_instantiate` and `wasm_runtime_create_exec_env`.
+(1 is the minimum because 0 means the default.)
+
+AUX stack (aka. C shadow stack)
+-------------------------------
+
+For the main thread, it's a part of the linear memory,
+between `__data_end` and `__heap_base` symbols.
+You can control the size of this stack with `wasm-ld`'s
+`-z stack-size` option.
+
+For threads created by `pthread_create`, libc allocates the stack for
+them dynamically from the libc heap.
+The size of this stack is inherited from the main thread's one
+unless overwritten with `pthread_attr_setstacksize` etc.
+
+WAMR tries to detect overflow/underflow when updating the stack pointer
+global. For threads created by `pthread_create`, the detection mechanism
+is disabled as of writing this.
+
+Native stack
+------------
+
+The stack of the host environment thread which runs WAMR.
+
+For threads created by `pthread_create`, WAMR automatically creates
+host threads to run those WASM threads. The stack size of these host
+threads are controlled by a build-time configuration.
+(`APP_THREAD_STACK_SIZE_DEFAULT`)
+
+In some configurations, runtime overflow can be detected using hardware traps.
+(`OS_ENABLE_HW_BOUND_CHECK`)
+
+In some configurations, explicit overflow detection logic can be emitted
+into AOT modules themselves. (cf. `os_thread_get_stack_boundary`,
+`check_stack_boundary`, `wamrc --stack-bounds-checks=1/0`)
+
+Memory profiling
+================
+
+You can collect and dump detailed information about memory usage
+by actually running a module with the `WASM_ENABLE_MEMORY_PROFILING`
+build-time option.

+ 7 - 1
language-bindings/go/build.sh

@@ -7,6 +7,12 @@ PLATFORM=$(uname -s | tr A-Z a-z)
 CUR_DIR=$PWD
 WAMR_DIR=$PWD/../..
 WAMR_GO_DIR=$PWD/wamr
+ARCH=$(uname -m)
+if [ ${ARCH} = "arm64" ]; then
+    ARCH="aarch64"
+elif [ ${ARCH} = "x86_64" ]; then
+    ARCH="amd64"
+fi
 
 cp -a ${WAMR_DIR}/core/iwasm/include/*.h ${WAMR_GO_DIR}/packaged/include
 
@@ -15,7 +21,7 @@ cmake ${WAMR_DIR}/product-mini/platforms/${PLATFORM} \
     -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_DUMP_CALL_STACK=1 \
     -DWAMR_BUILD_MEMORY_PROFILING=1
 make -j ${nproc}
-cp -a libvmlib.a ${WAMR_GO_DIR}/packaged/lib/${PLATFORM}-amd64
+cp -a libvmlib.a ${WAMR_GO_DIR}/packaged/lib/${PLATFORM}-${ARCH}
 
 cd ${WAMR_GO_DIR}
 go test

+ 1 - 0
language-bindings/go/go.sum

@@ -5,6 +5,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 6 - 0
language-bindings/go/wamr/packaged/lib/darwin-aarch64/dummy.go

@@ -0,0 +1,6 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+package darwin_aarch64

+ 3 - 3
samples/gui/wasm-apps/increase/Makefile

@@ -25,9 +25,9 @@ SRCS += $(APP_FRAMEWORK_DIR)/wgl/app/src/*.c
 
 all:
 	@$(CC) $(CFLAGS) $(SRCS) \
-    --target=wasm32 -O3 -z stack-size=2048 -Wl,--initial-memory=65536 \
-    -Wl,--allow-undefined \
-    -Wl,--strip-all,--no-entry -nostdlib \
+    --target=wasm32-wasi -O3 -z stack-size=2048 -Wl,--initial-memory=65536 \
+    -nostdlib -Wl,--allow-undefined \
+    -Wl,--strip-all,--no-entry \
     -Wl,--export=on_init -Wl,--export=on_timer_callback \
     -Wl,--export=on_widget_event \
     -Wl,--export=__heap_base,--export=__data_end \

+ 3 - 0
samples/multi-thread/wasm-apps/CMakeLists.txt

@@ -38,3 +38,6 @@ set (CMAKE_EXE_LINKER_FLAGS
 
 add_executable(test.wasm  main.c)
 target_link_libraries(test.wasm)
+
+add_executable(main_thread_exception.wasm  main_thread_exception.c)
+target_link_libraries(main_thread_exception.wasm)

+ 36 - 0
samples/multi-thread/wasm-apps/main_thread_exception.c

@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include <stdio.h>
+#include <pthread.h>
+
+typedef struct ThreadArgs {
+    int start;
+    int length;
+} ThreadArgs;
+
+void *
+thread(void *args)
+{
+    while (1) {
+        /* When other threads (including main thread) throw exception,
+            this thread can successfully exit the dead loop */
+    }
+}
+
+int
+main()
+{
+    pthread_t tids;
+
+    if (pthread_create(&tids, NULL, thread, NULL) != 0) {
+        printf("pthread_create failed\n");
+    }
+
+    /* Trigger an exception */
+    __builtin_trap();
+
+    return 0;
+}

+ 2 - 2
test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/help.html

@@ -33,7 +33,7 @@
                         </h1>
                         <p>
                             1. Download a simple runtime (build for ubuntu 20.04 64 bits, other platforms please build
-                            from the <a href="https://github.com/intel/wasm-micro-runtime">source code</a>)
+                            from the <a href="https://github.com/bytecodealliance/wasm-micro-runtime/tree/main/samples/simple">source code</a>)
                         </p>
                         <p>
                             2. In the terminal: <code>cd ~/Download && ./simple -a 82.156.57.236</code>
@@ -44,7 +44,7 @@
                                 <h5>
                                     Notes:
                                 </h5> We also have a <strong>UI-enabled runtime</strong>, please <a
-                                    href="../static/upload/simple">download here</a> and enjoy.</strong> It may require
+                                    href="../static/upload/wasm_runtime_wgl">download here</a> and enjoy.</strong> It may require
                                 a few more setups.
                                 <p>Before running the UI-enabled runtime, please install some required softwares:</p>
                                 <p><code>sudo apt-get install libsdl2-2.0-0:i386</code> </p>

+ 25 - 9
test-tools/IoT-APP-Store-Demo/wasm_django/server/wasm_server.py

@@ -16,14 +16,18 @@ import logging
 import os
 
 attr_type_list =  [
-    "ATTR_NONE",
-    "ATTR_TYPE_SHORT",
-    "ATTR_TYPE_INT",
+    "ATTR_TYPE_BYTE", # = ATTR_TYPE_INT8
+    "ATTR_TYPE_SHORT",# = ATTR_TYPE_INT16
+    "ATTR_TYPE_INT", # = ATTR_TYPE_INT32
     "ATTR_TYPE_INT64",
-    "ATTR_TYPE_BYTE",
+    "ATTR_TYPE_UINT8",
     "ATTR_TYPE_UINT16",
+    "ATTR_TYPE_UINT32",
+    "ATTR_TYPE_UINT64",
     "ATTR_TYPE_FLOAT",
     "ATTR_TYPE_DOUBLE",
+    "ATTR_NONE",
+    "ATTR_NONE",
     "ATTR_TYPE_BOOLEAN",
     "ATTR_TYPE_STRING",
     "ATTR_TYPE_BYTEARRAY"
@@ -140,26 +144,38 @@ def decode_attr_container(msg):
         attr_type = attr_type_list[int(type_index[0])]
         buf = buf[1 : ]
 
-        if attr_type == "ATTR_TYPE_SHORT":
+        if attr_type == "ATTR_TYPE_BYTE": # = ATTR_TYPE_INT8
+            (attr_value, ) = struct.unpack('@c', buf[0 : 1])
+            buf = buf[1 : ]
+            # continue
+        elif attr_type == "ATTR_TYPE_SHORT": # = ATTR_TYPE_INT16
             (attr_value, ) = struct.unpack('@h', buf[0 : 2])
             buf = buf[2 : ]
             # continue
-        elif attr_type == "ATTR_TYPE_INT":
-            (attr_value, ) = struct.unpack('@I', buf[0 : 4])
+        elif attr_type == "ATTR_TYPE_INT": # = ATTR_TYPE_INT32
+            (attr_value, ) = struct.unpack('@i', buf[0 : 4])
             buf = buf[4 : ]
             # continue
         elif attr_type == "ATTR_TYPE_INT64":
             (attr_value, ) = struct.unpack('@q', buf[0 : 8])
             buf = buf[8 : ]
             # continue
-        elif attr_type == "ATTR_TYPE_BYTE":
-            (attr_value, ) = struct.unpack('@c', buf[0 : 1])
+        elif attr_type == "ATTR_TYPE_UINT8":
+            (attr_value, ) = struct.unpack('@B', buf[0 : 1])
             buf = buf[1 : ]
             # continue
         elif attr_type == "ATTR_TYPE_UINT16":
             (attr_value, ) = struct.unpack('@H', buf[0 : 2])
             buf = buf[2 : ]
             # continue
+        elif attr_type == "ATTR_TYPE_UINT32":
+            (attr_value, ) = struct.unpack('@I', buf[0 : 4])
+            buf = buf[4 : ]
+            # continue
+        elif attr_type == "ATTR_TYPE_UINT64":
+            (attr_value, ) = struct.unpack('@Q', buf[0 : 8])
+            buf = buf[8 : ]
+            # continue
         elif attr_type == "ATTR_TYPE_FLOAT":
             (attr_value, ) = struct.unpack('@f', buf[0 : 4])
             buf = buf[4 : ]

BIN
test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/connection.wasm


BIN
test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/event_publisher.wasm


BIN
test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/event_subscriber.wasm


BIN
test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/request_handler.wasm


BIN
test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/request_sender.wasm


BIN
test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sensor.wasm


BIN
test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/simple


BIN
test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/connection.wasm


BIN
test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/event_publisher.wasm


BIN
test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/event_subscriber.wasm


BIN
test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/request_handler.wasm


BIN
test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/request_sender.wasm


BIN
test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/timer.wasm


BIN
test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/timer.wasm


BIN
test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/ui_app.wasm


BIN
test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/vgl_wasm_runtime


BIN
test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/wasm_runtime_wgl


+ 42 - 18
test-tools/host-tool/src/host_tool_utils.c

@@ -15,11 +15,14 @@
 
 typedef union jvalue {
     bool z;
-    int8_t b;
-    uint16_t c;
-    int16_t s;
-    int32_t i;
-    int64_t j;
+    int8_t i8;
+    uint8_t u8;
+    int16_t i16;
+    uint16_t u16;
+    int32_t i32;
+    uint32_t u32;
+    int64_t i64;
+    uint64_t u64;
     float f;
     double d;
 } jvalue;
@@ -90,43 +93,64 @@ attr2json(const attr_container_t *attr_cont)
         type = *p++;
 
         switch (type) {
-            case ATTR_TYPE_SHORT:
-                bh_memcpy_s(&value.s, sizeof(int16_t), p, sizeof(int16_t));
-                if (NULL == (obj = cJSON_CreateNumber(value.s)))
+            case ATTR_TYPE_BYTE: /* = ATTR_TYPE_INT8 */
+                bh_memcpy_s(&value.i8, 1, p, 1);
+                if (NULL == (obj = cJSON_CreateNumber(value.i8)))
+                    goto fail;
+                cJSON_AddItemToObject(root, key, obj);
+                p++;
+                break;
+            case ATTR_TYPE_SHORT: /* = ATTR_TYPE_INT16 */
+                bh_memcpy_s(&value.i16, sizeof(int16_t), p, sizeof(int16_t));
+                if (NULL == (obj = cJSON_CreateNumber(value.i16)))
                     goto fail;
                 cJSON_AddItemToObject(root, key, obj);
                 /* another approach: cJSON_AddNumberToObject(root, key, value.s)
                  */
                 p += 2;
                 break;
-            case ATTR_TYPE_INT:
-                bh_memcpy_s(&value.i, sizeof(int32_t), p, sizeof(int32_t));
-                if (NULL == (obj = cJSON_CreateNumber(value.i)))
+            case ATTR_TYPE_INT: /* = ATTR_TYPE_INT32 */
+                bh_memcpy_s(&value.i32, sizeof(int32_t), p, sizeof(int32_t));
+                if (NULL == (obj = cJSON_CreateNumber(value.i32)))
                     goto fail;
                 cJSON_AddItemToObject(root, key, obj);
                 p += 4;
                 break;
             case ATTR_TYPE_INT64:
-                bh_memcpy_s(&value.j, sizeof(uint64_t), p, sizeof(uint64_t));
-                if (NULL == (obj = cJSON_CreateNumber(value.j)))
+                bh_memcpy_s(&value.i64, sizeof(int64_t), p, sizeof(int64_t));
+                if (NULL == (obj = cJSON_CreateNumber(value.i64)))
                     goto fail;
                 cJSON_AddItemToObject(root, key, obj);
                 p += 8;
                 break;
-            case ATTR_TYPE_BYTE:
-                bh_memcpy_s(&value.b, 1, p, 1);
-                if (NULL == (obj = cJSON_CreateNumber(value.b)))
+            case ATTR_TYPE_UINT8:
+                bh_memcpy_s(&value.u8, 1, p, 1);
+                if (NULL == (obj = cJSON_CreateNumber(value.u8)))
                     goto fail;
                 cJSON_AddItemToObject(root, key, obj);
                 p++;
                 break;
             case ATTR_TYPE_UINT16:
-                bh_memcpy_s(&value.c, sizeof(uint16_t), p, sizeof(uint16_t));
-                if (NULL == (obj = cJSON_CreateNumber(value.c)))
+                bh_memcpy_s(&value.u16, sizeof(uint16_t), p, sizeof(uint16_t));
+                if (NULL == (obj = cJSON_CreateNumber(value.u16)))
                     goto fail;
                 cJSON_AddItemToObject(root, key, obj);
                 p += 2;
                 break;
+            case ATTR_TYPE_UINT32:
+                bh_memcpy_s(&value.u32, sizeof(uint32_t), p, sizeof(uint32_t));
+                if (NULL == (obj = cJSON_CreateNumber(value.u32)))
+                    goto fail;
+                cJSON_AddItemToObject(root, key, obj);
+                p += 4;
+                break;
+            case ATTR_TYPE_UINT64:
+                bh_memcpy_s(&value.u64, sizeof(uint64_t), p, sizeof(uint64_t));
+                if (NULL == (obj = cJSON_CreateNumber(value.u64)))
+                    goto fail;
+                cJSON_AddItemToObject(root, key, obj);
+                p += 8;
+                break;
             case ATTR_TYPE_FLOAT:
                 bh_memcpy_s(&value.f, sizeof(float), p, sizeof(float));
                 if (NULL == (obj = cJSON_CreateNumber(value.f)))

+ 1 - 1
test-tools/wamr-ide/VSCode-Extension/package.json

@@ -1,6 +1,6 @@
 {
     "name": "wamride",
-    "publisher": "wamr",
+    "publisher": "wamr-publisher",
     "repository": {
         "url": "https://github.com/bytecodealliance/wasm-micro-runtime/tree/main/test-tools/wamr-ide"
     },

+ 37 - 1
tests/wamr-test-suites/test_wamr.sh

@@ -46,6 +46,7 @@ PLATFORM=$(uname -s | tr A-Z a-z)
 PARALLELISM=0
 ENABLE_QEMU=0
 QEMU_FIRMWARE=""
+WASI_TESTSUITE_COMMIT="1d913f28b3f0d92086d6f50405cf85768e648b54"
 
 while getopts ":s:cabt:m:MCpSXxPQF:" opt
 do
@@ -447,7 +448,10 @@ function spec_test()
     cd ${WORK_DIR}
     echo "python3 ./all.py ${ARGS_FOR_SPEC_TEST} | tee -a ${REPORT_DIR}/spec_test_report.txt"
     python3 ./all.py ${ARGS_FOR_SPEC_TEST} | tee -a ${REPORT_DIR}/spec_test_report.txt
-    [[ ${PIPESTATUS[0]} -ne 0 ]] && exit 1
+    if [[ ${PIPESTATUS[0]} -ne 0 ]];then
+        echo -e "\nspec tests FAILED" | tee -a ${REPORT_DIR}/spec_test_report.txt
+        exit 1
+    fi
     cd -
 
     echo -e "\nFinish spec tests" | tee -a ${REPORT_DIR}/spec_test_report.txt
@@ -469,6 +473,38 @@ function wasi_test()
     echo "Finish wasi tests"
 }
 
+function wasi_certification_test()
+{
+    echo  "Now start wasi tests"
+
+    cd ${WORK_DIR}
+    if [ ! -d "wasi-testsuite" ]; then
+        echo "wasi not exist, clone it from github"
+        git clone -b prod/testsuite-base \
+            --single-branch https://github.com/WebAssembly/wasi-testsuite.git
+    fi
+    cd wasi-testsuite
+    git reset --hard ${WASI_TESTSUITE_COMMIT}
+
+    python3 -m venv wasi-env && source wasi-env/bin/activate
+    python3 -m pip install -r test-runner/requirements.txt
+    IWASM_PATH=$(dirname ${IWASM_CMD})
+    PATH=${PATH}:${IWASM_PATH} python3 test-runner/wasi_test_runner.py \
+                -r adapters/wasm-micro-runtime.sh \
+                -t \
+                    tests/c/testsuite/ \
+                    tests/assemblyscript/testsuite/ \
+                | tee -a ${REPORT_DIR}/wasi_test_report.txt
+    exit_code=${PIPESTATUS[0]}
+    deactivate
+
+    if [[ ${exit_code} -ne 0 ]];then
+        echo -e "\nwasi tests FAILED" | tee -a ${REPORT_DIR}/wasi_test_report.txt
+        exit 1
+    fi
+    echo -e "\nFinish wasi tests" | tee -a ${REPORT_DIR}/wasi_test_report.txt
+}
+
 function polybench_test()
 {
     echo "Now start polybench tests"

+ 44 - 3
wamr-sdk/app/libc-builtin-sysroot/include/stdint.h

@@ -11,6 +11,13 @@ extern "C" {
 #endif
 
 /* clang-format off */
+/* The word size of platform */
+#ifdef __wasm64__
+#define __WORDSIZE 64
+#else
+#define __WORDSIZE 32
+#endif
+
 typedef char            int8_t;
 typedef short int       int16_t;
 typedef int             int32_t;
@@ -25,22 +32,56 @@ typedef unsigned long long int  uint64_t;
 typedef __INTPTR_TYPE__		intptr_t;
 typedef __UINTPTR_TYPE__	uintptr_t;
 
+/* Signed and unsigned  */
+#if __WORDSIZE == 64
+#define INT64_C(c) c ## L
+#define UINT64_C(c) c ## UL
+#define INTMAX_C(c)  c ## L
+#define UINTMAX_C(c) c ## UL
+#else
+#define INT64_C(c) c ## LL
+#define UINT64_C(c) c ## ULL
+#define INTMAX_C(c)  c ## LL
+#define UINTMAX_C(c) c ## ULL
+#endif
+
+
 /* Minimum of signed integral types.  */
 # define INT8_MIN		(-128)
 # define INT16_MIN		(-32767-1)
 # define INT32_MIN		(-2147483647-1)
-# define INT64_MIN		(-__INT64_C(9223372036854775807)-1)
+# define INT64_MIN		(-INT64_C(9223372036854775807)-1)
+
 /* Maximum of signed integral types.  */
 # define INT8_MAX		(127)
 # define INT16_MAX		(32767)
 # define INT32_MAX		(2147483647)
-# define INT64_MAX		(__INT64_C(9223372036854775807))
+# define INT64_MAX		(INT64_C(9223372036854775807))
 
 /* Maximum of unsigned integral types.  */
 # define UINT8_MAX		(255)
 # define UINT16_MAX		(65535)
 # define UINT32_MAX		(4294967295U)
-# define UINT64_MAX		(__UINT64_C(18446744073709551615))
+# define UINT64_MAX		(UINT64_C(18446744073709551615))
+
+/* Values to test for integral types holding `void *' pointer.  */
+#if __WORDSIZE == 64
+#define INTPTR_MIN      INT64_MIN
+#define INTPTR_MAX      INT64_MAX
+#define UINTPTR_MAX     UINT64_MAX
+#else
+#define INTPTR_MIN      INT32_MIN
+#define INTPTR_MAX      INT32_MAX
+#define UINTPTR_MAX     UINT32_MAX
+#endif
+
+/* Limit of `size_t' type.  */
+#if __WORDSIZE == 64
+#define SIZE_MAX        UINT64_MAX
+#else
+#define SIZE_MAX        UINT32_MAX
+#endif
+
 /* clang-format on */
 
 #ifdef __cplusplus