Merge branch main into dev/wasi_threads
This commit is contained in:
@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user