Merge branch main into dev/wasi_threads

This commit is contained in:
Wenyong Huang 2023-01-21 13:18:55 +08:00
commit c7141894fb
52 changed files with 1155 additions and 345 deletions

View File

@ -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

View File

@ -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

View File

@ -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 }}

View File

@ -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);

View File

@ -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.

View File

@ -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);

View File

@ -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

View File

@ -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:

View File

@ -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 */

View File

@ -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

View File

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

View File

@ -9,6 +9,36 @@
#include "../aot/aot_intrinsic.h"
#include "../aot/aot_runtime.h"
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)
{
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, 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, lhs, rhs);
if (!res) {
goto fail;
}
res = LLVMBuildIntCast(comp_ctx->builder, res, INT1_TYPE, "bit_cast");
}
else {
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,
@ -18,26 +48,8 @@ trunc_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMBasicBlockRef check_nan_succ, check_overflow_succ;
LLVMValueRef is_less, is_greater, res;
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);
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);
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 = 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;
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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) {

View File

@ -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 */

View File

@ -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

View File

@ -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;
}
@ -665,17 +689,17 @@ notify_debug_instance_exit(WASMExecEnv *exec_env)
on_thread_exit_event(cluster->debug_inst, exec_env);
}
void
wasm_cluster_thread_stopped(WASMExecEnv *exec_env)
{
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);
/* 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);
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) {
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);
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) {
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);
}
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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
doc/memory_usage.md Normal file
View File

@ -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.

View File

@ -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

View File

@ -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=

View File

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

View File

@ -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 \

View File

@ -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)

View File

@ -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;
}

View File

@ -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>

View File

@ -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 : ]

View File

@ -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)))

View File

@ -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"
},

View File

@ -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"

View File

@ -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