Implement memory.grow and limit heap space base offset to 1G (#36)

* Implement memory profiler, optimize memory usage, modify code indent

* Implement memory.grow and limit heap space base offset to 1G; modify iwasm build type to Release and 64 bit by default
This commit is contained in:
wenyongh
2019-05-31 01:21:39 -05:00
committed by GitHub
parent ff7cbdd2fb
commit 504268b297
11 changed files with 237 additions and 140 deletions

View File

@ -74,26 +74,28 @@ GET_F64_FROM_ADDR (uint32 *addr)
}
#endif /* WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 */
#define is_valid_addr(memory, heap, addr) \
(memory->base_addr <= addr && addr <= memory->end_addr) \
#define CHECK_MEMORY_OVERFLOW() do { \
uint32 offset1 = offset + addr; \
uint8 *maddr1; \
if (flags != 2) \
LOG_VERBOSE("unaligned load/store in wasm interp, flag is: %d.\n", flags);\
if (offset + addr < addr) { \
wasm_runtime_set_exception(module, "out of bounds memory access"); \
goto got_exception; \
if (offset1 < offset) \
goto out_of_bounds; \
if (offset1 < heap_base_offset) { \
maddr = memory->memory_data + offset1; \
if (maddr < memory->base_addr) \
goto out_of_bounds; \
maddr1 = maddr + LOAD_SIZE[opcode - WASM_OP_I32_LOAD]; \
if (maddr1 > memory->end_addr) \
goto out_of_bounds; \
} \
maddr = memory->memory_data + (offset + addr); \
if (!is_valid_addr(memory, NULL, maddr)) { \
wasm_runtime_set_exception(module, "out of bounds memory access"); \
goto got_exception; \
} \
maddr1 = maddr + LOAD_SIZE[opcode - WASM_OP_I32_LOAD]; \
if (!is_valid_addr(memory, NULL, maddr1)) { \
wasm_runtime_set_exception(module, "out of bounds memory access"); \
goto got_exception; \
else { \
maddr = memory->heap_data + offset1 - memory->heap_base_offset; \
if (maddr < memory->heap_data) \
goto out_of_bounds; \
maddr1 = maddr + LOAD_SIZE[opcode - WASM_OP_I32_LOAD]; \
if (maddr1 > memory->heap_data_end) \
goto out_of_bounds; \
} \
} while (0)
@ -712,6 +714,7 @@ wasm_interp_call_func_bytecode(WASMThread *self,
{
WASMModuleInstance *module = self->module_inst;
WASMMemoryInstance *memory = module->default_memory;
int32 heap_base_offset = memory ? memory->heap_base_offset : 0;
WASMTableInstance *table = module->default_table;
uint8 opcode_IMPDEP2 = WASM_OP_IMPDEP2;
WASMInterpFrame *frame = NULL;
@ -1247,26 +1250,25 @@ wasm_interp_call_func_bytecode(WASMThread *self,
HANDLE_OP (WASM_OP_MEMORY_GROW):
{
uint32 reserved, prev_page_count, delta, tmp;
uint32 reserved, delta, prev_page_count = memory->cur_page_count;
read_leb_uint32(frame_ip, frame_ip_end, reserved);
prev_page_count = memory->cur_page_count;
delta = POP_I32();
PUSH_I32(prev_page_count);
if (delta == 0)
HANDLE_OP_END ();
else if (delta + prev_page_count > memory->max_page_count ||
delta + prev_page_count < prev_page_count) {
tmp = POP_I32();
if (!wasm_runtime_enlarge_memory(module, delta)) {
/* fail to memory.grow, return -1 */
PUSH_I32(-1);
(void)tmp;
HANDLE_OP_END ();
if (wasm_runtime_get_exception(module)) {
printf("%s\n", wasm_runtime_get_exception(module));
wasm_runtime_set_exception(module, NULL);
}
}
else {
/* success, return previous page count */
PUSH_I32(prev_page_count);
/* update the memory instance ptr */
memory = module->default_memory;
}
if (!wasm_runtime_enlarge_memory(module, delta))
goto got_exception;
memory = module->default_memory;
(void)reserved;
HANDLE_OP_END ();
@ -2093,6 +2095,9 @@ wasm_interp_call_func_bytecode(WASMThread *self,
HANDLE_OP_END ();
}
out_of_bounds:
wasm_runtime_set_exception(module, "out of bounds memory access");
got_exception:
if (depths && depths != depth_buf) {
wasm_free(depths);

View File

@ -314,14 +314,20 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end,
char *error_buf, uint32 error_buf_size)
{
const uint8 *p = *p_buf, *p_end = buf_end;
uint32 pool_size = bh_memory_pool_size();
uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT
/ NumBytesPerPage;
read_leb_uint32(p, p_end, memory->flags);
read_leb_uint32(p, p_end, memory->init_page_count);
if (memory->flags & 1)
if (memory->flags & 1) {
read_leb_uint32(p, p_end, memory->max_page_count);
if (memory->max_page_count > max_page_count)
memory->max_page_count = max_page_count;
}
else
/* Limit the maximum memory size to 4GB */
memory->max_page_count = 0x10000;
/* Limit the maximum memory size to max_page_count */
memory->max_page_count = max_page_count;
*p_buf = p;
return true;
@ -351,14 +357,20 @@ 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;
uint32 pool_size = bh_memory_pool_size();
uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT
/ NumBytesPerPage;
read_leb_uint32(p, p_end, memory->flags);
read_leb_uint32(p, p_end, memory->init_page_count);
if (memory->flags & 1)
if (memory->flags & 1) {
read_leb_uint32(p, p_end, memory->max_page_count);
if (memory->max_page_count > max_page_count)
memory->max_page_count = max_page_count;
}
else
/* Limit the maximum memory size to 4GB */
memory->max_page_count = 0x10000;
/* Limit the maximum memory size to max_page_count */
memory->max_page_count = max_page_count;
*p_buf = p;
return true;

View File

@ -163,6 +163,7 @@ memories_deinstantiate(WASMMemoryInstance **memories, uint32 count)
if (memories[i]) {
if (memories[i]->heap_handle)
mem_allocator_destroy(memories[i]->heap_handle);
wasm_free(memories[i]->heap_data);
wasm_free(memories[i]);
}
wasm_free(memories);
@ -177,10 +178,10 @@ memory_instantiate(uint32 init_page_count, uint32 max_page_count,
{
WASMMemoryInstance *memory;
uint32 total_size = offsetof(WASMMemoryInstance, base_addr) +
NumBytesPerPage * init_page_count +
addr_data_size + global_data_size +
heap_size;
NumBytesPerPage * init_page_count +
addr_data_size + global_data_size;
/* Allocate memory space, addr data and global data */
if (!(memory = wasm_malloc(total_size))) {
set_error_buf(error_buf, error_buf_size,
"Instantiate memory failed: allocate memory failed.");
@ -190,28 +191,46 @@ memory_instantiate(uint32 init_page_count, uint32 max_page_count,
memset(memory, 0, total_size);
memory->cur_page_count = init_page_count;
memory->max_page_count = max_page_count;
memory->addr_data = memory->base_addr;
memory->addr_data_size = addr_data_size;
memory->memory_data = memory->addr_data + addr_data_size;
memory->heap_data = memory->memory_data +
NumBytesPerPage * memory->cur_page_count;;
memory->heap_data_size = heap_size;
memory->global_data = memory->heap_data + memory->heap_data_size;
memory->global_data = memory->memory_data +
NumBytesPerPage * memory->cur_page_count;;
memory->global_data_size = global_data_size;
memory->end_addr = memory->global_data + global_data_size;
/* Allocate heap space */
if (!(memory->heap_data = wasm_malloc(heap_size))) {
set_error_buf(error_buf, error_buf_size,
"Instantiate memory failed: allocate memory failed.");
goto fail1;
}
memory->heap_data_end = memory->heap_data + heap_size;
/* Initialize heap */
if (!(memory->heap_handle = mem_allocator_create
(memory->heap_data, memory->heap_data_size))) {
wasm_free(memory);
return NULL;
(memory->heap_data, heap_size))) {
goto fail2;
}
#if WASM_ENABLE_MEMORY_GROW != 0
memory->heap_base_offset = DEFAULT_APP_HEAP_BASE_OFFSET;
#else
memory->heap_base_offset = memory->end_addr - memory->memory_data;
#endif
return memory;
fail2:
wasm_free(memory->heap_data);
fail1:
wasm_free(memory);
return NULL;
}
/**
@ -975,58 +994,65 @@ wasm_runtime_deinstantiate(WASMModuleInstance *module_inst)
bool
wasm_runtime_enlarge_memory(WASMModuleInstance *module, int inc_page_count)
{
#if 1
wasm_runtime_set_exception(module, "unsupported operation: enlarge memory.");
return false;
#else
#if WASM_ENABLE_MEMORY_GROW != 0
WASMMemoryInstance *memory = module->default_memory;
WASMMemoryInstance *new_memory;
uint32 total_page_count = inc_page_count + memory->cur_page_count;
uint32 total_size = offsetof(WASMMemoryInstance, base_addr) +
memory->addr_data_size +
NumBytesPerPage * total_page_count +
memory->global_data_size +
memory->thunk_argv_data_size +
sizeof(uint32) * memory->thunk_argc;
memory->global_data_size;
if (inc_page_count <= 0)
/* No need to enlarge memory */
return true;
if (total_page_count < memory->cur_page_count /* integer overflow */
|| total_page_count > memory->max_page_count) {
wasm_runtime_set_exception(module, "fail to enlarge memory.");
return false;
}
if (!(new_memory = wasm_malloc(total_size))) {
wasm_runtime_set_exception(module, "alloc memory for enlarge memory failed.");
wasm_runtime_set_exception(module, "fail to enlarge memory.");
return false;
}
new_memory->cur_page_count = total_page_count;
new_memory->max_page_count = memory->max_page_count > total_page_count
? memory->max_page_count : total_page_count;
new_memory->max_page_count = memory->max_page_count;
new_memory->addr_data = new_memory->base_addr;
new_memory->addr_data_size = memory->addr_data_size;
new_memory->thunk_argv_data = new_memory->addr_data + memory->addr_data_size;
new_memory->thunk_argv_data_size = memory->thunk_argv_data_size;
new_memory->thunk_argc = memory->thunk_argc;
new_memory->thunk_argv_offsets = new_memory->thunk_argv_data +
memory->thunk_argv_data_size;
new_memory->memory_data = new_memory->addr_data + new_memory->addr_data_size;
new_memory->memory_data = new_memory->thunk_argv_offsets +
sizeof(uint32) * memory->thunk_argc;
new_memory->global_data = new_memory->memory_data +
NumBytesPerPage * new_memory->cur_page_count;
NumBytesPerPage * total_page_count;
new_memory->global_data_size = memory->global_data_size;
new_memory->end_addr = new_memory->global_data + memory->global_data_size;
/* Copy addr data, thunk argv data, thunk argv offsets and memory data */
/* Copy addr data and memory data */
memcpy(new_memory->addr_data, memory->addr_data,
memory->global_data - memory->addr_data);
/* Copy global data */
memcpy(new_memory->global_data, memory->global_data,
memory->end_addr - memory->global_data);
memory->global_data_size);
/* Init free space of new memory */
memset(new_memory->memory_data + NumBytesPerPage * memory->cur_page_count,
0, NumBytesPerPage * (total_page_count - memory->cur_page_count));
0, NumBytesPerPage * (total_page_count - memory->cur_page_count));
new_memory->heap_data = memory->heap_data;
new_memory->heap_data_end = memory->heap_data_end;
new_memory->heap_handle = memory->heap_handle;
new_memory->heap_base_offset = memory->heap_base_offset;
wasm_free(memory);
module->memories[0] = module->default_memory = new_memory;
wasm_free(memory);
return true;
#else
wasm_runtime_set_exception(module, "unsupported operation: enlarge memory.");
return false;
#endif
}
@ -1098,29 +1124,29 @@ wasm_runtime_get_current_module_inst()
int32
wasm_runtime_module_malloc(WASMModuleInstance *module_inst, uint32 size)
{
uint8 *memory_base = module_inst->default_memory->memory_data;
void *heap = module_inst->default_memory->heap_handle;
uint8 *addr = mem_allocator_malloc(heap, size);
if (!addr)
WASMMemoryInstance *memory = module_inst->default_memory;
uint8 *addr = mem_allocator_malloc(memory->heap_handle, size);
if (!addr) {
wasm_runtime_set_exception(module_inst, "out of memory");
return addr ? addr - memory_base : 0;
return 0;
}
return memory->heap_base_offset + (addr - memory->heap_data);
}
void
wasm_runtime_module_free(WASMModuleInstance *module_inst, int32 ptr)
{
uint8 *memory_base = module_inst->default_memory->memory_data;
uint8 *heap_base = module_inst->default_memory->heap_data;
uint32 heap_size = module_inst->default_memory->heap_data_size;
void *heap = module_inst->default_memory->heap_handle;
uint8 *addr = ptr ? memory_base + ptr : NULL;
if (addr && (heap_base < addr && addr < heap_base + heap_size))
mem_allocator_free(heap, addr);
if (ptr) {
WASMMemoryInstance *memory = module_inst->default_memory;
uint8 *addr = memory->heap_data + (ptr - memory->heap_base_offset);
if (memory->heap_data < addr && addr < memory->heap_data_end)
mem_allocator_free(memory->heap_handle, addr);
}
}
int32
int32
wasm_runtime_module_dup_data(WASMModuleInstance *module_inst,
const char *src, uint32 size)
const char *src, uint32 size)
{
int32 buffer_offset = wasm_runtime_module_malloc(module_inst, size);
if (buffer_offset != 0) {
@ -1135,22 +1161,32 @@ bool
wasm_runtime_validate_app_addr(WASMModuleInstance *module_inst,
int32 app_offset, uint32 size)
{
WASMMemoryInstance *memory;
uint8 *addr;
/* integer overflow check */
if(app_offset < 0 ||
app_offset + size < size) {
wasm_runtime_set_exception(module_inst, "out of bounds memory access");
return false;
app_offset + size < app_offset) {
goto fail;
}
uint8 *memory_base = module_inst->default_memory->memory_data;
uint8 *addr = memory_base + app_offset;
uint8 *base_addr = module_inst->default_memory->base_addr;
uint8 *end_addr = module_inst->default_memory->end_addr;
bool ret = (base_addr <= addr
&& addr + size <= end_addr);
if (!ret)
wasm_runtime_set_exception(module_inst, "out of bounds memory access");
return ret;
memory = module_inst->default_memory;
if (app_offset < memory->heap_base_offset) {
addr = memory->memory_data + app_offset;
if (!(memory->base_addr <= addr && addr + size <= memory->end_addr))
goto fail;
return true;
}
else {
addr = memory->heap_data + (app_offset - memory->heap_base_offset);
if (!(memory->heap_data <= addr && addr + size <= memory->heap_data_end))
goto fail;
return true;
}
fail:
wasm_runtime_set_exception(module_inst, "out of bounds memory access");
return false;
}
bool
@ -1158,26 +1194,42 @@ wasm_runtime_validate_native_addr(WASMModuleInstance *module_inst,
void *native_ptr, uint32 size)
{
uint8 *addr = native_ptr;
uint8 *base_addr = module_inst->default_memory->base_addr;
uint8 *end_addr = module_inst->default_memory->end_addr;
bool ret = (base_addr <= addr && addr + size <= end_addr);
if (!ret || (addr + size < addr)/* integer overflow */)
wasm_runtime_set_exception(module_inst, "out of bounds memory access");
return ret;
WASMMemoryInstance *memory = module_inst->default_memory;
if (addr + size < addr) {
goto fail;
}
if ((memory->base_addr <= addr && addr + size <= memory->end_addr)
|| (memory->heap_data <= addr && addr + size <= memory->heap_data_end))
return true;
fail:
wasm_runtime_set_exception(module_inst, "out of bounds memory access");
return false;
}
void *
wasm_runtime_addr_app_to_native(WASMModuleInstance *module_inst,
int32 app_offset)
{
return module_inst->default_memory->memory_data + app_offset;
WASMMemoryInstance *memory = module_inst->default_memory;
if (app_offset < memory->heap_base_offset)
return memory->memory_data + app_offset;
else
return memory->heap_data + (app_offset - memory->heap_base_offset);
}
int32
wasm_runtime_addr_native_to_app(WASMModuleInstance *module_inst,
void *native_ptr)
{
return (uint8*)native_ptr - module_inst->default_memory->memory_data;
WASMMemoryInstance *memory = module_inst->default_memory;
if ((uint8*)native_ptr < memory->heap_data)
return (uint8*)native_ptr - memory->memory_data;
else
return memory->heap_base_offset
+ ((uint8*)native_ptr - memory->heap_data);
}
uint32

View File

@ -37,20 +37,14 @@ typedef struct WASMMemoryInstance {
/* Size of addr_data */
uint32 addr_data_size;
/* Thunk data of argument strings */
uint8 *thunk_argv_data;
uint32 thunk_argv_data_size;
/* Thunk argument count */
uint32 thunk_argc;
/* Thunk argument offsets */
uint8 *thunk_argv_offsets;
/* Heap data */
/* Heap data base address */
uint8 *heap_data;
/* Heap size */
uint32 heap_data_size;
/* Heap data end address */
uint8 *heap_data_end;
/* The heap created */
void *heap_handle;
/* Heap base offset of wasm app */
int32 heap_base_offset;
/* Memory data */
uint8 *memory_data;
@ -63,7 +57,7 @@ typedef struct WASMMemoryInstance {
/* Base address, the layout is:
addr_data + thunk_argv data + thunk arg offsets +
heap data + memory data + global data
memory data + global data
memory data init size is: NumBytesPerPage * cur_page_count
addr data size and global data size is calculated in module instantiating
Note: when memory is re-allocated, the addr data, thunk argv data, thunk