Merge branch main into dev/wasi-libc-windows

This commit is contained in:
Wenyong Huang
2023-08-23 17:05:19 +08:00
77 changed files with 1903 additions and 588 deletions

View File

@ -144,6 +144,14 @@
#define WASM_ENABLE_WASI_NN 0
#endif
#ifndef WASM_ENABLE_WASI_NN_GPU
#define WASM_ENABLE_WASI_NN_GPU 0
#endif
#ifndef WASM_ENABLE_WASI_NN_EXTERNAL_DELEGATE
#define WASM_ENABLE_WASI_NN_EXTERNAL_DELEGATE 0
#endif
/* Default disable libc emcc */
#ifndef WASM_ENABLE_LIBC_EMCC
#define WASM_ENABLE_LIBC_EMCC 0

View File

@ -1644,27 +1644,6 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, AOTModule *module,
const uint8 *p = buf, *p_end = buf_end;
uint32 i;
uint64 size, text_offset;
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
RUNTIME_FUNCTION *rtl_func_table;
AOTUnwindInfo *unwind_info;
uint32 unwind_info_offset = module->code_size - sizeof(AOTUnwindInfo);
uint32 unwind_code_offset = unwind_info_offset - PLT_ITEM_SIZE;
#endif
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
unwind_info = (AOTUnwindInfo *)((uint8 *)module->code + module->code_size
- sizeof(AOTUnwindInfo));
unwind_info->Version = 1;
unwind_info->Flags = UNW_FLAG_NHANDLER;
*(uint32 *)&unwind_info->UnwindCode[0] = unwind_code_offset;
size = sizeof(RUNTIME_FUNCTION) * (uint64)module->func_count;
if (size > 0
&& !(rtl_func_table = module->rtl_func_table =
loader_malloc(size, error_buf, error_buf_size))) {
return false;
}
#endif
size = sizeof(void *) * (uint64)module->func_count;
if (size > 0
@ -1691,33 +1670,9 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, AOTModule *module,
#if defined(BUILD_TARGET_THUMB) || defined(BUILD_TARGET_THUMB_VFP)
/* bits[0] of thumb function address must be 1 */
module->func_ptrs[i] = (void *)((uintptr_t)module->func_ptrs[i] | 1);
#endif
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
rtl_func_table[i].BeginAddress = (DWORD)text_offset;
if (i > 0) {
rtl_func_table[i - 1].EndAddress = rtl_func_table[i].BeginAddress;
}
rtl_func_table[i].UnwindInfoAddress = (DWORD)unwind_info_offset;
#endif
}
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
if (module->func_count > 0) {
uint32 plt_table_size =
module->is_indirect_mode ? 0 : get_plt_table_size();
rtl_func_table[module->func_count - 1].EndAddress =
(DWORD)(module->code_size - plt_table_size);
if (!RtlAddFunctionTable(rtl_func_table, module->func_count,
(DWORD64)(uintptr_t)module->code)) {
set_error_buf(error_buf, error_buf_size,
"add dynamic function table failed");
return false;
}
module->rtl_func_table_registered = true;
}
#endif
/* Set start function when function pointers are resolved */
if (module->start_func_index != (uint32)-1) {
if (module->start_func_index >= module->import_func_count)
@ -3261,14 +3216,6 @@ aot_unload(AOTModule *module)
}
#endif
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
if (module->rtl_func_table) {
if (module->rtl_func_table_registered)
RtlDeleteFunctionTable(module->rtl_func_table);
wasm_runtime_free(module->rtl_func_table);
}
#endif
#if (defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)) \
&& !defined(BH_PLATFORM_WINDOWS)
{

View File

@ -420,7 +420,7 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent,
if (num_bytes_per_page < heap_size) {
set_error_buf(error_buf, error_buf_size,
"failed to insert app heap into linear memory, "
"try using `--heap_size=0` option");
"try using `--heap-size=0` option");
return NULL;
}
}
@ -478,7 +478,7 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent,
if (init_page_count > DEFAULT_MAX_PAGES) {
set_error_buf(error_buf, error_buf_size,
"failed to insert app heap into linear memory, "
"try using `--heap_size=0` option");
"try using `--heap-size=0` option");
return NULL;
}
else if (init_page_count == DEFAULT_MAX_PAGES) {
@ -1271,9 +1271,9 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
if (module_inst->func_type_indexes)
wasm_runtime_free(module_inst->func_type_indexes);
if (((AOTModuleInstanceExtra *)module_inst->e)->c_api_func_imports)
wasm_runtime_free(
((AOTModuleInstanceExtra *)module_inst->e)->c_api_func_imports);
if (((AOTModuleInstanceExtra *)module_inst->e)->common.c_api_func_imports)
wasm_runtime_free(((AOTModuleInstanceExtra *)module_inst->e)
->common.c_api_func_imports);
if (!is_sub_inst) {
#if WASM_ENABLE_LIBC_WASI != 0
@ -1925,8 +1925,8 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
AOTModuleInstanceExtra *module_inst_extra =
(AOTModuleInstanceExtra *)module_inst->e;
CApiFuncImport *c_api_func_import =
module_inst_extra->c_api_func_imports
? module_inst_extra->c_api_func_imports + func_idx
module_inst_extra->common.c_api_func_imports
? module_inst_extra->common.c_api_func_imports + func_idx
: NULL;
uint32 *func_type_indexes = module_inst->func_type_indexes;
uint32 func_type_idx = func_type_indexes[func_idx];

View File

@ -89,37 +89,9 @@ typedef struct AOTFunctionInstance {
typedef struct AOTModuleInstanceExtra {
DefPointer(const uint32 *, stack_sizes);
CApiFuncImport *c_api_func_imports;
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
/* Disable bounds checks or not */
bool disable_bounds_checks;
#endif
WASMModuleInstanceExtraCommon common;
} AOTModuleInstanceExtra;
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
/* clang-format off */
typedef struct AOTUnwindInfo {
uint8 Version : 3;
uint8 Flags : 5;
uint8 SizeOfProlog;
uint8 CountOfCodes;
uint8 FrameRegister : 4;
uint8 FrameOffset : 4;
struct {
struct {
uint8 CodeOffset;
uint8 UnwindOp : 4;
uint8 OpInfo : 4;
};
uint16 FrameOffset;
} UnwindCode[1];
} AOTUnwindInfo;
/* clang-format on */
/* size of mov instruction and jmp instruction */
#define PLT_ITEM_SIZE 12
#endif
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
typedef struct GOTItem {
uint32 func_idx;
@ -215,14 +187,6 @@ typedef struct AOTModule {
uint32 float_plt_count;
#endif
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
/* dynamic function table to be added by RtlAddFunctionTable(),
used to unwind the call stack and register exception handler
for AOT functions */
RUNTIME_FUNCTION *rtl_func_table;
bool rtl_func_table_registered;
#endif
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
uint32 got_item_count;
GOTItemList got_item_list;

View File

@ -164,6 +164,9 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr,
(uint32)((uintptr_t)symbol_addr + (intptr_t)reloc_addend
- (uintptr_t)(target_section_addr
+ (uint32)reloc_offset)
#if defined(BH_PLATFORM_WINDOWS)
- sizeof(int32)
#endif
+ value); /* S + A - P */
break;
}

View File

@ -69,9 +69,6 @@ get_plt_table_size()
{
uint32 size =
get_plt_item_size() * (sizeof(target_sym_map) / sizeof(SymbolMap));
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
size += get_plt_item_size() + sizeof(AOTUnwindInfo);
#endif
return size;
}
@ -93,18 +90,6 @@ init_plt_table(uint8 *plt)
*p++ = 0xE0;
plt += get_plt_item_size();
}
#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
p = plt;
/* mov exception_handler, rax */
*p++ = 0x48;
*p++ = 0xB8;
*(uint64 *)p = 0; /*(uint64)(uintptr_t)aot_exception_handler;*/
p += sizeof(uint64);
/* jmp rax */
*p++ = 0xFF;
*p++ = 0xE0;
#endif
}
static bool
@ -242,7 +227,7 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr,
- (uintptr_t)(target_section_addr + reloc_offset));
}
else {
target_addr = (intptr_t) /* L + A - P */
target_addr = (intptr_t) /* S + A - P */
((uintptr_t)symbol_addr + reloc_addend
- (uintptr_t)(target_section_addr + reloc_offset));
}

View File

@ -36,5 +36,49 @@ if (WAMR_BUILD_DEBUG_AOT EQUAL 1)
file(GLOB debug_source ${IWASM_AOT_DIR}/debug/*.c)
endif()
set (IWASM_AOT_SOURCE ${c_source_all} ${arch_source} ${debug_source})
if ((WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64")
AND (WAMR_BUILD_PLATFORM STREQUAL "windows")
AND (NOT WAMR_DISABLE_HW_BOUND_CHECK EQUAL 1))
include(FetchContent)
FetchContent_Declare(
zycore
GIT_REPOSITORY https://github.com/zyantific/zycore-c.git
)
FetchContent_GetProperties(zycore)
if (NOT zycore_POPULATED)
message ("-- Fetching zycore ..")
FetchContent_Populate(zycore)
include_directories("${zycore_SOURCE_DIR}/include")
include_directories("${zycore_BINARY_DIR}")
add_definitions(-DZYCORE_STATIC_BUILD=1)
add_subdirectory(${zycore_SOURCE_DIR} ${zycore_BINARY_DIR} EXCLUDE_FROM_ALL)
file (GLOB_RECURSE c_source_zycore ${zycore_SOURCE_DIR}/src/*.c)
endif ()
FetchContent_Declare(
zydis
GIT_REPOSITORY https://github.com/zyantific/zydis.git
GIT_TAG e14a07895136182a5b53e181eec3b1c6e0b434de
)
FetchContent_GetProperties(zydis)
if (NOT zydis_POPULATED)
message ("-- Fetching zydis ..")
FetchContent_Populate(zydis)
option(ZYDIS_FEATURE_ENCODER "" OFF)
option(ZYDIS_BUILD_TOOLS "" OFF)
option(ZYDIS_BUILD_EXAMPLES "" OFF)
option(ZYDIS_BUILD_MAN "" OFF)
option(ZYDIS_BUILD_DOXYGEN "" OFF)
include_directories("${zydis_BINARY_DIR}")
include_directories("${zydis_SOURCE_DIR}/include")
include_directories("${zydis_SOURCE_DIR}/src")
add_definitions(-DZYDIS_STATIC_BUILD=1)
add_subdirectory(${zydis_SOURCE_DIR} ${zydis_BINARY_DIR} EXCLUDE_FROM_ALL)
file (GLOB_RECURSE c_source_zydis ${zydis_SOURCE_DIR}/src/*.c)
endif ()
endif ()
set (IWASM_AOT_SOURCE ${c_source_all} ${arch_source} ${debug_source}
${c_source_zycore} ${c_source_zydis})

View File

@ -2290,8 +2290,10 @@ quit:
bool
wasm_module_validate(wasm_store_t *store, const wasm_byte_vec_t *binary)
{
wasm_byte_vec_t local_binary = { 0 };
struct WASMModuleCommon *module_rt;
char error_buf[128] = { 0 };
bool ret;
bh_assert(singleton_engine);
@ -2300,15 +2302,25 @@ wasm_module_validate(wasm_store_t *store, const wasm_byte_vec_t *binary)
return false;
}
if ((module_rt = wasm_runtime_load((uint8 *)binary->data,
(uint32)binary->size, error_buf, 128))) {
/* make a copy of binary */
wasm_byte_vec_copy(&local_binary, binary);
if (binary->size && !local_binary.data)
return false;
module_rt = wasm_runtime_load((uint8 *)local_binary.data,
(uint32)local_binary.size, error_buf, 128);
wasm_byte_vec_delete(&local_binary);
if (module_rt) {
wasm_runtime_unload(module_rt);
return true;
ret = true;
}
else {
ret = false;
LOG_VERBOSE(error_buf);
return false;
}
return ret;
}
static void
@ -4858,7 +4870,7 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
if (instance->inst_comm_rt->module_type == Wasm_Module_Bytecode) {
WASMModuleInstanceExtra *e =
((WASMModuleInstance *)instance->inst_comm_rt)->e;
p_func_imports = &(e->c_api_func_imports);
p_func_imports = &(e->common.c_api_func_imports);
import_func_count = MODULE_INTERP(module)->import_function_count;
}
#endif
@ -4868,7 +4880,7 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
(AOTModuleInstanceExtra *)((AOTModuleInstance *)
instance->inst_comm_rt)
->e;
p_func_imports = &(e->c_api_func_imports);
p_func_imports = &(e->common.c_api_func_imports);
import_func_count = MODULE_AOT(module)->import_func_count;
}
#endif

View File

@ -199,7 +199,90 @@ runtime_signal_handler(void *sig_addr)
}
}
}
#else
#else /* else of BH_PLATFORM_WINDOWS */
#if WASM_ENABLE_AOT != 0
#include <Zydis/Zydis.h>
static uint32
decode_insn(uint8 *insn)
{
uint8 *data = (uint8 *)insn;
uint32 length = 32; /* reserve enough size */
/* Initialize decoder context */
ZydisDecoder decoder;
ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64,
ZYDIS_STACK_WIDTH_64);
/* Initialize formatter */
ZydisFormatter formatter;
ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL);
/* Loop over the instructions in our buffer */
ZyanU64 runtime_address = (ZyanU64)(uintptr_t)data;
ZyanUSize offset = 0;
ZydisDecodedInstruction instruction;
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT_VISIBLE];
char buffer[256];
if (ZYAN_SUCCESS(ZydisDecoderDecodeFull(
&decoder, data + offset, length - offset, &instruction, operands,
ZYDIS_MAX_OPERAND_COUNT_VISIBLE,
ZYDIS_DFLAG_VISIBLE_OPERANDS_ONLY))) {
/* Format & print the binary instruction structure to
human readable format */
ZydisFormatterFormatInstruction(&formatter, &instruction, operands,
instruction.operand_count_visible,
buffer, sizeof(buffer),
runtime_address);
/* Print current instruction */
/*
os_printf("%012" PRIX64 " ", runtime_address);
puts(buffer);
*/
return instruction.length;
}
/* Decode failed */
return 0;
}
#endif /* end of WASM_ENABLE_AOT != 0 */
static LONG
next_action(WASMModuleInstance *module_inst, EXCEPTION_POINTERS *exce_info)
{
#if WASM_ENABLE_AOT != 0
uint32 insn_size;
#endif
if (module_inst->module_type == Wasm_Module_Bytecode
&& module_inst->e->running_mode == Mode_Interp) {
/* Continue to search next exception handler for
interpreter mode as it can be caught by
`__try { .. } __except { .. }` sentences in
wasm_runtime.c */
return EXCEPTION_CONTINUE_SEARCH;
}
#if WASM_ENABLE_AOT != 0
/* Skip current instruction and continue to run for AOT/JIT mode.
TODO: implement unwind support for AOT/JIT code in Windows platform */
insn_size = decode_insn((uint8 *)exce_info->ContextRecord->Rip);
if (insn_size > 0) {
exce_info->ContextRecord->Rip += insn_size;
return EXCEPTION_CONTINUE_EXECUTION;
}
#endif
/* return different value from EXCEPTION_CONTINUE_SEARCH (= 0)
and EXCEPTION_CONTINUE_EXECUTION (= -1) */
return -2;
}
static LONG
runtime_exception_handler(EXCEPTION_POINTERS *exce_info)
{
@ -211,6 +294,7 @@ runtime_exception_handler(EXCEPTION_POINTERS *exce_info)
uint8 *mapped_mem_start_addr = NULL;
uint8 *mapped_mem_end_addr = NULL;
uint32 page_size = os_getpagesize();
LONG ret;
if (exec_env_tls && exec_env_tls->handle == os_self_thread()
&& (jmpbuf_node = exec_env_tls->jmpbuf_stack_top)) {
@ -232,32 +316,19 @@ runtime_exception_handler(EXCEPTION_POINTERS *exce_info)
the wasm func returns, the caller will check whether the
exception is thrown and return to runtime. */
wasm_set_exception(module_inst, "out of bounds memory access");
if (module_inst->module_type == Wasm_Module_Bytecode) {
/* Continue to search next exception handler for
interpreter mode as it can be caught by
`__try { .. } __except { .. }` sentences in
wasm_runtime.c */
return EXCEPTION_CONTINUE_SEARCH;
}
else {
/* Skip current instruction and continue to run for
AOT mode. TODO: implement unwind support for AOT
code in Windows platform */
exce_info->ContextRecord->Rip++;
return EXCEPTION_CONTINUE_EXECUTION;
}
ret = next_action(module_inst, exce_info);
if (ret == EXCEPTION_CONTINUE_SEARCH
|| ret == EXCEPTION_CONTINUE_EXECUTION)
return ret;
}
else if (exec_env_tls->exce_check_guard_page <= (uint8 *)sig_addr
&& (uint8 *)sig_addr
< exec_env_tls->exce_check_guard_page + page_size) {
bh_assert(wasm_copy_exception(module_inst, NULL));
if (module_inst->module_type == Wasm_Module_Bytecode) {
return EXCEPTION_CONTINUE_SEARCH;
}
else {
exce_info->ContextRecord->Rip++;
return EXCEPTION_CONTINUE_EXECUTION;
}
ret = next_action(module_inst, exce_info);
if (ret == EXCEPTION_CONTINUE_SEARCH
|| ret == EXCEPTION_CONTINUE_EXECUTION)
return ret;
}
}
#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
@ -267,12 +338,10 @@ runtime_exception_handler(EXCEPTION_POINTERS *exce_info)
whether the exception is thrown and return to runtime, and
the damaged stack will be recovered by _resetstkoflw(). */
wasm_set_exception(module_inst, "native stack overflow");
if (module_inst->module_type == Wasm_Module_Bytecode) {
return EXCEPTION_CONTINUE_SEARCH;
}
else {
return EXCEPTION_CONTINUE_EXECUTION;
}
ret = next_action(module_inst, exce_info);
if (ret == EXCEPTION_CONTINUE_SEARCH
|| ret == EXCEPTION_CONTINUE_EXECUTION)
return ret;
}
#endif
}
@ -2491,14 +2560,14 @@ wasm_runtime_set_bounds_checks(WASMModuleInstanceCommon *module_inst,
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode) {
((WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)->e)
->disable_bounds_checks = enable ? false : true;
->common.disable_bounds_checks = enable ? false : true;
}
#endif
#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT) {
((AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e)
->disable_bounds_checks = enable ? false : true;
->common.disable_bounds_checks = enable ? false : true;
}
#endif
}
@ -2511,7 +2580,7 @@ wasm_runtime_is_bounds_checks_enabled(WASMModuleInstanceCommon *module_inst)
if (module_inst->module_type == Wasm_Module_Bytecode) {
return !((WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)
->e)
->disable_bounds_checks;
->common.disable_bounds_checks;
}
#endif
@ -2519,7 +2588,7 @@ wasm_runtime_is_bounds_checks_enabled(WASMModuleInstanceCommon *module_inst)
if (module_inst->module_type == Wasm_Module_AoT) {
return !((AOTModuleInstanceExtra *)((WASMModuleInstance *)module_inst)
->e)
->disable_bounds_checks;
->common.disable_bounds_checks;
}
#endif
@ -4692,6 +4761,8 @@ typedef struct ExternRefMapNode {
bool retained;
/* Whether it is marked by runtime */
bool marked;
/* cleanup function called when the externref is freed */
void (*cleanup)(void *);
} ExternRefMapNode;
static uint32
@ -4754,6 +4825,81 @@ lookup_extobj_callback(void *key, void *value, void *user_data)
}
}
static void
delete_externref(void *key, ExternRefMapNode *node)
{
bh_hash_map_remove(externref_map, key, NULL, NULL);
if (node->cleanup) {
(*node->cleanup)(node->extern_obj);
}
wasm_runtime_free(node);
}
static void
delete_extobj_callback(void *key, void *value, void *user_data)
{
ExternRefMapNode *node = (ExternRefMapNode *)value;
LookupExtObj_UserData *lookup_user_data =
(LookupExtObj_UserData *)user_data;
if (node->extern_obj == lookup_user_data->node.extern_obj
&& node->module_inst == lookup_user_data->node.module_inst) {
lookup_user_data->found = true;
delete_externref(key, node);
}
}
bool
wasm_externref_objdel(WASMModuleInstanceCommon *module_inst, void *extern_obj)
{
LookupExtObj_UserData lookup_user_data = { 0 };
bool ok = false;
/* in a wrapper, extern_obj could be any value */
lookup_user_data.node.extern_obj = extern_obj;
lookup_user_data.node.module_inst = module_inst;
lookup_user_data.found = false;
os_mutex_lock(&externref_lock);
/* Lookup hashmap firstly */
bh_hash_map_traverse(externref_map, delete_extobj_callback,
(void *)&lookup_user_data);
if (lookup_user_data.found) {
ok = true;
}
os_mutex_unlock(&externref_lock);
return ok;
}
bool
wasm_externref_set_cleanup(WASMModuleInstanceCommon *module_inst,
void *extern_obj, void (*extern_obj_cleanup)(void *))
{
LookupExtObj_UserData lookup_user_data = { 0 };
bool ok = false;
/* in a wrapper, extern_obj could be any value */
lookup_user_data.node.extern_obj = extern_obj;
lookup_user_data.node.module_inst = module_inst;
lookup_user_data.found = false;
os_mutex_lock(&externref_lock);
/* Lookup hashmap firstly */
bh_hash_map_traverse(externref_map, lookup_extobj_callback,
(void *)&lookup_user_data);
if (lookup_user_data.found) {
void *key = (void *)(uintptr_t)lookup_user_data.externref_idx;
ExternRefMapNode *node = bh_hash_map_find(externref_map, key);
node->cleanup = extern_obj_cleanup;
ok = true;
}
os_mutex_unlock(&externref_lock);
return ok;
}
bool
wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst, void *extern_obj,
uint32 *p_externref_idx)
@ -4803,6 +4949,7 @@ wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst, void *extern_obj,
memset(node, 0, sizeof(ExternRefMapNode));
node->extern_obj = extern_obj;
node->module_inst = module_inst;
node->cleanup = NULL;
externref_idx = externref_global_id;
@ -4853,8 +5000,7 @@ reclaim_extobj_callback(void *key, void *value, void *user_data)
if (node->module_inst == module_inst) {
if (!node->marked && !node->retained) {
bh_hash_map_remove(externref_map, key, NULL, NULL);
wasm_runtime_free(value);
delete_externref(key, node);
}
else {
node->marked = false;
@ -4969,8 +5115,7 @@ cleanup_extobj_callback(void *key, void *value, void *user_data)
(WASMModuleInstanceCommon *)user_data;
if (node->module_inst == module_inst) {
bh_hash_map_remove(externref_map, key, NULL, NULL);
wasm_runtime_free(value);
delete_externref(key, node);
}
}

View File

@ -2735,6 +2735,33 @@ aot_generate_tempfile_name(const char *prefix, const char *extension,
snprintf(buffer + name_len, len - name_len, ".%s", extension);
return buffer;
}
#else
errno_t
_mktemp_s(char *nameTemplate, size_t sizeInChars);
char *
aot_generate_tempfile_name(const char *prefix, const char *extension,
char *buffer, uint32 len)
{
int name_len;
name_len = snprintf(buffer, len, "%s-XXXXXX", prefix);
if (_mktemp_s(buffer, name_len + 1) != 0) {
return NULL;
}
/* Check if buffer length is enough */
/* name_len + '.' + extension + '\0' */
if (name_len + 1 + strlen(extension) + 1 > len) {
aot_set_last_error("temp file name too long.");
return NULL;
}
snprintf(buffer + name_len, len - name_len, ".%s", extension);
return buffer;
}
#endif /* end of !(defined(_WIN32) || defined(_WIN32_)) */
bool

View File

@ -93,7 +93,10 @@ check_utf8_str(const uint8 *str, uint32 len)
/* Internal function in object file */
typedef struct AOTObjectFunc {
char *func_name;
/* text offset of aot_func#n */
uint64 text_offset;
/* text offset of aot_func_internal#n */
uint64 text_offset_of_aot_func_internal;
} AOTObjectFunc;
/* Symbol table list node */
@ -637,13 +640,33 @@ get_relocation_size(AOTRelocation *relocation, bool is_32bin)
}
static uint32
get_relocations_size(AOTRelocation *relocations, uint32 relocation_count,
get_relocations_size(AOTObjectData *obj_data,
AOTRelocationGroup *relocation_group,
AOTRelocation *relocations, uint32 relocation_count,
bool is_32bin)
{
AOTRelocation *relocation = relocations;
uint32 size = 0, i;
for (i = 0; i < relocation_count; i++, relocation++) {
/* ignore the relocations to aot_func_internal#n in text section
for windows platform since they will be applied in
aot_emit_text_section */
if (!strcmp(relocation_group->section_name, ".text")
&& !strncmp(relocation->symbol_name, AOT_FUNC_INTERNAL_PREFIX,
strlen(AOT_FUNC_INTERNAL_PREFIX))
&& ((!strncmp(obj_data->comp_ctx->target_arch, "x86_64", 6)
/* Windows AOT_COFF64_BIN_TYPE */
&& obj_data->target_info.bin_type == 6
/* IMAGE_REL_AMD64_REL32 in windows x86_64 */
&& relocation->relocation_type == 4)
|| (!strncmp(obj_data->comp_ctx->target_arch, "i386", 4)
/* Windows AOT_COFF32_BIN_TYPE */
&& obj_data->target_info.bin_type == 4
/* IMAGE_REL_I386_REL32 in windows x86_32 */
&& relocation->relocation_type == 20))) {
continue;
}
size = align_uint(size, 4);
size += get_relocation_size(relocation, is_32bin);
}
@ -651,19 +674,22 @@ get_relocations_size(AOTRelocation *relocations, uint32 relocation_count,
}
static uint32
get_relocation_group_size(AOTRelocationGroup *relocation_group, bool is_32bin)
get_relocation_group_size(AOTObjectData *obj_data,
AOTRelocationGroup *relocation_group, bool is_32bin)
{
uint32 size = 0;
/* section name index + relocation count + relocations */
size += (uint32)sizeof(uint32);
size += (uint32)sizeof(uint32);
size += get_relocations_size(relocation_group->relocations,
size += get_relocations_size(obj_data, relocation_group,
relocation_group->relocations,
relocation_group->relocation_count, is_32bin);
return size;
}
static uint32
get_relocation_groups_size(AOTRelocationGroup *relocation_groups,
get_relocation_groups_size(AOTObjectData *obj_data,
AOTRelocationGroup *relocation_groups,
uint32 relocation_group_count, bool is_32bin)
{
AOTRelocationGroup *relocation_group = relocation_groups;
@ -671,7 +697,7 @@ get_relocation_groups_size(AOTRelocationGroup *relocation_groups,
for (i = 0; i < relocation_group_count; i++, relocation_group++) {
size = align_uint(size, 4);
size += get_relocation_group_size(relocation_group, is_32bin);
size += get_relocation_group_size(obj_data, relocation_group, is_32bin);
}
return size;
}
@ -864,7 +890,7 @@ get_relocation_section_size(AOTCompContext *comp_ctx, AOTObjectData *obj_data)
/* relocation group count + symbol_table + relocation groups */
return (uint32)sizeof(uint32) + symbol_table_size
+ get_relocation_groups_size(relocation_groups,
+ get_relocation_groups_size(obj_data, relocation_groups,
relocation_group_count,
is_32bit_binary(obj_data));
}
@ -1734,6 +1760,10 @@ aot_emit_text_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
uint32 section_size = get_text_section_size(obj_data);
uint32 offset = *p_offset;
uint8 placeholder = 0;
AOTRelocationGroup *relocation_group;
AOTRelocation *relocation;
uint32 i, j, relocation_count;
uint8 *text;
*p_offset = offset = align_uint(offset, 4);
@ -1747,6 +1777,8 @@ aot_emit_text_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
EMIT_BUF(&placeholder, 1);
}
text = buf + offset;
if (obj_data->text_size > 0) {
EMIT_BUF(obj_data->text, obj_data->text_size);
while (offset & 3)
@ -1768,6 +1800,67 @@ aot_emit_text_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
return false;
}
/* apply relocations to aot_func_internal#n in text section for
windows platform */
if ((!strncmp(obj_data->comp_ctx->target_arch, "x86_64", 6)
/* Windows AOT_COFF64_BIN_TYPE */
&& obj_data->target_info.bin_type == 6)
|| (!strncmp(obj_data->comp_ctx->target_arch, "i386", 4)
/* Windows AOT_COFF32_BIN_TYPE */
&& obj_data->target_info.bin_type == 4)) {
relocation_group = obj_data->relocation_groups;
for (i = 0; i < obj_data->relocation_group_count;
i++, relocation_group++) {
/* relocation in text section */
if (!strcmp(relocation_group->section_name, ".text")) {
relocation = relocation_group->relocations;
relocation_count = relocation_group->relocation_count;
for (j = 0; j < relocation_count; j++) {
/* relocation to aot_func_internal#n */
if (str_starts_with(relocation->symbol_name,
AOT_FUNC_INTERNAL_PREFIX)
&& ((obj_data->target_info.bin_type
== 6 /* AOT_COFF64_BIN_TYPE */
&& relocation->relocation_type
== 4 /* IMAGE_REL_AMD64_REL32 */)
|| (obj_data->target_info.bin_type
== 4 /* AOT_COFF32_BIN_TYPE */
&& relocation->relocation_type
== 20 /* IMAGE_REL_I386_REL32 */))) {
uint32 func_idx =
atoi(relocation->symbol_name
+ strlen(AOT_FUNC_INTERNAL_PREFIX));
uint64 text_offset, reloc_offset, reloc_addend;
bh_assert(func_idx < obj_data->func_count);
text_offset = obj_data->funcs[func_idx]
.text_offset_of_aot_func_internal;
reloc_offset = relocation->relocation_offset;
reloc_addend = relocation->relocation_addend;
/* S + A - P */
*(uint32 *)(text + reloc_offset) =
(uint32)(text_offset + reloc_addend - reloc_offset
- 4);
/* remove current relocation as it has been applied */
if (j < relocation_count - 1) {
uint32 move_size =
(uint32)(sizeof(AOTRelocation)
* (relocation_count - 1 - j));
bh_memmove_s(relocation, move_size, relocation + 1,
move_size);
}
relocation_group->relocation_count--;
}
else {
relocation++;
}
}
}
}
}
*p_offset = offset;
return true;
@ -2403,7 +2496,7 @@ aot_resolve_object_data_sections(AOTObjectData *obj_data)
&& !strcmp(name, "__llvm_prf_cnts")) {
snprintf(buf, sizeof(buf), "%s%u", name,
llvm_prf_cnts_idx++);
size = strlen(buf) + 1;
size = (uint32)(strlen(buf) + 1);
if (!(data_section->name = wasm_runtime_malloc(size))) {
aot_set_last_error(
"allocate memory for data section name failed.");
@ -2416,7 +2509,7 @@ aot_resolve_object_data_sections(AOTObjectData *obj_data)
&& !strcmp(name, "__llvm_prf_data")) {
snprintf(buf, sizeof(buf), "%s%u", name,
llvm_prf_data_idx++);
size = strlen(buf) + 1;
size = (uint32)(strlen(buf) + 1);
if (!(data_section->name = wasm_runtime_malloc(size))) {
aot_set_last_error(
"allocate memory for data section name failed.");
@ -2520,15 +2613,15 @@ read_stack_usage_file(const AOTCompContext *comp_ctx, const char *filename,
}
if (prefix == aot_func_prefix) {
if (sz < precheck_stack_size_min) {
precheck_stack_size_min = sz;
precheck_stack_size_min = (uint32)sz;
}
if (sz > precheck_stack_size_max) {
precheck_stack_size_max = sz;
precheck_stack_size_max = (uint32)sz;
}
precheck_found++;
continue;
}
sizes[func_idx] = sz;
sizes[func_idx] = (uint32)sz;
found++;
}
fclose(fp);
@ -2605,9 +2698,16 @@ aot_resolve_stack_sizes(AOTCompContext *comp_ctx, AOTObjectData *obj_data)
while (!LLVMObjectFileIsSymbolIteratorAtEnd(obj_data->binary, sym_itr)) {
if ((name = LLVMGetSymbolName(sym_itr))
&& !strcmp(name, aot_stack_sizes_alias_name)) {
&& (!strcmp(name, aot_stack_sizes_alias_name)
/* symbol of COFF32 starts with "_" */
|| (obj_data->target_info.bin_type == AOT_COFF32_BIN_TYPE
&& !strncmp(name, "_", 1)
&& !strcmp(name + 1, aot_stack_sizes_alias_name)))) {
uint64 sz = LLVMGetSymbolSize(sym_itr);
if (sz != sizeof(uint32) * obj_data->func_count) {
if (sz != sizeof(uint32) * obj_data->func_count
/* sz of COFF64/COFF32 is 0, ignore the check */
&& obj_data->target_info.bin_type != AOT_COFF64_BIN_TYPE
&& obj_data->target_info.bin_type != AOT_COFF32_BIN_TYPE) {
aot_set_last_error("stack_sizes had unexpected size.");
goto fail;
}
@ -2642,16 +2742,12 @@ aot_resolve_stack_sizes(AOTCompContext *comp_ctx, AOTObjectData *obj_data)
goto fail;
}
}
if (addr > UINT32_MAX) {
aot_set_last_error("too large stack_sizes offset.");
goto fail;
}
/*
* Record section/offset and construct a copy of stack_sizes.
* aot_emit_object_data_section_info will emit this copy.
*/
obj_data->stack_sizes_section_name = sec_name;
obj_data->stack_sizes_offset = addr;
obj_data->stack_sizes_offset = (uint32)addr;
obj_data->stack_sizes = wasm_runtime_malloc(
obj_data->func_count * sizeof(*obj_data->stack_sizes));
if (obj_data->stack_sizes == NULL) {
@ -2770,6 +2866,7 @@ aot_resolve_functions(AOTCompContext *comp_ctx, AOTObjectData *obj_data)
while (!LLVMObjectFileIsSymbolIteratorAtEnd(obj_data->binary, sym_itr)) {
if ((name = (char *)LLVMGetSymbolName(sym_itr))
&& str_starts_with(name, prefix)) {
/* symbol aot_func#n */
func_index = (uint32)atoi(name + strlen(prefix));
if (func_index < obj_data->func_count) {
LLVMSectionIteratorRef contain_section;
@ -2804,6 +2901,44 @@ aot_resolve_functions(AOTCompContext *comp_ctx, AOTObjectData *obj_data)
}
}
}
else if ((name = (char *)LLVMGetSymbolName(sym_itr))
&& str_starts_with(name, AOT_FUNC_INTERNAL_PREFIX)) {
/* symbol aot_func_internal#n */
func_index = (uint32)atoi(name + strlen(AOT_FUNC_INTERNAL_PREFIX));
if (func_index < obj_data->func_count) {
LLVMSectionIteratorRef contain_section;
char *contain_section_name;
func = obj_data->funcs + func_index;
if (!(contain_section = LLVMObjectFileCopySectionIterator(
obj_data->binary))) {
aot_set_last_error("llvm get section iterator failed.");
LLVMDisposeSymbolIterator(sym_itr);
return false;
}
LLVMMoveToContainingSection(contain_section, sym_itr);
contain_section_name =
(char *)LLVMGetSectionName(contain_section);
LLVMDisposeSectionIterator(contain_section);
if (!strcmp(contain_section_name, ".text.unlikely.")) {
func->text_offset_of_aot_func_internal =
align_uint(obj_data->text_size, 4)
+ LLVMGetSymbolAddress(sym_itr);
}
else if (!strcmp(contain_section_name, ".text.hot.")) {
func->text_offset_of_aot_func_internal =
align_uint(obj_data->text_size, 4)
+ align_uint(obj_data->text_unlikely_size, 4)
+ LLVMGetSymbolAddress(sym_itr);
}
else {
func->text_offset_of_aot_func_internal =
LLVMGetSymbolAddress(sym_itr);
}
}
}
LLVMMoveToNextSymbol(sym_itr);
}
LLVMDisposeSymbolIterator(sym_itr);
@ -2975,7 +3110,7 @@ aot_resolve_object_relocation_group(AOTObjectData *obj_data,
|| !strcmp(group->section_name, ".rel.text")) {
snprintf(buf, sizeof(buf), "%s%u", relocation->symbol_name,
prof_section_idx);
size = strlen(buf) + 1;
size = (uint32)(strlen(buf) + 1);
if (!(relocation->symbol_name = wasm_runtime_malloc(size))) {
aot_set_last_error(
"allocate memory for relocation symbol name failed.");
@ -2990,7 +3125,7 @@ aot_resolve_object_relocation_group(AOTObjectData *obj_data,
19)) {
snprintf(buf, sizeof(buf), "%s%u", relocation->symbol_name,
prof_section_idx);
size = strlen(buf) + 1;
size = (uint32)(strlen(buf) + 1);
if (!(relocation->symbol_name = wasm_runtime_malloc(size))) {
aot_set_last_error(
"allocate memory for relocation symbol name failed.");
@ -3156,7 +3291,7 @@ aot_resolve_object_relocation_groups(AOTObjectData *obj_data)
|| !strcmp(name, ".rel__llvm_prf_data"))) {
char buf[32];
snprintf(buf, sizeof(buf), "%s%u", name, llvm_prf_data_idx);
size = strlen(buf) + 1;
size = (uint32)(strlen(buf) + 1);
if (!(relocation_group->section_name =
wasm_runtime_malloc(size))) {
aot_set_last_error(

View File

@ -18,6 +18,17 @@
} \
} while (0)
static bool
is_win_platform(AOTCompContext *comp_ctx)
{
char *triple = LLVMGetTargetMachineTriple(comp_ctx->target_machine);
bh_assert(triple);
if (strstr(triple, "win32") || strstr(triple, "win"))
return true;
return false;
}
static bool
create_func_return_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
@ -458,7 +469,7 @@ check_app_addr_and_convert(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
}
/* Check whether exception was thrown when executing the function */
if (comp_ctx->enable_bound_check
if ((comp_ctx->enable_bound_check || is_win_platform(comp_ctx))
&& !check_call_return(comp_ctx, func_ctx, res)) {
return false;
}
@ -696,7 +707,7 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
goto fail;
/* Check whether there was exception thrown when executing
the function */
if (comp_ctx->enable_bound_check
if ((comp_ctx->enable_bound_check || is_win_platform(comp_ctx))
&& !check_call_return(comp_ctx, func_ctx, res))
goto fail;
}
@ -849,7 +860,8 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
/* Check whether there was exception thrown when executing
the function */
if (!tail_call && comp_ctx->enable_bound_check
if (!tail_call
&& (comp_ctx->enable_bound_check || is_win_platform(comp_ctx))
&& !check_exception_thrown(comp_ctx, func_ctx))
goto fail;
}
@ -1431,7 +1443,7 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
goto fail;
/* Check whether exception was thrown when executing the function */
if (comp_ctx->enable_bound_check
if ((comp_ctx->enable_bound_check || is_win_platform(comp_ctx))
&& !check_call_return(comp_ctx, func_ctx, res))
goto fail;
@ -1483,7 +1495,7 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
}
/* Check whether exception was thrown when executing the function */
if (comp_ctx->enable_bound_check
if ((comp_ctx->enable_bound_check || is_win_platform(comp_ctx))
&& !check_exception_thrown(comp_ctx, func_ctx))
goto fail;

View File

@ -146,6 +146,13 @@ aot_target_precheck_can_use_musttail(const AOTCompContext *comp_ctx)
*/
return false;
}
if (!strcmp(comp_ctx->target_arch, "mips")) {
/*
* cf.
* https://github.com/bytecodealliance/wasm-micro-runtime/issues/2412
*/
return false;
}
/*
* x86-64/i386: true
*
@ -237,9 +244,10 @@ get_inst_extra_offset(AOTCompContext *comp_ctx)
const AOTCompData *comp_data = comp_ctx->comp_data;
uint32 table_count = comp_data->import_table_count + comp_data->table_count;
uint64 offset = get_tbl_inst_offset(comp_ctx, NULL, table_count);
bh_assert(offset <= UINT_MAX);
offset = align_uint(offset, 8);
return offset;
uint32 offset_32 = (uint32)offset;
bh_assert(offset <= UINT32_MAX);
offset_32 = align_uint((uint32)offset_32, 8);
return offset_32;
}
/*
@ -309,8 +317,8 @@ aot_add_precheck_function(AOTCompContext *comp_ctx, LLVMModuleRef module,
goto fail;
}
unsigned int param_count = LLVMCountParams(precheck_func);
uint64 sz = param_count * sizeof(LLVMValueRef);
uint32 param_count = LLVMCountParams(precheck_func);
uint32 sz = param_count * (uint32)sizeof(LLVMValueRef);
params = wasm_runtime_malloc(sz);
if (params == NULL) {
goto fail;
@ -626,8 +634,8 @@ aot_add_llvm_func(AOTCompContext *comp_ctx, LLVMModuleRef module,
if (comp_ctx->is_indirect_mode) {
/* avoid LUT relocations ("switch-table") */
LLVMAttributeRef attr_no_jump_tables = LLVMCreateStringAttribute(
comp_ctx->context, "no-jump-tables", strlen("no-jump-tables"),
"true", strlen("true"));
comp_ctx->context, "no-jump-tables",
(uint32)strlen("no-jump-tables"), "true", (uint32)strlen("true"));
LLVMAddAttributeAtIndex(func, LLVMAttributeFunctionIndex,
attr_no_jump_tables);
}
@ -2081,7 +2089,7 @@ jit_stack_size_callback(void *user_data, const char *name, size_t namelen,
return;
}
/* ensure NUL termination */
bh_memcpy_s(buf, sizeof(buf), name, namelen);
bh_memcpy_s(buf, (uint32)sizeof(buf), name, (uint32)namelen);
buf[namelen] = 0;
ret = sscanf(buf, AOT_FUNC_INTERNAL_PREFIX "%" SCNu32, &func_idx);
@ -2102,7 +2110,7 @@ jit_stack_size_callback(void *user_data, const char *name, size_t namelen,
/* Note: -1 == AOT_NEG_ONE from aot_create_stack_sizes */
bh_assert(comp_ctx->jit_stack_sizes[func_idx] == (uint32)-1);
comp_ctx->jit_stack_sizes[func_idx] = stack_size + call_size;
comp_ctx->jit_stack_sizes[func_idx] = (uint32)stack_size + call_size;
}
static bool
@ -2744,6 +2752,16 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
aot_set_last_error("create LLVM target machine failed.");
goto fail;
}
/* If only to create target machine for querying information, early stop
*/
if ((arch && !strcmp(arch, "help")) || (abi && !strcmp(abi, "help"))
|| (cpu && !strcmp(cpu, "help"))
|| (features && !strcmp(features, "+help"))) {
LOG_DEBUG(
"create LLVM target machine only for printing help info.");
goto fail;
}
}
triple = LLVMGetTargetMachineTriple(comp_ctx->target_machine);

View File

@ -186,6 +186,7 @@ enum wasm_valkind_enum {
#ifndef WASM_VAL_T_DEFINED
#define WASM_VAL_T_DEFINED
struct wasm_ref_t;
typedef struct wasm_val_t {
wasm_valkind_t kind;
@ -197,6 +198,7 @@ typedef struct wasm_val_t {
double f64;
/* represent a foreign object, aka externref in .wat */
uintptr_t foreign;
struct wasm_ref_t *ref;
} of;
} wasm_val_t;
#endif
@ -1290,6 +1292,32 @@ WASM_RUNTIME_API_EXTERN bool
wasm_externref_obj2ref(wasm_module_inst_t module_inst,
void *extern_obj, uint32_t *p_externref_idx);
/**
* Delete external object registered by `wasm_externref_obj2ref`.
*
* @param module_inst the WASM module instance that the extern object
* belongs to
* @param extern_obj the external object to be deleted
*
* @return true if success, false otherwise
*/
WASM_RUNTIME_API_EXTERN bool
wasm_externref_objdel(wasm_module_inst_t module_inst, void *extern_obj);
/**
* Set cleanup callback to release external object.
*
* @param module_inst the WASM module instance that the extern object
* belongs to
* @param extern_obj the external object to which to set the `extern_obj_cleanup` cleanup callback.
* @param extern_obj_cleanup a callback to release `extern_obj`
*
* @return true if success, false otherwise
*/
WASM_RUNTIME_API_EXTERN bool
wasm_externref_set_cleanup(wasm_module_inst_t module_inst, void *extern_obj,
void (*extern_obj_cleanup)(void *));
/**
* Retrieve the external object from an internal externref index
*

View File

@ -905,8 +905,9 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
if (!func_import->call_conv_wasm_c_api) {
native_func_pointer = module_inst->import_func_ptrs[cur_func_index];
}
else if (module_inst->e->c_api_func_imports) {
c_api_func_import = module_inst->e->c_api_func_imports + cur_func_index;
else if (module_inst->e->common.c_api_func_imports) {
c_api_func_import =
module_inst->e->common.c_api_func_imports + cur_func_index;
native_func_pointer = c_api_func_import->func_ptr_linked;
}

View File

@ -938,8 +938,9 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
if (!func_import->call_conv_wasm_c_api) {
native_func_pointer = module_inst->import_func_ptrs[cur_func_index];
}
else if (module_inst->e->c_api_func_imports) {
c_api_func_import = module_inst->e->c_api_func_imports + cur_func_index;
else if (module_inst->e->common.c_api_func_imports) {
c_api_func_import =
module_inst->e->common.c_api_func_imports + cur_func_index;
native_func_pointer = c_api_func_import->func_ptr_linked;
}

View File

@ -8064,6 +8064,9 @@ re_scan:
case WASM_OP_SELECT_T:
{
uint8 vec_len, ref_type;
#if WASM_ENABLE_FAST_INTERP != 0
uint8 *p_code_compiled_tmp = loader_ctx->p_code_compiled;
#endif
read_leb_uint32(p, p_end, vec_len);
if (vec_len != 1) {
@ -8086,8 +8089,6 @@ re_scan:
#if WASM_ENABLE_FAST_INTERP != 0
if (loader_ctx->p_code_compiled) {
uint8 opcode_tmp = WASM_OP_SELECT;
uint8 *p_code_compiled_tmp =
loader_ctx->p_code_compiled - 2;
if (ref_type == VALUE_TYPE_V128) {
#if (WASM_ENABLE_SIMD == 0) \

View File

@ -6233,6 +6233,9 @@ re_scan:
case WASM_OP_SELECT_T:
{
uint8 vec_len, ref_type;
#if WASM_ENABLE_FAST_INTERP != 0
uint8 *p_code_compiled_tmp = loader_ctx->p_code_compiled;
#endif
read_leb_uint32(p, p_end, vec_len);
if (vec_len != 1) {
@ -6255,8 +6258,6 @@ re_scan:
#if WASM_ENABLE_FAST_INTERP != 0
if (loader_ctx->p_code_compiled) {
uint8 opcode_tmp = WASM_OP_SELECT;
uint8 *p_code_compiled_tmp =
loader_ctx->p_code_compiled - 2;
if (ref_type == VALUE_TYPE_F64
|| ref_type == VALUE_TYPE_I64)

View File

@ -202,7 +202,7 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
if (num_bytes_per_page < heap_size) {
set_error_buf(error_buf, error_buf_size,
"failed to insert app heap into linear memory, "
"try using `--heap_size=0` option");
"try using `--heap-size=0` option");
return NULL;
}
}
@ -261,7 +261,7 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
if (init_page_count > DEFAULT_MAX_PAGES) {
set_error_buf(error_buf, error_buf_size,
"failed to insert app heap into linear memory, "
"try using `--heap_size=0` option");
"try using `--heap-size=0` option");
return NULL;
}
else if (init_page_count == DEFAULT_MAX_PAGES) {
@ -1840,7 +1840,7 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
for (i = 0; i < module->data_seg_count; i++) {
WASMMemoryInstance *memory = NULL;
uint8 *memory_data = NULL;
uint32 memory_size = 0;
uint64 memory_size = 0;
WASMDataSeg *data_seg = module->data_segments[i];
#if WASM_ENABLE_BULK_MEMORY != 0
@ -1853,7 +1853,8 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
bh_assert(memory);
memory_data = memory->memory_data;
memory_size = memory->num_bytes_per_page * memory->cur_page_count;
memory_size =
(uint64)memory->num_bytes_per_page * memory->cur_page_count;
bh_assert(memory_data || memory_size == 0);
bh_assert(data_seg->base_offset.init_expr_type
@ -1899,7 +1900,7 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
/* check offset + length(could be zero) */
length = data_seg->data_length;
if (base_offset + length > memory_size) {
if ((uint64)base_offset + length > memory_size) {
LOG_DEBUG("base_offset(%d) + length(%d) > memory_size(%d)",
base_offset, length, memory_size);
#if WASM_ENABLE_REF_TYPES != 0
@ -1913,8 +1914,9 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
}
if (memory_data) {
bh_memcpy_s(memory_data + base_offset, memory_size - base_offset,
data_seg->data, length);
bh_memcpy_s(memory_data + base_offset,
(uint32)memory_size - base_offset, data_seg->data,
length);
}
}
@ -2228,8 +2230,8 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
}
#endif
if (module_inst->e->c_api_func_imports)
wasm_runtime_free(module_inst->e->c_api_func_imports);
if (module_inst->e->common.c_api_func_imports)
wasm_runtime_free(module_inst->e->common.c_api_func_imports);
if (!is_sub_inst) {
#if WASM_ENABLE_LIBC_WASI != 0
@ -3094,11 +3096,7 @@ llvm_jit_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx,
{
bool ret;
#if WASM_ENABLE_JIT != 0
if (Wasm_Module_AoT == exec_env->module_inst->module_type) {
return aot_call_indirect(exec_env, tbl_idx, elem_idx, argc, argv);
}
#endif
bh_assert(exec_env->module_inst->module_type == Wasm_Module_Bytecode);
ret = call_indirect(exec_env, tbl_idx, elem_idx, argc, argv, false, 0);
#ifdef OS_ENABLE_HW_BOUND_CHECK
@ -3125,11 +3123,7 @@ llvm_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
char buf[96];
bool ret = false;
#if WASM_ENABLE_JIT != 0
if (Wasm_Module_AoT == exec_env->module_inst->module_type) {
return aot_invoke_native(exec_env, func_idx, argc, argv);
}
#endif
bh_assert(exec_env->module_inst->module_type == Wasm_Module_Bytecode);
module_inst = (WASMModuleInstance *)wasm_runtime_get_module_inst(exec_env);
module = module_inst->module;
@ -3142,8 +3136,9 @@ llvm_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
import_func = &module->import_functions[func_idx].u.function;
if (import_func->call_conv_wasm_c_api) {
if (module_inst->e->c_api_func_imports) {
c_api_func_import = module_inst->e->c_api_func_imports + func_idx;
if (module_inst->e->common.c_api_func_imports) {
c_api_func_import =
module_inst->e->common.c_api_func_imports + func_idx;
func_ptr = c_api_func_import->func_ptr_linked;
}
else {
@ -3198,11 +3193,7 @@ llvm_jit_memory_init(WASMModuleInstance *module_inst, uint32 seg_index,
uint8 *maddr;
uint64 seg_len = 0;
#if WASM_ENABLE_JIT != 0
if (Wasm_Module_AoT == module_inst->module_type) {
return aot_memory_init(module_inst, seg_index, offset, len, dst);
}
#endif
bh_assert(module_inst->module_type == Wasm_Module_Bytecode);
memory_inst = wasm_get_default_memory(module_inst);
module = module_inst->module;
@ -3228,11 +3219,7 @@ llvm_jit_memory_init(WASMModuleInstance *module_inst, uint32 seg_index,
bool
llvm_jit_data_drop(WASMModuleInstance *module_inst, uint32 seg_index)
{
#if WASM_ENABLE_JIT != 0
if (Wasm_Module_AoT == module_inst->module_type) {
return aot_data_drop(module_inst, seg_index);
}
#endif
bh_assert(module_inst->module_type == Wasm_Module_Bytecode);
module_inst->module->data_segments[seg_index]->data_length = 0;
/* Currently we can't free the dropped data segment
@ -3247,11 +3234,7 @@ llvm_jit_drop_table_seg(WASMModuleInstance *module_inst, uint32 tbl_seg_idx)
{
WASMTableSeg *tbl_segs;
#if WASM_ENABLE_JIT != 0
if (Wasm_Module_AoT == module_inst->module_type) {
return aot_drop_table_seg(module_inst, tbl_seg_idx);
}
#endif
bh_assert(module_inst->module_type == Wasm_Module_Bytecode);
tbl_segs = module_inst->module->table_segments;
tbl_segs[tbl_seg_idx].is_dropped = true;
@ -3265,12 +3248,7 @@ llvm_jit_table_init(WASMModuleInstance *module_inst, uint32 tbl_idx,
WASMTableInstance *tbl_inst;
WASMTableSeg *tbl_seg;
#if WASM_ENABLE_JIT != 0
if (Wasm_Module_AoT == module_inst->module_type) {
return aot_table_init(module_inst, tbl_idx, tbl_seg_idx, length,
src_offset, dst_offset);
}
#endif
bh_assert(module_inst->module_type == Wasm_Module_Bytecode);
tbl_inst = wasm_get_table_inst(module_inst, tbl_idx);
tbl_seg = module_inst->module->table_segments + tbl_seg_idx;
@ -3313,13 +3291,7 @@ llvm_jit_table_copy(WASMModuleInstance *module_inst, uint32 src_tbl_idx,
WASMTableInstance *src_tbl_inst;
WASMTableInstance *dst_tbl_inst;
#if WASM_ENABLE_JIT != 0
if (Wasm_Module_AoT == module_inst->module_type) {
aot_table_copy(module_inst, src_tbl_idx, dst_tbl_idx, length,
src_offset, dst_offset);
return;
}
#endif
bh_assert(module_inst->module_type == Wasm_Module_Bytecode);
src_tbl_inst = wasm_get_table_inst(module_inst, src_tbl_idx);
dst_tbl_inst = wasm_get_table_inst(module_inst, dst_tbl_idx);
@ -3350,12 +3322,7 @@ llvm_jit_table_fill(WASMModuleInstance *module_inst, uint32 tbl_idx,
{
WASMTableInstance *tbl_inst;
#if WASM_ENABLE_JIT != 0
if (Wasm_Module_AoT == module_inst->module_type) {
aot_table_fill(module_inst, tbl_idx, length, val, data_offset);
return;
}
#endif
bh_assert(module_inst->module_type == Wasm_Module_Bytecode);
tbl_inst = wasm_get_table_inst(module_inst, tbl_idx);
bh_assert(tbl_inst);
@ -3377,11 +3344,7 @@ llvm_jit_table_grow(WASMModuleInstance *module_inst, uint32 tbl_idx,
WASMTableInstance *tbl_inst;
uint32 i, orig_size, total_size;
#if WASM_ENABLE_JIT != 0
if (Wasm_Module_AoT == module_inst->module_type) {
return aot_table_grow(module_inst, tbl_idx, inc_size, init_val);
}
#endif
bh_assert(module_inst->module_type == Wasm_Module_Bytecode);
tbl_inst = wasm_get_table_inst(module_inst, tbl_idx);
if (!tbl_inst) {
@ -3421,11 +3384,7 @@ llvm_jit_alloc_frame(WASMExecEnv *exec_env, uint32 func_index)
WASMInterpFrame *frame;
uint32 size;
#if WASM_ENABLE_JIT != 0
if (Wasm_Module_AoT == exec_env->module_inst->module_type) {
return aot_alloc_frame(exec_env, func_index);
}
#endif
bh_assert(exec_env->module_inst->module_type == Wasm_Module_Bytecode);
module_inst = (WASMModuleInstance *)exec_env->module_inst;
size = wasm_interp_interp_frame_size(0);
@ -3454,12 +3413,7 @@ llvm_jit_free_frame(WASMExecEnv *exec_env)
WASMInterpFrame *frame;
WASMInterpFrame *prev_frame;
#if WASM_ENABLE_JIT != 0
if (Wasm_Module_AoT == exec_env->module_inst->module_type) {
aot_free_frame(exec_env);
return;
}
#endif
bh_assert(exec_env->module_inst->module_type == Wasm_Module_Bytecode);
frame = wasm_exec_env_get_cur_frame(exec_env);
prev_frame = frame->prev_frame;

View File

@ -210,8 +210,19 @@ typedef struct CApiFuncImport {
void *env_arg;
} CApiFuncImport;
/* The common part of WASMModuleInstanceExtra and AOTModuleInstanceExtra */
typedef struct WASMModuleInstanceExtraCommon {
CApiFuncImport *c_api_func_imports;
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
/* Disable bounds checks or not */
bool disable_bounds_checks;
#endif
} WASMModuleInstanceExtraCommon;
/* Extra info of WASM module instance for interpreter/jit mode */
typedef struct WASMModuleInstanceExtra {
WASMModuleInstanceExtraCommon common;
WASMGlobalInstance *globals;
WASMFunctionInstance *functions;
@ -223,7 +234,6 @@ typedef struct WASMModuleInstanceExtra {
WASMFunctionInstance *free_function;
WASMFunctionInstance *retain_function;
CApiFuncImport *c_api_func_imports;
RunningMode running_mode;
#if WASM_ENABLE_MULTI_MODULE != 0
@ -242,10 +252,6 @@ typedef struct WASMModuleInstanceExtra {
&& WASM_ENABLE_LAZY_JIT != 0)
WASMModuleInstance *next;
#endif
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
/* Disable bounds checks or not */
bool disable_bounds_checks;
#endif
} WASMModuleInstanceExtra;
struct AOTFuncPerfProfInfo;

View File

@ -23,6 +23,7 @@ include(FetchContent)
set(RATS_BUILD_MODE "sgx"
CACHE INTERNAL "Select build mode for librats(host|occlum|sgxwasm)")
set(RATS_INSTALL_PATH "${CMAKE_BINARY_DIR}/librats" CACHE INTERNAL "")
set(BUILD_SAMPLES OFF)
FetchContent_Declare(
librats
@ -34,8 +35,17 @@ if (NOT librats_POPULATED)
message("-- Fetching librats ..")
FetchContent_Populate(librats)
include_directories("${librats_SOURCE_DIR}/include")
# Prevent the propagation of the CMAKE_C_FLAGS of WAMR into librats
set(SAVED_CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
set(CMAKE_C_FLAGS "")
# Import the building scripts of librats
add_subdirectory(${librats_SOURCE_DIR} ${librats_BINARY_DIR} EXCLUDE_FROM_ALL)
# Restore the CMAKE_C_FLAGS of WAMR
set(CMAKE_C_FLAGS ${SAVED_CMAKE_C_FLAGS})
endif()
file (GLOB source_all ${LIB_RATS_DIR}/*.c)

View File

@ -9,8 +9,32 @@ set -eo pipefail
CC=${CC:=/opt/wasi-sdk/bin/clang}
WAMR_DIR=../../../../..
show_usage() {
echo "Usage: $0 [--sysroot PATH_TO_SYSROOT]"
echo "--sysroot PATH_TO_SYSROOT specify to build with custom sysroot for wasi-libc"
}
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
--sysroot)
sysroot_path="$2"
shift
shift
;;
--help)
show_usage
exit
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
# Stress tests names
thread_start_file_exclusions=("spawn_stress_test.wasm" "linear_memory_size_update.wasm")
thread_start_file_exclusions=("spawn_stress_test.wasm" "linear_memory_size_update.wasm" "stress_test_threads_creation.wasm")
for test_c in *.c; do
test_wasm="$(basename $test_c .c).wasm"
@ -21,9 +45,18 @@ for test_c in *.c; do
thread_start_file=$WAMR_DIR/samples/wasi-threads/wasm-apps/wasi_thread_start.S
fi
if [[ -n "$sysroot_path" ]]; then
if [ ! -d "$sysroot_path" ]; then
echo "Directory $sysroot_path doesn't exist. Aborting"
exit 1
fi
sysroot_command="--sysroot $sysroot_path"
fi
echo "Compiling $test_c to $test_wasm"
$CC \
-target wasm32-wasi-threads \
-O2 \
-pthread -ftls-model=local-exec \
-z stack-size=32768 \
-Wl,--export=__heap_base \
@ -33,6 +66,7 @@ for test_c in *.c; do
-Wl,--export=malloc \
-Wl,--export=free \
-I $WAMR_DIR/samples/wasi-threads/wasm-apps \
$sysroot_command \
$thread_start_file \
$test_c -o $test_wasm
done

View File

@ -1,5 +1,6 @@
{
"lib-wasi-threads tests": {
"spawn_stress_test": "Stress tests are incompatible with the other part and executed differently"
"spawn_stress_test": "Stress tests are incompatible with the other part and executed differently",
"stress_test_threads_creation": "Stress tests are incompatible with the other part and executed differently"
}
}

View File

@ -18,8 +18,9 @@
enum CONSTANTS {
NUM_ITER = 100000,
NUM_RETRY = 5,
NUM_RETRY = 8,
MAX_NUM_THREADS = 8,
RETRY_SLEEP_TIME_US = 2000,
};
unsigned prime_numbers_count = 0;
@ -62,11 +63,13 @@ void
spawn_thread(pthread_t *thread, unsigned int *arg)
{
int status_code = -1;
int timeout_us = RETRY_SLEEP_TIME_US;
for (int tries = 0; status_code != 0 && tries < NUM_RETRY; ++tries) {
status_code = pthread_create(thread, NULL, &check_if_prime, arg);
assert(status_code == 0 || status_code == EAGAIN);
if (status_code == EAGAIN) {
usleep(2000);
usleep(timeout_us);
timeout_us *= 2;
}
}
@ -95,7 +98,7 @@ main(int argc, char **argv)
args[thread_num] = factorised_number;
usleep(2000);
usleep(RETRY_SLEEP_TIME_US);
spawn_thread(&threads[thread_num], &args[thread_num]);
assert(threads[thread_num] != 0);
}

View File

@ -0,0 +1,93 @@
/*
* Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
enum CONSTANTS {
NUM_ITER = 200000,
NUM_RETRY = 8,
MAX_NUM_THREADS = 8,
RETRY_SLEEP_TIME_US = 4000,
SECOND = 1000 * 1000 * 1000
};
int threads_executed = 0;
unsigned int threads_creation_tried = 0;
unsigned int threads_in_use = 0;
void *
thread_func(void *arg)
{
(void)(arg);
__atomic_fetch_add(&threads_executed, 1, __ATOMIC_RELAXED);
__atomic_fetch_sub(&threads_in_use, 1, __ATOMIC_SEQ_CST);
return NULL;
}
void
spawn_thread(pthread_t *thread)
{
int status_code = -1;
int timeout_us = RETRY_SLEEP_TIME_US;
for (int tries = 0; status_code != 0 && tries < NUM_RETRY; ++tries) {
status_code = pthread_create(thread, NULL, &thread_func, NULL);
__atomic_fetch_add(&threads_creation_tried, 1, __ATOMIC_RELAXED);
assert(status_code == 0 || status_code == EAGAIN);
if (status_code == EAGAIN) {
usleep(timeout_us);
timeout_us *= 2;
}
}
assert(status_code == 0 && "Thread creation should succeed");
}
int
main(int argc, char **argv)
{
double percentage = 0.1;
for (int iter = 0; iter < NUM_ITER; ++iter) {
if (iter > NUM_ITER * percentage) {
fprintf(stderr, "Spawning stress test is %d%% finished\n",
(unsigned int)(percentage * 100));
percentage += 0.1;
}
while (__atomic_load_n(&threads_in_use, __ATOMIC_SEQ_CST)
== MAX_NUM_THREADS) {
usleep(100);
}
__atomic_fetch_add(&threads_in_use, 1, __ATOMIC_SEQ_CST);
pthread_t tmp;
spawn_thread(&tmp);
pthread_detach(tmp);
}
while ((__atomic_load_n(&threads_in_use, __ATOMIC_SEQ_CST) != 0)) {
__builtin_wasm_memory_atomic_wait32(&threads_in_use, 0, SECOND);
}
assert(__atomic_load_n(&threads_in_use, __ATOMIC_SEQ_CST) == 0);
// Validation
assert(threads_creation_tried >= threads_executed
&& "Test executed more threads than were created");
assert((1. * threads_creation_tried) / threads_executed < 2.5
&& "Ensuring that we're retrying thread creation less than 2.5 "
"times on average ");
fprintf(stderr,
"Spawning stress test finished successfully executed %d threads "
"with retry ratio %f\n",
threads_creation_tried,
(1. * threads_creation_tried) / threads_executed);
return 0;
}

View File

@ -21,7 +21,8 @@ tid_allocator_init(TidAllocator *tid_allocator)
return false;
for (int64 i = tid_allocator->pos - 1; i >= 0; i--)
tid_allocator->ids[i] = TID_MIN + (tid_allocator->pos - 1 - i);
tid_allocator->ids[i] =
(uint32)(TID_MIN + (tid_allocator->pos - 1 - i));
return true;
}
@ -54,7 +55,8 @@ tid_allocator_get_tid(TidAllocator *tid_allocator)
LOG_ERROR("Overflow detected during realloc");
return -1;
}
int32 *tmp = wasm_runtime_realloc(tid_allocator->ids, realloc_size);
int32 *tmp =
wasm_runtime_realloc(tid_allocator->ids, (uint32)realloc_size);
if (tmp == NULL) {
LOG_ERROR("Thread ID allocator realloc failed");
return -1;
@ -64,7 +66,8 @@ tid_allocator_get_tid(TidAllocator *tid_allocator)
tid_allocator->pos = new_size - old_size;
tid_allocator->ids = tmp;
for (int64 i = tid_allocator->pos - 1; i >= 0; i--)
tid_allocator->ids[i] = TID_MIN + (tid_allocator->size - 1 - i);
tid_allocator->ids[i] =
(uint32)(TID_MIN + (tid_allocator->size - 1 - i));
}
// Pop available thread identifier from the stack
@ -77,4 +80,4 @@ tid_allocator_release_tid(TidAllocator *tid_allocator, int32 thread_id)
// Release thread identifier by pushing it into the stack
bh_assert(tid_allocator->pos < tid_allocator->size);
tid_allocator->ids[tid_allocator->pos++] = thread_id;
}
}

View File

@ -746,10 +746,10 @@ wasm_cluster_dup_c_api_imports(WASMModuleInstanceCommon *module_inst_dst,
#if WASM_ENABLE_INTERP != 0
if (module_inst_src->module_type == Wasm_Module_Bytecode) {
new_c_api_func_imports =
&(((WASMModuleInstance *)module_inst_dst)->e->c_api_func_imports);
new_c_api_func_imports = &(((WASMModuleInstance *)module_inst_dst)
->e->common.c_api_func_imports);
c_api_func_imports = ((const WASMModuleInstance *)module_inst_src)
->e->c_api_func_imports;
->e->common.c_api_func_imports;
import_func_count =
((WASMModule *)(((const WASMModuleInstance *)module_inst_src)
->module))
@ -760,10 +760,10 @@ wasm_cluster_dup_c_api_imports(WASMModuleInstanceCommon *module_inst_dst,
if (module_inst_src->module_type == Wasm_Module_AoT) {
AOTModuleInstanceExtra *e =
(AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst_dst)->e;
new_c_api_func_imports = &(e->c_api_func_imports);
new_c_api_func_imports = &(e->common.c_api_func_imports);
e = (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst_src)->e;
c_api_func_imports = e->c_api_func_imports;
c_api_func_imports = e->common.c_api_func_imports;
import_func_count =
((AOTModule *)(((AOTModuleInstance *)module_inst_src)->module))

View File

@ -0,0 +1,2 @@
**/*.wasm
**/*.tflite

View File

@ -25,6 +25,7 @@ Build the runtime image for your execution target type.
* `cpu`
* `nvidia-gpu`
* `vx-delegate`
* `tpu`
```
EXECUTION_TYPE=cpu
@ -64,6 +65,8 @@ docker run \
```
* (NVIDIA) GPU
* Requirements:
* [NVIDIA docker](https://github.com/NVIDIA/nvidia-docker).
```
docker run \
@ -76,25 +79,36 @@ docker run \
/assets/test_tensorflow.wasm
```
* vx-delegate for NPU (x86 simulater)
* vx-delegate for NPU (x86 simulator)
```
docker run \
-v $PWD/core/iwasm/libraries/wasi-nn/test:/assets wasi-nn-vx-delegate \
--dir=/assets \
-v $PWD/core/iwasm/libraries/wasi-nn/test:/assets \
wasi-nn-vx-delegate \
--dir=/ \
--env="TARGET=gpu" \
/assets/test_tensorflow.wasm
/assets/test_tensorflow_quantized.wasm
```
* (Coral) TPU
* Requirements:
* [Coral USB](https://coral.ai/products/accelerator/).
Requirements:
* [NVIDIA docker](https://github.com/NVIDIA/nvidia-docker).
```
docker run \
--privileged \
--device=/dev/bus/usb:/dev/bus/usb \
-v $PWD/core/iwasm/libraries/wasi-nn/test:/assets \
wasi-nn-tpu \
--dir=/ \
--env="TARGET=tpu" \
/assets/test_tensorflow_quantized.wasm
```
## What is missing
Supported:
* Graph encoding: `tensorflowlite`.
* Execution target: `cpu` and `gpu`.
* Execution target: `cpu`, `gpu` and `tpu`.
* Tensor type: `fp32`.

View File

@ -18,12 +18,16 @@ if(NOT EXISTS ${TENSORFLOW_LITE})
set(TENSORFLOW_SOURCE_DIR "${WAMR_ROOT_DIR}/core/deps/tensorflow-src")
if(WASI_NN_ENABLE_GPU EQUAL 1)
if(WAMR_BUILD_WASI_NN_ENABLE_GPU EQUAL 1)
# Tensorflow specific:
# * https://www.tensorflow.org/lite/guide/build_cmake#available_options_to_build_tensorflow_lite
set (TFLITE_ENABLE_GPU ON)
endif()
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
set (TFLITE_ENABLE_XNNPACK OFF)
endif()
add_subdirectory(
"${TENSORFLOW_SOURCE_DIR}/tensorflow/lite"
"${CMAKE_CURRENT_BINARY_DIR}/tensorflow-lite"

View File

@ -16,11 +16,11 @@
#include <tensorflow/lite/optional_debug_tools.h>
#include <tensorflow/lite/error_reporter.h>
#if defined(WASI_NN_ENABLE_GPU)
#if WASM_ENABLE_WASI_NN_GPU != 0
#include <tensorflow/lite/delegates/gpu/delegate.h>
#endif
#if defined(WASI_NN_ENABLE_EXTERNAL_DELEGATE)
#if WASM_ENABLE_WASI_NN_EXTERNAL_DELEGATE != 0
#include <tensorflow/lite/delegates/external/external_delegate.h>
#endif
@ -130,8 +130,8 @@ tensorflowlite_load(void *tflite_ctx, graph_builder_array *builder,
return invalid_argument;
}
if (target != cpu && target != gpu) {
NN_ERR_PRINTF("Only CPU and GPU target is supported.");
if (target != cpu && target != gpu && target != tpu) {
NN_ERR_PRINTF("Only CPU, GPU and TPU target is supported.");
return invalid_argument;
}
@ -195,7 +195,7 @@ tensorflowlite_init_execution_context(void *tflite_ctx, graph g,
switch (tfl_ctx->models[g].target) {
case gpu:
{
#if defined(WASI_NN_ENABLE_GPU)
#if WASM_ENABLE_WASI_NN_GPU != 0
NN_WARN_PRINTF("GPU enabled.");
// https://www.tensorflow.org/lite/performance/gpu
TfLiteGpuDelegateOptionsV2 options =
@ -216,10 +216,19 @@ tensorflowlite_init_execution_context(void *tflite_ctx, graph g,
NN_ERR_PRINTF("Error when enabling GPU delegate.");
use_default = true;
}
#elif defined(WASI_NN_ENABLE_EXTERNAL_DELEGATE)
#else
NN_WARN_PRINTF("GPU not enabled.");
use_default = true;
#endif
break;
}
case tpu:
{
#if WASM_ENABLE_WASI_NN_EXTERNAL_DELEGATE != 0
NN_WARN_PRINTF("external delegation enabled.");
TfLiteExternalDelegateOptions options =
TfLiteExternalDelegateOptionsDefault(WASI_NN_EXT_DELEGATE_PATH);
TfLiteExternalDelegateOptionsDefault(
WASM_WASI_NN_EXTERNAL_DELEGATE_PATH);
tfl_ctx->delegate = TfLiteExternalDelegateCreate(&options);
if (tfl_ctx->delegate == NULL) {
NN_ERR_PRINTF("Error when generating External delegate.");
@ -233,7 +242,7 @@ tensorflowlite_init_execution_context(void *tflite_ctx, graph g,
use_default = true;
}
#else
NN_WARN_PRINTF("GPU not enabled.");
NN_WARN_PRINTF("External delegate not enabled.");
use_default = true;
#endif
break;
@ -285,14 +294,37 @@ tensorflowlite_set_input(void *tflite_ctx, graph_execution_context ctx,
return invalid_argument;
}
auto *input =
tfl_ctx->interpreters[ctx].interpreter->typed_input_tensor<float>(
index);
if (input == NULL)
return missing_memory;
if (tensor->quantization.type == kTfLiteNoQuantization) {
NN_DBG_PRINTF("No quantization information. Using float as default");
float *it =
tfl_ctx->interpreters[ctx].interpreter->typed_input_tensor<float>(
index);
int size = model_tensor_size * sizeof(float);
bh_memcpy_s(it, size, input_tensor->data, size);
}
else { // TODO: Assumming uint8 quantized networks.
TfLiteAffineQuantization *quant_info =
(TfLiteAffineQuantization *)tensor->quantization.params;
if (quant_info->scale->size != 1 || quant_info->zero_point->size != 1) {
NN_ERR_PRINTF("Quantization per channel is not supported");
return runtime_error;
}
uint8_t *it =
tfl_ctx->interpreters[ctx].interpreter->typed_input_tensor<uint8_t>(
index);
float scale = quant_info->scale->data[0];
float zero_point = (float)quant_info->zero_point->data[0];
NN_DBG_PRINTF("input tensor: (scale, offset) = (%f, %f)", scale,
zero_point);
float *input_tensor_f = (float *)input_tensor->data;
for (uint32_t i = 0; i < model_tensor_size; ++i) {
it[i] = (uint8_t)(input_tensor_f[i] / scale + zero_point);
}
}
bh_memcpy_s(input, model_tensor_size * sizeof(float), input_tensor->data,
model_tensor_size * sizeof(float));
return success;
}
@ -325,6 +357,7 @@ tensorflowlite_get_output(void *tflite_ctx, graph_execution_context ctx,
NN_DBG_PRINTF("Number of tensors (%d)", num_output_tensors);
if (index + 1 > num_output_tensors) {
NN_ERR_PRINTF("Index %d is invalid.", index);
return runtime_error;
}
@ -343,15 +376,37 @@ tensorflowlite_get_output(void *tflite_ctx, graph_execution_context ctx,
return missing_memory;
}
float *tensor_f =
tfl_ctx->interpreters[ctx].interpreter->typed_output_tensor<float>(
index);
for (uint32_t i = 0; i < model_tensor_size; ++i)
NN_DBG_PRINTF("output: %f", tensor_f[i]);
if (tensor->quantization.type == kTfLiteNoQuantization) {
NN_DBG_PRINTF("No quantization information");
float *ot =
tfl_ctx->interpreters[ctx].interpreter->typed_output_tensor<float>(
index);
int size = model_tensor_size * sizeof(float);
bh_memcpy_s(output_tensor, size, ot, size);
}
else { // TODO: Assumming uint8 quantized networks.
TfLiteAffineQuantization *quant_info =
(TfLiteAffineQuantization *)tensor->quantization.params;
if (quant_info->scale->size != 1 || quant_info->zero_point->size != 1) {
NN_ERR_PRINTF("Quantization per channel is not supported");
return runtime_error;
}
uint8_t *ot = tfl_ctx->interpreters[ctx]
.interpreter->typed_output_tensor<uint8_t>(index);
float scale = quant_info->scale->data[0];
float zero_point = (float)quant_info->zero_point->data[0];
NN_DBG_PRINTF("output tensor: (scale, offset) = (%f, %f)", scale,
zero_point);
float *output_tensor_f = (float *)output_tensor;
for (uint32_t i = 0; i < model_tensor_size; ++i) {
output_tensor_f[i] = (ot[i] - zero_point) * scale;
}
}
*output_tensor_size = model_tensor_size;
bh_memcpy_s(output_tensor, model_tensor_size * sizeof(float), tensor_f,
model_tensor_size * sizeof(float));
return success;
}
@ -392,19 +447,35 @@ tensorflowlite_destroy(void *tflite_ctx)
*/
TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx;
if (tfl_ctx->delegate != NULL) {
#if defined(WASI_NN_ENABLE_GPU)
TfLiteGpuDelegateV2Delete(tfl_ctx->delegate);
#elif defined(WASI_NN_ENABLE_EXTERNAL_DELEGATE)
TfLiteExternalDelegateDelete(tfl_ctx->delegate);
#endif
}
NN_DBG_PRINTF("Freeing memory.");
for (int i = 0; i < MAX_GRAPHS_PER_INST; ++i) {
tfl_ctx->models[i].model.reset();
if (tfl_ctx->models[i].model_pointer)
if (tfl_ctx->models[i].model_pointer) {
if (tfl_ctx->delegate) {
switch (tfl_ctx->models[i].target) {
case gpu:
{
#if WASM_ENABLE_WASI_NN_GPU != 0
TfLiteGpuDelegateV2Delete(tfl_ctx->delegate);
#else
NN_ERR_PRINTF("GPU delegate delete but not enabled.");
#endif
break;
}
case tpu:
{
#if WASM_ENABLE_WASI_NN_EXTERNAL_DELEGATE != 0
TfLiteExternalDelegateDelete(tfl_ctx->delegate);
#else
NN_ERR_PRINTF(
"External delegate delete but not enabled.");
#endif
break;
}
}
}
wasm_runtime_free(tfl_ctx->models[i].model_pointer);
}
tfl_ctx->models[i].model_pointer = NULL;
}
for (int i = 0; i < MAX_GRAPH_EXEC_CONTEXTS_PER_INST; ++i) {

View File

@ -30,7 +30,6 @@ RUN make -j "$(grep -c ^processor /proc/cpuinfo)"
FROM ubuntu:22.04
COPY --from=base /home/wamr/product-mini/platforms/linux/build/libvmlib.so /libvmlib.so
COPY --from=base /home/wamr/product-mini/platforms/linux/build/iwasm /iwasm
ENTRYPOINT [ "/iwasm" ]

View File

@ -24,7 +24,7 @@ RUN apt-get install -y wget ca-certificates --no-install-recommends \
RUN cmake \
-DWAMR_BUILD_WASI_NN=1 \
-DWASI_NN_ENABLE_GPU=1 \
-DWAMR_BUILD_WASI_NN_ENABLE_GPU=1 \
..
RUN make -j "$(grep -c ^processor /proc/cpuinfo)"
@ -44,7 +44,6 @@ RUN mkdir -p /etc/OpenCL/vendors && \
ENV NVIDIA_VISIBLE_DEVICES=all
ENV NVIDIA_DRIVER_CAPABILITIES=compute,utility
COPY --from=base /home/wamr/product-mini/platforms/linux/build/libvmlib.so /libvmlib.so
COPY --from=base /home/wamr/product-mini/platforms/linux/build/iwasm /iwasm
ENTRYPOINT [ "/iwasm" ]

View File

@ -0,0 +1,37 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
FROM ubuntu:20.04 AS base
ENV DEBIAN_FRONTEND=noninteractive
# hadolint ignore=DL3008
RUN apt-get update && apt-get install -y \
cmake build-essential git curl gnupg --no-install-recommends && \
rm -rf /var/lib/apt/lists/*
# hadolint ignore=DL3008,DL4006
RUN echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" | tee /etc/apt/sources.list.d/coral-edgetpu.list && \
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
apt-get update && apt-get install -y libedgetpu1-std --no-install-recommends && \
rm -rf /var/lib/apt/lists/*
WORKDIR /home/wamr
COPY . .
WORKDIR /home/wamr/product-mini/platforms/linux/build
RUN cmake \
-DWAMR_BUILD_WASI_NN=1 \
-DWAMR_BUILD_WASI_NN_ENABLE_EXTERNAL_DELEGATE=1 \
-DWAMR_BUILD_WASI_NN_EXTERNAL_DELEGATE_PATH="libedgetpu.so.1.0" \
-DWAMR_BUILD_WASI_NN_ENABLE_GPU=1 \
..
RUN make -j "$(grep -c ^processor /proc/cpuinfo)" && \
cp /home/wamr/product-mini/platforms/linux/build/iwasm /iwasm
WORKDIR /assets
ENTRYPOINT [ "/iwasm" ]

View File

@ -1,6 +1,10 @@
#!/bin/sh
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
CURR_PATH=$(cd $(dirname $0) && pwd -P)
# WASM application that uses WASI-NN
/opt/wasi-sdk/bin/clang \
@ -13,9 +17,25 @@
# TFLite models to use in the tests
cd models
cd ${CURR_PATH}/models
python3 average.py
python3 max.py
python3 mult_dimension.py
python3 mult_outputs.py
python3 sum.py
# Specific tests for TPU
cd ${CURR_PATH}
/opt/wasi-sdk/bin/clang \
-Wl,--allow-undefined \
-Wl,--strip-all,--no-entry \
--sysroot=/opt/wasi-sdk/share/wasi-sysroot \
-I../include -I../src/utils \
-o test_tensorflow_quantized.wasm \
test_tensorflow_quantized.c utils.c
cd ${CURR_PATH}/models
python3 quantized.py
cd ${CURR_PATH}

View File

@ -0,0 +1,30 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
import tensorflow as tf
import numpy as np
import pathlib
model = tf.keras.Sequential([
tf.keras.layers.InputLayer(input_shape=[5, 5, 1]),
tf.keras.layers.AveragePooling2D(
pool_size=(5, 5), strides=None, padding="valid", data_format=None)
])
def representative_dataset():
for _ in range(1000):
data = np.random.randint(0, 25, (1, 5, 5, 1))
yield [data.astype(np.float32)]
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.uint8 # or tf.int8
converter.inference_output_type = tf.uint8 # or tf.int8
tflite_model = converter.convert()
tflite_models_dir = pathlib.Path("./")
tflite_model_file = tflite_models_dir / "quantized_model.tflite"
tflite_model_file.write_bytes(tflite_model)

View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <math.h>
#include "utils.h"
#include "logger.h"
#undef EPSILON
#define EPSILON 1e-2
void
test_average_quantized(execution_target target)
{
int dims[] = { 1, 5, 5, 1 };
input_info input = create_input(dims);
uint32_t output_size = 0;
float *output =
run_inference(target, input.input_tensor, input.dim, &output_size,
"./models/quantized_model.tflite", 1);
NN_INFO_PRINTF("Output size: %d", output_size);
NN_INFO_PRINTF("Result: average is %f", output[0]);
// NOTE: 11.95 instead of 12 because of errors due quantization
assert(fabs(output[0] - 11.95) < EPSILON);
free(input.dim);
free(input.input_tensor);
free(output);
}
int
main()
{
char *env = getenv("TARGET");
if (env == NULL) {
NN_INFO_PRINTF("Usage:\n--env=\"TARGET=[cpu|gpu|tpu]\"");
return 1;
}
execution_target target;
if (strcmp(env, "cpu") == 0)
target = cpu;
else if (strcmp(env, "gpu") == 0)
target = gpu;
else if (strcmp(env, "tpu") == 0)
target = tpu;
else {
NN_ERR_PRINTF("Wrong target!");
return 1;
}
NN_INFO_PRINTF("################### Testing quantized model...");
test_average_quantized(target);
NN_INFO_PRINTF("Tests: passed!");
return 0;
}

View File

@ -132,8 +132,8 @@ run_inference(execution_target target, float *input, uint32_t *input_size,
*output_size = MAX_OUTPUT_TENSOR_SIZE - *output_size;
if (wasm_get_output(ctx, i, &out_tensor[offset], output_size)
!= success) {
NN_ERR_PRINTF("Error when getting output.");
exit(1);
NN_ERR_PRINTF("Error when getting index %d.", i);
break;
}
offset += *output_size;

View File

@ -11,7 +11,7 @@
#include "wasi_nn.h"
#define MAX_MODEL_SIZE 85000000
#define MAX_OUTPUT_TENSOR_SIZE 200
#define MAX_OUTPUT_TENSOR_SIZE 1000000
#define INPUT_TENSOR_DIMS 4
#define EPSILON 1e-8

View File

@ -275,7 +275,7 @@ os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags,
return -1;
}
}
else {
else if (src_addr) {
memset(src_addr, 0, sizeof(*src_addr));
}

View File

@ -31,6 +31,10 @@ b_memcpy_wa(void *s1, unsigned int s1max, const void *s2, unsigned int n)
unsigned int *p;
char *ps;
if (n == 0) {
return 0;
}
if (pa > src) {
pa -= 4;
}

View File

@ -12,25 +12,25 @@
extern "C" {
#endif
#define bh_memcpy_s(dest, dlen, src, slen) \
do { \
int _ret = slen == 0 ? 0 : b_memcpy_s(dest, dlen, src, slen); \
(void)_ret; \
bh_assert(_ret == 0); \
#define bh_memcpy_s(dest, dlen, src, slen) \
do { \
int _ret = b_memcpy_s(dest, dlen, src, slen); \
(void)_ret; \
bh_assert(_ret == 0); \
} while (0)
#define bh_memcpy_wa(dest, dlen, src, slen) \
do { \
int _ret = slen == 0 ? 0 : b_memcpy_wa(dest, dlen, src, slen); \
(void)_ret; \
bh_assert(_ret == 0); \
#define bh_memcpy_wa(dest, dlen, src, slen) \
do { \
int _ret = b_memcpy_wa(dest, dlen, src, slen); \
(void)_ret; \
bh_assert(_ret == 0); \
} while (0)
#define bh_memmove_s(dest, dlen, src, slen) \
do { \
int _ret = slen == 0 ? 0 : b_memmove_s(dest, dlen, src, slen); \
(void)_ret; \
bh_assert(_ret == 0); \
#define bh_memmove_s(dest, dlen, src, slen) \
do { \
int _ret = b_memmove_s(dest, dlen, src, slen); \
(void)_ret; \
bh_assert(_ret == 0); \
} while (0)
#define bh_strcat_s(dest, dlen, src) \

View File

@ -7,5 +7,5 @@
#define _WAMR_VERSION_H_
#define WAMR_VERSION_MAJOR 1
#define WAMR_VERSION_MINOR 2
#define WAMR_VERSION_PATCH 2
#define WAMR_VERSION_PATCH 3
#endif