Adding option to pass user data to allocator functions (#1765)

Add an option to pass user data to the allocator functions. It is common to
do this so that the host embedder can pass a struct as user data and access
that struct from the allocator, which gives the host embedder the ability to
do things such as track allocation statistics within the allocator.

Compile with `cmake -DWASM_MEM_ALLOC_WITH_USER_DATA=1` to enable
the option, and the allocator functions provided by the host embedder should
be like below (an extra argument `data` is added):
void *malloc(void *data, uint32 size) { .. }
void *realloc(void *data, uint32 size) { .. }
void free(void *data, void *ptr) { .. }

Signed-off-by: Andrew Chambers <ncham@amazon.com>
This commit is contained in:
Andy 2022-11-30 08:19:18 +00:00 committed by GitHub
parent 216b2cb540
commit 3e8927a31b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 88 additions and 9 deletions

View File

@ -311,3 +311,6 @@ endif ()
if (WAMR_BUILD_WASI_NN EQUAL 1) if (WAMR_BUILD_WASI_NN EQUAL 1)
message (" WASI-NN enabled") message (" WASI-NN enabled")
endif () endif ()
if (WAMR_BUILD_ALLOC_WITH_USER_DATA EQUAL 1)
add_definitions(-DWASM_MEM_ALLOC_WITH_USER_DATA=1)
endif()

View File

@ -426,4 +426,8 @@
#define WASM_ENABLE_SGX_IPFS 0 #define WASM_ENABLE_SGX_IPFS 0
#endif #endif
#ifndef WASM_MEM_ALLOC_WITH_USER_DATA
#define WASM_MEM_ALLOC_WITH_USER_DATA 0
#endif
#endif /* end of _CONFIG_H_ */ #endif /* end of _CONFIG_H_ */

View File

@ -340,6 +340,10 @@ wasm_engine_new_internal(mem_alloc_type_t type, const MemAllocOption *opts)
opts->allocator.free_func; opts->allocator.free_func;
init_args.mem_alloc_option.allocator.realloc_func = init_args.mem_alloc_option.allocator.realloc_func =
opts->allocator.realloc_func; opts->allocator.realloc_func;
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
init_args.mem_alloc_option.allocator.user_data =
opts->allocator.user_data;
#endif
} }
else { else {
init_args.mem_alloc_option.pool.heap_buf = NULL; init_args.mem_alloc_option.pool.heap_buf = NULL;

View File

@ -11,16 +11,25 @@
typedef enum Memory_Mode { typedef enum Memory_Mode {
MEMORY_MODE_UNKNOWN = 0, MEMORY_MODE_UNKNOWN = 0,
MEMORY_MODE_POOL, MEMORY_MODE_POOL,
MEMORY_MODE_ALLOCATOR MEMORY_MODE_ALLOCATOR,
MEMORY_MODE_SYSTEM_ALLOCATOR
} Memory_Mode; } Memory_Mode;
static Memory_Mode memory_mode = MEMORY_MODE_UNKNOWN; static Memory_Mode memory_mode = MEMORY_MODE_UNKNOWN;
static mem_allocator_t pool_allocator = NULL; static mem_allocator_t pool_allocator = NULL;
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
static void *allocator_user_data = NULL;
static void *(*malloc_func)(void *user_data, unsigned int size) = NULL;
static void *(*realloc_func)(void *user_data, void *ptr,
unsigned int size) = NULL;
static void (*free_func)(void *user_data, void *ptr) = NULL;
#else
static void *(*malloc_func)(unsigned int size) = NULL; static void *(*malloc_func)(unsigned int size) = NULL;
static void *(*realloc_func)(void *ptr, unsigned int size) = NULL; static void *(*realloc_func)(void *ptr, unsigned int size) = NULL;
static void (*free_func)(void *ptr) = NULL; static void (*free_func)(void *ptr) = NULL;
#endif
static unsigned int global_pool_size; static unsigned int global_pool_size;
@ -39,6 +48,24 @@ wasm_memory_init_with_pool(void *mem, unsigned int bytes)
return false; return false;
} }
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
static bool
wasm_memory_init_with_allocator(void *_user_data, void *_malloc_func,
void *_realloc_func, void *_free_func)
{
if (_malloc_func && _free_func && _malloc_func != _free_func) {
memory_mode = MEMORY_MODE_ALLOCATOR;
allocator_user_data = _user_data;
malloc_func = _malloc_func;
realloc_func = _realloc_func;
free_func = _free_func;
return true;
}
LOG_ERROR("Init memory with allocator (%p, %p, %p, %p) failed.\n",
_user_data, _malloc_func, _realloc_func, _free_func);
return false;
}
#else
static bool static bool
wasm_memory_init_with_allocator(void *_malloc_func, void *_realloc_func, wasm_memory_init_with_allocator(void *_malloc_func, void *_realloc_func,
void *_free_func) void *_free_func)
@ -54,23 +81,37 @@ wasm_memory_init_with_allocator(void *_malloc_func, void *_realloc_func,
_realloc_func, _free_func); _realloc_func, _free_func);
return false; return false;
} }
#endif
bool bool
wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type, wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type,
const MemAllocOption *alloc_option) const MemAllocOption *alloc_option)
{ {
if (mem_alloc_type == Alloc_With_Pool) if (mem_alloc_type == Alloc_With_Pool) {
return wasm_memory_init_with_pool(alloc_option->pool.heap_buf, return wasm_memory_init_with_pool(alloc_option->pool.heap_buf,
alloc_option->pool.heap_size); alloc_option->pool.heap_size);
else if (mem_alloc_type == Alloc_With_Allocator) }
else if (mem_alloc_type == Alloc_With_Allocator) {
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
return wasm_memory_init_with_allocator(
alloc_option->allocator.user_data,
alloc_option->allocator.malloc_func,
alloc_option->allocator.realloc_func,
alloc_option->allocator.free_func);
#else
return wasm_memory_init_with_allocator( return wasm_memory_init_with_allocator(
alloc_option->allocator.malloc_func, alloc_option->allocator.malloc_func,
alloc_option->allocator.realloc_func, alloc_option->allocator.realloc_func,
alloc_option->allocator.free_func); alloc_option->allocator.free_func);
else if (mem_alloc_type == Alloc_With_System_Allocator) #endif
return wasm_memory_init_with_allocator(os_malloc, os_realloc, os_free); }
else else if (mem_alloc_type == Alloc_With_System_Allocator) {
memory_mode = MEMORY_MODE_SYSTEM_ALLOCATOR;
return true;
}
else {
return false; return false;
}
} }
void void
@ -110,8 +151,15 @@ wasm_runtime_malloc_internal(unsigned int size)
else if (memory_mode == MEMORY_MODE_POOL) { else if (memory_mode == MEMORY_MODE_POOL) {
return mem_allocator_malloc(pool_allocator, size); return mem_allocator_malloc(pool_allocator, size);
} }
else { else if (memory_mode == MEMORY_MODE_ALLOCATOR) {
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
return malloc_func(allocator_user_data, size);
#else
return malloc_func(size); return malloc_func(size);
#endif
}
else {
return os_malloc(size);
} }
} }
@ -126,12 +174,19 @@ wasm_runtime_realloc_internal(void *ptr, unsigned int size)
else if (memory_mode == MEMORY_MODE_POOL) { else if (memory_mode == MEMORY_MODE_POOL) {
return mem_allocator_realloc(pool_allocator, ptr, size); return mem_allocator_realloc(pool_allocator, ptr, size);
} }
else { else if (memory_mode == MEMORY_MODE_ALLOCATOR) {
if (realloc_func) if (realloc_func)
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
return realloc_func(allocator_user_data, ptr, size);
#else
return realloc_func(ptr, size); return realloc_func(ptr, size);
#endif
else else
return NULL; return NULL;
} }
else {
return os_realloc(ptr, size);
}
} }
static inline void static inline void
@ -152,8 +207,15 @@ wasm_runtime_free_internal(void *ptr)
else if (memory_mode == MEMORY_MODE_POOL) { else if (memory_mode == MEMORY_MODE_POOL) {
mem_allocator_free(pool_allocator, ptr); mem_allocator_free(pool_allocator, ptr);
} }
else { else if (memory_mode == MEMORY_MODE_ALLOCATOR) {
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
free_func(allocator_user_data, ptr);
#else
free_func(ptr); free_func(ptr);
#endif
}
else {
os_free(ptr);
} }
} }

View File

@ -186,6 +186,9 @@ typedef union MemAllocOption {
void *malloc_func; void *malloc_func;
void *realloc_func; void *realloc_func;
void *free_func; void *free_func;
/* allocator user data, only used when
WASM_MEM_ALLOC_WITH_USER_DATA is defined */
void *user_data;
} allocator; } allocator;
} MemAllocOption; } MemAllocOption;
#endif #endif

View File

@ -117,6 +117,9 @@ typedef union MemAllocOption {
void *malloc_func; void *malloc_func;
void *realloc_func; void *realloc_func;
void *free_func; void *free_func;
/* allocator user data, only used when
WASM_MEM_ALLOC_WITH_USER_DATA is defined */
void *user_data;
} allocator; } allocator;
} MemAllocOption; } MemAllocOption;
#endif #endif