Refactor app heap and memory boundary check, and fix os_printf compilation error (#356)
Insert app heap before __heap_base, or before new page Fix os_printf compilation error in some platforms
This commit is contained in:
@ -325,15 +325,30 @@ typedef struct WASMModule {
|
||||
WASMDataSeg **data_segments;
|
||||
uint32 start_function;
|
||||
|
||||
/* __data_end global exported by llvm */
|
||||
uint32 llvm_aux_data_end;
|
||||
/* auxiliary stack bottom, or __heap_base global exported by llvm */
|
||||
uint32 llvm_aux_stack_bottom;
|
||||
/* auxiliary stack size */
|
||||
uint32 llvm_aux_stack_size;
|
||||
/* the index of a global exported by llvm, which is
|
||||
auxiliary stack top pointer */
|
||||
uint32 llvm_aux_stack_global_index;
|
||||
/* the index of auxiliary __data_end global,
|
||||
-1 means unexported */
|
||||
uint32 aux_data_end_global_index;
|
||||
/* auxiliary __data_end exported by wasm app */
|
||||
uint32 aux_data_end;
|
||||
|
||||
/* the index of auxiliary __heap_base global,
|
||||
-1 means unexported */
|
||||
uint32 aux_heap_base_global_index;
|
||||
/* auxiliary __heap_base exported by wasm app */
|
||||
uint32 aux_heap_base;
|
||||
|
||||
/* the index of auxiliary stack top global,
|
||||
-1 means unexported */
|
||||
uint32 aux_stack_top_global_index;
|
||||
/* auxiliary stack bottom resolved */
|
||||
uint32 aux_stack_bottom;
|
||||
/* auxiliary stack size resolved */
|
||||
uint32 aux_stack_size;
|
||||
|
||||
/* the index of malloc/free function,
|
||||
-1 means unexported */
|
||||
uint32 malloc_function;
|
||||
uint32 free_function;
|
||||
|
||||
/* Whether there is possible memory grow, e.g. memory.grow opcode */
|
||||
bool possible_memory_grow;
|
||||
|
||||
@ -227,9 +227,8 @@ LOAD_I16(void *addr)
|
||||
#endif /* WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 */
|
||||
|
||||
#define CHECK_MEMORY_OVERFLOW(bytes) do { \
|
||||
int64 offset1 = (int64)(uint32)offset + (int64)(int32)addr; \
|
||||
if (heap_base_offset <= offset1 \
|
||||
&& offset1 <= (int64)linear_mem_size - bytes) \
|
||||
uint64 offset1 = (uint64)offset + (uint64)addr; \
|
||||
if (offset1 + bytes <= (uint64)linear_mem_size) \
|
||||
/* If offset1 is in valid range, maddr must also be in valid range, \
|
||||
no need to check it again. */ \
|
||||
maddr = memory->memory_data + offset1; \
|
||||
@ -238,8 +237,8 @@ LOAD_I16(void *addr)
|
||||
} while (0)
|
||||
|
||||
#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) do { \
|
||||
uint64 offset1 = (int32)(start); \
|
||||
if (offset1 + bytes <= linear_mem_size) \
|
||||
uint64 offset1 = (uint32)(start); \
|
||||
if (offset1 + bytes <= (uint64)linear_mem_size) \
|
||||
/* App heap space is not valid space for bulk memory operation */ \
|
||||
maddr = memory->memory_data + offset1; \
|
||||
else \
|
||||
@ -1063,7 +1062,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
WASMInterpFrame *prev_frame)
|
||||
{
|
||||
WASMMemoryInstance *memory = module->default_memory;
|
||||
int32 heap_base_offset = memory ? memory->heap_base_offset : 0;
|
||||
uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0;
|
||||
uint8 *global_data = module->global_data;
|
||||
uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0;
|
||||
@ -1579,8 +1577,7 @@ label_pop_csp_n:
|
||||
HANDLE_OP (WASM_OP_I32_LOAD):
|
||||
HANDLE_OP (WASM_OP_F32_LOAD):
|
||||
{
|
||||
uint32 offset, flags;
|
||||
int32 addr;
|
||||
uint32 offset, flags, addr;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, flags);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
@ -1594,8 +1591,7 @@ label_pop_csp_n:
|
||||
HANDLE_OP (WASM_OP_I64_LOAD):
|
||||
HANDLE_OP (WASM_OP_F64_LOAD):
|
||||
{
|
||||
uint32 offset, flags;
|
||||
int32 addr;
|
||||
uint32 offset, flags, addr;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, flags);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
@ -1608,8 +1604,7 @@ label_pop_csp_n:
|
||||
|
||||
HANDLE_OP (WASM_OP_I32_LOAD8_S):
|
||||
{
|
||||
uint32 offset, flags;
|
||||
int32 addr;
|
||||
uint32 offset, flags, addr;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, flags);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
@ -1622,8 +1617,7 @@ label_pop_csp_n:
|
||||
|
||||
HANDLE_OP (WASM_OP_I32_LOAD8_U):
|
||||
{
|
||||
uint32 offset, flags;
|
||||
int32 addr;
|
||||
uint32 offset, flags, addr;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, flags);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
@ -1636,8 +1630,7 @@ label_pop_csp_n:
|
||||
|
||||
HANDLE_OP (WASM_OP_I32_LOAD16_S):
|
||||
{
|
||||
uint32 offset, flags;
|
||||
int32 addr;
|
||||
uint32 offset, flags, addr;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, flags);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
@ -1650,8 +1643,7 @@ label_pop_csp_n:
|
||||
|
||||
HANDLE_OP (WASM_OP_I32_LOAD16_U):
|
||||
{
|
||||
uint32 offset, flags;
|
||||
int32 addr;
|
||||
uint32 offset, flags, addr;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, flags);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
@ -1664,8 +1656,7 @@ label_pop_csp_n:
|
||||
|
||||
HANDLE_OP (WASM_OP_I64_LOAD8_S):
|
||||
{
|
||||
uint32 offset, flags;
|
||||
int32 addr;
|
||||
uint32 offset, flags, addr;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, flags);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
@ -1678,8 +1669,7 @@ label_pop_csp_n:
|
||||
|
||||
HANDLE_OP (WASM_OP_I64_LOAD8_U):
|
||||
{
|
||||
uint32 offset, flags;
|
||||
int32 addr;
|
||||
uint32 offset, flags, addr;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, flags);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
@ -1692,8 +1682,7 @@ label_pop_csp_n:
|
||||
|
||||
HANDLE_OP (WASM_OP_I64_LOAD16_S):
|
||||
{
|
||||
uint32 offset, flags;
|
||||
int32 addr;
|
||||
uint32 offset, flags, addr;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, flags);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
@ -1706,8 +1695,7 @@ label_pop_csp_n:
|
||||
|
||||
HANDLE_OP (WASM_OP_I64_LOAD16_U):
|
||||
{
|
||||
uint32 offset, flags;
|
||||
int32 addr;
|
||||
uint32 offset, flags, addr;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, flags);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
@ -1720,8 +1708,7 @@ label_pop_csp_n:
|
||||
|
||||
HANDLE_OP (WASM_OP_I64_LOAD32_S):
|
||||
{
|
||||
uint32 offset, flags;
|
||||
int32 addr;
|
||||
uint32 offset, flags, addr;
|
||||
|
||||
opcode = *(frame_ip - 1);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, flags);
|
||||
@ -1735,8 +1722,7 @@ label_pop_csp_n:
|
||||
|
||||
HANDLE_OP (WASM_OP_I64_LOAD32_U):
|
||||
{
|
||||
uint32 offset, flags;
|
||||
int32 addr;
|
||||
uint32 offset, flags, addr;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, flags);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
@ -1751,8 +1737,7 @@ label_pop_csp_n:
|
||||
HANDLE_OP (WASM_OP_I32_STORE):
|
||||
HANDLE_OP (WASM_OP_F32_STORE):
|
||||
{
|
||||
uint32 offset, flags;
|
||||
int32 addr;
|
||||
uint32 offset, flags, addr;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, flags);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
@ -1767,8 +1752,7 @@ label_pop_csp_n:
|
||||
HANDLE_OP (WASM_OP_I64_STORE):
|
||||
HANDLE_OP (WASM_OP_F64_STORE):
|
||||
{
|
||||
uint32 offset, flags;
|
||||
int32 addr;
|
||||
uint32 offset, flags, addr;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, flags);
|
||||
read_leb_uint32(frame_ip, frame_ip_end, offset);
|
||||
@ -1784,8 +1768,7 @@ label_pop_csp_n:
|
||||
HANDLE_OP (WASM_OP_I32_STORE8):
|
||||
HANDLE_OP (WASM_OP_I32_STORE16):
|
||||
{
|
||||
uint32 offset, flags;
|
||||
int32 addr;
|
||||
uint32 offset, flags, addr;
|
||||
uint32 sval;
|
||||
|
||||
opcode = *(frame_ip - 1);
|
||||
@ -1811,8 +1794,7 @@ label_pop_csp_n:
|
||||
HANDLE_OP (WASM_OP_I64_STORE16):
|
||||
HANDLE_OP (WASM_OP_I64_STORE32):
|
||||
{
|
||||
uint32 offset, flags;
|
||||
int32 addr;
|
||||
uint32 offset, flags, addr;
|
||||
uint64 sval;
|
||||
|
||||
opcode = *(frame_ip - 1);
|
||||
@ -2665,9 +2647,12 @@ label_pop_csp_n:
|
||||
|
||||
HANDLE_OP (WASM_OP_MISC_PREFIX):
|
||||
{
|
||||
opcode = *frame_ip++;
|
||||
switch (opcode)
|
||||
{
|
||||
uint32 opcode1;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, opcode1);
|
||||
opcode = (uint8)opcode1;
|
||||
|
||||
switch (opcode) {
|
||||
case WASM_OP_I32_TRUNC_SAT_S_F32:
|
||||
DEF_OP_TRUNC_SAT_F32(-2147483904.0f, 2147483648.0f,
|
||||
true, true);
|
||||
@ -2787,8 +2772,7 @@ label_pop_csp_n:
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
HANDLE_OP (WASM_OP_ATOMIC_PREFIX):
|
||||
{
|
||||
uint32 offset, align;
|
||||
int32 addr;
|
||||
uint32 offset, align, addr;
|
||||
|
||||
opcode = *frame_ip++;
|
||||
|
||||
|
||||
@ -229,9 +229,8 @@ LOAD_I16(void *addr)
|
||||
#endif /* WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 */
|
||||
|
||||
#define CHECK_MEMORY_OVERFLOW(bytes) do { \
|
||||
int64 offset1 = (int64)(uint32)offset + (int64)(int32)addr; \
|
||||
if (heap_base_offset <= offset1 \
|
||||
&& offset1 <= (int64)linear_mem_size - bytes) \
|
||||
uint64 offset1 = (uint64)offset + (uint64)addr; \
|
||||
if (offset1 + bytes <= (uint64)linear_mem_size) \
|
||||
/* If offset1 is in valid range, maddr must also be in valid range,\
|
||||
no need to check it again. */ \
|
||||
maddr = memory->memory_data + offset1; \
|
||||
@ -239,13 +238,13 @@ LOAD_I16(void *addr)
|
||||
goto out_of_bounds; \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) do { \
|
||||
uint64 offset1 = (int32)(start); \
|
||||
if (offset1 + bytes <= linear_mem_size) \
|
||||
/* App heap space is not valid space for bulk memory operation */ \
|
||||
maddr = memory->memory_data + offset1; \
|
||||
else \
|
||||
goto out_of_bounds; \
|
||||
#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) do { \
|
||||
uint64 offset1 = (uint32)(start); \
|
||||
if (offset1 + bytes <= linear_mem_size) \
|
||||
/* App heap space is not valid space for bulk memory operation */ \
|
||||
maddr = memory->memory_data + offset1; \
|
||||
else \
|
||||
goto out_of_bounds; \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_ATOMIC_MEMORY_ACCESS(align) do { \
|
||||
@ -1163,7 +1162,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
WASMInterpFrame *prev_frame)
|
||||
{
|
||||
WASMMemoryInstance *memory = module->default_memory;
|
||||
int32 heap_base_offset = memory ? memory->heap_base_offset : 0;
|
||||
uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0;
|
||||
uint8 *global_data = module->global_data;
|
||||
uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0;
|
||||
@ -2768,8 +2766,7 @@ recover_br_info:
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
HANDLE_OP (WASM_OP_ATOMIC_PREFIX):
|
||||
{
|
||||
uint32 offset;
|
||||
int32 addr;
|
||||
uint32 offset, addr;
|
||||
|
||||
GET_OPCODE();
|
||||
|
||||
|
||||
@ -52,14 +52,14 @@ check_buf1(const uint8 *buf, const uint8 *buf_end, uint32 length,
|
||||
#define CHECK_BUF(buf, buf_end, length) do { \
|
||||
if (!check_buf(buf, buf_end, length, \
|
||||
error_buf, error_buf_size)) { \
|
||||
return false; \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_BUF1(buf, buf_end, length) do { \
|
||||
if (!check_buf1(buf, buf_end, length, \
|
||||
error_buf, error_buf_size)) { \
|
||||
return false; \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
@ -90,6 +90,8 @@ skip_leb(const uint8 **p_buf, const uint8 *buf_end, uint32 maxbits,
|
||||
|
||||
*p_buf += offset;
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
#define skip_leb_int64(p, p_end) do { \
|
||||
@ -184,6 +186,7 @@ read_leb(uint8 **p_buf, const uint8 *buf_end,
|
||||
fail_integer_too_large:
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"WASM module load failed: integer too large");
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -195,7 +198,7 @@ fail_integer_too_large:
|
||||
uint64 res64; \
|
||||
if (!read_leb((uint8**)&p, p_end, 64, true, &res64,\
|
||||
error_buf, error_buf_size)) \
|
||||
return false; \
|
||||
goto fail; \
|
||||
res = (int64)res64; \
|
||||
} while (0)
|
||||
|
||||
@ -203,7 +206,7 @@ fail_integer_too_large:
|
||||
uint64 res64; \
|
||||
if (!read_leb((uint8**)&p, p_end, 32, false, &res64,\
|
||||
error_buf, error_buf_size)) \
|
||||
return false; \
|
||||
goto fail; \
|
||||
res = (uint32)res64; \
|
||||
} while (0)
|
||||
|
||||
@ -211,7 +214,7 @@ fail_integer_too_large:
|
||||
uint64 res64; \
|
||||
if (!read_leb((uint8**)&p, p_end, 32, true, &res64,\
|
||||
error_buf, error_buf_size)) \
|
||||
return false; \
|
||||
goto fail; \
|
||||
res = (int32)res64; \
|
||||
} while (0)
|
||||
|
||||
@ -335,19 +338,19 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end,
|
||||
/* i32.const */
|
||||
case INIT_EXPR_TYPE_I32_CONST:
|
||||
if (type != VALUE_TYPE_I32)
|
||||
goto fail;
|
||||
goto fail_type_mismatch;
|
||||
read_leb_int32(p, p_end, init_expr->u.i32);
|
||||
break;
|
||||
/* i64.const */
|
||||
case INIT_EXPR_TYPE_I64_CONST:
|
||||
if (type != VALUE_TYPE_I64)
|
||||
goto fail;
|
||||
goto fail_type_mismatch;
|
||||
read_leb_int64(p, p_end, init_expr->u.i64);
|
||||
break;
|
||||
/* f32.const */
|
||||
case INIT_EXPR_TYPE_F32_CONST:
|
||||
if (type != VALUE_TYPE_F32)
|
||||
goto fail;
|
||||
goto fail_type_mismatch;
|
||||
CHECK_BUF(p, p_end, 4);
|
||||
p_float = (uint8*)&init_expr->u.f32;
|
||||
for (i = 0; i < sizeof(float32); i++)
|
||||
@ -356,7 +359,7 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end,
|
||||
/* f64.const */
|
||||
case INIT_EXPR_TYPE_F64_CONST:
|
||||
if (type != VALUE_TYPE_F64)
|
||||
goto fail;
|
||||
goto fail_type_mismatch;
|
||||
CHECK_BUF(p, p_end, 8);
|
||||
p_float = (uint8*)&init_expr->u.f64;
|
||||
for (i = 0; i < sizeof(float64); i++)
|
||||
@ -367,19 +370,20 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end,
|
||||
read_leb_uint32(p, p_end, init_expr->u.global_index);
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
goto fail_type_mismatch;
|
||||
}
|
||||
CHECK_BUF(p, p_end, 1);
|
||||
end_byte = read_uint8(p);
|
||||
if (end_byte != 0x0b)
|
||||
goto fail;
|
||||
goto fail_type_mismatch;
|
||||
*p_buf = p;
|
||||
|
||||
return true;
|
||||
fail:
|
||||
fail_type_mismatch:
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"WASM module load failed: type mismatch or "
|
||||
"constant expression required.");
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -472,6 +476,8 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
||||
|
||||
LOG_VERBOSE("Load type section success.\n");
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
@ -804,6 +810,8 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module,
|
||||
function->import_func_linked = is_built_in_module ? NULL : linked_func;
|
||||
#endif
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -905,6 +913,8 @@ load_table_import(WASMModule *sub_module, const char *sub_module_name,
|
||||
table->flags = declare_max_size_flag;
|
||||
table->max_size = declare_max_size;
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned
|
||||
@ -1034,6 +1044,8 @@ load_memory_import(WASMModule *sub_module, const char *sub_module_name,
|
||||
|
||||
*p_buf = p;
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -1107,13 +1119,15 @@ load_global_import(const WASMModule *parent_module,
|
||||
global->type = declare_type;
|
||||
global->is_mutable = is_mutable;
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
const uint8 *p = *p_buf, *p_end = buf_end;
|
||||
const uint8 *p = *p_buf, *p_end = buf_end, *p_org;
|
||||
|
||||
CHECK_BUF(p, p_end, 1);
|
||||
/* 0x70 */
|
||||
@ -1123,32 +1137,40 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table,
|
||||
return false;
|
||||
}
|
||||
|
||||
p_org = p;
|
||||
read_leb_uint32(p, p_end, table->flags);
|
||||
if (p - p_org > 1) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"integer representation too long");
|
||||
return false;
|
||||
}
|
||||
if (table->flags > 1) {
|
||||
set_error_buf(error_buf, error_buf_size, "integer too large");
|
||||
return false;
|
||||
}
|
||||
|
||||
read_leb_uint32(p, p_end, table->init_size);
|
||||
if (table->flags & 1) {
|
||||
if (table->flags == 0) {
|
||||
table->max_size = 0x10000;
|
||||
}
|
||||
else if (table->flags == 1) {
|
||||
read_leb_uint32(p, p_end, table->max_size);
|
||||
if (!check_table_max_size(table->init_size, table->max_size,
|
||||
error_buf, error_buf_size))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
table->max_size = 0x10000;
|
||||
|
||||
if ((table->flags & 1) && table->init_size > table->max_size) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"size minimum must not be greater than maximum");
|
||||
return false;
|
||||
}
|
||||
|
||||
*p_buf = p;
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
const uint8 *p = *p_buf, *p_end = buf_end;
|
||||
const uint8 *p = *p_buf, *p_end = buf_end, *p_org;
|
||||
uint32 pool_size = wasm_runtime_memory_pool_size();
|
||||
#if WASM_ENABLE_APP_FRAMEWORK != 0
|
||||
uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT
|
||||
@ -1157,7 +1179,25 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory,
|
||||
uint32 max_page_count = pool_size / DEFAULT_NUM_BYTES_PER_PAGE;
|
||||
#endif
|
||||
|
||||
p_org = p;
|
||||
read_leb_uint32(p, p_end, memory->flags);
|
||||
if (p - p_org > 1) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"integer representation too long");
|
||||
return false;
|
||||
}
|
||||
#if WASM_ENABLE_SHARED_MEMORY == 0
|
||||
if (memory->flags > 1) {
|
||||
set_error_buf(error_buf, error_buf_size, "integer too large");
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (memory->flags > 3 || memory->flags == 2) {
|
||||
set_error_buf(error_buf, error_buf_size, "integer too large");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
read_leb_uint32(p, p_end, memory->init_page_count);
|
||||
if (!check_memory_init_size(memory->init_page_count,
|
||||
error_buf, error_buf_size))
|
||||
@ -1172,14 +1212,17 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory,
|
||||
if (memory->max_page_count > max_page_count)
|
||||
memory->max_page_count = max_page_count;
|
||||
}
|
||||
else
|
||||
else {
|
||||
/* Limit the maximum memory size to max_page_count */
|
||||
memory->max_page_count = max_page_count;
|
||||
}
|
||||
|
||||
memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE;
|
||||
|
||||
*p_buf = p;
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
@ -1434,7 +1477,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
||||
|
||||
default:
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"Load import section failed: invalid import type.");
|
||||
"Load import section failed: invalid import kind");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1454,7 +1497,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
||||
|
||||
p = p_old;
|
||||
|
||||
// TODO: move it out of the loop
|
||||
/* TODO: move it out of the loop */
|
||||
/* insert "env", "wasi_unstable" and "wasi_snapshot_preview1" to const str list */
|
||||
if (!const_str_list_insert((uint8*)"env", 3, module, error_buf, error_buf_size)
|
||||
|| !const_str_list_insert((uint8*)"wasi_unstable", 13, module,
|
||||
@ -1566,7 +1609,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
||||
default:
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"Load import section failed: "
|
||||
"invalid import type.");
|
||||
"invalid import kind");
|
||||
return false;
|
||||
}
|
||||
import->kind = kind;
|
||||
@ -1598,6 +1641,8 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
||||
(void)u32;
|
||||
(void)type_index;
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -1779,6 +1824,8 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
|
||||
|
||||
LOG_VERBOSE("Load function section success.\n");
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -1820,6 +1867,8 @@ load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
||||
|
||||
LOG_VERBOSE("Load table section success.\n");
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -1861,6 +1910,8 @@ load_memory_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
||||
|
||||
LOG_VERBOSE("Load memory section success.\n");
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -1926,6 +1977,8 @@ load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
||||
|
||||
LOG_VERBOSE("Load global section success.\n");
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -2029,6 +2082,8 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
||||
|
||||
LOG_VERBOSE("Load export section success.\n");
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -2102,6 +2157,8 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m
|
||||
|
||||
LOG_VERBOSE("Load table segment section success.\n");
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -2217,6 +2274,8 @@ check_mem_index:
|
||||
|
||||
LOG_VERBOSE("Load data segment section success.\n");
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
@ -2238,6 +2297,8 @@ load_datacount_section(const uint8 *buf, const uint8 *buf_end, WASMModule *modul
|
||||
|
||||
LOG_VERBOSE("Load datacount section success.\n");
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2268,6 +2329,8 @@ load_code_section(const uint8 *buf, const uint8 *buf_end,
|
||||
|
||||
LOG_VERBOSE("Load code segment section success.\n");
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -2311,6 +2374,8 @@ load_start_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
||||
|
||||
LOG_VERBOSE("Load start section success.\n");
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -2344,6 +2409,8 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
||||
|
||||
LOG_VERBOSE("Load custom section success.\n");
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -2367,12 +2434,14 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
||||
WASMSection *section = sections;
|
||||
const uint8 *buf, *buf_end, *buf_code = NULL, *buf_code_end = NULL,
|
||||
*buf_func = NULL, *buf_func_end = NULL;
|
||||
WASMGlobal *llvm_data_end_global = NULL, *llvm_heap_base_global = NULL;
|
||||
WASMGlobal *llvm_stack_top_global = NULL, *global;
|
||||
uint32 llvm_data_end = UINT32_MAX, llvm_heap_base = UINT32_MAX;
|
||||
uint32 llvm_stack_top = UINT32_MAX, global_index, i;
|
||||
uint32 stack_top_global_index = UINT32_MAX;
|
||||
WASMGlobal *aux_data_end_global = NULL, *aux_heap_base_global = NULL;
|
||||
WASMGlobal *aux_stack_top_global = NULL, *global;
|
||||
uint32 aux_data_end = (uint32)-1, aux_heap_base = (uint32)-1;
|
||||
uint32 aux_stack_top = (uint32)-1, global_index, func_index, i;
|
||||
uint32 aux_data_end_global_index = (uint32)-1;
|
||||
uint32 aux_heap_base_global_index = (uint32)-1;
|
||||
BlockAddr *block_addr_cache;
|
||||
WASMType *func_type;
|
||||
uint64 total_size;
|
||||
|
||||
/* Find code and function sections if have */
|
||||
@ -2481,7 +2550,11 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
||||
}
|
||||
wasm_runtime_free(block_addr_cache);
|
||||
|
||||
/* Resolve llvm auxiliary data/stack/heap info and reset memory info */
|
||||
module->aux_data_end_global_index = (uint32)-1;
|
||||
module->aux_heap_base_global_index = (uint32)-1;
|
||||
module->aux_stack_top_global_index = (uint32)-1;
|
||||
|
||||
/* Resolve auxiliary data/stack/heap info and reset memory info */
|
||||
export = module->exports;
|
||||
for (i = 0; i < module->export_count; i++, export++) {
|
||||
if (export->kind == EXPORT_KIND_GLOBAL) {
|
||||
@ -2492,10 +2565,11 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
||||
&& !global->is_mutable
|
||||
&& global->init_expr.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST) {
|
||||
llvm_heap_base_global = global;
|
||||
llvm_heap_base = global->init_expr.u.i32;
|
||||
LOG_VERBOSE("found llvm __heap_base global, value: %d\n",
|
||||
llvm_heap_base);
|
||||
aux_heap_base_global = global;
|
||||
aux_heap_base = global->init_expr.u.i32;
|
||||
aux_heap_base_global_index = export->index;
|
||||
LOG_VERBOSE("Found aux __heap_base global, value: %d",
|
||||
aux_heap_base);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(export->name, "__data_end")) {
|
||||
@ -2505,12 +2579,13 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
||||
&& !global->is_mutable
|
||||
&& global->init_expr.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST) {
|
||||
llvm_data_end_global = global;
|
||||
llvm_data_end = global->init_expr.u.i32;
|
||||
LOG_VERBOSE("found llvm __data_end global, value: %d\n",
|
||||
llvm_data_end);
|
||||
aux_data_end_global = global;
|
||||
aux_data_end = global->init_expr.u.i32;
|
||||
aux_data_end_global_index = export->index;
|
||||
LOG_VERBOSE("Found aux __data_end global, value: %d",
|
||||
aux_data_end);
|
||||
|
||||
llvm_data_end = align_uint(llvm_data_end, 16);
|
||||
aux_data_end = align_uint(aux_data_end, 16);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2530,64 +2605,97 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
||||
[3] heap_base <-- 3
|
||||
[4] dso_handle
|
||||
*/
|
||||
if (llvm_data_end_global && llvm_heap_base_global) {
|
||||
if (aux_data_end_global && aux_heap_base_global
|
||||
&& aux_data_end <= aux_heap_base) {
|
||||
module->aux_data_end_global_index = aux_data_end_global_index;
|
||||
module->aux_data_end = aux_data_end;
|
||||
module->aux_heap_base_global_index = aux_heap_base_global_index;
|
||||
module->aux_heap_base = aux_heap_base;
|
||||
|
||||
/* Resolve aux stack top global */
|
||||
for (global_index = 0; global_index < module->global_count; global_index++) {
|
||||
for (global_index = 0; global_index < module->global_count;
|
||||
global_index++) {
|
||||
global = module->globals + global_index;
|
||||
if (global != llvm_data_end_global
|
||||
&& global != llvm_heap_base_global
|
||||
if (global->is_mutable /* heap_base and data_end is
|
||||
not mutable */
|
||||
&& global->type == VALUE_TYPE_I32
|
||||
&& global->is_mutable
|
||||
&& global->init_expr.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST
|
||||
&& (global->init_expr.u.i32 <=
|
||||
llvm_heap_base_global->init_expr.u.i32
|
||||
&& llvm_data_end_global->init_expr.u.i32 <=
|
||||
llvm_heap_base_global->init_expr.u.i32)) {
|
||||
llvm_stack_top_global = global;
|
||||
llvm_stack_top = global->init_expr.u.i32;
|
||||
stack_top_global_index = global_index;
|
||||
LOG_VERBOSE("found llvm stack top global, "
|
||||
"value: %d, global index: %d\n",
|
||||
llvm_stack_top, global_index);
|
||||
&& (uint32)global->init_expr.u.i32 <= aux_heap_base) {
|
||||
aux_stack_top_global = global;
|
||||
aux_stack_top = (uint32)global->init_expr.u.i32;
|
||||
module->aux_stack_top_global_index =
|
||||
module->import_global_count + global_index;
|
||||
module->aux_stack_bottom = aux_stack_top;
|
||||
module->aux_stack_size = aux_stack_top > aux_data_end
|
||||
? aux_stack_top - aux_data_end
|
||||
: aux_stack_top;
|
||||
LOG_VERBOSE("Found aux stack top global, value: %d, "
|
||||
"global index: %d, stack size: %d",
|
||||
aux_stack_top, global_index,
|
||||
module->aux_stack_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
module->llvm_aux_data_end = llvm_data_end;
|
||||
module->llvm_aux_stack_bottom = llvm_stack_top;
|
||||
module->llvm_aux_stack_size = llvm_stack_top > llvm_data_end
|
||||
? llvm_stack_top - llvm_data_end
|
||||
: llvm_stack_top;
|
||||
module->llvm_aux_stack_global_index = stack_top_global_index;
|
||||
LOG_VERBOSE("aux stack bottom: %d, size: %d\n",
|
||||
module->llvm_aux_stack_bottom,
|
||||
module->llvm_aux_stack_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module->malloc_function = (uint32)-1;
|
||||
module->free_function = (uint32)-1;
|
||||
|
||||
/* Resolve auxiliary data/stack/heap info and reset memory info */
|
||||
export = module->exports;
|
||||
for (i = 0; i < module->export_count; i++, export++) {
|
||||
if (export->kind == EXPORT_KIND_FUNC) {
|
||||
if (!strcmp(export->name, "malloc")
|
||||
&& export->index >= module->import_function_count) {
|
||||
func_index = export->index - module->import_function_count;
|
||||
func_type = module->functions[func_index]->func_type;
|
||||
if (func_type->param_count == 1
|
||||
&& func_type->result_count == 1
|
||||
&& func_type->types[0] == VALUE_TYPE_I32
|
||||
&& func_type->types[1] == VALUE_TYPE_I32) {
|
||||
module->malloc_function = export->index;
|
||||
LOG_VERBOSE("Found malloc function, index: %u",
|
||||
export->index);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(export->name, "free")
|
||||
&& export->index >= module->import_function_count) {
|
||||
func_index = export->index - module->import_function_count;
|
||||
func_type = module->functions[func_index]->func_type;
|
||||
if (func_type->param_count == 1
|
||||
&& func_type->result_count == 0
|
||||
&& func_type->types[0] == VALUE_TYPE_I32) {
|
||||
module->free_function = export->index;
|
||||
LOG_VERBOSE("Found free function, index: %u",
|
||||
export->index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!module->possible_memory_grow) {
|
||||
if (llvm_data_end_global
|
||||
&& llvm_heap_base_global
|
||||
&& llvm_stack_top_global
|
||||
&& llvm_stack_top <= llvm_heap_base) {
|
||||
WASMMemoryImport *memory_import;
|
||||
WASMMemory *memory;
|
||||
WASMMemoryImport *memory_import;
|
||||
WASMMemory *memory;
|
||||
|
||||
if (aux_data_end_global
|
||||
&& aux_heap_base_global
|
||||
&& aux_stack_top_global) {
|
||||
uint64 init_memory_size;
|
||||
uint32 shrunk_memory_size = llvm_heap_base > llvm_data_end
|
||||
? llvm_heap_base : llvm_data_end;
|
||||
uint32 shrunk_memory_size = align_uint(aux_heap_base, 8);
|
||||
|
||||
if (module->import_memory_count) {
|
||||
memory_import = &module->import_memories[0].u.memory;
|
||||
init_memory_size = (uint64)memory_import->num_bytes_per_page *
|
||||
memory_import->init_page_count;
|
||||
if (llvm_heap_base <= init_memory_size
|
||||
&& llvm_data_end <= init_memory_size) {
|
||||
if (shrunk_memory_size <= init_memory_size) {
|
||||
/* Reset memory info to decrease memory usage */
|
||||
memory_import->num_bytes_per_page = shrunk_memory_size;
|
||||
memory_import->init_page_count = 1;
|
||||
LOG_VERBOSE("reset import memory size to %d\n",
|
||||
LOG_VERBOSE("Shrink import memory size to %d",
|
||||
shrunk_memory_size);
|
||||
}
|
||||
}
|
||||
@ -2595,15 +2703,31 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
||||
memory = &module->memories[0];
|
||||
init_memory_size = (uint64)memory->num_bytes_per_page *
|
||||
memory->init_page_count;
|
||||
if (llvm_heap_base <= init_memory_size
|
||||
&& llvm_data_end <= init_memory_size) {
|
||||
if (shrunk_memory_size <= init_memory_size) {
|
||||
/* Reset memory info to decrease memory usage */
|
||||
memory->num_bytes_per_page = shrunk_memory_size;
|
||||
memory->init_page_count = 1;
|
||||
LOG_VERBOSE("reset memory size to %d\n", shrunk_memory_size);
|
||||
LOG_VERBOSE("Shrink memory size to %d", shrunk_memory_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE == 0
|
||||
if (module->import_memory_count) {
|
||||
memory_import = &module->import_memories[0].u.memory;
|
||||
/* Memory init page count cannot be larger than 65536, we don't
|
||||
check integer overflow again. */
|
||||
memory_import->num_bytes_per_page *= memory_import->init_page_count;
|
||||
memory_import->init_page_count = memory_import->max_page_count = 1;
|
||||
}
|
||||
if (module->memory_count) {
|
||||
/* Memory init page count cannot be larger than 65536, we don't
|
||||
check integer overflow again. */
|
||||
memory = &module->memories[0];
|
||||
memory->num_bytes_per_page *= memory->init_page_count;
|
||||
memory->init_page_count = memory->max_page_count = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -2759,6 +2883,8 @@ create_sections(const uint8 *buf, uint32 size,
|
||||
}
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2819,6 +2945,8 @@ load(const uint8 *buf, uint32 size, WASMModule *module,
|
||||
|
||||
destroy_sections(section_list);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
WASMModule*
|
||||
@ -2834,7 +2962,7 @@ wasm_loader_load(const uint8 *buf, uint32 size, char *error_buf, uint32 error_bu
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LOG_VERBOSE("Load module success");
|
||||
LOG_VERBOSE("Load module success.\n");
|
||||
return module;
|
||||
|
||||
fail:
|
||||
@ -3275,8 +3403,11 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
|
||||
break;
|
||||
case WASM_OP_MISC_PREFIX:
|
||||
{
|
||||
opcode = read_uint8(p);
|
||||
switch (opcode) {
|
||||
uint32 opcode1;
|
||||
|
||||
read_leb_uint32(p, p_end, opcode1);
|
||||
|
||||
switch (opcode1) {
|
||||
case WASM_OP_I32_TRUNC_SAT_S_F32:
|
||||
case WASM_OP_I32_TRUNC_SAT_U_F32:
|
||||
case WASM_OP_I32_TRUNC_SAT_S_F64:
|
||||
@ -3340,6 +3471,8 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
|
||||
|
||||
(void)u8;
|
||||
return false;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
#define REF_I32 VALUE_TYPE_I32
|
||||
@ -6032,8 +6165,8 @@ handle_op_block_and_loop:
|
||||
|| global_type == VALUE_TYPE_F64) {
|
||||
*p_org = WASM_OP_SET_GLOBAL_64;
|
||||
}
|
||||
else if (module->llvm_aux_stack_size > 0
|
||||
&& global_idx == module->llvm_aux_stack_global_index) {
|
||||
else if (module->aux_stack_size > 0
|
||||
&& global_idx == module->aux_stack_top_global_index) {
|
||||
*p_org = WASM_OP_SET_GLOBAL_AUX_STACK;
|
||||
}
|
||||
#endif
|
||||
@ -6043,8 +6176,8 @@ handle_op_block_and_loop:
|
||||
skip_label();
|
||||
emit_label(WASM_OP_SET_GLOBAL_64);
|
||||
}
|
||||
else if (module->llvm_aux_stack_size > 0
|
||||
&& global_idx == module->llvm_aux_stack_global_index) {
|
||||
else if (module->aux_stack_size > 0
|
||||
&& global_idx == module->aux_stack_top_global_index) {
|
||||
skip_label();
|
||||
emit_label(WASM_OP_SET_GLOBAL_AUX_STACK);
|
||||
}
|
||||
@ -6462,11 +6595,13 @@ handle_op_block_and_loop:
|
||||
|
||||
case WASM_OP_MISC_PREFIX:
|
||||
{
|
||||
opcode = read_uint8(p);
|
||||
uint32 opcode1;
|
||||
|
||||
read_leb_uint32(p, p_end, opcode1);
|
||||
#if WASM_ENABLE_FAST_INTERP != 0
|
||||
emit_byte(loader_ctx, opcode);
|
||||
emit_byte(loader_ctx, ((uint8)opcode1));
|
||||
#endif
|
||||
switch (opcode)
|
||||
switch (opcode1)
|
||||
{
|
||||
case WASM_OP_I32_TRUNC_SAT_S_F32:
|
||||
case WASM_OP_I32_TRUNC_SAT_U_F32:
|
||||
@ -6574,7 +6709,7 @@ fail_data_cnt_sec_require:
|
||||
if (error_buf != NULL)
|
||||
snprintf(error_buf, error_buf_size,
|
||||
"WASM module load failed: "
|
||||
"invalid opcode 0xfc %02x.", opcode);
|
||||
"invalid opcode 0xfc %02x.", opcode1);
|
||||
goto fail;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -555,24 +555,27 @@ static bool
|
||||
load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
const uint8 *p = *p_buf, *p_end = buf_end;
|
||||
const uint8 *p = *p_buf, *p_end = buf_end, *p_org;
|
||||
|
||||
CHECK_BUF(p, p_end, 1);
|
||||
/* 0x70 */
|
||||
table->elem_type = read_uint8(p);
|
||||
bh_assert(TABLE_ELEM_TYPE_ANY_FUNC == table->elem_type);
|
||||
|
||||
p_org = p;
|
||||
read_leb_uint32(p, p_end, table->flags);
|
||||
bh_assert(p - p_org <= 1);
|
||||
bh_assert(table->flags <= 1);
|
||||
(void)p_org;
|
||||
|
||||
read_leb_uint32(p, p_end, table->init_size);
|
||||
if (table->flags & 1) {
|
||||
if (table->flags == 0) {
|
||||
table->max_size = 0x10000;
|
||||
}
|
||||
else if (table->flags == 1) {
|
||||
read_leb_uint32(p, p_end, table->max_size);
|
||||
bh_assert(table->init_size <= table->max_size);
|
||||
}
|
||||
else
|
||||
table->max_size = 0x10000;
|
||||
|
||||
bh_assert(!((table->flags & 1)
|
||||
&& table->init_size > table->max_size));
|
||||
|
||||
*p_buf = p;
|
||||
return true;
|
||||
@ -582,7 +585,7 @@ static bool
|
||||
load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
const uint8 *p = *p_buf, *p_end = buf_end;
|
||||
const uint8 *p = *p_buf, *p_end = buf_end, *p_org;
|
||||
uint32 pool_size = wasm_runtime_memory_pool_size();
|
||||
#if WASM_ENABLE_APP_FRAMEWORK != 0
|
||||
uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT
|
||||
@ -591,7 +594,15 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory,
|
||||
uint32 max_page_count = pool_size / DEFAULT_NUM_BYTES_PER_PAGE;
|
||||
#endif
|
||||
|
||||
p_org = p;
|
||||
read_leb_uint32(p, p_end, memory->flags);
|
||||
bh_assert(p - p_org <= 1);
|
||||
#if WASM_ENABLE_SHARED_MEMORY == 0
|
||||
bh_assert(memory->flags <= 1);
|
||||
#else
|
||||
bh_assert(memory->flags <= 3 && memory->flags != 2);
|
||||
#endif
|
||||
|
||||
read_leb_uint32(p, p_end, memory->init_page_count);
|
||||
bh_assert(memory->init_page_count <= 65536);
|
||||
|
||||
@ -602,9 +613,10 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory,
|
||||
if (memory->max_page_count > max_page_count)
|
||||
memory->max_page_count = max_page_count;
|
||||
}
|
||||
else
|
||||
else {
|
||||
/* Limit the maximum memory size to max_page_count */
|
||||
memory->max_page_count = max_page_count;
|
||||
}
|
||||
|
||||
memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE;
|
||||
|
||||
@ -707,7 +719,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
||||
|
||||
p = p_old;
|
||||
|
||||
// TODO: move it out of the loop
|
||||
/* TODO: move it out of the loop */
|
||||
/* insert "env", "wasi_unstable" and "wasi_snapshot_preview1" to const str list */
|
||||
if (!const_str_list_insert((uint8*)"env", 3, module, error_buf, error_buf_size)
|
||||
|| !const_str_list_insert((uint8*)"wasi_unstable", 13, module,
|
||||
@ -1436,12 +1448,14 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
||||
WASMSection *section = sections;
|
||||
const uint8 *buf, *buf_end, *buf_code = NULL, *buf_code_end = NULL,
|
||||
*buf_func = NULL, *buf_func_end = NULL;
|
||||
WASMGlobal *llvm_data_end_global = NULL, *llvm_heap_base_global = NULL;
|
||||
WASMGlobal *llvm_stack_top_global = NULL, *global;
|
||||
uint32 llvm_data_end = UINT32_MAX, llvm_heap_base = UINT32_MAX;
|
||||
uint32 llvm_stack_top = UINT32_MAX, global_index, i;
|
||||
uint32 stack_top_global_index = UINT32_MAX;
|
||||
WASMGlobal *aux_data_end_global = NULL, *aux_heap_base_global = NULL;
|
||||
WASMGlobal *aux_stack_top_global = NULL, *global;
|
||||
uint32 aux_data_end = (uint32)-1, aux_heap_base = (uint32)-1;
|
||||
uint32 aux_stack_top = (uint32)-1, global_index, func_index, i;
|
||||
uint32 aux_data_end_global_index = (uint32)-1;
|
||||
uint32 aux_heap_base_global_index = (uint32)-1;
|
||||
BlockAddr *block_addr_cache;
|
||||
WASMType *func_type;
|
||||
uint64 total_size;
|
||||
|
||||
/* Find code and function sections if have */
|
||||
@ -1550,7 +1564,11 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
||||
}
|
||||
wasm_runtime_free(block_addr_cache);
|
||||
|
||||
/* Resolve llvm auxiliary data/stack/heap info and reset memory info */
|
||||
module->aux_data_end_global_index = (uint32)-1;
|
||||
module->aux_heap_base_global_index = (uint32)-1;
|
||||
module->aux_stack_top_global_index = (uint32)-1;
|
||||
|
||||
/* Resolve auxiliary data/stack/heap info and reset memory info */
|
||||
export = module->exports;
|
||||
for (i = 0; i < module->export_count; i++, export++) {
|
||||
if (export->kind == EXPORT_KIND_GLOBAL) {
|
||||
@ -1561,10 +1579,11 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
||||
&& !global->is_mutable
|
||||
&& global->init_expr.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST) {
|
||||
llvm_heap_base_global = global;
|
||||
llvm_heap_base = global->init_expr.u.i32;
|
||||
LOG_VERBOSE("found llvm __heap_base global, value: %d\n",
|
||||
llvm_heap_base);
|
||||
aux_heap_base_global = global;
|
||||
aux_heap_base = global->init_expr.u.i32;
|
||||
aux_heap_base_global_index = export->index;
|
||||
LOG_VERBOSE("Found aux __heap_base global, value: %d",
|
||||
aux_heap_base);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(export->name, "__data_end")) {
|
||||
@ -1574,89 +1593,155 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
||||
&& !global->is_mutable
|
||||
&& global->init_expr.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST) {
|
||||
llvm_data_end_global = global;
|
||||
llvm_data_end = global->init_expr.u.i32;
|
||||
LOG_VERBOSE("found llvm __data_end global, value: %d\n",
|
||||
llvm_data_end);
|
||||
aux_data_end_global = global;
|
||||
aux_data_end = global->init_expr.u.i32;
|
||||
aux_data_end_global_index = export->index;
|
||||
LOG_VERBOSE("Found aux __data_end global, value: %d",
|
||||
aux_data_end);
|
||||
|
||||
llvm_data_end = align_uint(llvm_data_end, 16);
|
||||
aux_data_end = align_uint(aux_data_end, 16);
|
||||
}
|
||||
}
|
||||
|
||||
if (llvm_data_end_global && llvm_heap_base_global) {
|
||||
/* For module compiled with -pthread option, the global is:
|
||||
[0] stack_top <-- 0
|
||||
[1] tls_pointer
|
||||
[2] tls_size
|
||||
[3] data_end <-- 3
|
||||
[4] global_base
|
||||
[5] heap_base <-- 5
|
||||
[6] dso_handle
|
||||
|
||||
For module compiled without -pthread option:
|
||||
[0] stack_top <-- 0
|
||||
[1] data_end <-- 1
|
||||
[2] global_base
|
||||
[3] heap_base <-- 3
|
||||
[4] dso_handle
|
||||
*/
|
||||
if (aux_data_end_global && aux_heap_base_global
|
||||
&& aux_data_end <= aux_heap_base) {
|
||||
module->aux_data_end_global_index = aux_data_end_global_index;
|
||||
module->aux_data_end = aux_data_end;
|
||||
module->aux_heap_base_global_index = aux_heap_base_global_index;
|
||||
module->aux_heap_base = aux_heap_base;
|
||||
|
||||
/* Resolve aux stack top global */
|
||||
for (global_index = 0; global_index < module->global_count; global_index++) {
|
||||
for (global_index = 0; global_index < module->global_count;
|
||||
global_index++) {
|
||||
global = module->globals + global_index;
|
||||
if (global != llvm_data_end_global
|
||||
&& global != llvm_heap_base_global
|
||||
if (global->is_mutable /* heap_base and data_end is
|
||||
not mutable */
|
||||
&& global->type == VALUE_TYPE_I32
|
||||
&& global->is_mutable
|
||||
&& global->init_expr.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST
|
||||
&& (global->init_expr.u.i32 <=
|
||||
llvm_heap_base_global->init_expr.u.i32
|
||||
&& llvm_data_end_global->init_expr.u.i32 <=
|
||||
llvm_heap_base_global->init_expr.u.i32)) {
|
||||
llvm_stack_top_global = global;
|
||||
llvm_stack_top = global->init_expr.u.i32;
|
||||
stack_top_global_index = global_index;
|
||||
LOG_VERBOSE("found llvm stack top global, "
|
||||
"value: %d, global index: %d\n",
|
||||
llvm_stack_top, global_index);
|
||||
&& (uint32)global->init_expr.u.i32 <= aux_heap_base) {
|
||||
aux_stack_top_global = global;
|
||||
aux_stack_top = (uint32)global->init_expr.u.i32;
|
||||
module->aux_stack_top_global_index =
|
||||
module->import_global_count + global_index;
|
||||
module->aux_stack_bottom = aux_stack_top;
|
||||
module->aux_stack_size = aux_stack_top > aux_data_end
|
||||
? aux_stack_top - aux_data_end
|
||||
: aux_stack_top;
|
||||
LOG_VERBOSE("Found aux stack top global, value: %d, "
|
||||
"global index: %d, stack size: %d",
|
||||
aux_stack_top, global_index,
|
||||
module->aux_stack_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
module->llvm_aux_data_end = llvm_data_end;
|
||||
module->llvm_aux_stack_bottom = llvm_stack_top;
|
||||
module->llvm_aux_stack_size = llvm_stack_top > llvm_data_end
|
||||
? llvm_stack_top - llvm_data_end
|
||||
: llvm_stack_top;
|
||||
module->llvm_aux_stack_global_index = stack_top_global_index;
|
||||
LOG_VERBOSE("aux stack bottom: %d, size: %d\n",
|
||||
module->llvm_aux_stack_bottom,
|
||||
module->llvm_aux_stack_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module->malloc_function = (uint32)-1;
|
||||
module->free_function = (uint32)-1;
|
||||
|
||||
/* Resolve auxiliary data/stack/heap info and reset memory info */
|
||||
export = module->exports;
|
||||
for (i = 0; i < module->export_count; i++, export++) {
|
||||
if (export->kind == EXPORT_KIND_FUNC) {
|
||||
if (!strcmp(export->name, "malloc")
|
||||
&& export->index >= module->import_function_count) {
|
||||
func_index = export->index - module->import_function_count;
|
||||
func_type = module->functions[func_index]->func_type;
|
||||
if (func_type->param_count == 1
|
||||
&& func_type->result_count == 1
|
||||
&& func_type->types[0] == VALUE_TYPE_I32
|
||||
&& func_type->types[1] == VALUE_TYPE_I32) {
|
||||
module->malloc_function = export->index;
|
||||
LOG_VERBOSE("Found malloc function, index: %u",
|
||||
export->index);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(export->name, "free")
|
||||
&& export->index >= module->import_function_count) {
|
||||
func_index = export->index - module->import_function_count;
|
||||
func_type = module->functions[func_index]->func_type;
|
||||
if (func_type->param_count == 1
|
||||
&& func_type->result_count == 0
|
||||
&& func_type->types[0] == VALUE_TYPE_I32) {
|
||||
module->free_function = export->index;
|
||||
LOG_VERBOSE("Found free function, index: %u",
|
||||
export->index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!module->possible_memory_grow) {
|
||||
if (llvm_data_end_global
|
||||
&& llvm_heap_base_global
|
||||
&& llvm_stack_top_global
|
||||
&& llvm_stack_top <= llvm_heap_base) {
|
||||
WASMMemoryImport *memory_import;
|
||||
WASMMemory *memory;
|
||||
WASMMemoryImport *memory_import;
|
||||
WASMMemory *memory;
|
||||
|
||||
if (aux_data_end_global
|
||||
&& aux_heap_base_global
|
||||
&& aux_stack_top_global) {
|
||||
uint64 init_memory_size;
|
||||
uint32 shrunk_memory_size = llvm_heap_base > llvm_data_end
|
||||
? llvm_heap_base : llvm_data_end;
|
||||
uint32 shrunk_memory_size = align_uint(aux_heap_base, 8);
|
||||
|
||||
if (module->import_memory_count) {
|
||||
memory_import = &module->import_memories[0].u.memory;
|
||||
init_memory_size = (uint64)memory_import->num_bytes_per_page *
|
||||
memory_import->init_page_count;
|
||||
if (llvm_heap_base <= init_memory_size
|
||||
&& llvm_data_end <= init_memory_size) {
|
||||
if (shrunk_memory_size <= init_memory_size) {
|
||||
/* Reset memory info to decrease memory usage */
|
||||
memory_import->num_bytes_per_page = shrunk_memory_size;
|
||||
memory_import->init_page_count = 1;
|
||||
LOG_VERBOSE("reset import memory size to %d\n",
|
||||
LOG_VERBOSE("Shrink import memory size to %d",
|
||||
shrunk_memory_size);
|
||||
}
|
||||
}
|
||||
if (module->memory_count) {
|
||||
memory = &module->memories[0];
|
||||
init_memory_size = (uint64)memory->num_bytes_per_page *
|
||||
memory->init_page_count;
|
||||
if (llvm_heap_base <= init_memory_size
|
||||
&& llvm_data_end <= init_memory_size) {
|
||||
memory->init_page_count;
|
||||
if (shrunk_memory_size <= init_memory_size) {
|
||||
/* Reset memory info to decrease memory usage */
|
||||
memory->num_bytes_per_page = shrunk_memory_size;
|
||||
memory->init_page_count = 1;
|
||||
LOG_VERBOSE("reset memory size to %d\n", shrunk_memory_size);
|
||||
LOG_VERBOSE("Shrink memory size to %d", shrunk_memory_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE == 0
|
||||
if (module->import_memory_count) {
|
||||
memory_import = &module->import_memories[0].u.memory;
|
||||
/* Memory init page count cannot be larger than 65536, we don't
|
||||
check integer overflow again. */
|
||||
memory_import->num_bytes_per_page *= memory_import->init_page_count;
|
||||
memory_import->init_page_count = memory_import->max_page_count = 1;
|
||||
}
|
||||
if (module->memory_count) {
|
||||
/* Memory init page count cannot be larger than 65536, we don't
|
||||
check integer overflow again. */
|
||||
memory = &module->memories[0];
|
||||
memory->num_bytes_per_page *= memory->init_page_count;
|
||||
memory->init_page_count = memory->max_page_count = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1878,7 +1963,7 @@ wasm_loader_load(const uint8 *buf, uint32 size, char *error_buf, uint32 error_bu
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LOG_VERBOSE("Load module success");
|
||||
LOG_VERBOSE("Load module success.\n");
|
||||
return module;
|
||||
|
||||
fail:
|
||||
@ -2295,8 +2380,11 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
|
||||
break;
|
||||
case WASM_OP_MISC_PREFIX:
|
||||
{
|
||||
opcode = read_uint8(p);
|
||||
switch (opcode) {
|
||||
uint32 opcode1;
|
||||
|
||||
read_leb_uint32(p, p_end, opcode1);
|
||||
|
||||
switch (opcode1) {
|
||||
case WASM_OP_I32_TRUNC_SAT_S_F32:
|
||||
case WASM_OP_I32_TRUNC_SAT_U_F32:
|
||||
case WASM_OP_I32_TRUNC_SAT_S_F64:
|
||||
@ -4869,8 +4957,8 @@ handle_op_block_and_loop:
|
||||
|| global_type == VALUE_TYPE_F64) {
|
||||
*p_org = WASM_OP_SET_GLOBAL_64;
|
||||
}
|
||||
else if (module->llvm_aux_stack_size > 0
|
||||
&& global_idx == module->llvm_aux_stack_global_index) {
|
||||
else if (module->aux_stack_size > 0
|
||||
&& global_idx == module->aux_stack_top_global_index) {
|
||||
*p_org = WASM_OP_SET_GLOBAL_AUX_STACK;
|
||||
}
|
||||
#endif
|
||||
@ -4880,8 +4968,8 @@ handle_op_block_and_loop:
|
||||
skip_label();
|
||||
emit_label(WASM_OP_SET_GLOBAL_64);
|
||||
}
|
||||
else if (module->llvm_aux_stack_size > 0
|
||||
&& global_idx == module->llvm_aux_stack_global_index) {
|
||||
else if (module->aux_stack_size > 0
|
||||
&& global_idx == module->aux_stack_top_global_index) {
|
||||
skip_label();
|
||||
emit_label(WASM_OP_SET_GLOBAL_AUX_STACK);
|
||||
}
|
||||
@ -5289,12 +5377,13 @@ handle_op_block_and_loop:
|
||||
|
||||
case WASM_OP_MISC_PREFIX:
|
||||
{
|
||||
opcode = read_uint8(p);
|
||||
uint32 opcode1;
|
||||
|
||||
read_leb_uint32(p, p_end, opcode1);
|
||||
#if WASM_ENABLE_FAST_INTERP != 0
|
||||
emit_byte(loader_ctx, opcode);
|
||||
emit_byte(loader_ctx, ((uint8)opcode1));
|
||||
#endif
|
||||
switch (opcode)
|
||||
{
|
||||
switch (opcode1) {
|
||||
case WASM_OP_I32_TRUNC_SAT_S_F32:
|
||||
case WASM_OP_I32_TRUNC_SAT_U_F32:
|
||||
POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I32);
|
||||
|
||||
@ -122,11 +122,13 @@ memory_instantiate(WASMModuleInstance *module_inst,
|
||||
uint32 heap_size, uint32 flags,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
WASMModule *module = module_inst->module;
|
||||
WASMMemoryInstance *memory;
|
||||
uint64 heap_and_inst_size = offsetof(WASMMemoryInstance, base_addr) +
|
||||
(uint64)heap_size;
|
||||
uint64 total_size = heap_and_inst_size +
|
||||
num_bytes_per_page * (uint64)init_page_count;
|
||||
uint64 total_size, memory_data_size;
|
||||
uint32 heap_offset = num_bytes_per_page * init_page_count;
|
||||
uint32 inc_page_count, aux_heap_base, global_idx;
|
||||
uint32 bytes_of_last_page, bytes_to_page_end;
|
||||
uint8 *global_addr;
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
bool is_shared_memory = flags & 0x02 ? true : false;
|
||||
@ -149,12 +151,96 @@ memory_instantiate(WASMModuleInstance *module_inst,
|
||||
(void)ref_count;
|
||||
return memory;
|
||||
}
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_SHARED_MEMORY */
|
||||
|
||||
if (heap_size > 0
|
||||
&& module_inst->module->malloc_function != (uint32)-1
|
||||
&& module_inst->module->free_function != (uint32)-1) {
|
||||
/* Disable app heap, use malloc/free function exported
|
||||
by wasm app to allocate/free memory instead */
|
||||
heap_size = 0;
|
||||
}
|
||||
|
||||
if (init_page_count == max_page_count && init_page_count == 1) {
|
||||
/* If only one page and at most one page, we just append
|
||||
the app heap to the end of linear memory, enlarge the
|
||||
num_bytes_per_page, and don't change the page count*/
|
||||
heap_offset = num_bytes_per_page;
|
||||
num_bytes_per_page += heap_size;
|
||||
if (num_bytes_per_page < heap_size) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"memory size must be at most 65536 pages (4GiB)");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (heap_size > 0) {
|
||||
if (module->aux_heap_base_global_index != (uint32)-1
|
||||
&& module->aux_heap_base < num_bytes_per_page
|
||||
* init_page_count) {
|
||||
/* Insert app heap before __heap_base */
|
||||
aux_heap_base = module->aux_heap_base;
|
||||
bytes_of_last_page = aux_heap_base % num_bytes_per_page;
|
||||
if (bytes_of_last_page == 0)
|
||||
bytes_of_last_page = num_bytes_per_page;
|
||||
bytes_to_page_end = num_bytes_per_page - bytes_of_last_page;
|
||||
inc_page_count = (heap_size - bytes_to_page_end
|
||||
+ num_bytes_per_page - 1) / num_bytes_per_page;
|
||||
heap_offset = aux_heap_base;
|
||||
aux_heap_base += heap_size;
|
||||
|
||||
bytes_of_last_page = aux_heap_base % num_bytes_per_page;
|
||||
if (bytes_of_last_page == 0)
|
||||
bytes_of_last_page = num_bytes_per_page;
|
||||
bytes_to_page_end = num_bytes_per_page - bytes_of_last_page;
|
||||
if (bytes_to_page_end < 1 * BH_KB) {
|
||||
aux_heap_base += 1 * BH_KB;
|
||||
inc_page_count++;
|
||||
}
|
||||
|
||||
/* Adjust __heap_base global value */
|
||||
global_idx = module->aux_heap_base_global_index;
|
||||
global_addr = module_inst->global_data +
|
||||
module_inst->globals[global_idx].data_offset;
|
||||
*(uint32 *)global_addr = aux_heap_base;
|
||||
LOG_VERBOSE("Reset __heap_base global to %u", aux_heap_base);
|
||||
}
|
||||
else {
|
||||
/* Insert app heap before new page */
|
||||
inc_page_count = (heap_size + num_bytes_per_page - 1)
|
||||
/ num_bytes_per_page;
|
||||
heap_offset = num_bytes_per_page * init_page_count;
|
||||
heap_size = num_bytes_per_page * inc_page_count;
|
||||
if (heap_size > 0)
|
||||
heap_size -= 1 * BH_KB;
|
||||
}
|
||||
init_page_count += inc_page_count;
|
||||
max_page_count += inc_page_count;
|
||||
if (init_page_count > 65536) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"memory size must be at most 65536 pages (4GiB)");
|
||||
return NULL;
|
||||
}
|
||||
if (max_page_count > 65536)
|
||||
max_page_count = 65536;
|
||||
}
|
||||
|
||||
LOG_VERBOSE("Memory instantiate:");
|
||||
LOG_VERBOSE(" page bytes: %u, init pages: %u, max pages: %u",
|
||||
num_bytes_per_page, init_page_count, max_page_count);
|
||||
LOG_VERBOSE(" heap offset: %u, heap size: %d\n", heap_offset, heap_size);
|
||||
|
||||
memory_data_size = (uint64)num_bytes_per_page * init_page_count;
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (is_shared_memory) {
|
||||
/* Allocate max page for shared memory */
|
||||
total_size = heap_and_inst_size +
|
||||
num_bytes_per_page * (uint64)max_page_count;
|
||||
memory_data_size = (uint64)num_bytes_per_page * max_page_count;
|
||||
}
|
||||
#endif
|
||||
|
||||
total_size = offsetof(WASMMemoryInstance, memory_data)
|
||||
+ memory_data_size;
|
||||
|
||||
/* Allocate memory space, addr data and global data */
|
||||
if (!(memory = runtime_malloc(total_size,
|
||||
error_buf, error_buf_size))) {
|
||||
@ -166,37 +252,28 @@ memory_instantiate(WASMModuleInstance *module_inst,
|
||||
memory->cur_page_count = init_page_count;
|
||||
memory->max_page_count = max_page_count;
|
||||
|
||||
memory->heap_data = memory->base_addr;
|
||||
memory->memory_data = memory->heap_data + heap_size;
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (is_shared_memory) {
|
||||
memory->end_addr = memory->memory_data +
|
||||
num_bytes_per_page * memory->max_page_count;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
memory->end_addr = memory->memory_data +
|
||||
num_bytes_per_page * memory->cur_page_count;
|
||||
}
|
||||
memory->heap_data = memory->memory_data + heap_offset;
|
||||
memory->heap_data_end = memory->heap_data + heap_size;
|
||||
memory->memory_data_end = memory->memory_data + (uint32)memory_data_size;
|
||||
|
||||
bh_assert(memory->end_addr - (uint8*)memory == (uint32)total_size);
|
||||
bh_assert(memory->memory_data_end - (uint8*)memory == (uint32)total_size);
|
||||
|
||||
/* Initialize heap */
|
||||
if (heap_size > 0
|
||||
&& !(memory->heap_handle =
|
||||
mem_allocator_create(memory->heap_data, heap_size))) {
|
||||
wasm_runtime_free(memory);
|
||||
return NULL;
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"Instantiate memory failed: "
|
||||
"init app heap failed.");
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
memory->heap_base_offset = -(int32)heap_size;
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (0 != os_mutex_init(&memory->mem_lock)) {
|
||||
mem_allocator_destroy(memory->heap_handle);
|
||||
wasm_runtime_free(memory);
|
||||
return NULL;
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"Instantiate memory failed: "
|
||||
"init mutex failed.");
|
||||
goto fail2;
|
||||
}
|
||||
if (is_shared_memory) {
|
||||
memory->is_shared = true;
|
||||
@ -204,16 +281,23 @@ memory_instantiate(WASMModuleInstance *module_inst,
|
||||
(WASMModuleCommon *)module_inst->module,
|
||||
(WASMMemoryInstanceCommon *)memory)) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"Instantiate memory failed:"
|
||||
"Instantiate memory failed: "
|
||||
"allocate memory failed.");
|
||||
os_mutex_destroy(&memory->mem_lock);
|
||||
mem_allocator_destroy(memory->heap_handle);
|
||||
wasm_runtime_free(memory);
|
||||
return NULL;
|
||||
goto fail3;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return memory;
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
fail3:
|
||||
os_mutex_destroy(&memory->mem_lock);
|
||||
fail2:
|
||||
if (heap_size > 0)
|
||||
mem_allocator_destroy(memory->heap_handle);
|
||||
#endif
|
||||
fail1:
|
||||
wasm_runtime_free(memory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -275,12 +359,7 @@ memories_instantiate(const WASMModule *module,
|
||||
module_inst, num_bytes_per_page, init_page_count,
|
||||
max_page_count, actual_heap_size, flags,
|
||||
error_buf, error_buf_size))) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"Instantiate memory failed: "
|
||||
"allocate memory failed.");
|
||||
memories_deinstantiate(
|
||||
module_inst,
|
||||
memories, memory_count);
|
||||
memories_deinstantiate(module_inst, memories, memory_count);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -295,12 +374,7 @@ memories_instantiate(const WASMModule *module,
|
||||
module->memories[i].max_page_count,
|
||||
heap_size, module->memories[i].flags,
|
||||
error_buf, error_buf_size))) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"Instantiate memory failed: "
|
||||
"allocate memory failed.");
|
||||
memories_deinstantiate(
|
||||
module_inst,
|
||||
memories, memory_count);
|
||||
memories_deinstantiate(module_inst, memories, memory_count);
|
||||
return NULL;
|
||||
}
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
@ -316,9 +390,6 @@ memories_instantiate(const WASMModule *module,
|
||||
if (!(memory = memories[mem_index++] =
|
||||
memory_instantiate(module_inst, 0, 0, 0, heap_size, 0,
|
||||
error_buf, error_buf_size))) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"Instantiate memory failed: "
|
||||
"allocate memory failed.\n");
|
||||
memories_deinstantiate(module_inst, memories, memory_count);
|
||||
return NULL;
|
||||
}
|
||||
@ -914,6 +985,34 @@ execute_start_function(WASMModuleInstance *module_inst)
|
||||
return wasm_create_exec_env_and_call_function(module_inst, func, 0, NULL);
|
||||
}
|
||||
|
||||
static bool
|
||||
execute_malloc_function(WASMModuleInstance *module_inst,
|
||||
WASMFunctionInstance *malloc_func,
|
||||
uint32 size, uint32 *p_result)
|
||||
{
|
||||
uint32 argv[2];
|
||||
bool ret;
|
||||
|
||||
argv[0] = size;
|
||||
ret = wasm_create_exec_env_and_call_function
|
||||
(module_inst, malloc_func, 1, argv);
|
||||
if (ret)
|
||||
*p_result = argv[0];
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
execute_free_function(WASMModuleInstance *module_inst,
|
||||
WASMFunctionInstance *free_func,
|
||||
uint32 offset)
|
||||
{
|
||||
uint32 argv[2];
|
||||
|
||||
argv[0] = offset;
|
||||
return wasm_create_exec_env_and_call_function
|
||||
(module_inst, free_func, 1, argv);
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
static bool
|
||||
sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst,
|
||||
@ -1251,6 +1350,28 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst,
|
||||
table_seg->func_indexes, (uint32)(length * sizeof(uint32)));
|
||||
}
|
||||
|
||||
/* module instance type */
|
||||
module_inst->module_type = Wasm_Module_Bytecode;
|
||||
|
||||
/* Initialize the thread related data */
|
||||
if (stack_size == 0)
|
||||
stack_size = DEFAULT_WASM_STACK_SIZE;
|
||||
#if WASM_ENABLE_SPEC_TEST != 0
|
||||
if (stack_size < 48 *1024)
|
||||
stack_size = 48 * 1024;
|
||||
#endif
|
||||
module_inst->default_wasm_stack_size = stack_size;
|
||||
|
||||
if (module->malloc_function != (uint32)-1) {
|
||||
module_inst->malloc_function =
|
||||
&module_inst->functions[module->malloc_function];
|
||||
}
|
||||
|
||||
if (module->free_function != (uint32)-1) {
|
||||
module_inst->free_function =
|
||||
&module_inst->functions[module->free_function];
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
/* The sub-instance will get the wasi_ctx from main-instance */
|
||||
if (!is_sub_inst) {
|
||||
@ -1278,18 +1399,6 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst,
|
||||
&module_inst->functions[module->start_function];
|
||||
}
|
||||
|
||||
/* module instance type */
|
||||
module_inst->module_type = Wasm_Module_Bytecode;
|
||||
|
||||
/* Initialize the thread related data */
|
||||
if (stack_size == 0)
|
||||
stack_size = DEFAULT_WASM_STACK_SIZE;
|
||||
#if WASM_ENABLE_SPEC_TEST != 0
|
||||
if (stack_size < 48 *1024)
|
||||
stack_size = 48 * 1024;
|
||||
#endif
|
||||
module_inst->default_wasm_stack_size = stack_size;
|
||||
|
||||
/* Execute __post_instantiate function */
|
||||
if (!execute_post_inst_function(module_inst)
|
||||
|| !execute_start_function(module_inst)) {
|
||||
@ -1467,7 +1576,22 @@ wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size,
|
||||
void **p_native_addr)
|
||||
{
|
||||
WASMMemoryInstance *memory = module_inst->default_memory;
|
||||
uint8 *addr = mem_allocator_malloc(memory->heap_handle, size);
|
||||
uint8 *addr = NULL;
|
||||
uint32 offset = 0;
|
||||
|
||||
if (memory->heap_handle) {
|
||||
addr = mem_allocator_malloc(memory->heap_handle, size);
|
||||
}
|
||||
else if (module_inst->malloc_function
|
||||
&& module_inst->free_function) {
|
||||
if (!execute_malloc_function(module_inst,
|
||||
module_inst->malloc_function,
|
||||
size, &offset)) {
|
||||
return 0;
|
||||
}
|
||||
addr = offset ? memory->memory_data + offset : NULL;
|
||||
}
|
||||
|
||||
if (!addr) {
|
||||
wasm_set_exception(module_inst, "out of memory");
|
||||
return 0;
|
||||
@ -1482,9 +1606,21 @@ wasm_module_free(WASMModuleInstance *module_inst, int32 ptr)
|
||||
{
|
||||
if (ptr) {
|
||||
WASMMemoryInstance *memory = module_inst->default_memory;
|
||||
uint8 *addr = memory->memory_data + ptr;
|
||||
if (memory->heap_data < addr && addr < memory->memory_data)
|
||||
uint8 *addr = memory->memory_data + (uint32)ptr;
|
||||
|
||||
if (memory->heap_handle
|
||||
&& memory->heap_data <= addr
|
||||
&& addr < memory->heap_data_end) {
|
||||
mem_allocator_free(memory->heap_handle, addr);
|
||||
}
|
||||
else if (module_inst->malloc_function
|
||||
&& module_inst->free_function
|
||||
&& memory->memory_data <= addr
|
||||
&& addr < memory->memory_data_end) {
|
||||
execute_free_function(module_inst,
|
||||
module_inst->free_function,
|
||||
(uint32)ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1507,16 +1643,15 @@ wasm_validate_app_addr(WASMModuleInstance *module_inst,
|
||||
int32 app_offset, uint32 size)
|
||||
{
|
||||
WASMMemoryInstance *memory = module_inst->default_memory;
|
||||
int32 memory_data_size =
|
||||
(int32)(memory->num_bytes_per_page * memory->cur_page_count);
|
||||
uint32 memory_data_size =
|
||||
memory->num_bytes_per_page * memory->cur_page_count;
|
||||
|
||||
/* integer overflow check */
|
||||
if (app_offset + (int32)size < app_offset) {
|
||||
if ((uint32)app_offset + size < (uint32)app_offset) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (memory->heap_base_offset <= app_offset
|
||||
&& app_offset + (int32)size <= memory_data_size) {
|
||||
if ((uint32)app_offset + size <= memory_data_size) {
|
||||
return true;
|
||||
}
|
||||
fail:
|
||||
@ -1528,17 +1663,16 @@ bool
|
||||
wasm_validate_native_addr(WASMModuleInstance *module_inst,
|
||||
void *native_ptr, uint32 size)
|
||||
{
|
||||
uint8 *addr = (uint8*)native_ptr;
|
||||
uint8 *addr = (uint8 *)native_ptr;
|
||||
WASMMemoryInstance *memory = module_inst->default_memory;
|
||||
int32 memory_data_size =
|
||||
(int32)(memory->num_bytes_per_page * memory->cur_page_count);
|
||||
|
||||
/* integer overflow check */
|
||||
if (addr + size < addr) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (memory->heap_data <= addr
|
||||
&& addr + size <= memory->memory_data + memory_data_size) {
|
||||
if (memory->memory_data <= addr
|
||||
&& addr + size <= memory->memory_data_end) {
|
||||
return true;
|
||||
}
|
||||
fail:
|
||||
@ -1552,11 +1686,9 @@ wasm_addr_app_to_native(WASMModuleInstance *module_inst,
|
||||
{
|
||||
WASMMemoryInstance *memory = module_inst->default_memory;
|
||||
uint8 *addr = memory->memory_data + app_offset;
|
||||
int32 memory_data_size =
|
||||
(int32)(memory->num_bytes_per_page * memory->cur_page_count);
|
||||
|
||||
if (memory->heap_data <= addr
|
||||
&& addr < memory->memory_data + memory_data_size)
|
||||
if (memory->memory_data <= addr
|
||||
&& addr < memory->memory_data_end)
|
||||
return addr;
|
||||
return NULL;
|
||||
}
|
||||
@ -1566,12 +1698,10 @@ wasm_addr_native_to_app(WASMModuleInstance *module_inst,
|
||||
void *native_ptr)
|
||||
{
|
||||
WASMMemoryInstance *memory = module_inst->default_memory;
|
||||
uint8 *addr = (uint8*)native_ptr;
|
||||
int32 memory_data_size =
|
||||
(int32)(memory->num_bytes_per_page * memory->cur_page_count);
|
||||
uint8 *addr = (uint8 *)native_ptr;
|
||||
|
||||
if (memory->heap_data <= addr
|
||||
&& addr < memory->memory_data + memory_data_size)
|
||||
if (memory->memory_data <= addr
|
||||
&& addr < memory->memory_data_end)
|
||||
return (int32)(addr - memory->memory_data);
|
||||
return 0;
|
||||
}
|
||||
@ -1583,13 +1713,12 @@ wasm_get_app_addr_range(WASMModuleInstance *module_inst,
|
||||
int32 *p_app_end_offset)
|
||||
{
|
||||
WASMMemoryInstance *memory = module_inst->default_memory;
|
||||
int32 memory_data_size =
|
||||
(int32)(memory->num_bytes_per_page * memory->cur_page_count);
|
||||
uint32 memory_data_size =
|
||||
memory->num_bytes_per_page * memory->cur_page_count;
|
||||
|
||||
if (memory->heap_base_offset <= app_offset
|
||||
&& app_offset < memory_data_size) {
|
||||
if ((uint32)app_offset < memory_data_size) {
|
||||
if (p_app_start_offset)
|
||||
*p_app_start_offset = memory->heap_base_offset;
|
||||
*p_app_start_offset = 0;
|
||||
if (p_app_end_offset)
|
||||
*p_app_end_offset = memory_data_size;
|
||||
return true;
|
||||
@ -1604,16 +1733,14 @@ wasm_get_native_addr_range(WASMModuleInstance *module_inst,
|
||||
uint8 **p_native_end_addr)
|
||||
{
|
||||
WASMMemoryInstance *memory = module_inst->default_memory;
|
||||
uint8 *addr = (uint8*)native_ptr;
|
||||
int32 memory_data_size =
|
||||
(int32)(memory->num_bytes_per_page * memory->cur_page_count);
|
||||
uint8 *addr = (uint8 *)native_ptr;
|
||||
|
||||
if (memory->heap_data <= addr
|
||||
&& addr < memory->memory_data + memory_data_size) {
|
||||
if (memory->memory_data <= addr
|
||||
&& addr < memory->memory_data_end) {
|
||||
if (p_native_start_addr)
|
||||
*p_native_start_addr = memory->heap_data;
|
||||
*p_native_start_addr = memory->memory_data;
|
||||
if (p_native_end_addr)
|
||||
*p_native_end_addr = memory->memory_data + memory_data_size;
|
||||
*p_native_end_addr = memory->memory_data_end;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -1623,13 +1750,13 @@ bool
|
||||
wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
|
||||
{
|
||||
WASMMemoryInstance *memory = module->default_memory, *new_memory;
|
||||
uint32 heap_size = memory->memory_data - memory->heap_data;
|
||||
uint32 total_size_old = memory->end_addr - (uint8*)memory;
|
||||
uint32 heap_size = memory->heap_data_end - memory->heap_data;
|
||||
uint32 total_size_old = memory->memory_data_end - (uint8 *)memory;
|
||||
uint32 total_page_count = inc_page_count + memory->cur_page_count;
|
||||
uint64 total_size = offsetof(WASMMemoryInstance, base_addr)
|
||||
+ (uint64)heap_size
|
||||
uint64 total_size = offsetof(WASMMemoryInstance, memory_data)
|
||||
+ memory->num_bytes_per_page * (uint64)total_page_count;
|
||||
void *heap_handle_old = memory->heap_handle;
|
||||
uint8 *heap_data_old = memory->heap_data;
|
||||
|
||||
if (inc_page_count <= 0)
|
||||
/* No need to enlarge memory */
|
||||
@ -1669,17 +1796,17 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
|
||||
wasm_set_exception(module, "fail to enlarge memory.");
|
||||
return false;
|
||||
}
|
||||
bh_memcpy_s((uint8*)new_memory, (uint32)total_size,
|
||||
(uint8*)memory, total_size_old);
|
||||
bh_memcpy_s((uint8 *)new_memory, (uint32)total_size,
|
||||
(uint8 *)memory, total_size_old);
|
||||
wasm_runtime_free(memory);
|
||||
}
|
||||
|
||||
memset((uint8*)new_memory + total_size_old,
|
||||
memset((uint8 *)new_memory + total_size_old,
|
||||
0, (uint32)total_size - total_size_old);
|
||||
|
||||
if (heap_size > 0) {
|
||||
new_memory->heap_handle = (uint8*)heap_handle_old +
|
||||
((uint8*)new_memory - (uint8*)memory);
|
||||
new_memory->heap_handle = (uint8 *)heap_handle_old +
|
||||
((uint8 *)new_memory - (uint8 *)memory);
|
||||
if (mem_allocator_migrate(new_memory->heap_handle,
|
||||
heap_handle_old) != 0) {
|
||||
wasm_set_exception(module, "fail to enlarge memory.");
|
||||
@ -1688,10 +1815,12 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
|
||||
}
|
||||
|
||||
new_memory->cur_page_count = total_page_count;
|
||||
new_memory->heap_data = new_memory->base_addr;
|
||||
new_memory->memory_data = new_memory->base_addr + heap_size;
|
||||
new_memory->end_addr = new_memory->memory_data +
|
||||
new_memory->num_bytes_per_page * total_page_count;
|
||||
new_memory->heap_data = heap_data_old +
|
||||
((uint8 *)new_memory - (uint8 *)memory);
|
||||
new_memory->heap_data_end = new_memory->heap_data + heap_size;
|
||||
new_memory->memory_data_end = new_memory->memory_data
|
||||
+ new_memory->num_bytes_per_page
|
||||
* total_page_count;
|
||||
|
||||
module->memories[0] = module->default_memory = new_memory;
|
||||
return true;
|
||||
@ -1757,13 +1886,9 @@ wasm_set_aux_stack(WASMExecEnv *exec_env,
|
||||
{
|
||||
WASMModuleInstance *module_inst =
|
||||
(WASMModuleInstance*)exec_env->module_inst;
|
||||
|
||||
uint32 stack_top_idx =
|
||||
module_inst->module->llvm_aux_stack_global_index;
|
||||
uint32 data_end =
|
||||
module_inst->module->llvm_aux_data_end;
|
||||
uint32 stack_bottom =
|
||||
module_inst->module->llvm_aux_stack_bottom;
|
||||
uint32 stack_top_idx = module_inst->module->aux_stack_top_global_index;
|
||||
uint32 data_end = module_inst->module->aux_data_end;
|
||||
uint32 stack_bottom = module_inst->module->aux_stack_bottom;
|
||||
bool is_stack_before_data =
|
||||
stack_bottom < data_end ? true : false;
|
||||
|
||||
@ -1772,7 +1897,7 @@ wasm_set_aux_stack(WASMExecEnv *exec_env,
|
||||
|| ((!is_stack_before_data) && (start_offset - data_end < size)))
|
||||
return false;
|
||||
|
||||
if ((stack_bottom != (uint32)-1) && (stack_top_idx != (uint32)-1)) {
|
||||
if (stack_top_idx != (uint32)-1) {
|
||||
/* The aux stack top is a wasm global,
|
||||
set the initial value for the global */
|
||||
uint8 *global_addr =
|
||||
@ -1798,9 +1923,9 @@ wasm_get_aux_stack(WASMExecEnv *exec_env,
|
||||
/* The aux stack information is resolved in loader
|
||||
and store in module */
|
||||
uint32 stack_bottom =
|
||||
module_inst->module->llvm_aux_stack_bottom;
|
||||
module_inst->module->aux_stack_bottom;
|
||||
uint32 total_aux_stack_size =
|
||||
module_inst->module->llvm_aux_stack_size;
|
||||
module_inst->module->aux_stack_size;
|
||||
|
||||
if (stack_bottom != 0 && total_aux_stack_size != 0) {
|
||||
if (start_offset)
|
||||
|
||||
@ -33,19 +33,13 @@ typedef struct WASMMemoryInstance {
|
||||
/* Maximum page count */
|
||||
uint32 max_page_count;
|
||||
|
||||
/* Heap base offset of wasm app */
|
||||
int32 heap_base_offset;
|
||||
/* Heap data base address */
|
||||
uint8 *heap_data;
|
||||
/* Heap data end address */
|
||||
uint8 *heap_data_end;
|
||||
/* The heap created */
|
||||
void *heap_handle;
|
||||
|
||||
/* Memory data */
|
||||
uint8 *memory_data;
|
||||
|
||||
/* End address of memory */
|
||||
uint8 *end_addr;
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
/* to indicate which module instance create it */
|
||||
WASMModuleInstance *owner;
|
||||
@ -56,13 +50,13 @@ typedef struct WASMMemoryInstance {
|
||||
korp_mutex mem_lock;
|
||||
#endif
|
||||
|
||||
/* Base address, the layout is:
|
||||
heap_data + memory data
|
||||
memory data init size is: num_bytes_per_page * cur_page_count
|
||||
/* Memory data end address */
|
||||
uint8 *memory_data_end;
|
||||
|
||||
/* Memory data begin address, the layout is: memory data + heap data
|
||||
Note: when memory is re-allocated, the heap data and memory data
|
||||
must be copied to new memory also.
|
||||
*/
|
||||
uint8 base_addr[1];
|
||||
must be copied to new memory also. */
|
||||
uint8 memory_data[1];
|
||||
} WASMMemoryInstance;
|
||||
|
||||
typedef struct WASMTableInstance {
|
||||
@ -188,6 +182,8 @@ typedef struct WASMModuleInstance {
|
||||
uint8 *global_data;
|
||||
|
||||
WASMFunctionInstance *start_function;
|
||||
WASMFunctionInstance *malloc_function;
|
||||
WASMFunctionInstance *free_function;
|
||||
|
||||
WASMModule *module;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user