mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-02-06 06:55:07 +00:00
Implement multi-module feature and bulk-memory feature (#271)
Refine wasm loader and aot loader Fix potential issue of os_mmap/os_munmap Update document
This commit is contained in:
parent
e81f72d41f
commit
752826a667
|
@ -1,13 +1,47 @@
|
|||
---
|
||||
RawStringFormats:
|
||||
- Language: Cpp
|
||||
Delimiters:
|
||||
- c
|
||||
- C
|
||||
- cc
|
||||
- CC
|
||||
- cpp
|
||||
- Cpp
|
||||
- CPP
|
||||
- 'c++'
|
||||
- 'C++'
|
||||
- h
|
||||
- hpp
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
- Language: TextProto
|
||||
Delimiters:
|
||||
- pb
|
||||
- PB
|
||||
- proto
|
||||
- PROTO
|
||||
EnclosingFunctions:
|
||||
- EqualsProto
|
||||
- EquivToProto
|
||||
- PARSE_PARTIAL_TEXT_PROTO
|
||||
- PARSE_TEST_PROTO
|
||||
- PARSE_TEXT_PROTO
|
||||
- ParseTextOrDie
|
||||
- ParseTextProtoOrDie
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
|
||||
Language: Cpp
|
||||
BasedOnStyle: Mozilla
|
||||
IndentWidth: 4
|
||||
|
||||
---
|
||||
Language: Cpp
|
||||
AlignAfterOpenBracket: Align
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AlignConsecutiveMacros: true
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AlwaysBreakAfterReturnType: All
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BinPackParameters: false
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
|
@ -17,16 +51,17 @@ BraceWrapping:
|
|||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: true
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: true
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeElse: true
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: true
|
||||
ColumnLimit: 79
|
||||
ContinuationIndentWidth: 2
|
||||
DerivePointerAlignment: false
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
|
@ -36,20 +71,22 @@ IncludeCategories:
|
|||
Priority: 1
|
||||
- Regex: ".*"
|
||||
Priority: 3
|
||||
IndentPPDirectives: None
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
NamespaceIndentation: None
|
||||
PointerAlignment: Right
|
||||
ReflowComments: false
|
||||
Standard: Cpp03
|
||||
Standard: Auto
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
|
||||
# AccessModifierOffset: -2
|
||||
# AlignAfterOpenBracket: Align
|
||||
# AlignConsecutiveAssignments: false
|
||||
# AlignConsecutiveDeclarations: false
|
||||
# AlignEscapedNewlines: Right
|
||||
# AlignOperands: true
|
||||
# AlignTrailingComments: true
|
||||
# AllowAllArgumentsOnNextLine: true
|
||||
# AllowAllConstructorInitializersOnNextLine: true
|
||||
# AllowAllParametersOfDeclarationOnNextLine: false
|
||||
# AllowShortCaseLabelsOnASingleLine: false
|
||||
|
@ -61,7 +98,6 @@ StatementMacros:
|
|||
# AlwaysBreakAfterReturnType: TopLevel
|
||||
# AlwaysBreakBeforeMultilineStrings: false
|
||||
# AlwaysBreakTemplateDeclarations: Yes
|
||||
# BreakBeforeBinaryOperators: None
|
||||
# BreakBeforeInheritanceComma: false
|
||||
# BreakInheritanceList: BeforeComma
|
||||
# BreakBeforeTernaryOperators: true
|
||||
|
@ -73,7 +109,6 @@ StatementMacros:
|
|||
# CompactNamespaces: false
|
||||
# ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
# ConstructorInitializerIndentWidth: 2
|
||||
# ContinuationIndentWidth: 2
|
||||
# Cpp11BracedListStyle: false
|
||||
# DisableFormat: false
|
||||
# ExperimentalAutoDetectBinPacking: false
|
||||
|
@ -84,7 +119,6 @@ StatementMacros:
|
|||
# - BOOST_FOREACH
|
||||
# IncludeIsMainRegex: '(Test)?$'
|
||||
# IndentCaseLabels: true
|
||||
# IndentPPDirectives: None
|
||||
# IndentWrappedFunctionNames: false
|
||||
# JavaScriptQuotes: Leave
|
||||
# JavaScriptWrapImports: true
|
||||
|
@ -92,7 +126,6 @@ StatementMacros:
|
|||
# MacroBlockBegin: ''
|
||||
# MacroBlockEnd: ''
|
||||
# MaxEmptyLinesToKeep: 1
|
||||
# NamespaceIndentation: None
|
||||
# ObjCBinPackProtocolList: Auto
|
||||
# ObjCBlockIndentWidth: 2
|
||||
# ObjCSpaceAfterProperty: true
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -3,8 +3,11 @@
|
|||
core/deps/lv_drivers
|
||||
core/deps/llvm
|
||||
core/deps/lvgl
|
||||
core/deps/tlsf
|
||||
core/shared/mem-alloc/tlsf
|
||||
core/app-framework/wgl
|
||||
|
||||
wamr-sdk/out/
|
||||
wamr-sdk/runtime/build_runtime_sdk/
|
||||
test-tools/host-tool/bin/
|
||||
product-mini/app-samples/hello-world/test.wasm
|
|
@ -22,11 +22,17 @@ iwasm VM core
|
|||
|
||||
- 100% compliant to the W3C WASM MVP
|
||||
- Small runtime binary size (85K for interpreter and 50K for AoT) and low memory usage
|
||||
- Near to native speed by AoT
|
||||
- Near to native speed by AoT
|
||||
- Self-implemented module loader enables AoT working cross Linux, SGX and MCU systems
|
||||
- Choices of WASM application libc support: the built-in libc subset for the embedded environment or [WASI](https://github.com/WebAssembly/WASI) for standard libc
|
||||
- [Embeddable with the supporting C API's](./doc/embed_wamr.md)
|
||||
- [The mechanism for exporting native API's to WASM applications](./doc/export_native_api.md)
|
||||
- [Multiple modules as dependencies](./doc/multi_module.md)
|
||||
|
||||
### post-MVP features
|
||||
- [Non-trapping float-to-int conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions)
|
||||
- [Sign-extension operators](https://github.com/WebAssembly/sign-extension-ops)
|
||||
- [Bulk memory operations](https://github.com/WebAssembly/bulk-memory-operations)
|
||||
|
||||
### Performance and memory usage
|
||||
The WAMR performance, footprint and memory usage data are available at the [performance](../../wiki/Performance) wiki page.
|
||||
|
|
1
assembly-script/.gitignore
vendored
Normal file
1
assembly-script/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/node_modules
|
|
@ -123,8 +123,20 @@ else ()
|
|||
add_definitions (-DWASM_ENABLE_FAST_INTERP=0)
|
||||
message (" Fast interpreter disabled")
|
||||
endif ()
|
||||
|
||||
if (WAMR_BUILD_MULTI_MODULE EQUAL 1)
|
||||
add_definitions (-DWASM_ENABLE_MULTI_MODULE=1)
|
||||
message (" Multiple modules enabled")
|
||||
else ()
|
||||
add_definitions (-DWASM_ENABLE_MULTI_MODULE=0)
|
||||
message (" Multiple modules disabled")
|
||||
endif ()
|
||||
if (WAMR_BUILD_SPEC_TEST EQUAL 1)
|
||||
add_definitions (-DWASM_ENABLE_SPEC_TEST=1)
|
||||
message (" spec test compatible mode is on")
|
||||
endif()
|
||||
if (WAMR_BUILD_BULK_MEMORY EQUAL 1)
|
||||
add_definitions (-DWASM_ENABLE_BULK_MEMORY=1)
|
||||
message (" Bulk memory feature enabled")
|
||||
else ()
|
||||
add_definitions (-DWASM_ENABLE_BULK_MEMORY=0)
|
||||
endif()
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#ifndef _ATTR_CONTAINER_H_
|
||||
#define _ATTR_CONTAINER_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
|
|
@ -71,23 +71,18 @@ void free_req_resp_packet(char * packet)
|
|||
request_t * unpack_request(char * packet, int size, request_t * request)
|
||||
{
|
||||
if (*packet != REQUES_PACKET_VER) {
|
||||
printf("version fail\n");
|
||||
return NULL;
|
||||
}
|
||||
if (size < REQUEST_PACKET_FIX_PART_LEN) {
|
||||
printf("size error: %d\n", size);
|
||||
return NULL;
|
||||
}
|
||||
uint16 url_len = ntohs(*((uint16*) (packet + 12)));
|
||||
uint32 payload_len = ntohl(*((uint32*) (packet + 14)));
|
||||
|
||||
if (size != ( REQUEST_PACKET_FIX_PART_LEN + url_len + payload_len)) {
|
||||
printf("size error: %d, expect: %d\n", size,
|
||||
REQUEST_PACKET_FIX_PART_LEN + url_len + payload_len);
|
||||
return NULL;
|
||||
}
|
||||
if (*(packet + REQUEST_PACKET_FIX_PART_LEN + url_len - 1) != 0) {
|
||||
printf("url not end with 0\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -246,7 +246,7 @@ bool app_manager_host_init(host_interface *interface)
|
|||
return true;
|
||||
}
|
||||
|
||||
int app_manager_host_send_msg(int msg_type, const unsigned char *buf, int size)
|
||||
int app_manager_host_send_msg(int msg_type, const char *buf, int size)
|
||||
{
|
||||
/* send an IMRT LINK message contains the buf as payload */
|
||||
if (host_commu.send != NULL) {
|
||||
|
@ -276,10 +276,10 @@ int app_manager_host_send_msg(int msg_type, const unsigned char *buf, int size)
|
|||
n = host_commu.send(NULL, buf, size);
|
||||
os_mutex_unlock(&host_lock);
|
||||
|
||||
printf("sent %d bytes to host\n", n);
|
||||
app_manager_printf("sent %d bytes to host\n", n);
|
||||
return n;
|
||||
} else {
|
||||
printf("no send api provided\n");
|
||||
app_manager_printf("no send api provided\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -445,7 +445,7 @@ wasm_app_routine(void *arg)
|
|||
0, NULL)) {
|
||||
const char *exception = wasm_runtime_get_exception(inst);
|
||||
bh_assert(exception);
|
||||
printf("Got exception running wasi start function: %s\n",
|
||||
app_manager_printf("Got exception running wasi start function: %s\n",
|
||||
exception);
|
||||
wasm_runtime_clear_exception(inst);
|
||||
goto fail1;
|
||||
|
@ -467,7 +467,7 @@ wasm_app_routine(void *arg)
|
|||
0, NULL)) {
|
||||
const char *exception = wasm_runtime_get_exception(inst);
|
||||
bh_assert(exception);
|
||||
printf("Got exception running WASM code: %s\n",
|
||||
app_manager_printf("Got exception running WASM code: %s\n",
|
||||
exception);
|
||||
wasm_runtime_clear_exception(inst);
|
||||
/* call on_destroy() in case some resources are opened in on_init()
|
||||
|
@ -644,7 +644,7 @@ wasm_app_module_install(request_t * msg)
|
|||
if (!module) {
|
||||
SEND_ERR_RESPONSE(msg->mid,
|
||||
"Install WASM app failed: load WASM file failed.");
|
||||
printf("error: %s\n", err);
|
||||
app_manager_printf("error: %s\n", err);
|
||||
destroy_all_aot_sections(aot_file->sections);
|
||||
return false;
|
||||
}
|
||||
|
@ -674,7 +674,7 @@ wasm_app_module_install(request_t * msg)
|
|||
if (!inst) {
|
||||
SEND_ERR_RESPONSE(msg->mid,
|
||||
"Install WASM app failed: instantiate wasm runtime failed.");
|
||||
printf("error: %s\n", err);
|
||||
app_manager_printf("error: %s\n", err);
|
||||
wasm_runtime_unload(module);
|
||||
destroy_all_aot_sections(aot_file->sections);
|
||||
return false;
|
||||
|
@ -713,7 +713,7 @@ wasm_app_module_install(request_t * msg)
|
|||
if (!module) {
|
||||
SEND_ERR_RESPONSE(msg->mid,
|
||||
"Install WASM app failed: load WASM file failed.");
|
||||
printf("error: %s\n", err);
|
||||
app_manager_printf("error: %s\n", err);
|
||||
destroy_all_wasm_sections(bytecode_file->sections);
|
||||
return false;
|
||||
}
|
||||
|
@ -744,7 +744,7 @@ wasm_app_module_install(request_t * msg)
|
|||
if (!inst) {
|
||||
SEND_ERR_RESPONSE(msg->mid,
|
||||
"Install WASM app failed: instantiate wasm runtime failed.");
|
||||
printf("error: %s\n", err);
|
||||
app_manager_printf("error: %s\n", err);
|
||||
wasm_runtime_unload(module);
|
||||
destroy_all_wasm_sections(bytecode_file->sections);
|
||||
return false;
|
||||
|
|
|
@ -285,7 +285,7 @@ bool
|
|||
bh_applet_check_permission(const char *perm);
|
||||
|
||||
int
|
||||
app_manager_host_send_msg(int msg_type, const unsigned char *buf, int size);
|
||||
app_manager_host_send_msg(int msg_type, const char *buf, int size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
|
|
|
@ -94,6 +94,11 @@ enum {
|
|||
#define WASM_ENABLE_APP_FRAMEWORK 0
|
||||
#endif
|
||||
|
||||
/* Bulk memory operation */
|
||||
#ifndef WASM_ENABLE_BULK_MEMORY
|
||||
#define WASM_ENABLE_BULK_MEMORY 0
|
||||
#endif
|
||||
|
||||
/* WASM log system */
|
||||
#ifndef WASM_ENABLE_LOG
|
||||
#define WASM_ENABLE_LOG 1
|
||||
|
@ -120,6 +125,11 @@ enum {
|
|||
#define WASM_ENABLE_OPCODE_COUNTER 0
|
||||
#endif
|
||||
|
||||
/* Support a module with dependency, other modules */
|
||||
#ifndef WASM_ENABLE_MULTI_MODULE
|
||||
#define WASM_ENABLE_MULTI_MODULE 0
|
||||
#endif
|
||||
|
||||
/* Heap and stack profiling */
|
||||
#define BH_ENABLE_MEMORY_PROFILING 0
|
||||
|
||||
|
|
|
@ -363,6 +363,11 @@ load_mem_init_data_list(const uint8 **p_buf, const uint8 *buf_end,
|
|||
for (i = 0; i < module->mem_init_data_count; i++) {
|
||||
uint32 init_expr_type, byte_count;
|
||||
uint64 init_expr_value;
|
||||
uint32 is_passive;
|
||||
uint32 memory_index;
|
||||
|
||||
read_uint32(buf, buf_end, is_passive);
|
||||
read_uint32(buf, buf_end, memory_index);
|
||||
read_uint32(buf, buf_end, init_expr_type);
|
||||
read_uint64(buf, buf_end, init_expr_value);
|
||||
read_uint32(buf, buf_end, byte_count);
|
||||
|
@ -375,6 +380,11 @@ load_mem_init_data_list(const uint8 **p_buf, const uint8 *buf_end,
|
|||
return false;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
/* is_passive and memory_index is only used in bulk memory mode */
|
||||
data_list[i]->is_passive = (bool)is_passive;
|
||||
data_list[i]->memory_index = memory_index;
|
||||
#endif
|
||||
data_list[i]->offset.init_expr_type = (uint8)init_expr_type;
|
||||
data_list[i]->offset.u.i64 = (int64)init_expr_value;
|
||||
data_list[i]->byte_count = byte_count;
|
||||
|
@ -773,8 +783,7 @@ load_import_funcs(const uint8 **p_buf, const uint8 *buf_end,
|
|||
read_uint16(buf, buf_end, import_funcs[i].func_type_index);
|
||||
if (import_funcs[i].func_type_index >= module->func_type_count) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"AOT module load failed: "
|
||||
"invalid function type index.");
|
||||
"AOT module load failed: unknown type.");
|
||||
return false;
|
||||
}
|
||||
import_funcs[i].func_type = module->func_types[import_funcs[i].func_type_index];
|
||||
|
@ -1067,8 +1076,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
|
|||
read_uint32(p, p_end, module->func_type_indexes[i]);
|
||||
if (module->func_type_indexes[i] >= module->func_type_count) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"AOT module load failed: "
|
||||
"invalid function type index.");
|
||||
"AOT module load failed: unknown type.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,30 @@ typedef struct {
|
|||
|
||||
#define REG_SYM(symbol) { #symbol, (void*)symbol }
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
#define REG_COMMON_SYMBOLS \
|
||||
REG_SYM(aot_set_exception_with_id), \
|
||||
REG_SYM(aot_invoke_native), \
|
||||
REG_SYM(aot_call_indirect), \
|
||||
REG_SYM(wasm_runtime_enlarge_memory), \
|
||||
REG_SYM(wasm_runtime_set_exception), \
|
||||
REG_SYM(fmin), \
|
||||
REG_SYM(fminf), \
|
||||
REG_SYM(fmax), \
|
||||
REG_SYM(fmaxf), \
|
||||
REG_SYM(ceil), \
|
||||
REG_SYM(ceilf), \
|
||||
REG_SYM(floor), \
|
||||
REG_SYM(floorf), \
|
||||
REG_SYM(trunc), \
|
||||
REG_SYM(truncf), \
|
||||
REG_SYM(rint), \
|
||||
REG_SYM(rintf), \
|
||||
REG_SYM(memset), \
|
||||
REG_SYM(memmove), \
|
||||
REG_SYM(aot_memory_init), \
|
||||
REG_SYM(aot_data_drop)
|
||||
#else
|
||||
#define REG_COMMON_SYMBOLS \
|
||||
REG_SYM(aot_set_exception_with_id), \
|
||||
REG_SYM(aot_invoke_native), \
|
||||
|
@ -30,6 +54,7 @@ typedef struct {
|
|||
REG_SYM(truncf), \
|
||||
REG_SYM(rint), \
|
||||
REG_SYM(rintf)
|
||||
#endif
|
||||
|
||||
#define CHECK_RELOC_OFFSET(data_size) do { \
|
||||
if (!check_reloc_offset(target_section_size, reloc_offset, data_size, \
|
||||
|
|
|
@ -68,42 +68,62 @@ table_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
|
|||
uint32 i, global_index, global_data_offset, base_offset, length;
|
||||
AOTTableInitData *table_seg;
|
||||
|
||||
if (module->table_init_data_count > 0) {
|
||||
for (i = 0; i < module->table_init_data_count; i++) {
|
||||
table_seg = module->table_init_data_list[i];
|
||||
bh_assert(table_seg->offset.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST
|
||||
|| table_seg->offset.init_expr_type ==
|
||||
INIT_EXPR_TYPE_GET_GLOBAL);
|
||||
for (i = 0; i < module->table_init_data_count; i++) {
|
||||
table_seg = module->table_init_data_list[i];
|
||||
bh_assert(table_seg->offset.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST
|
||||
|| table_seg->offset.init_expr_type ==
|
||||
INIT_EXPR_TYPE_GET_GLOBAL);
|
||||
|
||||
/* Resolve table data base offset */
|
||||
if (table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) {
|
||||
global_index = table_seg->offset.u.global_index;
|
||||
bh_assert(global_index <
|
||||
module->import_global_count + module->global_count);
|
||||
/* TODO: && globals[table_seg->offset.u.global_index].type ==
|
||||
VALUE_TYPE_I32*/
|
||||
if (global_index < module->import_global_count)
|
||||
global_data_offset =
|
||||
module->import_globals[global_index].data_offset;
|
||||
else
|
||||
global_data_offset =
|
||||
module->globals[global_index - module->import_global_count]
|
||||
.data_offset;
|
||||
|
||||
base_offset = *(uint32*)
|
||||
((uint8*)module_inst->global_data.ptr + global_data_offset);
|
||||
}
|
||||
/* Resolve table data base offset */
|
||||
if (table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) {
|
||||
global_index = table_seg->offset.u.global_index;
|
||||
bh_assert(global_index <
|
||||
module->import_global_count + module->global_count);
|
||||
/* TODO: && globals[table_seg->offset.u.global_index].type ==
|
||||
VALUE_TYPE_I32*/
|
||||
if (global_index < module->import_global_count)
|
||||
global_data_offset =
|
||||
module->import_globals[global_index].data_offset;
|
||||
else
|
||||
base_offset = (uint32)table_seg->offset.u.i32;
|
||||
global_data_offset =
|
||||
module->globals[global_index - module->import_global_count]
|
||||
.data_offset;
|
||||
|
||||
/* Copy table data */
|
||||
length = table_seg->func_index_count;
|
||||
if (base_offset < module_inst->table_size) {
|
||||
memcpy((uint32*)module_inst->table_data.ptr + base_offset,
|
||||
table_seg->func_indexes, length * sizeof(uint32));
|
||||
}
|
||||
base_offset = *(uint32*)
|
||||
((uint8*)module_inst->global_data.ptr + global_data_offset);
|
||||
}
|
||||
else
|
||||
base_offset = (uint32)table_seg->offset.u.i32;
|
||||
|
||||
/* Copy table data */
|
||||
bh_assert(module_inst->table_data.ptr);
|
||||
/* base_offset only since length might negative */
|
||||
if (base_offset > module_inst->table_size) {
|
||||
LOG_DEBUG("base_offset(%d) > table_size(%d)", base_offset,
|
||||
module_inst->table_size);
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"elements segment does not fit");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* base_offset + length(could be zero) */
|
||||
length = table_seg->func_index_count;
|
||||
if (base_offset + length > module_inst->table_size) {
|
||||
LOG_DEBUG("base_offset(%d) + length(%d) > table_size(%d)",
|
||||
base_offset, length, module_inst->table_size);
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"elements segment does not fit");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check function index in the current module inst for now.
|
||||
* will check the linked table inst owner in future
|
||||
*/
|
||||
memcpy((uint32 *)module_inst->table_data.ptr + base_offset,
|
||||
table_seg->func_indexes,
|
||||
length * sizeof(uint32));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -169,50 +189,64 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
|
|||
module_inst->mem_bound_check_8bytes = module_inst->total_mem_size - 8;
|
||||
}
|
||||
|
||||
if (module->mem_init_page_count > 0) {
|
||||
for (i = 0; i < module->mem_init_data_count; i++) {
|
||||
data_seg = module->mem_init_data_list[i];
|
||||
bh_assert(data_seg->offset.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST
|
||||
|| data_seg->offset.init_expr_type ==
|
||||
INIT_EXPR_TYPE_GET_GLOBAL);
|
||||
for (i = 0; i < module->mem_init_data_count; i++) {
|
||||
data_seg = module->mem_init_data_list[i];
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
if (data_seg->is_passive)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
/* Resolve memory data base offset */
|
||||
if (data_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) {
|
||||
global_index = data_seg->offset.u.global_index;
|
||||
bh_assert(global_index <
|
||||
module->import_global_count + module->global_count);
|
||||
/* TODO: && globals[data_seg->offset.u.global_index].type ==
|
||||
VALUE_TYPE_I32*/
|
||||
if (global_index < module->import_global_count)
|
||||
global_data_offset =
|
||||
module->import_globals[global_index].data_offset;
|
||||
else
|
||||
global_data_offset =
|
||||
module->globals[global_index - module->import_global_count]
|
||||
.data_offset;
|
||||
bh_assert(data_seg->offset.init_expr_type ==
|
||||
INIT_EXPR_TYPE_I32_CONST
|
||||
|| data_seg->offset.init_expr_type ==
|
||||
INIT_EXPR_TYPE_GET_GLOBAL);
|
||||
|
||||
base_offset = *(uint32*)
|
||||
((uint8*)module_inst->global_data.ptr + global_data_offset);
|
||||
}
|
||||
/* Resolve memory data base offset */
|
||||
if (data_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) {
|
||||
global_index = data_seg->offset.u.global_index;
|
||||
bh_assert(global_index <
|
||||
module->import_global_count + module->global_count);
|
||||
/* TODO: && globals[data_seg->offset.u.global_index].type ==
|
||||
VALUE_TYPE_I32*/
|
||||
if (global_index < module->import_global_count)
|
||||
global_data_offset =
|
||||
module->import_globals[global_index].data_offset;
|
||||
else
|
||||
base_offset = (uint32)data_seg->offset.u.i32;
|
||||
global_data_offset =
|
||||
module->globals[global_index - module->import_global_count]
|
||||
.data_offset;
|
||||
|
||||
length = data_seg->byte_count;
|
||||
|
||||
/* Check memory data */
|
||||
if (length > 0
|
||||
&& (base_offset >= module_inst->memory_data_size
|
||||
|| base_offset + length > module_inst->memory_data_size)) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"AOT module instantiate failed: data segment out of range.");
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
/* Copy memory data */
|
||||
memcpy((uint8*)module_inst->memory_data.ptr + base_offset,
|
||||
data_seg->bytes, length);
|
||||
base_offset = *(uint32*)
|
||||
((uint8*)module_inst->global_data.ptr + global_data_offset);
|
||||
} else {
|
||||
base_offset = (uint32)data_seg->offset.u.i32;
|
||||
}
|
||||
|
||||
/* Copy memory data */
|
||||
bh_assert(module_inst->memory_data.ptr);
|
||||
|
||||
/* Check memory data */
|
||||
/* check offset since length might negative */
|
||||
if (base_offset > module_inst->memory_data_size) {
|
||||
LOG_DEBUG("base_offset(%d) > memory_data_size(%d)", base_offset,
|
||||
module_inst->memory_data_size);
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"data segment does not fit");
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
/* check offset + length(could be zero) */
|
||||
length = data_seg->byte_count;
|
||||
if (base_offset + length > module_inst->memory_data_size) {
|
||||
LOG_DEBUG("base_offset(%d) + length(%d) > memory_data_size(%d)",
|
||||
base_offset, length, module_inst->memory_data_size);
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"data segment does not fit");
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
memcpy((uint8*)module_inst->memory_data.ptr + base_offset,
|
||||
data_seg->bytes, length);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -952,3 +986,61 @@ aot_call_indirect(WASMExecEnv *exec_env,
|
|||
func_type, signature, attachment,
|
||||
argv, argc, argv);
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
bool
|
||||
aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index,
|
||||
uint32 offset, uint32 len, uint32 dst)
|
||||
{
|
||||
AOTModule *aot_module;
|
||||
uint8 *data = NULL;
|
||||
uint8 *maddr;
|
||||
uint64 seg_len = 0;
|
||||
|
||||
aot_module = (AOTModule *)module_inst->aot_module.ptr;
|
||||
if (aot_module->is_jit_mode) {
|
||||
#if WASM_ENABLE_JIT != 0
|
||||
seg_len = aot_module->wasm_module->data_segments[seg_index]->data_length;
|
||||
data = aot_module->wasm_module->data_segments[seg_index]->data;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
seg_len = aot_module->mem_init_data_list[seg_index]->byte_count;
|
||||
data = aot_module->mem_init_data_list[seg_index]->bytes;
|
||||
}
|
||||
|
||||
if (!aot_validate_app_addr(module_inst, dst, len))
|
||||
return false;
|
||||
|
||||
if ((uint64)offset + (uint64)len > seg_len) {
|
||||
aot_set_exception(module_inst, "out of bounds memory access");
|
||||
return false;
|
||||
}
|
||||
|
||||
maddr = aot_addr_app_to_native(module_inst, dst);
|
||||
|
||||
bh_memcpy_s(maddr, module_inst->memory_data_size - dst,
|
||||
data + offset, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_data_drop(AOTModuleInstance *module_inst, uint32 seg_index)
|
||||
{
|
||||
AOTModule *aot_module = (AOTModule *)(module_inst->aot_module.ptr);
|
||||
|
||||
if (aot_module->is_jit_mode) {
|
||||
#if WASM_ENABLE_JIT != 0
|
||||
aot_module->wasm_module->data_segments[seg_index]->data_length = 0;
|
||||
/* Currently we can't free the dropped data segment
|
||||
as they are stored in wasm bytecode */
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
aot_module->mem_init_data_list[seg_index]->byte_count = 0;
|
||||
/* Currently we can't free the dropped data segment
|
||||
as the mem_init_data_count is a continuous array */
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif /* WASM_ENABLE_BULK_MEMORY */
|
||||
|
|
|
@ -458,6 +458,15 @@ aot_call_indirect(WASMExecEnv *exec_env,
|
|||
uint32
|
||||
aot_get_plt_table_size();
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
bool
|
||||
aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index,
|
||||
uint32 offset, uint32 len, uint32 dst);
|
||||
|
||||
bool
|
||||
aot_data_drop(AOTModuleInstance *module_inst, uint32 seg_index);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
|
|
@ -243,6 +243,7 @@ wasm_native_init()
|
|||
if (!wasm_native_register_natives("env",
|
||||
native_symbols, n_native_symbols))
|
||||
return false;
|
||||
#endif /* WASM_ENABLE_LIBC_BUILTIN */
|
||||
|
||||
#if WASM_ENABLE_SPEC_TEST
|
||||
n_native_symbols = get_spectest_export_apis(&native_symbols);
|
||||
|
@ -250,7 +251,6 @@ wasm_native_init()
|
|||
native_symbols, n_native_symbols))
|
||||
return false;
|
||||
#endif /* WASM_ENABLE_SPEC_TEST */
|
||||
#endif /* WASM_ENABLE_LIBC_BUILTIN */
|
||||
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
n_native_symbols = get_libc_wasi_export_apis(&native_symbols);
|
||||
|
|
|
@ -16,6 +16,43 @@
|
|||
#include "../aot/aot_runtime.h"
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
/*
|
||||
* a safety insurance to prevent
|
||||
* circular depencies leading a stack overflow
|
||||
* try break early
|
||||
*/
|
||||
typedef struct LoadingModule {
|
||||
bh_list_link l;
|
||||
/* point to a string pool */
|
||||
const char *module_name;
|
||||
} LoadingModule;
|
||||
|
||||
static bh_list loading_module_list_head;
|
||||
static bh_list *const loading_module_list = &loading_module_list_head;
|
||||
static korp_mutex loading_module_list_lock;
|
||||
|
||||
/*
|
||||
* a list about all exported functions, globals, memories, tables of every
|
||||
* fully loaded module
|
||||
*/
|
||||
static bh_list registered_module_list_head;
|
||||
static bh_list *const registered_module_list = ®istered_module_list_head;
|
||||
static korp_mutex registered_module_list_lock;
|
||||
static void
|
||||
wasm_runtime_destroy_registered_module_list();
|
||||
#endif /* WASM_ENABLE_MULTI_MODULE */
|
||||
|
||||
void
|
||||
set_error_buf_v(char *error_buf, uint32 error_buf_size, const char *format,
|
||||
...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(error_buf, error_buf_size, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void
|
||||
set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
|
||||
{
|
||||
|
@ -34,11 +71,25 @@ wasm_runtime_env_init()
|
|||
return false;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE
|
||||
if (BHT_OK != os_mutex_init(®istered_module_list_lock)) {
|
||||
wasm_native_destroy();
|
||||
bh_platform_destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (BHT_OK != os_mutex_init(&loading_module_list_lock)) {
|
||||
os_mutex_destroy(®istered_module_list_lock);
|
||||
wasm_native_destroy();
|
||||
bh_platform_destroy();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
wasm_runtime_env_check(WASMExecEnv *exec_env)
|
||||
wasm_runtime_exec_env_check(WASMExecEnv *exec_env)
|
||||
{
|
||||
return !(!exec_env
|
||||
|| !exec_env->module_inst
|
||||
|
@ -65,8 +116,17 @@ wasm_runtime_init()
|
|||
void
|
||||
wasm_runtime_destroy()
|
||||
{
|
||||
/* runtime env destroy */
|
||||
#if WASM_ENABLE_MULTI_MODULE
|
||||
wasm_runtime_destroy_loading_module_list();
|
||||
os_mutex_destroy(&loading_module_list_lock);
|
||||
|
||||
wasm_runtime_destroy_registered_module_list();
|
||||
os_mutex_destroy(®istered_module_list_lock);
|
||||
#endif
|
||||
wasm_native_destroy();
|
||||
bh_platform_destroy();
|
||||
|
||||
wasm_runtime_memory_destroy();
|
||||
}
|
||||
|
||||
|
@ -105,10 +165,342 @@ get_package_type(const uint8 *buf, uint32 size)
|
|||
return Package_Type_Unknown;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
static module_reader reader;
|
||||
static module_destroyer destroyer;
|
||||
|
||||
void
|
||||
wasm_runtime_set_module_reader(const module_reader reader_cb,
|
||||
const module_destroyer destroyer_cb)
|
||||
{
|
||||
reader = reader_cb;
|
||||
destroyer = destroyer_cb;
|
||||
}
|
||||
|
||||
module_reader
|
||||
wasm_runtime_get_module_reader()
|
||||
{
|
||||
return reader;
|
||||
}
|
||||
|
||||
module_destroyer
|
||||
wasm_runtime_get_module_destroyer()
|
||||
{
|
||||
return destroyer;
|
||||
}
|
||||
|
||||
static WASMRegisteredModule *
|
||||
wasm_runtime_find_module_registered_by_reference(WASMModuleCommon *module)
|
||||
{
|
||||
WASMRegisteredModule *reg_module = NULL;
|
||||
|
||||
os_mutex_lock(®istered_module_list_lock);
|
||||
reg_module = bh_list_first_elem(registered_module_list);
|
||||
while (reg_module && module != reg_module->module) {
|
||||
reg_module = bh_list_elem_next(reg_module);
|
||||
}
|
||||
os_mutex_unlock(®istered_module_list_lock);
|
||||
|
||||
return reg_module;
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_runtime_register_module_internal(const char *module_name,
|
||||
WASMModuleCommon *module,
|
||||
uint8 *orig_file_buf,
|
||||
uint32 orig_file_buf_size,
|
||||
char *error_buf,
|
||||
uint32_t error_buf_size)
|
||||
{
|
||||
WASMRegisteredModule *node = NULL;
|
||||
|
||||
node = wasm_runtime_find_module_registered_by_reference(module);
|
||||
if (node) { /* module has been registered */
|
||||
if (node->module_name) { /* module has name */
|
||||
if (strcmp(node->module_name, module_name)) {
|
||||
/* module has different name */
|
||||
LOG_DEBUG("module(%p) has been registered with name %s",
|
||||
module, node->module_name);
|
||||
set_error_buf_v(error_buf, error_buf_size,
|
||||
"can not rename the module");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
/* module has the same name */
|
||||
LOG_DEBUG("module(%p) has been registered with the same name %s",
|
||||
module, node->module_name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* module has empyt name, reset it */
|
||||
node->module_name = module_name;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* module hasn't been registered */
|
||||
node = wasm_runtime_malloc(sizeof(WASMRegisteredModule));
|
||||
if (!node) {
|
||||
LOG_DEBUG("malloc WASMRegisteredModule failed. SZ=%d",
|
||||
sizeof(WASMRegisteredModule));
|
||||
set_error_buf_v(error_buf, error_buf_size,
|
||||
"malloc WASMRegisteredModule failed. SZ=%d",
|
||||
sizeof(WASMRegisteredModule));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* share the string and the module */
|
||||
node->module_name = module_name;
|
||||
node->module = module;
|
||||
node->orig_file_buf = orig_file_buf;
|
||||
node->orig_file_buf_size = orig_file_buf_size;
|
||||
|
||||
os_mutex_lock(®istered_module_list_lock);
|
||||
bh_list_status ret = bh_list_insert(registered_module_list, node);
|
||||
bh_assert(BH_LIST_SUCCESS == ret);
|
||||
(void)ret;
|
||||
os_mutex_unlock(®istered_module_list_lock);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_runtime_register_module(const char *module_name, WASMModuleCommon *module,
|
||||
char *error_buf, uint32_t error_buf_size)
|
||||
{
|
||||
if (!error_buf || !error_buf_size) {
|
||||
LOG_ERROR("error buffer is required");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!module_name || !module) {
|
||||
LOG_DEBUG("module_name and module are required");
|
||||
set_error_buf_v(error_buf, error_buf_size,
|
||||
"module_name and module are required");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wasm_runtime_is_built_in_module(module_name)) {
|
||||
LOG_DEBUG("%s is a built-in module name", module_name);
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"can not register as a built-in module");
|
||||
return false;
|
||||
}
|
||||
|
||||
return wasm_runtime_register_module_internal(
|
||||
module_name, module, NULL, 0,
|
||||
error_buf, error_buf_size);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_runtime_unregister_module(const WASMModuleCommon *module)
|
||||
{
|
||||
WASMRegisteredModule *registered_module = NULL;
|
||||
|
||||
os_mutex_lock(®istered_module_list_lock);
|
||||
registered_module = bh_list_first_elem(registered_module_list);
|
||||
while (registered_module && module != registered_module->module) {
|
||||
registered_module = bh_list_elem_next(registered_module);
|
||||
}
|
||||
|
||||
/* it does not matter if it is not exist. after all, it is gone */
|
||||
if (registered_module) {
|
||||
bh_list_remove(registered_module_list, registered_module);
|
||||
wasm_runtime_free(registered_module);
|
||||
}
|
||||
os_mutex_unlock(®istered_module_list_lock);
|
||||
}
|
||||
|
||||
WASMModuleCommon *
|
||||
wasm_runtime_find_module_registered(const char *module_name)
|
||||
{
|
||||
WASMRegisteredModule *module = NULL, *module_next;
|
||||
|
||||
os_mutex_lock(®istered_module_list_lock);
|
||||
module = bh_list_first_elem(registered_module_list);
|
||||
while (module) {
|
||||
module_next = bh_list_elem_next(module);
|
||||
if (module->module_name
|
||||
&& !strcmp(module_name, module->module_name)) {
|
||||
break;
|
||||
}
|
||||
module = module_next;
|
||||
}
|
||||
os_mutex_unlock(®istered_module_list_lock);
|
||||
|
||||
return module ? module->module : NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_runtime_is_module_registered(const char *module_name)
|
||||
{
|
||||
return NULL != wasm_runtime_find_module_registered(module_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* simply destroy all
|
||||
*/
|
||||
static void
|
||||
wasm_runtime_destroy_registered_module_list()
|
||||
{
|
||||
WASMRegisteredModule *reg_module = NULL;
|
||||
|
||||
os_mutex_lock(®istered_module_list_lock);
|
||||
reg_module = bh_list_first_elem(registered_module_list);
|
||||
while (reg_module) {
|
||||
WASMRegisteredModule *next_reg_module = bh_list_elem_next(reg_module);
|
||||
|
||||
bh_list_remove(registered_module_list, reg_module);
|
||||
|
||||
/* now, it is time to release every module in the runtime */
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
if (reg_module->module->module_type == Wasm_Module_Bytecode)
|
||||
wasm_unload((WASMModule *)reg_module->module);
|
||||
#endif
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (reg_module->module->module_type == Wasm_Module_AoT)
|
||||
aot_unload((AOTModule *)reg_module->module);
|
||||
#endif
|
||||
|
||||
/* destroy the file buffer */
|
||||
if (destroyer && reg_module->orig_file_buf) {
|
||||
destroyer(reg_module->orig_file_buf,
|
||||
reg_module->orig_file_buf_size);
|
||||
reg_module->orig_file_buf = NULL;
|
||||
reg_module->orig_file_buf_size = 0;
|
||||
}
|
||||
|
||||
wasm_runtime_free(reg_module);
|
||||
reg_module = next_reg_module;
|
||||
}
|
||||
os_mutex_unlock(®istered_module_list_lock);
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_runtime_add_loading_module(const char *module_name, char *error_buf,
|
||||
uint32 error_buf_size)
|
||||
{
|
||||
LOG_DEBUG("add %s into a loading list", module_name);
|
||||
LoadingModule *loadingModule = wasm_runtime_malloc(sizeof(LoadingModule));
|
||||
|
||||
if (!loadingModule) {
|
||||
set_error_buf_v(error_buf, error_buf_size,
|
||||
"malloc LoadingModule failed. SZ=%d",
|
||||
sizeof(LoadingModule));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* share the incoming string */
|
||||
loadingModule->module_name = module_name;
|
||||
|
||||
os_mutex_lock(&loading_module_list_lock);
|
||||
bh_list_status ret = bh_list_insert(loading_module_list, loadingModule);
|
||||
bh_assert(BH_LIST_SUCCESS == ret);
|
||||
(void)ret;
|
||||
os_mutex_unlock(&loading_module_list_lock);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
wasm_runtime_delete_loading_module(const char *module_name)
|
||||
{
|
||||
LOG_DEBUG("delete %s from a loading list", module_name);
|
||||
|
||||
LoadingModule *module = NULL;
|
||||
|
||||
os_mutex_lock(&loading_module_list_lock);
|
||||
module = bh_list_first_elem(loading_module_list);
|
||||
while (module && strcmp(module->module_name, module_name)) {
|
||||
module = bh_list_elem_next(module);
|
||||
}
|
||||
|
||||
/* it does not matter if it is not exist. after all, it is gone */
|
||||
if (module) {
|
||||
bh_list_remove(loading_module_list, module);
|
||||
wasm_runtime_free(module);
|
||||
}
|
||||
os_mutex_unlock(&loading_module_list_lock);
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_runtime_is_loading_module(const char *module_name)
|
||||
{
|
||||
LOG_DEBUG("find %s in a loading list", module_name);
|
||||
|
||||
LoadingModule *module = NULL;
|
||||
|
||||
os_mutex_lock(&loading_module_list_lock);
|
||||
module = bh_list_first_elem(loading_module_list);
|
||||
while (module && strcmp(module_name, module->module_name)) {
|
||||
module = bh_list_elem_next(module);
|
||||
}
|
||||
os_mutex_unlock(&loading_module_list_lock);
|
||||
|
||||
return module != NULL;
|
||||
}
|
||||
|
||||
void
|
||||
wasm_runtime_destroy_loading_module_list()
|
||||
{
|
||||
LoadingModule *module = NULL;
|
||||
|
||||
os_mutex_lock(&loading_module_list_lock);
|
||||
module = bh_list_first_elem(loading_module_list);
|
||||
while (module) {
|
||||
LoadingModule *next_module = bh_list_elem_next(module);
|
||||
|
||||
bh_list_remove(loading_module_list, module);
|
||||
/*
|
||||
* will not free the module_name since it is
|
||||
* shared one of the const string pool
|
||||
*/
|
||||
wasm_runtime_free(module);
|
||||
|
||||
module = next_module;
|
||||
}
|
||||
|
||||
os_mutex_unlock(&loading_module_list_lock);
|
||||
}
|
||||
#endif /* WASM_ENABLE_MULTI_MODULE */
|
||||
|
||||
bool
|
||||
wasm_runtime_is_built_in_module(const char *module_name)
|
||||
{
|
||||
return (!strcmp("env", module_name)
|
||||
|| !strcmp("wasi_unstable", module_name)
|
||||
|| !strcmp("wasi_snapshot_preview1", module_name)
|
||||
|| !strcmp("spectest", module_name)
|
||||
);
|
||||
}
|
||||
|
||||
static WASMModuleCommon *
|
||||
register_module_with_null_name(WASMModuleCommon *module_common,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
if (module_common) {
|
||||
if (!wasm_runtime_register_module_internal(NULL, module_common,
|
||||
NULL, 0,
|
||||
error_buf,
|
||||
error_buf_size)) {
|
||||
wasm_runtime_unload(module_common);
|
||||
return NULL;
|
||||
}
|
||||
return module_common;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
#else
|
||||
return module_common;
|
||||
#endif
|
||||
}
|
||||
|
||||
WASMModuleCommon *
|
||||
wasm_runtime_load(const uint8 *buf, uint32 size,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
WASMModuleCommon *module_common = NULL;
|
||||
|
||||
if (get_package_type(buf, size) == Wasm_Module_Bytecode) {
|
||||
#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0
|
||||
AOTModule *aot_module;
|
||||
|
@ -121,18 +513,24 @@ wasm_runtime_load(const uint8 *buf, uint32 size,
|
|||
wasm_unload(module);
|
||||
return NULL;
|
||||
}
|
||||
return (WASMModuleCommon*)aot_module;
|
||||
|
||||
module_common = (WASMModuleCommon*)aot_module;
|
||||
return register_module_with_null_name(module_common,
|
||||
error_buf, error_buf_size);
|
||||
#elif WASM_ENABLE_INTERP != 0
|
||||
return (WASMModuleCommon*)
|
||||
module_common = (WASMModuleCommon*)
|
||||
wasm_load(buf, size, error_buf, error_buf_size);
|
||||
return register_module_with_null_name(module_common,
|
||||
error_buf, error_buf_size);
|
||||
#endif
|
||||
}
|
||||
else if (get_package_type(buf, size) == Wasm_Module_AoT) {
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
return (WASMModuleCommon*)
|
||||
module_common = (WASMModuleCommon*)
|
||||
aot_load_from_aot_file(buf, size, error_buf, error_buf_size);
|
||||
|
||||
#endif /* end of WASM_ENABLE_AOT */
|
||||
return register_module_with_null_name(module_common,
|
||||
error_buf, error_buf_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (size < 4)
|
||||
|
@ -148,17 +546,25 @@ WASMModuleCommon *
|
|||
wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot,
|
||||
char *error_buf, uint32_t error_buf_size)
|
||||
{
|
||||
WASMModuleCommon *module_common;
|
||||
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
if (!is_aot)
|
||||
return (WASMModuleCommon*)
|
||||
if (!is_aot) {
|
||||
module_common = (WASMModuleCommon*)
|
||||
wasm_load_from_sections(section_list,
|
||||
error_buf, error_buf_size);
|
||||
return register_module_with_null_name(module_common,
|
||||
error_buf, error_buf_size);
|
||||
}
|
||||
#endif
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (is_aot)
|
||||
return (WASMModuleCommon*)
|
||||
if (is_aot) {
|
||||
module_common = (WASMModuleCommon*)
|
||||
aot_load_from_sections(section_list,
|
||||
error_buf, error_buf_size);
|
||||
return register_module_with_null_name(module_common,
|
||||
error_buf, error_buf_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
|
@ -169,12 +575,21 @@ wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot,
|
|||
void
|
||||
wasm_runtime_unload(WASMModuleCommon *module)
|
||||
{
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
/**
|
||||
* since we will unload and free all module when runtime_destroy()
|
||||
* we don't want users to unwillingly disrupt it
|
||||
*/
|
||||
return;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
if (module->module_type == Wasm_Module_Bytecode) {
|
||||
wasm_unload((WASMModule*)module);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (module->module_type == Wasm_Module_AoT) {
|
||||
aot_unload((AOTModule*)module);
|
||||
|
@ -285,9 +700,9 @@ wasm_runtime_lookup_function(WASMModuleInstanceCommon * const module_inst,
|
|||
bool
|
||||
wasm_runtime_call_wasm(WASMExecEnv *exec_env,
|
||||
WASMFunctionInstanceCommon *function,
|
||||
unsigned argc, uint32 argv[])
|
||||
uint32 argc, uint32 argv[])
|
||||
{
|
||||
if (!wasm_runtime_env_check(exec_env)) {
|
||||
if (!wasm_runtime_exec_env_check(exec_env)) {
|
||||
LOG_ERROR("Invalid exec env stack info.");
|
||||
return false;
|
||||
}
|
||||
|
@ -313,7 +728,7 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env,
|
|||
bool
|
||||
wasm_runtime_create_exec_env_and_call_wasm(WASMModuleInstanceCommon *module_inst,
|
||||
WASMFunctionInstanceCommon *function,
|
||||
unsigned argc, uint32 argv[])
|
||||
uint32 argc, uint32 argv[])
|
||||
{
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
if (module_inst->module_type == Wasm_Module_Bytecode)
|
||||
|
@ -1077,7 +1492,7 @@ check_main_func_type(const WASMType *type)
|
|||
|
||||
bool
|
||||
wasm_application_execute_main(WASMModuleInstanceCommon *module_inst,
|
||||
int argc, char *argv[])
|
||||
int32 argc, char *argv[])
|
||||
{
|
||||
WASMFunctionInstanceCommon *func;
|
||||
WASMType *func_type = NULL;
|
||||
|
@ -1165,6 +1580,54 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst,
|
|||
argc1, argv1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
static WASMModuleInstance *
|
||||
get_sub_module_inst(const WASMModuleInstance *parent_module_inst,
|
||||
const char *sub_module_name)
|
||||
{
|
||||
WASMSubModInstNode *node =
|
||||
bh_list_first_elem(parent_module_inst->sub_module_inst_list);
|
||||
|
||||
while (node && strcmp(node->module_name, sub_module_name)) {
|
||||
node = bh_list_elem_next(node);
|
||||
}
|
||||
return node ? node->module_inst : NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_function_name(char *orig_function_name, char **p_module_name,
|
||||
char **p_function_name)
|
||||
{
|
||||
if (orig_function_name[0] != '$') {
|
||||
*p_module_name = NULL;
|
||||
*p_function_name = orig_function_name;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* $module_name$function_name\0
|
||||
* ===>
|
||||
* module_name\0function_name\0
|
||||
* ===>
|
||||
* module_name
|
||||
* function_name
|
||||
*/
|
||||
char *p1 = orig_function_name;
|
||||
char *p2 = strchr(p1 + 1, '$');
|
||||
if (!p2) {
|
||||
LOG_DEBUG("can not parse the incoming function name");
|
||||
return false;
|
||||
}
|
||||
|
||||
*p_module_name = p1 + 1;
|
||||
*p2 = '\0';
|
||||
*p_function_name = p2 + 1;
|
||||
return strlen(*p_module_name) && strlen(*p_function_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Implementation of wasm_application_execute_func()
|
||||
*/
|
||||
|
@ -1173,32 +1636,76 @@ static WASMFunctionInstanceCommon*
|
|||
resolve_function(const WASMModuleInstanceCommon *module_inst,
|
||||
const char *name)
|
||||
{
|
||||
uint32 i;
|
||||
uint32 i = 0;
|
||||
WASMFunctionInstanceCommon *ret = NULL;
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
WASMModuleInstance *sub_module_inst = NULL;
|
||||
char *orig_name = NULL;
|
||||
char *sub_module_name = NULL;
|
||||
char *function_name = NULL;
|
||||
uint32 length = strlen(name) + 1;
|
||||
|
||||
orig_name = wasm_runtime_malloc(sizeof(char) * length);
|
||||
if (!orig_name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(orig_name, 0, sizeof(char) * length);
|
||||
strncpy(orig_name, name, length);
|
||||
|
||||
if (!parse_function_name(orig_name, &sub_module_name, &function_name)) {
|
||||
goto LEAVE;
|
||||
}
|
||||
|
||||
LOG_DEBUG("%s -> %s and %s", name, sub_module_name, function_name);
|
||||
|
||||
if (sub_module_name) {
|
||||
sub_module_inst = get_sub_module_inst(
|
||||
(WASMModuleInstance *)module_inst, sub_module_name);
|
||||
if (!sub_module_inst) {
|
||||
LOG_DEBUG("can not find a sub module named %s", sub_module_name);
|
||||
goto LEAVE;
|
||||
}
|
||||
}
|
||||
#else
|
||||
const char *function_name = name;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
if (module_inst->module_type == Wasm_Module_Bytecode) {
|
||||
WASMModuleInstance *wasm_inst = (WASMModuleInstance*)module_inst;
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
wasm_inst = sub_module_inst ? sub_module_inst : wasm_inst;
|
||||
#endif /* WASM_ENABLE_MULTI_MODULE */
|
||||
|
||||
for (i = 0; i < wasm_inst->export_func_count; i++) {
|
||||
if (!strcmp(wasm_inst->export_functions[i].name, name))
|
||||
return wasm_inst->export_functions[i].function;
|
||||
if (!strcmp(wasm_inst->export_functions[i].name, function_name)) {
|
||||
ret = wasm_inst->export_functions[i].function;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
#endif /* WASM_ENABLE_INTERP */
|
||||
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (module_inst->module_type == Wasm_Module_AoT) {
|
||||
AOTModuleInstance *aot_inst = (AOTModuleInstance*)module_inst;
|
||||
AOTModule *module = (AOTModule*)aot_inst->aot_module.ptr;
|
||||
for (i = 0; i < module->export_func_count; i++) {
|
||||
if (!strcmp(module->export_funcs[i].func_name, name))
|
||||
return (WASMFunctionInstance*)&module->export_funcs[i];
|
||||
if (!strcmp(module->export_funcs[i].func_name, function_name)) {
|
||||
ret = (WASMFunctionInstance*)&module->export_funcs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
LEAVE:
|
||||
wasm_runtime_free(orig_name);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
union ieee754_float {
|
||||
|
@ -1251,7 +1758,7 @@ static union {
|
|||
|
||||
bool
|
||||
wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
|
||||
const char *name, int argc, char *argv[])
|
||||
const char *name, int32 argc, char *argv[])
|
||||
{
|
||||
WASMFunctionInstanceCommon *func;
|
||||
WASMType *type = NULL;
|
||||
|
@ -1262,6 +1769,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
|
|||
char buf[128];
|
||||
|
||||
bh_assert(argc >= 0);
|
||||
LOG_DEBUG("call a function \"%s\" with %d arguments", name, argc);
|
||||
func = resolve_function(module_inst, name);
|
||||
|
||||
if (!func) {
|
||||
|
@ -1273,7 +1781,11 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
|
|||
#if WASM_ENABLE_INTERP != 0
|
||||
if (module_inst->module_type == Wasm_Module_Bytecode) {
|
||||
WASMFunctionInstance *wasm_func = (WASMFunctionInstance*)func;
|
||||
if (wasm_func->is_import_func) {
|
||||
if (wasm_func->is_import_func
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
&& !wasm_func->import_func_inst
|
||||
#endif
|
||||
) {
|
||||
snprintf(buf, sizeof(buf), "lookup function %s failed.", name);
|
||||
wasm_runtime_set_exception(module_inst, buf);
|
||||
goto fail;
|
||||
|
@ -2146,7 +2658,7 @@ wasm_runtime_call_indirect(WASMExecEnv *exec_env,
|
|||
uint32_t element_indices,
|
||||
uint32_t argc, uint32_t argv[])
|
||||
{
|
||||
if (!wasm_runtime_env_check(exec_env)) {
|
||||
if (!wasm_runtime_exec_env_check(exec_env)) {
|
||||
LOG_ERROR("Invalid exec env stack info.");
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct WASMModuleCommon {
|
||||
/* Module type, for module loaded from WASM bytecode binary,
|
||||
this field is Wasm_Module_Bytecode, and this structure should
|
||||
|
@ -56,9 +55,25 @@ typedef struct WASIContext {
|
|||
} WASIContext;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
typedef struct WASMRegisteredModule {
|
||||
bh_list_link l;
|
||||
/* point to a string pool */
|
||||
const char *module_name;
|
||||
WASMModuleCommon *module;
|
||||
/* to store the original module file buffer address */
|
||||
uint8 *orig_file_buf;
|
||||
uint32 orig_file_buf_size;
|
||||
} WASMRegisteredModule;
|
||||
#endif
|
||||
|
||||
typedef package_type_t PackageType;
|
||||
typedef wasm_section_t WASMSection, AOTSection;
|
||||
|
||||
void
|
||||
set_error_buf_v(char *error_buf, uint32 error_buf_size, const char *format,
|
||||
...);
|
||||
|
||||
/* See wasm_export.h for description */
|
||||
bool
|
||||
wasm_runtime_init();
|
||||
|
@ -75,6 +90,7 @@ wasm_runtime_destroy();
|
|||
PackageType
|
||||
get_package_type(const uint8 *buf, uint32 size);
|
||||
|
||||
|
||||
/* See wasm_export.h for description */
|
||||
WASMModuleCommon *
|
||||
wasm_runtime_load(const uint8 *buf, uint32 size,
|
||||
|
@ -83,7 +99,7 @@ wasm_runtime_load(const uint8 *buf, uint32 size,
|
|||
/* See wasm_export.h for description */
|
||||
WASMModuleCommon *
|
||||
wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot,
|
||||
char *error_buf, uint32_t error_buf_size);
|
||||
char *error_buf, uint32 error_buf_size);
|
||||
|
||||
/* See wasm_export.h for description */
|
||||
void
|
||||
|
@ -119,21 +135,21 @@ wasm_runtime_get_module_inst(WASMExecEnv *exec_env);
|
|||
|
||||
/* See wasm_export.h for description */
|
||||
void *
|
||||
wasm_runtime_get_function_attachment(wasm_exec_env_t exec_env);
|
||||
wasm_runtime_get_function_attachment(WASMExecEnv *exec_env);
|
||||
|
||||
/* See wasm_export.h for description */
|
||||
void
|
||||
wasm_runtime_set_user_data(wasm_exec_env_t exec_env, void *user_data);
|
||||
wasm_runtime_set_user_data(WASMExecEnv *exec_env, void *user_data);
|
||||
|
||||
/* See wasm_export.h for description */
|
||||
void *
|
||||
wasm_runtime_get_user_data(wasm_exec_env_t exec_env);
|
||||
wasm_runtime_get_user_data(WASMExecEnv *exec_env);
|
||||
|
||||
/* See wasm_export.h for description */
|
||||
bool
|
||||
wasm_runtime_call_wasm(WASMExecEnv *exec_env,
|
||||
WASMFunctionInstanceCommon *function,
|
||||
unsigned argc, uint32 argv[]);
|
||||
uint32 argc, uint32 argv[]);
|
||||
|
||||
/**
|
||||
* Call a function reference of a given WASM runtime instance with
|
||||
|
@ -154,23 +170,23 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env,
|
|||
*/
|
||||
bool
|
||||
wasm_runtime_call_indirect(WASMExecEnv *exec_env,
|
||||
uint32_t element_indices,
|
||||
uint32_t argc, uint32_t argv[]);
|
||||
uint32 element_indices,
|
||||
uint32 argc, uint32 argv[]);
|
||||
|
||||
bool
|
||||
wasm_runtime_create_exec_env_and_call_wasm(WASMModuleInstanceCommon *module_inst,
|
||||
WASMFunctionInstanceCommon *function,
|
||||
unsigned argc, uint32 argv[]);
|
||||
uint32 argc, uint32 argv[]);
|
||||
|
||||
/* See wasm_export.h for description */
|
||||
bool
|
||||
wasm_application_execute_main(WASMModuleInstanceCommon *module_inst,
|
||||
int argc, char *argv[]);
|
||||
int32 argc, char *argv[]);
|
||||
|
||||
/* See wasm_export.h for description */
|
||||
bool
|
||||
wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
|
||||
const char *name, int argc, char *argv[]);
|
||||
const char *name, int32 argc, char *argv[]);
|
||||
|
||||
/* See wasm_export.h for description */
|
||||
void
|
||||
|
@ -261,6 +277,48 @@ void
|
|||
wasm_runtime_set_llvm_stack(WASMModuleInstanceCommon *module_inst,
|
||||
uint32 llvm_stack);
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
void
|
||||
wasm_runtime_set_module_reader(const module_reader reader,
|
||||
const module_destroyer destroyer);
|
||||
|
||||
module_reader
|
||||
wasm_runtime_get_module_reader();
|
||||
|
||||
module_destroyer
|
||||
wasm_runtime_get_module_destroyer();
|
||||
|
||||
bool
|
||||
wasm_runtime_register_module_internal(const char *module_name,
|
||||
WASMModuleCommon *module,
|
||||
uint8 *orig_file_buf,
|
||||
uint32 orig_file_buf_size,
|
||||
char *error_buf,
|
||||
uint32 error_buf_size);
|
||||
|
||||
void
|
||||
wasm_runtime_unregister_module(const WASMModuleCommon *module);
|
||||
|
||||
bool
|
||||
wasm_runtime_is_module_registered(const char *module_name);
|
||||
|
||||
bool
|
||||
wasm_runtime_add_loading_module(const char *module_name,
|
||||
char *error_buf, uint32 error_buf_size);
|
||||
|
||||
void
|
||||
wasm_runtime_delete_loading_module(const char *module_name);
|
||||
|
||||
bool
|
||||
wasm_runtime_is_loading_module(const char *module_name);
|
||||
|
||||
void
|
||||
wasm_runtime_destroy_loading_module_list();
|
||||
#endif /* WASM_ENALBE_MULTI_MODULE */
|
||||
|
||||
bool
|
||||
wasm_runtime_is_built_in_module(const char *module_name);
|
||||
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
/* See wasm_export.h for description */
|
||||
void
|
||||
|
|
|
@ -60,6 +60,10 @@ aot_create_mem_init_data_list(const WASMModule *module)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
data_list[i]->is_passive = module->data_segments[i]->is_passive;
|
||||
data_list[i]->memory_index = module->data_segments[i]->memory_index;
|
||||
#endif
|
||||
data_list[i]->offset = module->data_segments[i]->base_offset;
|
||||
data_list[i]->byte_count = module->data_segments[i]->data_length;
|
||||
memcpy(data_list[i]->bytes, module->data_segments[i]->data,
|
||||
|
|
|
@ -24,6 +24,12 @@ typedef WASMType AOTFuncType;
|
|||
* A segment of memory init data
|
||||
*/
|
||||
typedef struct AOTMemInitData {
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
/* Passive flag */
|
||||
bool is_passive;
|
||||
/* memory index */
|
||||
uint32 memory_index;
|
||||
#endif
|
||||
/* Start address of init data */
|
||||
AOTInitExpr offset;
|
||||
/* Byte count */
|
||||
|
|
|
@ -741,6 +741,39 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
|||
if (!aot_compile_op_i64_trunc_f64(comp_ctx, func_ctx, sign, true))
|
||||
return false;
|
||||
break;
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
case WASM_OP_MEMORY_INIT:
|
||||
{
|
||||
uint32 seg_index;
|
||||
read_leb_uint32(frame_ip, frame_ip_end, seg_index);
|
||||
frame_ip ++;
|
||||
if (!aot_compile_op_memory_init(comp_ctx, func_ctx, seg_index))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case WASM_OP_DATA_DROP:
|
||||
{
|
||||
uint32 seg_index;
|
||||
read_leb_uint32(frame_ip, frame_ip_end, seg_index);
|
||||
if (!aot_compile_op_data_drop(comp_ctx, func_ctx, seg_index))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case WASM_OP_MEMORY_COPY:
|
||||
{
|
||||
frame_ip += 2;
|
||||
if (!aot_compile_op_memory_copy(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case WASM_OP_MEMORY_FILL:
|
||||
{
|
||||
frame_ip ++;
|
||||
if (!aot_compile_op_memory_fill(comp_ctx, func_ctx))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
#endif /* WASM_ENABLE_BULK_MEMORY */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -124,8 +124,18 @@ get_mem_init_data_size(AOTMemInitData *mem_init_data)
|
|||
{
|
||||
/* init expr type (4 bytes) + init expr value (8 bytes)
|
||||
+ byte count (4 bytes) + bytes */
|
||||
return (uint32)(sizeof(uint32) + sizeof(uint64)
|
||||
+ sizeof(uint32) + mem_init_data->byte_count);
|
||||
uint32 total_size =
|
||||
(uint32)(sizeof(uint32) + sizeof(uint64)
|
||||
+ sizeof(uint32) + mem_init_data->byte_count);
|
||||
|
||||
/* bulk_memory enabled:
|
||||
is_passive (4 bytes) + memory_index (4 bytes)
|
||||
bulk memory disabled:
|
||||
placeholder (4 bytes) + placeholder (4 bytes)
|
||||
*/
|
||||
total_size += (sizeof(uint32) + sizeof(uint32));
|
||||
|
||||
return total_size;
|
||||
}
|
||||
|
||||
static uint32
|
||||
|
@ -682,7 +692,8 @@ get_relocation_section_size(AOTObjectData *obj_data)
|
|||
}
|
||||
|
||||
static uint32
|
||||
get_aot_file_size(AOTCompData *comp_data, AOTObjectData *obj_data)
|
||||
get_aot_file_size(AOTCompContext *comp_ctx, AOTCompData *comp_data,
|
||||
AOTObjectData *obj_data)
|
||||
{
|
||||
uint32 size = 0;
|
||||
|
||||
|
@ -868,7 +879,8 @@ aot_emit_target_info_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
|
|||
|
||||
static bool
|
||||
aot_emit_mem_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
|
||||
AOTCompData *comp_data, AOTObjectData *obj_data)
|
||||
AOTCompContext *comp_ctx, AOTCompData *comp_data,
|
||||
AOTObjectData *obj_data)
|
||||
{
|
||||
uint32 offset = *p_offset, i;
|
||||
AOTMemInitData **init_datas = comp_data->mem_init_data_list;
|
||||
|
@ -882,6 +894,18 @@ aot_emit_mem_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
|
|||
|
||||
for (i = 0; i < comp_data->mem_init_data_count; i++) {
|
||||
offset = align_uint(offset, 4);
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
if (comp_ctx->enable_bulk_memory) {
|
||||
EMIT_U32(init_datas[i]->is_passive);
|
||||
EMIT_U32(init_datas[i]->memory_index);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* emit two placeholder to keep the same size */
|
||||
EMIT_U32(0);
|
||||
EMIT_U32(0);
|
||||
}
|
||||
EMIT_U32(init_datas[i]->offset.init_expr_type);
|
||||
EMIT_U64(init_datas[i]->offset.u.i64);
|
||||
EMIT_U32(init_datas[i]->byte_count);
|
||||
|
@ -1077,7 +1101,8 @@ aot_emit_object_data_section_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
|
|||
|
||||
static bool
|
||||
aot_emit_init_data_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
|
||||
AOTCompData *comp_data, AOTObjectData *obj_data)
|
||||
AOTCompContext *comp_ctx, AOTCompData *comp_data,
|
||||
AOTObjectData *obj_data)
|
||||
{
|
||||
uint32 section_size = get_init_data_section_size(comp_data, obj_data);
|
||||
uint32 offset = *p_offset;
|
||||
|
@ -1087,7 +1112,7 @@ aot_emit_init_data_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
|
|||
EMIT_U32(AOT_SECTION_TYPE_INIT_DATA);
|
||||
EMIT_U32(section_size);
|
||||
|
||||
if (!aot_emit_mem_info(buf, buf_end, &offset, comp_data, obj_data)
|
||||
if (!aot_emit_mem_info(buf, buf_end, &offset, comp_ctx, comp_data, obj_data)
|
||||
|| !aot_emit_table_info(buf, buf_end, &offset, comp_data, obj_data)
|
||||
|| !aot_emit_func_type_info(buf, buf_end, &offset, comp_data, obj_data)
|
||||
|| !aot_emit_import_global_info(buf, buf_end, &offset, comp_data, obj_data)
|
||||
|
@ -1405,7 +1430,8 @@ aot_resolve_target_info(AOTCompContext *comp_ctx, AOTObjectData *obj_data)
|
|||
|
||||
obj_data->target_info.bin_type = bin_type - LLVMBinaryTypeELF32L;
|
||||
|
||||
if (bin_type == LLVMBinaryTypeELF32L || bin_type == LLVMBinaryTypeELF32B) {
|
||||
if (bin_type == LLVMBinaryTypeELF32L
|
||||
|| bin_type == LLVMBinaryTypeELF32B) {
|
||||
struct elf32_ehdr *elf_header;
|
||||
bool is_little_bin = bin_type == LLVMBinaryTypeELF32L;
|
||||
|
||||
|
@ -1420,7 +1446,8 @@ aot_resolve_target_info(AOTCompContext *comp_ctx, AOTObjectData *obj_data)
|
|||
SET_TARGET_INFO(e_version, e_version, uint32, is_little_bin);
|
||||
SET_TARGET_INFO(e_flags, e_flags, uint32, is_little_bin);
|
||||
}
|
||||
else {
|
||||
else if (bin_type == LLVMBinaryTypeELF64L
|
||||
|| bin_type == LLVMBinaryTypeELF64B) {
|
||||
struct elf64_ehdr *elf_header;
|
||||
bool is_little_bin = bin_type == LLVMBinaryTypeELF64L;
|
||||
|
||||
|
@ -1435,6 +1462,19 @@ aot_resolve_target_info(AOTCompContext *comp_ctx, AOTObjectData *obj_data)
|
|||
SET_TARGET_INFO(e_version, e_version, uint32, is_little_bin);
|
||||
SET_TARGET_INFO(e_flags, e_flags, uint32, is_little_bin);
|
||||
}
|
||||
else if (bin_type == LLVMBinaryTypeMachO32L
|
||||
|| bin_type == LLVMBinaryTypeMachO32B) {
|
||||
/* TODO: parse file type of Mach-O 32 */
|
||||
aot_set_last_error("invaid llvm binary bin_type.");
|
||||
return false;
|
||||
}
|
||||
else if (bin_type == LLVMBinaryTypeMachO64L
|
||||
|| bin_type == LLVMBinaryTypeMachO64B) {
|
||||
/* TODO: parse file type of Mach-O 64 */
|
||||
aot_set_last_error("invaid llvm binary bin_type.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
strncpy(obj_data->target_info.arch, comp_ctx->target_arch,
|
||||
sizeof(obj_data->target_info.arch));
|
||||
|
@ -1941,7 +1981,7 @@ aot_emit_aot_file(AOTCompContext *comp_ctx, AOTCompData *comp_data,
|
|||
|
||||
bh_print_time("Begin to emit AOT file");
|
||||
|
||||
aot_file_size = get_aot_file_size(comp_data, obj_data);
|
||||
aot_file_size = get_aot_file_size(comp_ctx, comp_data, obj_data);
|
||||
|
||||
if (!(buf = aot_file_buf = wasm_runtime_malloc(aot_file_size))) {
|
||||
aot_set_last_error("allocate memory failed.");
|
||||
|
@ -1953,7 +1993,7 @@ aot_emit_aot_file(AOTCompContext *comp_ctx, AOTCompData *comp_data,
|
|||
|
||||
if (!aot_emit_file_header(buf, buf_end, &offset, comp_data, obj_data)
|
||||
|| !aot_emit_target_info_section(buf, buf_end, &offset, comp_data, obj_data)
|
||||
|| !aot_emit_init_data_section(buf, buf_end, &offset, comp_data, obj_data)
|
||||
|| !aot_emit_init_data_section(buf, buf_end, &offset, comp_ctx, comp_data, obj_data)
|
||||
|| !aot_emit_text_section(buf, buf_end, &offset, comp_data, obj_data)
|
||||
|| !aot_emit_func_section(buf, buf_end, &offset, comp_data, obj_data)
|
||||
|| !aot_emit_export_section(buf, buf_end, &offset, comp_data, obj_data)
|
||||
|
|
|
@ -626,3 +626,290 @@ fail:
|
|||
return false;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
|
||||
static LLVMValueRef
|
||||
check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
LLVMValueRef offset, LLVMValueRef bytes)
|
||||
{
|
||||
LLVMValueRef maddr, max_addr, cmp;
|
||||
LLVMValueRef mem_base_addr;
|
||||
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
LLVMBasicBlockRef check_succ;
|
||||
uint32 off = offsetof(AOTModuleInstance, memory_data_size);
|
||||
LLVMValueRef mem_size_offset, mem_size_ptr, mem_size;
|
||||
|
||||
/* Get memory base address and memory data size */
|
||||
if (func_ctx->mem_space_unchanged) {
|
||||
mem_base_addr = func_ctx->mem_base_addr;
|
||||
}
|
||||
else {
|
||||
if (!(mem_base_addr = LLVMBuildLoad(comp_ctx->builder,
|
||||
func_ctx->mem_base_addr,
|
||||
"mem_base"))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* return addres directly if constant offset and inside memory space */
|
||||
if (LLVMIsConstant(offset) && LLVMIsConstant(bytes)) {
|
||||
uint64 mem_offset = (uint64)LLVMConstIntGetZExtValue(offset);
|
||||
uint64 mem_len = (uint64)LLVMConstIntGetZExtValue(bytes);
|
||||
uint32 num_bytes_per_page = comp_ctx->comp_data->num_bytes_per_page;
|
||||
uint32 init_page_count = comp_ctx->comp_data->mem_init_page_count;
|
||||
uint32 mem_data_size = num_bytes_per_page * init_page_count;
|
||||
if (mem_data_size > 0
|
||||
&& mem_offset + mem_len <= mem_data_size) {
|
||||
/* inside memory space */
|
||||
/* maddr = mem_base_addr + moffset */
|
||||
if (!(maddr = LLVMBuildInBoundsGEP(comp_ctx->builder,
|
||||
mem_base_addr,
|
||||
&offset, 1, "maddr"))) {
|
||||
aot_set_last_error("llvm build add failed.");
|
||||
goto fail;
|
||||
}
|
||||
return maddr;
|
||||
}
|
||||
}
|
||||
|
||||
/* mem_size_offset = aot_inst + off */
|
||||
mem_size_offset = I32_CONST(off);
|
||||
if (!(mem_size_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder,
|
||||
func_ctx->aot_inst,
|
||||
&mem_size_offset, 1,
|
||||
"mem_size_ptr_tmp"))) {
|
||||
aot_set_last_error("llvm build inbounds gep failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* cast to int32* */
|
||||
if (!(mem_size_ptr = LLVMBuildBitCast(comp_ctx->builder, mem_size_ptr,
|
||||
INT32_PTR_TYPE, "mem_size_ptr"))) {
|
||||
aot_set_last_error("llvm build bitcast failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* load memory size */
|
||||
if (!(mem_size = LLVMBuildLoad(comp_ctx->builder,
|
||||
mem_size_ptr, "mem_size"))) {
|
||||
aot_set_last_error("llvm build load failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ADD_BASIC_BLOCK(check_succ, "check_succ");
|
||||
LLVMMoveBasicBlockAfter(check_succ, block_curr);
|
||||
|
||||
offset = LLVMBuildZExt(comp_ctx->builder, offset, I64_TYPE, "extend_offset");
|
||||
bytes = LLVMBuildZExt(comp_ctx->builder, bytes, I64_TYPE, "extend_len");
|
||||
mem_size = LLVMBuildZExt(comp_ctx->builder, mem_size, I64_TYPE, "extend_size");
|
||||
|
||||
BUILD_OP(Add, offset, bytes, max_addr, "max_addr");
|
||||
BUILD_ICMP(LLVMIntUGT, max_addr, mem_size, cmp,
|
||||
"cmp_max_mem_addr");
|
||||
if (!aot_emit_exception(comp_ctx, func_ctx,
|
||||
EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS,
|
||||
true, cmp, check_succ)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* maddr = mem_base_addr + offset */
|
||||
if (!(maddr = LLVMBuildInBoundsGEP(comp_ctx->builder, mem_base_addr,
|
||||
&offset, 1, "maddr"))) {
|
||||
aot_set_last_error("llvm build add failed.");
|
||||
goto fail;
|
||||
}
|
||||
return maddr;
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define GET_AOT_FUNCTION(name, argc) do { \
|
||||
if (!(func_type = LLVMFunctionType(ret_type, param_types, \
|
||||
argc, false))) { \
|
||||
aot_set_last_error("llvm add function type failed."); \
|
||||
return false; \
|
||||
} \
|
||||
if (comp_ctx->is_jit_mode) { \
|
||||
/* JIT mode, call the function directly */ \
|
||||
if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { \
|
||||
aot_set_last_error("llvm add pointer type failed."); \
|
||||
return false; \
|
||||
} \
|
||||
if (!(value = I64_CONST((uint64)(uintptr_t)name)) \
|
||||
|| !(func = LLVMConstIntToPtr(value, func_ptr_type))) { \
|
||||
aot_set_last_error("create LLVM value failed."); \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
char *func_name = #name; \
|
||||
/* AOT mode, delcare the function */ \
|
||||
if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name)) \
|
||||
&& !(func = LLVMAddFunction(comp_ctx->module, \
|
||||
func_name, func_type))) { \
|
||||
aot_set_last_error("llvm add function failed."); \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
bool
|
||||
aot_compile_op_memory_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 seg_index)
|
||||
{
|
||||
LLVMValueRef seg, offset, dst, len, param_values[5], ret_value, func, value;
|
||||
LLVMTypeRef param_types[5], ret_type, func_type, func_ptr_type;
|
||||
AOTFuncType *aot_func_type = func_ctx->aot_func->func_type;
|
||||
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
LLVMBasicBlockRef mem_init_fail, init_success;
|
||||
|
||||
seg = I32_CONST(seg_index);
|
||||
|
||||
POP_I32(len);
|
||||
POP_I32(offset);
|
||||
POP_I32(dst);
|
||||
|
||||
param_types[0] = INT8_PTR_TYPE;
|
||||
param_types[1] = I32_TYPE;
|
||||
param_types[2] = I32_TYPE;
|
||||
param_types[3] = I32_TYPE;
|
||||
param_types[4] = I32_TYPE;
|
||||
ret_type = INT8_TYPE;
|
||||
|
||||
GET_AOT_FUNCTION(aot_memory_init, 5);
|
||||
|
||||
/* Call function aot_memory_init() */
|
||||
param_values[0] = func_ctx->aot_inst;
|
||||
param_values[1] = seg;
|
||||
param_values[2] = offset;
|
||||
param_values[3] = len;
|
||||
param_values[4] = dst;
|
||||
if (!(ret_value = LLVMBuildCall(comp_ctx->builder, func,
|
||||
param_values, 5, "call"))) {
|
||||
aot_set_last_error("llvm build call failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
BUILD_ICMP(LLVMIntUGT, ret_value, I8_ZERO, ret_value, "mem_init_ret");
|
||||
|
||||
ADD_BASIC_BLOCK(mem_init_fail, "mem_init_fail");
|
||||
ADD_BASIC_BLOCK(init_success, "init_success");
|
||||
|
||||
LLVMMoveBasicBlockAfter(mem_init_fail, block_curr);
|
||||
LLVMMoveBasicBlockAfter(init_success, block_curr);
|
||||
|
||||
if (!LLVMBuildCondBr(comp_ctx->builder, ret_value,
|
||||
init_success, mem_init_fail)) {
|
||||
aot_set_last_error("llvm build cond br failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* If memory.init failed, return this function
|
||||
so the runtime can catch the exception */
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, mem_init_fail);
|
||||
if (aot_func_type->result_count) {
|
||||
switch (aot_func_type->types[aot_func_type->param_count]) {
|
||||
case VALUE_TYPE_I32:
|
||||
LLVMBuildRet(comp_ctx->builder, I32_ZERO);
|
||||
break;
|
||||
case VALUE_TYPE_I64:
|
||||
LLVMBuildRet(comp_ctx->builder, I64_ZERO);
|
||||
break;
|
||||
case VALUE_TYPE_F32:
|
||||
LLVMBuildRet(comp_ctx->builder, F32_ZERO);
|
||||
break;
|
||||
case VALUE_TYPE_F64:
|
||||
LLVMBuildRet(comp_ctx->builder, F64_ZERO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LLVMBuildRetVoid(comp_ctx->builder);
|
||||
}
|
||||
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, init_success);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_data_drop(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 seg_index)
|
||||
{
|
||||
LLVMValueRef seg, param_values[2], ret_value, func, value;
|
||||
LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
|
||||
|
||||
seg = I32_CONST(seg_index);
|
||||
|
||||
param_types[0] = INT8_PTR_TYPE;
|
||||
param_types[1] = I32_TYPE;
|
||||
ret_type = INT8_TYPE;
|
||||
|
||||
GET_AOT_FUNCTION(aot_data_drop, 2);
|
||||
|
||||
/* Call function aot_data_drop() */
|
||||
param_values[0] = func_ctx->aot_inst;
|
||||
param_values[1] = seg;
|
||||
if (!(ret_value = LLVMBuildCall(comp_ctx->builder, func,
|
||||
param_values, 2, "call"))) {
|
||||
aot_set_last_error("llvm build call failed.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMValueRef src, dst, src_addr, dst_addr, len, res;
|
||||
|
||||
POP_I32(len);
|
||||
POP_I32(src);
|
||||
POP_I32(dst);
|
||||
|
||||
if (!(src_addr =
|
||||
check_bulk_memory_overflow(comp_ctx, func_ctx, src, len)))
|
||||
return false;
|
||||
|
||||
if (!(dst_addr =
|
||||
check_bulk_memory_overflow(comp_ctx, func_ctx, dst, len)))
|
||||
return false;
|
||||
|
||||
if (!(res = LLVMBuildMemMove(comp_ctx->builder, dst_addr, 1,
|
||||
src_addr, 1, len))) {
|
||||
aot_set_last_error("llvm build memmove failed.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_memory_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMValueRef val, dst, dst_addr, len, res;
|
||||
|
||||
POP_I32(len);
|
||||
POP_I32(val);
|
||||
POP_I32(dst);
|
||||
|
||||
if (!(dst_addr =
|
||||
check_bulk_memory_overflow(comp_ctx, func_ctx, dst, len)))
|
||||
return false;
|
||||
|
||||
val = LLVMBuildIntCast2(comp_ctx->builder, val, INT8_TYPE, true, "mem_set_value");
|
||||
|
||||
if (!(res = LLVMBuildMemSet(comp_ctx->builder, dst_addr,
|
||||
val, len, 1))) {
|
||||
aot_set_last_error("llvm build memset failed.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
#endif /* WASM_ENABLE_BULK_MEMORY */
|
||||
|
|
|
@ -50,6 +50,22 @@ aot_compile_op_memory_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
|||
bool
|
||||
aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
bool
|
||||
aot_compile_op_memory_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 seg_index);
|
||||
|
||||
bool
|
||||
aot_compile_op_data_drop(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 seg_index);
|
||||
|
||||
bool
|
||||
aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_memory_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
|
|
@ -914,6 +914,9 @@ aot_create_comp_context(AOTCompData *comp_data,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (option->enable_bulk_memory)
|
||||
comp_ctx->enable_bulk_memory = true;
|
||||
|
||||
if (option->is_jit_mode) {
|
||||
/* Create LLVM execution engine */
|
||||
LLVMInitializeMCJITCompilerOptions(&jit_options, sizeof(jit_options));
|
||||
|
|
|
@ -185,6 +185,9 @@ typedef struct AOTCompContext {
|
|||
LLVMExecutionEngineRef exec_engine;
|
||||
bool is_jit_mode;
|
||||
|
||||
/* Bulk memory feature */
|
||||
bool enable_bulk_memory;
|
||||
|
||||
/* Whether optimize the JITed code */
|
||||
bool optimize;
|
||||
|
||||
|
@ -223,6 +226,7 @@ typedef struct AOTCompOption{
|
|||
char *target_abi;
|
||||
char *target_cpu;
|
||||
char *cpu_features;
|
||||
bool enable_bulk_memory;
|
||||
uint32 opt_level;
|
||||
uint32 size_level;
|
||||
uint32 output_format;
|
||||
|
|
|
@ -39,6 +39,7 @@ typedef struct AOTCompOption{
|
|||
char *target_abi;
|
||||
char *target_cpu;
|
||||
char *cpu_features;
|
||||
bool enable_bulk_memory;
|
||||
uint32_t opt_level;
|
||||
uint32_t size_level;
|
||||
uint32_t output_format;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#ifndef _LIB_EXPORT_H_
|
||||
#define _LIB_EXPORT_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#ifndef _WASM_EXPORT_H
|
||||
#define _WASM_EXPORT_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "lib_export.h"
|
||||
|
||||
|
@ -178,6 +178,56 @@ void wasm_runtime_free(void *ptr);
|
|||
package_type_t
|
||||
get_package_type(const uint8_t *buf, uint32_t size);
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
/**
|
||||
* It is a callback for WAMR providing by embedding to load a module file
|
||||
* into a buffer
|
||||
*/
|
||||
typedef bool (*module_reader)(const char *module_name,
|
||||
uint8_t **p_buffer, uint32_t *p_size);
|
||||
|
||||
/**
|
||||
* It is a callback for WAMR providing by embedding to release the buffer which
|
||||
* is used by loading a module file
|
||||
*/
|
||||
typedef void (*module_destroyer)(uint8_t *buffer, uint32_t size);
|
||||
|
||||
/**
|
||||
* To setup callbacks for reading and releasing a buffer about a module file
|
||||
*
|
||||
* @param reader a callback to read a module file into a buffer
|
||||
* @param destroyer a callback to release above buffer
|
||||
*/
|
||||
void
|
||||
wasm_runtime_set_module_reader(const module_reader reader,
|
||||
const module_destroyer destroyer);
|
||||
/**
|
||||
* Give the "module" a name "module_name".
|
||||
* can not assign a new name to a module if it already has a name
|
||||
*
|
||||
* @param module_name indicate a name
|
||||
* @param module the target module
|
||||
* @param error_buf output of the exception info
|
||||
* @param error_buf_size the size of the exception string
|
||||
*
|
||||
* @return true means success, false means failed
|
||||
*/
|
||||
bool
|
||||
wasm_runtime_register_module(const char *module_name, wasm_module_t module,
|
||||
char *error_buf, uint32_t error_buf_size);
|
||||
|
||||
/**
|
||||
* To check if there is already a loaded module named module_name in the
|
||||
* runtime. you will not want to load repeately
|
||||
*
|
||||
* @param module_name indicate a name
|
||||
*
|
||||
* @return return WASM module loaded, NULL if failed
|
||||
*/
|
||||
wasm_module_t
|
||||
wasm_runtime_find_module_registered(const char *module_name);
|
||||
#endif /* WASM_ENABLE_MULTI_MODULE */
|
||||
|
||||
/**
|
||||
* Load a WASM module from a specified byte buffer. The byte buffer can be
|
||||
* WASM binary data when interpreter or JIT is enabled, or AOT binary data
|
||||
|
@ -348,7 +398,9 @@ wasm_application_execute_main(wasm_module_inst_t module_inst,
|
|||
* and execute that function.
|
||||
*
|
||||
* @param module_inst the WASM module instance
|
||||
* @param name the name of the function to execute
|
||||
* @param name the name of the function to execute.
|
||||
* to indicate the module name via: $module_name$function_name
|
||||
* or just a function name: function_name
|
||||
* @param argc the number of arguments
|
||||
* @param argv the arguments array
|
||||
*
|
||||
|
|
|
@ -22,6 +22,8 @@ extern "C" {
|
|||
#define VALUE_TYPE_VOID 0x40
|
||||
/* Used by AOT */
|
||||
#define VALUE_TYPE_I1 0x41
|
||||
/* Used by loader to represent any type of i32/i64/f32/f64 */
|
||||
#define VALUE_TYPE_ANY 0x42
|
||||
|
||||
/* Table Element Type */
|
||||
#define TABLE_ELEM_TYPE_ANY_FUNC 0x70
|
||||
|
@ -50,6 +52,9 @@ extern "C" {
|
|||
#define SECTION_TYPE_ELEM 9
|
||||
#define SECTION_TYPE_CODE 10
|
||||
#define SECTION_TYPE_DATA 11
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
#define SECTION_TYPE_DATACOUNT 12
|
||||
#endif
|
||||
|
||||
#define IMPORT_KIND_FUNC 0
|
||||
#define IMPORT_KIND_TABLE 1
|
||||
|
@ -66,6 +71,10 @@ extern "C" {
|
|||
#define BLOCK_TYPE_IF 2
|
||||
#define BLOCK_TYPE_FUNCTION 3
|
||||
|
||||
typedef struct WASMModule WASMModule;
|
||||
typedef struct WASMFunction WASMFunction;
|
||||
typedef struct WASMGlobal WASMGlobal;
|
||||
|
||||
typedef union WASMValue {
|
||||
int32 i32;
|
||||
uint32 u32;
|
||||
|
@ -119,6 +128,10 @@ typedef struct WASMTableImport {
|
|||
uint32 init_size;
|
||||
/* specified if (flags & 1), else it is 0x10000 */
|
||||
uint32 max_size;
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
WASMModule *import_module;
|
||||
WASMTable *import_table_linked;
|
||||
#endif
|
||||
} WASMTableImport;
|
||||
|
||||
typedef struct WASMMemoryImport {
|
||||
|
@ -128,6 +141,10 @@ typedef struct WASMMemoryImport {
|
|||
uint32 num_bytes_per_page;
|
||||
uint32 init_page_count;
|
||||
uint32 max_page_count;
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
WASMModule *import_module;
|
||||
WASMMemory *import_memory_linked;
|
||||
#endif
|
||||
} WASMMemoryImport;
|
||||
|
||||
typedef struct WASMFunctionImport {
|
||||
|
@ -135,13 +152,17 @@ typedef struct WASMFunctionImport {
|
|||
char *field_name;
|
||||
/* function type */
|
||||
WASMType *func_type;
|
||||
/* function pointer after linked */
|
||||
/* native function pointer after linked */
|
||||
void *func_ptr_linked;
|
||||
/* signature from registered native symbols */
|
||||
const char *signature;
|
||||
/* attachment */
|
||||
void *attachment;
|
||||
bool call_conv_raw;
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
WASMModule *import_module;
|
||||
WASMFunction *import_func_linked;
|
||||
#endif
|
||||
} WASMFunctionImport;
|
||||
|
||||
typedef struct WASMGlobalImport {
|
||||
|
@ -151,6 +172,12 @@ typedef struct WASMGlobalImport {
|
|||
bool is_mutable;
|
||||
/* global data after linked */
|
||||
WASMValue global_data_linked;
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
/* imported function pointer after linked */
|
||||
// TODO: remove if not necessary
|
||||
WASMModule *import_module;
|
||||
WASMGlobal *import_global_linked;
|
||||
#endif
|
||||
} WASMGlobalImport;
|
||||
|
||||
typedef struct WASMImport {
|
||||
|
@ -223,6 +250,9 @@ typedef struct WASMDataSeg {
|
|||
uint32 memory_index;
|
||||
InitializerExpression base_offset;
|
||||
uint32 data_length;
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
bool is_passive;
|
||||
#endif
|
||||
uint8 *data;
|
||||
} WASMDataSeg;
|
||||
|
||||
|
@ -266,7 +296,12 @@ typedef struct WASMModule {
|
|||
uint32 global_count;
|
||||
uint32 export_count;
|
||||
uint32 table_seg_count;
|
||||
/* data seg count read from data segment section */
|
||||
uint32 data_seg_count;
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
/* data count read from datacount section */
|
||||
uint32 data_seg_count1;
|
||||
#endif
|
||||
|
||||
uint32 import_function_count;
|
||||
uint32 import_table_count;
|
||||
|
@ -308,6 +343,12 @@ typedef struct WASMModule {
|
|||
WASIArguments wasi_args;
|
||||
bool is_wasi_module;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
// TODO: mutex ? mutli-threads ?
|
||||
bh_list import_module_list_head;
|
||||
bh_list *import_module_list;
|
||||
#endif
|
||||
} WASMModule;
|
||||
|
||||
typedef struct WASMBranchBlock {
|
||||
|
@ -430,5 +471,4 @@ wasm_type_equal(const WASMType *type1, const WASMType *type2)
|
|||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _WASM_H_ */
|
||||
|
||||
#endif /* end of _WASM_H_ */
|
|
@ -236,6 +236,15 @@ LOAD_I16(void *addr)
|
|||
goto out_of_bounds; \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) do { \
|
||||
uint64 offset1 = (int32)(start); \
|
||||
if (offset1 + bytes <= linear_mem_size) \
|
||||
/* App heap space is not valid space for bulk memory operation */ \
|
||||
maddr = memory->memory_data + offset1; \
|
||||
else \
|
||||
goto out_of_bounds; \
|
||||
} while (0)
|
||||
|
||||
static inline uint32
|
||||
rotl32(uint32 n, uint32 c)
|
||||
{
|
||||
|
@ -877,6 +886,59 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
|
|||
wasm_exec_env_set_cur_frame(exec_env, prev_frame);
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
static void
|
||||
wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
WASMExecEnv *exec_env,
|
||||
WASMFunctionInstance *cur_func,
|
||||
WASMInterpFrame *prev_frame);
|
||||
|
||||
static void
|
||||
wasm_interp_call_func_import(WASMModuleInstance *module_inst,
|
||||
WASMExecEnv *exec_env,
|
||||
WASMFunctionInstance *cur_func,
|
||||
WASMInterpFrame *prev_frame)
|
||||
{
|
||||
WASMModuleInstance *sub_module_inst = cur_func->import_module_inst;
|
||||
WASMFunctionInstance *sub_func_inst = cur_func->import_func_inst;
|
||||
WASMFunctionImport *func_import = cur_func->u.func_import;
|
||||
uint8 *ip = prev_frame->ip;
|
||||
char buf[128];
|
||||
|
||||
if (!sub_func_inst) {
|
||||
snprintf(buf, sizeof(buf),
|
||||
"fail to call unlinked import function (%s, %s)",
|
||||
func_import->module_name, func_import->field_name);
|
||||
wasm_set_exception(module_inst, buf);
|
||||
return;
|
||||
}
|
||||
|
||||
/* set ip NULL to make call_func_bytecode return after executing
|
||||
this function */
|
||||
prev_frame->ip = NULL;
|
||||
|
||||
/* replace exec_env's module_inst with sub_module_inst so we can
|
||||
call it */
|
||||
exec_env->module_inst = (WASMModuleInstanceCommon *)sub_module_inst;
|
||||
|
||||
/* call function of sub-module*/
|
||||
wasm_interp_call_func_bytecode(sub_module_inst, exec_env,
|
||||
sub_func_inst, prev_frame);
|
||||
|
||||
/* restore ip and module_inst */
|
||||
prev_frame->ip = ip;
|
||||
exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
|
||||
|
||||
/* transfer exception if it is thrown */
|
||||
if (wasm_get_exception(sub_module_inst)) {
|
||||
bh_memcpy_s(module_inst->cur_exception,
|
||||
sizeof(module_inst->cur_exception),
|
||||
sub_module_inst->cur_exception,
|
||||
sizeof(sub_module_inst->cur_exception));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_LABELS_AS_VALUES != 0
|
||||
|
||||
#define HANDLE_OP(opcode) HANDLE_##opcode
|
||||
|
@ -902,6 +964,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
uint32 total_mem_size = memory ? num_bytes_per_page * memory->cur_page_count
|
||||
- heap_base_offset : 0;
|
||||
uint8 *global_data = module->global_data;
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0;
|
||||
#endif
|
||||
WASMTableInstance *table = module->default_table;
|
||||
WASMGlobalInstance *globals = module->globals;
|
||||
uint8 opcode_IMPDEP = WASM_OP_IMPDEP;
|
||||
|
@ -1086,14 +1151,27 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
|
||||
HANDLE_OP (WASM_OP_CALL):
|
||||
read_leb_uint32(frame_ip, frame_ip_end, fidx);
|
||||
bh_assert(fidx < module->function_count);
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
if (fidx >= module->function_count) {
|
||||
wasm_set_exception(module, "unknown function");
|
||||
goto got_exception;
|
||||
}
|
||||
#endif
|
||||
|
||||
cur_func = module->functions + fidx;
|
||||
goto call_func_from_interp;
|
||||
|
||||
HANDLE_OP (WASM_OP_CALL_INDIRECT):
|
||||
{
|
||||
WASMType *cur_type, *cur_func_type;
|
||||
WASMTableInstance *cur_table_inst;
|
||||
|
||||
/**
|
||||
* type check. compiler will make sure all like
|
||||
* (call_indirect (type $x) (i32.const 1))
|
||||
* the function type has to be defined in the module also
|
||||
* no matter it is used or not
|
||||
*/
|
||||
read_leb_uint32(frame_ip, frame_ip_end, tidx);
|
||||
if (tidx >= module->module->type_count) {
|
||||
wasm_set_exception(module, "type index is overflow");
|
||||
|
@ -1105,27 +1183,48 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
frame_ip++;
|
||||
val = POP_I32();
|
||||
|
||||
if (val < 0 || val >= (int32)table->cur_size) {
|
||||
/* careful, it might be a table in another module */
|
||||
cur_table_inst = table;
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
if (table->table_inst_linked) {
|
||||
cur_table_inst = table->table_inst_linked;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (val < 0 || val >= (int32)cur_table_inst->cur_size) {
|
||||
wasm_set_exception(module, "undefined element");
|
||||
goto got_exception;
|
||||
}
|
||||
|
||||
fidx = ((uint32*)table->base_addr)[val];
|
||||
fidx = ((uint32*)cur_table_inst->base_addr)[val];
|
||||
if (fidx == (uint32)-1) {
|
||||
wasm_set_exception(module, "uninitialized element");
|
||||
goto got_exception;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
if (fidx >= module->function_count) {
|
||||
wasm_set_exception(module, "unknown function");
|
||||
goto got_exception;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* always call module own functions */
|
||||
cur_func = module->functions + fidx;
|
||||
|
||||
if (cur_func->is_import_func)
|
||||
cur_func_type = cur_func->u.func_import->func_type;
|
||||
if (cur_func->is_import_func
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
&& !cur_func->import_func_inst
|
||||
#endif
|
||||
)
|
||||
cur_func_type = cur_func->u.func_import->func_type;
|
||||
else
|
||||
cur_func_type = cur_func->u.func->func_type;
|
||||
if (!wasm_type_equal(cur_type, cur_func_type)) {
|
||||
wasm_set_exception(module, "indirect call type mismatch");
|
||||
goto got_exception;
|
||||
}
|
||||
|
||||
goto call_func_from_interp;
|
||||
}
|
||||
|
||||
|
@ -1264,7 +1363,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
|
||||
bh_assert(global_idx < module->global_count);
|
||||
global = globals + global_idx;
|
||||
global_addr = global_data + global->data_offset;
|
||||
global_addr =
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
global->import_global_inst
|
||||
? global->import_module_inst->global_data
|
||||
+ global->import_global_inst->data_offset
|
||||
:
|
||||
#endif
|
||||
global_data + global->data_offset;
|
||||
|
||||
switch (global->type) {
|
||||
case VALUE_TYPE_I32:
|
||||
|
@ -1289,7 +1395,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
|
||||
bh_assert(global_idx < module->global_count);
|
||||
global = globals + global_idx;
|
||||
global_addr = global_data + global->data_offset;
|
||||
global_addr =
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
global->import_global_inst
|
||||
? global->import_module_inst->global_data
|
||||
+ global->import_global_inst->data_offset
|
||||
:
|
||||
#endif
|
||||
global_data + global->data_offset;
|
||||
|
||||
switch (global->type) {
|
||||
case VALUE_TYPE_I32:
|
||||
|
@ -1521,6 +1634,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
memory = module->default_memory;
|
||||
total_mem_size = num_bytes_per_page * memory->cur_page_count
|
||||
- heap_base_offset;
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
linear_mem_size = num_bytes_per_page * memory->cur_page_count;
|
||||
#endif
|
||||
}
|
||||
|
||||
(void)reserved;
|
||||
|
@ -2357,6 +2473,78 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
DEF_OP_TRUNC_SAT_F64(-1.0f, 18446744073709551616.0,
|
||||
false, false);
|
||||
break;
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
case WASM_OP_MEMORY_INIT:
|
||||
{
|
||||
uint32 addr, segment;
|
||||
uint64 bytes, offset, seg_len;
|
||||
uint8* data;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, segment);
|
||||
/* skip memory index */
|
||||
frame_ip++;
|
||||
|
||||
bytes = (uint64)(uint32)POP_I32();
|
||||
offset = (uint64)(uint32)POP_I32();
|
||||
addr = (uint32)POP_I32();
|
||||
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr);
|
||||
|
||||
seg_len = (uint64)module->module->data_segments[segment]->data_length;
|
||||
data = module->module->data_segments[segment]->data;
|
||||
if (offset + bytes > seg_len)
|
||||
goto out_of_bounds;
|
||||
|
||||
bh_memcpy_s(maddr, linear_mem_size - addr,
|
||||
data + offset, bytes);
|
||||
break;
|
||||
}
|
||||
case WASM_OP_DATA_DROP:
|
||||
{
|
||||
uint32 segment;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, segment);
|
||||
module->module->data_segments[segment]->data_length = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
case WASM_OP_MEMORY_COPY:
|
||||
{
|
||||
uint32 dst, src, len;
|
||||
uint8 *mdst, *msrc;
|
||||
|
||||
frame_ip += 2;
|
||||
|
||||
len = POP_I32();
|
||||
src = POP_I32();
|
||||
dst = POP_I32();
|
||||
|
||||
CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc);
|
||||
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
|
||||
|
||||
/* allowing the destination and source to overlap */
|
||||
bh_memmove_s(mdst, linear_mem_size - dst,
|
||||
msrc, len);
|
||||
|
||||
break;
|
||||
}
|
||||
case WASM_OP_MEMORY_FILL:
|
||||
{
|
||||
uint32 dst, len;
|
||||
uint8 val, *mdst;
|
||||
frame_ip++;
|
||||
|
||||
len = POP_I32();
|
||||
val = POP_I32();
|
||||
dst = POP_I32();
|
||||
|
||||
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
|
||||
|
||||
memset(mdst, val, len);
|
||||
|
||||
break;
|
||||
}
|
||||
#endif /* WASM_ENABLE_BULK_MEMORY */
|
||||
default:
|
||||
wasm_set_exception(module, "WASM interp failed: unsupported opcode.");
|
||||
goto got_exception;
|
||||
|
@ -2430,14 +2618,25 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
call_func_from_entry:
|
||||
{
|
||||
if (cur_func->is_import_func) {
|
||||
wasm_interp_call_func_native(module, exec_env, cur_func, prev_frame);
|
||||
prev_frame = frame->prev_frame;
|
||||
cur_func = frame->function;
|
||||
UPDATE_ALL_FROM_FRAME();
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
if (cur_func->import_func_inst) {
|
||||
wasm_interp_call_func_import(module, exec_env, cur_func,
|
||||
prev_frame);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
wasm_interp_call_func_native(module, exec_env, cur_func,
|
||||
prev_frame);
|
||||
}
|
||||
|
||||
memory = module->default_memory;
|
||||
if (wasm_get_exception(module))
|
||||
goto got_exception;
|
||||
prev_frame = frame->prev_frame;
|
||||
cur_func = frame->function;
|
||||
UPDATE_ALL_FROM_FRAME();
|
||||
|
||||
memory = module->default_memory;
|
||||
if (wasm_get_exception(module))
|
||||
goto got_exception;
|
||||
}
|
||||
else {
|
||||
WASMFunction *cur_wasm_func = cur_func->u.func;
|
||||
|
@ -2521,6 +2720,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst,
|
|||
WASMFunctionInstance *function,
|
||||
uint32 argc, uint32 argv[])
|
||||
{
|
||||
// TODO: since module_inst = exec_env->module_inst, shall we remove the 1st arg?
|
||||
WASMRuntimeFrame *prev_frame = wasm_exec_env_get_cur_frame(exec_env);
|
||||
WASMInterpFrame *frame, *outs_area;
|
||||
|
||||
|
@ -2559,15 +2759,44 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst,
|
|||
|
||||
wasm_exec_env_set_cur_frame(exec_env, frame);
|
||||
|
||||
if (function->is_import_func)
|
||||
wasm_interp_call_func_native(module_inst, exec_env, function, frame);
|
||||
else
|
||||
if (function->is_import_func) {
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
if (function->import_module_inst) {
|
||||
LOG_DEBUG("it is a function of a sub module");
|
||||
wasm_interp_call_func_import(module_inst,
|
||||
exec_env,
|
||||
function,
|
||||
frame);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
LOG_DEBUG("it is an native function");
|
||||
/* it is a native function */
|
||||
wasm_interp_call_func_native(module_inst,
|
||||
exec_env,
|
||||
function,
|
||||
frame);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG_DEBUG("it is a function of the module itself");
|
||||
wasm_interp_call_func_bytecode(module_inst, exec_env, function, frame);
|
||||
}
|
||||
|
||||
/* Output the return value to the caller */
|
||||
if (!wasm_get_exception(module_inst)) {
|
||||
for (i = 0; i < function->ret_cell_num; i++)
|
||||
for (i = 0; i < function->ret_cell_num; i++) {
|
||||
argv[i] = *(frame->sp + i - function->ret_cell_num);
|
||||
}
|
||||
|
||||
if (function->ret_cell_num) {
|
||||
LOG_DEBUG("first return value argv[0]=%d", argv[0]);
|
||||
} else {
|
||||
LOG_DEBUG("no return value");
|
||||
}
|
||||
} else {
|
||||
LOG_DEBUG("meet an exception %s", wasm_get_exception(module_inst));
|
||||
}
|
||||
|
||||
wasm_exec_env_set_cur_frame(exec_env, prev_frame);
|
||||
|
|
|
@ -238,6 +238,15 @@ LOAD_I16(void *addr)
|
|||
goto out_of_bounds; \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) do { \
|
||||
uint64 offset1 = (int32)(start); \
|
||||
if (offset1 + bytes <= linear_mem_size) \
|
||||
/* App heap space is not valid space for bulk memory operation */ \
|
||||
maddr = memory->memory_data + offset1; \
|
||||
else \
|
||||
goto out_of_bounds; \
|
||||
} while (0)
|
||||
|
||||
static inline uint32
|
||||
rotl32(uint32 n, uint32 c)
|
||||
{
|
||||
|
@ -815,6 +824,59 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
|
|||
wasm_exec_env_set_cur_frame(exec_env, prev_frame);
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
static void
|
||||
wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
WASMExecEnv *exec_env,
|
||||
WASMFunctionInstance *cur_func,
|
||||
WASMInterpFrame *prev_frame);
|
||||
|
||||
static void
|
||||
wasm_interp_call_func_import(WASMModuleInstance *module_inst,
|
||||
WASMExecEnv *exec_env,
|
||||
WASMFunctionInstance *cur_func,
|
||||
WASMInterpFrame *prev_frame)
|
||||
{
|
||||
WASMModuleInstance *sub_module_inst = cur_func->import_module_inst;
|
||||
WASMFunctionInstance *sub_func_inst = cur_func->import_func_inst;
|
||||
WASMFunctionImport *func_import = cur_func->u.func_import;
|
||||
uint8 *ip = prev_frame->ip;
|
||||
char buf[128];
|
||||
|
||||
if (!sub_func_inst) {
|
||||
snprintf(buf, sizeof(buf),
|
||||
"fail to call unlinked import function (%s, %s)",
|
||||
func_import->module_name, func_import->field_name);
|
||||
wasm_set_exception(module_inst, buf);
|
||||
return;
|
||||
}
|
||||
|
||||
/* set ip NULL to make call_func_bytecode return after executing
|
||||
this function */
|
||||
prev_frame->ip = NULL;
|
||||
|
||||
/* replace exec_env's module_inst with sub_module_inst so we can
|
||||
call it */
|
||||
exec_env->module_inst = (WASMModuleInstanceCommon *)sub_module_inst;
|
||||
|
||||
/* call function of sub-module*/
|
||||
wasm_interp_call_func_bytecode(sub_module_inst, exec_env,
|
||||
sub_func_inst, prev_frame);
|
||||
|
||||
/* restore ip and module_inst */
|
||||
prev_frame->ip = ip;
|
||||
exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
|
||||
|
||||
/* transfer exception if it is thrown */
|
||||
if (wasm_get_exception(sub_module_inst)) {
|
||||
bh_memcpy_s(module_inst->cur_exception,
|
||||
sizeof(module_inst->cur_exception),
|
||||
sub_module_inst->cur_exception,
|
||||
sizeof(sub_module_inst->cur_exception));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_OPCODE_COUNTER != 0
|
||||
typedef struct OpcodeInfo {
|
||||
char *name;
|
||||
|
@ -894,6 +956,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
uint32 total_mem_size = memory ? num_bytes_per_page * memory->cur_page_count
|
||||
- heap_base_offset : 0;
|
||||
uint8 *global_data = module->global_data;
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0;
|
||||
#endif
|
||||
WASMTableInstance *table = module->default_table;
|
||||
WASMGlobalInstance *globals = module->globals;
|
||||
uint8 opcode_IMPDEP = WASM_OP_IMPDEP;
|
||||
|
@ -997,6 +1062,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
HANDLE_OP (WASM_OP_CALL_INDIRECT):
|
||||
{
|
||||
WASMType *cur_type, *cur_func_type;
|
||||
WASMTableInstance *cur_table_inst;
|
||||
|
||||
tidx = GET_OPERAND(int32, 0);
|
||||
val = GET_OPERAND(int32, 2);
|
||||
|
@ -1008,21 +1074,41 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
}
|
||||
cur_type = module->module->types[tidx];
|
||||
|
||||
if (val < 0 || val >= (int32)table->cur_size) {
|
||||
/* careful, it might be a table in another module */
|
||||
cur_table_inst = table;
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
if (table->table_inst_linked) {
|
||||
cur_table_inst = table->table_inst_linked;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (val < 0 || val >= (int32)cur_table_inst->cur_size) {
|
||||
wasm_set_exception(module, "undefined element");
|
||||
goto got_exception;
|
||||
}
|
||||
|
||||
fidx = ((uint32*)table->base_addr)[val];
|
||||
fidx = ((uint32*)cur_table_inst->base_addr)[val];
|
||||
if (fidx == (uint32)-1) {
|
||||
wasm_set_exception(module, "uninitialized element");
|
||||
goto got_exception;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
if (fidx >= module->function_count) {
|
||||
wasm_set_exception(module, "unknown function");
|
||||
goto got_exception;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* always call module own functions */
|
||||
cur_func = module->functions + fidx;
|
||||
|
||||
if (cur_func->is_import_func)
|
||||
cur_func_type = cur_func->u.func_import->func_type;
|
||||
if (cur_func->is_import_func
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
&& !cur_func->import_func_inst
|
||||
#endif
|
||||
)
|
||||
cur_func_type = cur_func->u.func_import->func_type;
|
||||
else
|
||||
cur_func_type = cur_func->u.func->func_type;
|
||||
if (!wasm_type_equal(cur_type, cur_func_type)) {
|
||||
|
@ -1115,7 +1201,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
|
||||
bh_assert(global_idx < module->global_count);
|
||||
global = globals + global_idx;
|
||||
global_addr = global_data + global->data_offset;
|
||||
global_addr =
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
global->import_global_inst
|
||||
? global->import_module_inst->global_data
|
||||
+ global->import_global_inst->data_offset
|
||||
:
|
||||
#endif
|
||||
global_data + global->data_offset;
|
||||
|
||||
switch (global->type) {
|
||||
case VALUE_TYPE_I32:
|
||||
|
@ -1141,7 +1234,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
|
||||
bh_assert(global_idx < module->global_count);
|
||||
global = globals + global_idx;
|
||||
global_addr = global_data + global->data_offset;
|
||||
global_addr =
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
global->import_global_inst
|
||||
? global->import_module_inst->global_data
|
||||
+ global->import_global_inst->data_offset
|
||||
:
|
||||
#endif
|
||||
global_data + global->data_offset;
|
||||
|
||||
switch (global->type) {
|
||||
case VALUE_TYPE_I32:
|
||||
|
@ -1429,6 +1529,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
memory = module->default_memory;
|
||||
total_mem_size = num_bytes_per_page * memory->cur_page_count
|
||||
- heap_base_offset;
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
linear_mem_size = num_bytes_per_page * memory->cur_page_count;
|
||||
#endif
|
||||
}
|
||||
|
||||
(void)reserved;
|
||||
|
@ -2295,6 +2398,76 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
DEF_OP_TRUNC_SAT_F64(-1.0, 18446744073709551616.0,
|
||||
false, false);
|
||||
break;
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
case WASM_OP_MEMORY_INIT:
|
||||
{
|
||||
uint32 addr, segment;
|
||||
uint64 bytes, offset, seg_len;
|
||||
uint8* data;
|
||||
|
||||
segment = GET_OPERAND(uint32, 0);
|
||||
frame_ip += 2;
|
||||
|
||||
bytes = (uint64)POP_I32();
|
||||
offset = (uint64)POP_I32();
|
||||
addr = POP_I32();
|
||||
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr);
|
||||
|
||||
seg_len = (uint64)module->module->data_segments[segment]->data_length;
|
||||
data = module->module->data_segments[segment]->data;
|
||||
if (offset + bytes > seg_len)
|
||||
goto out_of_bounds;
|
||||
|
||||
bh_memcpy_s(maddr, linear_mem_size - addr,
|
||||
data + offset, bytes);
|
||||
break;
|
||||
}
|
||||
case WASM_OP_DATA_DROP:
|
||||
{
|
||||
uint32 segment;
|
||||
|
||||
segment = GET_OPERAND(uint32, 0);
|
||||
frame_ip += 2;
|
||||
|
||||
module->module->data_segments[segment]->data_length = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
case WASM_OP_MEMORY_COPY:
|
||||
{
|
||||
uint32 dst, src, len;
|
||||
uint8 *mdst, *msrc;
|
||||
|
||||
len = POP_I32();
|
||||
src = POP_I32();
|
||||
dst = POP_I32();
|
||||
|
||||
CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc);
|
||||
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
|
||||
|
||||
/* allowing the destination and source to overlap */
|
||||
bh_memmove_s(mdst, linear_mem_size - dst,
|
||||
msrc, len);
|
||||
|
||||
break;
|
||||
}
|
||||
case WASM_OP_MEMORY_FILL:
|
||||
{
|
||||
uint32 dst, len;
|
||||
uint8 val, *mdst;
|
||||
|
||||
len = POP_I32();
|
||||
val = POP_I32();
|
||||
dst = POP_I32();
|
||||
|
||||
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
|
||||
|
||||
memset(mdst, val, len);
|
||||
|
||||
break;
|
||||
}
|
||||
#endif /* WASM_ENABLE_BULK_MEMORY */
|
||||
default:
|
||||
wasm_set_exception(module, "WASM interp failed: unsupported opcode.");
|
||||
goto got_exception;
|
||||
|
@ -2310,7 +2483,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
|
||||
HANDLE_OP (WASM_OP_CALL):
|
||||
fidx = frame_lp[GET_OFFSET()];
|
||||
bh_assert(fidx < module->function_count);
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
if (fidx >= module->function_count) {
|
||||
wasm_set_exception(module, "unknown function");
|
||||
goto got_exception;
|
||||
}
|
||||
#endif
|
||||
cur_func = module->functions + fidx;
|
||||
goto call_func_from_interp;
|
||||
|
||||
|
@ -2383,7 +2561,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
GET_OPERAND(int64, (2 * (cur_func->param_count - i - 1)));
|
||||
outs_area->lp += 2;
|
||||
} else {
|
||||
*(outs_area->lp) = GET_OPERAND(int32, (2 * (cur_func->param_count - i - 1)));;
|
||||
*(outs_area->lp) = GET_OPERAND(int32, (2 * (cur_func->param_count - i - 1)));
|
||||
outs_area->lp ++;
|
||||
}
|
||||
}
|
||||
|
@ -2397,14 +2575,25 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
call_func_from_entry:
|
||||
{
|
||||
if (cur_func->is_import_func) {
|
||||
wasm_interp_call_func_native(module, exec_env, cur_func, prev_frame);
|
||||
prev_frame = frame->prev_frame;
|
||||
cur_func = frame->function;
|
||||
UPDATE_ALL_FROM_FRAME();
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
if (cur_func->import_func_inst) {
|
||||
wasm_interp_call_func_import(module, exec_env, cur_func,
|
||||
prev_frame);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
wasm_interp_call_func_native(module, exec_env, cur_func,
|
||||
prev_frame);
|
||||
}
|
||||
|
||||
memory = module->default_memory;
|
||||
if (wasm_get_exception(module))
|
||||
goto got_exception;
|
||||
prev_frame = frame->prev_frame;
|
||||
cur_func = frame->function;
|
||||
UPDATE_ALL_FROM_FRAME();
|
||||
|
||||
memory = module->default_memory;
|
||||
if (wasm_get_exception(module))
|
||||
goto got_exception;
|
||||
}
|
||||
else {
|
||||
WASMFunction *cur_wasm_func = cur_func->u.func;
|
||||
|
@ -2528,10 +2717,28 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst,
|
|||
|
||||
wasm_exec_env_set_cur_frame(exec_env, frame);
|
||||
|
||||
if (function->is_import_func)
|
||||
wasm_interp_call_func_native(module_inst, exec_env, function, frame);
|
||||
else
|
||||
if (function->is_import_func) {
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
if (function->import_module_inst) {
|
||||
LOG_DEBUG("it is a function of a sub module");
|
||||
wasm_interp_call_func_import(module_inst,
|
||||
exec_env,
|
||||
function,
|
||||
frame);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
LOG_DEBUG("it is an native function");
|
||||
wasm_interp_call_func_native(module_inst,
|
||||
exec_env,
|
||||
function,
|
||||
frame);
|
||||
}
|
||||
}
|
||||
else {
|
||||
wasm_interp_call_func_bytecode(module_inst, exec_env, function, frame);
|
||||
}
|
||||
|
||||
/* Output the return value to the caller */
|
||||
if (!wasm_get_exception(module_inst)) {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -262,7 +262,7 @@ typedef enum WASMOpcode {
|
|||
WASM_OP_MISC_PREFIX = 0xfc,
|
||||
} WASMOpcode;
|
||||
|
||||
typedef enum WASMEXTOpcode {
|
||||
typedef enum WASMMiscEXTOpcode {
|
||||
WASM_OP_I32_TRUNC_SAT_S_F32 = 0x00,
|
||||
WASM_OP_I32_TRUNC_SAT_U_F32 = 0x01,
|
||||
WASM_OP_I32_TRUNC_SAT_S_F64 = 0x02,
|
||||
|
@ -271,7 +271,16 @@ typedef enum WASMEXTOpcode {
|
|||
WASM_OP_I64_TRUNC_SAT_U_F32 = 0x05,
|
||||
WASM_OP_I64_TRUNC_SAT_S_F64 = 0x06,
|
||||
WASM_OP_I64_TRUNC_SAT_U_F64 = 0x07,
|
||||
} WASMEXTOpcode;
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
WASM_OP_MEMORY_INIT = 0x08,
|
||||
WASM_OP_DATA_DROP = 0x09,
|
||||
WASM_OP_MEMORY_COPY = 0x0a,
|
||||
WASM_OP_MEMORY_FILL = 0x0b,
|
||||
WASM_OP_TABLE_INIT = 0x0c,
|
||||
WASM_OP_ELEM_DROP = 0x0d,
|
||||
WASM_OP_TABLE_COPY = 0x0e
|
||||
#endif
|
||||
} WASMMiscEXTOpcode;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,6 +15,12 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct WASMModuleInstance WASMModuleInstance;
|
||||
typedef struct WASMFunctionInstance WASMFunctionInstance;
|
||||
typedef struct WASMMemoryInstance WASMMemoryInstance;
|
||||
typedef struct WASMTableInstance WASMTableInstance;
|
||||
typedef struct WASMGlobalInstance WASMGlobalInstance;
|
||||
|
||||
typedef struct WASMMemoryInstance {
|
||||
/* Number bytes per page */
|
||||
uint32 num_bytes_per_page;
|
||||
|
@ -36,6 +42,10 @@ typedef struct WASMMemoryInstance {
|
|||
/* End address of memory */
|
||||
uint8 *end_addr;
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
/* to indicate which module instance create it */
|
||||
WASMModuleInstance *owner;
|
||||
#endif
|
||||
/* Base address, the layout is:
|
||||
heap_data + memory data
|
||||
memory data init size is: num_bytes_per_page * cur_page_count
|
||||
|
@ -52,6 +62,10 @@ typedef struct WASMTableInstance {
|
|||
uint32 cur_size;
|
||||
/* Maximum size */
|
||||
uint32 max_size;
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
/* just for import, keep the reference here */
|
||||
WASMTableInstance *table_inst_linked;
|
||||
#endif
|
||||
/* Base address */
|
||||
uint8 base_addr[1];
|
||||
} WASMTableInstance;
|
||||
|
@ -65,6 +79,11 @@ typedef struct WASMGlobalInstance {
|
|||
uint32 data_offset;
|
||||
/* initial value */
|
||||
WASMValue initial_value;
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
/* just for import, keep the reference here */
|
||||
WASMModuleInstance *import_module_inst;
|
||||
WASMGlobalInstance *import_global_inst;
|
||||
#endif
|
||||
} WASMGlobalInstance;
|
||||
|
||||
typedef struct WASMFunctionInstance {
|
||||
|
@ -93,6 +112,10 @@ typedef struct WASMFunctionInstance {
|
|||
WASMFunctionImport *func_import;
|
||||
WASMFunction *func;
|
||||
} u;
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
WASMModuleInstance *import_module_inst;
|
||||
WASMFunctionInstance *import_func_inst;
|
||||
#endif
|
||||
} WASMFunctionInstance;
|
||||
|
||||
typedef struct WASMExportFuncInstance {
|
||||
|
@ -100,6 +123,23 @@ typedef struct WASMExportFuncInstance {
|
|||
WASMFunctionInstance *function;
|
||||
} WASMExportFuncInstance;
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
typedef struct WASMExportGlobInstance {
|
||||
char *name;
|
||||
WASMGlobalInstance *global;
|
||||
} WASMExportGlobInstance;
|
||||
|
||||
typedef struct WASMExportTabInstance {
|
||||
char *name;
|
||||
WASMTableInstance *table;
|
||||
} WASMExportTabInstance;
|
||||
|
||||
typedef struct WASMExportMemInstance {
|
||||
char *name;
|
||||
WASMMemoryInstance *memory;
|
||||
} WASMExportMemInstance;
|
||||
#endif
|
||||
|
||||
typedef struct WASMModuleInstance {
|
||||
/* Module instance type, for module instance loaded from
|
||||
WASM bytecode binary, this field is Wasm_Module_Bytecode;
|
||||
|
@ -112,13 +152,25 @@ typedef struct WASMModuleInstance {
|
|||
uint32 table_count;
|
||||
uint32 global_count;
|
||||
uint32 function_count;
|
||||
|
||||
uint32 export_func_count;
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
uint32 export_glob_count;
|
||||
uint32 export_mem_count;
|
||||
uint32 export_tab_count;
|
||||
#endif
|
||||
|
||||
WASMMemoryInstance **memories;
|
||||
WASMTableInstance **tables;
|
||||
WASMGlobalInstance *globals;
|
||||
WASMFunctionInstance *functions;
|
||||
|
||||
WASMExportFuncInstance *export_functions;
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
WASMExportGlobInstance *export_globals;
|
||||
WASMExportMemInstance *export_memories;
|
||||
WASMExportTabInstance *export_tables;
|
||||
#endif
|
||||
|
||||
WASMMemoryInstance *default_memory;
|
||||
WASMTableInstance *default_table;
|
||||
|
@ -148,11 +200,26 @@ typedef struct WASMModuleInstance {
|
|||
|
||||
/* Main exec env */
|
||||
WASMExecEnv *main_exec_env;
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
// TODO: mutex ? mutli-threads ?
|
||||
bh_list sub_module_inst_list_head;
|
||||
bh_list *sub_module_inst_list;
|
||||
#endif
|
||||
} WASMModuleInstance;
|
||||
|
||||
struct WASMInterpFrame;
|
||||
typedef struct WASMInterpFrame WASMRuntimeFrame;
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
typedef struct WASMSubModInstNode {
|
||||
bh_list_link l;
|
||||
/* point to a string pool */
|
||||
const char *module_name;
|
||||
WASMModuleInstance *module_inst;
|
||||
} WASMSubModInstNode;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Return the code block of a function.
|
||||
*
|
||||
|
@ -182,10 +249,11 @@ wasm_get_func_code_end(WASMFunctionInstance *func)
|
|||
{
|
||||
#if WASM_ENABLE_FAST_INTERP == 0
|
||||
return func->is_import_func
|
||||
? NULL : func->u.func->code + func->u.func->code_size;
|
||||
? NULL : func->u.func->code + func->u.func->code_size;
|
||||
#else
|
||||
return func->is_import_func
|
||||
? NULL : func->u.func->code_compiled + func->u.func->code_compiled_size;
|
||||
? NULL
|
||||
: func->u.func->code_compiled + func->u.func->code_compiled_size;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -212,6 +280,17 @@ WASMFunctionInstance *
|
|||
wasm_lookup_function(const WASMModuleInstance *module_inst,
|
||||
const char *name, const char *signature);
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
WASMGlobalInstance *
|
||||
wasm_lookup_global(const WASMModuleInstance *module_inst, const char *name);
|
||||
|
||||
WASMMemoryInstance *
|
||||
wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name);
|
||||
|
||||
WASMTableInstance *
|
||||
wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name);
|
||||
#endif
|
||||
|
||||
bool
|
||||
wasm_call_function(WASMExecEnv *exec_env,
|
||||
WASMFunctionInstance *function,
|
||||
|
|
|
@ -1098,7 +1098,7 @@ static NativeSymbol native_symbols_spectest[] = {
|
|||
REG_NATIVE_FUNC(print, "()"),
|
||||
REG_NATIVE_FUNC(print_i32, "(i)"),
|
||||
REG_NATIVE_FUNC(print_i32_f32, "(if)"),
|
||||
REG_NATIVE_FUNC(print_f64_f64, "(fF)"),
|
||||
REG_NATIVE_FUNC(print_f64_f64, "(FF)"),
|
||||
REG_NATIVE_FUNC(print_f32, "(f)"),
|
||||
REG_NATIVE_FUNC(print_f64, "(F)")
|
||||
};
|
||||
|
|
|
@ -11,13 +11,11 @@ os_mmap(void *hint, uint32 size, int prot, int flags)
|
|||
int map_prot = PROT_NONE;
|
||||
int map_flags = MAP_ANONYMOUS | MAP_PRIVATE;
|
||||
uint64 request_size, page_size;
|
||||
uint8 *addr, *addr_aligned;
|
||||
uint8 *addr;
|
||||
uint32 i;
|
||||
|
||||
/* align to 2M if no less than 2M, else align to 4K */
|
||||
page_size = size < 2 * 1024 * 1024 ? 4096 : 2 * 1024 * 1024;
|
||||
page_size = getpagesize();
|
||||
request_size = (size + page_size - 1) & ~(page_size - 1);
|
||||
request_size += page_size;
|
||||
|
||||
if (request_size >= UINT32_MAX)
|
||||
return NULL;
|
||||
|
@ -47,43 +45,25 @@ os_mmap(void *hint, uint32 size, int prot, int flags)
|
|||
if (addr != MAP_FAILED)
|
||||
break;
|
||||
}
|
||||
|
||||
if (addr == MAP_FAILED)
|
||||
return NULL;
|
||||
|
||||
addr_aligned = (uint8*)(uintptr_t)
|
||||
(((uint64)(uintptr_t)addr + page_size - 1) & ~(page_size - 1));
|
||||
|
||||
/* Unmap memory allocated before the aligned base address */
|
||||
if (addr != addr_aligned) {
|
||||
uint32 prefix_size = (uint32)(addr_aligned - addr);
|
||||
munmap(addr, prefix_size);
|
||||
request_size -= prefix_size;
|
||||
}
|
||||
|
||||
/* Unmap memory allocated after the potentially unaligned end */
|
||||
if (size != request_size) {
|
||||
uint32 suffix_size = (uint32)(request_size - size);
|
||||
munmap(addr_aligned + size, suffix_size);
|
||||
request_size -= size;
|
||||
}
|
||||
|
||||
#ifndef __APPLE__
|
||||
if (size >= 2 * 1024 * 1024) {
|
||||
/* Try to use huge page to improve performance */
|
||||
if (!madvise(addr, size, MADV_HUGEPAGE))
|
||||
/* make huge page become effective */
|
||||
memset(addr, 0, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
return addr_aligned;
|
||||
return addr;
|
||||
}
|
||||
|
||||
void
|
||||
os_munmap(void *addr, uint32 size)
|
||||
{
|
||||
if (addr)
|
||||
munmap(addr, size);
|
||||
uint64 page_size = getpagesize();
|
||||
uint64 request_size = (size + page_size - 1) & ~(page_size - 1);
|
||||
|
||||
if (addr) {
|
||||
if (munmap(addr, request_size)) {
|
||||
os_printf("os_munmap error addr:%p, size:0x%lx, errno:%d\n",
|
||||
addr, request_size, errno);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -249,5 +249,4 @@ uint8 *os_thread_get_stack_boundary()
|
|||
#endif
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
}
|
|
@ -82,29 +82,39 @@ int os_vprintf(const char * format, va_list arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void* os_mmap(void *hint, unsigned int size, int prot, int flags)
|
||||
void* os_mmap(void *hint, uint32 size, int prot, int flags)
|
||||
{
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
int mprot = 0;
|
||||
unsigned alignedSize = (size+4095) & (unsigned)~4095; //Page aligned
|
||||
uint64 aligned_size, page_size;
|
||||
void* ret = NULL;
|
||||
sgx_status_t st = 0;
|
||||
|
||||
ret = sgx_alloc_rsrv_mem(alignedSize);
|
||||
page_size = getpagesize();
|
||||
aligned_size = (size + page_size - 1) & ~(page_size - 1);
|
||||
|
||||
if (aligned_size >= UINT32_MAX)
|
||||
return NULL;
|
||||
|
||||
ret = sgx_alloc_rsrv_mem(aligned_size);
|
||||
if (ret == NULL) {
|
||||
os_printf("os_mmap(size=%d, alignedSize=%d, prot=0x%x) failed.",size, alignedSize, prot);
|
||||
os_printf("os_mmap(size=%u, aligned size=%lu, prot=0x%x) failed.",
|
||||
size, aligned_size, prot);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (prot & MMAP_PROT_READ)
|
||||
mprot |= SGX_PROT_READ;
|
||||
if (prot & MMAP_PROT_WRITE)
|
||||
mprot |= SGX_PROT_WRITE;
|
||||
if (prot & MMAP_PROT_EXEC)
|
||||
mprot |= SGX_PROT_EXEC;
|
||||
st = sgx_tprotect_rsrv_mem(ret, alignedSize, mprot);
|
||||
if (st != SGX_SUCCESS){
|
||||
os_printf("os_mmap(size=%d,prot=0x%x) failed to set protect.",size, prot);
|
||||
sgx_free_rsrv_mem(ret, alignedSize);
|
||||
|
||||
st = sgx_tprotect_rsrv_mem(ret, aligned_size, mprot);
|
||||
if (st != SGX_SUCCESS) {
|
||||
os_printf("os_mmap(size=%u, prot=0x%x) failed to set protect.",
|
||||
size, prot);
|
||||
sgx_free_rsrv_mem(ret, aligned_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -117,7 +127,11 @@ void* os_mmap(void *hint, unsigned int size, int prot, int flags)
|
|||
void os_munmap(void *addr, uint32 size)
|
||||
{
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
sgx_free_rsrv_mem(addr, size);
|
||||
uint64 aligned_size, page_size;
|
||||
|
||||
page_size = getpagesize();
|
||||
aligned_size = (size + page_size - 1) & ~(page_size - 1);
|
||||
sgx_free_rsrv_mem(addr, aligned_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -135,7 +149,8 @@ int os_mprotect(void *addr, uint32 size, int prot)
|
|||
mprot |= SGX_PROT_EXEC;
|
||||
st = sgx_tprotect_rsrv_mem(addr, size, mprot);
|
||||
if (st != SGX_SUCCESS)
|
||||
os_printf("os_mprotect(addr=0x%lx,size=%d,prot=0x%x) failed.", addr, size, prot);
|
||||
os_printf("os_mprotect(addr=0x%lx, size=%u, prot=0x%x) failed.",
|
||||
addr, size, prot);
|
||||
|
||||
return (st == SGX_SUCCESS? 0:-1);
|
||||
#else
|
||||
|
|
|
@ -32,6 +32,26 @@ b_memcpy_s(void * s1, unsigned int s1max,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int b_memmove_s(void * s1, unsigned int s1max,
|
||||
const void * s2, unsigned int n)
|
||||
{
|
||||
char *dest = (char*)s1;
|
||||
char *src = (char*)s2;
|
||||
if (n == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (s1 == NULL || s1max > RSIZE_MAX) {
|
||||
return -1;
|
||||
}
|
||||
if (s2 == NULL || n > s1max) {
|
||||
memset(dest, 0, s1max);
|
||||
return -1;
|
||||
}
|
||||
memmove(dest, src, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
b_strcat_s(char * s1, unsigned int s1max, const char * s2)
|
||||
{
|
||||
|
|
|
@ -18,6 +18,12 @@ extern "C" {
|
|||
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); \
|
||||
} while (0)
|
||||
|
||||
#define bh_strcat_s(dest, dlen, src) do { \
|
||||
int _ret = b_strcat_s (dest, dlen, src); \
|
||||
(void)_ret; \
|
||||
|
@ -31,6 +37,7 @@ extern "C" {
|
|||
} while (0)
|
||||
|
||||
int b_memcpy_s(void * s1, unsigned int s1max, const void * s2, unsigned int n);
|
||||
int b_memmove_s(void * s1, unsigned int s1max, const void * s2, unsigned int n);
|
||||
int b_strcat_s(char * s1, unsigned int s1max, const char * s2);
|
||||
int b_strcpy_s(char * s1, unsigned int s1max, const char * s2);
|
||||
|
||||
|
|
|
@ -41,12 +41,22 @@ bh_log_set_verbose_level(uint32 level);
|
|||
void
|
||||
bh_log(LogLevel log_level, const char *file, int line, const char *fmt, ...);
|
||||
|
||||
#if BH_DEBUG == 1
|
||||
#define LOG_FATAL(...) bh_log(BH_LOG_LEVEL_FATAL, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LOG_FATAL(...) bh_log(BH_LOG_LEVEL_FATAL, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define LOG_ERROR(...) bh_log(BH_LOG_LEVEL_ERROR, NULL, 0, __VA_ARGS__)
|
||||
#define LOG_DEBUG(...) bh_log(BH_LOG_LEVEL_DEBUG, __FILE__, __LINE__, 0, __VA_ARGS__)
|
||||
#define LOG_WARNING(...) bh_log(BH_LOG_LEVEL_WARNING, NULL, 0, __VA_ARGS__)
|
||||
#define LOG_VERBOSE(...) bh_log(BH_LOG_LEVEL_VERBOSE, NULL, 0, __VA_ARGS__)
|
||||
|
||||
#if BH_DEBUG == 1
|
||||
#define LOG_DEBUG(...) bh_log(BH_LOG_LEVEL_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LOG_DEBUG(...) /* do nothing */
|
||||
#endif
|
||||
|
||||
void
|
||||
bh_print_time(const char *prompt);
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ uint32 bh_get_elpased_ms(uint32 *last_system_clock);
|
|||
|
||||
struct _timer_ctx;
|
||||
typedef struct _timer_ctx * timer_ctx_t;
|
||||
typedef void (*timer_callback_f)(uint32 id, unsigned int owner);
|
||||
typedef void (*timer_callback_f)(unsigned int id, unsigned int owner);
|
||||
typedef void (*check_timer_expiry_f)(timer_ctx_t ctx);
|
||||
|
||||
timer_ctx_t create_timer_ctx(timer_callback_f timer_handler,
|
||||
|
|
|
@ -7,7 +7,7 @@ It is recommended to use the [WAMR SDK](../wamr-sdk) tools to build a project th
|
|||
|
||||
## iwasm VM core CMake building configurations
|
||||
|
||||
By including the script `runtime_lib.cmake` under folder [build-scripts](../build-scripts) in CMakeList.txt, it is easy to build minimal product with CMake.
|
||||
By including the script `runtime_lib.cmake` under folder [build-scripts](../build-scripts) in CMakeList.txt, it is easy to build minimal product with CMake.
|
||||
|
||||
```cmake
|
||||
# add this in your CMakeList.text
|
||||
|
@ -21,19 +21,19 @@ The script `runtime_lib.cmake` defined a number of variables for configuring the
|
|||
|
||||
#### **Configure platform and architecture**
|
||||
|
||||
- **WAMR_BUILD_PLATFORM**: set the target platform. It can be set to any platform name (folder name) under folder [core/shared/platform](../core/shared/platform).
|
||||
- **WAMR_BUILD_PLATFORM**: set the target platform. It can be set to any platform name (folder name) under folder [core/shared/platform](../core/shared/platform).
|
||||
|
||||
- **WAMR_BUILD_TARGET**: set the target CPU architecture. Current supported targets: X86_64, X86_32, AArch64, ARM, THUMB, XTENSA and MIPS. For AArch64, ARM and THUMB, the format is <arch>[<sub-arch>][_VFP] where <sub-arch> is the ARM sub-architecture and the "_VFP" suffix means VFP coprocessor registers s0-s15 (d0-d7) are used for passing arguments or returning results in standard procedure-call. Both <sub-arch> and "_VFP" are optional. e.g. AARCH64, AARCH64V8, AARCHV8.1, ARMV7, ARMV7_VFP, THUMBV7, THUMBV7_VFP and so on.
|
||||
|
||||
```bash
|
||||
cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM
|
||||
cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM
|
||||
```
|
||||
|
||||
#### **Configure interpreter**
|
||||
#### **Configure interpreter**
|
||||
|
||||
- **WAMR_BUILD_INTERP**=1/0: enable or disable WASM interpreter
|
||||
|
||||
- **WAMR_BUILD_FAST_INTERP**=1/0:build fast (default) or classic WASM interpreter.
|
||||
- **WAMR_BUILD_FAST_INTERP**=1/0:build fast (default) or classic WASM interpreter.
|
||||
|
||||
NOTE: the fast interpreter will run ~2X faster than classic interpreter, but it consumes about 2X memory to hold the WASM bytecode code.
|
||||
|
||||
|
@ -48,14 +48,16 @@ The script `runtime_lib.cmake` defined a number of variables for configuring the
|
|||
|
||||
- **WAMR_BUILD_LIBC_WASI**=1/0, default to disable if no set
|
||||
|
||||
|
||||
#### **Enable Multi-Module feature**
|
||||
|
||||
- **WAMR_BUILD_MULTI_MODULE**=1/0, default to disable if not set
|
||||
|
||||
**Combination of configurations:**
|
||||
|
||||
We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command:
|
||||
|
||||
``` Bash
|
||||
cmake .. -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_LIBC_WASI=0 -DWAMR_BUILD_PLATFORM=linux
|
||||
cmake .. -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_LIBC_WASI=0 -DWAMR_BUILD_PLATFORM=linux
|
||||
```
|
||||
|
||||
Or if we want to enable interpreter, disable AOT and WASI, and build as X86_32, we can run command:
|
||||
|
@ -73,7 +75,7 @@ If you are building for ARM architecture on a X86 development machine, you can u
|
|||
```
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=$TOOL_CHAIN_FILE \
|
||||
-DWAMR_BUILD_PLATFORM=linux \
|
||||
-DWAMR_BUILD_TARGET=ARM
|
||||
-DWAMR_BUILD_TARGET=ARM
|
||||
```
|
||||
|
||||
Refer to toochain sample file [`samples/simple/profiles/arm-interp/toolchain.cmake`](../samples/simple/profiles/arm-interp/toolchain.cmake) for how to build mini product for ARM target architecture.
|
||||
|
@ -260,7 +262,7 @@ AliOS-Things
|
|||
```
|
||||
7. build source code and run
|
||||
For linux host:
|
||||
|
||||
|
||||
``` Bash
|
||||
aos make helloworld@linuxhost -c config
|
||||
aos make
|
||||
|
@ -269,7 +271,7 @@ AliOS-Things
|
|||
|
||||
For developerkit:
|
||||
Modify file middleware/iwasm/aos.mk, patch as:
|
||||
|
||||
|
||||
``` C
|
||||
WAMR_BUILD_TARGET := THUMBV7M
|
||||
```
|
||||
|
@ -285,11 +287,11 @@ Android
|
|||
able to generate a shared library support Android platform.
|
||||
- need an [android SDK](https://developer.android.com/studio). Go and get the "Command line tools only"
|
||||
- look for a command named *sdkmanager* and download below components. version numbers might need to check and pick others
|
||||
- "build-tools;29.0.3"
|
||||
- "cmake;3.10.2.4988404"
|
||||
- "ndk;21.0.6113669"
|
||||
- "build-tools;29.0.3"
|
||||
- "cmake;3.10.2.4988404"
|
||||
- "ndk;21.0.6113669"
|
||||
- "patcher;v4"
|
||||
- "platform-tools"
|
||||
- "platform-tools"
|
||||
- "platforms;android-29"
|
||||
- add bin/ of the downloaded cmake to $PATH
|
||||
- export ANDROID_SDK_HOME=/the/path/of/downloaded/sdk/
|
||||
|
|
228
doc/multi_module.md
Normal file
228
doc/multi_module.md
Normal file
|
@ -0,0 +1,228 @@
|
|||
Multiple Modules as Dependencies
|
||||
=========================
|
||||
|
||||
It is allowed that one WASM module can *import* *functions*, *globals*, *memories* and *tables* from other modules as its dependencies, and also one module can *export* those entities for other modules to *access* and may *write*.
|
||||
|
||||
WAMR loads all dependencies recursively according to the *import section* of a module.
|
||||
|
||||
> Currently WAMR only implements the load-time dynamic linking. Please refer to [dynamic linking](https://webassembly.org/docs/dynamic-linking/) for more details.
|
||||
|
||||
## Multi-Module Related APIs
|
||||
|
||||
### Register a module
|
||||
|
||||
``` c
|
||||
bool
|
||||
wasm_runtime_register_module(const char *module_name,
|
||||
wasm_module_t module,
|
||||
char *error_buf,
|
||||
uint32_t error_buf_size);
|
||||
```
|
||||
|
||||
It is used to register a *module* with a *module_name* to WASM runtime, especially for the root module, which is loaded by `wasm_runtime_load()` and doesn't have a chance to tell runtime its *module name*.
|
||||
|
||||
Fot all the sub modules, WAMR will get their names and load the .wasm files from the filesystem or stream, so no need to register the sub modules again.
|
||||
|
||||
### Find a registered module
|
||||
|
||||
``` c
|
||||
wasm_module_t
|
||||
wasm_runtime_find_module_registered(
|
||||
const char *module_name);
|
||||
```
|
||||
|
||||
It is used to check if a module with a given *module_name* has been registered, if yes return the module.
|
||||
|
||||
### Module reader and destroyer
|
||||
|
||||
``` c
|
||||
typedef bool (*module_reader)(const char *module_name,
|
||||
uint8_t **p_buffer,
|
||||
uint32_t *p_size);
|
||||
|
||||
typedef void (*module_destroyer)(uint8_t *buffer,
|
||||
uint32_t size);
|
||||
|
||||
void
|
||||
wasm_runtime_set_module_reader(const module_reader reader,
|
||||
const module_destroyer destroyer);
|
||||
```
|
||||
|
||||
WAMR hopes that the native host or embedding environment loads/unloads the module WASM files by themselves and only passes runtime the binary content without worrying filesystem or storage issues. `module_reader` and `module_destroyer` are two callbacks called when dynamic-loading/unloading the sub modules. Developers must implement the two callbacks by themselves.
|
||||
|
||||
### Call function of sub module
|
||||
|
||||
```c
|
||||
wasm_function_inst_t
|
||||
wasm_runtime_lookup_function(wasm_module_inst_t const module_inst,
|
||||
const char *name,
|
||||
const char *signature);
|
||||
```
|
||||
|
||||
Multi-module allows to lookup the function of sub module and call it. There are two ways to indicate the function *name*:
|
||||
|
||||
- parent function name only by default, used to lookup the function of parent module
|
||||
- sub module name, function name of sub module and two $ symbols, e.g. `$sub_module_name$function_name`, used to lookup function of sub module
|
||||
|
||||
## Example
|
||||
|
||||
### WASM modules
|
||||
Suppose we have three C files, *mA.c*, *mB.c* and *mC.c*. Each of them has some exported functions and import some from others except mA.
|
||||
|
||||
Undefined symbols can be marked in the source code with the *import_name* clang attribute which means that they are expected to be undefined at static link time. Without the *import_module* clang attribute, undefined symbols will be marked from the *env* module.
|
||||
|
||||
``` C
|
||||
// mA.c
|
||||
int A() { return 10; }
|
||||
```
|
||||
|
||||
``` C
|
||||
// mB.c
|
||||
__attribute__((import_module("mA"))) __attribute__((import_name("A"))) extern int A();
|
||||
int B() { return 11; }
|
||||
int call_A() { return A(); }
|
||||
```
|
||||
|
||||
``` C
|
||||
// mC.c
|
||||
__attribute__((import_module("mA"))) __attribute__((import_name("A"))) extern int A();
|
||||
__attribute__((import_module("mB"))) __attribute__((import_name("B"))) extern int B();
|
||||
int C() { return 12; }
|
||||
int call_A() { return A(); }
|
||||
int call_B() { return B(); }
|
||||
```
|
||||
|
||||
By default no undefined symbols are allowed in the final binary. The flag *--allow-undefined* results in a WebAssembly import being defined for each undefined symbol. It is then up to the runtime to provide such symbols.
|
||||
|
||||
When building an executable, only the entry point (_start) and symbols with the *export_name* attribute exported by default. in addition, symbols can be exported via the linker command line using *--export*.
|
||||
|
||||
In the example, another linked command option *--export-all* is used.
|
||||
|
||||
> with more detail, please refer to [WebAssembly lld port][https://lld.llvm.org/WebAssembly.html]
|
||||
|
||||
Here is an example how to compile a *.c* to a *.wasm* with clang. Since there is no *start* function, we use *--no-entry* option.
|
||||
|
||||
``` shell
|
||||
$ clang --target=wasm32 -nostdlib \
|
||||
-Wl,--no-entry,--allow-undefined,--export-all \
|
||||
-o mA.wasm mA.c
|
||||
$ clang --target=wasm32 -nostdlib \
|
||||
-Wl,--no-entry,--allow-undefined,--export-all \
|
||||
-o mB.wasm mB.c
|
||||
$ clang --target=wasm32 -nostdlib \
|
||||
-Wl,--no-entry,--allow-undefined,--export-all \
|
||||
-o mC.wasm mC.c
|
||||
```
|
||||
|
||||
put *mA.wasm*, *mB.wasm* and *mC.wasm* in the directory *wasm-apps*
|
||||
|
||||
``` shell
|
||||
$ # copy mA.wasm, mB.wasm and mC.wasm into wasm-apps
|
||||
$ tree wasm-apps/
|
||||
wasm-apps/
|
||||
├── mA.wasm
|
||||
├── mB.wasm
|
||||
└── mC.wasm
|
||||
```
|
||||
|
||||
eventually, their *import relationships* will be like:
|
||||
|
||||
![import relationships](./pics/multi_module_pic1.png)
|
||||
|
||||
### libvmlib
|
||||
|
||||
We need to enable *WAMR_BUILD_MULTI_MODULE* option when building WAMR vmlib. Please ref to [Build WAMR core](./build_wamr.md) for a thoughtful guide.
|
||||
|
||||
### code
|
||||
|
||||
After all above preparation, we can call some functions from native code with APIs
|
||||
|
||||
first, create two callbacks to load WASM module files into memory and unload them later
|
||||
|
||||
``` c
|
||||
static bool
|
||||
module_reader_cb(const char *module_name, uint8 **p_buffer, uint32 *p_size)
|
||||
{
|
||||
// ...
|
||||
*p_buffer = (uint8_t *)bh_read_file_to_buffer(wasm_file_path, p_size);
|
||||
// ...
|
||||
}
|
||||
|
||||
static void
|
||||
module_destroyer_cb(uint8 *buffer, uint32 size)
|
||||
{
|
||||
BH_FREE(buffer);
|
||||
}
|
||||
```
|
||||
|
||||
second, create a large buffer and tell WAMR malloc any resource only from this buffer later
|
||||
|
||||
``` c
|
||||
static char sandbox_memory_space[10 * 1024 * 1024] = { 0 };
|
||||
```
|
||||
|
||||
third, put all together
|
||||
|
||||
``` c
|
||||
int main()
|
||||
{
|
||||
/* all malloc() only from the given buffer */
|
||||
init_args.mem_alloc_type = Alloc_With_Pool;
|
||||
init_args.mem_alloc_option.pool.heap_buf = sandbox_memory_space;
|
||||
init_args.mem_alloc_option.pool.heap_size = sizeof(sandbox_memory_space);
|
||||
|
||||
/* initialize runtime environment */
|
||||
wasm_runtime_full_init(&init_args);
|
||||
|
||||
/* set module reader and destroyer */
|
||||
wasm_runtime_set_module_reader(module_reader_cb, module_destroyer_cb);
|
||||
|
||||
/* load WASM byte buffer from WASM bin file */
|
||||
module_reader_cb("mC", &file_buf, &file_buf_size));
|
||||
|
||||
/* load mC and let WAMR load mA and mB */
|
||||
module = wasm_runtime_load(file_buf, file_buf_size,
|
||||
error_buf, sizeof(error_buf));
|
||||
|
||||
/* instantiate the module */
|
||||
module_inst =
|
||||
wasm_runtime_instantiate(module, stack_size,
|
||||
heap_size, error_buf, sizeof(error_buf)));
|
||||
|
||||
|
||||
printf("call \"C\", it will return 0xc:i32, ===> ");
|
||||
wasm_application_execute_func(module_inst, "C", 0, &args[0]);
|
||||
printf("call \"call_B\", it will return 0xb:i32, ===> ");
|
||||
wasm_application_execute_func(module_inst, "call_B", 0, &args[0]);
|
||||
printf("call \"call_A\", it will return 0xa:i32, ===>");
|
||||
wasm_application_execute_func(module_inst, "call_A", 0, &args[0]);
|
||||
|
||||
/* call some functions of mB */
|
||||
printf("call \"mB.B\", it will return 0xb:i32, ===>");
|
||||
wasm_application_execute_func(module_inst, "$mB$B", 0, &args[0]);
|
||||
printf("call \"mB.call_A\", it will return 0xa:i32, ===>");
|
||||
wasm_application_execute_func(module_inst, "$mB$call_A", 0, &args[0]);
|
||||
|
||||
/* call some functions of mA */
|
||||
printf("call \"mA.A\", it will return 0xa:i32, ===>");
|
||||
wasm_application_execute_func(module_inst, "$mA$A", 0, &args[0]);
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
> please refer to [main.c](../samples/multi_modules/src/main.c)
|
||||
|
||||
The output of the main.c will like:
|
||||
|
||||
``` shell
|
||||
$ ./a.out
|
||||
|
||||
call "C", it will return 0xc:i32, ===> 0xc:i32
|
||||
call "call_B", it will return 0xb:i32, ===> 0xb:i32
|
||||
call "call_A", it will return 0xa:i32, ===>0xa:i32
|
||||
call "mB.B", it will return 0xb:i32, ===>0xb:i32
|
||||
call "mB.call_A", it will return 0xa:i32, ===>0xa:i32
|
||||
call "mA.A", it will return 0xa:i32, ===>0xa:i32
|
||||
|
||||
```
|
BIN
doc/pics/multi_module_pic1.png
Normal file
BIN
doc/pics/multi_module_pic1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.4 KiB |
|
@ -4,6 +4,7 @@
|
|||
cmake_minimum_required (VERSION 2.8)
|
||||
|
||||
project (iwasm)
|
||||
# set (CMAKE_VERBOSE_MAKEFILE 1)
|
||||
|
||||
set (WAMR_BUILD_PLATFORM "linux")
|
||||
|
||||
|
@ -11,6 +12,8 @@ set (WAMR_BUILD_PLATFORM "linux")
|
|||
set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
|
||||
set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
|
||||
|
||||
set (CMAKE_C_STANDARD 99)
|
||||
|
||||
# Set WAMR_BUILD_TARGET, currently values supported:
|
||||
# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", "MIPS", "XTENSA"
|
||||
if (NOT DEFINED WAMR_BUILD_TARGET)
|
||||
|
@ -57,6 +60,11 @@ if (NOT DEFINED WAMR_BUILD_FAST_INTERP)
|
|||
set (WAMR_BUILD_FAST_INTERP 1)
|
||||
endif ()
|
||||
|
||||
if (NOT DEFINED WAMR_BUILD_MULTI_MODULE)
|
||||
# Enable multiple modules
|
||||
set (WAMR_BUILD_MULTI_MODULE 0)
|
||||
endif ()
|
||||
|
||||
set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
|
||||
|
||||
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
|
||||
|
|
|
@ -8,24 +8,26 @@
|
|||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bh_platform.h"
|
||||
#include "bh_assert.h"
|
||||
#include "bh_log.h"
|
||||
#include "bh_read_file.h"
|
||||
#include "wasm_export.h"
|
||||
|
||||
static int app_argc;
|
||||
static char **app_argv;
|
||||
|
||||
static int print_help()
|
||||
#define MODULE_PATH ("--module-path=")
|
||||
|
||||
static int
|
||||
print_help()
|
||||
{
|
||||
printf("Usage: iwasm [-options] wasm_file [args...]\n");
|
||||
printf("options:\n");
|
||||
printf(" -f|--function name Specify function name to run in module\n"
|
||||
" rather than main\n");
|
||||
printf(" -f|--function name Specify a function name of the module to run rather\n"
|
||||
" than main\n");
|
||||
#if WASM_ENABLE_LOG != 0
|
||||
printf(" -v=n Set log verbose level (0 to 5, default is 2),\n"
|
||||
" larger level with more log\n");
|
||||
printf(" -v=n Set log verbose level (0 to 5, default is 2) larger\n"
|
||||
" level with more log\n");
|
||||
#endif
|
||||
printf(" --stack-size=n Set maximum stack size in bytes, default is 16 KB\n");
|
||||
printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n");
|
||||
|
@ -39,11 +41,14 @@ static int print_help()
|
|||
printf(" to the program, for example:\n");
|
||||
printf(" --dir=<dir1> --dir=<dir2>\n");
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
printf(" --module-path= Indicate a module search path. default is current\n"
|
||||
" directory('./')\n");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void*
|
||||
static void *
|
||||
app_instance_main(wasm_module_inst_t module_inst)
|
||||
{
|
||||
const char *exception;
|
||||
|
@ -54,7 +59,7 @@ app_instance_main(wasm_module_inst_t module_inst)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void*
|
||||
static void *
|
||||
app_instance_func(wasm_module_inst_t module_inst, const char *func_name)
|
||||
{
|
||||
wasm_application_execute_func(module_inst, func_name, app_argc - 1,
|
||||
|
@ -81,20 +86,31 @@ split_string(char *str, int *count)
|
|||
do {
|
||||
p = strtok(str, " ");
|
||||
str = NULL;
|
||||
res = (char**) realloc(res, sizeof(char*) * (uint32)(idx + 1));
|
||||
res = (char **)realloc(res, sizeof(char *) * (uint32)(idx + 1));
|
||||
if (res == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
res[idx++] = p;
|
||||
} while (p);
|
||||
|
||||
/**
|
||||
* since the function name,
|
||||
* res[0] might be contains a '\' to indicate a space
|
||||
* func\name -> func name
|
||||
*/
|
||||
p = strchr(res[0], '\\');
|
||||
while (p) {
|
||||
*p = ' ';
|
||||
p = strchr(p, '\\');
|
||||
}
|
||||
|
||||
if (count) {
|
||||
*count = idx - 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void*
|
||||
static void *
|
||||
app_instance_repl(wasm_module_inst_t module_inst)
|
||||
{
|
||||
char *cmd = NULL;
|
||||
|
@ -149,7 +165,49 @@ validate_env_str(char *env)
|
|||
static char global_heap_buf[10 * 1024 * 1024] = { 0 };
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
static char *
|
||||
handle_module_path(const char *module_path)
|
||||
{
|
||||
// next character after =
|
||||
return (strchr(module_path, '=')) + 1;
|
||||
}
|
||||
|
||||
static char *module_search_path = ".";
|
||||
static bool
|
||||
module_reader_callback(const char *module_name, uint8 **p_buffer,
|
||||
uint32 *p_size)
|
||||
{
|
||||
const char *format = "%s/%s.wasm";
|
||||
int sz = strlen(module_search_path) + strlen("/") + strlen(module_name) +
|
||||
strlen(".wasm") + 1;
|
||||
char *wasm_file_name = BH_MALLOC(sz);
|
||||
if (!wasm_file_name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
snprintf(wasm_file_name, sz, format, module_search_path, module_name);
|
||||
|
||||
*p_buffer = (uint8_t *)bh_read_file_to_buffer(wasm_file_name, p_size);
|
||||
|
||||
wasm_runtime_free(wasm_file_name);
|
||||
return *p_buffer != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
moudle_destroyer(uint8 *buffer, uint32 size)
|
||||
{
|
||||
if (!buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
wasm_runtime_free(buffer);
|
||||
buffer = NULL;
|
||||
}
|
||||
#endif /* WASM_ENABLE_MULTI_MODULE */
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char *wasm_file = NULL;
|
||||
const char *func_name = NULL;
|
||||
|
@ -172,6 +230,8 @@ int main(int argc, char *argv[])
|
|||
#endif
|
||||
|
||||
/* Process options. */
|
||||
// TODO: use a option name and option handler pair table to
|
||||
// optimize
|
||||
for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
|
||||
if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--function")) {
|
||||
argc--, argv++;
|
||||
|
@ -188,8 +248,9 @@ int main(int argc, char *argv[])
|
|||
return print_help();
|
||||
}
|
||||
#endif
|
||||
else if (!strcmp(argv[0], "--repl"))
|
||||
else if (!strcmp(argv[0], "--repl")) {
|
||||
is_repl_mode = true;
|
||||
}
|
||||
else if (!strncmp(argv[0], "--stack-size=", 13)) {
|
||||
if (argv[0][13] == '\0')
|
||||
return print_help();
|
||||
|
@ -204,9 +265,9 @@ int main(int argc, char *argv[])
|
|||
else if (!strncmp(argv[0], "--dir=", 6)) {
|
||||
if (argv[0][6] == '\0')
|
||||
return print_help();
|
||||
if (dir_list_size >= sizeof(dir_list) / sizeof(char*)) {
|
||||
if (dir_list_size >= sizeof(dir_list) / sizeof(char *)) {
|
||||
printf("Only allow max dir number %d\n",
|
||||
(int)(sizeof(dir_list) / sizeof(char*)));
|
||||
(int)(sizeof(dir_list) / sizeof(char *)));
|
||||
return -1;
|
||||
}
|
||||
dir_list[dir_list_size++] = argv[0] + 6;
|
||||
|
@ -216,20 +277,29 @@ int main(int argc, char *argv[])
|
|||
|
||||
if (argv[0][6] == '\0')
|
||||
return print_help();
|
||||
if (env_list_size >= sizeof(env_list) / sizeof(char*)) {
|
||||
if (env_list_size >= sizeof(env_list) / sizeof(char *)) {
|
||||
printf("Only allow max env number %d\n",
|
||||
(int)(sizeof(env_list) / sizeof(char*)));
|
||||
(int)(sizeof(env_list) / sizeof(char *)));
|
||||
return -1;
|
||||
}
|
||||
tmp_env = argv[0] + 6;
|
||||
if (validate_env_str(tmp_env))
|
||||
env_list[env_list_size++] = tmp_env;
|
||||
else {
|
||||
printf("Wasm parse env string failed: expect \"key=value\", got \"%s\"\n",
|
||||
printf("Wasm parse env string failed: expect \"key=value\", "
|
||||
"got \"%s\"\n",
|
||||
tmp_env);
|
||||
return print_help();
|
||||
}
|
||||
}
|
||||
#endif /* WASM_ENABLE_LIBC_WASI */
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
else if (!strncmp(argv[0], MODULE_PATH, strlen(MODULE_PATH))) {
|
||||
module_search_path = handle_module_path(argv[0]);
|
||||
if (!strlen(module_search_path)) {
|
||||
return print_help();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
return print_help();
|
||||
|
@ -261,13 +331,19 @@ int main(int argc, char *argv[])
|
|||
return -1;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_LOG != 0
|
||||
bh_log_set_verbose_level(log_verbose_level);
|
||||
#endif
|
||||
|
||||
/* load WASM byte buffer from WASM bin file */
|
||||
if (!(wasm_file_buf = (uint8*) bh_read_file_to_buffer(wasm_file,
|
||||
&wasm_file_size)))
|
||||
if (!(wasm_file_buf =
|
||||
(uint8 *)bh_read_file_to_buffer(wasm_file, &wasm_file_size)))
|
||||
goto fail1;
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
wasm_runtime_set_module_reader(module_reader_callback, moudle_destroyer);
|
||||
#endif
|
||||
|
||||
/* load WASM module */
|
||||
if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size,
|
||||
error_buf, sizeof(error_buf)))) {
|
||||
|
@ -276,19 +352,14 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
wasm_runtime_set_wasi_args(wasm_module,
|
||||
dir_list, dir_list_size,
|
||||
NULL, 0,
|
||||
env_list, env_list_size,
|
||||
argv, argc);
|
||||
wasm_runtime_set_wasi_args(wasm_module, dir_list, dir_list_size, NULL, 0,
|
||||
env_list, env_list_size, argv, argc);
|
||||
#endif
|
||||
|
||||
/* instantiate the module */
|
||||
if (!(wasm_module_inst = wasm_runtime_instantiate(wasm_module,
|
||||
stack_size,
|
||||
heap_size,
|
||||
error_buf,
|
||||
sizeof(error_buf)))) {
|
||||
if (!(wasm_module_inst =
|
||||
wasm_runtime_instantiate(wasm_module, stack_size, heap_size,
|
||||
error_buf, sizeof(error_buf)))) {
|
||||
printf("%s\n", error_buf);
|
||||
goto fail3;
|
||||
}
|
||||
|
@ -316,4 +387,3 @@ fail1:
|
|||
wasm_runtime_destroy();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
51
samples/multi-module/CMakeLists.txt
Normal file
51
samples/multi-module/CMakeLists.txt
Normal file
|
@ -0,0 +1,51 @@
|
|||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
project(multi_module)
|
||||
set(CMAKE_VERBOSE_MAKEFILE on)
|
||||
|
||||
################ runtime settings ################
|
||||
set(WAMR_BUILD_PLATFORM "linux")
|
||||
|
||||
# Resetdefault linker flags
|
||||
set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
|
||||
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
|
||||
|
||||
# WAMR features switch
|
||||
set(WAMR_BUILD_TARGET "X86_64")
|
||||
set(WAMR_BUILD_INTERP 1)
|
||||
set(WAMR_BUILD_AOT 0)
|
||||
set(WAMR_BUILD_JIT 0)
|
||||
set(WAMR_BUILD_LIBC_BUILTIN 1)
|
||||
set(WAMR_BUILD_LIBC_WASI 1)
|
||||
set(WAMR_BUILD_FAST_INTERP 0)
|
||||
set(WAMR_BUILD_MULTI_MODULE 1)
|
||||
|
||||
# compiling and linking flags
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security -mindirect-branch-register")
|
||||
|
||||
# build out vmlib
|
||||
set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
|
||||
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
|
||||
|
||||
add_library(vmlib STATIC ${WAMR_RUNTIME_LIB_SOURCE})
|
||||
################################################
|
||||
|
||||
################ application related ################
|
||||
|
||||
################ WASM MODULES
|
||||
# .c -> .wasm
|
||||
add_subdirectory(wasm-apps)
|
||||
|
||||
################ NATIVE
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR}/src)
|
||||
include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
|
||||
|
||||
add_executable(multi_module src/main.c ${UNCOMMON_SHARED_SOURCE})
|
||||
|
||||
add_dependencies(multi_module vmlib wasm-modules)
|
||||
|
||||
# libraries
|
||||
target_link_libraries(multi_module PRIVATE vmlib -lpthread -lm)
|
144
samples/multi-module/src/main.c
Normal file
144
samples/multi-module/src/main.c
Normal file
|
@ -0,0 +1,144 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bh_read_file.h"
|
||||
#include "platform_common.h"
|
||||
#include "wasm_export.h"
|
||||
|
||||
static char *
|
||||
build_module_path(const char *module_name)
|
||||
{
|
||||
const char *module_search_path = "./wasm-apps";
|
||||
const char *format = "%s/%s.wasm";
|
||||
int sz = strlen(module_search_path) + strlen("/") + strlen(module_name)
|
||||
+ strlen(".wasm") + 1;
|
||||
char *wasm_file_name = BH_MALLOC(sz);
|
||||
if (!wasm_file_name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf(wasm_file_name, sz, format, module_search_path, module_name);
|
||||
return wasm_file_name;
|
||||
}
|
||||
|
||||
static bool
|
||||
module_reader_cb(const char *module_name, uint8 **p_buffer, uint32 *p_size)
|
||||
{
|
||||
char *wasm_file_path = build_module_path(module_name);
|
||||
if (!wasm_file_path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("- bh_read_file_to_buffer %s\n", wasm_file_path);
|
||||
*p_buffer = (uint8_t *)bh_read_file_to_buffer(wasm_file_path, p_size);
|
||||
BH_FREE(wasm_file_path);
|
||||
return *p_buffer != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
module_destroyer_cb(uint8 *buffer, uint32 size)
|
||||
{
|
||||
printf("- release the read file buffer\n");
|
||||
if (!buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
BH_FREE(buffer);
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
/* 10M */
|
||||
static char sandbox_memory_space[10 * 1024 * 1024] = { 0 };
|
||||
int
|
||||
main()
|
||||
{
|
||||
bool ret = false;
|
||||
/* 16K */
|
||||
const uint32 stack_size = 16 * 1024;
|
||||
const uint32 heap_size = 16 * 1024;
|
||||
|
||||
RuntimeInitArgs init_args = { 0 };
|
||||
char error_buf[128] = { 0 };
|
||||
/* parameters and return values */
|
||||
char* args[1] = { 0 };
|
||||
|
||||
uint8 *file_buf = NULL;
|
||||
uint32 file_buf_size = 0;
|
||||
wasm_module_t module = NULL;
|
||||
wasm_module_inst_t module_inst = NULL;
|
||||
|
||||
/* all malloc() only from the given buffer */
|
||||
init_args.mem_alloc_type = Alloc_With_Pool;
|
||||
init_args.mem_alloc_option.pool.heap_buf = sandbox_memory_space;
|
||||
init_args.mem_alloc_option.pool.heap_size = sizeof(sandbox_memory_space);
|
||||
|
||||
printf("- wasm_runtime_full_init\n");
|
||||
/* initialize runtime environment */
|
||||
if (!wasm_runtime_full_init(&init_args)) {
|
||||
printf("Init runtime environment failed.\n");
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
printf("- wasm_runtime_set_module_reader\n");
|
||||
/* set module reader and destroyer */
|
||||
wasm_runtime_set_module_reader(module_reader_cb, module_destroyer_cb);
|
||||
#endif
|
||||
|
||||
/* load WASM byte buffer from WASM bin file */
|
||||
if (!module_reader_cb("mC", &file_buf, &file_buf_size)) {
|
||||
goto RELEASE_RUNTIME;
|
||||
}
|
||||
|
||||
/* load mC and let WAMR load mA and mB */
|
||||
printf("- wasm_runtime_load\n");
|
||||
if (!(module = wasm_runtime_load(file_buf, file_buf_size,
|
||||
error_buf, sizeof(error_buf)))) {
|
||||
printf("%s\n", error_buf);
|
||||
goto RELEASE_BINARY;
|
||||
}
|
||||
|
||||
/* instantiate the module */
|
||||
printf("- wasm_runtime_instantiate\n");
|
||||
if (!(module_inst =
|
||||
wasm_runtime_instantiate(module, stack_size, heap_size,
|
||||
error_buf, sizeof(error_buf)))) {
|
||||
printf("%s\n", error_buf);
|
||||
goto UNLOAD_MODULE;
|
||||
}
|
||||
|
||||
/* call some functions of mC */
|
||||
printf("\n----------------------------------------\n");
|
||||
printf("call \"C\", it will return 0xc:i32, ===> ");
|
||||
wasm_application_execute_func(module_inst, "C", 0, &args[0]);
|
||||
printf("call \"call_B\", it will return 0xb:i32, ===> ");
|
||||
wasm_application_execute_func(module_inst, "call_B", 0, &args[0]);
|
||||
printf("call \"call_A\", it will return 0xa:i32, ===>");
|
||||
wasm_application_execute_func(module_inst, "call_A", 0, &args[0]);
|
||||
|
||||
/* call some functions of mB */
|
||||
printf("call \"mB.B\", it will return 0xb:i32, ===>");
|
||||
wasm_application_execute_func(module_inst, "$mB$B", 0, &args[0]);
|
||||
printf("call \"mB.call_A\", it will return 0xa:i32, ===>");
|
||||
wasm_application_execute_func(module_inst, "$mB$call_A", 0, &args[0]);
|
||||
|
||||
/* call some functions of mA */
|
||||
printf("call \"mA.A\", it will return 0xa:i32, ===>");
|
||||
wasm_application_execute_func(module_inst, "$mA$A", 0, &args[0]);
|
||||
printf("----------------------------------------\n\n");
|
||||
ret = true;
|
||||
|
||||
printf("- wasm_runtime_deinstantiate\n");
|
||||
wasm_runtime_deinstantiate(module_inst);
|
||||
UNLOAD_MODULE:
|
||||
printf("- wasm_runtime_unload\n");
|
||||
wasm_runtime_unload(module);
|
||||
RELEASE_BINARY:
|
||||
module_destroyer_cb(file_buf, file_buf_size);
|
||||
RELEASE_RUNTIME:
|
||||
printf("- wasm_runtime_destroy\n");
|
||||
wasm_runtime_destroy();
|
||||
EXIT:
|
||||
return ret ? 0 : 1;
|
||||
}
|
41
samples/multi-module/wasm-apps/CMakeLists.txt
Normal file
41
samples/multi-module/wasm-apps/CMakeLists.txt
Normal file
|
@ -0,0 +1,41 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
project(wasm-apps)
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE on)
|
||||
|
||||
set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
|
||||
set(CLANG_COMMAND "/opt/wasi-sdk/bin/clang")
|
||||
|
||||
set(CLANG_FLAGS --target=wasm32 -nostdlib)
|
||||
set(CLANG_FLAGS ${CLANG_FLAGS} -Wl,--no-entry,--allow-undefined,--export-all)
|
||||
|
||||
set(SOURCE_A ${CMAKE_CURRENT_SOURCE_DIR}/mA.c)
|
||||
add_custom_command(
|
||||
OUTPUT mA.wasm
|
||||
COMMENT "Transform mA.C to mA.WASM"
|
||||
COMMAND ${CLANG_COMMAND} ${CLANG_FLAGS} -o mA.wasm ${SOURCE_A}
|
||||
DEPENDS ${SOURCE_A}
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
set(SOURCE_B ${CMAKE_CURRENT_SOURCE_DIR}/mB.c)
|
||||
add_custom_command(
|
||||
OUTPUT mB.wasm
|
||||
COMMENT "Transform mB.C to mB.WASM"
|
||||
COMMAND ${CLANG_COMMAND} ${CLANG_FLAGS} -o mB.wasm ${SOURCE_B}
|
||||
DEPENDS ${SOURCE_B}
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
set(SOURCE_C ${CMAKE_CURRENT_SOURCE_DIR}/mC.c)
|
||||
add_custom_command(
|
||||
OUTPUT mC.wasm
|
||||
COMMENT "Transform mC.C to mC.WASM"
|
||||
COMMAND ${CLANG_COMMAND} ${CLANG_FLAGS} -o mC.wasm ${SOURCE_C}
|
||||
DEPENDS ${SOURCE_C}
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
add_custom_target(wasm-modules ALL
|
||||
DEPENDS mA.wasm mB.wasm mC.wasm
|
||||
)
|
5
samples/multi-module/wasm-apps/mA.c
Normal file
5
samples/multi-module/wasm-apps/mA.c
Normal file
|
@ -0,0 +1,5 @@
|
|||
int
|
||||
A()
|
||||
{
|
||||
return 10;
|
||||
}
|
16
samples/multi-module/wasm-apps/mB.c
Normal file
16
samples/multi-module/wasm-apps/mB.c
Normal file
|
@ -0,0 +1,16 @@
|
|||
__attribute__((import_module("mA")))
|
||||
__attribute__((import_name("A"))) extern int
|
||||
A();
|
||||
|
||||
int
|
||||
B()
|
||||
{
|
||||
return 11;
|
||||
}
|
||||
|
||||
int
|
||||
call_A()
|
||||
{
|
||||
return A();
|
||||
}
|
||||
|
25
samples/multi-module/wasm-apps/mC.c
Normal file
25
samples/multi-module/wasm-apps/mC.c
Normal file
|
@ -0,0 +1,25 @@
|
|||
__attribute__((import_module("mA")))
|
||||
__attribute__((import_name("A"))) extern int
|
||||
A();
|
||||
|
||||
__attribute__((import_module("mB")))
|
||||
__attribute__((import_name("B"))) extern int
|
||||
B();
|
||||
|
||||
int
|
||||
C()
|
||||
{
|
||||
return 12;
|
||||
}
|
||||
|
||||
int
|
||||
call_A()
|
||||
{
|
||||
return A();
|
||||
}
|
||||
|
||||
int
|
||||
call_B()
|
||||
{
|
||||
return B();
|
||||
}
|
|
@ -14,6 +14,7 @@ set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
|
|||
|
||||
add_definitions(-DWASM_ENABLE_INTERP=1)
|
||||
add_definitions(-DWASM_ENABLE_WAMR_COMPILER=1)
|
||||
add_definitions(-DWASM_ENABLE_BULK_MEMORY=1)
|
||||
|
||||
# Set WAMR_BUILD_TARGET, currently values supported:
|
||||
# "X86_64", "AMD_64", "X86_32", "ARM_32", "MIPS_32", "XTENSA_32"
|
||||
|
|
|
@ -35,6 +35,7 @@ print_help()
|
|||
printf(" object Native object file\n");
|
||||
printf(" llvmir-unopt Unoptimized LLVM IR\n");
|
||||
printf(" llvmir-opt Optimized LLVM IR\n");
|
||||
printf(" --enable-bulk-memory Enable the post-MVP bulk memory feature\n");
|
||||
printf(" -v=n Set log verbose level (0 to 5, default is 2), larger with more log\n");
|
||||
printf("Examples: wamrc -o test.aot test.wasm\n");
|
||||
printf(" wamrc --target=i386 -o test.aot test.wasm\n");
|
||||
|
@ -127,6 +128,9 @@ main(int argc, char *argv[])
|
|||
if (log_verbose_level < 0 || log_verbose_level > 5)
|
||||
return print_help();
|
||||
}
|
||||
else if (!strcmp(argv[0], "--enable-bulk-memory")) {
|
||||
option.enable_bulk_memory = true;
|
||||
}
|
||||
else
|
||||
return print_help();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user