mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-03-12 00:45:28 +00:00
Merge branch main into dev/wasi_threads
This commit is contained in:
commit
c7141894fb
3
.github/workflows/build_wamr_vscode_ext.yml
vendored
3
.github/workflows/build_wamr_vscode_ext.yml
vendored
|
@ -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
|
||||
|
|
|
@ -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
.github/workflows/release_process.yml
vendored
1
.github/workflows/release_process.yml
vendored
|
@ -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 }}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -149,6 +149,7 @@ typedef struct AOTImportGlobal {
|
|||
uint32 data_offset;
|
||||
/* global data after linked */
|
||||
WASMValue global_data_linked;
|
||||
bool is_linked;
|
||||
} AOTImportGlobal;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
135
doc/memory_usage.md
Normal 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.
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
package darwin_aarch64
|
|
@ -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 \
|
||||
|
|
|
@ -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
samples/multi-thread/wasm-apps/main_thread_exception.c
Normal file
36
samples/multi-thread/wasm-apps/main_thread_exception.c
Normal 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;
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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 : ]
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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,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"
|
||||
},
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user