summaryrefslogtreecommitdiffstats
path: root/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter
diff options
context:
space:
mode:
Diffstat (limited to 'fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter')
-rw-r--r--fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/SConscript30
-rw-r--r--fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/iwasm_interp.cmake29
-rw-r--r--fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm.h797
-rw-r--r--fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp.h96
-rw-r--r--fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp_classic.c4315
-rw-r--r--fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp_fast.c4021
-rw-r--r--fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_loader.c10131
-rw-r--r--fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_loader.h80
-rw-r--r--fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_mini_loader.c7544
-rw-r--r--fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_opcode.h917
-rw-r--r--fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_runtime.c3532
-rw-r--r--fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_runtime.h668
12 files changed, 32160 insertions, 0 deletions
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/SConscript b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/SConscript
new file mode 100644
index 000000000..7c0605ee9
--- /dev/null
+++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/SConscript
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 2021, RT-Thread Development Team
+#
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#
+
+from building import *
+
+cwd = GetCurrentDir()
+
+src = Split('''
+wasm_runtime.c
+''')
+
+if GetDepend(['WAMR_BUILD_FAST_INTERP']):
+ src += ["wasm_interp_fast.c"]
+else:
+ src += ["wasm_interp_classic.c"]
+
+if GetDepend(['WAMR_BUILD_MINI_LOADER']):
+ src += ["wasm_mini_loader.c"]
+else:
+ src += ["wasm_loader.c"]
+
+
+CPPPATH = [cwd]
+
+group = DefineGroup('iwasm_interpreter', src, depend = [''], CPPPATH = CPPPATH)
+
+Return('group')
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/iwasm_interp.cmake b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/iwasm_interp.cmake
new file mode 100644
index 000000000..e6e52e42c
--- /dev/null
+++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/iwasm_interp.cmake
@@ -0,0 +1,29 @@
+# Copyright (C) 2019 Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+set (IWASM_INTERP_DIR ${CMAKE_CURRENT_LIST_DIR})
+
+add_definitions (-DWASM_ENABLE_INTERP=1)
+
+include_directories(${IWASM_INTERP_DIR})
+
+if (WAMR_BUILD_FAST_INTERP EQUAL 1)
+ set (INTERPRETER "wasm_interp_fast.c")
+else ()
+ set (INTERPRETER "wasm_interp_classic.c")
+endif ()
+
+if (WAMR_BUILD_MINI_LOADER EQUAL 1)
+ set (LOADER "wasm_mini_loader.c")
+else ()
+ set (LOADER "wasm_loader.c")
+endif ()
+
+file (GLOB_RECURSE source_all
+ ${IWASM_INTERP_DIR}/${LOADER}
+ ${IWASM_INTERP_DIR}/wasm_runtime.c
+ ${IWASM_INTERP_DIR}/${INTERPRETER}
+)
+
+set (IWASM_INTERP_SOURCE ${source_all})
+
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm.h b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm.h
new file mode 100644
index 000000000..0797a018b
--- /dev/null
+++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm.h
@@ -0,0 +1,797 @@
+/*
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef _WASM_H_
+#define _WASM_H_
+
+#include "bh_platform.h"
+#include "bh_hashmap.h"
+#include "bh_assert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Value Type */
+#define VALUE_TYPE_I32 0x7F
+#define VALUE_TYPE_I64 0X7E
+#define VALUE_TYPE_F32 0x7D
+#define VALUE_TYPE_F64 0x7C
+#define VALUE_TYPE_V128 0x7B
+#define VALUE_TYPE_FUNCREF 0x70
+#define VALUE_TYPE_EXTERNREF 0x6F
+#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
+
+#define DEFAULT_NUM_BYTES_PER_PAGE 65536
+#define DEFAULT_MAX_PAGES 65536
+
+#define NULL_REF (0xFFFFFFFF)
+
+#define TABLE_MAX_SIZE (1024)
+
+#define INIT_EXPR_TYPE_I32_CONST 0x41
+#define INIT_EXPR_TYPE_I64_CONST 0x42
+#define INIT_EXPR_TYPE_F32_CONST 0x43
+#define INIT_EXPR_TYPE_F64_CONST 0x44
+#define INIT_EXPR_TYPE_V128_CONST 0xFD
+/* = WASM_OP_REF_FUNC */
+#define INIT_EXPR_TYPE_FUNCREF_CONST 0xD2
+/* = WASM_OP_REF_NULL */
+#define INIT_EXPR_TYPE_REFNULL_CONST 0xD0
+#define INIT_EXPR_TYPE_GET_GLOBAL 0x23
+#define INIT_EXPR_TYPE_ERROR 0xff
+
+#define WASM_MAGIC_NUMBER 0x6d736100
+#define WASM_CURRENT_VERSION 1
+
+#define SECTION_TYPE_USER 0
+#define SECTION_TYPE_TYPE 1
+#define SECTION_TYPE_IMPORT 2
+#define SECTION_TYPE_FUNC 3
+#define SECTION_TYPE_TABLE 4
+#define SECTION_TYPE_MEMORY 5
+#define SECTION_TYPE_GLOBAL 6
+#define SECTION_TYPE_EXPORT 7
+#define SECTION_TYPE_START 8
+#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 SUB_SECTION_TYPE_MODULE 0
+#define SUB_SECTION_TYPE_FUNC 1
+#define SUB_SECTION_TYPE_LOCAL 2
+
+#define IMPORT_KIND_FUNC 0
+#define IMPORT_KIND_TABLE 1
+#define IMPORT_KIND_MEMORY 2
+#define IMPORT_KIND_GLOBAL 3
+
+#define EXPORT_KIND_FUNC 0
+#define EXPORT_KIND_TABLE 1
+#define EXPORT_KIND_MEMORY 2
+#define EXPORT_KIND_GLOBAL 3
+
+#define LABEL_TYPE_BLOCK 0
+#define LABEL_TYPE_LOOP 1
+#define LABEL_TYPE_IF 2
+#define LABEL_TYPE_FUNCTION 3
+
+typedef struct WASMModule WASMModule;
+typedef struct WASMFunction WASMFunction;
+typedef struct WASMGlobal WASMGlobal;
+
+typedef union V128 {
+ int8 i8x16[16];
+ int16 i16x8[8];
+ int32 i32x8[4];
+ int64 i64x2[2];
+ float32 f32x4[4];
+ float64 f64x2[2];
+} V128;
+
+typedef union WASMValue {
+ int32 i32;
+ uint32 u32;
+ uint32 global_index;
+ uint32 ref_index;
+ int64 i64;
+ uint64 u64;
+ float32 f32;
+ float64 f64;
+ uintptr_t addr;
+ V128 v128;
+} WASMValue;
+
+typedef struct InitializerExpression {
+ /* type of INIT_EXPR_TYPE_XXX */
+ /* it actually is instr, in some places, requires constant only */
+ uint8 init_expr_type;
+ WASMValue u;
+} InitializerExpression;
+
+typedef struct WASMType {
+ uint16 param_count;
+ uint16 result_count;
+ uint16 param_cell_num;
+ uint16 ret_cell_num;
+ uint16 ref_count;
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0
+ /* Code block to call llvm jit functions of this
+ kind of function type from fast jit jitted code */
+ void *call_to_llvm_jit_from_fast_jit;
+#endif
+ /* types of params and results */
+ uint8 types[1];
+} WASMType;
+
+typedef struct WASMTable {
+ uint8 elem_type;
+ uint32 flags;
+ uint32 init_size;
+ /* specified if (flags & 1), else it is 0x10000 */
+ uint32 max_size;
+ bool possible_grow;
+} WASMTable;
+
+typedef struct WASMMemory {
+ uint32 flags;
+ uint32 num_bytes_per_page;
+ uint32 init_page_count;
+ uint32 max_page_count;
+} WASMMemory;
+
+typedef struct WASMTableImport {
+ char *module_name;
+ char *field_name;
+ uint8 elem_type;
+ uint32 flags;
+ uint32 init_size;
+ /* specified if (flags & 1), else it is 0x10000 */
+ uint32 max_size;
+ bool possible_grow;
+#if WASM_ENABLE_MULTI_MODULE != 0
+ WASMModule *import_module;
+ WASMTable *import_table_linked;
+#endif
+} WASMTableImport;
+
+typedef struct WASMMemoryImport {
+ char *module_name;
+ char *field_name;
+ uint32 flags;
+ 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 {
+ char *module_name;
+ char *field_name;
+ /* function type */
+ WASMType *func_type;
+ /* 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
+ bool call_conv_wasm_c_api;
+} WASMFunctionImport;
+
+typedef struct WASMGlobalImport {
+ char *module_name;
+ char *field_name;
+ uint8 type;
+ bool is_mutable;
+ /* global data after linked */
+ WASMValue global_data_linked;
+ bool is_linked;
+#if WASM_ENABLE_MULTI_MODULE != 0
+ /* imported function pointer after linked */
+ /* TODO: remove if not needed */
+ WASMModule *import_module;
+ WASMGlobal *import_global_linked;
+#endif
+#if WASM_ENABLE_FAST_JIT != 0
+ /* The data offset of current global in global data */
+ uint32 data_offset;
+#endif
+} WASMGlobalImport;
+
+typedef struct WASMImport {
+ uint8 kind;
+ union {
+ WASMFunctionImport function;
+ WASMTableImport table;
+ WASMMemoryImport memory;
+ WASMGlobalImport global;
+ struct {
+ char *module_name;
+ char *field_name;
+ } names;
+ } u;
+} WASMImport;
+
+struct WASMFunction {
+#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
+ char *field_name;
+#endif
+ /* the type of function */
+ WASMType *func_type;
+ uint32 local_count;
+ uint8 *local_types;
+
+ /* cell num of parameters */
+ uint16 param_cell_num;
+ /* cell num of return type */
+ uint16 ret_cell_num;
+ /* cell num of local variables */
+ uint16 local_cell_num;
+ /* offset of each local, including function parameters
+ and local variables */
+ uint16 *local_offsets;
+
+ uint32 max_stack_cell_num;
+ uint32 max_block_num;
+ uint32 code_size;
+ uint8 *code;
+#if WASM_ENABLE_FAST_INTERP != 0
+ uint32 code_compiled_size;
+ uint8 *code_compiled;
+ uint8 *consts;
+ uint32 const_cell_num;
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \
+ || WASM_ENABLE_WAMR_COMPILER != 0
+ /* Whether function has opcode memory.grow */
+ bool has_op_memory_grow;
+ /* Whether function has opcode call or call_indirect */
+ bool has_op_func_call;
+#endif
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ /* Whether function has memory operation opcodes */
+ bool has_memory_operations;
+ /* Whether function has opcode call_indirect */
+ bool has_op_call_indirect;
+ /* Whether function has opcode set_global_aux_stack */
+ bool has_op_set_global_aux_stack;
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0
+ /* The compiled fast jit jitted code block of this function */
+ void *fast_jit_jitted_code;
+#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
+ /* The compiled llvm jit func ptr of this function */
+ void *llvm_jit_func_ptr;
+ /* Code block to call fast jit jitted code of this function
+ from the llvm jit jitted code */
+ void *call_to_fast_jit_from_llvm_jit;
+#endif
+#endif
+};
+
+struct WASMGlobal {
+ uint8 type;
+ bool is_mutable;
+ InitializerExpression init_expr;
+#if WASM_ENABLE_FAST_JIT != 0
+ /* The data offset of current global in global data */
+ uint32 data_offset;
+#endif
+};
+
+typedef struct WASMExport {
+ char *name;
+ uint8 kind;
+ uint32 index;
+} WASMExport;
+
+typedef struct WASMTableSeg {
+ /* 0 to 7 */
+ uint32 mode;
+ /* funcref or externref, elemkind will be considered as funcref */
+ uint32 elem_type;
+ bool is_dropped;
+ /* optional, only for active */
+ uint32 table_index;
+ InitializerExpression base_offset;
+ uint32 function_count;
+ uint32 *func_indexes;
+} WASMTableSeg;
+
+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;
+
+typedef struct BlockAddr {
+ const uint8 *start_addr;
+ uint8 *else_addr;
+ uint8 *end_addr;
+} BlockAddr;
+
+#if WASM_ENABLE_LIBC_WASI != 0
+typedef struct WASIArguments {
+ const char **dir_list;
+ uint32 dir_count;
+ const char **map_dir_list;
+ uint32 map_dir_count;
+ const char **env;
+ uint32 env_count;
+ /* in CIDR noation */
+ const char **addr_pool;
+ uint32 addr_count;
+ const char **ns_lookup_pool;
+ uint32 ns_lookup_count;
+ char **argv;
+ uint32 argc;
+ int stdio[3];
+} WASIArguments;
+#endif
+
+typedef struct StringNode {
+ struct StringNode *next;
+ char *str;
+} StringNode, *StringList;
+
+typedef struct BrTableCache {
+ struct BrTableCache *next;
+ /* Address of br_table opcode */
+ uint8 *br_table_op_addr;
+ uint32 br_count;
+ uint32 br_depths[1];
+} BrTableCache;
+
+#if WASM_ENABLE_DEBUG_INTERP != 0
+typedef struct WASMFastOPCodeNode {
+ struct WASMFastOPCodeNode *next;
+ uint64 offset;
+ uint8 orig_op;
+} WASMFastOPCodeNode;
+#endif
+
+#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
+typedef struct WASMCustomSection {
+ struct WASMCustomSection *next;
+ /* Start address of the section name */
+ char *name_addr;
+ /* Length of the section name decoded from leb */
+ uint32 name_len;
+ /* Start address of the content (name len and name skipped) */
+ uint8 *content_addr;
+ uint32 content_len;
+} WASMCustomSection;
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0
+struct AOTCompData;
+struct AOTCompContext;
+
+/* Orc JIT thread arguments */
+typedef struct OrcJitThreadArg {
+#if WASM_ENABLE_JIT != 0
+ struct AOTCompContext *comp_ctx;
+#endif
+ struct WASMModule *module;
+ uint32 group_idx;
+} OrcJitThreadArg;
+#endif
+
+struct WASMModuleInstance;
+
+struct WASMModule {
+ /* Module type, for module loaded from WASM bytecode binary,
+ this field is Wasm_Module_Bytecode;
+ for module loaded from AOT file, this field is
+ Wasm_Module_AoT, and this structure should be treated as
+ AOTModule structure. */
+ uint32 module_type;
+
+ uint32 type_count;
+ uint32 import_count;
+ uint32 function_count;
+ uint32 table_count;
+ uint32 memory_count;
+ 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;
+ uint32 import_memory_count;
+ uint32 import_global_count;
+
+ WASMImport *import_functions;
+ WASMImport *import_tables;
+ WASMImport *import_memories;
+ WASMImport *import_globals;
+
+ WASMType **types;
+ WASMImport *imports;
+ WASMFunction **functions;
+ WASMTable *tables;
+ WASMMemory *memories;
+ WASMGlobal *globals;
+ WASMExport *exports;
+ WASMTableSeg *table_segments;
+ WASMDataSeg **data_segments;
+ uint32 start_function;
+
+ /* total global variable size */
+ uint32 global_data_size;
+
+ /* the index of auxiliary __data_end global,
+ -1 means unexported */
+ uint32 aux_data_end_global_index;
+ /* auxiliary __data_end exported by wasm app */
+ uint32 aux_data_end;
+
+ /* the index of auxiliary __heap_base global,
+ -1 means unexported */
+ uint32 aux_heap_base_global_index;
+ /* auxiliary __heap_base exported by wasm app */
+ uint32 aux_heap_base;
+
+ /* the index of auxiliary stack top global,
+ -1 means unexported */
+ uint32 aux_stack_top_global_index;
+ /* auxiliary stack bottom resolved */
+ uint32 aux_stack_bottom;
+ /* auxiliary stack size resolved */
+ uint32 aux_stack_size;
+
+ /* the index of malloc/free function,
+ -1 means unexported */
+ uint32 malloc_function;
+ uint32 free_function;
+
+ /* the index of __retain function,
+ -1 means unexported */
+ uint32 retain_function;
+
+ /* Whether there is possible memory grow, e.g. memory.grow opcode */
+ bool possible_memory_grow;
+
+ StringList const_str_list;
+#if WASM_ENABLE_FAST_INTERP == 0
+ bh_list br_table_cache_list_head;
+ bh_list *br_table_cache_list;
+#endif
+
+#if WASM_ENABLE_LIBC_WASI != 0
+ WASIArguments wasi_args;
+ bool import_wasi_api;
+#endif
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+ /* TODO: add mutex for mutli-thread? */
+ bh_list import_module_list_head;
+ bh_list *import_module_list;
+#endif
+#if WASM_ENABLE_DEBUG_INTERP != 0 || WASM_ENABLE_DEBUG_AOT != 0
+ bh_list fast_opcode_list;
+ uint8 *buf_code;
+ uint64 buf_code_size;
+#endif
+#if WASM_ENABLE_DEBUG_INTERP != 0 || WASM_ENABLE_DEBUG_AOT != 0 \
+ || WASM_ENABLE_FAST_JIT != 0
+ uint8 *load_addr;
+ uint64 load_size;
+#endif
+
+#if WASM_ENABLE_DEBUG_INTERP != 0 \
+ || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0)
+ /**
+ * List of instances referred to this module. When source debugging
+ * feature is enabled, the debugger may modify the code section of
+ * the module, so we need to report a warning if user create several
+ * instances based on the same module.
+ *
+ * Also add the instance to the list for Fast JIT to LLVM JIT
+ * tier-up, since we need to lazily update the LLVM func pointers
+ * in the instance.
+ */
+ struct WASMModuleInstance *instance_list;
+ korp_mutex instance_list_lock;
+#endif
+
+#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
+ const uint8 *name_section_buf;
+ const uint8 *name_section_buf_end;
+#endif
+
+#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
+ WASMCustomSection *custom_section_list;
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0
+ /**
+ * func pointers of Fast JITed (un-imported) functions
+ * for non Multi-Tier JIT mode:
+ * (1) when lazy jit is disabled, each pointer is set to the compiled
+ * fast jit jitted code
+ * (2) when lazy jit is enabled, each pointer is firstly inited as
+ * jit_global->compile_fast_jit_and_then_call, and then set to the
+ * compiled fast jit jitted code when it is called (the stub will
+ * compile the jit function and then update itself)
+ * for Multi-Tier JIT mode:
+ * each pointer is firstly inited as compile_fast_jit_and_then_call,
+ * and then set to the compiled fast jit jitted code when it is called,
+ * and when the llvm jit func ptr of the same function is compiled, it
+ * will be set to call_to_llvm_jit_from_fast_jit of this function type
+ * (tier-up from fast-jit to llvm-jit)
+ */
+ void **fast_jit_func_ptrs;
+ /* locks for Fast JIT lazy compilation */
+ korp_mutex fast_jit_thread_locks[WASM_ORC_JIT_BACKEND_THREAD_NUM];
+ bool fast_jit_thread_locks_inited[WASM_ORC_JIT_BACKEND_THREAD_NUM];
+#endif
+
+#if WASM_ENABLE_JIT != 0
+ struct AOTCompData *comp_data;
+ struct AOTCompContext *comp_ctx;
+ /**
+ * func pointers of LLVM JITed (un-imported) functions
+ * for non Multi-Tier JIT mode:
+ * each pointer is set to the lookuped llvm jit func ptr, note that it
+ * is a stub and will trigger the actual compilation when it is called
+ * for Multi-Tier JIT mode:
+ * each pointer is inited as call_to_fast_jit code block, when the llvm
+ * jit func ptr is actually compiled, it is set to the compiled llvm jit
+ * func ptr
+ */
+ void **func_ptrs;
+ /* whether the func pointers are compiled */
+ bool *func_ptrs_compiled;
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0
+ /* backend compilation threads */
+ korp_tid orcjit_threads[WASM_ORC_JIT_BACKEND_THREAD_NUM];
+ /* backend thread arguments */
+ OrcJitThreadArg orcjit_thread_args[WASM_ORC_JIT_BACKEND_THREAD_NUM];
+ /* whether to stop the compilation of backend threads */
+ bool orcjit_stop_compiling;
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0
+ /* wait lock/cond for the synchronization of
+ the llvm jit initialization */
+ korp_mutex tierup_wait_lock;
+ korp_cond tierup_wait_cond;
+ bool tierup_wait_lock_inited;
+ korp_tid llvm_jit_init_thread;
+ /* whether the llvm jit is initialized */
+ bool llvm_jit_inited;
+ /* Whether to enable llvm jit compilation:
+ it is set to true only when there is a module instance starts to
+ run with running mode Mode_LLVM_JIT or Mode_Multi_Tier_JIT,
+ since no need to enable llvm jit compilation for Mode_Interp and
+ Mode_Fast_JIT, so as to improve performance for them */
+ bool enable_llvm_jit_compilation;
+ /* The count of groups which finish compiling the fast jit
+ functions in that group */
+ uint32 fast_jit_ready_groups;
+#endif
+};
+
+typedef struct BlockType {
+ /* Block type may be expressed in one of two forms:
+ * either by the type of the single return value or
+ * by a type index of module.
+ */
+ union {
+ uint8 value_type;
+ WASMType *type;
+ } u;
+ bool is_value_type;
+} BlockType;
+
+typedef struct WASMBranchBlock {
+ uint8 *begin_addr;
+ uint8 *target_addr;
+ uint32 *frame_sp;
+ uint32 cell_num;
+} WASMBranchBlock;
+
+/* Execution environment, e.g. stack info */
+/**
+ * Align an unsigned value on a alignment boundary.
+ *
+ * @param v the value to be aligned
+ * @param b the alignment boundary (2, 4, 8, ...)
+ *
+ * @return the aligned value
+ */
+inline static unsigned
+align_uint(unsigned v, unsigned b)
+{
+ unsigned m = b - 1;
+ return (v + m) & ~m;
+}
+
+/**
+ * Return the hash value of c string.
+ */
+inline static uint32
+wasm_string_hash(const char *str)
+{
+ unsigned h = (unsigned)strlen(str);
+ const uint8 *p = (uint8 *)str;
+ const uint8 *end = p + h;
+
+ while (p != end)
+ h = ((h << 5) - h) + *p++;
+ return h;
+}
+
+/**
+ * Whether two c strings are equal.
+ */
+inline static bool
+wasm_string_equal(const char *s1, const char *s2)
+{
+ return strcmp(s1, s2) == 0 ? true : false;
+}
+
+/**
+ * Return the byte size of value type.
+ *
+ */
+inline static uint32
+wasm_value_type_size(uint8 value_type)
+{
+ switch (value_type) {
+ case VALUE_TYPE_I32:
+ case VALUE_TYPE_F32:
+#if WASM_ENABLE_REF_TYPES != 0
+ case VALUE_TYPE_FUNCREF:
+ case VALUE_TYPE_EXTERNREF:
+#endif
+ return sizeof(int32);
+ case VALUE_TYPE_I64:
+ case VALUE_TYPE_F64:
+ return sizeof(int64);
+#if WASM_ENABLE_SIMD != 0
+ case VALUE_TYPE_V128:
+ return sizeof(int64) * 2;
+#endif
+ case VALUE_TYPE_VOID:
+ return 0;
+ default:
+ bh_assert(0);
+ }
+ return 0;
+}
+
+inline static uint16
+wasm_value_type_cell_num(uint8 value_type)
+{
+ return wasm_value_type_size(value_type) / 4;
+}
+
+inline static uint32
+wasm_get_cell_num(const uint8 *types, uint32 type_count)
+{
+ uint32 cell_num = 0;
+ uint32 i;
+ for (i = 0; i < type_count; i++)
+ cell_num += wasm_value_type_cell_num(types[i]);
+ return cell_num;
+}
+
+#if WASM_ENABLE_REF_TYPES != 0
+inline static uint16
+wasm_value_type_cell_num_outside(uint8 value_type)
+{
+ if (VALUE_TYPE_EXTERNREF == value_type) {
+ return sizeof(uintptr_t) / sizeof(uint32);
+ }
+ else {
+ return wasm_value_type_cell_num(value_type);
+ }
+}
+#endif
+
+inline static bool
+wasm_type_equal(const WASMType *type1, const WASMType *type2)
+{
+ if (type1 == type2) {
+ return true;
+ }
+ return (type1->param_count == type2->param_count
+ && type1->result_count == type2->result_count
+ && memcmp(type1->types, type2->types,
+ (uint32)(type1->param_count + type1->result_count))
+ == 0)
+ ? true
+ : false;
+}
+
+inline static uint32
+wasm_get_smallest_type_idx(WASMType **types, uint32 type_count,
+ uint32 cur_type_idx)
+{
+ uint32 i;
+
+ for (i = 0; i < cur_type_idx; i++) {
+ if (wasm_type_equal(types[cur_type_idx], types[i]))
+ return i;
+ }
+ (void)type_count;
+ return cur_type_idx;
+}
+
+static inline uint32
+block_type_get_param_types(BlockType *block_type, uint8 **p_param_types)
+{
+ uint32 param_count = 0;
+ if (!block_type->is_value_type) {
+ WASMType *wasm_type = block_type->u.type;
+ *p_param_types = wasm_type->types;
+ param_count = wasm_type->param_count;
+ }
+ else {
+ *p_param_types = NULL;
+ param_count = 0;
+ }
+
+ return param_count;
+}
+
+static inline uint32
+block_type_get_result_types(BlockType *block_type, uint8 **p_result_types)
+{
+ uint32 result_count = 0;
+ if (block_type->is_value_type) {
+ if (block_type->u.value_type != VALUE_TYPE_VOID) {
+ *p_result_types = &block_type->u.value_type;
+ result_count = 1;
+ }
+ }
+ else {
+ WASMType *wasm_type = block_type->u.type;
+ *p_result_types = wasm_type->types + wasm_type->param_count;
+ result_count = wasm_type->result_count;
+ }
+ return result_count;
+}
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif /* end of _WASM_H_ */
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp.h b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp.h
new file mode 100644
index 000000000..d3692ff21
--- /dev/null
+++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef _WASM_INTERP_H
+#define _WASM_INTERP_H
+
+#include "wasm.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct WASMModuleInstance;
+struct WASMFunctionInstance;
+struct WASMExecEnv;
+
+typedef struct WASMInterpFrame {
+ /* The frame of the caller that are calling the current function. */
+ struct WASMInterpFrame *prev_frame;
+
+ /* The current WASM function. */
+ struct WASMFunctionInstance *function;
+
+ /* Instruction pointer of the bytecode array. */
+ uint8 *ip;
+
+#if WASM_ENABLE_FAST_JIT != 0
+ uint8 *jitted_return_addr;
+#endif
+
+#if WASM_ENABLE_PERF_PROFILING != 0
+ uint64 time_started;
+#endif
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* Return offset of the first return value of current frame,
+ the callee will put return values here continuously */
+ uint32 ret_offset;
+ uint32 *lp;
+ uint32 operand[1];
+#else
+ /* Operand stack top pointer of the current frame. The bottom of
+ the stack is the next cell after the last local variable. */
+ uint32 *sp_bottom;
+ uint32 *sp_boundary;
+ uint32 *sp;
+
+ WASMBranchBlock *csp_bottom;
+ WASMBranchBlock *csp_boundary;
+ WASMBranchBlock *csp;
+
+ /**
+ * Frame data, the layout is:
+ * lp: parameters and local variables
+ * sp_bottom to sp_boundary: wasm operand stack
+ * csp_bottom to csp_boundary: wasm label stack
+ * jit spill cache: only available for fast jit
+ */
+ uint32 lp[1];
+#endif
+} WASMInterpFrame;
+
+/**
+ * Calculate the size of interpreter area of frame of a function.
+ *
+ * @param all_cell_num number of all cells including local variables
+ * and the working stack slots
+ *
+ * @return the size of interpreter area of the frame
+ */
+static inline unsigned
+wasm_interp_interp_frame_size(unsigned all_cell_num)
+{
+ unsigned frame_size;
+
+#if WASM_ENABLE_FAST_INTERP == 0
+ frame_size = (uint32)offsetof(WASMInterpFrame, lp) + all_cell_num * 4;
+#else
+ frame_size = (uint32)offsetof(WASMInterpFrame, operand) + all_cell_num * 4;
+#endif
+ return align_uint(frame_size, 4);
+}
+
+void
+wasm_interp_call_wasm(struct WASMModuleInstance *module_inst,
+ struct WASMExecEnv *exec_env,
+ struct WASMFunctionInstance *function, uint32 argc,
+ uint32 argv[]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end of _WASM_INTERP_H */
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp_classic.c b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp_classic.c
new file mode 100644
index 000000000..4cc470143
--- /dev/null
+++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp_classic.c
@@ -0,0 +1,4315 @@
+/*
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "wasm_interp.h"
+#include "bh_log.h"
+#include "wasm_runtime.h"
+#include "wasm_opcode.h"
+#include "wasm_loader.h"
+#include "wasm_memory.h"
+#include "../common/wasm_exec_env.h"
+#if WASM_ENABLE_SHARED_MEMORY != 0
+#include "../common/wasm_shared_memory.h"
+#endif
+#if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0
+#include "../libraries/thread-mgr/thread_manager.h"
+#include "../libraries/debug-engine/debug_engine.h"
+#endif
+#if WASM_ENABLE_FAST_JIT != 0
+#include "../fast-jit/jit_compiler.h"
+#endif
+
+typedef int32 CellType_I32;
+typedef int64 CellType_I64;
+typedef float32 CellType_F32;
+typedef float64 CellType_F64;
+
+#define BR_TABLE_TMP_BUF_LEN 32
+
+#if WASM_ENABLE_THREAD_MGR == 0
+#define get_linear_mem_size() linear_mem_size
+#else
+/**
+ * Load memory data size in each time boundary check in
+ * multi-threading mode since it may be changed by other
+ * threads in memory.grow
+ */
+#define get_linear_mem_size() memory->memory_data_size
+#endif
+
+#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
+ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+#define CHECK_MEMORY_OVERFLOW(bytes) \
+ do { \
+ uint64 offset1 = (uint64)offset + (uint64)addr; \
+ if (offset1 + bytes <= (uint64)get_linear_mem_size()) \
+ /* If offset1 is in valid range, maddr must also \
+ be in valid range, no need to check it again. */ \
+ maddr = memory->memory_data + offset1; \
+ else \
+ goto out_of_bounds; \
+ } while (0)
+
+#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
+ do { \
+ uint64 offset1 = (uint32)(start); \
+ if (offset1 + bytes <= (uint64)get_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)
+#else
+#define CHECK_MEMORY_OVERFLOW(bytes) \
+ do { \
+ uint64 offset1 = (uint64)offset + (uint64)addr; \
+ maddr = memory->memory_data + offset1; \
+ } while (0)
+
+#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
+ do { \
+ maddr = memory->memory_data + (uint32)(start); \
+ } while (0)
+#endif /* !defined(OS_ENABLE_HW_BOUND_CHECK) \
+ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */
+
+#define CHECK_ATOMIC_MEMORY_ACCESS() \
+ do { \
+ if (((uintptr_t)maddr & (((uintptr_t)1 << align) - 1)) != 0) \
+ goto unaligned_atomic; \
+ } while (0)
+
+#if WASM_ENABLE_DEBUG_INTERP != 0
+#define TRIGGER_WATCHPOINT_SIGTRAP() \
+ do { \
+ wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TRAP); \
+ CHECK_SUSPEND_FLAGS(); \
+ } while (0)
+
+#define CHECK_WATCHPOINT(list, current_addr) \
+ do { \
+ WASMDebugWatchPoint *watchpoint = bh_list_first_elem(list); \
+ while (watchpoint) { \
+ WASMDebugWatchPoint *next = bh_list_elem_next(watchpoint); \
+ if (watchpoint->addr <= current_addr \
+ && watchpoint->addr + watchpoint->length > current_addr) { \
+ TRIGGER_WATCHPOINT_SIGTRAP(); \
+ } \
+ watchpoint = next; \
+ } \
+ } while (0)
+
+#define CHECK_READ_WATCHPOINT(addr, offset) \
+ CHECK_WATCHPOINT(watch_point_list_read, WASM_ADDR_OFFSET(addr + offset))
+#define CHECK_WRITE_WATCHPOINT(addr, offset) \
+ CHECK_WATCHPOINT(watch_point_list_write, WASM_ADDR_OFFSET(addr + offset))
+#else
+#define CHECK_READ_WATCHPOINT(addr, offset) (void)0
+#define CHECK_WRITE_WATCHPOINT(addr, offset) (void)0
+#endif
+
+static inline uint32
+rotl32(uint32 n, uint32 c)
+{
+ const uint32 mask = (31);
+ c = c % 32;
+ c &= mask;
+ return (n << c) | (n >> ((0 - c) & mask));
+}
+
+static inline uint32
+rotr32(uint32 n, uint32 c)
+{
+ const uint32 mask = (31);
+ c = c % 32;
+ c &= mask;
+ return (n >> c) | (n << ((0 - c) & mask));
+}
+
+static inline uint64
+rotl64(uint64 n, uint64 c)
+{
+ const uint64 mask = (63);
+ c = c % 64;
+ c &= mask;
+ return (n << c) | (n >> ((0 - c) & mask));
+}
+
+static inline uint64
+rotr64(uint64 n, uint64 c)
+{
+ const uint64 mask = (63);
+ c = c % 64;
+ c &= mask;
+ return (n >> c) | (n << ((0 - c) & mask));
+}
+
+static inline float32
+f32_min(float32 a, float32 b)
+{
+ if (isnan(a) || isnan(b))
+ return NAN;
+ else if (a == 0 && a == b)
+ return signbit(a) ? a : b;
+ else
+ return a > b ? b : a;
+}
+
+static inline float32
+f32_max(float32 a, float32 b)
+{
+ if (isnan(a) || isnan(b))
+ return NAN;
+ else if (a == 0 && a == b)
+ return signbit(a) ? b : a;
+ else
+ return a > b ? a : b;
+}
+
+static inline float64
+f64_min(float64 a, float64 b)
+{
+ if (isnan(a) || isnan(b))
+ return NAN;
+ else if (a == 0 && a == b)
+ return signbit(a) ? a : b;
+ else
+ return a > b ? b : a;
+}
+
+static inline float64
+f64_max(float64 a, float64 b)
+{
+ if (isnan(a) || isnan(b))
+ return NAN;
+ else if (a == 0 && a == b)
+ return signbit(a) ? b : a;
+ else
+ return a > b ? a : b;
+}
+
+static inline uint32
+clz32(uint32 type)
+{
+ uint32 num = 0;
+ if (type == 0)
+ return 32;
+ while (!(type & 0x80000000)) {
+ num++;
+ type <<= 1;
+ }
+ return num;
+}
+
+static inline uint32
+clz64(uint64 type)
+{
+ uint32 num = 0;
+ if (type == 0)
+ return 64;
+ while (!(type & 0x8000000000000000LL)) {
+ num++;
+ type <<= 1;
+ }
+ return num;
+}
+
+static inline uint32
+ctz32(uint32 type)
+{
+ uint32 num = 0;
+ if (type == 0)
+ return 32;
+ while (!(type & 1)) {
+ num++;
+ type >>= 1;
+ }
+ return num;
+}
+
+static inline uint32
+ctz64(uint64 type)
+{
+ uint32 num = 0;
+ if (type == 0)
+ return 64;
+ while (!(type & 1)) {
+ num++;
+ type >>= 1;
+ }
+ return num;
+}
+
+static inline uint32
+popcount32(uint32 u)
+{
+ uint32 ret = 0;
+ while (u) {
+ u = (u & (u - 1));
+ ret++;
+ }
+ return ret;
+}
+
+static inline uint32
+popcount64(uint64 u)
+{
+ uint32 ret = 0;
+ while (u) {
+ u = (u & (u - 1));
+ ret++;
+ }
+ return ret;
+}
+
+static float
+local_copysignf(float x, float y)
+{
+ union {
+ float f;
+ uint32 i;
+ } ux = { x }, uy = { y };
+ ux.i &= 0x7fffffff;
+ ux.i |= uy.i & 0x80000000;
+ return ux.f;
+}
+
+static double
+local_copysign(double x, double y)
+{
+ union {
+ double f;
+ uint64 i;
+ } ux = { x }, uy = { y };
+ ux.i &= UINT64_MAX / 2;
+ ux.i |= uy.i & 1ULL << 63;
+ return ux.f;
+}
+
+static uint64
+read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign)
+{
+ uint64 result = 0, byte;
+ uint32 offset = *p_offset;
+ uint32 shift = 0;
+
+ while (true) {
+ byte = buf[offset++];
+ result |= ((byte & 0x7f) << shift);
+ shift += 7;
+ if ((byte & 0x80) == 0) {
+ break;
+ }
+ }
+ if (sign && (shift < maxbits) && (byte & 0x40)) {
+ /* Sign extend */
+ result |= (~((uint64)0)) << shift;
+ }
+ *p_offset = offset;
+ return result;
+}
+
+#define skip_leb(p) while (*p++ & 0x80)
+
+#define PUSH_I32(value) \
+ do { \
+ *(int32 *)frame_sp++ = (int32)(value); \
+ } while (0)
+
+#define PUSH_F32(value) \
+ do { \
+ *(float32 *)frame_sp++ = (float32)(value); \
+ } while (0)
+
+#define PUSH_I64(value) \
+ do { \
+ PUT_I64_TO_ADDR(frame_sp, value); \
+ frame_sp += 2; \
+ } while (0)
+
+#define PUSH_F64(value) \
+ do { \
+ PUT_F64_TO_ADDR(frame_sp, value); \
+ frame_sp += 2; \
+ } while (0)
+
+#define PUSH_CSP(_label_type, param_cell_num, cell_num, _target_addr) \
+ do { \
+ bh_assert(frame_csp < frame->csp_boundary); \
+ /* frame_csp->label_type = _label_type; */ \
+ frame_csp->cell_num = cell_num; \
+ frame_csp->begin_addr = frame_ip; \
+ frame_csp->target_addr = _target_addr; \
+ frame_csp->frame_sp = frame_sp - param_cell_num; \
+ frame_csp++; \
+ } while (0)
+
+#define POP_I32() (--frame_sp, *(int32 *)frame_sp)
+
+#define POP_F32() (--frame_sp, *(float32 *)frame_sp)
+
+#define POP_I64() (frame_sp -= 2, GET_I64_FROM_ADDR(frame_sp))
+
+#define POP_F64() (frame_sp -= 2, GET_F64_FROM_ADDR(frame_sp))
+
+#define POP_CSP_CHECK_OVERFLOW(n) \
+ do { \
+ bh_assert(frame_csp - n >= frame->csp_bottom); \
+ } while (0)
+
+#define POP_CSP() \
+ do { \
+ POP_CSP_CHECK_OVERFLOW(1); \
+ --frame_csp; \
+ } while (0)
+
+#define POP_CSP_N(n) \
+ do { \
+ uint32 *frame_sp_old = frame_sp; \
+ uint32 cell_num_to_copy; \
+ POP_CSP_CHECK_OVERFLOW(n + 1); \
+ frame_csp -= n; \
+ frame_ip = (frame_csp - 1)->target_addr; \
+ /* copy arity values of block */ \
+ frame_sp = (frame_csp - 1)->frame_sp; \
+ cell_num_to_copy = (frame_csp - 1)->cell_num; \
+ if (cell_num_to_copy > 0) { \
+ word_copy(frame_sp, frame_sp_old - cell_num_to_copy, \
+ cell_num_to_copy); \
+ } \
+ frame_sp += cell_num_to_copy; \
+ } while (0)
+
+/* Pop the given number of elements from the given frame's stack. */
+#define POP(N) \
+ do { \
+ int n = (N); \
+ frame_sp -= n; \
+ } while (0)
+
+#define SYNC_ALL_TO_FRAME() \
+ do { \
+ frame->sp = frame_sp; \
+ frame->ip = frame_ip; \
+ frame->csp = frame_csp; \
+ } while (0)
+
+#define UPDATE_ALL_FROM_FRAME() \
+ do { \
+ frame_sp = frame->sp; \
+ frame_ip = frame->ip; \
+ frame_csp = frame->csp; \
+ } while (0)
+
+#define read_leb_int64(p, p_end, res) \
+ do { \
+ uint8 _val = *p; \
+ if (!(_val & 0x80)) { \
+ res = (int64)_val; \
+ if (_val & 0x40) \
+ /* sign extend */ \
+ res |= 0xFFFFFFFFFFFFFF80LL; \
+ p++; \
+ break; \
+ } \
+ uint32 _off = 0; \
+ res = (int64)read_leb(p, &_off, 64, true); \
+ p += _off; \
+ } while (0)
+
+#define read_leb_uint32(p, p_end, res) \
+ do { \
+ uint8 _val = *p; \
+ if (!(_val & 0x80)) { \
+ res = _val; \
+ p++; \
+ break; \
+ } \
+ uint32 _off = 0; \
+ res = (uint32)read_leb(p, &_off, 32, false); \
+ p += _off; \
+ } while (0)
+
+#define read_leb_int32(p, p_end, res) \
+ do { \
+ uint8 _val = *p; \
+ if (!(_val & 0x80)) { \
+ res = (int32)_val; \
+ if (_val & 0x40) \
+ /* sign extend */ \
+ res |= 0xFFFFFF80; \
+ p++; \
+ break; \
+ } \
+ uint32 _off = 0; \
+ res = (int32)read_leb(p, &_off, 32, true); \
+ p += _off; \
+ } while (0)
+
+#if WASM_ENABLE_LABELS_AS_VALUES == 0
+#define RECOVER_FRAME_IP_END() frame_ip_end = wasm_get_func_code_end(cur_func)
+#else
+#define RECOVER_FRAME_IP_END() (void)0
+#endif
+
+#define RECOVER_CONTEXT(new_frame) \
+ do { \
+ frame = (new_frame); \
+ cur_func = frame->function; \
+ prev_frame = frame->prev_frame; \
+ frame_ip = frame->ip; \
+ RECOVER_FRAME_IP_END(); \
+ frame_lp = frame->lp; \
+ frame_sp = frame->sp; \
+ frame_csp = frame->csp; \
+ } while (0)
+
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+#define GET_OPCODE() opcode = *(frame_ip - 1);
+#else
+#define GET_OPCODE() (void)0
+#endif
+
+#define DEF_OP_I_CONST(ctype, src_op_type) \
+ do { \
+ ctype cval; \
+ read_leb_##ctype(frame_ip, frame_ip_end, cval); \
+ PUSH_##src_op_type(cval); \
+ } while (0)
+
+#define DEF_OP_EQZ(src_op_type) \
+ do { \
+ int32 pop_val; \
+ pop_val = POP_##src_op_type() == 0; \
+ PUSH_I32(pop_val); \
+ } while (0)
+
+#define DEF_OP_CMP(src_type, src_op_type, cond) \
+ do { \
+ uint32 res; \
+ src_type val1, val2; \
+ val2 = (src_type)POP_##src_op_type(); \
+ val1 = (src_type)POP_##src_op_type(); \
+ res = val1 cond val2; \
+ PUSH_I32(res); \
+ } while (0)
+
+#define DEF_OP_BIT_COUNT(src_type, src_op_type, operation) \
+ do { \
+ src_type val1, val2; \
+ val1 = (src_type)POP_##src_op_type(); \
+ val2 = (src_type)operation(val1); \
+ PUSH_##src_op_type(val2); \
+ } while (0)
+
+#define DEF_OP_NUMERIC(src_type1, src_type2, src_op_type, operation) \
+ do { \
+ frame_sp -= sizeof(src_type2) / sizeof(uint32); \
+ *(src_type1 *)(frame_sp - sizeof(src_type1) / sizeof(uint32)) \
+ operation## = *(src_type2 *)(frame_sp); \
+ } while (0)
+
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
+#define DEF_OP_NUMERIC_64 DEF_OP_NUMERIC
+#else
+#define DEF_OP_NUMERIC_64(src_type1, src_type2, src_op_type, operation) \
+ do { \
+ src_type1 val1; \
+ src_type2 val2; \
+ frame_sp -= 2; \
+ val1 = (src_type1)GET_##src_op_type##_FROM_ADDR(frame_sp - 2); \
+ val2 = (src_type2)GET_##src_op_type##_FROM_ADDR(frame_sp); \
+ val1 operation## = val2; \
+ PUT_##src_op_type##_TO_ADDR(frame_sp - 2, val1); \
+ } while (0)
+#endif
+
+#define DEF_OP_NUMERIC2(src_type1, src_type2, src_op_type, operation) \
+ do { \
+ frame_sp -= sizeof(src_type2) / sizeof(uint32); \
+ *(src_type1 *)(frame_sp - sizeof(src_type1) / sizeof(uint32)) \
+ operation## = (*(src_type2 *)(frame_sp) % 32); \
+ } while (0)
+
+#define DEF_OP_NUMERIC2_64(src_type1, src_type2, src_op_type, operation) \
+ do { \
+ src_type1 val1; \
+ src_type2 val2; \
+ frame_sp -= 2; \
+ val1 = (src_type1)GET_##src_op_type##_FROM_ADDR(frame_sp - 2); \
+ val2 = (src_type2)GET_##src_op_type##_FROM_ADDR(frame_sp); \
+ val1 operation## = (val2 % 64); \
+ PUT_##src_op_type##_TO_ADDR(frame_sp - 2, val1); \
+ } while (0)
+
+#define DEF_OP_MATH(src_type, src_op_type, method) \
+ do { \
+ src_type src_val; \
+ src_val = POP_##src_op_type(); \
+ PUSH_##src_op_type(method(src_val)); \
+ } while (0)
+
+#define TRUNC_FUNCTION(func_name, src_type, dst_type, signed_type) \
+ static dst_type func_name(src_type src_value, src_type src_min, \
+ src_type src_max, dst_type dst_min, \
+ dst_type dst_max, bool is_sign) \
+ { \
+ dst_type dst_value = 0; \
+ if (!isnan(src_value)) { \
+ if (src_value <= src_min) \
+ dst_value = dst_min; \
+ else if (src_value >= src_max) \
+ dst_value = dst_max; \
+ else { \
+ if (is_sign) \
+ dst_value = (dst_type)(signed_type)src_value; \
+ else \
+ dst_value = (dst_type)src_value; \
+ } \
+ } \
+ return dst_value; \
+ }
+
+TRUNC_FUNCTION(trunc_f32_to_i32, float32, uint32, int32)
+TRUNC_FUNCTION(trunc_f32_to_i64, float32, uint64, int64)
+TRUNC_FUNCTION(trunc_f64_to_i32, float64, uint32, int32)
+TRUNC_FUNCTION(trunc_f64_to_i64, float64, uint64, int64)
+
+static bool
+trunc_f32_to_int(WASMModuleInstance *module, uint32 *frame_sp, float32 src_min,
+ float32 src_max, bool saturating, bool is_i32, bool is_sign)
+{
+ float32 src_value = POP_F32();
+ uint64 dst_value_i64;
+ uint32 dst_value_i32;
+
+ if (!saturating) {
+ if (isnan(src_value)) {
+ wasm_set_exception(module, "invalid conversion to integer");
+ return false;
+ }
+ else if (src_value <= src_min || src_value >= src_max) {
+ wasm_set_exception(module, "integer overflow");
+ return false;
+ }
+ }
+
+ if (is_i32) {
+ uint32 dst_min = is_sign ? INT32_MIN : 0;
+ uint32 dst_max = is_sign ? INT32_MAX : UINT32_MAX;
+ dst_value_i32 = trunc_f32_to_i32(src_value, src_min, src_max, dst_min,
+ dst_max, is_sign);
+ PUSH_I32(dst_value_i32);
+ }
+ else {
+ uint64 dst_min = is_sign ? INT64_MIN : 0;
+ uint64 dst_max = is_sign ? INT64_MAX : UINT64_MAX;
+ dst_value_i64 = trunc_f32_to_i64(src_value, src_min, src_max, dst_min,
+ dst_max, is_sign);
+ PUSH_I64(dst_value_i64);
+ }
+ return true;
+}
+
+static bool
+trunc_f64_to_int(WASMModuleInstance *module, uint32 *frame_sp, float64 src_min,
+ float64 src_max, bool saturating, bool is_i32, bool is_sign)
+{
+ float64 src_value = POP_F64();
+ uint64 dst_value_i64;
+ uint32 dst_value_i32;
+
+ if (!saturating) {
+ if (isnan(src_value)) {
+ wasm_set_exception(module, "invalid conversion to integer");
+ return false;
+ }
+ else if (src_value <= src_min || src_value >= src_max) {
+ wasm_set_exception(module, "integer overflow");
+ return false;
+ }
+ }
+
+ if (is_i32) {
+ uint32 dst_min = is_sign ? INT32_MIN : 0;
+ uint32 dst_max = is_sign ? INT32_MAX : UINT32_MAX;
+ dst_value_i32 = trunc_f64_to_i32(src_value, src_min, src_max, dst_min,
+ dst_max, is_sign);
+ PUSH_I32(dst_value_i32);
+ }
+ else {
+ uint64 dst_min = is_sign ? INT64_MIN : 0;
+ uint64 dst_max = is_sign ? INT64_MAX : UINT64_MAX;
+ dst_value_i64 = trunc_f64_to_i64(src_value, src_min, src_max, dst_min,
+ dst_max, is_sign);
+ PUSH_I64(dst_value_i64);
+ }
+ return true;
+}
+
+#define DEF_OP_TRUNC_F32(min, max, is_i32, is_sign) \
+ do { \
+ if (!trunc_f32_to_int(module, frame_sp, min, max, false, is_i32, \
+ is_sign)) \
+ goto got_exception; \
+ } while (0)
+
+#define DEF_OP_TRUNC_F64(min, max, is_i32, is_sign) \
+ do { \
+ if (!trunc_f64_to_int(module, frame_sp, min, max, false, is_i32, \
+ is_sign)) \
+ goto got_exception; \
+ } while (0)
+
+#define DEF_OP_TRUNC_SAT_F32(min, max, is_i32, is_sign) \
+ do { \
+ (void)trunc_f32_to_int(module, frame_sp, min, max, true, is_i32, \
+ is_sign); \
+ } while (0)
+
+#define DEF_OP_TRUNC_SAT_F64(min, max, is_i32, is_sign) \
+ do { \
+ (void)trunc_f64_to_int(module, frame_sp, min, max, true, is_i32, \
+ is_sign); \
+ } while (0)
+
+#define DEF_OP_CONVERT(dst_type, dst_op_type, src_type, src_op_type) \
+ do { \
+ dst_type value = (dst_type)(src_type)POP_##src_op_type(); \
+ PUSH_##dst_op_type(value); \
+ } while (0)
+
+#define GET_LOCAL_INDEX_TYPE_AND_OFFSET() \
+ do { \
+ uint32 param_count = cur_func->param_count; \
+ read_leb_uint32(frame_ip, frame_ip_end, local_idx); \
+ bh_assert(local_idx < param_count + cur_func->local_count); \
+ local_offset = cur_func->local_offsets[local_idx]; \
+ if (local_idx < param_count) \
+ local_type = cur_func->param_types[local_idx]; \
+ else \
+ local_type = cur_func->local_types[local_idx - param_count]; \
+ } while (0)
+
+#define DEF_ATOMIC_RMW_OPCODE(OP_NAME, op) \
+ case WASM_OP_ATOMIC_RMW_I32_##OP_NAME: \
+ case WASM_OP_ATOMIC_RMW_I32_##OP_NAME##8_U: \
+ case WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U: \
+ { \
+ uint32 readv, sval; \
+ \
+ sval = POP_I32(); \
+ addr = POP_I32(); \
+ \
+ if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##8_U) { \
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \
+ CHECK_ATOMIC_MEMORY_ACCESS(); \
+ \
+ os_mutex_lock(&node->shared_mem_lock); \
+ readv = (uint32)(*(uint8 *)maddr); \
+ *(uint8 *)maddr = (uint8)(readv op sval); \
+ os_mutex_unlock(&node->shared_mem_lock); \
+ } \
+ else if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U) { \
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \
+ CHECK_ATOMIC_MEMORY_ACCESS(); \
+ \
+ os_mutex_lock(&node->shared_mem_lock); \
+ readv = (uint32)LOAD_U16(maddr); \
+ STORE_U16(maddr, (uint16)(readv op sval)); \
+ os_mutex_unlock(&node->shared_mem_lock); \
+ } \
+ else { \
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \
+ CHECK_ATOMIC_MEMORY_ACCESS(); \
+ \
+ os_mutex_lock(&node->shared_mem_lock); \
+ readv = LOAD_I32(maddr); \
+ STORE_U32(maddr, readv op sval); \
+ os_mutex_unlock(&node->shared_mem_lock); \
+ } \
+ PUSH_I32(readv); \
+ break; \
+ } \
+ case WASM_OP_ATOMIC_RMW_I64_##OP_NAME: \
+ case WASM_OP_ATOMIC_RMW_I64_##OP_NAME##8_U: \
+ case WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U: \
+ case WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U: \
+ { \
+ uint64 readv, sval; \
+ \
+ sval = (uint64)POP_I64(); \
+ addr = POP_I32(); \
+ \
+ if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##8_U) { \
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \
+ CHECK_ATOMIC_MEMORY_ACCESS(); \
+ \
+ os_mutex_lock(&node->shared_mem_lock); \
+ readv = (uint64)(*(uint8 *)maddr); \
+ *(uint8 *)maddr = (uint8)(readv op sval); \
+ os_mutex_unlock(&node->shared_mem_lock); \
+ } \
+ else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U) { \
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \
+ CHECK_ATOMIC_MEMORY_ACCESS(); \
+ \
+ os_mutex_lock(&node->shared_mem_lock); \
+ readv = (uint64)LOAD_U16(maddr); \
+ STORE_U16(maddr, (uint16)(readv op sval)); \
+ os_mutex_unlock(&node->shared_mem_lock); \
+ } \
+ else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U) { \
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \
+ CHECK_ATOMIC_MEMORY_ACCESS(); \
+ \
+ os_mutex_lock(&node->shared_mem_lock); \
+ readv = (uint64)LOAD_U32(maddr); \
+ STORE_U32(maddr, (uint32)(readv op sval)); \
+ os_mutex_unlock(&node->shared_mem_lock); \
+ } \
+ else { \
+ uint64 op_result; \
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); \
+ CHECK_ATOMIC_MEMORY_ACCESS(); \
+ \
+ os_mutex_lock(&node->shared_mem_lock); \
+ readv = (uint64)LOAD_I64(maddr); \
+ op_result = readv op sval; \
+ STORE_I64(maddr, op_result); \
+ os_mutex_unlock(&node->shared_mem_lock); \
+ } \
+ PUSH_I64(readv); \
+ break; \
+ }
+
+static inline int32
+sign_ext_8_32(int8 val)
+{
+ if (val & 0x80)
+ return (int32)val | (int32)0xffffff00;
+ return val;
+}
+
+static inline int32
+sign_ext_16_32(int16 val)
+{
+ if (val & 0x8000)
+ return (int32)val | (int32)0xffff0000;
+ return val;
+}
+
+static inline int64
+sign_ext_8_64(int8 val)
+{
+ if (val & 0x80)
+ return (int64)val | (int64)0xffffffffffffff00LL;
+ return val;
+}
+
+static inline int64
+sign_ext_16_64(int16 val)
+{
+ if (val & 0x8000)
+ return (int64)val | (int64)0xffffffffffff0000LL;
+ return val;
+}
+
+static inline int64
+sign_ext_32_64(int32 val)
+{
+ if (val & (int32)0x80000000)
+ return (int64)val | (int64)0xffffffff00000000LL;
+ return val;
+}
+
+static inline void
+word_copy(uint32 *dest, uint32 *src, unsigned num)
+{
+ bh_assert(dest != NULL);
+ bh_assert(src != NULL);
+ bh_assert(num > 0);
+ if (dest != src) {
+ /* No overlap buffer */
+ bh_assert(!((src < dest) && (dest < src + num)));
+ for (; num > 0; num--)
+ *dest++ = *src++;
+ }
+}
+
+static inline WASMInterpFrame *
+ALLOC_FRAME(WASMExecEnv *exec_env, uint32 size, WASMInterpFrame *prev_frame)
+{
+ WASMInterpFrame *frame = wasm_exec_env_alloc_wasm_frame(exec_env, size);
+
+ if (frame) {
+ frame->prev_frame = prev_frame;
+#if WASM_ENABLE_PERF_PROFILING != 0
+ frame->time_started = os_time_get_boot_microsecond();
+#endif
+ }
+ else {
+ wasm_set_exception((WASMModuleInstance *)exec_env->module_inst,
+ "wasm operand stack overflow");
+ }
+
+ return frame;
+}
+
+static inline void
+FREE_FRAME(WASMExecEnv *exec_env, WASMInterpFrame *frame)
+{
+#if WASM_ENABLE_PERF_PROFILING != 0
+ if (frame->function) {
+ frame->function->total_exec_time +=
+ os_time_get_boot_microsecond() - frame->time_started;
+ frame->function->total_exec_cnt++;
+ }
+#endif
+ wasm_exec_env_free_wasm_frame(exec_env, frame);
+}
+
+static void
+wasm_interp_call_func_native(WASMModuleInstance *module_inst,
+ WASMExecEnv *exec_env,
+ WASMFunctionInstance *cur_func,
+ WASMInterpFrame *prev_frame)
+{
+ WASMFunctionImport *func_import = cur_func->u.func_import;
+ CApiFuncImport *c_api_func_import = NULL;
+ unsigned local_cell_num = 2;
+ WASMInterpFrame *frame;
+ uint32 argv_ret[2], cur_func_index;
+ void *native_func_pointer = NULL;
+ char buf[128];
+ bool ret;
+
+ if (!(frame = ALLOC_FRAME(exec_env,
+ wasm_interp_interp_frame_size(local_cell_num),
+ prev_frame)))
+ return;
+
+ frame->function = cur_func;
+ frame->ip = NULL;
+ frame->sp = frame->lp + local_cell_num;
+
+ wasm_exec_env_set_cur_frame(exec_env, frame);
+
+ cur_func_index = (uint32)(cur_func - module_inst->e->functions);
+ bh_assert(cur_func_index < module_inst->module->import_function_count);
+ if (!func_import->call_conv_wasm_c_api) {
+ native_func_pointer = module_inst->import_func_ptrs[cur_func_index];
+ }
+ else if (module_inst->e->c_api_func_imports) {
+ c_api_func_import = module_inst->e->c_api_func_imports + cur_func_index;
+ native_func_pointer = c_api_func_import->func_ptr_linked;
+ }
+
+ if (!native_func_pointer) {
+ snprintf(buf, sizeof(buf),
+ "failed to call unlinked import function (%s, %s)",
+ func_import->module_name, func_import->field_name);
+ wasm_set_exception(module_inst, buf);
+ return;
+ }
+
+ if (func_import->call_conv_wasm_c_api) {
+ ret = wasm_runtime_invoke_c_api_native(
+ (WASMModuleInstanceCommon *)module_inst, native_func_pointer,
+ func_import->func_type, cur_func->param_cell_num, frame->lp,
+ c_api_func_import->with_env_arg, c_api_func_import->env_arg);
+ if (ret) {
+ argv_ret[0] = frame->lp[0];
+ argv_ret[1] = frame->lp[1];
+ }
+ }
+ else if (!func_import->call_conv_raw) {
+ ret = wasm_runtime_invoke_native(
+ exec_env, native_func_pointer, func_import->func_type,
+ func_import->signature, func_import->attachment, frame->lp,
+ cur_func->param_cell_num, argv_ret);
+ }
+ else {
+ ret = wasm_runtime_invoke_native_raw(
+ exec_env, native_func_pointer, func_import->func_type,
+ func_import->signature, func_import->attachment, frame->lp,
+ cur_func->param_cell_num, argv_ret);
+ }
+
+ if (!ret)
+ return;
+
+ if (cur_func->ret_cell_num == 1) {
+ prev_frame->sp[0] = argv_ret[0];
+ prev_frame->sp++;
+ }
+ else if (cur_func->ret_cell_num == 2) {
+ prev_frame->sp[0] = argv_ret[0];
+ prev_frame->sp[1] = argv_ret[1];
+ prev_frame->sp += 2;
+ }
+
+ FREE_FRAME(exec_env, frame);
+ wasm_exec_env_set_cur_frame(exec_env, prev_frame);
+}
+
+#if WASM_ENABLE_FAST_JIT != 0
+bool
+fast_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx,
+ WASMInterpFrame *prev_frame)
+{
+ WASMModuleInstance *module_inst =
+ (WASMModuleInstance *)exec_env->module_inst;
+ WASMFunctionInstance *cur_func = module_inst->e->functions + func_idx;
+
+ wasm_interp_call_func_native(module_inst, exec_env, cur_func, prev_frame);
+ return wasm_copy_exception(module_inst, NULL) ? false : true;
+}
+#endif
+
+#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];
+ WASMExecEnv *sub_module_exec_env = NULL;
+ uint32 aux_stack_origin_boundary = 0;
+ uint32 aux_stack_origin_bottom = 0;
+
+ if (!sub_func_inst) {
+ snprintf(buf, sizeof(buf),
+ "failed to call unlinked import function (%s, %s)",
+ func_import->module_name, func_import->field_name);
+ wasm_set_exception(module_inst, buf);
+ return;
+ }
+
+ /* Switch exec_env but keep using the same one by replacing necessary
+ * variables */
+ sub_module_exec_env = wasm_runtime_get_exec_env_singleton(
+ (WASMModuleInstanceCommon *)sub_module_inst);
+ if (!sub_module_exec_env) {
+ wasm_set_exception(module_inst, "create singleton exec_env failed");
+ return;
+ }
+
+ /* - module_inst */
+ exec_env->module_inst = (WASMModuleInstanceCommon *)sub_module_inst;
+ /* - aux_stack_boundary */
+ aux_stack_origin_boundary = exec_env->aux_stack_boundary.boundary;
+ exec_env->aux_stack_boundary.boundary =
+ sub_module_exec_env->aux_stack_boundary.boundary;
+ /* - aux_stack_bottom */
+ aux_stack_origin_bottom = exec_env->aux_stack_bottom.bottom;
+ exec_env->aux_stack_bottom.bottom =
+ sub_module_exec_env->aux_stack_bottom.bottom;
+
+ /* set ip NULL to make call_func_bytecode return after executing
+ this function */
+ prev_frame->ip = NULL;
+
+ /* call function of sub-module*/
+ wasm_interp_call_func_bytecode(sub_module_inst, exec_env, sub_func_inst,
+ prev_frame);
+
+ /* restore ip and other replaced */
+ prev_frame->ip = ip;
+ exec_env->aux_stack_boundary.boundary = aux_stack_origin_boundary;
+ exec_env->aux_stack_bottom.bottom = aux_stack_origin_bottom;
+ exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
+
+ /* transfer exception if it is thrown */
+ if (wasm_copy_exception(sub_module_inst, NULL)) {
+ 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_THREAD_MGR != 0
+#if WASM_ENABLE_DEBUG_INTERP != 0
+#define CHECK_SUSPEND_FLAGS() \
+ do { \
+ os_mutex_lock(&exec_env->wait_lock); \
+ if (IS_WAMR_TERM_SIG(exec_env->current_status->signal_flag)) { \
+ os_mutex_unlock(&exec_env->wait_lock); \
+ return; \
+ } \
+ if (IS_WAMR_STOP_SIG(exec_env->current_status->signal_flag)) { \
+ SYNC_ALL_TO_FRAME(); \
+ wasm_cluster_thread_waiting_run(exec_env); \
+ } \
+ os_mutex_unlock(&exec_env->wait_lock); \
+ } while (0)
+#else
+#define CHECK_SUSPEND_FLAGS() \
+ do { \
+ os_mutex_lock(&exec_env->wait_lock); \
+ if (exec_env->suspend_flags.flags != 0) { \
+ if (exec_env->suspend_flags.flags & 0x01) { \
+ /* terminate current thread */ \
+ os_mutex_unlock(&exec_env->wait_lock); \
+ return; \
+ } \
+ while (exec_env->suspend_flags.flags & 0x02) { \
+ /* suspend current thread */ \
+ os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock); \
+ } \
+ } \
+ os_mutex_unlock(&exec_env->wait_lock); \
+ } while (0)
+#endif /* WASM_ENABLE_DEBUG_INTERP */
+#endif /* WASM_ENABLE_THREAD_MGR */
+
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+
+#define HANDLE_OP(opcode) HANDLE_##opcode:
+#define FETCH_OPCODE_AND_DISPATCH() goto *handle_table[*frame_ip++]
+
+#if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0
+#define HANDLE_OP_END() \
+ do { \
+ /* Record the current frame_ip, so when exception occurs, \
+ debugger can know the exact opcode who caused the exception */ \
+ frame_ip_orig = frame_ip; \
+ os_mutex_lock(&exec_env->wait_lock); \
+ while (exec_env->current_status->signal_flag == WAMR_SIG_SINGSTEP \
+ && exec_env->current_status->step_count++ == 1) { \
+ exec_env->current_status->step_count = 0; \
+ SYNC_ALL_TO_FRAME(); \
+ wasm_cluster_thread_waiting_run(exec_env); \
+ } \
+ os_mutex_unlock(&exec_env->wait_lock); \
+ goto *handle_table[*frame_ip++]; \
+ } while (0)
+#else
+#define HANDLE_OP_END() FETCH_OPCODE_AND_DISPATCH()
+#endif
+
+#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
+#define HANDLE_OP(opcode) case opcode:
+#if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0
+#define HANDLE_OP_END() \
+ os_mutex_lock(&exec_env->wait_lock); \
+ if (exec_env->current_status->signal_flag == WAMR_SIG_SINGSTEP \
+ && exec_env->current_status->step_count++ == 2) { \
+ exec_env->current_status->step_count = 0; \
+ SYNC_ALL_TO_FRAME(); \
+ wasm_cluster_thread_waiting_run(exec_env); \
+ } \
+ os_mutex_unlock(&exec_env->wait_lock); \
+ continue
+#else
+#define HANDLE_OP_END() continue
+#endif
+
+#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */
+
+static inline uint8 *
+get_global_addr(uint8 *global_data, WASMGlobalInstance *global)
+{
+#if WASM_ENABLE_MULTI_MODULE == 0
+ return global_data + global->data_offset;
+#else
+ return global->import_global_inst
+ ? global->import_module_inst->global_data
+ + global->import_global_inst->data_offset
+ : global_data + global->data_offset;
+#endif
+}
+
+static void
+wasm_interp_call_func_bytecode(WASMModuleInstance *module,
+ WASMExecEnv *exec_env,
+ WASMFunctionInstance *cur_func,
+ WASMInterpFrame *prev_frame)
+{
+#if WASM_ENABLE_SHARED_MEMORY != 0
+ WASMSharedMemNode *node =
+ wasm_module_get_shared_memory((WASMModuleCommon *)module->module);
+#endif
+ WASMMemoryInstance *memory = wasm_get_default_memory(module);
+#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
+ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
+ || WASM_ENABLE_BULK_MEMORY != 0
+ uint32 linear_mem_size = memory ? memory->memory_data_size : 0;
+#endif
+ WASMType **wasm_types = module->module->types;
+ WASMGlobalInstance *globals = module->e->globals, *global;
+ uint8 *global_data = module->global_data;
+ uint8 opcode_IMPDEP = WASM_OP_IMPDEP;
+ WASMInterpFrame *frame = NULL;
+ /* Points to this special opcode so as to jump to the
+ * call_method_from_entry. */
+ register uint8 *frame_ip = &opcode_IMPDEP; /* cache of frame->ip */
+ register uint32 *frame_lp = NULL; /* cache of frame->lp */
+ register uint32 *frame_sp = NULL; /* cache of frame->sp */
+ WASMBranchBlock *frame_csp = NULL;
+ BlockAddr *cache_items;
+ uint8 *frame_ip_end = frame_ip + 1;
+ uint8 opcode;
+ uint32 i, depth, cond, count, fidx, tidx, lidx, frame_size = 0;
+ uint32 all_cell_num = 0;
+ int32 val;
+ uint8 *else_addr, *end_addr, *maddr = NULL;
+ uint32 local_idx, local_offset, global_idx;
+ uint8 local_type, *global_addr;
+ uint32 cache_index, type_index, param_cell_num, cell_num;
+ uint8 value_type;
+
+#if WASM_ENABLE_DEBUG_INTERP != 0
+ uint8 *frame_ip_orig = NULL;
+ WASMDebugInstance *debug_instance = wasm_exec_env_get_instance(exec_env);
+ bh_list *watch_point_list_read =
+ debug_instance ? &debug_instance->watch_point_list_read : NULL;
+ bh_list *watch_point_list_write =
+ debug_instance ? &debug_instance->watch_point_list_write : NULL;
+#endif
+
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+#define HANDLE_OPCODE(op) &&HANDLE_##op
+ DEFINE_GOTO_TABLE(const void *, handle_table);
+#undef HANDLE_OPCODE
+#endif
+
+#if WASM_ENABLE_LABELS_AS_VALUES == 0
+ while (frame_ip < frame_ip_end) {
+ opcode = *frame_ip++;
+ switch (opcode) {
+#else
+ FETCH_OPCODE_AND_DISPATCH();
+#endif
+ /* control instructions */
+ HANDLE_OP(WASM_OP_UNREACHABLE)
+ {
+ wasm_set_exception(module, "unreachable");
+ goto got_exception;
+ }
+
+ HANDLE_OP(WASM_OP_NOP) { HANDLE_OP_END(); }
+
+ HANDLE_OP(EXT_OP_BLOCK)
+ {
+ read_leb_uint32(frame_ip, frame_ip_end, type_index);
+ param_cell_num = wasm_types[type_index]->param_cell_num;
+ cell_num = wasm_types[type_index]->ret_cell_num;
+ goto handle_op_block;
+ }
+
+ HANDLE_OP(WASM_OP_BLOCK)
+ {
+ value_type = *frame_ip++;
+ param_cell_num = 0;
+ cell_num = wasm_value_type_cell_num(value_type);
+ handle_op_block:
+ cache_index = ((uintptr_t)frame_ip)
+ & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1);
+ cache_items = exec_env->block_addr_cache[cache_index];
+ if (cache_items[0].start_addr == frame_ip) {
+ end_addr = cache_items[0].end_addr;
+ }
+ else if (cache_items[1].start_addr == frame_ip) {
+ end_addr = cache_items[1].end_addr;
+ }
+#if WASM_ENABLE_DEBUG_INTERP != 0
+ else if (!wasm_loader_find_block_addr(
+ exec_env, (BlockAddr *)exec_env->block_addr_cache,
+ frame_ip, (uint8 *)-1, LABEL_TYPE_BLOCK,
+ &else_addr, &end_addr)) {
+ wasm_set_exception(module, "find block address failed");
+ goto got_exception;
+ }
+#endif
+ else {
+ end_addr = NULL;
+ }
+ PUSH_CSP(LABEL_TYPE_BLOCK, param_cell_num, cell_num, end_addr);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(EXT_OP_LOOP)
+ {
+ read_leb_uint32(frame_ip, frame_ip_end, type_index);
+ param_cell_num = wasm_types[type_index]->param_cell_num;
+ cell_num = wasm_types[type_index]->param_cell_num;
+ goto handle_op_loop;
+ }
+
+ HANDLE_OP(WASM_OP_LOOP)
+ {
+ value_type = *frame_ip++;
+ param_cell_num = 0;
+ cell_num = 0;
+ handle_op_loop:
+ PUSH_CSP(LABEL_TYPE_LOOP, param_cell_num, cell_num, frame_ip);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(EXT_OP_IF)
+ {
+ read_leb_uint32(frame_ip, frame_ip_end, type_index);
+ param_cell_num = wasm_types[type_index]->param_cell_num;
+ cell_num = wasm_types[type_index]->ret_cell_num;
+ goto handle_op_if;
+ }
+
+ HANDLE_OP(WASM_OP_IF)
+ {
+ value_type = *frame_ip++;
+ param_cell_num = 0;
+ cell_num = wasm_value_type_cell_num(value_type);
+ handle_op_if:
+ cache_index = ((uintptr_t)frame_ip)
+ & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1);
+ cache_items = exec_env->block_addr_cache[cache_index];
+ if (cache_items[0].start_addr == frame_ip) {
+ else_addr = cache_items[0].else_addr;
+ end_addr = cache_items[0].end_addr;
+ }
+ else if (cache_items[1].start_addr == frame_ip) {
+ else_addr = cache_items[1].else_addr;
+ end_addr = cache_items[1].end_addr;
+ }
+ else if (!wasm_loader_find_block_addr(
+ exec_env, (BlockAddr *)exec_env->block_addr_cache,
+ frame_ip, (uint8 *)-1, LABEL_TYPE_IF, &else_addr,
+ &end_addr)) {
+ wasm_set_exception(module, "find block address failed");
+ goto got_exception;
+ }
+
+ cond = (uint32)POP_I32();
+
+ if (cond) { /* if branch is met */
+ PUSH_CSP(LABEL_TYPE_IF, param_cell_num, cell_num, end_addr);
+ }
+ else { /* if branch is not met */
+ /* if there is no else branch, go to the end addr */
+ if (else_addr == NULL) {
+ frame_ip = end_addr + 1;
+ }
+ /* if there is an else branch, go to the else addr */
+ else {
+ PUSH_CSP(LABEL_TYPE_IF, param_cell_num, cell_num,
+ end_addr);
+ frame_ip = else_addr + 1;
+ }
+ }
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_ELSE)
+ {
+ /* comes from the if branch in WASM_OP_IF */
+ frame_ip = (frame_csp - 1)->target_addr;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_END)
+ {
+ if (frame_csp > frame->csp_bottom + 1) {
+ POP_CSP();
+ }
+ else { /* end of function, treat as WASM_OP_RETURN */
+ frame_sp -= cur_func->ret_cell_num;
+ for (i = 0; i < cur_func->ret_cell_num; i++) {
+ *prev_frame->sp++ = frame_sp[i];
+ }
+ goto return_func;
+ }
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_BR)
+ {
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+ read_leb_uint32(frame_ip, frame_ip_end, depth);
+ label_pop_csp_n:
+ POP_CSP_N(depth);
+ if (!frame_ip) { /* must be label pushed by WASM_OP_BLOCK */
+ if (!wasm_loader_find_block_addr(
+ exec_env, (BlockAddr *)exec_env->block_addr_cache,
+ (frame_csp - 1)->begin_addr, (uint8 *)-1,
+ LABEL_TYPE_BLOCK, &else_addr, &end_addr)) {
+ wasm_set_exception(module, "find block address failed");
+ goto got_exception;
+ }
+ frame_ip = end_addr;
+ }
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_BR_IF)
+ {
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+ read_leb_uint32(frame_ip, frame_ip_end, depth);
+ cond = (uint32)POP_I32();
+ if (cond)
+ goto label_pop_csp_n;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_BR_TABLE)
+ {
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+ read_leb_uint32(frame_ip, frame_ip_end, count);
+ lidx = POP_I32();
+ if (lidx > count)
+ lidx = count;
+ depth = frame_ip[lidx];
+ goto label_pop_csp_n;
+ }
+
+ HANDLE_OP(EXT_OP_BR_TABLE_CACHE)
+ {
+ BrTableCache *node_cache =
+ bh_list_first_elem(module->module->br_table_cache_list);
+ BrTableCache *node_next;
+
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+ lidx = POP_I32();
+
+ while (node_cache) {
+ node_next = bh_list_elem_next(node_cache);
+ if (node_cache->br_table_op_addr == frame_ip - 1) {
+ depth = node_cache->br_depths[lidx];
+ goto label_pop_csp_n;
+ }
+ node_cache = node_next;
+ }
+ bh_assert(0);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_RETURN)
+ {
+ frame_sp -= cur_func->ret_cell_num;
+ for (i = 0; i < cur_func->ret_cell_num; i++) {
+ *prev_frame->sp++ = frame_sp[i];
+ }
+ goto return_func;
+ }
+
+ HANDLE_OP(WASM_OP_CALL)
+ {
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+ read_leb_uint32(frame_ip, frame_ip_end, fidx);
+#if WASM_ENABLE_MULTI_MODULE != 0
+ if (fidx >= module->e->function_count) {
+ wasm_set_exception(module, "unknown function");
+ goto got_exception;
+ }
+#endif
+
+ cur_func = module->e->functions + fidx;
+ goto call_func_from_interp;
+ }
+
+#if WASM_ENABLE_TAIL_CALL != 0
+ HANDLE_OP(WASM_OP_RETURN_CALL)
+ {
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+ read_leb_uint32(frame_ip, frame_ip_end, fidx);
+#if WASM_ENABLE_MULTI_MODULE != 0
+ if (fidx >= module->e->function_count) {
+ wasm_set_exception(module, "unknown function");
+ goto got_exception;
+ }
+#endif
+ cur_func = module->e->functions + fidx;
+
+ goto call_func_from_return_call;
+ }
+#endif /* WASM_ENABLE_TAIL_CALL */
+
+ HANDLE_OP(WASM_OP_CALL_INDIRECT)
+#if WASM_ENABLE_TAIL_CALL != 0
+ HANDLE_OP(WASM_OP_RETURN_CALL_INDIRECT)
+#endif
+ {
+ WASMType *cur_type, *cur_func_type;
+ WASMTableInstance *tbl_inst;
+ uint32 tbl_idx;
+#if WASM_ENABLE_TAIL_CALL != 0
+ opcode = *(frame_ip - 1);
+#endif
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+
+ /**
+ * 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);
+ bh_assert(tidx < module->module->type_count);
+ cur_type = wasm_types[tidx];
+
+ read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
+ bh_assert(tbl_idx < module->table_count);
+
+ tbl_inst = wasm_get_table_inst(module, tbl_idx);
+
+ val = POP_I32();
+ if ((uint32)val >= tbl_inst->cur_size) {
+ wasm_set_exception(module, "undefined element");
+ goto got_exception;
+ }
+
+ fidx = tbl_inst->elems[val];
+ if (fidx == NULL_REF) {
+ wasm_set_exception(module, "uninitialized element");
+ goto got_exception;
+ }
+
+ /*
+ * we might be using a table injected by host or
+ * another module. In that case, we don't validate
+ * the elem value while loading
+ */
+ if (fidx >= module->e->function_count) {
+ wasm_set_exception(module, "unknown function");
+ goto got_exception;
+ }
+
+ /* always call module own functions */
+ cur_func = module->e->functions + fidx;
+
+ if (cur_func->is_import_func)
+ cur_func_type = cur_func->u.func_import->func_type;
+ else
+ cur_func_type = cur_func->u.func->func_type;
+
+ if (cur_type != cur_func_type) {
+ wasm_set_exception(module, "indirect call type mismatch");
+ goto got_exception;
+ }
+
+#if WASM_ENABLE_TAIL_CALL != 0
+ if (opcode == WASM_OP_RETURN_CALL_INDIRECT)
+ goto call_func_from_return_call;
+#endif
+ goto call_func_from_interp;
+ }
+
+ /* parametric instructions */
+ HANDLE_OP(WASM_OP_DROP)
+ {
+ frame_sp--;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_DROP_64)
+ {
+ frame_sp -= 2;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_SELECT)
+ {
+ cond = (uint32)POP_I32();
+ frame_sp--;
+ if (!cond)
+ *(frame_sp - 1) = *frame_sp;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_SELECT_64)
+ {
+ cond = (uint32)POP_I32();
+ frame_sp -= 2;
+ if (!cond) {
+ *(frame_sp - 2) = *frame_sp;
+ *(frame_sp - 1) = *(frame_sp + 1);
+ }
+ HANDLE_OP_END();
+ }
+
+#if WASM_ENABLE_REF_TYPES != 0
+ HANDLE_OP(WASM_OP_SELECT_T)
+ {
+ uint32 vec_len;
+ uint8 type;
+
+ read_leb_uint32(frame_ip, frame_ip_end, vec_len);
+ type = *frame_ip++;
+
+ cond = (uint32)POP_I32();
+ if (type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64) {
+ frame_sp -= 2;
+ if (!cond) {
+ *(frame_sp - 2) = *frame_sp;
+ *(frame_sp - 1) = *(frame_sp + 1);
+ }
+ }
+ else {
+ frame_sp--;
+ if (!cond)
+ *(frame_sp - 1) = *frame_sp;
+ }
+
+ (void)vec_len;
+ HANDLE_OP_END();
+ }
+ HANDLE_OP(WASM_OP_TABLE_GET)
+ {
+ uint32 tbl_idx, elem_idx;
+ WASMTableInstance *tbl_inst;
+
+ read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
+ bh_assert(tbl_idx < module->table_count);
+
+ tbl_inst = wasm_get_table_inst(module, tbl_idx);
+
+ elem_idx = POP_I32();
+ if (elem_idx >= tbl_inst->cur_size) {
+ wasm_set_exception(module, "out of bounds table access");
+ goto got_exception;
+ }
+
+ PUSH_I32(tbl_inst->elems[elem_idx]);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_TABLE_SET)
+ {
+ uint32 tbl_idx, elem_idx, elem_val;
+ WASMTableInstance *tbl_inst;
+
+ read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
+ bh_assert(tbl_idx < module->table_count);
+
+ tbl_inst = wasm_get_table_inst(module, tbl_idx);
+
+ elem_val = POP_I32();
+ elem_idx = POP_I32();
+ if (elem_idx >= tbl_inst->cur_size) {
+ wasm_set_exception(module, "out of bounds table access");
+ goto got_exception;
+ }
+
+ tbl_inst->elems[elem_idx] = elem_val;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_REF_NULL)
+ {
+ uint32 ref_type;
+ read_leb_uint32(frame_ip, frame_ip_end, ref_type);
+ PUSH_I32(NULL_REF);
+ (void)ref_type;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_REF_IS_NULL)
+ {
+ uint32 ref_val;
+ ref_val = POP_I32();
+ PUSH_I32(ref_val == NULL_REF ? 1 : 0);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_REF_FUNC)
+ {
+ uint32 func_idx;
+ read_leb_uint32(frame_ip, frame_ip_end, func_idx);
+ PUSH_I32(func_idx);
+ HANDLE_OP_END();
+ }
+#endif /* WASM_ENABLE_REF_TYPES */
+
+ /* variable instructions */
+ HANDLE_OP(WASM_OP_GET_LOCAL)
+ {
+ GET_LOCAL_INDEX_TYPE_AND_OFFSET();
+
+ switch (local_type) {
+ case VALUE_TYPE_I32:
+ case VALUE_TYPE_F32:
+#if WASM_ENABLE_REF_TYPES != 0
+ case VALUE_TYPE_FUNCREF:
+ case VALUE_TYPE_EXTERNREF:
+#endif
+ PUSH_I32(*(int32 *)(frame_lp + local_offset));
+ break;
+ case VALUE_TYPE_I64:
+ case VALUE_TYPE_F64:
+ PUSH_I64(GET_I64_FROM_ADDR(frame_lp + local_offset));
+ break;
+ default:
+ wasm_set_exception(module, "invalid local type");
+ goto got_exception;
+ }
+
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(EXT_OP_GET_LOCAL_FAST)
+ {
+ local_offset = *frame_ip++;
+ if (local_offset & 0x80)
+ PUSH_I64(
+ GET_I64_FROM_ADDR(frame_lp + (local_offset & 0x7F)));
+ else
+ PUSH_I32(*(int32 *)(frame_lp + local_offset));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_SET_LOCAL)
+ {
+ GET_LOCAL_INDEX_TYPE_AND_OFFSET();
+
+ switch (local_type) {
+ case VALUE_TYPE_I32:
+ case VALUE_TYPE_F32:
+#if WASM_ENABLE_REF_TYPES != 0
+ case VALUE_TYPE_FUNCREF:
+ case VALUE_TYPE_EXTERNREF:
+#endif
+ *(int32 *)(frame_lp + local_offset) = POP_I32();
+ break;
+ case VALUE_TYPE_I64:
+ case VALUE_TYPE_F64:
+ PUT_I64_TO_ADDR((uint32 *)(frame_lp + local_offset),
+ POP_I64());
+ break;
+ default:
+ wasm_set_exception(module, "invalid local type");
+ goto got_exception;
+ }
+
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(EXT_OP_SET_LOCAL_FAST)
+ {
+ local_offset = *frame_ip++;
+ if (local_offset & 0x80)
+ PUT_I64_TO_ADDR(
+ (uint32 *)(frame_lp + (local_offset & 0x7F)),
+ POP_I64());
+ else
+ *(int32 *)(frame_lp + local_offset) = POP_I32();
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_TEE_LOCAL)
+ {
+ GET_LOCAL_INDEX_TYPE_AND_OFFSET();
+
+ switch (local_type) {
+ case VALUE_TYPE_I32:
+ case VALUE_TYPE_F32:
+#if WASM_ENABLE_REF_TYPES != 0
+ case VALUE_TYPE_FUNCREF:
+ case VALUE_TYPE_EXTERNREF:
+#endif
+ *(int32 *)(frame_lp + local_offset) =
+ *(int32 *)(frame_sp - 1);
+ break;
+ case VALUE_TYPE_I64:
+ case VALUE_TYPE_F64:
+ PUT_I64_TO_ADDR((uint32 *)(frame_lp + local_offset),
+ GET_I64_FROM_ADDR(frame_sp - 2));
+ break;
+ default:
+ wasm_set_exception(module, "invalid local type");
+ goto got_exception;
+ }
+
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(EXT_OP_TEE_LOCAL_FAST)
+ {
+ local_offset = *frame_ip++;
+ if (local_offset & 0x80)
+ PUT_I64_TO_ADDR(
+ (uint32 *)(frame_lp + (local_offset & 0x7F)),
+ GET_I64_FROM_ADDR(frame_sp - 2));
+ else
+ *(int32 *)(frame_lp + local_offset) =
+ *(int32 *)(frame_sp - 1);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_GET_GLOBAL)
+ {
+ read_leb_uint32(frame_ip, frame_ip_end, global_idx);
+ bh_assert(global_idx < module->e->global_count);
+ global = globals + global_idx;
+ global_addr = get_global_addr(global_data, global);
+ PUSH_I32(*(uint32 *)global_addr);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_GET_GLOBAL_64)
+ {
+ read_leb_uint32(frame_ip, frame_ip_end, global_idx);
+ bh_assert(global_idx < module->e->global_count);
+ global = globals + global_idx;
+ global_addr = get_global_addr(global_data, global);
+ PUSH_I64(GET_I64_FROM_ADDR((uint32 *)global_addr));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_SET_GLOBAL)
+ {
+ read_leb_uint32(frame_ip, frame_ip_end, global_idx);
+ bh_assert(global_idx < module->e->global_count);
+ global = globals + global_idx;
+ global_addr = get_global_addr(global_data, global);
+ *(int32 *)global_addr = POP_I32();
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_SET_GLOBAL_AUX_STACK)
+ {
+ uint32 aux_stack_top;
+
+ read_leb_uint32(frame_ip, frame_ip_end, global_idx);
+ bh_assert(global_idx < module->e->global_count);
+ global = globals + global_idx;
+ global_addr = get_global_addr(global_data, global);
+ aux_stack_top = *(uint32 *)(frame_sp - 1);
+ if (aux_stack_top <= exec_env->aux_stack_boundary.boundary) {
+ wasm_set_exception(module, "wasm auxiliary stack overflow");
+ goto got_exception;
+ }
+ if (aux_stack_top > exec_env->aux_stack_bottom.bottom) {
+ wasm_set_exception(module,
+ "wasm auxiliary stack underflow");
+ goto got_exception;
+ }
+ *(int32 *)global_addr = aux_stack_top;
+ frame_sp--;
+#if WASM_ENABLE_MEMORY_PROFILING != 0
+ if (module->module->aux_stack_top_global_index != (uint32)-1) {
+ uint32 aux_stack_used = module->module->aux_stack_bottom
+ - *(uint32 *)global_addr;
+ if (aux_stack_used > module->e->max_aux_stack_used)
+ module->e->max_aux_stack_used = aux_stack_used;
+ }
+#endif
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_SET_GLOBAL_64)
+ {
+ read_leb_uint32(frame_ip, frame_ip_end, global_idx);
+ bh_assert(global_idx < module->e->global_count);
+ global = globals + global_idx;
+ global_addr = get_global_addr(global_data, global);
+ PUT_I64_TO_ADDR((uint32 *)global_addr, POP_I64());
+ HANDLE_OP_END();
+ }
+
+ /* memory load instructions */
+ HANDLE_OP(WASM_OP_I32_LOAD)
+ HANDLE_OP(WASM_OP_F32_LOAD)
+ {
+ uint32 offset, flags, addr;
+
+ read_leb_uint32(frame_ip, frame_ip_end, flags);
+ read_leb_uint32(frame_ip, frame_ip_end, offset);
+ addr = POP_I32();
+ CHECK_MEMORY_OVERFLOW(4);
+ PUSH_I32(LOAD_I32(maddr));
+ CHECK_READ_WATCHPOINT(addr, offset);
+ (void)flags;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LOAD)
+ HANDLE_OP(WASM_OP_F64_LOAD)
+ {
+ uint32 offset, flags, addr;
+
+ read_leb_uint32(frame_ip, frame_ip_end, flags);
+ read_leb_uint32(frame_ip, frame_ip_end, offset);
+ addr = POP_I32();
+ CHECK_MEMORY_OVERFLOW(8);
+ PUSH_I64(LOAD_I64(maddr));
+ CHECK_READ_WATCHPOINT(addr, offset);
+ (void)flags;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_LOAD8_S)
+ {
+ uint32 offset, flags, addr;
+
+ read_leb_uint32(frame_ip, frame_ip_end, flags);
+ read_leb_uint32(frame_ip, frame_ip_end, offset);
+ addr = POP_I32();
+ CHECK_MEMORY_OVERFLOW(1);
+ PUSH_I32(sign_ext_8_32(*(int8 *)maddr));
+ CHECK_READ_WATCHPOINT(addr, offset);
+ (void)flags;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_LOAD8_U)
+ {
+ uint32 offset, flags, addr;
+
+ read_leb_uint32(frame_ip, frame_ip_end, flags);
+ read_leb_uint32(frame_ip, frame_ip_end, offset);
+ addr = POP_I32();
+ CHECK_MEMORY_OVERFLOW(1);
+ PUSH_I32((uint32)(*(uint8 *)maddr));
+ CHECK_READ_WATCHPOINT(addr, offset);
+ (void)flags;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_LOAD16_S)
+ {
+ uint32 offset, flags, addr;
+
+ read_leb_uint32(frame_ip, frame_ip_end, flags);
+ read_leb_uint32(frame_ip, frame_ip_end, offset);
+ addr = POP_I32();
+ CHECK_MEMORY_OVERFLOW(2);
+ PUSH_I32(sign_ext_16_32(LOAD_I16(maddr)));
+ CHECK_READ_WATCHPOINT(addr, offset);
+ (void)flags;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_LOAD16_U)
+ {
+ uint32 offset, flags, addr;
+
+ read_leb_uint32(frame_ip, frame_ip_end, flags);
+ read_leb_uint32(frame_ip, frame_ip_end, offset);
+ addr = POP_I32();
+ CHECK_MEMORY_OVERFLOW(2);
+ PUSH_I32((uint32)(LOAD_U16(maddr)));
+ CHECK_READ_WATCHPOINT(addr, offset);
+ (void)flags;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LOAD8_S)
+ {
+ uint32 offset, flags, addr;
+
+ read_leb_uint32(frame_ip, frame_ip_end, flags);
+ read_leb_uint32(frame_ip, frame_ip_end, offset);
+ addr = POP_I32();
+ CHECK_MEMORY_OVERFLOW(1);
+ PUSH_I64(sign_ext_8_64(*(int8 *)maddr));
+ CHECK_READ_WATCHPOINT(addr, offset);
+ (void)flags;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LOAD8_U)
+ {
+ uint32 offset, flags, addr;
+
+ read_leb_uint32(frame_ip, frame_ip_end, flags);
+ read_leb_uint32(frame_ip, frame_ip_end, offset);
+ addr = POP_I32();
+ CHECK_MEMORY_OVERFLOW(1);
+ PUSH_I64((uint64)(*(uint8 *)maddr));
+ CHECK_READ_WATCHPOINT(addr, offset);
+ (void)flags;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LOAD16_S)
+ {
+ uint32 offset, flags, addr;
+
+ read_leb_uint32(frame_ip, frame_ip_end, flags);
+ read_leb_uint32(frame_ip, frame_ip_end, offset);
+ addr = POP_I32();
+ CHECK_MEMORY_OVERFLOW(2);
+ PUSH_I64(sign_ext_16_64(LOAD_I16(maddr)));
+ CHECK_READ_WATCHPOINT(addr, offset);
+ (void)flags;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LOAD16_U)
+ {
+ uint32 offset, flags, addr;
+
+ read_leb_uint32(frame_ip, frame_ip_end, flags);
+ read_leb_uint32(frame_ip, frame_ip_end, offset);
+ addr = POP_I32();
+ CHECK_MEMORY_OVERFLOW(2);
+ PUSH_I64((uint64)(LOAD_U16(maddr)));
+ CHECK_READ_WATCHPOINT(addr, offset);
+ (void)flags;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LOAD32_S)
+ {
+ uint32 offset, flags, addr;
+
+ opcode = *(frame_ip - 1);
+ read_leb_uint32(frame_ip, frame_ip_end, flags);
+ read_leb_uint32(frame_ip, frame_ip_end, offset);
+ addr = POP_I32();
+ CHECK_MEMORY_OVERFLOW(4);
+ PUSH_I64(sign_ext_32_64(LOAD_I32(maddr)));
+ CHECK_READ_WATCHPOINT(addr, offset);
+ (void)flags;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LOAD32_U)
+ {
+ uint32 offset, flags, addr;
+
+ read_leb_uint32(frame_ip, frame_ip_end, flags);
+ read_leb_uint32(frame_ip, frame_ip_end, offset);
+ addr = POP_I32();
+ CHECK_MEMORY_OVERFLOW(4);
+ PUSH_I64((uint64)(LOAD_U32(maddr)));
+ CHECK_READ_WATCHPOINT(addr, offset);
+ (void)flags;
+ HANDLE_OP_END();
+ }
+
+ /* memory store instructions */
+ HANDLE_OP(WASM_OP_I32_STORE)
+ HANDLE_OP(WASM_OP_F32_STORE)
+ {
+ uint32 offset, flags, addr;
+
+ read_leb_uint32(frame_ip, frame_ip_end, flags);
+ read_leb_uint32(frame_ip, frame_ip_end, offset);
+ frame_sp--;
+ addr = POP_I32();
+ CHECK_MEMORY_OVERFLOW(4);
+ STORE_U32(maddr, frame_sp[1]);
+ CHECK_WRITE_WATCHPOINT(addr, offset);
+ (void)flags;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_STORE)
+ HANDLE_OP(WASM_OP_F64_STORE)
+ {
+ uint32 offset, flags, addr;
+
+ read_leb_uint32(frame_ip, frame_ip_end, flags);
+ read_leb_uint32(frame_ip, frame_ip_end, offset);
+ frame_sp -= 2;
+ addr = POP_I32();
+ CHECK_MEMORY_OVERFLOW(8);
+ PUT_I64_TO_ADDR((uint32 *)maddr,
+ GET_I64_FROM_ADDR(frame_sp + 1));
+ CHECK_WRITE_WATCHPOINT(addr, offset);
+ (void)flags;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_STORE8)
+ HANDLE_OP(WASM_OP_I32_STORE16)
+ {
+ uint32 offset, flags, addr;
+ uint32 sval;
+
+ opcode = *(frame_ip - 1);
+ read_leb_uint32(frame_ip, frame_ip_end, flags);
+ read_leb_uint32(frame_ip, frame_ip_end, offset);
+ sval = (uint32)POP_I32();
+ addr = POP_I32();
+
+ if (opcode == WASM_OP_I32_STORE8) {
+ CHECK_MEMORY_OVERFLOW(1);
+ *(uint8 *)maddr = (uint8)sval;
+ }
+ else {
+ CHECK_MEMORY_OVERFLOW(2);
+ STORE_U16(maddr, (uint16)sval);
+ }
+ CHECK_WRITE_WATCHPOINT(addr, offset);
+ (void)flags;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_STORE8)
+ HANDLE_OP(WASM_OP_I64_STORE16)
+ HANDLE_OP(WASM_OP_I64_STORE32)
+ {
+ uint32 offset, flags, addr;
+ uint64 sval;
+
+ opcode = *(frame_ip - 1);
+ read_leb_uint32(frame_ip, frame_ip_end, flags);
+ read_leb_uint32(frame_ip, frame_ip_end, offset);
+ sval = (uint64)POP_I64();
+ addr = POP_I32();
+
+ if (opcode == WASM_OP_I64_STORE8) {
+ CHECK_MEMORY_OVERFLOW(1);
+ *(uint8 *)maddr = (uint8)sval;
+ }
+ else if (opcode == WASM_OP_I64_STORE16) {
+ CHECK_MEMORY_OVERFLOW(2);
+ STORE_U16(maddr, (uint16)sval);
+ }
+ else {
+ CHECK_MEMORY_OVERFLOW(4);
+ STORE_U32(maddr, (uint32)sval);
+ }
+ CHECK_WRITE_WATCHPOINT(addr, offset);
+ (void)flags;
+ HANDLE_OP_END();
+ }
+
+ /* memory size and memory grow instructions */
+ HANDLE_OP(WASM_OP_MEMORY_SIZE)
+ {
+ uint32 reserved;
+ read_leb_uint32(frame_ip, frame_ip_end, reserved);
+ PUSH_I32(memory->cur_page_count);
+ (void)reserved;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_MEMORY_GROW)
+ {
+ uint32 reserved, delta,
+ prev_page_count = memory->cur_page_count;
+
+ read_leb_uint32(frame_ip, frame_ip_end, reserved);
+ delta = (uint32)POP_I32();
+
+ if (!wasm_enlarge_memory(module, delta)) {
+ /* failed to memory.grow, return -1 */
+ PUSH_I32(-1);
+ }
+ else {
+ /* success, return previous page count */
+ PUSH_I32(prev_page_count);
+ /* update memory size, no need to update memory ptr as
+ it isn't changed in wasm_enlarge_memory */
+#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
+ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
+ || WASM_ENABLE_BULK_MEMORY != 0
+ linear_mem_size = memory->memory_data_size;
+#endif
+ }
+
+ (void)reserved;
+ HANDLE_OP_END();
+ }
+
+ /* constant instructions */
+ HANDLE_OP(WASM_OP_I32_CONST)
+ DEF_OP_I_CONST(int32, I32);
+ HANDLE_OP_END();
+
+ HANDLE_OP(WASM_OP_I64_CONST)
+ DEF_OP_I_CONST(int64, I64);
+ HANDLE_OP_END();
+
+ HANDLE_OP(WASM_OP_F32_CONST)
+ {
+ uint8 *p_float = (uint8 *)frame_sp++;
+ for (i = 0; i < sizeof(float32); i++)
+ *p_float++ = *frame_ip++;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_CONST)
+ {
+ uint8 *p_float = (uint8 *)frame_sp++;
+ frame_sp++;
+ for (i = 0; i < sizeof(float64); i++)
+ *p_float++ = *frame_ip++;
+ HANDLE_OP_END();
+ }
+
+ /* comparison instructions of i32 */
+ HANDLE_OP(WASM_OP_I32_EQZ)
+ {
+ DEF_OP_EQZ(I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_EQ)
+ {
+ DEF_OP_CMP(uint32, I32, ==);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_NE)
+ {
+ DEF_OP_CMP(uint32, I32, !=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_LT_S)
+ {
+ DEF_OP_CMP(int32, I32, <);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_LT_U)
+ {
+ DEF_OP_CMP(uint32, I32, <);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_GT_S)
+ {
+ DEF_OP_CMP(int32, I32, >);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_GT_U)
+ {
+ DEF_OP_CMP(uint32, I32, >);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_LE_S)
+ {
+ DEF_OP_CMP(int32, I32, <=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_LE_U)
+ {
+ DEF_OP_CMP(uint32, I32, <=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_GE_S)
+ {
+ DEF_OP_CMP(int32, I32, >=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_GE_U)
+ {
+ DEF_OP_CMP(uint32, I32, >=);
+ HANDLE_OP_END();
+ }
+
+ /* comparison instructions of i64 */
+ HANDLE_OP(WASM_OP_I64_EQZ)
+ {
+ DEF_OP_EQZ(I64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_EQ)
+ {
+ DEF_OP_CMP(uint64, I64, ==);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_NE)
+ {
+ DEF_OP_CMP(uint64, I64, !=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LT_S)
+ {
+ DEF_OP_CMP(int64, I64, <);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LT_U)
+ {
+ DEF_OP_CMP(uint64, I64, <);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_GT_S)
+ {
+ DEF_OP_CMP(int64, I64, >);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_GT_U)
+ {
+ DEF_OP_CMP(uint64, I64, >);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LE_S)
+ {
+ DEF_OP_CMP(int64, I64, <=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LE_U)
+ {
+ DEF_OP_CMP(uint64, I64, <=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_GE_S)
+ {
+ DEF_OP_CMP(int64, I64, >=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_GE_U)
+ {
+ DEF_OP_CMP(uint64, I64, >=);
+ HANDLE_OP_END();
+ }
+
+ /* comparison instructions of f32 */
+ HANDLE_OP(WASM_OP_F32_EQ)
+ {
+ DEF_OP_CMP(float32, F32, ==);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_NE)
+ {
+ DEF_OP_CMP(float32, F32, !=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_LT)
+ {
+ DEF_OP_CMP(float32, F32, <);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_GT)
+ {
+ DEF_OP_CMP(float32, F32, >);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_LE)
+ {
+ DEF_OP_CMP(float32, F32, <=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_GE)
+ {
+ DEF_OP_CMP(float32, F32, >=);
+ HANDLE_OP_END();
+ }
+
+ /* comparison instructions of f64 */
+ HANDLE_OP(WASM_OP_F64_EQ)
+ {
+ DEF_OP_CMP(float64, F64, ==);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_NE)
+ {
+ DEF_OP_CMP(float64, F64, !=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_LT)
+ {
+ DEF_OP_CMP(float64, F64, <);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_GT)
+ {
+ DEF_OP_CMP(float64, F64, >);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_LE)
+ {
+ DEF_OP_CMP(float64, F64, <=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_GE)
+ {
+ DEF_OP_CMP(float64, F64, >=);
+ HANDLE_OP_END();
+ }
+
+ /* numberic instructions of i32 */
+ HANDLE_OP(WASM_OP_I32_CLZ)
+ {
+ DEF_OP_BIT_COUNT(uint32, I32, clz32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_CTZ)
+ {
+ DEF_OP_BIT_COUNT(uint32, I32, ctz32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_POPCNT)
+ {
+ DEF_OP_BIT_COUNT(uint32, I32, popcount32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_ADD)
+ {
+ DEF_OP_NUMERIC(uint32, uint32, I32, +);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_SUB)
+ {
+ DEF_OP_NUMERIC(uint32, uint32, I32, -);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_MUL)
+ {
+ DEF_OP_NUMERIC(uint32, uint32, I32, *);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_DIV_S)
+ {
+ int32 a, b;
+
+ b = POP_I32();
+ a = POP_I32();
+ if (a == (int32)0x80000000 && b == -1) {
+ wasm_set_exception(module, "integer overflow");
+ goto got_exception;
+ }
+ if (b == 0) {
+ wasm_set_exception(module, "integer divide by zero");
+ goto got_exception;
+ }
+ PUSH_I32(a / b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_DIV_U)
+ {
+ uint32 a, b;
+
+ b = (uint32)POP_I32();
+ a = (uint32)POP_I32();
+ if (b == 0) {
+ wasm_set_exception(module, "integer divide by zero");
+ goto got_exception;
+ }
+ PUSH_I32(a / b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_REM_S)
+ {
+ int32 a, b;
+
+ b = POP_I32();
+ a = POP_I32();
+ if (a == (int32)0x80000000 && b == -1) {
+ PUSH_I32(0);
+ HANDLE_OP_END();
+ }
+ if (b == 0) {
+ wasm_set_exception(module, "integer divide by zero");
+ goto got_exception;
+ }
+ PUSH_I32(a % b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_REM_U)
+ {
+ uint32 a, b;
+
+ b = (uint32)POP_I32();
+ a = (uint32)POP_I32();
+ if (b == 0) {
+ wasm_set_exception(module, "integer divide by zero");
+ goto got_exception;
+ }
+ PUSH_I32(a % b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_AND)
+ {
+ DEF_OP_NUMERIC(uint32, uint32, I32, &);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_OR)
+ {
+ DEF_OP_NUMERIC(uint32, uint32, I32, |);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_XOR)
+ {
+ DEF_OP_NUMERIC(uint32, uint32, I32, ^);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_SHL)
+ {
+ DEF_OP_NUMERIC2(uint32, uint32, I32, <<);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_SHR_S)
+ {
+ DEF_OP_NUMERIC2(int32, uint32, I32, >>);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_SHR_U)
+ {
+ DEF_OP_NUMERIC2(uint32, uint32, I32, >>);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_ROTL)
+ {
+ uint32 a, b;
+
+ b = (uint32)POP_I32();
+ a = (uint32)POP_I32();
+ PUSH_I32(rotl32(a, b));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_ROTR)
+ {
+ uint32 a, b;
+
+ b = (uint32)POP_I32();
+ a = (uint32)POP_I32();
+ PUSH_I32(rotr32(a, b));
+ HANDLE_OP_END();
+ }
+
+ /* numberic instructions of i64 */
+ HANDLE_OP(WASM_OP_I64_CLZ)
+ {
+ DEF_OP_BIT_COUNT(uint64, I64, clz64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_CTZ)
+ {
+ DEF_OP_BIT_COUNT(uint64, I64, ctz64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_POPCNT)
+ {
+ DEF_OP_BIT_COUNT(uint64, I64, popcount64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_ADD)
+ {
+ DEF_OP_NUMERIC_64(uint64, uint64, I64, +);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_SUB)
+ {
+ DEF_OP_NUMERIC_64(uint64, uint64, I64, -);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_MUL)
+ {
+ DEF_OP_NUMERIC_64(uint64, uint64, I64, *);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_DIV_S)
+ {
+ int64 a, b;
+
+ b = POP_I64();
+ a = POP_I64();
+ if (a == (int64)0x8000000000000000LL && b == -1) {
+ wasm_set_exception(module, "integer overflow");
+ goto got_exception;
+ }
+ if (b == 0) {
+ wasm_set_exception(module, "integer divide by zero");
+ goto got_exception;
+ }
+ PUSH_I64(a / b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_DIV_U)
+ {
+ uint64 a, b;
+
+ b = (uint64)POP_I64();
+ a = (uint64)POP_I64();
+ if (b == 0) {
+ wasm_set_exception(module, "integer divide by zero");
+ goto got_exception;
+ }
+ PUSH_I64(a / b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_REM_S)
+ {
+ int64 a, b;
+
+ b = POP_I64();
+ a = POP_I64();
+ if (a == (int64)0x8000000000000000LL && b == -1) {
+ PUSH_I64(0);
+ HANDLE_OP_END();
+ }
+ if (b == 0) {
+ wasm_set_exception(module, "integer divide by zero");
+ goto got_exception;
+ }
+ PUSH_I64(a % b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_REM_U)
+ {
+ uint64 a, b;
+
+ b = (uint64)POP_I64();
+ a = (uint64)POP_I64();
+ if (b == 0) {
+ wasm_set_exception(module, "integer divide by zero");
+ goto got_exception;
+ }
+ PUSH_I64(a % b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_AND)
+ {
+ DEF_OP_NUMERIC_64(uint64, uint64, I64, &);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_OR)
+ {
+ DEF_OP_NUMERIC_64(uint64, uint64, I64, |);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_XOR)
+ {
+ DEF_OP_NUMERIC_64(uint64, uint64, I64, ^);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_SHL)
+ {
+ DEF_OP_NUMERIC2_64(uint64, uint64, I64, <<);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_SHR_S)
+ {
+ DEF_OP_NUMERIC2_64(int64, uint64, I64, >>);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_SHR_U)
+ {
+ DEF_OP_NUMERIC2_64(uint64, uint64, I64, >>);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_ROTL)
+ {
+ uint64 a, b;
+
+ b = (uint64)POP_I64();
+ a = (uint64)POP_I64();
+ PUSH_I64(rotl64(a, b));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_ROTR)
+ {
+ uint64 a, b;
+
+ b = (uint64)POP_I64();
+ a = (uint64)POP_I64();
+ PUSH_I64(rotr64(a, b));
+ HANDLE_OP_END();
+ }
+
+ /* numberic instructions of f32 */
+ HANDLE_OP(WASM_OP_F32_ABS)
+ {
+ DEF_OP_MATH(float32, F32, fabsf);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_NEG)
+ {
+ uint32 u32 = frame_sp[-1];
+ uint32 sign_bit = u32 & ((uint32)1 << 31);
+ if (sign_bit)
+ frame_sp[-1] = u32 & ~((uint32)1 << 31);
+ else
+ frame_sp[-1] = u32 | ((uint32)1 << 31);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_CEIL)
+ {
+ DEF_OP_MATH(float32, F32, ceilf);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_FLOOR)
+ {
+ DEF_OP_MATH(float32, F32, floorf);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_TRUNC)
+ {
+ DEF_OP_MATH(float32, F32, truncf);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_NEAREST)
+ {
+ DEF_OP_MATH(float32, F32, rintf);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_SQRT)
+ {
+ DEF_OP_MATH(float32, F32, sqrtf);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_ADD)
+ {
+ DEF_OP_NUMERIC(float32, float32, F32, +);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_SUB)
+ {
+ DEF_OP_NUMERIC(float32, float32, F32, -);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_MUL)
+ {
+ DEF_OP_NUMERIC(float32, float32, F32, *);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_DIV)
+ {
+ DEF_OP_NUMERIC(float32, float32, F32, /);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_MIN)
+ {
+ float32 a, b;
+
+ b = POP_F32();
+ a = POP_F32();
+
+ PUSH_F32(f32_min(a, b));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_MAX)
+ {
+ float32 a, b;
+
+ b = POP_F32();
+ a = POP_F32();
+
+ PUSH_F32(f32_max(a, b));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_COPYSIGN)
+ {
+ float32 a, b;
+
+ b = POP_F32();
+ a = POP_F32();
+ PUSH_F32(local_copysignf(a, b));
+ HANDLE_OP_END();
+ }
+
+ /* numberic instructions of f64 */
+ HANDLE_OP(WASM_OP_F64_ABS)
+ {
+ DEF_OP_MATH(float64, F64, fabs);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_NEG)
+ {
+ uint64 u64 = GET_I64_FROM_ADDR(frame_sp - 2);
+ uint64 sign_bit = u64 & (((uint64)1) << 63);
+ if (sign_bit)
+ PUT_I64_TO_ADDR(frame_sp - 2, (u64 & ~(((uint64)1) << 63)));
+ else
+ PUT_I64_TO_ADDR(frame_sp - 2, (u64 | (((uint64)1) << 63)));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_CEIL)
+ {
+ DEF_OP_MATH(float64, F64, ceil);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_FLOOR)
+ {
+ DEF_OP_MATH(float64, F64, floor);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_TRUNC)
+ {
+ DEF_OP_MATH(float64, F64, trunc);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_NEAREST)
+ {
+ DEF_OP_MATH(float64, F64, rint);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_SQRT)
+ {
+ DEF_OP_MATH(float64, F64, sqrt);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_ADD)
+ {
+ DEF_OP_NUMERIC_64(float64, float64, F64, +);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_SUB)
+ {
+ DEF_OP_NUMERIC_64(float64, float64, F64, -);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_MUL)
+ {
+ DEF_OP_NUMERIC_64(float64, float64, F64, *);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_DIV)
+ {
+ DEF_OP_NUMERIC_64(float64, float64, F64, /);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_MIN)
+ {
+ float64 a, b;
+
+ b = POP_F64();
+ a = POP_F64();
+
+ PUSH_F64(f64_min(a, b));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_MAX)
+ {
+ float64 a, b;
+
+ b = POP_F64();
+ a = POP_F64();
+
+ PUSH_F64(f64_max(a, b));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_COPYSIGN)
+ {
+ float64 a, b;
+
+ b = POP_F64();
+ a = POP_F64();
+ PUSH_F64(local_copysign(a, b));
+ HANDLE_OP_END();
+ }
+
+ /* conversions of i32 */
+ HANDLE_OP(WASM_OP_I32_WRAP_I64)
+ {
+ int32 value = (int32)(POP_I64() & 0xFFFFFFFFLL);
+ PUSH_I32(value);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_TRUNC_S_F32)
+ {
+ /* We don't use INT32_MIN/INT32_MAX/UINT32_MIN/UINT32_MAX,
+ since float/double values of ieee754 cannot precisely
+ represent all int32/uint32/int64/uint64 values, e.g.
+ UINT32_MAX is 4294967295, but (float32)4294967295 is
+ 4294967296.0f, but not 4294967295.0f. */
+ DEF_OP_TRUNC_F32(-2147483904.0f, 2147483648.0f, true, true);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_TRUNC_U_F32)
+ {
+ DEF_OP_TRUNC_F32(-1.0f, 4294967296.0f, true, false);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_TRUNC_S_F64)
+ {
+ DEF_OP_TRUNC_F64(-2147483649.0, 2147483648.0, true, true);
+ /* frame_sp can't be moved in trunc function, we need to
+ manually adjust it if src and dst op's cell num is
+ different */
+ frame_sp--;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_TRUNC_U_F64)
+ {
+ DEF_OP_TRUNC_F64(-1.0, 4294967296.0, true, false);
+ frame_sp--;
+ HANDLE_OP_END();
+ }
+
+ /* conversions of i64 */
+ HANDLE_OP(WASM_OP_I64_EXTEND_S_I32)
+ {
+ DEF_OP_CONVERT(int64, I64, int32, I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_EXTEND_U_I32)
+ {
+ DEF_OP_CONVERT(int64, I64, uint32, I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_TRUNC_S_F32)
+ {
+ DEF_OP_TRUNC_F32(-9223373136366403584.0f,
+ 9223372036854775808.0f, false, true);
+ frame_sp++;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_TRUNC_U_F32)
+ {
+ DEF_OP_TRUNC_F32(-1.0f, 18446744073709551616.0f, false, false);
+ frame_sp++;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_TRUNC_S_F64)
+ {
+ DEF_OP_TRUNC_F64(-9223372036854777856.0, 9223372036854775808.0,
+ false, true);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_TRUNC_U_F64)
+ {
+ DEF_OP_TRUNC_F64(-1.0, 18446744073709551616.0, false, false);
+ HANDLE_OP_END();
+ }
+
+ /* conversions of f32 */
+ HANDLE_OP(WASM_OP_F32_CONVERT_S_I32)
+ {
+ DEF_OP_CONVERT(float32, F32, int32, I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_CONVERT_U_I32)
+ {
+ DEF_OP_CONVERT(float32, F32, uint32, I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_CONVERT_S_I64)
+ {
+ DEF_OP_CONVERT(float32, F32, int64, I64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_CONVERT_U_I64)
+ {
+ DEF_OP_CONVERT(float32, F32, uint64, I64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_DEMOTE_F64)
+ {
+ DEF_OP_CONVERT(float32, F32, float64, F64);
+ HANDLE_OP_END();
+ }
+
+ /* conversions of f64 */
+ HANDLE_OP(WASM_OP_F64_CONVERT_S_I32)
+ {
+ DEF_OP_CONVERT(float64, F64, int32, I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_CONVERT_U_I32)
+ {
+ DEF_OP_CONVERT(float64, F64, uint32, I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_CONVERT_S_I64)
+ {
+ DEF_OP_CONVERT(float64, F64, int64, I64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_CONVERT_U_I64)
+ {
+ DEF_OP_CONVERT(float64, F64, uint64, I64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_PROMOTE_F32)
+ {
+ DEF_OP_CONVERT(float64, F64, float32, F32);
+ HANDLE_OP_END();
+ }
+
+ /* reinterpretations */
+ HANDLE_OP(WASM_OP_I32_REINTERPRET_F32)
+ HANDLE_OP(WASM_OP_I64_REINTERPRET_F64)
+ HANDLE_OP(WASM_OP_F32_REINTERPRET_I32)
+ HANDLE_OP(WASM_OP_F64_REINTERPRET_I64) { HANDLE_OP_END(); }
+
+ HANDLE_OP(WASM_OP_I32_EXTEND8_S)
+ {
+ DEF_OP_CONVERT(int32, I32, int8, I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_EXTEND16_S)
+ {
+ DEF_OP_CONVERT(int32, I32, int16, I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_EXTEND8_S)
+ {
+ DEF_OP_CONVERT(int64, I64, int8, I64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_EXTEND16_S)
+ {
+ DEF_OP_CONVERT(int64, I64, int16, I64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_EXTEND32_S)
+ {
+ DEF_OP_CONVERT(int64, I64, int32, I64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_MISC_PREFIX)
+ {
+ uint32 opcode1;
+
+ read_leb_uint32(frame_ip, frame_ip_end, opcode1);
+ opcode = (uint8)opcode1;
+
+ switch (opcode) {
+ case WASM_OP_I32_TRUNC_SAT_S_F32:
+ DEF_OP_TRUNC_SAT_F32(-2147483904.0f, 2147483648.0f,
+ true, true);
+ break;
+ case WASM_OP_I32_TRUNC_SAT_U_F32:
+ DEF_OP_TRUNC_SAT_F32(-1.0f, 4294967296.0f, true, false);
+ break;
+ case WASM_OP_I32_TRUNC_SAT_S_F64:
+ DEF_OP_TRUNC_SAT_F64(-2147483649.0, 2147483648.0, true,
+ true);
+ frame_sp--;
+ break;
+ case WASM_OP_I32_TRUNC_SAT_U_F64:
+ DEF_OP_TRUNC_SAT_F64(-1.0, 4294967296.0, true, false);
+ frame_sp--;
+ break;
+ case WASM_OP_I64_TRUNC_SAT_S_F32:
+ DEF_OP_TRUNC_SAT_F32(-9223373136366403584.0f,
+ 9223372036854775808.0f, false,
+ true);
+ frame_sp++;
+ break;
+ case WASM_OP_I64_TRUNC_SAT_U_F32:
+ DEF_OP_TRUNC_SAT_F32(-1.0f, 18446744073709551616.0f,
+ false, false);
+ frame_sp++;
+ break;
+ case WASM_OP_I64_TRUNC_SAT_S_F64:
+ DEF_OP_TRUNC_SAT_F64(-9223372036854777856.0,
+ 9223372036854775808.0, false,
+ true);
+ break;
+ case WASM_OP_I64_TRUNC_SAT_U_F64:
+ 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();
+
+#if WASM_ENABLE_THREAD_MGR != 0
+ linear_mem_size = memory->memory_data_size;
+#endif
+
+#ifndef OS_ENABLE_HW_BOUND_CHECK
+ CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr);
+#else
+ if ((uint64)(uint32)addr + bytes
+ > (uint64)linear_mem_size)
+ goto out_of_bounds;
+ maddr = memory->memory_data + (uint32)addr;
+#endif
+
+ 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, (uint32)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();
+
+#if WASM_ENABLE_THREAD_MGR != 0
+ linear_mem_size = memory->memory_data_size;
+#endif
+
+#ifndef OS_ENABLE_HW_BOUND_CHECK
+ CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc);
+ CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
+#else
+ if ((uint64)(uint32)src + len > (uint64)linear_mem_size)
+ goto out_of_bounds;
+ msrc = memory->memory_data + (uint32)src;
+
+ if ((uint64)(uint32)dst + len > (uint64)linear_mem_size)
+ goto out_of_bounds;
+ mdst = memory->memory_data + (uint32)dst;
+#endif
+
+ /* 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 fill_val, *mdst;
+ frame_ip++;
+
+ len = POP_I32();
+ fill_val = POP_I32();
+ dst = POP_I32();
+
+#if WASM_ENABLE_THREAD_MGR != 0
+ linear_mem_size = memory->memory_data_size;
+#endif
+
+#ifndef OS_ENABLE_HW_BOUND_CHECK
+ CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
+#else
+ if ((uint64)(uint32)dst + len > (uint64)linear_mem_size)
+ goto out_of_bounds;
+ mdst = memory->memory_data + (uint32)dst;
+#endif
+
+ memset(mdst, fill_val, len);
+ break;
+ }
+#endif /* WASM_ENABLE_BULK_MEMORY */
+#if WASM_ENABLE_REF_TYPES != 0
+ case WASM_OP_TABLE_INIT:
+ {
+ uint32 tbl_idx, elem_idx;
+ uint64 n, s, d;
+ WASMTableInstance *tbl_inst;
+
+ read_leb_uint32(frame_ip, frame_ip_end, elem_idx);
+ bh_assert(elem_idx < module->module->table_seg_count);
+
+ read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
+ bh_assert(tbl_idx < module->module->table_count);
+
+ tbl_inst = wasm_get_table_inst(module, tbl_idx);
+
+ n = (uint32)POP_I32();
+ s = (uint32)POP_I32();
+ d = (uint32)POP_I32();
+
+ /* TODO: what if the element is not passive? */
+
+ if (!n) {
+ break;
+ }
+
+ if (n + s > module->module->table_segments[elem_idx]
+ .function_count
+ || d + n > tbl_inst->cur_size) {
+ wasm_set_exception(module,
+ "out of bounds table access");
+ goto got_exception;
+ }
+
+ if (module->module->table_segments[elem_idx]
+ .is_dropped) {
+ wasm_set_exception(module,
+ "out of bounds table access");
+ goto got_exception;
+ }
+
+ if (!wasm_elem_is_passive(
+ module->module->table_segments[elem_idx]
+ .mode)) {
+ wasm_set_exception(module,
+ "out of bounds table access");
+ goto got_exception;
+ }
+
+ bh_memcpy_s(
+ (uint8 *)tbl_inst
+ + offsetof(WASMTableInstance, elems)
+ + d * sizeof(uint32),
+ (uint32)((tbl_inst->cur_size - d) * sizeof(uint32)),
+ module->module->table_segments[elem_idx]
+ .func_indexes
+ + s,
+ (uint32)(n * sizeof(uint32)));
+
+ break;
+ }
+ case WASM_OP_ELEM_DROP:
+ {
+ uint32 elem_idx;
+ read_leb_uint32(frame_ip, frame_ip_end, elem_idx);
+ bh_assert(elem_idx < module->module->table_seg_count);
+
+ module->module->table_segments[elem_idx].is_dropped =
+ true;
+ break;
+ }
+ case WASM_OP_TABLE_COPY:
+ {
+ uint32 src_tbl_idx, dst_tbl_idx;
+ uint64 n, s, d;
+ WASMTableInstance *src_tbl_inst, *dst_tbl_inst;
+
+ read_leb_uint32(frame_ip, frame_ip_end, dst_tbl_idx);
+ bh_assert(dst_tbl_idx < module->table_count);
+
+ dst_tbl_inst = wasm_get_table_inst(module, dst_tbl_idx);
+
+ read_leb_uint32(frame_ip, frame_ip_end, src_tbl_idx);
+ bh_assert(src_tbl_idx < module->table_count);
+
+ src_tbl_inst = wasm_get_table_inst(module, src_tbl_idx);
+
+ n = (uint32)POP_I32();
+ s = (uint32)POP_I32();
+ d = (uint32)POP_I32();
+
+ if (d + n > dst_tbl_inst->cur_size
+ || s + n > src_tbl_inst->cur_size) {
+ wasm_set_exception(module,
+ "out of bounds table access");
+ goto got_exception;
+ }
+
+ /* if s >= d, copy from front to back */
+ /* if s < d, copy from back to front */
+ /* merge all together */
+ bh_memmove_s((uint8 *)dst_tbl_inst
+ + offsetof(WASMTableInstance, elems)
+ + d * sizeof(uint32),
+ (uint32)((dst_tbl_inst->cur_size - d)
+ * sizeof(uint32)),
+ (uint8 *)src_tbl_inst
+ + offsetof(WASMTableInstance, elems)
+ + s * sizeof(uint32),
+ (uint32)(n * sizeof(uint32)));
+ break;
+ }
+ case WASM_OP_TABLE_GROW:
+ {
+ uint32 tbl_idx, n, init_val, orig_tbl_sz;
+ WASMTableInstance *tbl_inst;
+
+ read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
+ bh_assert(tbl_idx < module->table_count);
+
+ tbl_inst = wasm_get_table_inst(module, tbl_idx);
+
+ orig_tbl_sz = tbl_inst->cur_size;
+
+ n = POP_I32();
+ init_val = POP_I32();
+
+ if (!wasm_enlarge_table(module, tbl_idx, n, init_val)) {
+ PUSH_I32(-1);
+ }
+ else {
+ PUSH_I32(orig_tbl_sz);
+ }
+ break;
+ }
+ case WASM_OP_TABLE_SIZE:
+ {
+ uint32 tbl_idx;
+ WASMTableInstance *tbl_inst;
+
+ read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
+ bh_assert(tbl_idx < module->table_count);
+
+ tbl_inst = wasm_get_table_inst(module, tbl_idx);
+
+ PUSH_I32(tbl_inst->cur_size);
+ break;
+ }
+ case WASM_OP_TABLE_FILL:
+ {
+ uint32 tbl_idx, n, fill_val;
+ WASMTableInstance *tbl_inst;
+
+ read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
+ bh_assert(tbl_idx < module->table_count);
+
+ tbl_inst = wasm_get_table_inst(module, tbl_idx);
+
+ n = POP_I32();
+ fill_val = POP_I32();
+ i = POP_I32();
+
+ /* TODO: what if the element is not passive? */
+ /* TODO: what if the element is dropped? */
+
+ if (i + n > tbl_inst->cur_size) {
+ /* TODO: verify warning content */
+ wasm_set_exception(module,
+ "out of bounds table access");
+ goto got_exception;
+ }
+
+ for (; n != 0; i++, n--) {
+ tbl_inst->elems[i] = fill_val;
+ }
+
+ break;
+ }
+#endif /* WASM_ENABLE_REF_TYPES */
+ default:
+ wasm_set_exception(module, "unsupported opcode");
+ goto got_exception;
+ }
+ HANDLE_OP_END();
+ }
+
+#if WASM_ENABLE_SHARED_MEMORY != 0
+ HANDLE_OP(WASM_OP_ATOMIC_PREFIX)
+ {
+ uint32 offset = 0, align, addr;
+
+ opcode = *frame_ip++;
+
+ if (opcode != WASM_OP_ATOMIC_FENCE) {
+ read_leb_uint32(frame_ip, frame_ip_end, align);
+ read_leb_uint32(frame_ip, frame_ip_end, offset);
+ }
+
+ switch (opcode) {
+ case WASM_OP_ATOMIC_NOTIFY:
+ {
+ uint32 notify_count, ret;
+
+ notify_count = POP_I32();
+ addr = POP_I32();
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+
+ ret = wasm_runtime_atomic_notify(
+ (WASMModuleInstanceCommon *)module, maddr,
+ notify_count);
+ if (ret == (uint32)-1)
+ goto got_exception;
+
+ PUSH_I32(ret);
+ break;
+ }
+ case WASM_OP_ATOMIC_WAIT32:
+ {
+ uint64 timeout;
+ uint32 expect, ret;
+
+ timeout = POP_I64();
+ expect = POP_I32();
+ addr = POP_I32();
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+
+ ret = wasm_runtime_atomic_wait(
+ (WASMModuleInstanceCommon *)module, maddr,
+ (uint64)expect, timeout, false);
+ if (ret == (uint32)-1)
+ goto got_exception;
+
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+
+ PUSH_I32(ret);
+ break;
+ }
+ case WASM_OP_ATOMIC_WAIT64:
+ {
+ uint64 timeout, expect;
+ uint32 ret;
+
+ timeout = POP_I64();
+ expect = POP_I64();
+ addr = POP_I32();
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+
+ ret = wasm_runtime_atomic_wait(
+ (WASMModuleInstanceCommon *)module, maddr, expect,
+ timeout, true);
+ if (ret == (uint32)-1)
+ goto got_exception;
+
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+
+ PUSH_I32(ret);
+ break;
+ }
+ case WASM_OP_ATOMIC_FENCE:
+ {
+ /* Skip the memory index */
+ frame_ip++;
+ os_atomic_thread_fence(os_memory_order_seq_cst);
+ break;
+ }
+
+ case WASM_OP_ATOMIC_I32_LOAD:
+ case WASM_OP_ATOMIC_I32_LOAD8_U:
+ case WASM_OP_ATOMIC_I32_LOAD16_U:
+ {
+ uint32 readv;
+
+ addr = POP_I32();
+
+ if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint32)(*(uint8 *)maddr);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else if (opcode == WASM_OP_ATOMIC_I32_LOAD16_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint32)LOAD_U16(maddr);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = LOAD_I32(maddr);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+
+ PUSH_I32(readv);
+ break;
+ }
+
+ case WASM_OP_ATOMIC_I64_LOAD:
+ case WASM_OP_ATOMIC_I64_LOAD8_U:
+ case WASM_OP_ATOMIC_I64_LOAD16_U:
+ case WASM_OP_ATOMIC_I64_LOAD32_U:
+ {
+ uint64 readv;
+
+ addr = POP_I32();
+
+ if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint64)(*(uint8 *)maddr);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else if (opcode == WASM_OP_ATOMIC_I64_LOAD16_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint64)LOAD_U16(maddr);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else if (opcode == WASM_OP_ATOMIC_I64_LOAD32_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint64)LOAD_U32(maddr);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = LOAD_I64(maddr);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+
+ PUSH_I64(readv);
+ break;
+ }
+
+ case WASM_OP_ATOMIC_I32_STORE:
+ case WASM_OP_ATOMIC_I32_STORE8:
+ case WASM_OP_ATOMIC_I32_STORE16:
+ {
+ uint32 sval;
+
+ sval = (uint32)POP_I32();
+ addr = POP_I32();
+
+ if (opcode == WASM_OP_ATOMIC_I32_STORE8) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+ os_mutex_lock(&node->shared_mem_lock);
+ *(uint8 *)maddr = (uint8)sval;
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else if (opcode == WASM_OP_ATOMIC_I32_STORE16) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+ os_mutex_lock(&node->shared_mem_lock);
+ STORE_U16(maddr, (uint16)sval);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+ os_mutex_lock(&node->shared_mem_lock);
+ STORE_U32(maddr, sval);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ break;
+ }
+
+ case WASM_OP_ATOMIC_I64_STORE:
+ case WASM_OP_ATOMIC_I64_STORE8:
+ case WASM_OP_ATOMIC_I64_STORE16:
+ case WASM_OP_ATOMIC_I64_STORE32:
+ {
+ uint64 sval;
+
+ sval = (uint64)POP_I64();
+ addr = POP_I32();
+
+ if (opcode == WASM_OP_ATOMIC_I64_STORE8) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+ os_mutex_lock(&node->shared_mem_lock);
+ *(uint8 *)maddr = (uint8)sval;
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else if (opcode == WASM_OP_ATOMIC_I64_STORE16) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+ os_mutex_lock(&node->shared_mem_lock);
+ STORE_U16(maddr, (uint16)sval);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else if (opcode == WASM_OP_ATOMIC_I64_STORE32) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+ os_mutex_lock(&node->shared_mem_lock);
+ STORE_U32(maddr, (uint32)sval);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+ os_mutex_lock(&node->shared_mem_lock);
+ PUT_I64_TO_ADDR((uint32 *)maddr, sval);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ break;
+ }
+
+ case WASM_OP_ATOMIC_RMW_I32_CMPXCHG:
+ case WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U:
+ case WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U:
+ {
+ uint32 readv, sval, expect;
+
+ sval = POP_I32();
+ expect = POP_I32();
+ addr = POP_I32();
+
+ if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+
+ expect = (uint8)expect;
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint32)(*(uint8 *)maddr);
+ if (readv == expect)
+ *(uint8 *)maddr = (uint8)(sval);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+
+ expect = (uint16)expect;
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint32)LOAD_U16(maddr);
+ if (readv == expect)
+ STORE_U16(maddr, (uint16)(sval));
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = LOAD_I32(maddr);
+ if (readv == expect)
+ STORE_U32(maddr, sval);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ PUSH_I32(readv);
+ break;
+ }
+ case WASM_OP_ATOMIC_RMW_I64_CMPXCHG:
+ case WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U:
+ case WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U:
+ case WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U:
+ {
+ uint64 readv, sval, expect;
+
+ sval = (uint64)POP_I64();
+ expect = (uint64)POP_I64();
+ addr = POP_I32();
+
+ if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+
+ expect = (uint8)expect;
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint64)(*(uint8 *)maddr);
+ if (readv == expect)
+ *(uint8 *)maddr = (uint8)(sval);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+
+ expect = (uint16)expect;
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint64)LOAD_U16(maddr);
+ if (readv == expect)
+ STORE_U16(maddr, (uint16)(sval));
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+
+ expect = (uint32)expect;
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint64)LOAD_U32(maddr);
+ if (readv == expect)
+ STORE_U32(maddr, (uint32)(sval));
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS();
+
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint64)LOAD_I64(maddr);
+ if (readv == expect)
+ STORE_I64(maddr, sval);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ PUSH_I64(readv);
+ break;
+ }
+
+ DEF_ATOMIC_RMW_OPCODE(ADD, +);
+ DEF_ATOMIC_RMW_OPCODE(SUB, -);
+ DEF_ATOMIC_RMW_OPCODE(AND, &);
+ DEF_ATOMIC_RMW_OPCODE(OR, |);
+ DEF_ATOMIC_RMW_OPCODE(XOR, ^);
+ /* xchg, ignore the read value, and store the given
+ value: readv * 0 + sval */
+ DEF_ATOMIC_RMW_OPCODE(XCHG, *0 +);
+ }
+
+ HANDLE_OP_END();
+ }
+#endif
+
+ HANDLE_OP(WASM_OP_IMPDEP)
+ {
+ frame = prev_frame;
+ frame_ip = frame->ip;
+ frame_sp = frame->sp;
+ frame_csp = frame->csp;
+ goto call_func_from_entry;
+ }
+
+#if WASM_ENABLE_DEBUG_INTERP != 0
+ HANDLE_OP(DEBUG_OP_BREAK)
+ {
+ wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TRAP);
+ exec_env->suspend_flags.flags |= 2;
+ frame_ip--;
+ SYNC_ALL_TO_FRAME();
+ CHECK_SUSPEND_FLAGS();
+ HANDLE_OP_END();
+ }
+#endif
+#if WASM_ENABLE_LABELS_AS_VALUES == 0
+ default:
+ wasm_set_exception(module, "unsupported opcode");
+ goto got_exception;
+ }
+#endif
+
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+ HANDLE_OP(WASM_OP_UNUSED_0x06)
+ HANDLE_OP(WASM_OP_UNUSED_0x07)
+ HANDLE_OP(WASM_OP_UNUSED_0x08)
+ HANDLE_OP(WASM_OP_UNUSED_0x09)
+ HANDLE_OP(WASM_OP_UNUSED_0x0a)
+#if WASM_ENABLE_TAIL_CALL == 0
+ HANDLE_OP(WASM_OP_RETURN_CALL)
+ HANDLE_OP(WASM_OP_RETURN_CALL_INDIRECT)
+#endif
+#if WASM_ENABLE_SHARED_MEMORY == 0
+ HANDLE_OP(WASM_OP_ATOMIC_PREFIX)
+#endif
+#if WASM_ENABLE_REF_TYPES == 0
+ HANDLE_OP(WASM_OP_SELECT_T)
+ HANDLE_OP(WASM_OP_TABLE_GET)
+ HANDLE_OP(WASM_OP_TABLE_SET)
+ HANDLE_OP(WASM_OP_REF_NULL)
+ HANDLE_OP(WASM_OP_REF_IS_NULL)
+ HANDLE_OP(WASM_OP_REF_FUNC)
+#endif
+ HANDLE_OP(WASM_OP_UNUSED_0x14)
+ HANDLE_OP(WASM_OP_UNUSED_0x15)
+ HANDLE_OP(WASM_OP_UNUSED_0x16)
+ HANDLE_OP(WASM_OP_UNUSED_0x17)
+ HANDLE_OP(WASM_OP_UNUSED_0x18)
+ HANDLE_OP(WASM_OP_UNUSED_0x19)
+ HANDLE_OP(WASM_OP_UNUSED_0x27)
+ /* Used by fast interpreter */
+ HANDLE_OP(EXT_OP_SET_LOCAL_FAST_I64)
+ HANDLE_OP(EXT_OP_TEE_LOCAL_FAST_I64)
+ HANDLE_OP(EXT_OP_COPY_STACK_TOP)
+ HANDLE_OP(EXT_OP_COPY_STACK_TOP_I64)
+ HANDLE_OP(EXT_OP_COPY_STACK_VALUES)
+ {
+ wasm_set_exception(module, "unsupported opcode");
+ goto got_exception;
+ }
+#endif
+
+#if WASM_ENABLE_LABELS_AS_VALUES == 0
+ continue;
+#else
+ FETCH_OPCODE_AND_DISPATCH();
+#endif
+
+#if WASM_ENABLE_TAIL_CALL != 0
+ call_func_from_return_call:
+ {
+ POP(cur_func->param_cell_num);
+ if (cur_func->param_cell_num > 0) {
+ word_copy(frame->lp, frame_sp, cur_func->param_cell_num);
+ }
+ FREE_FRAME(exec_env, frame);
+ wasm_exec_env_set_cur_frame(exec_env, prev_frame);
+ goto call_func_from_entry;
+ }
+#endif
+ call_func_from_interp:
+ {
+ /* Only do the copy when it's called from interpreter. */
+ WASMInterpFrame *outs_area = wasm_exec_env_wasm_stack_top(exec_env);
+ POP(cur_func->param_cell_num);
+ SYNC_ALL_TO_FRAME();
+ if (cur_func->param_cell_num > 0) {
+ word_copy(outs_area->lp, frame_sp, cur_func->param_cell_num);
+ }
+ prev_frame = frame;
+ }
+
+ call_func_from_entry:
+ {
+ if (cur_func->is_import_func) {
+#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);
+ }
+
+ prev_frame = frame->prev_frame;
+ cur_func = frame->function;
+ UPDATE_ALL_FROM_FRAME();
+
+ /* update memory size, no need to update memory ptr as
+ it isn't changed in wasm_enlarge_memory */
+#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
+ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
+ || WASM_ENABLE_BULK_MEMORY != 0
+ if (memory)
+ linear_mem_size = memory->memory_data_size;
+#endif
+ if (wasm_copy_exception(module, NULL))
+ goto got_exception;
+ }
+ else {
+ WASMFunction *cur_wasm_func = cur_func->u.func;
+ WASMType *func_type;
+
+ func_type = cur_wasm_func->func_type;
+
+ all_cell_num = cur_func->param_cell_num + cur_func->local_cell_num
+ + cur_wasm_func->max_stack_cell_num
+ + cur_wasm_func->max_block_num
+ * (uint32)sizeof(WASMBranchBlock) / 4;
+ /* param_cell_num, local_cell_num, max_stack_cell_num and
+ max_block_num are all no larger than UINT16_MAX (checked
+ in loader), all_cell_num must be smaller than 1MB */
+ bh_assert(all_cell_num < 1 * BH_MB);
+
+ frame_size = wasm_interp_interp_frame_size(all_cell_num);
+ if (!(frame = ALLOC_FRAME(exec_env, frame_size, prev_frame))) {
+ frame = prev_frame;
+ goto got_exception;
+ }
+
+ /* Initialize the interpreter context. */
+ frame->function = cur_func;
+ frame_ip = wasm_get_func_code(cur_func);
+ frame_ip_end = wasm_get_func_code_end(cur_func);
+ frame_lp = frame->lp;
+
+ frame_sp = frame->sp_bottom =
+ frame_lp + cur_func->param_cell_num + cur_func->local_cell_num;
+ frame->sp_boundary =
+ frame->sp_bottom + cur_wasm_func->max_stack_cell_num;
+
+ frame_csp = frame->csp_bottom =
+ (WASMBranchBlock *)frame->sp_boundary;
+ frame->csp_boundary =
+ frame->csp_bottom + cur_wasm_func->max_block_num;
+
+ /* Initialize the local variables */
+ memset(frame_lp + cur_func->param_cell_num, 0,
+ (uint32)(cur_func->local_cell_num * 4));
+
+ /* Push function block as first block */
+ cell_num = func_type->ret_cell_num;
+ PUSH_CSP(LABEL_TYPE_FUNCTION, 0, cell_num, frame_ip_end - 1);
+
+ wasm_exec_env_set_cur_frame(exec_env, frame);
+ }
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+ HANDLE_OP_END();
+ }
+
+ return_func:
+ {
+ FREE_FRAME(exec_env, frame);
+ wasm_exec_env_set_cur_frame(exec_env, prev_frame);
+
+ if (!prev_frame->ip)
+ /* Called from native. */
+ return;
+
+ RECOVER_CONTEXT(prev_frame);
+ HANDLE_OP_END();
+ }
+
+#if WASM_ENABLE_SHARED_MEMORY != 0
+ unaligned_atomic:
+ wasm_set_exception(module, "unaligned atomic");
+ goto got_exception;
+#endif
+
+#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
+ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
+ || WASM_ENABLE_BULK_MEMORY != 0
+ out_of_bounds:
+ wasm_set_exception(module, "out of bounds memory access");
+#endif
+
+ got_exception:
+#if WASM_ENABLE_DEBUG_INTERP != 0
+ if (wasm_exec_env_get_instance(exec_env) != NULL) {
+ uint8 *frame_ip_temp = frame_ip;
+ frame_ip = frame_ip_orig;
+ wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TRAP);
+ CHECK_SUSPEND_FLAGS();
+ frame_ip = frame_ip_temp;
+ }
+#endif
+ SYNC_ALL_TO_FRAME();
+ return;
+
+#if WASM_ENABLE_LABELS_AS_VALUES == 0
+ }
+#else
+ FETCH_OPCODE_AND_DISPATCH();
+#endif
+}
+
+#if WASM_ENABLE_FAST_JIT != 0
+static void
+fast_jit_call_func_bytecode(WASMModuleInstance *module_inst,
+ WASMExecEnv *exec_env,
+ WASMFunctionInstance *function,
+ WASMInterpFrame *frame)
+{
+ JitGlobals *jit_globals = jit_compiler_get_jit_globals();
+ JitInterpSwitchInfo info;
+ WASMModule *module = module_inst->module;
+ WASMType *func_type = function->u.func->func_type;
+ uint8 type = func_type->result_count
+ ? func_type->types[func_type->param_count]
+ : VALUE_TYPE_VOID;
+ uint32 func_idx = (uint32)(function - module_inst->e->functions);
+ uint32 func_idx_non_import = func_idx - module->import_function_count;
+ int32 action;
+
+#if WASM_ENABLE_REF_TYPES != 0
+ if (type == VALUE_TYPE_EXTERNREF || type == VALUE_TYPE_FUNCREF)
+ type = VALUE_TYPE_I32;
+#endif
+
+#if WASM_ENABLE_LAZY_JIT != 0
+ if (!jit_compiler_compile(module, func_idx)) {
+ wasm_set_exception(module_inst, "failed to compile fast jit function");
+ return;
+ }
+#endif
+ bh_assert(jit_compiler_is_compiled(module, func_idx));
+
+ /* Switch to jitted code to call the jit function */
+ info.out.ret.last_return_type = type;
+ info.frame = frame;
+ frame->jitted_return_addr =
+ (uint8 *)jit_globals->return_to_interp_from_jitted;
+ action = jit_interp_switch_to_jitted(
+ exec_env, &info, func_idx,
+ module_inst->fast_jit_func_ptrs[func_idx_non_import]);
+ bh_assert(action == JIT_INTERP_ACTION_NORMAL
+ || (action == JIT_INTERP_ACTION_THROWN
+ && wasm_copy_exception(
+ (WASMModuleInstance *)exec_env->module_inst, NULL)));
+
+ /* Get the return values form info.out.ret */
+ if (func_type->result_count) {
+ switch (type) {
+ case VALUE_TYPE_I32:
+ *(frame->sp - function->ret_cell_num) = info.out.ret.ival[0];
+ break;
+ case VALUE_TYPE_I64:
+ *(frame->sp - function->ret_cell_num) = info.out.ret.ival[0];
+ *(frame->sp - function->ret_cell_num + 1) =
+ info.out.ret.ival[1];
+ break;
+ case VALUE_TYPE_F32:
+ *(frame->sp - function->ret_cell_num) = info.out.ret.fval[0];
+ break;
+ case VALUE_TYPE_F64:
+ *(frame->sp - function->ret_cell_num) = info.out.ret.fval[0];
+ *(frame->sp - function->ret_cell_num + 1) =
+ info.out.ret.fval[1];
+ break;
+ default:
+ bh_assert(0);
+ break;
+ }
+ }
+ (void)action;
+ (void)func_idx;
+}
+#endif /* end of WASM_ENABLE_FAST_JIT != 0 */
+
+#if WASM_ENABLE_JIT != 0
+static bool
+llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
+ WASMExecEnv *exec_env,
+ WASMFunctionInstance *function, uint32 argc,
+ uint32 argv[])
+{
+ WASMType *func_type = function->u.func->func_type;
+ uint32 result_count = func_type->result_count;
+ uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0;
+ uint32 func_idx = (uint32)(function - module_inst->e->functions);
+ bool ret;
+
+#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
+ if (!llvm_jit_alloc_frame(exec_env, function - module_inst->e->functions)) {
+ /* wasm operand stack overflow has been thrown,
+ no need to throw again */
+ return false;
+ }
+#endif
+
+ if (ext_ret_count > 0) {
+ uint32 cell_num = 0, i;
+ uint8 *ext_ret_types = func_type->types + func_type->param_count + 1;
+ uint32 argv1_buf[32], *argv1 = argv1_buf, *ext_rets = NULL;
+ uint32 *argv_ret = argv;
+ uint32 ext_ret_cell = wasm_get_cell_num(ext_ret_types, ext_ret_count);
+ uint64 size;
+
+ /* Allocate memory all arguments */
+ size =
+ sizeof(uint32) * (uint64)argc /* original arguments */
+ + sizeof(void *)
+ * (uint64)ext_ret_count /* extra result values' addr */
+ + sizeof(uint32) * (uint64)ext_ret_cell; /* extra result values */
+ if (size > sizeof(argv1_buf)) {
+ if (size > UINT32_MAX
+ || !(argv1 = wasm_runtime_malloc((uint32)size))) {
+ wasm_set_exception(module_inst, "allocate memory failed");
+ return false;
+ }
+ }
+
+ /* Copy original arguments */
+ bh_memcpy_s(argv1, (uint32)size, argv, sizeof(uint32) * argc);
+
+ /* Get the extra result value's address */
+ ext_rets =
+ argv1 + argc + sizeof(void *) / sizeof(uint32) * ext_ret_count;
+
+ /* Append each extra result value's address to original arguments */
+ for (i = 0; i < ext_ret_count; i++) {
+ *(uintptr_t *)(argv1 + argc + sizeof(void *) / sizeof(uint32) * i) =
+ (uintptr_t)(ext_rets + cell_num);
+ cell_num += wasm_value_type_cell_num(ext_ret_types[i]);
+ }
+
+ ret = wasm_runtime_invoke_native(
+ exec_env, module_inst->func_ptrs[func_idx], func_type, NULL, NULL,
+ argv1, argc, argv);
+ if (!ret) {
+ if (argv1 != argv1_buf)
+ wasm_runtime_free(argv1);
+ return ret;
+ }
+
+ /* Get extra result values */
+ switch (func_type->types[func_type->param_count]) {
+ case VALUE_TYPE_I32:
+ case VALUE_TYPE_F32:
+#if WASM_ENABLE_REF_TYPES != 0
+ case VALUE_TYPE_FUNCREF:
+ case VALUE_TYPE_EXTERNREF:
+#endif
+ argv_ret++;
+ break;
+ case VALUE_TYPE_I64:
+ case VALUE_TYPE_F64:
+ argv_ret += 2;
+ break;
+#if WASM_ENABLE_SIMD != 0
+ case VALUE_TYPE_V128:
+ argv_ret += 4;
+ break;
+#endif
+ default:
+ bh_assert(0);
+ break;
+ }
+
+ ext_rets =
+ argv1 + argc + sizeof(void *) / sizeof(uint32) * ext_ret_count;
+ bh_memcpy_s(argv_ret, sizeof(uint32) * cell_num, ext_rets,
+ sizeof(uint32) * cell_num);
+
+ if (argv1 != argv1_buf)
+ wasm_runtime_free(argv1);
+ return true;
+ }
+ else {
+ ret = wasm_runtime_invoke_native(
+ exec_env, module_inst->func_ptrs[func_idx], func_type, NULL, NULL,
+ argv, argc, argv);
+
+ return ret && !wasm_copy_exception(module_inst, NULL) ? true : false;
+ }
+}
+#endif /* end of WASM_ENABLE_JIT != 0 */
+
+void
+wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
+ WASMFunctionInstance *function, uint32 argc,
+ uint32 argv[])
+{
+ WASMRuntimeFrame *prev_frame = wasm_exec_env_get_cur_frame(exec_env);
+ WASMInterpFrame *frame, *outs_area;
+ /* Allocate sufficient cells for all kinds of return values. */
+ unsigned all_cell_num =
+ function->ret_cell_num > 2 ? function->ret_cell_num : 2;
+ /* This frame won't be used by JITed code, so only allocate interp
+ frame here. */
+ unsigned frame_size = wasm_interp_interp_frame_size(all_cell_num);
+ unsigned i;
+ bool copy_argv_from_frame = true;
+ char exception[EXCEPTION_BUF_LEN];
+
+ if (argc < function->param_cell_num) {
+ char buf[128];
+ snprintf(buf, sizeof(buf),
+ "invalid argument count %" PRIu32
+ ", must be no smaller than %u",
+ argc, function->param_cell_num);
+ wasm_set_exception(module_inst, buf);
+ return;
+ }
+ argc = function->param_cell_num;
+
+ RECORD_STACK_USAGE(exec_env, (uint8 *)&prev_frame);
+#if !(defined(OS_ENABLE_HW_BOUND_CHECK) \
+ && WASM_DISABLE_STACK_HW_BOUND_CHECK == 0)
+ if ((uint8 *)&prev_frame < exec_env->native_stack_boundary) {
+ wasm_set_exception((WASMModuleInstance *)exec_env->module_inst,
+ "native stack overflow");
+ return;
+ }
+#endif
+
+ if (!(frame = ALLOC_FRAME(exec_env, frame_size, prev_frame)))
+ return;
+
+ outs_area = wasm_exec_env_wasm_stack_top(exec_env);
+ frame->function = NULL;
+ frame->ip = NULL;
+ /* There is no local variable. */
+ frame->sp = frame->lp + 0;
+
+ if ((uint8 *)(outs_area->lp + function->param_cell_num)
+ > exec_env->wasm_stack.s.top_boundary) {
+ wasm_set_exception(module_inst, "wasm operand stack overflow");
+ return;
+ }
+
+ if (argc > 0)
+ word_copy(outs_area->lp, argv, argc);
+
+ wasm_exec_env_set_cur_frame(exec_env, frame);
+
+ if (function->is_import_func) {
+#if WASM_ENABLE_MULTI_MODULE != 0
+ if (function->import_module_inst) {
+ wasm_interp_call_func_import(module_inst, exec_env, function,
+ frame);
+ }
+ else
+#endif
+ {
+ /* it is a native function */
+ wasm_interp_call_func_native(module_inst, exec_env, function,
+ frame);
+ }
+ }
+ else {
+ RunningMode running_mode =
+ wasm_runtime_get_running_mode((wasm_module_inst_t)module_inst);
+
+ if (running_mode == Mode_Interp) {
+ wasm_interp_call_func_bytecode(module_inst, exec_env, function,
+ frame);
+ }
+#if WASM_ENABLE_FAST_JIT != 0
+ else if (running_mode == Mode_Fast_JIT) {
+ fast_jit_call_func_bytecode(module_inst, exec_env, function, frame);
+ }
+#endif
+#if WASM_ENABLE_JIT != 0
+ else if (running_mode == Mode_LLVM_JIT) {
+ llvm_jit_call_func_bytecode(module_inst, exec_env, function, argc,
+ argv);
+ /* For llvm jit, the results have been stored in argv,
+ no need to copy them from stack frame again */
+ copy_argv_from_frame = false;
+ }
+#endif
+#if WASM_ENABLE_LAZY_JIT != 0 && WASM_ENABLE_FAST_JIT != 0 \
+ && WASM_ENABLE_JIT != 0
+ else if (running_mode == Mode_Multi_Tier_JIT) {
+ /* Tier-up from Fast JIT to LLVM JIT, call llvm jit function
+ if it is compiled, else call fast jit function */
+ uint32 func_idx = (uint32)(function - module_inst->e->functions);
+ if (module_inst->module->func_ptrs_compiled
+ [func_idx - module_inst->module->import_function_count]) {
+ llvm_jit_call_func_bytecode(module_inst, exec_env, function,
+ argc, argv);
+ /* For llvm jit, the results have been stored in argv,
+ no need to copy them from stack frame again */
+ copy_argv_from_frame = false;
+ }
+ else {
+ fast_jit_call_func_bytecode(module_inst, exec_env, function,
+ frame);
+ }
+ }
+#endif
+ else {
+ /* There should always be a supported running mode selected */
+ bh_assert(0);
+ }
+
+ (void)wasm_interp_call_func_bytecode;
+#if WASM_ENABLE_FAST_JIT != 0
+ (void)fast_jit_call_func_bytecode;
+#endif
+ }
+
+ /* Output the return value to the caller */
+ if (!wasm_copy_exception(module_inst, NULL)) {
+ if (copy_argv_from_frame) {
+ for (i = 0; i < function->ret_cell_num; i++) {
+ argv[i] = *(frame->sp + i - function->ret_cell_num);
+ }
+ }
+ }
+ else {
+#if WASM_ENABLE_DUMP_CALL_STACK != 0
+ if (wasm_interp_create_call_stack(exec_env)) {
+ wasm_interp_dump_call_stack(exec_env, true, NULL, 0);
+ }
+#endif
+ wasm_copy_exception(module_inst, exception);
+ LOG_DEBUG("meet an exception %s", exception);
+ }
+
+ wasm_exec_env_set_cur_frame(exec_env, prev_frame);
+ FREE_FRAME(exec_env, frame);
+}
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp_fast.c b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp_fast.c
new file mode 100644
index 000000000..6ddeaa9c0
--- /dev/null
+++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp_fast.c
@@ -0,0 +1,4021 @@
+/*
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "wasm_interp.h"
+#include "bh_log.h"
+#include "wasm_runtime.h"
+#include "wasm_opcode.h"
+#include "wasm_loader.h"
+#include "wasm_memory.h"
+#include "../common/wasm_exec_env.h"
+#if WASM_ENABLE_SHARED_MEMORY != 0
+#include "../common/wasm_shared_memory.h"
+#endif
+
+typedef int32 CellType_I32;
+typedef int64 CellType_I64;
+typedef float32 CellType_F32;
+typedef float64 CellType_F64;
+
+#if WASM_ENABLE_THREAD_MGR == 0
+#define get_linear_mem_size() linear_mem_size
+#else
+/**
+ * Load memory data size in each time boundary check in
+ * multi-threading mode since it may be changed by other
+ * threads in memory.grow
+ */
+#define get_linear_mem_size() memory->memory_data_size
+#endif
+
+#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
+ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+#define CHECK_MEMORY_OVERFLOW(bytes) \
+ do { \
+ uint64 offset1 = (uint64)offset + (uint64)addr; \
+ if (offset1 + bytes <= (uint64)get_linear_mem_size()) \
+ /* If offset1 is in valid range, maddr must also \
+ be in valid range, no need to check it again. */ \
+ maddr = memory->memory_data + offset1; \
+ else \
+ goto out_of_bounds; \
+ } while (0)
+
+#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
+ do { \
+ uint64 offset1 = (uint32)(start); \
+ if (offset1 + bytes <= get_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)
+#else
+#define CHECK_MEMORY_OVERFLOW(bytes) \
+ do { \
+ uint64 offset1 = (uint64)offset + (uint64)addr; \
+ maddr = memory->memory_data + offset1; \
+ } while (0)
+
+#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
+ do { \
+ maddr = memory->memory_data + (uint32)(start); \
+ } while (0)
+#endif /* !defined(OS_ENABLE_HW_BOUND_CHECK) \
+ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */
+
+#define CHECK_ATOMIC_MEMORY_ACCESS(align) \
+ do { \
+ if (((uintptr_t)maddr & (align - 1)) != 0) \
+ goto unaligned_atomic; \
+ } while (0)
+
+static inline uint32
+rotl32(uint32 n, uint32 c)
+{
+ const uint32 mask = (31);
+ c = c % 32;
+ c &= mask;
+ return (n << c) | (n >> ((0 - c) & mask));
+}
+
+static inline uint32
+rotr32(uint32 n, uint32 c)
+{
+ const uint32 mask = (31);
+ c = c % 32;
+ c &= mask;
+ return (n >> c) | (n << ((0 - c) & mask));
+}
+
+static inline uint64
+rotl64(uint64 n, uint64 c)
+{
+ const uint64 mask = (63);
+ c = c % 64;
+ c &= mask;
+ return (n << c) | (n >> ((0 - c) & mask));
+}
+
+static inline uint64
+rotr64(uint64 n, uint64 c)
+{
+ const uint64 mask = (63);
+ c = c % 64;
+ c &= mask;
+ return (n >> c) | (n << ((0 - c) & mask));
+}
+
+static inline float32
+f32_min(float32 a, float32 b)
+{
+ if (isnan(a) || isnan(b))
+ return NAN;
+ else if (a == 0 && a == b)
+ return signbit(a) ? a : b;
+ else
+ return a > b ? b : a;
+}
+
+static inline float32
+f32_max(float32 a, float32 b)
+{
+ if (isnan(a) || isnan(b))
+ return NAN;
+ else if (a == 0 && a == b)
+ return signbit(a) ? b : a;
+ else
+ return a > b ? a : b;
+}
+
+static inline float64
+f64_min(float64 a, float64 b)
+{
+ if (isnan(a) || isnan(b))
+ return NAN;
+ else if (a == 0 && a == b)
+ return signbit(a) ? a : b;
+ else
+ return a > b ? b : a;
+}
+
+static inline float64
+f64_max(float64 a, float64 b)
+{
+ if (isnan(a) || isnan(b))
+ return NAN;
+ else if (a == 0 && a == b)
+ return signbit(a) ? b : a;
+ else
+ return a > b ? a : b;
+}
+
+static inline uint32
+clz32(uint32 type)
+{
+ uint32 num = 0;
+ if (type == 0)
+ return 32;
+ while (!(type & 0x80000000)) {
+ num++;
+ type <<= 1;
+ }
+ return num;
+}
+
+static inline uint32
+clz64(uint64 type)
+{
+ uint32 num = 0;
+ if (type == 0)
+ return 64;
+ while (!(type & 0x8000000000000000LL)) {
+ num++;
+ type <<= 1;
+ }
+ return num;
+}
+
+static inline uint32
+ctz32(uint32 type)
+{
+ uint32 num = 0;
+ if (type == 0)
+ return 32;
+ while (!(type & 1)) {
+ num++;
+ type >>= 1;
+ }
+ return num;
+}
+
+static inline uint32
+ctz64(uint64 type)
+{
+ uint32 num = 0;
+ if (type == 0)
+ return 64;
+ while (!(type & 1)) {
+ num++;
+ type >>= 1;
+ }
+ return num;
+}
+
+static inline uint32
+popcount32(uint32 u)
+{
+ uint32 ret = 0;
+ while (u) {
+ u = (u & (u - 1));
+ ret++;
+ }
+ return ret;
+}
+
+static inline uint32
+popcount64(uint64 u)
+{
+ uint32 ret = 0;
+ while (u) {
+ u = (u & (u - 1));
+ ret++;
+ }
+ return ret;
+}
+
+static float
+local_copysignf(float x, float y)
+{
+ union {
+ float f;
+ uint32 i;
+ } ux = { x }, uy = { y };
+ ux.i &= 0x7fffffff;
+ ux.i |= uy.i & 0x80000000;
+ return ux.f;
+}
+
+static double
+local_copysign(double x, double y)
+{
+ union {
+ double f;
+ uint64 i;
+ } ux = { x }, uy = { y };
+ ux.i &= UINT64_MAX / 2;
+ ux.i |= uy.i & 1ULL << 63;
+ return ux.f;
+}
+
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
+#define LOAD_U32_WITH_2U16S(addr) (*(uint32 *)(addr))
+#define LOAD_PTR(addr) (*(void **)(addr))
+#else /* else of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */
+static inline uint32
+LOAD_U32_WITH_2U16S(void *addr)
+{
+ union {
+ uint32 val;
+ uint16 u16[2];
+ } u;
+
+ bh_assert(((uintptr_t)addr & 1) == 0);
+ u.u16[0] = ((uint16 *)addr)[0];
+ u.u16[1] = ((uint16 *)addr)[1];
+ return u.val;
+}
+#if UINTPTR_MAX == UINT32_MAX
+#define LOAD_PTR(addr) ((void *)LOAD_U32_WITH_2U16S(addr))
+#elif UINTPTR_MAX == UINT64_MAX
+static inline void *
+LOAD_PTR(void *addr)
+{
+ uintptr_t addr1 = (uintptr_t)addr;
+ union {
+ void *val;
+ uint32 u32[2];
+ uint16 u16[4];
+ } u;
+
+ bh_assert(((uintptr_t)addr & 1) == 0);
+ if ((addr1 & (uintptr_t)7) == 0)
+ return *(void **)addr;
+
+ if ((addr1 & (uintptr_t)3) == 0) {
+ u.u32[0] = ((uint32 *)addr)[0];
+ u.u32[1] = ((uint32 *)addr)[1];
+ }
+ else {
+ u.u16[0] = ((uint16 *)addr)[0];
+ u.u16[1] = ((uint16 *)addr)[1];
+ u.u16[2] = ((uint16 *)addr)[2];
+ u.u16[3] = ((uint16 *)addr)[3];
+ }
+ return u.val;
+}
+#endif /* end of UINTPTR_MAX */
+#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */
+
+#define read_uint32(p) \
+ (p += sizeof(uint32), LOAD_U32_WITH_2U16S(p - sizeof(uint32)))
+
+#define GET_LOCAL_INDEX_TYPE_AND_OFFSET() \
+ do { \
+ uint32 param_count = cur_func->param_count; \
+ local_idx = read_uint32(frame_ip); \
+ bh_assert(local_idx < param_count + cur_func->local_count); \
+ local_offset = cur_func->local_offsets[local_idx]; \
+ if (local_idx < param_count) \
+ local_type = cur_func->param_types[local_idx]; \
+ else \
+ local_type = cur_func->local_types[local_idx - param_count]; \
+ } while (0)
+
+#define GET_OFFSET() (frame_ip += 2, *(int16 *)(frame_ip - 2))
+
+#define SET_OPERAND_I32(off, value) \
+ do { \
+ *(uint32 *)(frame_lp + *(int16 *)(frame_ip + off)) = value; \
+ } while (0)
+#define SET_OPERAND_F32(off, value) \
+ do { \
+ *(float32 *)(frame_lp + *(int16 *)(frame_ip + off)) = value; \
+ } while (0)
+#define SET_OPERAND_I64(off, value) \
+ do { \
+ uint32 *addr_tmp = frame_lp + *(int16 *)(frame_ip + off); \
+ PUT_I64_TO_ADDR(addr_tmp, value); \
+ } while (0)
+#define SET_OPERAND_F64(off, value) \
+ do { \
+ uint32 *addr_tmp = frame_lp + *(int16 *)(frame_ip + off); \
+ PUT_F64_TO_ADDR(addr_tmp, value); \
+ } while (0)
+
+#define SET_OPERAND(op_type, off, value) SET_OPERAND_##op_type(off, value)
+
+#define GET_OPERAND_I32(type, off) \
+ *(type *)(frame_lp + *(int16 *)(frame_ip + off))
+#define GET_OPERAND_F32(type, off) \
+ *(type *)(frame_lp + *(int16 *)(frame_ip + off))
+#define GET_OPERAND_I64(type, off) \
+ (type) GET_I64_FROM_ADDR(frame_lp + *(int16 *)(frame_ip + off))
+#define GET_OPERAND_F64(type, off) \
+ (type) GET_F64_FROM_ADDR(frame_lp + *(int16 *)(frame_ip + off))
+
+#define GET_OPERAND(type, op_type, off) GET_OPERAND_##op_type(type, off)
+
+#define PUSH_I32(value) \
+ do { \
+ *(int32 *)(frame_lp + GET_OFFSET()) = value; \
+ } while (0)
+
+#define PUSH_F32(value) \
+ do { \
+ *(float32 *)(frame_lp + GET_OFFSET()) = value; \
+ } while (0)
+
+#define PUSH_I64(value) \
+ do { \
+ uint32 *addr_tmp = frame_lp + GET_OFFSET(); \
+ PUT_I64_TO_ADDR(addr_tmp, value); \
+ } while (0)
+
+#define PUSH_F64(value) \
+ do { \
+ uint32 *addr_tmp = frame_lp + GET_OFFSET(); \
+ PUT_F64_TO_ADDR(addr_tmp, value); \
+ } while (0)
+
+#define POP_I32() (*(int32 *)(frame_lp + GET_OFFSET()))
+
+#define POP_F32() (*(float32 *)(frame_lp + GET_OFFSET()))
+
+#define POP_I64() (GET_I64_FROM_ADDR(frame_lp + GET_OFFSET()))
+
+#define POP_F64() (GET_F64_FROM_ADDR(frame_lp + GET_OFFSET()))
+
+#define SYNC_ALL_TO_FRAME() \
+ do { \
+ frame->ip = frame_ip; \
+ } while (0)
+
+#define UPDATE_ALL_FROM_FRAME() \
+ do { \
+ frame_ip = frame->ip; \
+ } while (0)
+
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+#define UPDATE_FRAME_IP_END() (void)0
+#else
+#define UPDATE_FRAME_IP_END() frame_ip_end = wasm_get_func_code_end(cur_func)
+#endif
+
+#define RECOVER_CONTEXT(new_frame) \
+ do { \
+ frame = (new_frame); \
+ cur_func = frame->function; \
+ prev_frame = frame->prev_frame; \
+ frame_ip = frame->ip; \
+ UPDATE_FRAME_IP_END(); \
+ frame_lp = frame->lp; \
+ } while (0)
+
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
+#define GET_OPCODE() opcode = *frame_ip++;
+#else
+#define GET_OPCODE() \
+ opcode = *frame_ip; \
+ frame_ip += 2;
+#endif
+
+#define DEF_OP_EQZ(ctype, src_op_type) \
+ do { \
+ SET_OPERAND(I32, 2, (GET_OPERAND(ctype, src_op_type, 0) == 0)); \
+ frame_ip += 4; \
+ } while (0)
+
+#define DEF_OP_CMP(src_type, src_op_type, cond) \
+ do { \
+ SET_OPERAND(I32, 4, \
+ GET_OPERAND(src_type, src_op_type, 2) \
+ cond GET_OPERAND(src_type, src_op_type, 0)); \
+ frame_ip += 6; \
+ } while (0)
+
+#define DEF_OP_BIT_COUNT(src_type, src_op_type, operation) \
+ do { \
+ SET_OPERAND( \
+ src_op_type, 2, \
+ (src_type)operation(GET_OPERAND(src_type, src_op_type, 0))); \
+ frame_ip += 4; \
+ } while (0)
+
+#define DEF_OP_NUMERIC(src_type1, src_type2, src_op_type, operation) \
+ do { \
+ SET_OPERAND(src_op_type, 4, \
+ GET_OPERAND(src_type1, src_op_type, 2) \
+ operation GET_OPERAND(src_type2, src_op_type, 0)); \
+ frame_ip += 6; \
+ } while (0)
+
+#define DEF_OP_REINTERPRET(src_type, src_op_type) \
+ do { \
+ SET_OPERAND(src_op_type, 2, GET_OPERAND(src_type, src_op_type, 0)); \
+ frame_ip += 4; \
+ } while (0)
+
+#define DEF_OP_NUMERIC_64 DEF_OP_NUMERIC
+
+#define DEF_OP_NUMERIC2(src_type1, src_type2, src_op_type, operation) \
+ do { \
+ SET_OPERAND(src_op_type, 4, \
+ GET_OPERAND(src_type1, src_op_type, 2) operation( \
+ GET_OPERAND(src_type2, src_op_type, 0) % 32)); \
+ frame_ip += 6; \
+ } while (0)
+
+#define DEF_OP_NUMERIC2_64(src_type1, src_type2, src_op_type, operation) \
+ do { \
+ SET_OPERAND(src_op_type, 4, \
+ GET_OPERAND(src_type1, src_op_type, 2) operation( \
+ GET_OPERAND(src_type2, src_op_type, 0) % 64)); \
+ frame_ip += 6; \
+ } while (0)
+
+#define DEF_ATOMIC_RMW_OPCODE(OP_NAME, op) \
+ case WASM_OP_ATOMIC_RMW_I32_##OP_NAME: \
+ case WASM_OP_ATOMIC_RMW_I32_##OP_NAME##8_U: \
+ case WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U: \
+ { \
+ uint32 readv, sval; \
+ \
+ sval = POP_I32(); \
+ addr = POP_I32(); \
+ \
+ if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##8_U) { \
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \
+ CHECK_ATOMIC_MEMORY_ACCESS(1); \
+ \
+ os_mutex_lock(&node->shared_mem_lock); \
+ readv = (uint32)(*(uint8 *)maddr); \
+ *(uint8 *)maddr = (uint8)(readv op sval); \
+ os_mutex_unlock(&node->shared_mem_lock); \
+ } \
+ else if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U) { \
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \
+ CHECK_ATOMIC_MEMORY_ACCESS(2); \
+ \
+ os_mutex_lock(&node->shared_mem_lock); \
+ readv = (uint32)LOAD_U16(maddr); \
+ STORE_U16(maddr, (uint16)(readv op sval)); \
+ os_mutex_unlock(&node->shared_mem_lock); \
+ } \
+ else { \
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \
+ CHECK_ATOMIC_MEMORY_ACCESS(4); \
+ \
+ os_mutex_lock(&node->shared_mem_lock); \
+ readv = LOAD_I32(maddr); \
+ STORE_U32(maddr, readv op sval); \
+ os_mutex_unlock(&node->shared_mem_lock); \
+ } \
+ PUSH_I32(readv); \
+ break; \
+ } \
+ case WASM_OP_ATOMIC_RMW_I64_##OP_NAME: \
+ case WASM_OP_ATOMIC_RMW_I64_##OP_NAME##8_U: \
+ case WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U: \
+ case WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U: \
+ { \
+ uint64 readv, sval; \
+ \
+ sval = (uint64)POP_I64(); \
+ addr = POP_I32(); \
+ \
+ if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##8_U) { \
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \
+ CHECK_ATOMIC_MEMORY_ACCESS(1); \
+ \
+ os_mutex_lock(&node->shared_mem_lock); \
+ readv = (uint64)(*(uint8 *)maddr); \
+ *(uint8 *)maddr = (uint8)(readv op sval); \
+ os_mutex_unlock(&node->shared_mem_lock); \
+ } \
+ else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U) { \
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \
+ CHECK_ATOMIC_MEMORY_ACCESS(2); \
+ \
+ os_mutex_lock(&node->shared_mem_lock); \
+ readv = (uint64)LOAD_U16(maddr); \
+ STORE_U16(maddr, (uint16)(readv op sval)); \
+ os_mutex_unlock(&node->shared_mem_lock); \
+ } \
+ else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U) { \
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \
+ CHECK_ATOMIC_MEMORY_ACCESS(4); \
+ \
+ os_mutex_lock(&node->shared_mem_lock); \
+ readv = (uint64)LOAD_U32(maddr); \
+ STORE_U32(maddr, (uint32)(readv op sval)); \
+ os_mutex_unlock(&node->shared_mem_lock); \
+ } \
+ else { \
+ uint64 op_result; \
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); \
+ CHECK_ATOMIC_MEMORY_ACCESS(8); \
+ \
+ os_mutex_lock(&node->shared_mem_lock); \
+ readv = (uint64)LOAD_I64(maddr); \
+ op_result = readv op sval; \
+ STORE_I64(maddr, op_result); \
+ os_mutex_unlock(&node->shared_mem_lock); \
+ } \
+ PUSH_I64(readv); \
+ break; \
+ }
+
+#define DEF_OP_MATH(src_type, src_op_type, method) \
+ do { \
+ SET_OPERAND(src_op_type, 2, \
+ (src_type)method(GET_OPERAND(src_type, src_op_type, 0))); \
+ frame_ip += 4; \
+ } while (0)
+
+#define TRUNC_FUNCTION(func_name, src_type, dst_type, signed_type) \
+ static dst_type func_name(src_type src_value, src_type src_min, \
+ src_type src_max, dst_type dst_min, \
+ dst_type dst_max, bool is_sign) \
+ { \
+ dst_type dst_value = 0; \
+ if (!isnan(src_value)) { \
+ if (src_value <= src_min) \
+ dst_value = dst_min; \
+ else if (src_value >= src_max) \
+ dst_value = dst_max; \
+ else { \
+ if (is_sign) \
+ dst_value = (dst_type)(signed_type)src_value; \
+ else \
+ dst_value = (dst_type)src_value; \
+ } \
+ } \
+ return dst_value; \
+ }
+
+TRUNC_FUNCTION(trunc_f32_to_i32, float32, uint32, int32)
+TRUNC_FUNCTION(trunc_f32_to_i64, float32, uint64, int64)
+TRUNC_FUNCTION(trunc_f64_to_i32, float64, uint32, int32)
+TRUNC_FUNCTION(trunc_f64_to_i64, float64, uint64, int64)
+
+static bool
+trunc_f32_to_int(WASMModuleInstance *module, uint8 *frame_ip, uint32 *frame_lp,
+ float32 src_min, float32 src_max, bool saturating, bool is_i32,
+ bool is_sign)
+{
+ float32 src_value = GET_OPERAND(float32, F32, 0);
+ uint64 dst_value_i64;
+ uint32 dst_value_i32;
+
+ if (!saturating) {
+ if (isnan(src_value)) {
+ wasm_set_exception(module, "invalid conversion to integer");
+ return false;
+ }
+ else if (src_value <= src_min || src_value >= src_max) {
+ wasm_set_exception(module, "integer overflow");
+ return false;
+ }
+ }
+
+ if (is_i32) {
+ uint32 dst_min = is_sign ? INT32_MIN : 0;
+ uint32 dst_max = is_sign ? INT32_MAX : UINT32_MAX;
+ dst_value_i32 = trunc_f32_to_i32(src_value, src_min, src_max, dst_min,
+ dst_max, is_sign);
+ SET_OPERAND(I32, 2, dst_value_i32);
+ }
+ else {
+ uint64 dst_min = is_sign ? INT64_MIN : 0;
+ uint64 dst_max = is_sign ? INT64_MAX : UINT64_MAX;
+ dst_value_i64 = trunc_f32_to_i64(src_value, src_min, src_max, dst_min,
+ dst_max, is_sign);
+ SET_OPERAND(I64, 2, dst_value_i64);
+ }
+ return true;
+}
+
+static bool
+trunc_f64_to_int(WASMModuleInstance *module, uint8 *frame_ip, uint32 *frame_lp,
+ float64 src_min, float64 src_max, bool saturating, bool is_i32,
+ bool is_sign)
+{
+ float64 src_value = GET_OPERAND(float64, F64, 0);
+ uint64 dst_value_i64;
+ uint32 dst_value_i32;
+
+ if (!saturating) {
+ if (isnan(src_value)) {
+ wasm_set_exception(module, "invalid conversion to integer");
+ return false;
+ }
+ else if (src_value <= src_min || src_value >= src_max) {
+ wasm_set_exception(module, "integer overflow");
+ return false;
+ }
+ }
+
+ if (is_i32) {
+ uint32 dst_min = is_sign ? INT32_MIN : 0;
+ uint32 dst_max = is_sign ? INT32_MAX : UINT32_MAX;
+ dst_value_i32 = trunc_f64_to_i32(src_value, src_min, src_max, dst_min,
+ dst_max, is_sign);
+ SET_OPERAND(I32, 2, dst_value_i32);
+ }
+ else {
+ uint64 dst_min = is_sign ? INT64_MIN : 0;
+ uint64 dst_max = is_sign ? INT64_MAX : UINT64_MAX;
+ dst_value_i64 = trunc_f64_to_i64(src_value, src_min, src_max, dst_min,
+ dst_max, is_sign);
+ SET_OPERAND(I64, 2, dst_value_i64);
+ }
+ return true;
+}
+
+#define DEF_OP_TRUNC_F32(min, max, is_i32, is_sign) \
+ do { \
+ if (!trunc_f32_to_int(module, frame_ip, frame_lp, min, max, false, \
+ is_i32, is_sign)) \
+ goto got_exception; \
+ frame_ip += 4; \
+ } while (0)
+
+#define DEF_OP_TRUNC_F64(min, max, is_i32, is_sign) \
+ do { \
+ if (!trunc_f64_to_int(module, frame_ip, frame_lp, min, max, false, \
+ is_i32, is_sign)) \
+ goto got_exception; \
+ frame_ip += 4; \
+ } while (0)
+
+#define DEF_OP_TRUNC_SAT_F32(min, max, is_i32, is_sign) \
+ do { \
+ (void)trunc_f32_to_int(module, frame_ip, frame_lp, min, max, true, \
+ is_i32, is_sign); \
+ frame_ip += 4; \
+ } while (0)
+
+#define DEF_OP_TRUNC_SAT_F64(min, max, is_i32, is_sign) \
+ do { \
+ (void)trunc_f64_to_int(module, frame_ip, frame_lp, min, max, true, \
+ is_i32, is_sign); \
+ frame_ip += 4; \
+ } while (0)
+
+#define DEF_OP_CONVERT(dst_type, dst_op_type, src_type, src_op_type) \
+ do { \
+ dst_type value = (dst_type)(src_type)POP_##src_op_type(); \
+ PUSH_##dst_op_type(value); \
+ } while (0)
+
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
+#define CELL_SIZE sizeof(uint8)
+#else
+#define CELL_SIZE (sizeof(uint8) * 2)
+#endif
+
+static bool
+copy_stack_values(WASMModuleInstance *module, uint32 *frame_lp, uint32 arity,
+ uint32 total_cell_num, const uint8 *cells,
+ const int16 *src_offsets, const uint16 *dst_offsets)
+{
+ /* To avoid the overlap issue between src offsets and dst offset,
+ * we use 2 steps to do the copy. First step, copy the src values
+ * to a tmp buf. Second step, copy the values from tmp buf to dst.
+ */
+ uint32 buf[16] = { 0 }, i;
+ uint32 *tmp_buf = buf;
+ uint8 cell;
+ int16 src, buf_index = 0;
+ uint16 dst;
+
+ /* Allocate memory if the buf is not large enough */
+ if (total_cell_num > sizeof(buf) / sizeof(uint32)) {
+ uint64 total_size = sizeof(uint32) * (uint64)total_cell_num;
+ if (total_size >= UINT32_MAX
+ || !(tmp_buf = wasm_runtime_malloc((uint32)total_size))) {
+ wasm_set_exception(module, "allocate memory failed");
+ return false;
+ }
+ }
+
+ /* 1) Copy values from src to tmp buf */
+ for (i = 0; i < arity; i++) {
+ cell = cells[i * CELL_SIZE];
+ src = src_offsets[i];
+ if (cell == 1)
+ tmp_buf[buf_index] = frame_lp[src];
+ else {
+ tmp_buf[buf_index] = frame_lp[src];
+ tmp_buf[buf_index + 1] = frame_lp[src + 1];
+ }
+ buf_index += cell;
+ }
+
+ /* 2) Copy values from tmp buf to dest */
+ buf_index = 0;
+ for (i = 0; i < arity; i++) {
+ cell = cells[i * CELL_SIZE];
+ dst = dst_offsets[i];
+ if (cell == 1)
+ frame_lp[dst] = tmp_buf[buf_index];
+ else {
+ frame_lp[dst] = tmp_buf[buf_index];
+ frame_lp[dst + 1] = tmp_buf[buf_index + 1];
+ }
+ buf_index += cell;
+ }
+
+ if (tmp_buf != buf) {
+ wasm_runtime_free(tmp_buf);
+ }
+
+ return true;
+}
+
+#define RECOVER_BR_INFO() \
+ do { \
+ uint32 arity; \
+ /* read arity */ \
+ arity = read_uint32(frame_ip); \
+ if (arity) { \
+ uint32 total_cell; \
+ uint16 *dst_offsets = NULL; \
+ uint8 *cells; \
+ int16 *src_offsets = NULL; \
+ /* read total cell num */ \
+ total_cell = read_uint32(frame_ip); \
+ /* cells */ \
+ cells = (uint8 *)frame_ip; \
+ frame_ip += arity * CELL_SIZE; \
+ /* src offsets */ \
+ src_offsets = (int16 *)frame_ip; \
+ frame_ip += arity * sizeof(int16); \
+ /* dst offsets */ \
+ dst_offsets = (uint16 *)frame_ip; \
+ frame_ip += arity * sizeof(uint16); \
+ if (arity == 1) { \
+ if (cells[0] == 1) \
+ frame_lp[dst_offsets[0]] = frame_lp[src_offsets[0]]; \
+ else if (cells[0] == 2) { \
+ frame_lp[dst_offsets[0]] = frame_lp[src_offsets[0]]; \
+ frame_lp[dst_offsets[0] + 1] = \
+ frame_lp[src_offsets[0] + 1]; \
+ } \
+ } \
+ else { \
+ if (!copy_stack_values(module, frame_lp, arity, total_cell, \
+ cells, src_offsets, dst_offsets)) \
+ goto got_exception; \
+ } \
+ } \
+ frame_ip = (uint8 *)LOAD_PTR(frame_ip); \
+ } while (0)
+
+#define SKIP_BR_INFO() \
+ do { \
+ uint32 arity; \
+ /* read and skip arity */ \
+ arity = read_uint32(frame_ip); \
+ if (arity) { \
+ /* skip total cell num */ \
+ frame_ip += sizeof(uint32); \
+ /* skip cells, src offsets and dst offsets */ \
+ frame_ip += (CELL_SIZE + sizeof(int16) + sizeof(uint16)) * arity; \
+ } \
+ /* skip target address */ \
+ frame_ip += sizeof(uint8 *); \
+ } while (0)
+
+static inline int32
+sign_ext_8_32(int8 val)
+{
+ if (val & 0x80)
+ return (int32)val | (int32)0xffffff00;
+ return val;
+}
+
+static inline int32
+sign_ext_16_32(int16 val)
+{
+ if (val & 0x8000)
+ return (int32)val | (int32)0xffff0000;
+ return val;
+}
+
+static inline int64
+sign_ext_8_64(int8 val)
+{
+ if (val & 0x80)
+ return (int64)val | (int64)0xffffffffffffff00LL;
+ return val;
+}
+
+static inline int64
+sign_ext_16_64(int16 val)
+{
+ if (val & 0x8000)
+ return (int64)val | (int64)0xffffffffffff0000LL;
+ return val;
+}
+
+static inline int64
+sign_ext_32_64(int32 val)
+{
+ if (val & (int32)0x80000000)
+ return (int64)val | (int64)0xffffffff00000000LL;
+ return val;
+}
+
+static inline void
+word_copy(uint32 *dest, uint32 *src, unsigned num)
+{
+ bh_assert(dest != NULL);
+ bh_assert(src != NULL);
+ bh_assert(num > 0);
+ if (dest != src) {
+ /* No overlap buffer */
+ bh_assert(!((src < dest) && (dest < src + num)));
+ for (; num > 0; num--)
+ *dest++ = *src++;
+ }
+}
+
+static inline WASMInterpFrame *
+ALLOC_FRAME(WASMExecEnv *exec_env, uint32 size, WASMInterpFrame *prev_frame)
+{
+ WASMInterpFrame *frame = wasm_exec_env_alloc_wasm_frame(exec_env, size);
+
+ if (frame) {
+ frame->prev_frame = prev_frame;
+#if WASM_ENABLE_PERF_PROFILING != 0
+ frame->time_started = os_time_get_boot_microsecond();
+#endif
+ }
+ else {
+ wasm_set_exception((WASMModuleInstance *)exec_env->module_inst,
+ "wasm operand stack overflow");
+ }
+
+ return frame;
+}
+
+static inline void
+FREE_FRAME(WASMExecEnv *exec_env, WASMInterpFrame *frame)
+{
+#if WASM_ENABLE_PERF_PROFILING != 0
+ if (frame->function) {
+ frame->function->total_exec_time +=
+ os_time_get_boot_microsecond() - frame->time_started;
+ frame->function->total_exec_cnt++;
+ }
+#endif
+ wasm_exec_env_free_wasm_frame(exec_env, frame);
+}
+
+static void
+wasm_interp_call_func_native(WASMModuleInstance *module_inst,
+ WASMExecEnv *exec_env,
+ WASMFunctionInstance *cur_func,
+ WASMInterpFrame *prev_frame)
+{
+ WASMFunctionImport *func_import = cur_func->u.func_import;
+ CApiFuncImport *c_api_func_import = NULL;
+ unsigned local_cell_num = 2;
+ WASMInterpFrame *frame;
+ uint32 argv_ret[2], cur_func_index;
+ void *native_func_pointer = NULL;
+ bool ret;
+
+ if (!(frame = ALLOC_FRAME(exec_env,
+ wasm_interp_interp_frame_size(local_cell_num),
+ prev_frame)))
+ return;
+
+ frame->function = cur_func;
+ frame->ip = NULL;
+ frame->lp = frame->operand;
+
+ wasm_exec_env_set_cur_frame(exec_env, frame);
+
+ cur_func_index = (uint32)(cur_func - module_inst->e->functions);
+ bh_assert(cur_func_index < module_inst->module->import_function_count);
+ if (!func_import->call_conv_wasm_c_api) {
+ native_func_pointer = module_inst->import_func_ptrs[cur_func_index];
+ }
+ else if (module_inst->e->c_api_func_imports) {
+ c_api_func_import = module_inst->e->c_api_func_imports + cur_func_index;
+ native_func_pointer = c_api_func_import->func_ptr_linked;
+ }
+
+ if (!native_func_pointer) {
+ char buf[128];
+ snprintf(buf, sizeof(buf),
+ "failed to call unlinked import function (%s, %s)",
+ func_import->module_name, func_import->field_name);
+ wasm_set_exception((WASMModuleInstance *)module_inst, buf);
+ return;
+ }
+
+ if (func_import->call_conv_wasm_c_api) {
+ ret = wasm_runtime_invoke_c_api_native(
+ (WASMModuleInstanceCommon *)module_inst, native_func_pointer,
+ func_import->func_type, cur_func->param_cell_num, frame->lp,
+ c_api_func_import->with_env_arg, c_api_func_import->env_arg);
+ if (ret) {
+ argv_ret[0] = frame->lp[0];
+ argv_ret[1] = frame->lp[1];
+ }
+ }
+ else if (!func_import->call_conv_raw) {
+ ret = wasm_runtime_invoke_native(
+ exec_env, native_func_pointer, func_import->func_type,
+ func_import->signature, func_import->attachment, frame->lp,
+ cur_func->param_cell_num, argv_ret);
+ }
+ else {
+ ret = wasm_runtime_invoke_native_raw(
+ exec_env, native_func_pointer, func_import->func_type,
+ func_import->signature, func_import->attachment, frame->lp,
+ cur_func->param_cell_num, argv_ret);
+ }
+
+ if (!ret)
+ return;
+
+ if (cur_func->ret_cell_num == 1) {
+ prev_frame->lp[prev_frame->ret_offset] = argv_ret[0];
+ }
+ else if (cur_func->ret_cell_num == 2) {
+ prev_frame->lp[prev_frame->ret_offset] = argv_ret[0];
+ prev_frame->lp[prev_frame->ret_offset + 1] = argv_ret[1];
+ }
+
+ FREE_FRAME(exec_env, frame);
+ 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];
+ WASMExecEnv *sub_module_exec_env = NULL;
+ uint32 aux_stack_origin_boundary = 0;
+ uint32 aux_stack_origin_bottom = 0;
+
+ if (!sub_func_inst) {
+ snprintf(buf, sizeof(buf),
+ "failed to call unlinked import function (%s, %s)",
+ func_import->module_name, func_import->field_name);
+ wasm_set_exception(module_inst, buf);
+ return;
+ }
+
+ /* Switch exec_env but keep using the same one by replacing necessary
+ * variables */
+ sub_module_exec_env = wasm_runtime_get_exec_env_singleton(
+ (WASMModuleInstanceCommon *)sub_module_inst);
+ if (!sub_module_exec_env) {
+ wasm_set_exception(module_inst, "create singleton exec_env failed");
+ return;
+ }
+
+ /* - module_inst */
+ exec_env->module_inst = (WASMModuleInstanceCommon *)sub_module_inst;
+ /* - aux_stack_boundary */
+ aux_stack_origin_boundary = exec_env->aux_stack_boundary.boundary;
+ exec_env->aux_stack_boundary.boundary =
+ sub_module_exec_env->aux_stack_boundary.boundary;
+ /* - aux_stack_bottom */
+ aux_stack_origin_bottom = exec_env->aux_stack_bottom.bottom;
+ exec_env->aux_stack_bottom.bottom =
+ sub_module_exec_env->aux_stack_bottom.bottom;
+
+ /* set ip NULL to make call_func_bytecode return after executing
+ this function */
+ prev_frame->ip = NULL;
+
+ /* call function of sub-module*/
+ wasm_interp_call_func_bytecode(sub_module_inst, exec_env, sub_func_inst,
+ prev_frame);
+
+ /* restore ip and other replaced */
+ prev_frame->ip = ip;
+ exec_env->aux_stack_boundary.boundary = aux_stack_origin_boundary;
+ exec_env->aux_stack_bottom.bottom = aux_stack_origin_bottom;
+ exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
+
+ /* transfer exception if it is thrown */
+ if (wasm_copy_exception(sub_module_inst, NULL)) {
+ 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_THREAD_MGR != 0
+#define CHECK_SUSPEND_FLAGS() \
+ do { \
+ os_mutex_lock(&exec_env->wait_lock); \
+ if (exec_env->suspend_flags.flags != 0) { \
+ if (exec_env->suspend_flags.flags & 0x01) { \
+ /* terminate current thread */ \
+ os_mutex_unlock(&exec_env->wait_lock); \
+ return; \
+ } \
+ /* TODO: support suspend and breakpoint */ \
+ } \
+ os_mutex_unlock(&exec_env->wait_lock); \
+ } while (0)
+#endif
+
+#if WASM_ENABLE_OPCODE_COUNTER != 0
+typedef struct OpcodeInfo {
+ char *name;
+ uint64 count;
+} OpcodeInfo;
+
+/* clang-format off */
+#define HANDLE_OPCODE(op) \
+ { \
+ #op, 0 \
+ }
+DEFINE_GOTO_TABLE(OpcodeInfo, opcode_table);
+#undef HANDLE_OPCODE
+/* clang-format on */
+
+static void
+wasm_interp_dump_op_count()
+{
+ uint32 i;
+ uint64 total_count = 0;
+ for (i = 0; i < WASM_OP_IMPDEP; i++)
+ total_count += opcode_table[i].count;
+
+ printf("total opcode count: %ld\n", total_count);
+ for (i = 0; i < WASM_OP_IMPDEP; i++)
+ if (opcode_table[i].count > 0)
+ printf("\t\t%s count:\t\t%ld,\t\t%.2f%%\n", opcode_table[i].name,
+ opcode_table[i].count,
+ opcode_table[i].count * 100.0f / total_count);
+}
+#endif
+
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+
+/* #define HANDLE_OP(opcode) HANDLE_##opcode:printf(#opcode"\n"); */
+#if WASM_ENABLE_OPCODE_COUNTER != 0
+#define HANDLE_OP(opcode) HANDLE_##opcode : opcode_table[opcode].count++;
+#else
+#define HANDLE_OP(opcode) HANDLE_##opcode:
+#endif
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
+#define FETCH_OPCODE_AND_DISPATCH() \
+ do { \
+ const void *p_label_addr = *(void **)frame_ip; \
+ frame_ip += sizeof(void *); \
+ goto *p_label_addr; \
+ } while (0)
+#else
+#define FETCH_OPCODE_AND_DISPATCH() \
+ do { \
+ const void *p_label_addr = label_base + *(int16 *)frame_ip; \
+ frame_ip += sizeof(int16); \
+ goto *p_label_addr; \
+ } while (0)
+#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */
+#define HANDLE_OP_END() FETCH_OPCODE_AND_DISPATCH()
+
+#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
+
+#define HANDLE_OP(opcode) case opcode:
+#define HANDLE_OP_END() continue
+
+#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */
+
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+static void **global_handle_table;
+#endif
+
+static inline uint8 *
+get_global_addr(uint8 *global_data, WASMGlobalInstance *global)
+{
+#if WASM_ENABLE_MULTI_MODULE == 0
+ return global_data + global->data_offset;
+#else
+ return global->import_global_inst
+ ? global->import_module_inst->global_data
+ + global->import_global_inst->data_offset
+ : global_data + global->data_offset;
+#endif
+}
+
+static void
+wasm_interp_call_func_bytecode(WASMModuleInstance *module,
+ WASMExecEnv *exec_env,
+ WASMFunctionInstance *cur_func,
+ WASMInterpFrame *prev_frame)
+{
+#if WASM_ENABLE_SHARED_MEMORY != 0
+ WASMSharedMemNode *node =
+ wasm_module_get_shared_memory((WASMModuleCommon *)module->module);
+#endif
+ WASMMemoryInstance *memory = wasm_get_default_memory(module);
+#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
+ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
+ || WASM_ENABLE_BULK_MEMORY != 0
+ uint32 linear_mem_size = memory ? memory->memory_data_size : 0;
+#endif
+ WASMGlobalInstance *globals = module->e ? module->e->globals : NULL;
+ WASMGlobalInstance *global;
+ uint8 *global_data = module->global_data;
+ uint8 opcode_IMPDEP = WASM_OP_IMPDEP;
+ WASMInterpFrame *frame = NULL;
+ /* Points to this special opcode so as to jump to the
+ * call_method_from_entry. */
+ register uint8 *frame_ip = &opcode_IMPDEP; /* cache of frame->ip */
+ register uint32 *frame_lp = NULL; /* cache of frame->lp */
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ /* cache of label base addr */
+ register uint8 *label_base = &&HANDLE_WASM_OP_UNREACHABLE;
+#endif
+#endif
+ uint8 *frame_ip_end = frame_ip + 1;
+ uint32 cond, count, fidx, tidx, frame_size = 0;
+ uint32 all_cell_num = 0;
+ int16 addr1, addr2, addr_ret = 0;
+ int32 didx, val;
+ uint8 *maddr = NULL;
+ uint32 local_idx, local_offset, global_idx;
+ uint8 opcode, local_type, *global_addr;
+
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+#define HANDLE_OPCODE(op) &&HANDLE_##op
+ DEFINE_GOTO_TABLE(const void *, handle_table);
+#undef HANDLE_OPCODE
+ if (exec_env == NULL) {
+ global_handle_table = (void **)handle_table;
+ return;
+ }
+#endif
+
+#if WASM_ENABLE_LABELS_AS_VALUES == 0
+ while (frame_ip < frame_ip_end) {
+ opcode = *frame_ip++;
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ frame_ip++;
+#endif
+ switch (opcode) {
+#else
+ goto *handle_table[WASM_OP_IMPDEP];
+#endif
+ /* control instructions */
+ HANDLE_OP(WASM_OP_UNREACHABLE)
+ {
+ wasm_set_exception(module, "unreachable");
+ goto got_exception;
+ }
+
+ HANDLE_OP(WASM_OP_IF)
+ {
+ cond = (uint32)POP_I32();
+
+ if (cond == 0) {
+ uint8 *else_addr = (uint8 *)LOAD_PTR(frame_ip);
+ if (else_addr == NULL) {
+ frame_ip =
+ (uint8 *)LOAD_PTR(frame_ip + sizeof(uint8 *));
+ }
+ else {
+ frame_ip = else_addr;
+ }
+ }
+ else {
+ frame_ip += sizeof(uint8 *) * 2;
+ }
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_ELSE)
+ {
+ frame_ip = (uint8 *)LOAD_PTR(frame_ip);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_BR)
+ {
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+ recover_br_info:
+ RECOVER_BR_INFO();
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_BR_IF)
+ {
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+ cond = frame_lp[GET_OFFSET()];
+
+ if (cond)
+ goto recover_br_info;
+ else
+ SKIP_BR_INFO();
+
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_BR_TABLE)
+ {
+ uint32 arity, br_item_size;
+
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+ count = read_uint32(frame_ip);
+ didx = GET_OPERAND(uint32, I32, 0);
+ frame_ip += 2;
+
+ if (!(didx >= 0 && (uint32)didx < count))
+ didx = count;
+
+ /* all br items must have the same arity and item size,
+ so we only calculate the first item size */
+ arity = LOAD_U32_WITH_2U16S(frame_ip);
+ br_item_size = sizeof(uint32); /* arity */
+ if (arity) {
+ /* total cell num */
+ br_item_size += sizeof(uint32);
+ /* cells, src offsets and dst offsets */
+ br_item_size +=
+ (CELL_SIZE + sizeof(int16) + sizeof(uint16)) * arity;
+ }
+ /* target address */
+ br_item_size += sizeof(uint8 *);
+
+ frame_ip += br_item_size * didx;
+ goto recover_br_info;
+ }
+
+ HANDLE_OP(WASM_OP_RETURN)
+ {
+ uint32 ret_idx;
+ WASMType *func_type;
+ uint32 off, ret_offset;
+ uint8 *ret_types;
+ if (cur_func->is_import_func)
+ func_type = cur_func->u.func_import->func_type;
+ else
+ func_type = cur_func->u.func->func_type;
+
+ /* types of each return value */
+ ret_types = func_type->types + func_type->param_count;
+ ret_offset = prev_frame->ret_offset;
+
+ for (ret_idx = 0,
+ off = sizeof(int16) * (func_type->result_count - 1);
+ ret_idx < func_type->result_count;
+ ret_idx++, off -= sizeof(int16)) {
+ if (ret_types[ret_idx] == VALUE_TYPE_I64
+ || ret_types[ret_idx] == VALUE_TYPE_F64) {
+ PUT_I64_TO_ADDR(prev_frame->lp + ret_offset,
+ GET_OPERAND(uint64, I64, off));
+ ret_offset += 2;
+ }
+ else {
+ prev_frame->lp[ret_offset] =
+ GET_OPERAND(uint32, I32, off);
+ ret_offset++;
+ }
+ }
+ goto return_func;
+ }
+
+ HANDLE_OP(WASM_OP_CALL_INDIRECT)
+#if WASM_ENABLE_TAIL_CALL != 0
+ HANDLE_OP(WASM_OP_RETURN_CALL_INDIRECT)
+#endif
+ {
+ WASMType *cur_type, *cur_func_type;
+ WASMTableInstance *tbl_inst;
+ uint32 tbl_idx;
+
+#if WASM_ENABLE_TAIL_CALL != 0
+ GET_OPCODE();
+#endif
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+
+ tidx = read_uint32(frame_ip);
+ cur_type = module->module->types[tidx];
+
+ tbl_idx = read_uint32(frame_ip);
+ bh_assert(tbl_idx < module->table_count);
+
+ tbl_inst = wasm_get_table_inst(module, tbl_idx);
+
+ val = GET_OPERAND(uint32, I32, 0);
+ frame_ip += 2;
+
+ if ((uint32)val >= tbl_inst->cur_size) {
+ wasm_set_exception(module, "undefined element");
+ goto got_exception;
+ }
+
+ fidx = tbl_inst->elems[val];
+ if (fidx == NULL_REF) {
+ wasm_set_exception(module, "uninitialized element");
+ goto got_exception;
+ }
+
+ /*
+ * we might be using a table injected by host or
+ * another module. in that case, we don't validate
+ * the elem value while loading
+ */
+ if (fidx >= module->e->function_count) {
+ wasm_set_exception(module, "unknown function");
+ goto got_exception;
+ }
+
+ /* always call module own functions */
+ cur_func = module->e->functions + fidx;
+
+ if (cur_func->is_import_func)
+ cur_func_type = cur_func->u.func_import->func_type;
+ else
+ cur_func_type = cur_func->u.func->func_type;
+
+ if (cur_type != cur_func_type) {
+ wasm_set_exception(module, "indirect call type mismatch");
+ goto got_exception;
+ }
+
+#if WASM_ENABLE_TAIL_CALL != 0
+ if (opcode == WASM_OP_RETURN_CALL_INDIRECT)
+ goto call_func_from_return_call;
+#endif
+ goto call_func_from_interp;
+ }
+
+ /* parametric instructions */
+ HANDLE_OP(WASM_OP_SELECT)
+ {
+ cond = frame_lp[GET_OFFSET()];
+ addr1 = GET_OFFSET();
+ addr2 = GET_OFFSET();
+ addr_ret = GET_OFFSET();
+
+ if (!cond) {
+ if (addr_ret != addr1)
+ frame_lp[addr_ret] = frame_lp[addr1];
+ }
+ else {
+ if (addr_ret != addr2)
+ frame_lp[addr_ret] = frame_lp[addr2];
+ }
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_SELECT_64)
+ {
+ cond = frame_lp[GET_OFFSET()];
+ addr1 = GET_OFFSET();
+ addr2 = GET_OFFSET();
+ addr_ret = GET_OFFSET();
+
+ if (!cond) {
+ if (addr_ret != addr1)
+ PUT_I64_TO_ADDR(frame_lp + addr_ret,
+ GET_I64_FROM_ADDR(frame_lp + addr1));
+ }
+ else {
+ if (addr_ret != addr2)
+ PUT_I64_TO_ADDR(frame_lp + addr_ret,
+ GET_I64_FROM_ADDR(frame_lp + addr2));
+ }
+ HANDLE_OP_END();
+ }
+
+#if WASM_ENABLE_REF_TYPES != 0
+ HANDLE_OP(WASM_OP_TABLE_GET)
+ {
+ uint32 tbl_idx, elem_idx;
+ WASMTableInstance *tbl_inst;
+
+ tbl_idx = read_uint32(frame_ip);
+ bh_assert(tbl_idx < module->table_count);
+
+ tbl_inst = wasm_get_table_inst(module, tbl_idx);
+
+ elem_idx = POP_I32();
+ if (elem_idx >= tbl_inst->cur_size) {
+ wasm_set_exception(module, "out of bounds table access");
+ goto got_exception;
+ }
+
+ PUSH_I32(tbl_inst->elems[elem_idx]);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_TABLE_SET)
+ {
+ uint32 tbl_idx, elem_idx, elem_val;
+ WASMTableInstance *tbl_inst;
+
+ tbl_idx = read_uint32(frame_ip);
+ bh_assert(tbl_idx < module->table_count);
+
+ tbl_inst = wasm_get_table_inst(module, tbl_idx);
+
+ elem_val = POP_I32();
+ elem_idx = POP_I32();
+ if (elem_idx >= tbl_inst->cur_size) {
+ wasm_set_exception(module, "out of bounds table access");
+ goto got_exception;
+ }
+
+ tbl_inst->elems[elem_idx] = elem_val;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_REF_NULL)
+ {
+ PUSH_I32(NULL_REF);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_REF_IS_NULL)
+ {
+ uint32 ref_val;
+ ref_val = POP_I32();
+ PUSH_I32(ref_val == NULL_REF ? 1 : 0);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_REF_FUNC)
+ {
+ uint32 func_idx = read_uint32(frame_ip);
+ PUSH_I32(func_idx);
+ HANDLE_OP_END();
+ }
+#endif /* WASM_ENABLE_REF_TYPES */
+
+ /* variable instructions */
+ HANDLE_OP(EXT_OP_SET_LOCAL_FAST)
+ HANDLE_OP(EXT_OP_TEE_LOCAL_FAST)
+ {
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
+ local_offset = *frame_ip++;
+#else
+ /* clang-format off */
+ local_offset = *frame_ip;
+ frame_ip += 2;
+ /* clang-format on */
+#endif
+ *(uint32 *)(frame_lp + local_offset) =
+ GET_OPERAND(uint32, I32, 0);
+ frame_ip += 2;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(EXT_OP_SET_LOCAL_FAST_I64)
+ HANDLE_OP(EXT_OP_TEE_LOCAL_FAST_I64)
+ {
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
+ local_offset = *frame_ip++;
+#else
+ /* clang-format off */
+ local_offset = *frame_ip;
+ frame_ip += 2;
+ /* clang-format on */
+#endif
+ PUT_I64_TO_ADDR((uint32 *)(frame_lp + local_offset),
+ GET_OPERAND(uint64, I64, 0));
+ frame_ip += 2;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_GET_GLOBAL)
+ {
+ global_idx = read_uint32(frame_ip);
+ bh_assert(global_idx < module->e->global_count);
+ global = globals + global_idx;
+ global_addr = get_global_addr(global_data, global);
+ addr_ret = GET_OFFSET();
+ frame_lp[addr_ret] = *(uint32 *)global_addr;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_GET_GLOBAL_64)
+ {
+ global_idx = read_uint32(frame_ip);
+ bh_assert(global_idx < module->e->global_count);
+ global = globals + global_idx;
+ global_addr = get_global_addr(global_data, global);
+ addr_ret = GET_OFFSET();
+ PUT_I64_TO_ADDR(frame_lp + addr_ret,
+ GET_I64_FROM_ADDR((uint32 *)global_addr));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_SET_GLOBAL)
+ {
+ global_idx = read_uint32(frame_ip);
+ bh_assert(global_idx < module->e->global_count);
+ global = globals + global_idx;
+ global_addr = get_global_addr(global_data, global);
+ addr1 = GET_OFFSET();
+ *(int32 *)global_addr = frame_lp[addr1];
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_SET_GLOBAL_AUX_STACK)
+ {
+ uint32 aux_stack_top;
+
+ global_idx = read_uint32(frame_ip);
+ bh_assert(global_idx < module->e->global_count);
+ global = globals + global_idx;
+ global_addr = get_global_addr(global_data, global);
+ aux_stack_top = frame_lp[GET_OFFSET()];
+ if (aux_stack_top <= exec_env->aux_stack_boundary.boundary) {
+ wasm_set_exception(module, "wasm auxiliary stack overflow");
+ goto got_exception;
+ }
+ if (aux_stack_top > exec_env->aux_stack_bottom.bottom) {
+ wasm_set_exception(module,
+ "wasm auxiliary stack underflow");
+ goto got_exception;
+ }
+ *(int32 *)global_addr = aux_stack_top;
+#if WASM_ENABLE_MEMORY_PROFILING != 0
+ if (module->module->aux_stack_top_global_index != (uint32)-1) {
+ uint32 aux_stack_used = module->module->aux_stack_bottom
+ - *(uint32 *)global_addr;
+ if (aux_stack_used > module->e->max_aux_stack_used)
+ module->e->max_aux_stack_used = aux_stack_used;
+ }
+#endif
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_SET_GLOBAL_64)
+ {
+ global_idx = read_uint32(frame_ip);
+ bh_assert(global_idx < module->e->global_count);
+ global = globals + global_idx;
+ global_addr = get_global_addr(global_data, global);
+ addr1 = GET_OFFSET();
+ PUT_I64_TO_ADDR((uint32 *)global_addr,
+ GET_I64_FROM_ADDR(frame_lp + addr1));
+ HANDLE_OP_END();
+ }
+
+ /* memory load instructions */
+ HANDLE_OP(WASM_OP_I32_LOAD)
+ {
+ uint32 offset, addr;
+ offset = read_uint32(frame_ip);
+ addr = GET_OPERAND(uint32, I32, 0);
+ frame_ip += 2;
+ addr_ret = GET_OFFSET();
+ CHECK_MEMORY_OVERFLOW(4);
+ frame_lp[addr_ret] = LOAD_I32(maddr);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LOAD)
+ {
+ uint32 offset, addr;
+ offset = read_uint32(frame_ip);
+ addr = GET_OPERAND(uint32, I32, 0);
+ frame_ip += 2;
+ addr_ret = GET_OFFSET();
+ CHECK_MEMORY_OVERFLOW(8);
+ PUT_I64_TO_ADDR(frame_lp + addr_ret, LOAD_I64(maddr));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_LOAD8_S)
+ {
+ uint32 offset, addr;
+ offset = read_uint32(frame_ip);
+ addr = GET_OPERAND(uint32, I32, 0);
+ frame_ip += 2;
+ addr_ret = GET_OFFSET();
+ CHECK_MEMORY_OVERFLOW(1);
+ frame_lp[addr_ret] = sign_ext_8_32(*(int8 *)maddr);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_LOAD8_U)
+ {
+ uint32 offset, addr;
+ offset = read_uint32(frame_ip);
+ addr = GET_OPERAND(uint32, I32, 0);
+ frame_ip += 2;
+ addr_ret = GET_OFFSET();
+ CHECK_MEMORY_OVERFLOW(1);
+ frame_lp[addr_ret] = (uint32)(*(uint8 *)maddr);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_LOAD16_S)
+ {
+ uint32 offset, addr;
+ offset = read_uint32(frame_ip);
+ addr = GET_OPERAND(uint32, I32, 0);
+ frame_ip += 2;
+ addr_ret = GET_OFFSET();
+ CHECK_MEMORY_OVERFLOW(2);
+ frame_lp[addr_ret] = sign_ext_16_32(LOAD_I16(maddr));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_LOAD16_U)
+ {
+ uint32 offset, addr;
+ offset = read_uint32(frame_ip);
+ addr = GET_OPERAND(uint32, I32, 0);
+ frame_ip += 2;
+ addr_ret = GET_OFFSET();
+ CHECK_MEMORY_OVERFLOW(2);
+ frame_lp[addr_ret] = (uint32)(LOAD_U16(maddr));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LOAD8_S)
+ {
+ uint32 offset, addr;
+ offset = read_uint32(frame_ip);
+ addr = GET_OPERAND(uint32, I32, 0);
+ frame_ip += 2;
+ addr_ret = GET_OFFSET();
+ CHECK_MEMORY_OVERFLOW(1);
+ PUT_I64_TO_ADDR(frame_lp + addr_ret,
+ sign_ext_8_64(*(int8 *)maddr));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LOAD8_U)
+ {
+ uint32 offset, addr;
+ offset = read_uint32(frame_ip);
+ addr = GET_OPERAND(uint32, I32, 0);
+ frame_ip += 2;
+ addr_ret = GET_OFFSET();
+ CHECK_MEMORY_OVERFLOW(1);
+ PUT_I64_TO_ADDR(frame_lp + addr_ret, (uint64)(*(uint8 *)maddr));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LOAD16_S)
+ {
+ uint32 offset, addr;
+ offset = read_uint32(frame_ip);
+ addr = GET_OPERAND(uint32, I32, 0);
+ frame_ip += 2;
+ addr_ret = GET_OFFSET();
+ CHECK_MEMORY_OVERFLOW(2);
+ PUT_I64_TO_ADDR(frame_lp + addr_ret,
+ sign_ext_16_64(LOAD_I16(maddr)));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LOAD16_U)
+ {
+ uint32 offset, addr;
+ offset = read_uint32(frame_ip);
+ addr = GET_OPERAND(uint32, I32, 0);
+ frame_ip += 2;
+ addr_ret = GET_OFFSET();
+ CHECK_MEMORY_OVERFLOW(2);
+ PUT_I64_TO_ADDR(frame_lp + addr_ret, (uint64)(LOAD_U16(maddr)));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LOAD32_S)
+ {
+ uint32 offset, addr;
+ offset = read_uint32(frame_ip);
+ addr = GET_OPERAND(uint32, I32, 0);
+ frame_ip += 2;
+ addr_ret = GET_OFFSET();
+ CHECK_MEMORY_OVERFLOW(4);
+ PUT_I64_TO_ADDR(frame_lp + addr_ret,
+ sign_ext_32_64(LOAD_I32(maddr)));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LOAD32_U)
+ {
+ uint32 offset, addr;
+ offset = read_uint32(frame_ip);
+ addr = GET_OPERAND(uint32, I32, 0);
+ frame_ip += 2;
+ addr_ret = GET_OFFSET();
+ CHECK_MEMORY_OVERFLOW(4);
+ PUT_I64_TO_ADDR(frame_lp + addr_ret, (uint64)(LOAD_U32(maddr)));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_STORE)
+ {
+ uint32 offset, addr;
+ uint32 sval;
+ offset = read_uint32(frame_ip);
+ sval = GET_OPERAND(uint32, I32, 0);
+ addr = GET_OPERAND(uint32, I32, 2);
+ frame_ip += 4;
+ CHECK_MEMORY_OVERFLOW(4);
+ STORE_U32(maddr, sval);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_STORE8)
+ {
+ uint32 offset, addr;
+ uint32 sval;
+ offset = read_uint32(frame_ip);
+ sval = GET_OPERAND(uint32, I32, 0);
+ addr = GET_OPERAND(uint32, I32, 2);
+ frame_ip += 4;
+ CHECK_MEMORY_OVERFLOW(1);
+ *(uint8 *)maddr = (uint8)sval;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_STORE16)
+ {
+ uint32 offset, addr;
+ uint32 sval;
+ offset = read_uint32(frame_ip);
+ sval = GET_OPERAND(uint32, I32, 0);
+ addr = GET_OPERAND(uint32, I32, 2);
+ frame_ip += 4;
+ CHECK_MEMORY_OVERFLOW(2);
+ STORE_U16(maddr, (uint16)sval);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_STORE)
+ {
+ uint32 offset, addr;
+ uint64 sval;
+ offset = read_uint32(frame_ip);
+ sval = GET_OPERAND(uint64, I64, 0);
+ addr = GET_OPERAND(uint32, I32, 2);
+ frame_ip += 4;
+ CHECK_MEMORY_OVERFLOW(8);
+ STORE_I64(maddr, sval);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_STORE8)
+ {
+ uint32 offset, addr;
+ uint64 sval;
+ offset = read_uint32(frame_ip);
+ sval = GET_OPERAND(uint64, I64, 0);
+ addr = GET_OPERAND(uint32, I32, 2);
+ frame_ip += 4;
+ CHECK_MEMORY_OVERFLOW(1);
+ *(uint8 *)maddr = (uint8)sval;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_STORE16)
+ {
+ uint32 offset, addr;
+ uint64 sval;
+ offset = read_uint32(frame_ip);
+ sval = GET_OPERAND(uint64, I64, 0);
+ addr = GET_OPERAND(uint32, I32, 2);
+ frame_ip += 4;
+ CHECK_MEMORY_OVERFLOW(2);
+ STORE_U16(maddr, (uint16)sval);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_STORE32)
+ {
+ uint32 offset, addr;
+ uint64 sval;
+ offset = read_uint32(frame_ip);
+ sval = GET_OPERAND(uint64, I64, 0);
+ addr = GET_OPERAND(uint32, I32, 2);
+ frame_ip += 4;
+ CHECK_MEMORY_OVERFLOW(4);
+ STORE_U32(maddr, (uint32)sval);
+ HANDLE_OP_END();
+ }
+
+ /* memory size and memory grow instructions */
+ HANDLE_OP(WASM_OP_MEMORY_SIZE)
+ {
+ uint32 reserved;
+ addr_ret = GET_OFFSET();
+ frame_lp[addr_ret] = memory->cur_page_count;
+ (void)reserved;
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_MEMORY_GROW)
+ {
+ uint32 reserved, delta,
+ prev_page_count = memory->cur_page_count;
+
+ addr1 = GET_OFFSET();
+ addr_ret = GET_OFFSET();
+ delta = (uint32)frame_lp[addr1];
+
+ if (!wasm_enlarge_memory(module, delta)) {
+ /* failed to memory.grow, return -1 */
+ frame_lp[addr_ret] = -1;
+ }
+ else {
+ /* success, return previous page count */
+ frame_lp[addr_ret] = prev_page_count;
+ /* update memory size, no need to update memory ptr as
+ it isn't changed in wasm_enlarge_memory */
+#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
+ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
+ || WASM_ENABLE_BULK_MEMORY != 0
+ linear_mem_size = memory->memory_data_size;
+#endif
+ }
+
+ (void)reserved;
+ HANDLE_OP_END();
+ }
+
+ /* constant instructions */
+ HANDLE_OP(WASM_OP_F64_CONST)
+ HANDLE_OP(WASM_OP_I64_CONST)
+ {
+ uint8 *orig_ip = frame_ip;
+
+ frame_ip += sizeof(uint64);
+ addr_ret = GET_OFFSET();
+
+ bh_memcpy_s(frame_lp + addr_ret, sizeof(uint64), orig_ip,
+ sizeof(uint64));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_CONST)
+ HANDLE_OP(WASM_OP_I32_CONST)
+ {
+ uint8 *orig_ip = frame_ip;
+
+ frame_ip += sizeof(uint32);
+ addr_ret = GET_OFFSET();
+
+ bh_memcpy_s(frame_lp + addr_ret, sizeof(uint32), orig_ip,
+ sizeof(uint32));
+ HANDLE_OP_END();
+ }
+
+ /* comparison instructions of i32 */
+ HANDLE_OP(WASM_OP_I32_EQZ)
+ {
+ DEF_OP_EQZ(int32, I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_EQ)
+ {
+ DEF_OP_CMP(uint32, I32, ==);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_NE)
+ {
+ DEF_OP_CMP(uint32, I32, !=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_LT_S)
+ {
+ DEF_OP_CMP(int32, I32, <);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_LT_U)
+ {
+ DEF_OP_CMP(uint32, I32, <);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_GT_S)
+ {
+ DEF_OP_CMP(int32, I32, >);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_GT_U)
+ {
+ DEF_OP_CMP(uint32, I32, >);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_LE_S)
+ {
+ DEF_OP_CMP(int32, I32, <=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_LE_U)
+ {
+ DEF_OP_CMP(uint32, I32, <=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_GE_S)
+ {
+ DEF_OP_CMP(int32, I32, >=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_GE_U)
+ {
+ DEF_OP_CMP(uint32, I32, >=);
+ HANDLE_OP_END();
+ }
+
+ /* comparison instructions of i64 */
+ HANDLE_OP(WASM_OP_I64_EQZ)
+ {
+ DEF_OP_EQZ(int64, I64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_EQ)
+ {
+ DEF_OP_CMP(uint64, I64, ==);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_NE)
+ {
+ DEF_OP_CMP(uint64, I64, !=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LT_S)
+ {
+ DEF_OP_CMP(int64, I64, <);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LT_U)
+ {
+ DEF_OP_CMP(uint64, I64, <);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_GT_S)
+ {
+ DEF_OP_CMP(int64, I64, >);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_GT_U)
+ {
+ DEF_OP_CMP(uint64, I64, >);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LE_S)
+ {
+ DEF_OP_CMP(int64, I64, <=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_LE_U)
+ {
+ DEF_OP_CMP(uint64, I64, <=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_GE_S)
+ {
+ DEF_OP_CMP(int64, I64, >=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_GE_U)
+ {
+ DEF_OP_CMP(uint64, I64, >=);
+ HANDLE_OP_END();
+ }
+
+ /* comparison instructions of f32 */
+ HANDLE_OP(WASM_OP_F32_EQ)
+ {
+ DEF_OP_CMP(float32, F32, ==);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_NE)
+ {
+ DEF_OP_CMP(float32, F32, !=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_LT)
+ {
+ DEF_OP_CMP(float32, F32, <);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_GT)
+ {
+ DEF_OP_CMP(float32, F32, >);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_LE)
+ {
+ DEF_OP_CMP(float32, F32, <=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_GE)
+ {
+ DEF_OP_CMP(float32, F32, >=);
+ HANDLE_OP_END();
+ }
+
+ /* comparison instructions of f64 */
+ HANDLE_OP(WASM_OP_F64_EQ)
+ {
+ DEF_OP_CMP(float64, F64, ==);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_NE)
+ {
+ DEF_OP_CMP(float64, F64, !=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_LT)
+ {
+ DEF_OP_CMP(float64, F64, <);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_GT)
+ {
+ DEF_OP_CMP(float64, F64, >);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_LE)
+ {
+ DEF_OP_CMP(float64, F64, <=);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_GE)
+ {
+ DEF_OP_CMP(float64, F64, >=);
+ HANDLE_OP_END();
+ }
+
+ /* numberic instructions of i32 */
+ HANDLE_OP(WASM_OP_I32_CLZ)
+ {
+ DEF_OP_BIT_COUNT(uint32, I32, clz32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_CTZ)
+ {
+ DEF_OP_BIT_COUNT(uint32, I32, ctz32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_POPCNT)
+ {
+ DEF_OP_BIT_COUNT(uint32, I32, popcount32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_ADD)
+ {
+ DEF_OP_NUMERIC(uint32, uint32, I32, +);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_SUB)
+ {
+ DEF_OP_NUMERIC(uint32, uint32, I32, -);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_MUL)
+ {
+ DEF_OP_NUMERIC(uint32, uint32, I32, *);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_DIV_S)
+ {
+ int32 a, b;
+
+ b = frame_lp[GET_OFFSET()];
+ a = frame_lp[GET_OFFSET()];
+ addr_ret = GET_OFFSET();
+ if (a == (int32)0x80000000 && b == -1) {
+ wasm_set_exception(module, "integer overflow");
+ goto got_exception;
+ }
+ if (b == 0) {
+ wasm_set_exception(module, "integer divide by zero");
+ goto got_exception;
+ }
+ frame_lp[addr_ret] = (a / b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_DIV_U)
+ {
+ uint32 a, b;
+
+ addr1 = GET_OFFSET();
+ addr2 = GET_OFFSET();
+ addr_ret = GET_OFFSET();
+
+ b = (uint32)frame_lp[addr1];
+ a = (uint32)frame_lp[addr2];
+ if (b == 0) {
+ wasm_set_exception(module, "integer divide by zero");
+ goto got_exception;
+ }
+ frame_lp[addr_ret] = (a / b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_REM_S)
+ {
+ int32 a, b;
+
+ addr1 = GET_OFFSET();
+ addr2 = GET_OFFSET();
+ addr_ret = GET_OFFSET();
+
+ b = frame_lp[addr1];
+ a = frame_lp[addr2];
+ if (a == (int32)0x80000000 && b == -1) {
+ frame_lp[addr_ret] = 0;
+ HANDLE_OP_END();
+ }
+ if (b == 0) {
+ wasm_set_exception(module, "integer divide by zero");
+ goto got_exception;
+ }
+ frame_lp[addr_ret] = (a % b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_REM_U)
+ {
+ uint32 a, b;
+
+ addr1 = GET_OFFSET();
+ addr2 = GET_OFFSET();
+ addr_ret = GET_OFFSET();
+
+ b = (uint32)frame_lp[addr1];
+ a = (uint32)frame_lp[addr2];
+ if (b == 0) {
+ wasm_set_exception(module, "integer divide by zero");
+ goto got_exception;
+ }
+ frame_lp[addr_ret] = (a % b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_AND)
+ {
+ DEF_OP_NUMERIC(uint32, uint32, I32, &);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_OR)
+ {
+ DEF_OP_NUMERIC(uint32, uint32, I32, |);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_XOR)
+ {
+ DEF_OP_NUMERIC(uint32, uint32, I32, ^);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_SHL)
+ {
+ DEF_OP_NUMERIC2(uint32, uint32, I32, <<);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_SHR_S)
+ {
+ DEF_OP_NUMERIC2(int32, uint32, I32, >>);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_SHR_U)
+ {
+ DEF_OP_NUMERIC2(uint32, uint32, I32, >>);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_ROTL)
+ {
+ uint32 a, b;
+
+ b = (uint32)frame_lp[GET_OFFSET()];
+ a = (uint32)frame_lp[GET_OFFSET()];
+ frame_lp[GET_OFFSET()] = rotl32(a, b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_ROTR)
+ {
+ uint32 a, b;
+
+ b = (uint32)frame_lp[GET_OFFSET()];
+ a = (uint32)frame_lp[GET_OFFSET()];
+ frame_lp[GET_OFFSET()] = rotr32(a, b);
+ HANDLE_OP_END();
+ }
+
+ /* numberic instructions of i64 */
+ HANDLE_OP(WASM_OP_I64_CLZ)
+ {
+ DEF_OP_BIT_COUNT(uint64, I64, clz64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_CTZ)
+ {
+ DEF_OP_BIT_COUNT(uint64, I64, ctz64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_POPCNT)
+ {
+ DEF_OP_BIT_COUNT(uint64, I64, popcount64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_ADD)
+ {
+ DEF_OP_NUMERIC_64(uint64, uint64, I64, +);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_SUB)
+ {
+ DEF_OP_NUMERIC_64(uint64, uint64, I64, -);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_MUL)
+ {
+ DEF_OP_NUMERIC_64(uint64, uint64, I64, *);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_DIV_S)
+ {
+ int64 a, b;
+
+ b = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET());
+ a = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET());
+ if (a == (int64)0x8000000000000000LL && b == -1) {
+ wasm_set_exception(module, "integer overflow");
+ goto got_exception;
+ }
+ if (b == 0) {
+ wasm_set_exception(module, "integer divide by zero");
+ goto got_exception;
+ }
+ PUT_I64_TO_ADDR(frame_lp + GET_OFFSET(), a / b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_DIV_U)
+ {
+ uint64 a, b;
+
+ b = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET());
+ a = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET());
+ if (b == 0) {
+ wasm_set_exception(module, "integer divide by zero");
+ goto got_exception;
+ }
+ PUT_I64_TO_ADDR(frame_lp + GET_OFFSET(), a / b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_REM_S)
+ {
+ int64 a, b;
+
+ b = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET());
+ a = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET());
+ if (a == (int64)0x8000000000000000LL && b == -1) {
+ *(int64 *)(frame_lp + GET_OFFSET()) = 0;
+ HANDLE_OP_END();
+ }
+ if (b == 0) {
+ wasm_set_exception(module, "integer divide by zero");
+ goto got_exception;
+ }
+ PUT_I64_TO_ADDR(frame_lp + GET_OFFSET(), a % b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_REM_U)
+ {
+ uint64 a, b;
+
+ b = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET());
+ a = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET());
+ if (b == 0) {
+ wasm_set_exception(module, "integer divide by zero");
+ goto got_exception;
+ }
+ PUT_I64_TO_ADDR(frame_lp + GET_OFFSET(), a % b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_AND)
+ {
+ DEF_OP_NUMERIC_64(uint64, uint64, I64, &);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_OR)
+ {
+ DEF_OP_NUMERIC_64(uint64, uint64, I64, |);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_XOR)
+ {
+ DEF_OP_NUMERIC_64(uint64, uint64, I64, ^);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_SHL)
+ {
+ DEF_OP_NUMERIC2_64(uint64, uint64, I64, <<);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_SHR_S)
+ {
+ DEF_OP_NUMERIC2_64(int64, uint64, I64, >>);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_SHR_U)
+ {
+ DEF_OP_NUMERIC2_64(uint64, uint64, I64, >>);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_ROTL)
+ {
+ uint64 a, b;
+
+ b = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET());
+ a = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET());
+ PUT_I64_TO_ADDR(frame_lp + GET_OFFSET(), rotl64(a, b));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_ROTR)
+ {
+ uint64 a, b;
+
+ b = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET());
+ a = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET());
+ PUT_I64_TO_ADDR(frame_lp + GET_OFFSET(), rotr64(a, b));
+ HANDLE_OP_END();
+ }
+
+ /* numberic instructions of f32 */
+ HANDLE_OP(WASM_OP_F32_ABS)
+ {
+ DEF_OP_MATH(float32, F32, fabsf);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_NEG)
+ {
+ uint32 u32 = frame_lp[GET_OFFSET()];
+ uint32 sign_bit = u32 & ((uint32)1 << 31);
+ addr_ret = GET_OFFSET();
+ if (sign_bit)
+ frame_lp[addr_ret] = u32 & ~((uint32)1 << 31);
+ else
+ frame_lp[addr_ret] = u32 | ((uint32)1 << 31);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_CEIL)
+ {
+ DEF_OP_MATH(float32, F32, ceilf);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_FLOOR)
+ {
+ DEF_OP_MATH(float32, F32, floorf);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_TRUNC)
+ {
+ DEF_OP_MATH(float32, F32, truncf);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_NEAREST)
+ {
+ DEF_OP_MATH(float32, F32, rintf);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_SQRT)
+ {
+ DEF_OP_MATH(float32, F32, sqrtf);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_ADD)
+ {
+ DEF_OP_NUMERIC(float32, float32, F32, +);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_SUB)
+ {
+ DEF_OP_NUMERIC(float32, float32, F32, -);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_MUL)
+ {
+ DEF_OP_NUMERIC(float32, float32, F32, *);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_DIV)
+ {
+ DEF_OP_NUMERIC(float32, float32, F32, /);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_MIN)
+ {
+ float32 a, b;
+
+ b = *(float32 *)(frame_lp + GET_OFFSET());
+ a = *(float32 *)(frame_lp + GET_OFFSET());
+
+ *(float32 *)(frame_lp + GET_OFFSET()) = f32_min(a, b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_MAX)
+ {
+ float32 a, b;
+
+ b = *(float32 *)(frame_lp + GET_OFFSET());
+ a = *(float32 *)(frame_lp + GET_OFFSET());
+
+ *(float32 *)(frame_lp + GET_OFFSET()) = f32_max(a, b);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_COPYSIGN)
+ {
+ float32 a, b;
+
+ b = *(float32 *)(frame_lp + GET_OFFSET());
+ a = *(float32 *)(frame_lp + GET_OFFSET());
+ *(float32 *)(frame_lp + GET_OFFSET()) = local_copysignf(a, b);
+ HANDLE_OP_END();
+ }
+
+ /* numberic instructions of f64 */
+ HANDLE_OP(WASM_OP_F64_ABS)
+ {
+ DEF_OP_MATH(float64, F64, fabs);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_NEG)
+ {
+ uint64 u64 = GET_I64_FROM_ADDR(frame_lp + GET_OFFSET());
+ uint64 sign_bit = u64 & (((uint64)1) << 63);
+ if (sign_bit)
+ PUT_I64_TO_ADDR(frame_lp + GET_OFFSET(),
+ (u64 & ~(((uint64)1) << 63)));
+ else
+ PUT_I64_TO_ADDR(frame_lp + GET_OFFSET(),
+ (u64 | (((uint64)1) << 63)));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_CEIL)
+ {
+ DEF_OP_MATH(float64, F64, ceil);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_FLOOR)
+ {
+ DEF_OP_MATH(float64, F64, floor);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_TRUNC)
+ {
+ DEF_OP_MATH(float64, F64, trunc);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_NEAREST)
+ {
+ DEF_OP_MATH(float64, F64, rint);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_SQRT)
+ {
+ DEF_OP_MATH(float64, F64, sqrt);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_ADD)
+ {
+ DEF_OP_NUMERIC_64(float64, float64, F64, +);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_SUB)
+ {
+ DEF_OP_NUMERIC_64(float64, float64, F64, -);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_MUL)
+ {
+ DEF_OP_NUMERIC_64(float64, float64, F64, *);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_DIV)
+ {
+ DEF_OP_NUMERIC_64(float64, float64, F64, /);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_MIN)
+ {
+ float64 a, b;
+
+ b = POP_F64();
+ a = POP_F64();
+
+ PUSH_F64(f64_min(a, b));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_MAX)
+ {
+ float64 a, b;
+
+ b = POP_F64();
+ a = POP_F64();
+
+ PUSH_F64(f64_max(a, b));
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_COPYSIGN)
+ {
+ float64 a, b;
+
+ b = POP_F64();
+ a = POP_F64();
+ PUSH_F64(local_copysign(a, b));
+ HANDLE_OP_END();
+ }
+
+ /* conversions of i32 */
+ HANDLE_OP(WASM_OP_I32_WRAP_I64)
+ {
+ int32 value = (int32)(POP_I64() & 0xFFFFFFFFLL);
+ PUSH_I32(value);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_TRUNC_S_F32)
+ {
+ /* We don't use INT32_MIN/INT32_MAX/UINT32_MIN/UINT32_MAX,
+ since float/double values of ieee754 cannot precisely
+ represent all int32/uint32/int64/uint64 values, e.g.:
+ UINT32_MAX is 4294967295, but (float32)4294967295 is
+ 4294967296.0f, but not 4294967295.0f. */
+ DEF_OP_TRUNC_F32(-2147483904.0f, 2147483648.0f, true, true);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_TRUNC_U_F32)
+ {
+ DEF_OP_TRUNC_F32(-1.0f, 4294967296.0f, true, false);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_TRUNC_S_F64)
+ {
+ DEF_OP_TRUNC_F64(-2147483649.0, 2147483648.0, true, true);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_TRUNC_U_F64)
+ {
+ DEF_OP_TRUNC_F64(-1.0, 4294967296.0, true, false);
+ HANDLE_OP_END();
+ }
+
+ /* conversions of i64 */
+ HANDLE_OP(WASM_OP_I64_EXTEND_S_I32)
+ {
+ DEF_OP_CONVERT(int64, I64, int32, I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_EXTEND_U_I32)
+ {
+ DEF_OP_CONVERT(int64, I64, uint32, I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_TRUNC_S_F32)
+ {
+ DEF_OP_TRUNC_F32(-9223373136366403584.0f,
+ 9223372036854775808.0f, false, true);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_TRUNC_U_F32)
+ {
+ DEF_OP_TRUNC_F32(-1.0f, 18446744073709551616.0f, false, false);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_TRUNC_S_F64)
+ {
+ DEF_OP_TRUNC_F64(-9223372036854777856.0, 9223372036854775808.0,
+ false, true);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_TRUNC_U_F64)
+ {
+ DEF_OP_TRUNC_F64(-1.0, 18446744073709551616.0, false, false);
+ HANDLE_OP_END();
+ }
+
+ /* conversions of f32 */
+ HANDLE_OP(WASM_OP_F32_CONVERT_S_I32)
+ {
+ DEF_OP_CONVERT(float32, F32, int32, I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_CONVERT_U_I32)
+ {
+ DEF_OP_CONVERT(float32, F32, uint32, I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_CONVERT_S_I64)
+ {
+ DEF_OP_CONVERT(float32, F32, int64, I64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_CONVERT_U_I64)
+ {
+ DEF_OP_CONVERT(float32, F32, uint64, I64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F32_DEMOTE_F64)
+ {
+ DEF_OP_CONVERT(float32, F32, float64, F64);
+ HANDLE_OP_END();
+ }
+
+ /* conversions of f64 */
+ HANDLE_OP(WASM_OP_F64_CONVERT_S_I32)
+ {
+ DEF_OP_CONVERT(float64, F64, int32, I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_CONVERT_U_I32)
+ {
+ DEF_OP_CONVERT(float64, F64, uint32, I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_CONVERT_S_I64)
+ {
+ DEF_OP_CONVERT(float64, F64, int64, I64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_CONVERT_U_I64)
+ {
+ DEF_OP_CONVERT(float64, F64, uint64, I64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_F64_PROMOTE_F32)
+ {
+ DEF_OP_CONVERT(float64, F64, float32, F32);
+ HANDLE_OP_END();
+ }
+
+ /* reinterpretations */
+ HANDLE_OP(WASM_OP_I32_REINTERPRET_F32)
+ HANDLE_OP(WASM_OP_F32_REINTERPRET_I32)
+ {
+ DEF_OP_REINTERPRET(uint32, I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_REINTERPRET_F64)
+ HANDLE_OP(WASM_OP_F64_REINTERPRET_I64)
+ {
+ DEF_OP_REINTERPRET(int64, I64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(EXT_OP_COPY_STACK_TOP)
+ {
+ addr1 = GET_OFFSET();
+ addr2 = GET_OFFSET();
+ frame_lp[addr2] = frame_lp[addr1];
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(EXT_OP_COPY_STACK_TOP_I64)
+ {
+ addr1 = GET_OFFSET();
+ addr2 = GET_OFFSET();
+ frame_lp[addr2] = frame_lp[addr1];
+ frame_lp[addr2 + 1] = frame_lp[addr1 + 1];
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(EXT_OP_COPY_STACK_VALUES)
+ {
+ uint32 values_count, total_cell;
+ uint8 *cells;
+ int16 *src_offsets = NULL;
+ uint16 *dst_offsets = NULL;
+
+ /* read values_count */
+ values_count = read_uint32(frame_ip);
+ /* read total cell num */
+ total_cell = read_uint32(frame_ip);
+ /* cells */
+ cells = (uint8 *)frame_ip;
+ frame_ip += values_count * CELL_SIZE;
+ /* src offsets */
+ src_offsets = (int16 *)frame_ip;
+ frame_ip += values_count * sizeof(int16);
+ /* dst offsets */
+ dst_offsets = (uint16 *)frame_ip;
+ frame_ip += values_count * sizeof(uint16);
+
+ if (!copy_stack_values(module, frame_lp, values_count,
+ total_cell, cells, src_offsets,
+ dst_offsets))
+ goto got_exception;
+
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_SET_LOCAL)
+ HANDLE_OP(WASM_OP_TEE_LOCAL)
+ {
+ GET_LOCAL_INDEX_TYPE_AND_OFFSET();
+ addr1 = GET_OFFSET();
+
+ if (local_type == VALUE_TYPE_I32
+ || local_type == VALUE_TYPE_F32) {
+ *(int32 *)(frame_lp + local_offset) = frame_lp[addr1];
+ }
+ else if (local_type == VALUE_TYPE_I64
+ || local_type == VALUE_TYPE_F64) {
+ PUT_I64_TO_ADDR((uint32 *)(frame_lp + local_offset),
+ GET_I64_FROM_ADDR(frame_lp + addr1));
+ }
+ else {
+ wasm_set_exception(module, "invalid local type");
+ goto got_exception;
+ }
+
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_EXTEND8_S)
+ {
+ DEF_OP_CONVERT(int32, I32, int8, I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I32_EXTEND16_S)
+ {
+ DEF_OP_CONVERT(int32, I32, int16, I32);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_EXTEND8_S)
+ {
+ DEF_OP_CONVERT(int64, I64, int8, I64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_EXTEND16_S)
+ {
+ DEF_OP_CONVERT(int64, I64, int16, I64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_I64_EXTEND32_S)
+ {
+ DEF_OP_CONVERT(int64, I64, int32, I64);
+ HANDLE_OP_END();
+ }
+
+ HANDLE_OP(WASM_OP_MISC_PREFIX)
+ {
+ GET_OPCODE();
+ switch (opcode) {
+ case WASM_OP_I32_TRUNC_SAT_S_F32:
+ DEF_OP_TRUNC_SAT_F32(-2147483904.0f, 2147483648.0f,
+ true, true);
+ break;
+ case WASM_OP_I32_TRUNC_SAT_U_F32:
+ DEF_OP_TRUNC_SAT_F32(-1.0f, 4294967296.0f, true, false);
+ break;
+ case WASM_OP_I32_TRUNC_SAT_S_F64:
+ DEF_OP_TRUNC_SAT_F64(-2147483649.0, 2147483648.0, true,
+ true);
+ break;
+ case WASM_OP_I32_TRUNC_SAT_U_F64:
+ DEF_OP_TRUNC_SAT_F64(-1.0, 4294967296.0, true, false);
+ break;
+ case WASM_OP_I64_TRUNC_SAT_S_F32:
+ DEF_OP_TRUNC_SAT_F32(-9223373136366403584.0f,
+ 9223372036854775808.0f, false,
+ true);
+ break;
+ case WASM_OP_I64_TRUNC_SAT_U_F32:
+ DEF_OP_TRUNC_SAT_F32(-1.0f, 18446744073709551616.0f,
+ false, false);
+ break;
+ case WASM_OP_I64_TRUNC_SAT_S_F64:
+ DEF_OP_TRUNC_SAT_F64(-9223372036854777856.0,
+ 9223372036854775808.0, false,
+ true);
+ break;
+ case WASM_OP_I64_TRUNC_SAT_U_F64:
+ 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 = read_uint32(frame_ip);
+
+ bytes = (uint64)POP_I32();
+ offset = (uint64)POP_I32();
+ addr = POP_I32();
+
+#if WASM_ENABLE_THREAD_MGR
+ linear_mem_size = memory->memory_data_size;
+#endif
+
+#ifndef OS_ENABLE_HW_BOUND_CHECK
+ CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr);
+#else
+ if ((uint64)(uint32)addr + bytes
+ > (uint64)linear_mem_size)
+ goto out_of_bounds;
+ maddr = memory->memory_data + (uint32)addr;
+#endif
+
+ 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, (uint32)bytes);
+ break;
+ }
+ case WASM_OP_DATA_DROP:
+ {
+ uint32 segment;
+
+ segment = read_uint32(frame_ip);
+
+ 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();
+
+#if WASM_ENABLE_THREAD_MGR
+ linear_mem_size = memory->memory_data_size;
+#endif
+
+#ifndef OS_ENABLE_HW_BOUND_CHECK
+ CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc);
+ CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
+#else
+ if ((uint64)(uint32)src + len > (uint64)linear_mem_size)
+ goto out_of_bounds;
+ msrc = memory->memory_data + (uint32)src;
+
+ if ((uint64)(uint32)dst + len > (uint64)linear_mem_size)
+ goto out_of_bounds;
+ mdst = memory->memory_data + (uint32)dst;
+#endif
+
+ /* 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 fill_val, *mdst;
+
+ len = POP_I32();
+ fill_val = POP_I32();
+ dst = POP_I32();
+
+#if WASM_ENABLE_THREAD_MGR
+ linear_mem_size = memory->memory_data_size;
+#endif
+
+#ifndef OS_ENABLE_HW_BOUND_CHECK
+ CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
+#else
+ if ((uint64)(uint32)dst + len > (uint64)linear_mem_size)
+ goto out_of_bounds;
+ mdst = memory->memory_data + (uint32)dst;
+#endif
+
+ memset(mdst, fill_val, len);
+ break;
+ }
+#endif /* WASM_ENABLE_BULK_MEMORY */
+#if WASM_ENABLE_REF_TYPES != 0
+ case WASM_OP_TABLE_INIT:
+ {
+ uint32 tbl_idx, elem_idx;
+ uint64 n, s, d;
+ WASMTableInstance *tbl_inst;
+
+ elem_idx = read_uint32(frame_ip);
+ bh_assert(elem_idx < module->module->table_seg_count);
+
+ tbl_idx = read_uint32(frame_ip);
+ bh_assert(tbl_idx < module->module->table_count);
+
+ tbl_inst = wasm_get_table_inst(module, tbl_idx);
+
+ n = (uint32)POP_I32();
+ s = (uint32)POP_I32();
+ d = (uint32)POP_I32();
+
+ if (!n) {
+ break;
+ }
+
+ if (n + s > module->module->table_segments[elem_idx]
+ .function_count
+ || d + n > tbl_inst->cur_size) {
+ wasm_set_exception(module,
+ "out of bounds table access");
+ goto got_exception;
+ }
+
+ if (module->module->table_segments[elem_idx]
+ .is_dropped) {
+ wasm_set_exception(module,
+ "out of bounds table access");
+ goto got_exception;
+ }
+
+ if (!wasm_elem_is_passive(
+ module->module->table_segments[elem_idx]
+ .mode)) {
+ wasm_set_exception(module,
+ "out of bounds table access");
+ goto got_exception;
+ }
+
+ bh_memcpy_s(
+ (uint8 *)tbl_inst
+ + offsetof(WASMTableInstance, elems)
+ + d * sizeof(uint32),
+ (uint32)((tbl_inst->cur_size - d) * sizeof(uint32)),
+ module->module->table_segments[elem_idx]
+ .func_indexes
+ + s,
+ (uint32)(n * sizeof(uint32)));
+ break;
+ }
+ case WASM_OP_ELEM_DROP:
+ {
+ uint32 elem_idx = read_uint32(frame_ip);
+ bh_assert(elem_idx < module->module->table_seg_count);
+
+ module->module->table_segments[elem_idx].is_dropped =
+ true;
+ break;
+ }
+ case WASM_OP_TABLE_COPY:
+ {
+ uint32 src_tbl_idx, dst_tbl_idx;
+ uint64 n, s, d;
+ WASMTableInstance *src_tbl_inst, *dst_tbl_inst;
+
+ dst_tbl_idx = read_uint32(frame_ip);
+ bh_assert(dst_tbl_idx < module->table_count);
+
+ dst_tbl_inst = wasm_get_table_inst(module, dst_tbl_idx);
+
+ src_tbl_idx = read_uint32(frame_ip);
+ bh_assert(src_tbl_idx < module->table_count);
+
+ src_tbl_inst = wasm_get_table_inst(module, src_tbl_idx);
+
+ n = (uint32)POP_I32();
+ s = (uint32)POP_I32();
+ d = (uint32)POP_I32();
+
+ if (d + n > dst_tbl_inst->cur_size
+ || s + n > src_tbl_inst->cur_size) {
+ wasm_set_exception(module,
+ "out of bounds table access");
+ goto got_exception;
+ }
+
+ /* if s >= d, copy from front to back */
+ /* if s < d, copy from back to front */
+ /* merge all together */
+ bh_memmove_s((uint8 *)dst_tbl_inst
+ + offsetof(WASMTableInstance, elems)
+ + d * sizeof(uint32),
+ (uint32)((dst_tbl_inst->cur_size - d)
+ * sizeof(uint32)),
+ (uint8 *)src_tbl_inst
+ + offsetof(WASMTableInstance, elems)
+ + s * sizeof(uint32),
+ (uint32)(n * sizeof(uint32)));
+ break;
+ }
+ case WASM_OP_TABLE_GROW:
+ {
+ uint32 tbl_idx, n, init_val, orig_tbl_sz;
+ WASMTableInstance *tbl_inst;
+
+ tbl_idx = read_uint32(frame_ip);
+ bh_assert(tbl_idx < module->table_count);
+
+ tbl_inst = wasm_get_table_inst(module, tbl_idx);
+
+ orig_tbl_sz = tbl_inst->cur_size;
+
+ n = POP_I32();
+ init_val = POP_I32();
+
+ if (!wasm_enlarge_table(module, tbl_idx, n, init_val)) {
+ PUSH_I32(-1);
+ }
+ else {
+ PUSH_I32(orig_tbl_sz);
+ }
+
+ break;
+ }
+ case WASM_OP_TABLE_SIZE:
+ {
+ uint32 tbl_idx;
+ WASMTableInstance *tbl_inst;
+
+ tbl_idx = read_uint32(frame_ip);
+ bh_assert(tbl_idx < module->table_count);
+
+ tbl_inst = wasm_get_table_inst(module, tbl_idx);
+
+ PUSH_I32(tbl_inst->cur_size);
+ break;
+ }
+ case WASM_OP_TABLE_FILL:
+ {
+ uint32 tbl_idx, n, fill_val, i;
+ WASMTableInstance *tbl_inst;
+
+ tbl_idx = read_uint32(frame_ip);
+ bh_assert(tbl_idx < module->table_count);
+
+ tbl_inst = wasm_get_table_inst(module, tbl_idx);
+
+ n = POP_I32();
+ fill_val = POP_I32();
+ i = POP_I32();
+
+ if (i + n > tbl_inst->cur_size) {
+ wasm_set_exception(module,
+ "out of bounds table access");
+ goto got_exception;
+ }
+
+ for (; n != 0; i++, n--) {
+ tbl_inst->elems[i] = fill_val;
+ }
+
+ break;
+ }
+#endif /* WASM_ENABLE_REF_TYPES */
+ default:
+ wasm_set_exception(module, "unsupported opcode");
+ goto got_exception;
+ }
+ HANDLE_OP_END();
+ }
+
+#if WASM_ENABLE_SHARED_MEMORY != 0
+ HANDLE_OP(WASM_OP_ATOMIC_PREFIX)
+ {
+ uint32 offset = 0, addr;
+
+ GET_OPCODE();
+
+ if (opcode != WASM_OP_ATOMIC_FENCE) {
+ offset = read_uint32(frame_ip);
+ }
+
+ switch (opcode) {
+ case WASM_OP_ATOMIC_NOTIFY:
+ {
+ uint32 notify_count, ret;
+
+ notify_count = POP_I32();
+ addr = POP_I32();
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(4);
+
+ ret = wasm_runtime_atomic_notify(
+ (WASMModuleInstanceCommon *)module, maddr,
+ notify_count);
+ if (ret == (uint32)-1)
+ goto got_exception;
+
+ PUSH_I32(ret);
+ break;
+ }
+ case WASM_OP_ATOMIC_WAIT32:
+ {
+ uint64 timeout;
+ uint32 expect, ret;
+
+ timeout = POP_I64();
+ expect = POP_I32();
+ addr = POP_I32();
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(4);
+
+ ret = wasm_runtime_atomic_wait(
+ (WASMModuleInstanceCommon *)module, maddr,
+ (uint64)expect, timeout, false);
+ if (ret == (uint32)-1)
+ goto got_exception;
+
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+
+ PUSH_I32(ret);
+ break;
+ }
+ case WASM_OP_ATOMIC_WAIT64:
+ {
+ uint64 timeout, expect;
+ uint32 ret;
+
+ timeout = POP_I64();
+ expect = POP_I64();
+ addr = POP_I32();
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(8);
+
+ ret = wasm_runtime_atomic_wait(
+ (WASMModuleInstanceCommon *)module, maddr, expect,
+ timeout, true);
+ if (ret == (uint32)-1)
+ goto got_exception;
+
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+
+ PUSH_I32(ret);
+ break;
+ }
+ case WASM_OP_ATOMIC_FENCE:
+ {
+ os_atomic_thread_fence(os_memory_order_seq_cst);
+ break;
+ }
+
+ case WASM_OP_ATOMIC_I32_LOAD:
+ case WASM_OP_ATOMIC_I32_LOAD8_U:
+ case WASM_OP_ATOMIC_I32_LOAD16_U:
+ {
+ uint32 readv;
+
+ addr = POP_I32();
+
+ if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(1);
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint32)(*(uint8 *)maddr);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else if (opcode == WASM_OP_ATOMIC_I32_LOAD16_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(2);
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint32)LOAD_U16(maddr);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(4);
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = LOAD_I32(maddr);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+
+ PUSH_I32(readv);
+ break;
+ }
+
+ case WASM_OP_ATOMIC_I64_LOAD:
+ case WASM_OP_ATOMIC_I64_LOAD8_U:
+ case WASM_OP_ATOMIC_I64_LOAD16_U:
+ case WASM_OP_ATOMIC_I64_LOAD32_U:
+ {
+ uint64 readv;
+
+ addr = POP_I32();
+
+ if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(1);
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint64)(*(uint8 *)maddr);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else if (opcode == WASM_OP_ATOMIC_I64_LOAD16_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(2);
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint64)LOAD_U16(maddr);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else if (opcode == WASM_OP_ATOMIC_I64_LOAD32_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(4);
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint64)LOAD_U32(maddr);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(8);
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = LOAD_I64(maddr);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+
+ PUSH_I64(readv);
+ break;
+ }
+ case WASM_OP_ATOMIC_I32_STORE:
+ case WASM_OP_ATOMIC_I32_STORE8:
+ case WASM_OP_ATOMIC_I32_STORE16:
+ {
+ uint32 sval;
+
+ sval = (uint32)POP_I32();
+ addr = POP_I32();
+
+ if (opcode == WASM_OP_ATOMIC_I32_STORE8) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(1);
+ os_mutex_lock(&node->shared_mem_lock);
+ *(uint8 *)maddr = (uint8)sval;
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else if (opcode == WASM_OP_ATOMIC_I32_STORE16) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(2);
+ os_mutex_lock(&node->shared_mem_lock);
+ STORE_U16(maddr, (uint16)sval);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(4);
+ os_mutex_lock(&node->shared_mem_lock);
+ STORE_U32(maddr, sval);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ break;
+ }
+
+ case WASM_OP_ATOMIC_I64_STORE:
+ case WASM_OP_ATOMIC_I64_STORE8:
+ case WASM_OP_ATOMIC_I64_STORE16:
+ case WASM_OP_ATOMIC_I64_STORE32:
+ {
+ uint64 sval;
+
+ sval = (uint64)POP_I64();
+ addr = POP_I32();
+
+ if (opcode == WASM_OP_ATOMIC_I64_STORE8) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(1);
+ os_mutex_lock(&node->shared_mem_lock);
+ *(uint8 *)maddr = (uint8)sval;
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else if (opcode == WASM_OP_ATOMIC_I64_STORE16) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(2);
+ os_mutex_lock(&node->shared_mem_lock);
+ STORE_U16(maddr, (uint16)sval);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else if (opcode == WASM_OP_ATOMIC_I64_STORE32) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(4);
+ os_mutex_lock(&node->shared_mem_lock);
+ STORE_U32(maddr, (uint32)sval);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(8);
+ os_mutex_lock(&node->shared_mem_lock);
+ STORE_I64(maddr, sval);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ break;
+ }
+
+ case WASM_OP_ATOMIC_RMW_I32_CMPXCHG:
+ case WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U:
+ case WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U:
+ {
+ uint32 readv, sval, expect;
+
+ sval = POP_I32();
+ expect = POP_I32();
+ addr = POP_I32();
+
+ if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(1);
+
+ expect = (uint8)expect;
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint32)(*(uint8 *)maddr);
+ if (readv == expect)
+ *(uint8 *)maddr = (uint8)(sval);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(2);
+
+ expect = (uint16)expect;
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint32)LOAD_U16(maddr);
+ if (readv == expect)
+ STORE_U16(maddr, (uint16)(sval));
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(4);
+
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = LOAD_I32(maddr);
+ if (readv == expect)
+ STORE_U32(maddr, sval);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ PUSH_I32(readv);
+ break;
+ }
+ case WASM_OP_ATOMIC_RMW_I64_CMPXCHG:
+ case WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U:
+ case WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U:
+ case WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U:
+ {
+ uint64 readv, sval, expect;
+
+ sval = (uint64)POP_I64();
+ expect = (uint64)POP_I64();
+ addr = POP_I32();
+
+ if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(1);
+
+ expect = (uint8)expect;
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint64)(*(uint8 *)maddr);
+ if (readv == expect)
+ *(uint8 *)maddr = (uint8)(sval);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(2);
+
+ expect = (uint16)expect;
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint64)LOAD_U16(maddr);
+ if (readv == expect)
+ STORE_U16(maddr, (uint16)(sval));
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U) {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(4);
+
+ expect = (uint32)expect;
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint64)LOAD_U32(maddr);
+ if (readv == expect)
+ STORE_U32(maddr, (uint32)(sval));
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ else {
+ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
+ CHECK_ATOMIC_MEMORY_ACCESS(8);
+
+ os_mutex_lock(&node->shared_mem_lock);
+ readv = (uint64)LOAD_I64(maddr);
+ if (readv == expect)
+ STORE_I64(maddr, sval);
+ os_mutex_unlock(&node->shared_mem_lock);
+ }
+ PUSH_I64(readv);
+ break;
+ }
+
+ DEF_ATOMIC_RMW_OPCODE(ADD, +);
+ DEF_ATOMIC_RMW_OPCODE(SUB, -);
+ DEF_ATOMIC_RMW_OPCODE(AND, &);
+ DEF_ATOMIC_RMW_OPCODE(OR, |);
+ DEF_ATOMIC_RMW_OPCODE(XOR, ^);
+ /* xchg, ignore the read value, and store the given
+ value: readv * 0 + sval */
+ DEF_ATOMIC_RMW_OPCODE(XCHG, *0 +);
+ }
+
+ HANDLE_OP_END();
+ }
+#endif
+
+ HANDLE_OP(WASM_OP_IMPDEP)
+ {
+ frame = prev_frame;
+ frame_ip = frame->ip;
+ goto call_func_from_entry;
+ }
+
+ HANDLE_OP(WASM_OP_CALL)
+ {
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+ fidx = read_uint32(frame_ip);
+#if WASM_ENABLE_MULTI_MODULE != 0
+ if (fidx >= module->e->function_count) {
+ wasm_set_exception(module, "unknown function");
+ goto got_exception;
+ }
+#endif
+ cur_func = module->e->functions + fidx;
+ goto call_func_from_interp;
+ }
+
+#if WASM_ENABLE_TAIL_CALL != 0
+ HANDLE_OP(WASM_OP_RETURN_CALL)
+ {
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+ fidx = read_uint32(frame_ip);
+#if WASM_ENABLE_MULTI_MODULE != 0
+ if (fidx >= module->e->function_count) {
+ wasm_set_exception(module, "unknown function");
+ goto got_exception;
+ }
+#endif
+ cur_func = module->e->functions + fidx;
+ goto call_func_from_return_call;
+ }
+#endif /* WASM_ENABLE_TAIL_CALL */
+
+#if WASM_ENABLE_LABELS_AS_VALUES == 0
+ default:
+ wasm_set_exception(module, "unsupported opcode");
+ goto got_exception;
+ }
+#endif
+
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+ HANDLE_OP(WASM_OP_UNUSED_0x06)
+ HANDLE_OP(WASM_OP_UNUSED_0x07)
+ HANDLE_OP(WASM_OP_UNUSED_0x08)
+ HANDLE_OP(WASM_OP_UNUSED_0x09)
+ HANDLE_OP(WASM_OP_UNUSED_0x0a)
+#if WASM_ENABLE_TAIL_CALL == 0
+ HANDLE_OP(WASM_OP_RETURN_CALL)
+ HANDLE_OP(WASM_OP_RETURN_CALL_INDIRECT)
+#endif
+#if WASM_ENABLE_SHARED_MEMORY == 0
+ HANDLE_OP(WASM_OP_ATOMIC_PREFIX)
+#endif
+#if WASM_ENABLE_REF_TYPES == 0
+ HANDLE_OP(WASM_OP_TABLE_GET)
+ HANDLE_OP(WASM_OP_TABLE_SET)
+ HANDLE_OP(WASM_OP_REF_NULL)
+ HANDLE_OP(WASM_OP_REF_IS_NULL)
+ HANDLE_OP(WASM_OP_REF_FUNC)
+#endif
+ /* SELECT_T is converted to SELECT or SELECT_64 */
+ HANDLE_OP(WASM_OP_SELECT_T)
+ HANDLE_OP(WASM_OP_UNUSED_0x14)
+ HANDLE_OP(WASM_OP_UNUSED_0x15)
+ HANDLE_OP(WASM_OP_UNUSED_0x16)
+ HANDLE_OP(WASM_OP_UNUSED_0x17)
+ HANDLE_OP(WASM_OP_UNUSED_0x18)
+ HANDLE_OP(WASM_OP_UNUSED_0x19)
+ HANDLE_OP(WASM_OP_UNUSED_0x27)
+ /* optimized op code */
+ HANDLE_OP(WASM_OP_F32_STORE)
+ HANDLE_OP(WASM_OP_F64_STORE)
+ HANDLE_OP(WASM_OP_F32_LOAD)
+ HANDLE_OP(WASM_OP_F64_LOAD)
+ HANDLE_OP(EXT_OP_GET_LOCAL_FAST)
+ HANDLE_OP(WASM_OP_GET_LOCAL)
+ HANDLE_OP(WASM_OP_DROP)
+ HANDLE_OP(WASM_OP_DROP_64)
+ HANDLE_OP(WASM_OP_BLOCK)
+ HANDLE_OP(WASM_OP_LOOP)
+ HANDLE_OP(WASM_OP_END)
+ HANDLE_OP(WASM_OP_NOP)
+ HANDLE_OP(EXT_OP_BLOCK)
+ HANDLE_OP(EXT_OP_LOOP)
+ HANDLE_OP(EXT_OP_IF)
+ HANDLE_OP(EXT_OP_BR_TABLE_CACHE)
+ {
+ wasm_set_exception(module, "unsupported opcode");
+ goto got_exception;
+ }
+#endif
+
+#if WASM_ENABLE_LABELS_AS_VALUES == 0
+ continue;
+#else
+ FETCH_OPCODE_AND_DISPATCH();
+#endif
+
+#if WASM_ENABLE_TAIL_CALL != 0
+ call_func_from_return_call:
+ {
+ uint32 *lp_base;
+ uint32 *lp;
+ int i;
+
+ if (!(lp_base = lp = wasm_runtime_malloc(cur_func->param_cell_num
+ * sizeof(uint32)))) {
+ wasm_set_exception(module, "allocate memory failed");
+ goto got_exception;
+ }
+ for (i = 0; i < cur_func->param_count; i++) {
+ if (cur_func->param_types[i] == VALUE_TYPE_I64
+ || cur_func->param_types[i] == VALUE_TYPE_F64) {
+ PUT_I64_TO_ADDR(
+ lp, GET_OPERAND(uint64, I64,
+ 2 * (cur_func->param_count - i - 1)));
+ lp += 2;
+ }
+ else {
+ *lp = GET_OPERAND(uint32, I32,
+ (2 * (cur_func->param_count - i - 1)));
+ lp++;
+ }
+ }
+ frame->lp = frame->operand + cur_func->const_cell_num;
+ if (lp - lp_base > 0) {
+ word_copy(frame->lp, lp_base, lp - lp_base);
+ }
+ wasm_runtime_free(lp_base);
+ FREE_FRAME(exec_env, frame);
+ frame_ip += cur_func->param_count * sizeof(int16);
+ wasm_exec_env_set_cur_frame(exec_env, (WASMRuntimeFrame *)prev_frame);
+ goto call_func_from_entry;
+ }
+#endif /* WASM_ENABLE_TAIL_CALL */
+
+ call_func_from_interp:
+ {
+ /* Only do the copy when it's called from interpreter. */
+ WASMInterpFrame *outs_area = wasm_exec_env_wasm_stack_top(exec_env);
+ int i;
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+ if (cur_func->is_import_func) {
+ outs_area->lp = outs_area->operand
+ + (cur_func->import_func_inst
+ ? cur_func->import_func_inst->const_cell_num
+ : 0);
+ }
+ else
+#endif
+ {
+ outs_area->lp = outs_area->operand + cur_func->const_cell_num;
+ }
+
+ if ((uint8 *)(outs_area->lp + cur_func->param_cell_num)
+ > exec_env->wasm_stack.s.top_boundary) {
+ wasm_set_exception(module, "wasm operand stack overflow");
+ goto got_exception;
+ }
+
+ for (i = 0; i < cur_func->param_count; i++) {
+ if (cur_func->param_types[i] == VALUE_TYPE_I64
+ || cur_func->param_types[i] == VALUE_TYPE_F64) {
+ PUT_I64_TO_ADDR(
+ outs_area->lp,
+ GET_OPERAND(uint64, I64,
+ 2 * (cur_func->param_count - i - 1)));
+ outs_area->lp += 2;
+ }
+ else {
+ *outs_area->lp = GET_OPERAND(
+ uint32, I32, (2 * (cur_func->param_count - i - 1)));
+ outs_area->lp++;
+ }
+ }
+ frame_ip += cur_func->param_count * sizeof(int16);
+ if (cur_func->ret_cell_num != 0) {
+ /* Get the first return value's offset. Since loader emit
+ * all return values' offset so we must skip remain return
+ * values' offsets.
+ */
+ WASMType *func_type;
+ if (cur_func->is_import_func)
+ func_type = cur_func->u.func_import->func_type;
+ else
+ func_type = cur_func->u.func->func_type;
+ frame->ret_offset = GET_OFFSET();
+ frame_ip += 2 * (func_type->result_count - 1);
+ }
+ SYNC_ALL_TO_FRAME();
+ prev_frame = frame;
+ }
+
+ call_func_from_entry:
+ {
+ if (cur_func->is_import_func) {
+#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);
+ }
+
+ prev_frame = frame->prev_frame;
+ cur_func = frame->function;
+ UPDATE_ALL_FROM_FRAME();
+
+ /* update memory size, no need to update memory ptr as
+ it isn't changed in wasm_enlarge_memory */
+#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
+ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
+ || WASM_ENABLE_BULK_MEMORY != 0
+ if (memory)
+ linear_mem_size = memory->memory_data_size;
+#endif
+ if (wasm_copy_exception(module, NULL))
+ goto got_exception;
+ }
+ else {
+ WASMFunction *cur_wasm_func = cur_func->u.func;
+
+ all_cell_num = cur_func->param_cell_num + cur_func->local_cell_num
+ + cur_func->const_cell_num
+ + cur_wasm_func->max_stack_cell_num;
+ /* param_cell_num, local_cell_num, const_cell_num and
+ max_stack_cell_num are all no larger than UINT16_MAX (checked
+ in loader), all_cell_num must be smaller than 1MB */
+ bh_assert(all_cell_num < 1 * BH_MB);
+
+ frame_size = wasm_interp_interp_frame_size(all_cell_num);
+ if (!(frame = ALLOC_FRAME(exec_env, frame_size, prev_frame))) {
+ frame = prev_frame;
+ goto got_exception;
+ }
+
+ /* Initialize the interpreter context. */
+ frame->function = cur_func;
+ frame_ip = wasm_get_func_code(cur_func);
+ frame_ip_end = wasm_get_func_code_end(cur_func);
+
+ frame_lp = frame->lp =
+ frame->operand + cur_wasm_func->const_cell_num;
+
+ /* Initialize the consts */
+ if (cur_wasm_func->const_cell_num > 0) {
+ word_copy(frame->operand, (uint32 *)cur_wasm_func->consts,
+ cur_wasm_func->const_cell_num);
+ }
+
+ /* Initialize the local variables */
+ memset(frame_lp + cur_func->param_cell_num, 0,
+ (uint32)(cur_func->local_cell_num * 4));
+
+ wasm_exec_env_set_cur_frame(exec_env, (WASMRuntimeFrame *)frame);
+ }
+#if WASM_ENABLE_THREAD_MGR != 0
+ CHECK_SUSPEND_FLAGS();
+#endif
+ HANDLE_OP_END();
+ }
+
+ return_func:
+ {
+ FREE_FRAME(exec_env, frame);
+ wasm_exec_env_set_cur_frame(exec_env, (WASMRuntimeFrame *)prev_frame);
+
+ if (!prev_frame->ip)
+ /* Called from native. */
+ return;
+
+ RECOVER_CONTEXT(prev_frame);
+ HANDLE_OP_END();
+ }
+
+ (void)frame_ip_end;
+
+#if WASM_ENABLE_SHARED_MEMORY != 0
+ unaligned_atomic:
+ wasm_set_exception(module, "unaligned atomic");
+ goto got_exception;
+#endif
+
+#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
+ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
+ || WASM_ENABLE_BULK_MEMORY != 0
+ out_of_bounds:
+ wasm_set_exception(module, "out of bounds memory access");
+#endif
+
+ got_exception:
+ SYNC_ALL_TO_FRAME();
+ return;
+
+#if WASM_ENABLE_LABELS_AS_VALUES == 0
+ }
+#else
+ FETCH_OPCODE_AND_DISPATCH();
+#endif
+}
+
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+void **
+wasm_interp_get_handle_table()
+{
+ WASMModuleInstance module;
+ memset(&module, 0, sizeof(WASMModuleInstance));
+ wasm_interp_call_func_bytecode(&module, NULL, NULL, NULL);
+ return global_handle_table;
+}
+#endif
+
+void
+wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
+ WASMFunctionInstance *function, uint32 argc,
+ uint32 argv[])
+{
+ WASMRuntimeFrame *prev_frame = wasm_exec_env_get_cur_frame(exec_env);
+ WASMInterpFrame *frame, *outs_area;
+
+ /* Allocate sufficient cells for all kinds of return values. */
+ unsigned all_cell_num =
+ function->ret_cell_num > 2 ? function->ret_cell_num : 2,
+ i;
+ /* This frame won't be used by JITed code, so only allocate interp
+ frame here. */
+ unsigned frame_size = wasm_interp_interp_frame_size(all_cell_num);
+ char exception[EXCEPTION_BUF_LEN];
+
+ if (argc < function->param_cell_num) {
+ char buf[128];
+ snprintf(buf, sizeof(buf),
+ "invalid argument count %" PRIu32
+ ", must be no smaller than %" PRIu32,
+ argc, (uint32)function->param_cell_num);
+ wasm_set_exception(module_inst, buf);
+ return;
+ }
+ argc = function->param_cell_num;
+
+ RECORD_STACK_USAGE(exec_env, (uint8 *)&prev_frame);
+#if !(defined(OS_ENABLE_HW_BOUND_CHECK) \
+ && WASM_DISABLE_STACK_HW_BOUND_CHECK == 0)
+ if ((uint8 *)&prev_frame < exec_env->native_stack_boundary) {
+ wasm_set_exception((WASMModuleInstance *)exec_env->module_inst,
+ "native stack overflow");
+ return;
+ }
+#endif
+
+ if (!(frame =
+ ALLOC_FRAME(exec_env, frame_size, (WASMInterpFrame *)prev_frame)))
+ return;
+
+ outs_area = wasm_exec_env_wasm_stack_top(exec_env);
+ frame->function = NULL;
+ frame->ip = NULL;
+ /* There is no local variable. */
+ frame->lp = frame->operand + 0;
+ frame->ret_offset = 0;
+
+ if ((uint8 *)(outs_area->operand + function->const_cell_num + argc)
+ > exec_env->wasm_stack.s.top_boundary) {
+ wasm_set_exception((WASMModuleInstance *)exec_env->module_inst,
+ "wasm operand stack overflow");
+ return;
+ }
+
+ if (argc > 0)
+ word_copy(outs_area->operand + function->const_cell_num, argv, argc);
+
+ wasm_exec_env_set_cur_frame(exec_env, frame);
+
+ 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_copy_exception(module_inst, NULL)) {
+ for (i = 0; i < function->ret_cell_num; i++)
+ argv[i] = *(frame->lp + i);
+ }
+ else {
+#if WASM_ENABLE_DUMP_CALL_STACK != 0
+ if (wasm_interp_create_call_stack(exec_env)) {
+ wasm_interp_dump_call_stack(exec_env, true, NULL, 0);
+ }
+#endif
+ wasm_copy_exception(module_inst, exception);
+ LOG_DEBUG("meet an exception %s", exception);
+ }
+
+ wasm_exec_env_set_cur_frame(exec_env, prev_frame);
+ FREE_FRAME(exec_env, frame);
+#if WASM_ENABLE_OPCODE_COUNTER != 0
+ wasm_interp_dump_op_count();
+#endif
+}
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_loader.c b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_loader.c
new file mode 100644
index 000000000..a3c4f4224
--- /dev/null
+++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_loader.c
@@ -0,0 +1,10131 @@
+/*
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "wasm_loader.h"
+#include "bh_common.h"
+#include "bh_log.h"
+#include "wasm.h"
+#include "wasm_opcode.h"
+#include "wasm_runtime.h"
+#include "../common/wasm_native.h"
+#include "../common/wasm_memory.h"
+#if WASM_ENABLE_DEBUG_INTERP != 0
+#include "../libraries/debug-engine/debug_engine.h"
+#endif
+#if WASM_ENABLE_FAST_JIT != 0
+#include "../fast-jit/jit_compiler.h"
+#include "../fast-jit/jit_codecache.h"
+#endif
+#if WASM_ENABLE_JIT != 0
+#include "../compilation/aot_llvm.h"
+#endif
+
+/* Read a value of given type from the address pointed to by the given
+ pointer and increase the pointer to the position just after the
+ value being read. */
+#define TEMPLATE_READ_VALUE(Type, p) \
+ (p += sizeof(Type), *(Type *)(p - sizeof(Type)))
+
+static void
+set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
+{
+ if (error_buf != NULL) {
+ snprintf(error_buf, error_buf_size, "WASM module load failed: %s",
+ string);
+ }
+}
+
+static void
+set_error_buf_v(char *error_buf, uint32 error_buf_size, const char *format, ...)
+{
+ va_list args;
+ char buf[128];
+
+ if (error_buf != NULL) {
+ va_start(args, format);
+ vsnprintf(buf, sizeof(buf), format, args);
+ va_end(args);
+ snprintf(error_buf, error_buf_size, "WASM module load failed: %s", buf);
+ }
+}
+
+static bool
+check_buf(const uint8 *buf, const uint8 *buf_end, uint32 length,
+ char *error_buf, uint32 error_buf_size)
+{
+ if ((uintptr_t)buf + length < (uintptr_t)buf
+ || (uintptr_t)buf + length > (uintptr_t)buf_end) {
+ set_error_buf(error_buf, error_buf_size,
+ "unexpected end of section or function");
+ return false;
+ }
+ return true;
+}
+
+static bool
+check_buf1(const uint8 *buf, const uint8 *buf_end, uint32 length,
+ char *error_buf, uint32 error_buf_size)
+{
+ if ((uintptr_t)buf + length < (uintptr_t)buf
+ || (uintptr_t)buf + length > (uintptr_t)buf_end) {
+ set_error_buf(error_buf, error_buf_size, "unexpected end");
+ return false;
+ }
+ return true;
+}
+
+#define CHECK_BUF(buf, buf_end, length) \
+ do { \
+ if (!check_buf(buf, buf_end, length, error_buf, error_buf_size)) { \
+ goto fail; \
+ } \
+ } while (0)
+
+#define CHECK_BUF1(buf, buf_end, length) \
+ do { \
+ if (!check_buf1(buf, buf_end, length, error_buf, error_buf_size)) { \
+ goto fail; \
+ } \
+ } while (0)
+
+#define skip_leb(p) while (*p++ & 0x80)
+#define skip_leb_int64(p, p_end) skip_leb(p)
+#define skip_leb_uint32(p, p_end) skip_leb(p)
+#define skip_leb_int32(p, p_end) skip_leb(p)
+
+static bool
+read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign,
+ uint64 *p_result, char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *buf = *p_buf;
+ uint64 result = 0;
+ uint32 shift = 0;
+ uint32 offset = 0, bcnt = 0;
+ uint64 byte;
+
+ while (true) {
+ /* uN or SN must not exceed ceil(N/7) bytes */
+ if (bcnt + 1 > (maxbits + 6) / 7) {
+ set_error_buf(error_buf, error_buf_size,
+ "integer representation too long");
+ return false;
+ }
+
+ CHECK_BUF(buf, buf_end, offset + 1);
+ byte = buf[offset];
+ offset += 1;
+ result |= ((byte & 0x7f) << shift);
+ shift += 7;
+ bcnt += 1;
+ if ((byte & 0x80) == 0) {
+ break;
+ }
+ }
+
+ if (!sign && maxbits == 32 && shift >= maxbits) {
+ /* The top bits set represent values > 32 bits */
+ if (((uint8)byte) & 0xf0)
+ goto fail_integer_too_large;
+ }
+ else if (sign && maxbits == 32) {
+ if (shift < maxbits) {
+ /* Sign extend, second highest bit is the sign bit */
+ if ((uint8)byte & 0x40)
+ result |= (~((uint64)0)) << shift;
+ }
+ else {
+ /* The top bits should be a sign-extension of the sign bit */
+ bool sign_bit_set = ((uint8)byte) & 0x8;
+ int top_bits = ((uint8)byte) & 0xf0;
+ if ((sign_bit_set && top_bits != 0x70)
+ || (!sign_bit_set && top_bits != 0))
+ goto fail_integer_too_large;
+ }
+ }
+ else if (sign && maxbits == 64) {
+ if (shift < maxbits) {
+ /* Sign extend, second highest bit is the sign bit */
+ if ((uint8)byte & 0x40)
+ result |= (~((uint64)0)) << shift;
+ }
+ else {
+ /* The top bits should be a sign-extension of the sign bit */
+ bool sign_bit_set = ((uint8)byte) & 0x1;
+ int top_bits = ((uint8)byte) & 0xfe;
+
+ if ((sign_bit_set && top_bits != 0x7e)
+ || (!sign_bit_set && top_bits != 0))
+ goto fail_integer_too_large;
+ }
+ }
+
+ *p_buf += offset;
+ *p_result = result;
+ return true;
+
+fail_integer_too_large:
+ set_error_buf(error_buf, error_buf_size, "integer too large");
+fail:
+ return false;
+}
+
+#define read_uint8(p) TEMPLATE_READ_VALUE(uint8, p)
+#define read_uint32(p) TEMPLATE_READ_VALUE(uint32, p)
+#define read_bool(p) TEMPLATE_READ_VALUE(bool, p)
+
+#define read_leb_int64(p, p_end, res) \
+ do { \
+ uint64 res64; \
+ if (!read_leb((uint8 **)&p, p_end, 64, true, &res64, error_buf, \
+ error_buf_size)) \
+ goto fail; \
+ res = (int64)res64; \
+ } while (0)
+
+#define read_leb_uint32(p, p_end, res) \
+ do { \
+ uint64 res64; \
+ if (!read_leb((uint8 **)&p, p_end, 32, false, &res64, error_buf, \
+ error_buf_size)) \
+ goto fail; \
+ res = (uint32)res64; \
+ } while (0)
+
+#define read_leb_int32(p, p_end, res) \
+ do { \
+ uint64 res64; \
+ if (!read_leb((uint8 **)&p, p_end, 32, true, &res64, error_buf, \
+ error_buf_size)) \
+ goto fail; \
+ res = (int32)res64; \
+ } while (0)
+
+static char *
+type2str(uint8 type)
+{
+ char *type_str[] = { "v128", "f64", "f32", "i64", "i32" };
+
+ if (type >= VALUE_TYPE_V128 && type <= VALUE_TYPE_I32)
+ return type_str[type - VALUE_TYPE_V128];
+ else if (type == VALUE_TYPE_FUNCREF)
+ return "funcref";
+ else if (type == VALUE_TYPE_EXTERNREF)
+ return "externref";
+ else
+ return "unknown type";
+}
+
+static bool
+is_32bit_type(uint8 type)
+{
+ if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32
+#if WASM_ENABLE_REF_TYPES != 0
+ || type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF
+#endif
+ )
+ return true;
+ return false;
+}
+
+static bool
+is_64bit_type(uint8 type)
+{
+ if (type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64)
+ return true;
+ return false;
+}
+
+static bool
+is_value_type(uint8 type)
+{
+ if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_I64
+ || type == VALUE_TYPE_F32 || type == VALUE_TYPE_F64
+#if WASM_ENABLE_REF_TYPES != 0
+ || type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF
+#endif
+#if WASM_ENABLE_SIMD != 0
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+ || type == VALUE_TYPE_V128
+#endif
+#endif
+ )
+ return true;
+ return false;
+}
+
+static bool
+is_byte_a_type(uint8 type)
+{
+ return is_value_type(type) || (type == VALUE_TYPE_VOID);
+}
+
+#if WASM_ENABLE_SIMD != 0
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+static V128
+read_i8x16(uint8 *p_buf, char *error_buf, uint32 error_buf_size)
+{
+ V128 result;
+ uint8 i;
+
+ for (i = 0; i != 16; ++i) {
+ result.i8x16[i] = read_uint8(p_buf);
+ }
+
+ return result;
+}
+#endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) */
+#endif /* end of WASM_ENABLE_SIMD */
+
+static void *
+loader_malloc(uint64 size, char *error_buf, uint32 error_buf_size)
+{
+ void *mem;
+
+ if (size >= UINT32_MAX || !(mem = wasm_runtime_malloc((uint32)size))) {
+ set_error_buf(error_buf, error_buf_size, "allocate memory failed");
+ return NULL;
+ }
+
+ memset(mem, 0, (uint32)size);
+ return mem;
+}
+
+static bool
+check_utf8_str(const uint8 *str, uint32 len)
+{
+ /* The valid ranges are taken from page 125, below link
+ https://www.unicode.org/versions/Unicode9.0.0/ch03.pdf */
+ const uint8 *p = str, *p_end = str + len;
+ uint8 chr;
+
+ while (p < p_end) {
+ chr = *p;
+ if (chr < 0x80) {
+ p++;
+ }
+ else if (chr >= 0xC2 && chr <= 0xDF && p + 1 < p_end) {
+ if (p[1] < 0x80 || p[1] > 0xBF) {
+ return false;
+ }
+ p += 2;
+ }
+ else if (chr >= 0xE0 && chr <= 0xEF && p + 2 < p_end) {
+ if (chr == 0xE0) {
+ if (p[1] < 0xA0 || p[1] > 0xBF || p[2] < 0x80 || p[2] > 0xBF) {
+ return false;
+ }
+ }
+ else if (chr == 0xED) {
+ if (p[1] < 0x80 || p[1] > 0x9F || p[2] < 0x80 || p[2] > 0xBF) {
+ return false;
+ }
+ }
+ else if (chr >= 0xE1 && chr <= 0xEF) {
+ if (p[1] < 0x80 || p[1] > 0xBF || p[2] < 0x80 || p[2] > 0xBF) {
+ return false;
+ }
+ }
+ p += 3;
+ }
+ else if (chr >= 0xF0 && chr <= 0xF4 && p + 3 < p_end) {
+ if (chr == 0xF0) {
+ if (p[1] < 0x90 || p[1] > 0xBF || p[2] < 0x80 || p[2] > 0xBF
+ || p[3] < 0x80 || p[3] > 0xBF) {
+ return false;
+ }
+ }
+ else if (chr >= 0xF1 && chr <= 0xF3) {
+ if (p[1] < 0x80 || p[1] > 0xBF || p[2] < 0x80 || p[2] > 0xBF
+ || p[3] < 0x80 || p[3] > 0xBF) {
+ return false;
+ }
+ }
+ else if (chr == 0xF4) {
+ if (p[1] < 0x80 || p[1] > 0x8F || p[2] < 0x80 || p[2] > 0xBF
+ || p[3] < 0x80 || p[3] > 0xBF) {
+ return false;
+ }
+ }
+ p += 4;
+ }
+ else {
+ return false;
+ }
+ }
+ return (p == p_end);
+}
+
+static char *
+const_str_list_insert(const uint8 *str, uint32 len, WASMModule *module,
+ bool is_load_from_file_buf, char *error_buf,
+ uint32 error_buf_size)
+{
+ StringNode *node, *node_next;
+
+ if (!check_utf8_str(str, len)) {
+ set_error_buf(error_buf, error_buf_size, "invalid UTF-8 encoding");
+ return NULL;
+ }
+
+ if (len == 0) {
+ return "";
+ }
+ else if (is_load_from_file_buf) {
+ /* As the file buffer can be referred to after loading, we use
+ the previous byte of leb encoded size to adjust the string:
+ move string 1 byte backward and then append '\0' */
+ char *c_str = (char *)str - 1;
+ bh_memmove_s(c_str, len + 1, c_str + 1, len);
+ c_str[len] = '\0';
+ return c_str;
+ }
+
+ /* Search const str list */
+ node = module->const_str_list;
+ while (node) {
+ node_next = node->next;
+ if (strlen(node->str) == len && !memcmp(node->str, str, len))
+ break;
+ node = node_next;
+ }
+
+ if (node) {
+ return node->str;
+ }
+
+ if (!(node = loader_malloc(sizeof(StringNode) + len + 1, error_buf,
+ error_buf_size))) {
+ return NULL;
+ }
+
+ node->str = ((char *)node) + sizeof(StringNode);
+ bh_memcpy_s(node->str, len + 1, str, len);
+ node->str[len] = '\0';
+
+ if (!module->const_str_list) {
+ /* set as head */
+ module->const_str_list = node;
+ node->next = NULL;
+ }
+ else {
+ /* insert it */
+ node->next = module->const_str_list;
+ module->const_str_list = node;
+ }
+
+ return node->str;
+}
+
+static void
+destroy_wasm_type(WASMType *type)
+{
+ if (type->ref_count > 1) {
+ /* The type is referenced by other types
+ of current wasm module */
+ type->ref_count--;
+ return;
+ }
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0
+ if (type->call_to_llvm_jit_from_fast_jit)
+ jit_code_cache_free(type->call_to_llvm_jit_from_fast_jit);
+#endif
+
+ wasm_runtime_free(type);
+}
+
+static bool
+load_init_expr(const uint8 **p_buf, const uint8 *buf_end,
+ InitializerExpression *init_expr, uint8 type, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end;
+ uint8 flag, end_byte, *p_float;
+ uint32 i;
+
+ CHECK_BUF(p, p_end, 1);
+ init_expr->init_expr_type = read_uint8(p);
+ flag = init_expr->init_expr_type;
+
+ switch (flag) {
+ /* i32.const */
+ case INIT_EXPR_TYPE_I32_CONST:
+ if (type != VALUE_TYPE_I32)
+ goto fail_type_mismatch;
+ read_leb_int32(p, p_end, init_expr->u.i32);
+ break;
+ /* i64.const */
+ case INIT_EXPR_TYPE_I64_CONST:
+ if (type != VALUE_TYPE_I64)
+ goto fail_type_mismatch;
+ read_leb_int64(p, p_end, init_expr->u.i64);
+ break;
+ /* f32.const */
+ case INIT_EXPR_TYPE_F32_CONST:
+ if (type != VALUE_TYPE_F32)
+ goto fail_type_mismatch;
+ CHECK_BUF(p, p_end, 4);
+ p_float = (uint8 *)&init_expr->u.f32;
+ for (i = 0; i < sizeof(float32); i++)
+ *p_float++ = *p++;
+ break;
+ /* f64.const */
+ case INIT_EXPR_TYPE_F64_CONST:
+ if (type != VALUE_TYPE_F64)
+ goto fail_type_mismatch;
+ CHECK_BUF(p, p_end, 8);
+ p_float = (uint8 *)&init_expr->u.f64;
+ for (i = 0; i < sizeof(float64); i++)
+ *p_float++ = *p++;
+ break;
+#if WASM_ENABLE_SIMD != 0
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+ case INIT_EXPR_TYPE_V128_CONST:
+ {
+ uint64 high, low;
+
+ if (type != VALUE_TYPE_V128)
+ goto fail_type_mismatch;
+
+ flag = read_uint8(p);
+ (void)flag;
+
+ CHECK_BUF(p, p_end, 16);
+ wasm_runtime_read_v128(p, &high, &low);
+ p += 16;
+
+ init_expr->u.v128.i64x2[0] = high;
+ init_expr->u.v128.i64x2[1] = low;
+ break;
+ }
+#endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) */
+#endif /* end of WASM_ENABLE_SIMD */
+#if WASM_ENABLE_REF_TYPES != 0
+ case INIT_EXPR_TYPE_FUNCREF_CONST:
+ {
+ if (type != VALUE_TYPE_FUNCREF)
+ goto fail_type_mismatch;
+ read_leb_uint32(p, p_end, init_expr->u.ref_index);
+ break;
+ }
+ case INIT_EXPR_TYPE_REFNULL_CONST:
+ {
+ uint8 reftype;
+
+ CHECK_BUF(p, p_end, 1);
+ reftype = read_uint8(p);
+ if (reftype != type)
+ goto fail_type_mismatch;
+
+ init_expr->u.ref_index = NULL_REF;
+ break;
+ }
+#endif /* WASM_ENABLE_REF_TYPES != 0 */
+ /* get_global */
+ case INIT_EXPR_TYPE_GET_GLOBAL:
+ read_leb_uint32(p, p_end, init_expr->u.global_index);
+ break;
+ default:
+ {
+ set_error_buf(error_buf, error_buf_size,
+ "illegal opcode "
+ "or constant expression required "
+ "or type mismatch");
+ goto fail;
+ }
+ }
+ CHECK_BUF(p, p_end, 1);
+ end_byte = read_uint8(p);
+ if (end_byte != 0x0b)
+ goto fail_type_mismatch;
+ *p_buf = p;
+ return true;
+
+fail_type_mismatch:
+ set_error_buf(error_buf, error_buf_size,
+ "type mismatch or constant expression required");
+fail:
+ return false;
+}
+
+static bool
+load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end, *p_org;
+ uint32 type_count, param_count, result_count, i, j;
+ uint32 param_cell_num, ret_cell_num;
+ uint64 total_size;
+ uint8 flag;
+ WASMType *type;
+
+ read_leb_uint32(p, p_end, type_count);
+
+ if (type_count) {
+ module->type_count = type_count;
+ total_size = sizeof(WASMType *) * (uint64)type_count;
+ if (!(module->types =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ for (i = 0; i < type_count; i++) {
+ CHECK_BUF(p, p_end, 1);
+ flag = read_uint8(p);
+ if (flag != 0x60) {
+ set_error_buf(error_buf, error_buf_size, "invalid type flag");
+ return false;
+ }
+
+ read_leb_uint32(p, p_end, param_count);
+
+ /* Resolve param count and result count firstly */
+ p_org = p;
+ CHECK_BUF(p, p_end, param_count);
+ p += param_count;
+ read_leb_uint32(p, p_end, result_count);
+ CHECK_BUF(p, p_end, result_count);
+ p = p_org;
+
+ if (param_count > UINT16_MAX || result_count > UINT16_MAX) {
+ set_error_buf(error_buf, error_buf_size,
+ "param count or result count too large");
+ return false;
+ }
+
+ total_size = offsetof(WASMType, types)
+ + sizeof(uint8) * (uint64)(param_count + result_count);
+ if (!(type = module->types[i] =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ /* Resolve param types and result types */
+ type->ref_count = 1;
+ type->param_count = (uint16)param_count;
+ type->result_count = (uint16)result_count;
+ for (j = 0; j < param_count; j++) {
+ CHECK_BUF(p, p_end, 1);
+ type->types[j] = read_uint8(p);
+ }
+ read_leb_uint32(p, p_end, result_count);
+ for (j = 0; j < result_count; j++) {
+ CHECK_BUF(p, p_end, 1);
+ type->types[param_count + j] = read_uint8(p);
+ }
+ for (j = 0; j < param_count + result_count; j++) {
+ if (!is_value_type(type->types[j])) {
+ set_error_buf(error_buf, error_buf_size,
+ "unknown value type");
+ return false;
+ }
+ }
+
+ param_cell_num = wasm_get_cell_num(type->types, param_count);
+ ret_cell_num =
+ wasm_get_cell_num(type->types + param_count, result_count);
+ if (param_cell_num > UINT16_MAX || ret_cell_num > UINT16_MAX) {
+ set_error_buf(error_buf, error_buf_size,
+ "param count or result count too large");
+ return false;
+ }
+ type->param_cell_num = (uint16)param_cell_num;
+ type->ret_cell_num = (uint16)ret_cell_num;
+
+ /* If there is already a same type created, use it instead */
+ for (j = 0; j < i; j++) {
+ if (wasm_type_equal(type, module->types[j])) {
+ if (module->types[j]->ref_count == UINT16_MAX) {
+ set_error_buf(error_buf, error_buf_size,
+ "wasm type's ref count too large");
+ return false;
+ }
+ destroy_wasm_type(type);
+ module->types[i] = module->types[j];
+ module->types[j]->ref_count++;
+ break;
+ }
+ }
+ }
+ }
+
+ if (p != p_end) {
+ set_error_buf(error_buf, error_buf_size, "section size mismatch");
+ return false;
+ }
+
+ LOG_VERBOSE("Load type section success.\n");
+ return true;
+fail:
+ return false;
+}
+
+static void
+adjust_table_max_size(uint32 init_size, uint32 max_size_flag, uint32 *max_size)
+{
+ uint32 default_max_size =
+ init_size * 2 > TABLE_MAX_SIZE ? init_size * 2 : TABLE_MAX_SIZE;
+
+ if (max_size_flag) {
+ /* module defines the table limitation */
+ bh_assert(init_size <= *max_size);
+
+ if (init_size < *max_size) {
+ *max_size =
+ *max_size < default_max_size ? *max_size : default_max_size;
+ }
+ }
+ else {
+ /* partial defined table limitation, gives a default value */
+ *max_size = default_max_size;
+ }
+}
+
+#if WASM_ENABLE_LIBC_WASI != 0 || WASM_ENABLE_MULTI_MODULE != 0
+/**
+ * Find export item of a module with export info:
+ * module name, field name and export kind
+ */
+static WASMExport *
+wasm_loader_find_export(const WASMModule *module, const char *module_name,
+ const char *field_name, uint8 export_kind,
+ char *error_buf, uint32 error_buf_size)
+{
+ WASMExport *export;
+ uint32 i;
+
+ for (i = 0, export = module->exports; i < module->export_count;
+ ++i, ++export) {
+ /**
+ * need to consider a scenario that different kinds of exports
+ * may have the same name, like
+ * (table (export "m1" "exported") 10 funcref)
+ * (memory (export "m1" "exported") 10)
+ **/
+ if (export->kind == export_kind && !strcmp(field_name, export->name)) {
+ break;
+ }
+ }
+
+ if (i == module->export_count) {
+ LOG_DEBUG("can not find an export %d named %s in the module %s",
+ export_kind, field_name, module_name);
+ set_error_buf(error_buf, error_buf_size,
+ "unknown import or incompatible import type");
+ return NULL;
+ }
+
+ (void)module_name;
+
+ /* since there is a validation in load_export_section(), it is for sure
+ * export->index is valid*/
+ return export;
+}
+#endif
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+static WASMFunction *
+wasm_loader_resolve_function(const char *module_name, const char *function_name,
+ const WASMType *expected_function_type,
+ char *error_buf, uint32 error_buf_size)
+{
+ WASMModuleCommon *module_reg;
+ WASMFunction *function = NULL;
+ WASMExport *export = NULL;
+ WASMModule *module = NULL;
+ WASMType *target_function_type = NULL;
+
+ module_reg = wasm_runtime_find_module_registered(module_name);
+ if (!module_reg || module_reg->module_type != Wasm_Module_Bytecode) {
+ LOG_DEBUG("can not find a module named %s for function %s", module_name,
+ function_name);
+ set_error_buf(error_buf, error_buf_size, "unknown import");
+ return NULL;
+ }
+
+ module = (WASMModule *)module_reg;
+ export =
+ wasm_loader_find_export(module, module_name, function_name,
+ EXPORT_KIND_FUNC, error_buf, error_buf_size);
+ if (!export) {
+ return NULL;
+ }
+
+ /* resolve function type and function */
+ if (export->index < module->import_function_count) {
+ target_function_type =
+ module->import_functions[export->index].u.function.func_type;
+ function = module->import_functions[export->index]
+ .u.function.import_func_linked;
+ }
+ else {
+ target_function_type =
+ module->functions[export->index - module->import_function_count]
+ ->func_type;
+ function =
+ module->functions[export->index - module->import_function_count];
+ }
+
+ /* check function type */
+ if (!wasm_type_equal(expected_function_type, target_function_type)) {
+ LOG_DEBUG("%s.%s failed the type check", module_name, function_name);
+ set_error_buf(error_buf, error_buf_size, "incompatible import type");
+ return NULL;
+ }
+
+ return function;
+}
+
+static WASMTable *
+wasm_loader_resolve_table(const char *module_name, const char *table_name,
+ uint32 init_size, uint32 max_size, char *error_buf,
+ uint32 error_buf_size)
+{
+ WASMModuleCommon *module_reg;
+ WASMTable *table = NULL;
+ WASMExport *export = NULL;
+ WASMModule *module = NULL;
+
+ module_reg = wasm_runtime_find_module_registered(module_name);
+ if (!module_reg || module_reg->module_type != Wasm_Module_Bytecode) {
+ LOG_DEBUG("can not find a module named %s for table", module_name);
+ set_error_buf(error_buf, error_buf_size, "unknown import");
+ return NULL;
+ }
+
+ module = (WASMModule *)module_reg;
+ export =
+ wasm_loader_find_export(module, module_name, table_name,
+ EXPORT_KIND_TABLE, error_buf, error_buf_size);
+ if (!export) {
+ return NULL;
+ }
+
+ /* resolve table and check the init/max size */
+ if (export->index < module->import_table_count) {
+ table =
+ module->import_tables[export->index].u.table.import_table_linked;
+ }
+ else {
+ table = &(module->tables[export->index - module->import_table_count]);
+ }
+ if (table->init_size < init_size || table->max_size > max_size) {
+ LOG_DEBUG("%s,%s failed type check(%d-%d), expected(%d-%d)",
+ module_name, table_name, table->init_size, table->max_size,
+ init_size, max_size);
+ set_error_buf(error_buf, error_buf_size, "incompatible import type");
+ return NULL;
+ }
+
+ return table;
+}
+
+static WASMMemory *
+wasm_loader_resolve_memory(const char *module_name, const char *memory_name,
+ uint32 init_page_count, uint32 max_page_count,
+ char *error_buf, uint32 error_buf_size)
+{
+ WASMModuleCommon *module_reg;
+ WASMMemory *memory = NULL;
+ WASMExport *export = NULL;
+ WASMModule *module = NULL;
+
+ module_reg = wasm_runtime_find_module_registered(module_name);
+ if (!module_reg || module_reg->module_type != Wasm_Module_Bytecode) {
+ LOG_DEBUG("can not find a module named %s for memory", module_name);
+ set_error_buf(error_buf, error_buf_size, "unknown import");
+ return NULL;
+ }
+
+ module = (WASMModule *)module_reg;
+ export =
+ wasm_loader_find_export(module, module_name, memory_name,
+ EXPORT_KIND_MEMORY, error_buf, error_buf_size);
+ if (!export) {
+ return NULL;
+ }
+
+ /* resolve memory and check the init/max page count */
+ if (export->index < module->import_memory_count) {
+ memory = module->import_memories[export->index]
+ .u.memory.import_memory_linked;
+ }
+ else {
+ memory =
+ &(module->memories[export->index - module->import_memory_count]);
+ }
+ if (memory->init_page_count < init_page_count
+ || memory->max_page_count > max_page_count) {
+ LOG_DEBUG("%s,%s failed type check(%d-%d), expected(%d-%d)",
+ module_name, memory_name, memory->init_page_count,
+ memory->max_page_count, init_page_count, max_page_count);
+ set_error_buf(error_buf, error_buf_size, "incompatible import type");
+ return NULL;
+ }
+ return memory;
+}
+
+static WASMGlobal *
+wasm_loader_resolve_global(const char *module_name, const char *global_name,
+ uint8 type, bool is_mutable, char *error_buf,
+ uint32 error_buf_size)
+{
+ WASMModuleCommon *module_reg;
+ WASMGlobal *global = NULL;
+ WASMExport *export = NULL;
+ WASMModule *module = NULL;
+
+ module_reg = wasm_runtime_find_module_registered(module_name);
+ if (!module_reg || module_reg->module_type != Wasm_Module_Bytecode) {
+ LOG_DEBUG("can not find a module named %s for global", module_name);
+ set_error_buf(error_buf, error_buf_size, "unknown import");
+ return NULL;
+ }
+
+ module = (WASMModule *)module_reg;
+ export =
+ wasm_loader_find_export(module, module_name, global_name,
+ EXPORT_KIND_GLOBAL, error_buf, error_buf_size);
+ if (!export) {
+ return NULL;
+ }
+
+ /* resolve and check the global */
+ if (export->index < module->import_global_count) {
+ global =
+ module->import_globals[export->index].u.global.import_global_linked;
+ }
+ else {
+ global =
+ &(module->globals[export->index - module->import_global_count]);
+ }
+ if (global->type != type || global->is_mutable != is_mutable) {
+ LOG_DEBUG("%s,%s failed type check(%d, %d), expected(%d, %d)",
+ module_name, global_name, global->type, global->is_mutable,
+ type, is_mutable);
+ set_error_buf(error_buf, error_buf_size, "incompatible import type");
+ return NULL;
+ }
+ return global;
+}
+
+static WASMModule *
+search_sub_module(const WASMModule *parent_module, const char *sub_module_name)
+{
+ WASMRegisteredModule *node =
+ bh_list_first_elem(parent_module->import_module_list);
+ while (node && strcmp(sub_module_name, node->module_name)) {
+ node = bh_list_elem_next(node);
+ }
+ return node ? (WASMModule *)node->module : NULL;
+}
+
+static bool
+register_sub_module(const WASMModule *parent_module,
+ const char *sub_module_name, WASMModule *sub_module)
+{
+ /* register sub_module into its parent sub module list */
+ WASMRegisteredModule *node = NULL;
+ bh_list_status ret;
+
+ if (search_sub_module(parent_module, sub_module_name)) {
+ LOG_DEBUG("%s has been registered in its parent", sub_module_name);
+ return true;
+ }
+
+ node = loader_malloc(sizeof(WASMRegisteredModule), NULL, 0);
+ if (!node) {
+ return false;
+ }
+
+ node->module_name = sub_module_name;
+ node->module = (WASMModuleCommon *)sub_module;
+ ret = bh_list_insert(parent_module->import_module_list, node);
+ bh_assert(BH_LIST_SUCCESS == ret);
+ (void)ret;
+ return true;
+}
+
+static WASMModule *
+load_depended_module(const WASMModule *parent_module,
+ const char *sub_module_name, char *error_buf,
+ uint32 error_buf_size)
+{
+ WASMModule *sub_module = NULL;
+ bool ret = false;
+ uint8 *buffer = NULL;
+ uint32 buffer_size = 0;
+ const module_reader reader = wasm_runtime_get_module_reader();
+ const module_destroyer destroyer = wasm_runtime_get_module_destroyer();
+
+ /* check the registered module list of the parent */
+ sub_module = search_sub_module(parent_module, sub_module_name);
+ if (sub_module) {
+ LOG_DEBUG("%s has been loaded before", sub_module_name);
+ return sub_module;
+ }
+
+ /* check the global registered module list */
+ sub_module =
+ (WASMModule *)wasm_runtime_find_module_registered(sub_module_name);
+ if (sub_module) {
+ LOG_DEBUG("%s has been loaded", sub_module_name);
+ goto register_sub_module;
+ }
+
+ LOG_VERBOSE("loading %s", sub_module_name);
+
+ if (!reader) {
+ set_error_buf_v(error_buf, error_buf_size,
+ "no sub module reader to load %s", sub_module_name);
+ return NULL;
+ }
+
+ /* start to maintain a loading module list */
+ ret = wasm_runtime_is_loading_module(sub_module_name);
+ if (ret) {
+ set_error_buf_v(error_buf, error_buf_size,
+ "found circular dependency on %s", sub_module_name);
+ return NULL;
+ }
+
+ ret = wasm_runtime_add_loading_module(sub_module_name, error_buf,
+ error_buf_size);
+ if (!ret) {
+ LOG_DEBUG("can not add %s into loading module list\n", sub_module_name);
+ return NULL;
+ }
+
+ ret = reader(sub_module_name, &buffer, &buffer_size);
+ if (!ret) {
+ LOG_DEBUG("read the file of %s failed", sub_module_name);
+ set_error_buf_v(error_buf, error_buf_size, "unknown import",
+ sub_module_name);
+ goto delete_loading_module;
+ }
+
+ sub_module =
+ wasm_loader_load(buffer, buffer_size, false, error_buf, error_buf_size);
+ if (!sub_module) {
+ LOG_DEBUG("error: can not load the sub_module %s", sub_module_name);
+ /* others will be destroyed in runtime_destroy() */
+ goto destroy_file_buffer;
+ }
+
+ wasm_runtime_delete_loading_module(sub_module_name);
+
+ /* register on a global list */
+ ret = wasm_runtime_register_module_internal(
+ sub_module_name, (WASMModuleCommon *)sub_module, buffer, buffer_size,
+ error_buf, error_buf_size);
+ if (!ret) {
+ LOG_DEBUG("error: can not register module %s globally\n",
+ sub_module_name);
+ /* others will be unloaded in runtime_destroy() */
+ goto unload_module;
+ }
+
+ /* register into its parent list */
+register_sub_module:
+ ret = register_sub_module(parent_module, sub_module_name, sub_module);
+ if (!ret) {
+ set_error_buf_v(error_buf, error_buf_size,
+ "failed to register sub module %s", sub_module_name);
+ /* since it is in the global module list, no need to
+ * unload the module. the runtime_destroy() will do it
+ */
+ return NULL;
+ }
+
+ return sub_module;
+
+unload_module:
+ wasm_loader_unload(sub_module);
+
+destroy_file_buffer:
+ if (destroyer) {
+ destroyer(buffer, buffer_size);
+ }
+ else {
+ LOG_WARNING("need to release the reading buffer of %s manually",
+ sub_module_name);
+ }
+
+delete_loading_module:
+ wasm_runtime_delete_loading_module(sub_module_name);
+ return NULL;
+}
+#endif /* end of WASM_ENABLE_MULTI_MODULE */
+
+static bool
+load_function_import(const uint8 **p_buf, const uint8 *buf_end,
+ const WASMModule *parent_module,
+ const char *sub_module_name, const char *function_name,
+ WASMFunctionImport *function, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end;
+ uint32 declare_type_index = 0;
+ WASMType *declare_func_type = NULL;
+ WASMFunction *linked_func = NULL;
+#if WASM_ENABLE_MULTI_MODULE != 0
+ WASMModule *sub_module = NULL;
+#endif
+ const char *linked_signature = NULL;
+ void *linked_attachment = NULL;
+ bool linked_call_conv_raw = false;
+ bool is_native_symbol = false;
+
+ read_leb_uint32(p, p_end, declare_type_index);
+ *p_buf = p;
+
+ if (declare_type_index >= parent_module->type_count) {
+ set_error_buf(error_buf, error_buf_size, "unknown type");
+ return false;
+ }
+
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+ declare_type_index = wasm_get_smallest_type_idx(
+ parent_module->types, parent_module->type_count, declare_type_index);
+#endif
+
+ declare_func_type = parent_module->types[declare_type_index];
+
+ /* lookup registered native symbols first */
+ linked_func = wasm_native_resolve_symbol(
+ sub_module_name, function_name, declare_func_type, &linked_signature,
+ &linked_attachment, &linked_call_conv_raw);
+ if (linked_func) {
+ is_native_symbol = true;
+ }
+#if WASM_ENABLE_MULTI_MODULE != 0
+ else {
+ if (!wasm_runtime_is_built_in_module(sub_module_name)) {
+ sub_module = load_depended_module(parent_module, sub_module_name,
+ error_buf, error_buf_size);
+ if (!sub_module) {
+ return false;
+ }
+ }
+ linked_func = wasm_loader_resolve_function(
+ sub_module_name, function_name, declare_func_type, error_buf,
+ error_buf_size);
+ }
+#endif
+
+ function->module_name = (char *)sub_module_name;
+ function->field_name = (char *)function_name;
+ function->func_type = declare_func_type;
+ /* func_ptr_linked is for native registered symbol */
+ function->func_ptr_linked = is_native_symbol ? linked_func : NULL;
+ function->signature = linked_signature;
+ function->attachment = linked_attachment;
+ function->call_conv_raw = linked_call_conv_raw;
+#if WASM_ENABLE_MULTI_MODULE != 0
+ function->import_module = is_native_symbol ? NULL : sub_module;
+ function->import_func_linked = is_native_symbol ? NULL : linked_func;
+#endif
+ return true;
+fail:
+ return false;
+}
+
+static bool
+check_table_max_size(uint32 init_size, uint32 max_size, char *error_buf,
+ uint32 error_buf_size)
+{
+ if (max_size < init_size) {
+ set_error_buf(error_buf, error_buf_size,
+ "size minimum must not be greater than maximum");
+ return false;
+ }
+ return true;
+}
+
+static bool
+load_table_import(const uint8 **p_buf, const uint8 *buf_end,
+ WASMModule *parent_module, const char *sub_module_name,
+ const char *table_name, WASMTableImport *table,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end;
+ uint32 declare_elem_type = 0, declare_max_size_flag = 0,
+ declare_init_size = 0, declare_max_size = 0;
+#if WASM_ENABLE_MULTI_MODULE != 0
+ WASMModule *sub_module = NULL;
+ WASMTable *linked_table = NULL;
+#endif
+
+ CHECK_BUF(p, p_end, 1);
+ /* 0x70 or 0x6F */
+ declare_elem_type = read_uint8(p);
+ if (VALUE_TYPE_FUNCREF != declare_elem_type
+#if WASM_ENABLE_REF_TYPES != 0
+ && VALUE_TYPE_EXTERNREF != declare_elem_type
+#endif
+ ) {
+ set_error_buf(error_buf, error_buf_size, "incompatible import type");
+ return false;
+ }
+
+ read_leb_uint32(p, p_end, declare_max_size_flag);
+ if (declare_max_size_flag > 1) {
+ set_error_buf(error_buf, error_buf_size, "integer too large");
+ return false;
+ }
+
+ read_leb_uint32(p, p_end, declare_init_size);
+
+ if (declare_max_size_flag) {
+ read_leb_uint32(p, p_end, declare_max_size);
+ if (!check_table_max_size(declare_init_size, declare_max_size,
+ error_buf, error_buf_size))
+ return false;
+ }
+
+ adjust_table_max_size(declare_init_size, declare_max_size_flag,
+ &declare_max_size);
+
+ *p_buf = p;
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+ if (!wasm_runtime_is_built_in_module(sub_module_name)) {
+ sub_module = load_depended_module(parent_module, sub_module_name,
+ error_buf, error_buf_size);
+ if (!sub_module) {
+ return false;
+ }
+
+ linked_table = wasm_loader_resolve_table(
+ sub_module_name, table_name, declare_init_size, declare_max_size,
+ error_buf, error_buf_size);
+ if (!linked_table) {
+ return false;
+ }
+
+ /* reset with linked table limit */
+ declare_elem_type = linked_table->elem_type;
+ declare_init_size = linked_table->init_size;
+ declare_max_size = linked_table->max_size;
+ declare_max_size_flag = linked_table->flags;
+ table->import_table_linked = linked_table;
+ table->import_module = sub_module;
+ }
+#endif /* WASM_ENABLE_MULTI_MODULE != 0 */
+
+ /* (table (export "table") 10 20 funcref) */
+ /* we need this section working in wamrc */
+ if (!strcmp("spectest", sub_module_name)) {
+ const uint32 spectest_table_init_size = 10;
+ const uint32 spectest_table_max_size = 20;
+
+ if (strcmp("table", table_name)) {
+ set_error_buf(error_buf, error_buf_size,
+ "incompatible import type or unknown import");
+ return false;
+ }
+
+ if (declare_init_size > spectest_table_init_size
+ || declare_max_size < spectest_table_max_size) {
+ set_error_buf(error_buf, error_buf_size,
+ "incompatible import type");
+ return false;
+ }
+
+ declare_init_size = spectest_table_init_size;
+ declare_max_size = spectest_table_max_size;
+ }
+
+ /* now we believe all declaration are ok */
+ table->elem_type = declare_elem_type;
+ table->init_size = declare_init_size;
+ table->flags = declare_max_size_flag;
+ table->max_size = declare_max_size;
+
+ (void)parent_module;
+ return true;
+fail:
+ return false;
+}
+
+static bool
+check_memory_init_size(uint32 init_size, char *error_buf, uint32 error_buf_size)
+{
+ if (init_size > DEFAULT_MAX_PAGES) {
+ set_error_buf(error_buf, error_buf_size,
+ "memory size must be at most 65536 pages (4GiB)");
+ return false;
+ }
+ return true;
+}
+
+static bool
+check_memory_max_size(uint32 init_size, uint32 max_size, char *error_buf,
+ uint32 error_buf_size)
+{
+ if (max_size < init_size) {
+ set_error_buf(error_buf, error_buf_size,
+ "size minimum must not be greater than maximum");
+ return false;
+ }
+
+ if (max_size > DEFAULT_MAX_PAGES) {
+ set_error_buf(error_buf, error_buf_size,
+ "memory size must be at most 65536 pages (4GiB)");
+ return false;
+ }
+ return true;
+}
+
+static bool
+load_memory_import(const uint8 **p_buf, const uint8 *buf_end,
+ WASMModule *parent_module, const char *sub_module_name,
+ const char *memory_name, WASMMemoryImport *memory,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end;
+#if WASM_ENABLE_APP_FRAMEWORK != 0
+ uint32 pool_size = wasm_runtime_memory_pool_size();
+ uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT
+ / DEFAULT_NUM_BYTES_PER_PAGE;
+#else
+ uint32 max_page_count = DEFAULT_MAX_PAGES;
+#endif /* WASM_ENABLE_APP_FRAMEWORK */
+ uint32 declare_max_page_count_flag = 0;
+ uint32 declare_init_page_count = 0;
+ uint32 declare_max_page_count = 0;
+#if WASM_ENABLE_MULTI_MODULE != 0
+ WASMModule *sub_module = NULL;
+ WASMMemory *linked_memory = NULL;
+#endif
+
+ read_leb_uint32(p, p_end, declare_max_page_count_flag);
+ read_leb_uint32(p, p_end, declare_init_page_count);
+ if (!check_memory_init_size(declare_init_page_count, error_buf,
+ error_buf_size)) {
+ return false;
+ }
+
+ if (declare_max_page_count_flag & 1) {
+ read_leb_uint32(p, p_end, declare_max_page_count);
+ if (!check_memory_max_size(declare_init_page_count,
+ declare_max_page_count, error_buf,
+ error_buf_size)) {
+ return false;
+ }
+ if (declare_max_page_count > max_page_count) {
+ declare_max_page_count = max_page_count;
+ }
+ }
+ else {
+ /* Limit the maximum memory size to max_page_count */
+ declare_max_page_count = max_page_count;
+ }
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+ if (!wasm_runtime_is_built_in_module(sub_module_name)) {
+ sub_module = load_depended_module(parent_module, sub_module_name,
+ error_buf, error_buf_size);
+ if (!sub_module) {
+ return false;
+ }
+
+ linked_memory = wasm_loader_resolve_memory(
+ sub_module_name, memory_name, declare_init_page_count,
+ declare_max_page_count, error_buf, error_buf_size);
+ if (!linked_memory) {
+ return false;
+ }
+
+ /**
+ * reset with linked memory limit
+ */
+ memory->import_module = sub_module;
+ memory->import_memory_linked = linked_memory;
+ declare_init_page_count = linked_memory->init_page_count;
+ declare_max_page_count = linked_memory->max_page_count;
+ }
+#endif
+
+ /* (memory (export "memory") 1 2) */
+ if (!strcmp("spectest", sub_module_name)) {
+ uint32 spectest_memory_init_page = 1;
+ uint32 spectest_memory_max_page = 2;
+
+ if (strcmp("memory", memory_name)) {
+ set_error_buf(error_buf, error_buf_size,
+ "incompatible import type or unknown import");
+ return false;
+ }
+
+ if (declare_init_page_count > spectest_memory_init_page
+ || declare_max_page_count < spectest_memory_max_page) {
+ set_error_buf(error_buf, error_buf_size,
+ "incompatible import type");
+ return false;
+ }
+
+ declare_init_page_count = spectest_memory_init_page;
+ declare_max_page_count = spectest_memory_max_page;
+ }
+
+ /* now we believe all declaration are ok */
+ memory->flags = declare_max_page_count_flag;
+ memory->init_page_count = declare_init_page_count;
+ memory->max_page_count = declare_max_page_count;
+ memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE;
+
+ *p_buf = p;
+
+ (void)parent_module;
+ return true;
+fail:
+ return false;
+}
+
+static bool
+load_global_import(const uint8 **p_buf, const uint8 *buf_end,
+ const WASMModule *parent_module, char *sub_module_name,
+ char *global_name, WASMGlobalImport *global, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end;
+ uint8 declare_type = 0;
+ uint8 declare_mutable = 0;
+#if WASM_ENABLE_MULTI_MODULE != 0
+ WASMModule *sub_module = NULL;
+ WASMGlobal *linked_global = NULL;
+#endif
+ bool ret = false;
+
+ CHECK_BUF(p, p_end, 2);
+ declare_type = read_uint8(p);
+ declare_mutable = read_uint8(p);
+ *p_buf = p;
+
+ if (declare_mutable >= 2) {
+ set_error_buf(error_buf, error_buf_size, "invalid mutability");
+ return false;
+ }
+
+#if WASM_ENABLE_LIBC_BUILTIN != 0
+ ret = wasm_native_lookup_libc_builtin_global(sub_module_name, global_name,
+ global);
+ if (ret) {
+ if (global->type != declare_type
+ || global->is_mutable != declare_mutable) {
+ set_error_buf(error_buf, error_buf_size,
+ "incompatible import type");
+ return false;
+ }
+ global->is_linked = true;
+ }
+#endif
+#if WASM_ENABLE_MULTI_MODULE != 0
+ if (!global->is_linked
+ && !wasm_runtime_is_built_in_module(sub_module_name)) {
+ sub_module = load_depended_module(parent_module, sub_module_name,
+ error_buf, error_buf_size);
+ if (!sub_module) {
+ return false;
+ }
+
+ /* check sub modules */
+ linked_global = wasm_loader_resolve_global(
+ sub_module_name, global_name, declare_type, declare_mutable,
+ error_buf, error_buf_size);
+ if (linked_global) {
+ global->import_module = sub_module;
+ global->import_global_linked = linked_global;
+ global->is_linked = true;
+ }
+ }
+#endif
+
+ global->module_name = sub_module_name;
+ global->field_name = global_name;
+ global->type = declare_type;
+ global->is_mutable = (declare_mutable == 1);
+
+ (void)parent_module;
+ (void)ret;
+ return true;
+fail:
+ return false;
+}
+
+static bool
+load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end, *p_org;
+
+ CHECK_BUF(p, p_end, 1);
+ /* 0x70 or 0x6F */
+ table->elem_type = read_uint8(p);
+ if (VALUE_TYPE_FUNCREF != table->elem_type
+#if WASM_ENABLE_REF_TYPES != 0
+ && VALUE_TYPE_EXTERNREF != table->elem_type
+#endif
+ ) {
+ set_error_buf(error_buf, error_buf_size, "incompatible import type");
+ return false;
+ }
+
+ p_org = p;
+ read_leb_uint32(p, p_end, table->flags);
+#if WASM_ENABLE_SHARED_MEMORY == 0
+ if (p - p_org > 1) {
+ set_error_buf(error_buf, error_buf_size,
+ "integer representation too long");
+ return false;
+ }
+ if (table->flags > 1) {
+ set_error_buf(error_buf, error_buf_size, "integer too large");
+ return false;
+ }
+#else
+ if (p - p_org > 1) {
+ set_error_buf(error_buf, error_buf_size, "invalid limits flags");
+ return false;
+ }
+ if (table->flags == 2) {
+ set_error_buf(error_buf, error_buf_size, "tables cannot be shared");
+ return false;
+ }
+ if (table->flags > 1) {
+ set_error_buf(error_buf, error_buf_size, "invalid limits flags");
+ return false;
+ }
+#endif
+
+ read_leb_uint32(p, p_end, table->init_size);
+
+ if (table->flags) {
+ read_leb_uint32(p, p_end, table->max_size);
+ if (!check_table_max_size(table->init_size, table->max_size, error_buf,
+ error_buf_size))
+ return false;
+ }
+
+ adjust_table_max_size(table->init_size, table->flags, &table->max_size);
+
+ *p_buf = p;
+ return true;
+fail:
+ return false;
+}
+
+static bool
+load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end, *p_org;
+#if WASM_ENABLE_APP_FRAMEWORK != 0
+ uint32 pool_size = wasm_runtime_memory_pool_size();
+ uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT
+ / DEFAULT_NUM_BYTES_PER_PAGE;
+#else
+ uint32 max_page_count = DEFAULT_MAX_PAGES;
+#endif
+
+ p_org = p;
+ read_leb_uint32(p, p_end, memory->flags);
+#if WASM_ENABLE_SHARED_MEMORY == 0
+ if (p - p_org > 1) {
+ set_error_buf(error_buf, error_buf_size,
+ "integer representation too long");
+ return false;
+ }
+ if (memory->flags > 1) {
+ set_error_buf(error_buf, error_buf_size, "integer too large");
+ return false;
+ }
+#else
+ if (p - p_org > 1) {
+ set_error_buf(error_buf, error_buf_size, "invalid limits flags");
+ return false;
+ }
+ if (memory->flags > 3) {
+ set_error_buf(error_buf, error_buf_size, "invalid limits flags");
+ return false;
+ }
+ else if (memory->flags == 2) {
+ set_error_buf(error_buf, error_buf_size,
+ "shared memory must have maximum");
+ return false;
+ }
+#endif
+
+ read_leb_uint32(p, p_end, memory->init_page_count);
+ if (!check_memory_init_size(memory->init_page_count, error_buf,
+ error_buf_size))
+ return false;
+
+ if (memory->flags & 1) {
+ read_leb_uint32(p, p_end, memory->max_page_count);
+ if (!check_memory_max_size(memory->init_page_count,
+ memory->max_page_count, error_buf,
+ error_buf_size))
+ return false;
+ if (memory->max_page_count > max_page_count)
+ memory->max_page_count = max_page_count;
+ }
+ else {
+ /* Limit the maximum memory size to max_page_count */
+ memory->max_page_count = max_page_count;
+ }
+
+ memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE;
+
+ *p_buf = p;
+ return true;
+fail:
+ return false;
+}
+
+static bool
+load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
+ bool is_load_from_file_buf, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end, *p_old;
+ uint32 import_count, name_len, type_index, i, u32, flags;
+ uint64 total_size;
+ WASMImport *import;
+ WASMImport *import_functions = NULL, *import_tables = NULL;
+ WASMImport *import_memories = NULL, *import_globals = NULL;
+ char *sub_module_name, *field_name;
+ uint8 u8, kind;
+
+ read_leb_uint32(p, p_end, import_count);
+
+ if (import_count) {
+ module->import_count = import_count;
+ total_size = sizeof(WASMImport) * (uint64)import_count;
+ if (!(module->imports =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ p_old = p;
+
+ /* Scan firstly to get import count of each type */
+ for (i = 0; i < import_count; i++) {
+ /* module name */
+ read_leb_uint32(p, p_end, name_len);
+ CHECK_BUF(p, p_end, name_len);
+ p += name_len;
+
+ /* field name */
+ read_leb_uint32(p, p_end, name_len);
+ CHECK_BUF(p, p_end, name_len);
+ p += name_len;
+
+ CHECK_BUF(p, p_end, 1);
+ /* 0x00/0x01/0x02/0x03 */
+ kind = read_uint8(p);
+
+ switch (kind) {
+ case IMPORT_KIND_FUNC: /* import function */
+ read_leb_uint32(p, p_end, type_index);
+ module->import_function_count++;
+ break;
+
+ case IMPORT_KIND_TABLE: /* import table */
+ CHECK_BUF(p, p_end, 1);
+ /* 0x70 */
+ u8 = read_uint8(p);
+ read_leb_uint32(p, p_end, flags);
+ read_leb_uint32(p, p_end, u32);
+ if (flags & 1)
+ read_leb_uint32(p, p_end, u32);
+ module->import_table_count++;
+
+#if WASM_ENABLE_REF_TYPES == 0
+ if (module->import_table_count > 1) {
+ set_error_buf(error_buf, error_buf_size,
+ "multiple tables");
+ return false;
+ }
+#endif
+ break;
+
+ case IMPORT_KIND_MEMORY: /* import memory */
+ read_leb_uint32(p, p_end, flags);
+ read_leb_uint32(p, p_end, u32);
+ if (flags & 1)
+ read_leb_uint32(p, p_end, u32);
+ module->import_memory_count++;
+ if (module->import_memory_count > 1) {
+ set_error_buf(error_buf, error_buf_size,
+ "multiple memories");
+ return false;
+ }
+ break;
+
+ case IMPORT_KIND_GLOBAL: /* import global */
+ CHECK_BUF(p, p_end, 2);
+ p += 2;
+ module->import_global_count++;
+ break;
+
+ default:
+ set_error_buf(error_buf, error_buf_size,
+ "invalid import kind");
+ return false;
+ }
+ }
+
+ if (module->import_function_count)
+ import_functions = module->import_functions = module->imports;
+ if (module->import_table_count)
+ import_tables = module->import_tables =
+ module->imports + module->import_function_count;
+ if (module->import_memory_count)
+ import_memories = module->import_memories =
+ module->imports + module->import_function_count
+ + module->import_table_count;
+ if (module->import_global_count)
+ import_globals = module->import_globals =
+ module->imports + module->import_function_count
+ + module->import_table_count + module->import_memory_count;
+
+ p = p_old;
+
+ /* Scan again to resolve the data */
+ for (i = 0; i < import_count; i++) {
+ /* load module name */
+ read_leb_uint32(p, p_end, name_len);
+ CHECK_BUF(p, p_end, name_len);
+ if (!(sub_module_name = const_str_list_insert(
+ p, name_len, module, is_load_from_file_buf, error_buf,
+ error_buf_size))) {
+ return false;
+ }
+ p += name_len;
+
+ /* load field name */
+ read_leb_uint32(p, p_end, name_len);
+ CHECK_BUF(p, p_end, name_len);
+ if (!(field_name = const_str_list_insert(
+ p, name_len, module, is_load_from_file_buf, error_buf,
+ error_buf_size))) {
+ return false;
+ }
+ p += name_len;
+
+ CHECK_BUF(p, p_end, 1);
+ /* 0x00/0x01/0x02/0x03 */
+ kind = read_uint8(p);
+
+ switch (kind) {
+ case IMPORT_KIND_FUNC: /* import function */
+ bh_assert(import_functions);
+ import = import_functions++;
+ if (!load_function_import(
+ &p, p_end, module, sub_module_name, field_name,
+ &import->u.function, error_buf, error_buf_size)) {
+ return false;
+ }
+ break;
+
+ case IMPORT_KIND_TABLE: /* import table */
+ bh_assert(import_tables);
+ import = import_tables++;
+ if (!load_table_import(&p, p_end, module, sub_module_name,
+ field_name, &import->u.table,
+ error_buf, error_buf_size)) {
+ LOG_DEBUG("can not import such a table (%s,%s)",
+ sub_module_name, field_name);
+ return false;
+ }
+ break;
+
+ case IMPORT_KIND_MEMORY: /* import memory */
+ bh_assert(import_memories);
+ import = import_memories++;
+ if (!load_memory_import(&p, p_end, module, sub_module_name,
+ field_name, &import->u.memory,
+ error_buf, error_buf_size)) {
+ return false;
+ }
+ break;
+
+ case IMPORT_KIND_GLOBAL: /* import global */
+ bh_assert(import_globals);
+ import = import_globals++;
+ if (!load_global_import(&p, p_end, module, sub_module_name,
+ field_name, &import->u.global,
+ error_buf, error_buf_size)) {
+ return false;
+ }
+ break;
+
+ default:
+ set_error_buf(error_buf, error_buf_size,
+ "invalid import kind");
+ return false;
+ }
+ import->kind = kind;
+ import->u.names.module_name = sub_module_name;
+ import->u.names.field_name = field_name;
+ }
+
+#if WASM_ENABLE_LIBC_WASI != 0
+ import = module->import_functions;
+ for (i = 0; i < module->import_function_count; i++, import++) {
+ if (!strcmp(import->u.names.module_name, "wasi_unstable")
+ || !strcmp(import->u.names.module_name,
+ "wasi_snapshot_preview1")) {
+ module->import_wasi_api = true;
+ break;
+ }
+ }
+#endif
+ }
+
+ if (p != p_end) {
+ set_error_buf(error_buf, error_buf_size, "section size mismatch");
+ return false;
+ }
+
+ LOG_VERBOSE("Load import section success.\n");
+ (void)u8;
+ (void)u32;
+ (void)type_index;
+ return true;
+fail:
+ return false;
+}
+
+static bool
+init_function_local_offsets(WASMFunction *func, char *error_buf,
+ uint32 error_buf_size)
+{
+ WASMType *param_type = func->func_type;
+ uint32 param_count = param_type->param_count;
+ uint8 *param_types = param_type->types;
+ uint32 local_count = func->local_count;
+ uint8 *local_types = func->local_types;
+ uint32 i, local_offset = 0;
+ uint64 total_size = sizeof(uint16) * ((uint64)param_count + local_count);
+
+ /*
+ * Only allocate memory when total_size is not 0,
+ * or the return value of malloc(0) might be NULL on some platforms,
+ * which causes wasm loader return false.
+ */
+ if (total_size > 0
+ && !(func->local_offsets =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ for (i = 0; i < param_count; i++) {
+ func->local_offsets[i] = (uint16)local_offset;
+ local_offset += wasm_value_type_cell_num(param_types[i]);
+ }
+
+ for (i = 0; i < local_count; i++) {
+ func->local_offsets[param_count + i] = (uint16)local_offset;
+ local_offset += wasm_value_type_cell_num(local_types[i]);
+ }
+
+ bh_assert(local_offset == func->param_cell_num + func->local_cell_num);
+ return true;
+}
+
+static bool
+load_function_section(const uint8 *buf, const uint8 *buf_end,
+ const uint8 *buf_code, const uint8 *buf_code_end,
+ WASMModule *module, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ const uint8 *p_code = buf_code, *p_code_end, *p_code_save;
+ uint32 func_count;
+ uint64 total_size;
+ uint32 code_count = 0, code_size, type_index, i, j, k, local_type_index;
+ uint32 local_count, local_set_count, sub_local_count, local_cell_num;
+ uint8 type;
+ WASMFunction *func;
+
+ read_leb_uint32(p, p_end, func_count);
+
+ if (buf_code)
+ read_leb_uint32(p_code, buf_code_end, code_count);
+
+ if (func_count != code_count) {
+ set_error_buf(error_buf, error_buf_size,
+ "function and code section have inconsistent lengths or "
+ "unexpected end");
+ return false;
+ }
+
+ if (func_count) {
+ module->function_count = func_count;
+ total_size = sizeof(WASMFunction *) * (uint64)func_count;
+ if (!(module->functions =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ for (i = 0; i < func_count; i++) {
+ /* Resolve function type */
+ read_leb_uint32(p, p_end, type_index);
+ if (type_index >= module->type_count) {
+ set_error_buf(error_buf, error_buf_size, "unknown type");
+ return false;
+ }
+
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+ type_index = wasm_get_smallest_type_idx(
+ module->types, module->type_count, type_index);
+#endif
+
+ read_leb_uint32(p_code, buf_code_end, code_size);
+ if (code_size == 0 || p_code + code_size > buf_code_end) {
+ set_error_buf(error_buf, error_buf_size,
+ "invalid function code size");
+ return false;
+ }
+
+ /* Resolve local set count */
+ p_code_end = p_code + code_size;
+ local_count = 0;
+ read_leb_uint32(p_code, buf_code_end, local_set_count);
+ p_code_save = p_code;
+
+ /* Calculate total local count */
+ for (j = 0; j < local_set_count; j++) {
+ read_leb_uint32(p_code, buf_code_end, sub_local_count);
+ if (sub_local_count > UINT32_MAX - local_count) {
+ set_error_buf(error_buf, error_buf_size, "too many locals");
+ return false;
+ }
+ CHECK_BUF(p_code, buf_code_end, 1);
+ /* 0x7F/0x7E/0x7D/0x7C */
+ type = read_uint8(p_code);
+ local_count += sub_local_count;
+ }
+
+ /* Alloc memory, layout: function structure + local types */
+ code_size = (uint32)(p_code_end - p_code);
+
+ total_size = sizeof(WASMFunction) + (uint64)local_count;
+ if (!(func = module->functions[i] =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ /* Set function type, local count, code size and code body */
+ func->func_type = module->types[type_index];
+ func->local_count = local_count;
+ if (local_count > 0)
+ func->local_types = (uint8 *)func + sizeof(WASMFunction);
+ func->code_size = code_size;
+ /*
+ * we shall make a copy of code body [p_code, p_code + code_size]
+ * when we are worrying about inappropriate releasing behaviour.
+ * all code bodies are actually in a buffer which user allocates in
+ * his embedding environment and we don't have power on them.
+ * it will be like:
+ * code_body_cp = malloc(code_size);
+ * memcpy(code_body_cp, p_code, code_size);
+ * func->code = code_body_cp;
+ */
+ func->code = (uint8 *)p_code;
+
+ /* Load each local type */
+ p_code = p_code_save;
+ local_type_index = 0;
+ for (j = 0; j < local_set_count; j++) {
+ read_leb_uint32(p_code, buf_code_end, sub_local_count);
+ /* Note: sub_local_count is allowed to be 0 */
+ if (local_type_index > UINT32_MAX - sub_local_count
+ || local_type_index + sub_local_count > local_count) {
+ set_error_buf(error_buf, error_buf_size,
+ "invalid local count");
+ return false;
+ }
+ CHECK_BUF(p_code, buf_code_end, 1);
+ /* 0x7F/0x7E/0x7D/0x7C */
+ type = read_uint8(p_code);
+ if (!is_value_type(type)) {
+ if (type == VALUE_TYPE_V128)
+ set_error_buf(error_buf, error_buf_size,
+ "v128 value type requires simd feature");
+ else if (type == VALUE_TYPE_FUNCREF
+ || type == VALUE_TYPE_EXTERNREF)
+ set_error_buf(error_buf, error_buf_size,
+ "ref value type requires "
+ "reference types feature");
+ else
+ set_error_buf_v(error_buf, error_buf_size,
+ "invalid local type 0x%02X", type);
+ return false;
+ }
+ for (k = 0; k < sub_local_count; k++) {
+ func->local_types[local_type_index++] = type;
+ }
+ }
+
+ func->param_cell_num = func->func_type->param_cell_num;
+ func->ret_cell_num = func->func_type->ret_cell_num;
+ local_cell_num =
+ wasm_get_cell_num(func->local_types, func->local_count);
+
+ if (local_cell_num > UINT16_MAX) {
+ set_error_buf(error_buf, error_buf_size,
+ "local count too large");
+ return false;
+ }
+
+ func->local_cell_num = (uint16)local_cell_num;
+
+ if (!init_function_local_offsets(func, error_buf, error_buf_size))
+ return false;
+
+ p_code = p_code_end;
+ }
+ }
+
+ if (p != p_end) {
+ set_error_buf(error_buf, error_buf_size, "section size mismatch");
+ return false;
+ }
+
+ LOG_VERBOSE("Load function section success.\n");
+ return true;
+fail:
+ return false;
+}
+
+static bool
+check_function_index(const WASMModule *module, uint32 function_index,
+ char *error_buf, uint32 error_buf_size)
+{
+ if (function_index
+ >= module->import_function_count + module->function_count) {
+ set_error_buf_v(error_buf, error_buf_size, "unknown function %d",
+ function_index);
+ return false;
+ }
+ return true;
+}
+
+static bool
+load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 table_count, i;
+ uint64 total_size;
+ WASMTable *table;
+
+ read_leb_uint32(p, p_end, table_count);
+#if WASM_ENABLE_REF_TYPES == 0
+ if (module->import_table_count + table_count > 1) {
+ /* a total of one table is allowed */
+ set_error_buf(error_buf, error_buf_size, "multiple tables");
+ return false;
+ }
+#endif
+
+ if (table_count) {
+ module->table_count = table_count;
+ total_size = sizeof(WASMTable) * (uint64)table_count;
+ if (!(module->tables =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ /* load each table */
+ table = module->tables;
+ for (i = 0; i < table_count; i++, table++)
+ if (!load_table(&p, p_end, table, error_buf, error_buf_size))
+ return false;
+ }
+
+ if (p != p_end) {
+ set_error_buf(error_buf, error_buf_size, "section size mismatch");
+ return false;
+ }
+
+ LOG_VERBOSE("Load table section success.\n");
+ return true;
+fail:
+ return false;
+}
+
+static bool
+load_memory_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 memory_count, i;
+ uint64 total_size;
+ WASMMemory *memory;
+
+ read_leb_uint32(p, p_end, memory_count);
+ /* a total of one memory is allowed */
+ if (module->import_memory_count + memory_count > 1) {
+ set_error_buf(error_buf, error_buf_size, "multiple memories");
+ return false;
+ }
+
+ if (memory_count) {
+ module->memory_count = memory_count;
+ total_size = sizeof(WASMMemory) * (uint64)memory_count;
+ if (!(module->memories =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ /* load each memory */
+ memory = module->memories;
+ for (i = 0; i < memory_count; i++, memory++)
+ if (!load_memory(&p, p_end, memory, error_buf, error_buf_size))
+ return false;
+ }
+
+ if (p != p_end) {
+ set_error_buf(error_buf, error_buf_size, "section size mismatch");
+ return false;
+ }
+
+ LOG_VERBOSE("Load memory section success.\n");
+ return true;
+fail:
+ return false;
+}
+
+static bool
+load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 global_count, i;
+ uint64 total_size;
+ WASMGlobal *global;
+ uint8 mutable;
+
+ read_leb_uint32(p, p_end, global_count);
+
+ if (global_count) {
+ module->global_count = global_count;
+ total_size = sizeof(WASMGlobal) * (uint64)global_count;
+ if (!(module->globals =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ global = module->globals;
+
+ for (i = 0; i < global_count; i++, global++) {
+ CHECK_BUF(p, p_end, 2);
+ global->type = read_uint8(p);
+ mutable = read_uint8(p);
+ if (mutable >= 2) {
+ set_error_buf(error_buf, error_buf_size, "invalid mutability");
+ return false;
+ }
+ global->is_mutable = mutable ? true : false;
+
+ /* initialize expression */
+ if (!load_init_expr(&p, p_end, &(global->init_expr), global->type,
+ error_buf, error_buf_size))
+ return false;
+
+ if (INIT_EXPR_TYPE_GET_GLOBAL == global->init_expr.init_expr_type) {
+ /**
+ * Currently, constant expressions occurring as initializers
+ * of globals are further constrained in that contained
+ * global.get instructions are
+ * only allowed to refer to imported globals.
+ */
+ uint32 target_global_index = global->init_expr.u.global_index;
+ if (target_global_index >= module->import_global_count) {
+ set_error_buf(error_buf, error_buf_size, "unknown global");
+ return false;
+ }
+ }
+ else if (INIT_EXPR_TYPE_FUNCREF_CONST
+ == global->init_expr.init_expr_type) {
+ if (!check_function_index(module, global->init_expr.u.ref_index,
+ error_buf, error_buf_size)) {
+ return false;
+ }
+ }
+ }
+ }
+
+ if (p != p_end) {
+ set_error_buf(error_buf, error_buf_size, "section size mismatch");
+ return false;
+ }
+
+ LOG_VERBOSE("Load global section success.\n");
+ return true;
+fail:
+ return false;
+}
+
+static bool
+load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
+ bool is_load_from_file_buf, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 export_count, i, j, index;
+ uint64 total_size;
+ uint32 str_len;
+ WASMExport *export;
+ const char *name;
+
+ read_leb_uint32(p, p_end, export_count);
+
+ if (export_count) {
+ module->export_count = export_count;
+ total_size = sizeof(WASMExport) * (uint64)export_count;
+ if (!(module->exports =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ export = module->exports;
+ for (i = 0; i < export_count; i++, export ++) {
+#if WASM_ENABLE_THREAD_MGR == 0
+ if (p == p_end) {
+ /* export section with inconsistent count:
+ n export declared, but less than n given */
+ set_error_buf(error_buf, error_buf_size,
+ "length out of bounds");
+ return false;
+ }
+#endif
+ read_leb_uint32(p, p_end, str_len);
+ CHECK_BUF(p, p_end, str_len);
+
+ for (j = 0; j < i; j++) {
+ name = module->exports[j].name;
+ if (strlen(name) == str_len && memcmp(name, p, str_len) == 0) {
+ set_error_buf(error_buf, error_buf_size,
+ "duplicate export name");
+ return false;
+ }
+ }
+
+ if (!(export->name = const_str_list_insert(
+ p, str_len, module, is_load_from_file_buf, error_buf,
+ error_buf_size))) {
+ return false;
+ }
+
+ p += str_len;
+ CHECK_BUF(p, p_end, 1);
+ export->kind = read_uint8(p);
+ read_leb_uint32(p, p_end, index);
+ export->index = index;
+
+ switch (export->kind) {
+ /* function index */
+ case EXPORT_KIND_FUNC:
+ if (index >= module->function_count
+ + module->import_function_count) {
+ set_error_buf(error_buf, error_buf_size,
+ "unknown function");
+ return false;
+ }
+#if WASM_ENABLE_SIMD != 0
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+ /* TODO: check func type, if it has v128 param or result,
+ report error */
+#endif
+#endif
+ break;
+ /* table index */
+ case EXPORT_KIND_TABLE:
+ if (index
+ >= module->table_count + module->import_table_count) {
+ set_error_buf(error_buf, error_buf_size,
+ "unknown table");
+ return false;
+ }
+ break;
+ /* memory index */
+ case EXPORT_KIND_MEMORY:
+ if (index
+ >= module->memory_count + module->import_memory_count) {
+ set_error_buf(error_buf, error_buf_size,
+ "unknown memory");
+ return false;
+ }
+ break;
+ /* global index */
+ case EXPORT_KIND_GLOBAL:
+ if (index
+ >= module->global_count + module->import_global_count) {
+ set_error_buf(error_buf, error_buf_size,
+ "unknown global");
+ return false;
+ }
+ break;
+ default:
+ set_error_buf(error_buf, error_buf_size,
+ "invalid export kind");
+ return false;
+ }
+ }
+ }
+
+ if (p != p_end) {
+ set_error_buf(error_buf, error_buf_size, "section size mismatch");
+ return false;
+ }
+
+ LOG_VERBOSE("Load export section success.\n");
+ return true;
+fail:
+ return false;
+}
+
+static bool
+check_table_index(const WASMModule *module, uint32 table_index, char *error_buf,
+ uint32 error_buf_size)
+{
+#if WASM_ENABLE_REF_TYPES == 0
+ if (table_index != 0) {
+ set_error_buf(error_buf, error_buf_size, "zero byte expected");
+ return false;
+ }
+#endif
+
+ if (table_index >= module->import_table_count + module->table_count) {
+ set_error_buf_v(error_buf, error_buf_size, "unknown table %d",
+ table_index);
+ return false;
+ }
+ return true;
+}
+
+static bool
+load_table_index(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module,
+ uint32 *p_table_index, char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end;
+ uint32 table_index;
+
+ read_leb_uint32(p, p_end, table_index);
+ if (!check_table_index(module, table_index, error_buf, error_buf_size)) {
+ return false;
+ }
+
+ *p_table_index = table_index;
+ *p_buf = p;
+ return true;
+fail:
+ return false;
+}
+
+#if WASM_ENABLE_REF_TYPES != 0
+static bool
+load_elem_type(const uint8 **p_buf, const uint8 *buf_end, uint32 *p_elem_type,
+ bool elemkind_zero, char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end;
+ uint8 elem_type;
+
+ CHECK_BUF(p, p_end, 1);
+ elem_type = read_uint8(p);
+ if ((elemkind_zero && elem_type != 0)
+ || (!elemkind_zero && elem_type != VALUE_TYPE_FUNCREF
+ && elem_type != VALUE_TYPE_EXTERNREF)) {
+ set_error_buf(error_buf, error_buf_size, "invalid reference type");
+ return false;
+ }
+
+ if (elemkind_zero)
+ *p_elem_type = VALUE_TYPE_FUNCREF;
+ else
+ *p_elem_type = elem_type;
+ *p_buf = p;
+ return true;
+fail:
+ return false;
+}
+#endif /* WASM_ENABLE_REF_TYPES != 0*/
+
+static bool
+load_func_index_vec(const uint8 **p_buf, const uint8 *buf_end,
+ WASMModule *module, WASMTableSeg *table_segment,
+ bool use_init_expr, char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end;
+ uint32 function_count, function_index = 0, i;
+ uint64 total_size;
+
+ read_leb_uint32(p, p_end, function_count);
+ table_segment->function_count = function_count;
+ total_size = sizeof(uint32) * (uint64)function_count;
+ if (total_size > 0
+ && !(table_segment->func_indexes = (uint32 *)loader_malloc(
+ total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ for (i = 0; i < function_count; i++) {
+ InitializerExpression init_expr = { 0 };
+
+#if WASM_ENABLE_REF_TYPES != 0
+ if (!use_init_expr) {
+ read_leb_uint32(p, p_end, function_index);
+ }
+ else {
+ if (!load_init_expr(&p, p_end, &init_expr, table_segment->elem_type,
+ error_buf, error_buf_size))
+ return false;
+
+ function_index = init_expr.u.ref_index;
+ }
+#else
+ read_leb_uint32(p, p_end, function_index);
+ (void)use_init_expr;
+#endif
+
+ /* since we are using -1 to indicate ref.null */
+ if (init_expr.init_expr_type != INIT_EXPR_TYPE_REFNULL_CONST
+ && !check_function_index(module, function_index, error_buf,
+ error_buf_size)) {
+ return false;
+ }
+ table_segment->func_indexes[i] = function_index;
+ }
+
+ *p_buf = p;
+ return true;
+fail:
+ return false;
+}
+
+static bool
+load_table_segment_section(const uint8 *buf, const uint8 *buf_end,
+ WASMModule *module, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 table_segment_count, i;
+ uint64 total_size;
+ WASMTableSeg *table_segment;
+
+ read_leb_uint32(p, p_end, table_segment_count);
+
+ if (table_segment_count) {
+ module->table_seg_count = table_segment_count;
+ total_size = sizeof(WASMTableSeg) * (uint64)table_segment_count;
+ if (!(module->table_segments =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ table_segment = module->table_segments;
+ for (i = 0; i < table_segment_count; i++, table_segment++) {
+ if (p >= p_end) {
+ set_error_buf(error_buf, error_buf_size,
+ "invalid value type or "
+ "invalid elements segment kind");
+ return false;
+ }
+
+#if WASM_ENABLE_REF_TYPES != 0
+ read_leb_uint32(p, p_end, table_segment->mode);
+ /* last three bits */
+ table_segment->mode = table_segment->mode & 0x07;
+ switch (table_segment->mode) {
+ /* elemkind/elemtype + active */
+ case 0:
+ case 4:
+ table_segment->elem_type = VALUE_TYPE_FUNCREF;
+ table_segment->table_index = 0;
+
+ if (!check_table_index(module, table_segment->table_index,
+ error_buf, error_buf_size))
+ return false;
+ if (!load_init_expr(&p, p_end, &table_segment->base_offset,
+ VALUE_TYPE_I32, error_buf,
+ error_buf_size))
+ return false;
+ if (!load_func_index_vec(&p, p_end, module, table_segment,
+ table_segment->mode == 0 ? false
+ : true,
+ error_buf, error_buf_size))
+ return false;
+ break;
+ /* elemkind + passive/declarative */
+ case 1:
+ case 3:
+ if (!load_elem_type(&p, p_end, &table_segment->elem_type,
+ true, error_buf, error_buf_size))
+ return false;
+ if (!load_func_index_vec(&p, p_end, module, table_segment,
+ false, error_buf, error_buf_size))
+ return false;
+ break;
+ /* elemkind/elemtype + table_idx + active */
+ case 2:
+ case 6:
+ if (!load_table_index(&p, p_end, module,
+ &table_segment->table_index,
+ error_buf, error_buf_size))
+ return false;
+ if (!load_init_expr(&p, p_end, &table_segment->base_offset,
+ VALUE_TYPE_I32, error_buf,
+ error_buf_size))
+ return false;
+ if (!load_elem_type(&p, p_end, &table_segment->elem_type,
+ table_segment->mode == 2 ? true : false,
+ error_buf, error_buf_size))
+ return false;
+ if (!load_func_index_vec(&p, p_end, module, table_segment,
+ table_segment->mode == 2 ? false
+ : true,
+ error_buf, error_buf_size))
+ return false;
+ break;
+ case 5:
+ case 7:
+ if (!load_elem_type(&p, p_end, &table_segment->elem_type,
+ false, error_buf, error_buf_size))
+ return false;
+ if (!load_func_index_vec(&p, p_end, module, table_segment,
+ true, error_buf, error_buf_size))
+ return false;
+ break;
+ default:
+ set_error_buf(error_buf, error_buf_size,
+ "unknown element segment kind");
+ return false;
+ }
+#else
+ /*
+ * like: 00 41 05 0b 04 00 01 00 01
+ * for: (elem 0 (offset (i32.const 5)) $f1 $f2 $f1 $f2)
+ */
+ if (!load_table_index(&p, p_end, module,
+ &table_segment->table_index, error_buf,
+ error_buf_size))
+ return false;
+ if (!load_init_expr(&p, p_end, &table_segment->base_offset,
+ VALUE_TYPE_I32, error_buf, error_buf_size))
+ return false;
+ if (!load_func_index_vec(&p, p_end, module, table_segment, false,
+ error_buf, error_buf_size))
+ return false;
+#endif /* WASM_ENABLE_REF_TYPES != 0 */
+ }
+ }
+
+ if (p != p_end) {
+ set_error_buf(error_buf, error_buf_size, "section size mismatch");
+ return false;
+ }
+
+ LOG_VERBOSE("Load table segment section success.\n");
+ return true;
+fail:
+ return false;
+}
+
+static bool
+load_data_segment_section(const uint8 *buf, const uint8 *buf_end,
+ WASMModule *module, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 data_seg_count, i, mem_index, data_seg_len;
+ uint64 total_size;
+ WASMDataSeg *dataseg;
+ InitializerExpression init_expr;
+#if WASM_ENABLE_BULK_MEMORY != 0
+ bool is_passive = false;
+ uint32 mem_flag;
+#endif
+
+ read_leb_uint32(p, p_end, data_seg_count);
+
+#if WASM_ENABLE_BULK_MEMORY != 0
+ if ((module->data_seg_count1 != 0)
+ && (data_seg_count != module->data_seg_count1)) {
+ set_error_buf(error_buf, error_buf_size,
+ "data count and data section have inconsistent lengths");
+ return false;
+ }
+#endif
+
+ if (data_seg_count) {
+ module->data_seg_count = data_seg_count;
+ total_size = sizeof(WASMDataSeg *) * (uint64)data_seg_count;
+ if (!(module->data_segments =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ for (i = 0; i < data_seg_count; i++) {
+ read_leb_uint32(p, p_end, mem_index);
+#if WASM_ENABLE_BULK_MEMORY != 0
+ is_passive = false;
+ mem_flag = mem_index & 0x03;
+ switch (mem_flag) {
+ case 0x01:
+ is_passive = true;
+ break;
+ case 0x00:
+ /* no memory index, treat index as 0 */
+ mem_index = 0;
+ goto check_mem_index;
+ case 0x02:
+ /* read following memory index */
+ read_leb_uint32(p, p_end, mem_index);
+ check_mem_index:
+ if (mem_index
+ >= module->import_memory_count + module->memory_count) {
+ set_error_buf_v(error_buf, error_buf_size,
+ "unknown memory %d", mem_index);
+ return false;
+ }
+ break;
+ case 0x03:
+ default:
+ set_error_buf(error_buf, error_buf_size, "unknown memory");
+ return false;
+ break;
+ }
+#else
+ if (mem_index
+ >= module->import_memory_count + module->memory_count) {
+ set_error_buf_v(error_buf, error_buf_size, "unknown memory %d",
+ mem_index);
+ return false;
+ }
+#endif /* WASM_ENABLE_BULK_MEMORY */
+
+#if WASM_ENABLE_BULK_MEMORY != 0
+ if (!is_passive)
+#endif
+ if (!load_init_expr(&p, p_end, &init_expr, VALUE_TYPE_I32,
+ error_buf, error_buf_size))
+ return false;
+
+ read_leb_uint32(p, p_end, data_seg_len);
+
+ if (!(dataseg = module->data_segments[i] = loader_malloc(
+ sizeof(WASMDataSeg), error_buf, error_buf_size))) {
+ return false;
+ }
+
+#if WASM_ENABLE_BULK_MEMORY != 0
+ dataseg->is_passive = is_passive;
+ if (!is_passive)
+#endif
+ {
+ bh_memcpy_s(&dataseg->base_offset,
+ sizeof(InitializerExpression), &init_expr,
+ sizeof(InitializerExpression));
+
+ dataseg->memory_index = mem_index;
+ }
+
+ dataseg->data_length = data_seg_len;
+ CHECK_BUF(p, p_end, data_seg_len);
+ dataseg->data = (uint8 *)p;
+ p += data_seg_len;
+ }
+ }
+
+ if (p != p_end) {
+ set_error_buf(error_buf, error_buf_size, "section size mismatch");
+ return false;
+ }
+
+ LOG_VERBOSE("Load data segment section success.\n");
+ return true;
+fail:
+ return false;
+}
+
+#if WASM_ENABLE_BULK_MEMORY != 0
+static bool
+load_datacount_section(const uint8 *buf, const uint8 *buf_end,
+ WASMModule *module, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 data_seg_count1 = 0;
+
+ read_leb_uint32(p, p_end, data_seg_count1);
+ module->data_seg_count1 = data_seg_count1;
+
+ if (p != p_end) {
+ set_error_buf(error_buf, error_buf_size, "section size mismatch");
+ return false;
+ }
+
+ LOG_VERBOSE("Load datacount section success.\n");
+ return true;
+fail:
+ return false;
+}
+#endif
+
+static bool
+load_code_section(const uint8 *buf, const uint8 *buf_end, const uint8 *buf_func,
+ const uint8 *buf_func_end, WASMModule *module,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ const uint8 *p_func = buf_func;
+ uint32 func_count = 0, code_count;
+
+ /* code has been loaded in function section, so pass it here, just check
+ * whether function and code section have inconsistent lengths */
+ read_leb_uint32(p, p_end, code_count);
+
+ if (buf_func)
+ read_leb_uint32(p_func, buf_func_end, func_count);
+
+ if (func_count != code_count) {
+ set_error_buf(error_buf, error_buf_size,
+ "function and code section have inconsistent lengths");
+ return false;
+ }
+
+ LOG_VERBOSE("Load code segment section success.\n");
+ (void)module;
+ return true;
+fail:
+ return false;
+}
+
+static bool
+load_start_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ WASMType *type;
+ uint32 start_function;
+
+ read_leb_uint32(p, p_end, start_function);
+
+ if (start_function
+ >= module->function_count + module->import_function_count) {
+ set_error_buf(error_buf, error_buf_size, "unknown function");
+ return false;
+ }
+
+ if (start_function < module->import_function_count)
+ type = module->import_functions[start_function].u.function.func_type;
+ else
+ type = module->functions[start_function - module->import_function_count]
+ ->func_type;
+ if (type->param_count != 0 || type->result_count != 0) {
+ set_error_buf(error_buf, error_buf_size, "invalid start function");
+ return false;
+ }
+
+ module->start_function = start_function;
+
+ if (p != p_end) {
+ set_error_buf(error_buf, error_buf_size, "section size mismatch");
+ return false;
+ }
+
+ LOG_VERBOSE("Load start section success.\n");
+ return true;
+fail:
+ return false;
+}
+
+#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
+static bool
+handle_name_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
+ bool is_load_from_file_buf, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 name_type, subsection_size;
+ uint32 previous_name_type = 0;
+ uint32 num_func_name;
+ uint32 func_index;
+ uint32 previous_func_index = ~0U;
+ uint32 func_name_len;
+ uint32 name_index;
+ int i = 0;
+
+ if (p >= p_end) {
+ set_error_buf(error_buf, error_buf_size, "unexpected end");
+ return false;
+ }
+
+ while (p < p_end) {
+ read_leb_uint32(p, p_end, name_type);
+ if (i != 0) {
+ if (name_type == previous_name_type) {
+ set_error_buf(error_buf, error_buf_size,
+ "duplicate sub-section");
+ return false;
+ }
+ if (name_type < previous_name_type) {
+ set_error_buf(error_buf, error_buf_size,
+ "out-of-order sub-section");
+ return false;
+ }
+ }
+ previous_name_type = name_type;
+ read_leb_uint32(p, p_end, subsection_size);
+ CHECK_BUF(p, p_end, subsection_size);
+ switch (name_type) {
+ case SUB_SECTION_TYPE_FUNC:
+ if (subsection_size) {
+ read_leb_uint32(p, p_end, num_func_name);
+ for (name_index = 0; name_index < num_func_name;
+ name_index++) {
+ read_leb_uint32(p, p_end, func_index);
+ if (func_index == previous_func_index) {
+ set_error_buf(error_buf, error_buf_size,
+ "duplicate function name");
+ return false;
+ }
+ if (func_index < previous_func_index
+ && previous_func_index != ~0U) {
+ set_error_buf(error_buf, error_buf_size,
+ "out-of-order function index ");
+ return false;
+ }
+ previous_func_index = func_index;
+ read_leb_uint32(p, p_end, func_name_len);
+ CHECK_BUF(p, p_end, func_name_len);
+ /* Skip the import functions */
+ if (func_index >= module->import_function_count) {
+ func_index -= module->import_function_count;
+ if (func_index >= module->function_count) {
+ set_error_buf(error_buf, error_buf_size,
+ "out-of-range function index");
+ return false;
+ }
+ if (!(module->functions[func_index]->field_name =
+ const_str_list_insert(
+ p, func_name_len, module,
+ is_load_from_file_buf, error_buf,
+ error_buf_size))) {
+ return false;
+ }
+ }
+ p += func_name_len;
+ }
+ }
+ break;
+ case SUB_SECTION_TYPE_MODULE: /* TODO: Parse for module subsection
+ */
+ case SUB_SECTION_TYPE_LOCAL: /* TODO: Parse for local subsection */
+ default:
+ p = p + subsection_size;
+ break;
+ }
+ i++;
+ }
+
+ return true;
+fail:
+ return false;
+}
+#endif
+
+static bool
+load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
+ bool is_load_from_file_buf, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ char section_name[32];
+ uint32 name_len, buffer_len;
+
+ if (p >= p_end) {
+ set_error_buf(error_buf, error_buf_size, "unexpected end");
+ return false;
+ }
+
+ read_leb_uint32(p, p_end, name_len);
+
+ if (name_len == 0 || p + name_len > p_end) {
+ set_error_buf(error_buf, error_buf_size, "unexpected end");
+ return false;
+ }
+
+ if (!check_utf8_str(p, name_len)) {
+ set_error_buf(error_buf, error_buf_size, "invalid UTF-8 encoding");
+ return false;
+ }
+
+ buffer_len = sizeof(section_name);
+ memset(section_name, 0, buffer_len);
+ if (name_len < buffer_len) {
+ bh_memcpy_s(section_name, buffer_len, p, name_len);
+ }
+ else {
+ bh_memcpy_s(section_name, buffer_len, p, buffer_len - 4);
+ memset(section_name + buffer_len - 4, '.', 3);
+ }
+
+#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
+ if (memcmp(p, "name", 4) == 0) {
+ module->name_section_buf = buf;
+ module->name_section_buf_end = buf_end;
+ p += name_len;
+ handle_name_section(p, p_end, module, is_load_from_file_buf, error_buf,
+ error_buf_size);
+ LOG_VERBOSE("Load custom name section success.");
+ return true;
+ }
+#endif
+
+#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
+ {
+ WASMCustomSection *section =
+ loader_malloc(sizeof(WASMCustomSection), error_buf, error_buf_size);
+
+ if (!section) {
+ return false;
+ }
+
+ section->name_addr = (char *)p;
+ section->name_len = name_len;
+ section->content_addr = (uint8 *)(p + name_len);
+ section->content_len = (uint32)(p_end - p - name_len);
+
+ section->next = module->custom_section_list;
+ module->custom_section_list = section;
+ LOG_VERBOSE("Load custom section [%s] success.", section_name);
+ return true;
+ }
+#endif
+
+ LOG_VERBOSE("Ignore custom section [%s].", section_name);
+
+ (void)is_load_from_file_buf;
+ (void)module;
+ return true;
+fail:
+ return false;
+}
+
+static void
+calculate_global_data_offset(WASMModule *module)
+{
+ uint32 i, data_offset;
+
+ data_offset = 0;
+ for (i = 0; i < module->import_global_count; i++) {
+ WASMGlobalImport *import_global =
+ &((module->import_globals + i)->u.global);
+#if WASM_ENABLE_FAST_JIT != 0
+ import_global->data_offset = data_offset;
+#endif
+ data_offset += wasm_value_type_size(import_global->type);
+ }
+
+ for (i = 0; i < module->global_count; i++) {
+ WASMGlobal *global = module->globals + i;
+#if WASM_ENABLE_FAST_JIT != 0
+ global->data_offset = data_offset;
+#endif
+ data_offset += wasm_value_type_size(global->type);
+ }
+
+ module->global_data_size = data_offset;
+}
+
+#if WASM_ENABLE_FAST_JIT != 0
+static bool
+init_fast_jit_functions(WASMModule *module, char *error_buf,
+ uint32 error_buf_size)
+{
+#if WASM_ENABLE_LAZY_JIT != 0
+ JitGlobals *jit_globals = jit_compiler_get_jit_globals();
+#endif
+ uint32 i;
+
+ if (!module->function_count)
+ return true;
+
+ if (!(module->fast_jit_func_ptrs =
+ loader_malloc(sizeof(void *) * module->function_count, error_buf,
+ error_buf_size))) {
+ return false;
+ }
+
+#if WASM_ENABLE_LAZY_JIT != 0
+ for (i = 0; i < module->function_count; i++) {
+ module->fast_jit_func_ptrs[i] =
+ jit_globals->compile_fast_jit_and_then_call;
+ }
+#endif
+
+ for (i = 0; i < WASM_ORC_JIT_BACKEND_THREAD_NUM; i++) {
+ if (os_mutex_init(&module->fast_jit_thread_locks[i]) != 0) {
+ set_error_buf(error_buf, error_buf_size,
+ "init fast jit thread lock failed");
+ return false;
+ }
+ module->fast_jit_thread_locks_inited[i] = true;
+ }
+
+ return true;
+}
+#endif /* end of WASM_ENABLE_FAST_JIT != 0 */
+
+#if WASM_ENABLE_JIT != 0
+static bool
+init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
+ uint32 error_buf_size)
+{
+ LLVMJITOptions llvm_jit_options = wasm_runtime_get_llvm_jit_options();
+ AOTCompOption option = { 0 };
+ char *aot_last_error;
+ uint64 size;
+
+ if (module->function_count == 0)
+ return true;
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LLVM_JIT != 0
+ if (os_mutex_init(&module->tierup_wait_lock) != 0) {
+ set_error_buf(error_buf, error_buf_size, "init jit tierup lock failed");
+ return false;
+ }
+ if (os_cond_init(&module->tierup_wait_cond) != 0) {
+ set_error_buf(error_buf, error_buf_size, "init jit tierup cond failed");
+ os_mutex_destroy(&module->tierup_wait_lock);
+ return false;
+ }
+ module->tierup_wait_lock_inited = true;
+#endif
+
+ size = sizeof(void *) * (uint64)module->function_count
+ + sizeof(bool) * (uint64)module->function_count;
+ if (!(module->func_ptrs = loader_malloc(size, error_buf, error_buf_size))) {
+ return false;
+ }
+ module->func_ptrs_compiled =
+ (bool *)((uint8 *)module->func_ptrs
+ + sizeof(void *) * module->function_count);
+
+ module->comp_data = aot_create_comp_data(module);
+ if (!module->comp_data) {
+ aot_last_error = aot_get_last_error();
+ bh_assert(aot_last_error != NULL);
+ set_error_buf(error_buf, error_buf_size, aot_last_error);
+ return false;
+ }
+
+ option.is_jit_mode = true;
+
+ llvm_jit_options = wasm_runtime_get_llvm_jit_options();
+ option.opt_level = llvm_jit_options.opt_level;
+ option.size_level = llvm_jit_options.size_level;
+
+#if WASM_ENABLE_BULK_MEMORY != 0
+ option.enable_bulk_memory = true;
+#endif
+#if WASM_ENABLE_THREAD_MGR != 0
+ option.enable_thread_mgr = true;
+#endif
+#if WASM_ENABLE_TAIL_CALL != 0
+ option.enable_tail_call = true;
+#endif
+#if WASM_ENABLE_SIMD != 0
+ option.enable_simd = true;
+#endif
+#if WASM_ENABLE_REF_TYPES != 0
+ option.enable_ref_types = true;
+#endif
+ option.enable_aux_stack_check = true;
+#if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0)
+ option.enable_aux_stack_frame = true;
+#endif
+#if WASM_ENABLE_MEMORY_PROFILING != 0
+ option.enable_stack_estimation = true;
+#endif
+
+ module->comp_ctx = aot_create_comp_context(module->comp_data, &option);
+ if (!module->comp_ctx) {
+ aot_last_error = aot_get_last_error();
+ bh_assert(aot_last_error != NULL);
+ set_error_buf(error_buf, error_buf_size, aot_last_error);
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+init_llvm_jit_functions_stage2(WASMModule *module, char *error_buf,
+ uint32 error_buf_size)
+{
+ char *aot_last_error;
+ uint32 i;
+
+ if (module->function_count == 0)
+ return true;
+
+ if (!aot_compile_wasm(module->comp_ctx)) {
+ aot_last_error = aot_get_last_error();
+ bh_assert(aot_last_error != NULL);
+ set_error_buf(error_buf, error_buf_size, aot_last_error);
+ return false;
+ }
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
+ if (module->orcjit_stop_compiling)
+ return false;
+#endif
+
+ bh_print_time("Begin to lookup llvm jit functions");
+
+ for (i = 0; i < module->function_count; i++) {
+ LLVMOrcJITTargetAddress func_addr = 0;
+ LLVMErrorRef error;
+ char func_name[48];
+
+ snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i);
+ error = LLVMOrcLLLazyJITLookup(module->comp_ctx->orc_jit, &func_addr,
+ func_name);
+ if (error != LLVMErrorSuccess) {
+ char *err_msg = LLVMGetErrorMessage(error);
+ set_error_buf_v(error_buf, error_buf_size,
+ "failed to compile llvm jit function: %s", err_msg);
+ LLVMDisposeErrorMessage(err_msg);
+ return false;
+ }
+
+ /**
+ * No need to lock the func_ptr[func_idx] here as it is basic
+ * data type, the load/store for it can be finished by one cpu
+ * instruction, and there can be only one cpu instruction
+ * loading/storing at the same time.
+ */
+ module->func_ptrs[i] = (void *)func_addr;
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
+ module->functions[i]->llvm_jit_func_ptr = (void *)func_addr;
+
+ if (module->orcjit_stop_compiling)
+ return false;
+#endif
+ }
+
+ bh_print_time("End lookup llvm jit functions");
+
+ return true;
+}
+#endif /* end of WASM_ENABLE_JIT != 0 */
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0
+static void *
+init_llvm_jit_functions_stage2_callback(void *arg)
+{
+ WASMModule *module = (WASMModule *)arg;
+ char error_buf[128];
+ uint32 error_buf_size = (uint32)sizeof(error_buf);
+
+ if (!init_llvm_jit_functions_stage2(module, error_buf, error_buf_size)) {
+ module->orcjit_stop_compiling = true;
+ return NULL;
+ }
+
+ os_mutex_lock(&module->tierup_wait_lock);
+ module->llvm_jit_inited = true;
+ os_cond_broadcast(&module->tierup_wait_cond);
+ os_mutex_unlock(&module->tierup_wait_lock);
+
+ return NULL;
+}
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0
+/* The callback function to compile jit functions */
+static void *
+orcjit_thread_callback(void *arg)
+{
+ OrcJitThreadArg *thread_arg = (OrcJitThreadArg *)arg;
+#if WASM_ENABLE_JIT != 0
+ AOTCompContext *comp_ctx = thread_arg->comp_ctx;
+#endif
+ WASMModule *module = thread_arg->module;
+ uint32 group_idx = thread_arg->group_idx;
+ uint32 group_stride = WASM_ORC_JIT_BACKEND_THREAD_NUM;
+ uint32 func_count = module->function_count;
+ uint32 i;
+
+#if WASM_ENABLE_FAST_JIT != 0
+ /* Compile fast jit funcitons of this group */
+ for (i = group_idx; i < func_count; i += group_stride) {
+ if (!jit_compiler_compile(module, i + module->import_function_count)) {
+ os_printf("failed to compile fast jit function %u\n", i);
+ break;
+ }
+
+ if (module->orcjit_stop_compiling) {
+ return NULL;
+ }
+ }
+#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
+ os_mutex_lock(&module->tierup_wait_lock);
+ module->fast_jit_ready_groups++;
+ os_mutex_unlock(&module->tierup_wait_lock);
+#endif
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0
+ /* For JIT tier-up, set each llvm jit func to call_to_fast_jit */
+ for (i = group_idx; i < func_count;
+ i += group_stride * WASM_ORC_JIT_COMPILE_THREAD_NUM) {
+ uint32 j;
+
+ for (j = 0; j < WASM_ORC_JIT_COMPILE_THREAD_NUM; j++) {
+ if (i + j * group_stride < func_count) {
+ if (!jit_compiler_set_call_to_fast_jit(
+ module,
+ i + j * group_stride + module->import_function_count)) {
+ os_printf(
+ "failed to compile call_to_fast_jit for func %u\n",
+ i + j * group_stride + module->import_function_count);
+ module->orcjit_stop_compiling = true;
+ return NULL;
+ }
+ }
+ if (module->orcjit_stop_compiling) {
+ return NULL;
+ }
+ }
+ }
+
+ /* Wait until init_llvm_jit_functions_stage2 finishes and all
+ fast jit functions are compiled */
+ os_mutex_lock(&module->tierup_wait_lock);
+ while (!(module->llvm_jit_inited && module->enable_llvm_jit_compilation
+ && module->fast_jit_ready_groups >= group_stride)) {
+ os_cond_reltimedwait(&module->tierup_wait_cond,
+ &module->tierup_wait_lock, 10000);
+ if (module->orcjit_stop_compiling) {
+ /* init_llvm_jit_functions_stage2 failed */
+ os_mutex_unlock(&module->tierup_wait_lock);
+ return NULL;
+ }
+ }
+ os_mutex_unlock(&module->tierup_wait_lock);
+#endif
+
+#if WASM_ENABLE_JIT != 0
+ /* Compile llvm jit functions of this group */
+ for (i = group_idx; i < func_count;
+ i += group_stride * WASM_ORC_JIT_COMPILE_THREAD_NUM) {
+ LLVMOrcJITTargetAddress func_addr = 0;
+ LLVMErrorRef error;
+ char func_name[48];
+ typedef void (*F)(void);
+ union {
+ F f;
+ void *v;
+ } u;
+ uint32 j;
+
+ snprintf(func_name, sizeof(func_name), "%s%d%s", AOT_FUNC_PREFIX, i,
+ "_wrapper");
+ LOG_DEBUG("compile llvm jit func %s", func_name);
+ error =
+ LLVMOrcLLLazyJITLookup(comp_ctx->orc_jit, &func_addr, func_name);
+ if (error != LLVMErrorSuccess) {
+ char *err_msg = LLVMGetErrorMessage(error);
+ os_printf("failed to compile llvm jit function %u: %s", i, err_msg);
+ LLVMDisposeErrorMessage(err_msg);
+ break;
+ }
+
+ /* Call the jit wrapper function to trigger its compilation, so as
+ to compile the actual jit functions, since we add the latter to
+ function list in the PartitionFunction callback */
+ u.v = (void *)func_addr;
+ u.f();
+
+ for (j = 0; j < WASM_ORC_JIT_COMPILE_THREAD_NUM; j++) {
+ if (i + j * group_stride < func_count) {
+ module->func_ptrs_compiled[i + j * group_stride] = true;
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
+ snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX,
+ i + j * group_stride);
+ error = LLVMOrcLLLazyJITLookup(comp_ctx->orc_jit, &func_addr,
+ func_name);
+ if (error != LLVMErrorSuccess) {
+ char *err_msg = LLVMGetErrorMessage(error);
+ os_printf("failed to compile llvm jit function %u: %s", i,
+ err_msg);
+ LLVMDisposeErrorMessage(err_msg);
+ /* Ignore current llvm jit func, as its func ptr is
+ previous set to call_to_fast_jit, which also works */
+ continue;
+ }
+
+ jit_compiler_set_llvm_jit_func_ptr(
+ module,
+ i + j * group_stride + module->import_function_count,
+ (void *)func_addr);
+
+ /* Try to switch to call this llvm jit funtion instead of
+ fast jit function from fast jit jitted code */
+ jit_compiler_set_call_to_llvm_jit(
+ module,
+ i + j * group_stride + module->import_function_count);
+#endif
+ }
+ }
+
+ if (module->orcjit_stop_compiling) {
+ break;
+ }
+ }
+#endif
+
+ return NULL;
+}
+
+static void
+orcjit_stop_compile_threads(WASMModule *module)
+{
+ uint32 i, thread_num = (uint32)(sizeof(module->orcjit_thread_args)
+ / sizeof(OrcJitThreadArg));
+
+ module->orcjit_stop_compiling = true;
+ for (i = 0; i < thread_num; i++) {
+ if (module->orcjit_threads[i])
+ os_thread_join(module->orcjit_threads[i], NULL);
+ }
+}
+
+static bool
+compile_jit_functions(WASMModule *module, char *error_buf,
+ uint32 error_buf_size)
+{
+ uint32 thread_num =
+ (uint32)(sizeof(module->orcjit_thread_args) / sizeof(OrcJitThreadArg));
+ uint32 i, j;
+
+ bh_print_time("Begin to compile jit functions");
+
+ /* Create threads to compile the jit functions */
+ for (i = 0; i < thread_num && i < module->function_count; i++) {
+#if WASM_ENABLE_JIT != 0
+ module->orcjit_thread_args[i].comp_ctx = module->comp_ctx;
+#endif
+ module->orcjit_thread_args[i].module = module;
+ module->orcjit_thread_args[i].group_idx = i;
+
+ if (os_thread_create(&module->orcjit_threads[i], orcjit_thread_callback,
+ (void *)&module->orcjit_thread_args[i],
+ APP_THREAD_STACK_SIZE_DEFAULT)
+ != 0) {
+ set_error_buf(error_buf, error_buf_size,
+ "create orcjit compile thread failed");
+ /* Terminate the threads created */
+ module->orcjit_stop_compiling = true;
+ for (j = 0; j < i; j++) {
+ os_thread_join(module->orcjit_threads[j], NULL);
+ }
+ return false;
+ }
+ }
+
+#if WASM_ENABLE_LAZY_JIT == 0
+ /* Wait until all jit functions are compiled for eager mode */
+ for (i = 0; i < thread_num; i++) {
+ if (module->orcjit_threads[i])
+ os_thread_join(module->orcjit_threads[i], NULL);
+ }
+
+#if WASM_ENABLE_FAST_JIT != 0
+ /* Ensure all the fast-jit functions are compiled */
+ for (i = 0; i < module->function_count; i++) {
+ if (!jit_compiler_is_compiled(module,
+ i + module->import_function_count)) {
+ set_error_buf(error_buf, error_buf_size,
+ "failed to compile fast jit function");
+ return false;
+ }
+ }
+#endif
+
+#if WASM_ENABLE_JIT != 0
+ /* Ensure all the llvm-jit functions are compiled */
+ for (i = 0; i < module->function_count; i++) {
+ if (!module->func_ptrs_compiled[i]) {
+ set_error_buf(error_buf, error_buf_size,
+ "failed to compile llvm jit function");
+ return false;
+ }
+ }
+#endif
+#endif /* end of WASM_ENABLE_LAZY_JIT == 0 */
+
+ bh_print_time("End compile jit functions");
+
+ return true;
+}
+#endif /* end of WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 */
+
+static bool
+wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
+ uint32 cur_func_idx, char *error_buf,
+ uint32 error_buf_size);
+
+#if WASM_ENABLE_FAST_INTERP != 0 && WASM_ENABLE_LABELS_AS_VALUES != 0
+void **
+wasm_interp_get_handle_table();
+
+static void **handle_table;
+#endif
+
+static bool
+load_from_sections(WASMModule *module, WASMSection *sections,
+ bool is_load_from_file_buf, char *error_buf,
+ uint32 error_buf_size)
+{
+ WASMExport *export;
+ WASMSection *section = sections;
+ const uint8 *buf, *buf_end, *buf_code = NULL, *buf_code_end = NULL,
+ *buf_func = NULL, *buf_func_end = NULL;
+ WASMGlobal *aux_data_end_global = NULL, *aux_heap_base_global = NULL;
+ WASMGlobal *aux_stack_top_global = NULL, *global;
+ uint32 aux_data_end = (uint32)-1, aux_heap_base = (uint32)-1;
+ uint32 aux_stack_top = (uint32)-1, global_index, func_index, i;
+ uint32 aux_data_end_global_index = (uint32)-1;
+ uint32 aux_heap_base_global_index = (uint32)-1;
+ WASMType *func_type;
+
+ /* Find code and function sections if have */
+ while (section) {
+ if (section->section_type == SECTION_TYPE_CODE) {
+ buf_code = section->section_body;
+ buf_code_end = buf_code + section->section_body_size;
+#if WASM_ENABLE_DEBUG_INTERP != 0 || WASM_ENABLE_DEBUG_AOT != 0
+ module->buf_code = (uint8 *)buf_code;
+ module->buf_code_size = section->section_body_size;
+#endif
+ }
+ else if (section->section_type == SECTION_TYPE_FUNC) {
+ buf_func = section->section_body;
+ buf_func_end = buf_func + section->section_body_size;
+ }
+ section = section->next;
+ }
+
+ section = sections;
+ while (section) {
+ buf = section->section_body;
+ buf_end = buf + section->section_body_size;
+ switch (section->section_type) {
+ case SECTION_TYPE_USER:
+ /* unsupported user section, ignore it. */
+ if (!load_user_section(buf, buf_end, module,
+ is_load_from_file_buf, error_buf,
+ error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_TYPE:
+ if (!load_type_section(buf, buf_end, module, error_buf,
+ error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_IMPORT:
+ if (!load_import_section(buf, buf_end, module,
+ is_load_from_file_buf, error_buf,
+ error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_FUNC:
+ if (!load_function_section(buf, buf_end, buf_code, buf_code_end,
+ module, error_buf, error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_TABLE:
+ if (!load_table_section(buf, buf_end, module, error_buf,
+ error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_MEMORY:
+ if (!load_memory_section(buf, buf_end, module, error_buf,
+ error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_GLOBAL:
+ if (!load_global_section(buf, buf_end, module, error_buf,
+ error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_EXPORT:
+ if (!load_export_section(buf, buf_end, module,
+ is_load_from_file_buf, error_buf,
+ error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_START:
+ if (!load_start_section(buf, buf_end, module, error_buf,
+ error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_ELEM:
+ if (!load_table_segment_section(buf, buf_end, module, error_buf,
+ error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_CODE:
+ if (!load_code_section(buf, buf_end, buf_func, buf_func_end,
+ module, error_buf, error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_DATA:
+ if (!load_data_segment_section(buf, buf_end, module, error_buf,
+ error_buf_size))
+ return false;
+ break;
+#if WASM_ENABLE_BULK_MEMORY != 0
+ case SECTION_TYPE_DATACOUNT:
+ if (!load_datacount_section(buf, buf_end, module, error_buf,
+ error_buf_size))
+ return false;
+ break;
+#endif
+ default:
+ set_error_buf(error_buf, error_buf_size, "invalid section id");
+ return false;
+ }
+
+ section = section->next;
+ }
+
+ module->aux_data_end_global_index = (uint32)-1;
+ module->aux_heap_base_global_index = (uint32)-1;
+ module->aux_stack_top_global_index = (uint32)-1;
+
+ /* Resolve auxiliary data/stack/heap info and reset memory info */
+ export = module->exports;
+ for (i = 0; i < module->export_count; i++, export ++) {
+ if (export->kind == EXPORT_KIND_GLOBAL) {
+ if (!strcmp(export->name, "__heap_base")) {
+ global_index = export->index - module->import_global_count;
+ global = module->globals + global_index;
+ if (global->type == VALUE_TYPE_I32 && !global->is_mutable
+ && global->init_expr.init_expr_type
+ == INIT_EXPR_TYPE_I32_CONST) {
+ aux_heap_base_global = global;
+ aux_heap_base = global->init_expr.u.i32;
+ aux_heap_base_global_index = export->index;
+ LOG_VERBOSE("Found aux __heap_base global, value: %d",
+ aux_heap_base);
+ }
+ }
+ else if (!strcmp(export->name, "__data_end")) {
+ global_index = export->index - module->import_global_count;
+ global = module->globals + global_index;
+ if (global->type == VALUE_TYPE_I32 && !global->is_mutable
+ && global->init_expr.init_expr_type
+ == INIT_EXPR_TYPE_I32_CONST) {
+ aux_data_end_global = global;
+ aux_data_end = global->init_expr.u.i32;
+ aux_data_end_global_index = export->index;
+ LOG_VERBOSE("Found aux __data_end global, value: %d",
+ aux_data_end);
+
+ aux_data_end = align_uint(aux_data_end, 16);
+ }
+ }
+
+ /* For module compiled with -pthread option, the global is:
+ [0] stack_top <-- 0
+ [1] tls_pointer
+ [2] tls_size
+ [3] data_end <-- 3
+ [4] global_base
+ [5] heap_base <-- 5
+ [6] dso_handle
+
+ For module compiled without -pthread option:
+ [0] stack_top <-- 0
+ [1] data_end <-- 1
+ [2] global_base
+ [3] heap_base <-- 3
+ [4] dso_handle
+ */
+ if (aux_data_end_global && aux_heap_base_global
+ && aux_data_end <= aux_heap_base) {
+ module->aux_data_end_global_index = aux_data_end_global_index;
+ module->aux_data_end = aux_data_end;
+ module->aux_heap_base_global_index = aux_heap_base_global_index;
+ module->aux_heap_base = aux_heap_base;
+
+ /* Resolve aux stack top global */
+ for (global_index = 0; global_index < module->global_count;
+ global_index++) {
+ global = module->globals + global_index;
+ if (global->is_mutable /* heap_base and data_end is
+ not mutable */
+ && global->type == VALUE_TYPE_I32
+ && global->init_expr.init_expr_type
+ == INIT_EXPR_TYPE_I32_CONST
+ && (uint32)global->init_expr.u.i32 <= aux_heap_base) {
+ aux_stack_top_global = global;
+ aux_stack_top = (uint32)global->init_expr.u.i32;
+ module->aux_stack_top_global_index =
+ module->import_global_count + global_index;
+ module->aux_stack_bottom = aux_stack_top;
+ module->aux_stack_size =
+ aux_stack_top > aux_data_end
+ ? aux_stack_top - aux_data_end
+ : aux_stack_top;
+ LOG_VERBOSE("Found aux stack top global, value: %d, "
+ "global index: %d, stack size: %d",
+ aux_stack_top, global_index,
+ module->aux_stack_size);
+ break;
+ }
+ }
+ if (!aux_stack_top_global) {
+ /* Auxiliary stack global isn't found, it must be unused
+ in the wasm app, as if it is used, the global must be
+ defined. Here we set it to __heap_base global and set
+ its size to 0. */
+ aux_stack_top_global = aux_heap_base_global;
+ aux_stack_top = aux_heap_base;
+ module->aux_stack_top_global_index =
+ module->aux_heap_base_global_index;
+ module->aux_stack_bottom = aux_stack_top;
+ module->aux_stack_size = 0;
+ }
+ break;
+ }
+ }
+ }
+
+ module->malloc_function = (uint32)-1;
+ module->free_function = (uint32)-1;
+ module->retain_function = (uint32)-1;
+
+ /* Resolve malloc/free function exported by wasm module */
+ export = module->exports;
+ for (i = 0; i < module->export_count; i++, export ++) {
+ if (export->kind == EXPORT_KIND_FUNC) {
+ if (!strcmp(export->name, "malloc")
+ && export->index >= module->import_function_count) {
+ func_index = export->index - module->import_function_count;
+ func_type = module->functions[func_index]->func_type;
+ if (func_type->param_count == 1 && func_type->result_count == 1
+ && func_type->types[0] == VALUE_TYPE_I32
+ && func_type->types[1] == VALUE_TYPE_I32) {
+ bh_assert(module->malloc_function == (uint32)-1);
+ module->malloc_function = export->index;
+ LOG_VERBOSE("Found malloc function, name: %s, index: %u",
+ export->name, export->index);
+ }
+ }
+ else if (!strcmp(export->name, "__new")
+ && export->index >= module->import_function_count) {
+ /* __new && __pin for AssemblyScript */
+ func_index = export->index - module->import_function_count;
+ func_type = module->functions[func_index]->func_type;
+ if (func_type->param_count == 2 && func_type->result_count == 1
+ && func_type->types[0] == VALUE_TYPE_I32
+ && func_type->types[1] == VALUE_TYPE_I32
+ && func_type->types[2] == VALUE_TYPE_I32) {
+ uint32 j;
+ WASMExport *export_tmp;
+
+ bh_assert(module->malloc_function == (uint32)-1);
+ module->malloc_function = export->index;
+ LOG_VERBOSE("Found malloc function, name: %s, index: %u",
+ export->name, export->index);
+
+ /* resolve retain function.
+ If not found, reset malloc function index */
+ export_tmp = module->exports;
+ for (j = 0; j < module->export_count; j++, export_tmp++) {
+ if ((export_tmp->kind == EXPORT_KIND_FUNC)
+ && (!strcmp(export_tmp->name, "__retain")
+ || (!strcmp(export_tmp->name, "__pin")))
+ && (export_tmp->index
+ >= module->import_function_count)) {
+ func_index = export_tmp->index
+ - module->import_function_count;
+ func_type =
+ module->functions[func_index]->func_type;
+ if (func_type->param_count == 1
+ && func_type->result_count == 1
+ && func_type->types[0] == VALUE_TYPE_I32
+ && func_type->types[1] == VALUE_TYPE_I32) {
+ bh_assert(module->retain_function
+ == (uint32)-1);
+ module->retain_function = export_tmp->index;
+ LOG_VERBOSE("Found retain function, name: %s, "
+ "index: %u",
+ export_tmp->name,
+ export_tmp->index);
+ break;
+ }
+ }
+ }
+ if (j == module->export_count) {
+ module->malloc_function = (uint32)-1;
+ LOG_VERBOSE("Can't find retain function,"
+ "reset malloc function index to -1");
+ }
+ }
+ }
+ else if (((!strcmp(export->name, "free"))
+ || (!strcmp(export->name, "__release"))
+ || (!strcmp(export->name, "__unpin")))
+ && export->index >= module->import_function_count) {
+ func_index = export->index - module->import_function_count;
+ func_type = module->functions[func_index]->func_type;
+ if (func_type->param_count == 1 && func_type->result_count == 0
+ && func_type->types[0] == VALUE_TYPE_I32) {
+ bh_assert(module->free_function == (uint32)-1);
+ module->free_function = export->index;
+ LOG_VERBOSE("Found free function, name: %s, index: %u",
+ export->name, export->index);
+ }
+ }
+ }
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0 && WASM_ENABLE_LABELS_AS_VALUES != 0
+ handle_table = wasm_interp_get_handle_table();
+#endif
+
+ for (i = 0; i < module->function_count; i++) {
+ WASMFunction *func = module->functions[i];
+ if (!wasm_loader_prepare_bytecode(module, func, i, error_buf,
+ error_buf_size)) {
+ return false;
+ }
+
+ if (i == module->function_count - 1
+ && func->code + func->code_size != buf_code_end) {
+ set_error_buf(error_buf, error_buf_size,
+ "code section size mismatch");
+ return false;
+ }
+ }
+
+ if (!module->possible_memory_grow) {
+ WASMMemoryImport *memory_import;
+ WASMMemory *memory;
+
+ if (aux_data_end_global && aux_heap_base_global
+ && aux_stack_top_global) {
+ uint64 init_memory_size;
+ uint32 shrunk_memory_size = align_uint(aux_heap_base, 8);
+
+ if (module->import_memory_count) {
+ memory_import = &module->import_memories[0].u.memory;
+ init_memory_size = (uint64)memory_import->num_bytes_per_page
+ * memory_import->init_page_count;
+ if (shrunk_memory_size <= init_memory_size) {
+ /* Reset memory info to decrease memory usage */
+ memory_import->num_bytes_per_page = shrunk_memory_size;
+ memory_import->init_page_count = 1;
+ LOG_VERBOSE("Shrink import memory size to %d",
+ shrunk_memory_size);
+ }
+ }
+ if (module->memory_count) {
+ memory = &module->memories[0];
+ init_memory_size = (uint64)memory->num_bytes_per_page
+ * memory->init_page_count;
+ if (shrunk_memory_size <= init_memory_size) {
+ /* Reset memory info to decrease memory usage */
+ memory->num_bytes_per_page = shrunk_memory_size;
+ memory->init_page_count = 1;
+ LOG_VERBOSE("Shrink memory size to %d", shrunk_memory_size);
+ }
+ }
+ }
+
+#if WASM_ENABLE_MULTI_MODULE == 0
+ if (module->import_memory_count) {
+ memory_import = &module->import_memories[0].u.memory;
+ if (memory_import->init_page_count < DEFAULT_MAX_PAGES)
+ memory_import->num_bytes_per_page *=
+ memory_import->init_page_count;
+ else
+ memory_import->num_bytes_per_page = UINT32_MAX;
+
+ if (memory_import->init_page_count > 0)
+ memory_import->init_page_count = memory_import->max_page_count =
+ 1;
+ else
+ memory_import->init_page_count = memory_import->max_page_count =
+ 0;
+ }
+ if (module->memory_count) {
+ memory = &module->memories[0];
+ if (memory->init_page_count < DEFAULT_MAX_PAGES)
+ memory->num_bytes_per_page *= memory->init_page_count;
+ else
+ memory->num_bytes_per_page = UINT32_MAX;
+
+ if (memory->init_page_count > 0)
+ memory->init_page_count = memory->max_page_count = 1;
+ else
+ memory->init_page_count = memory->max_page_count = 0;
+ }
+#endif
+ }
+
+ calculate_global_data_offset(module);
+
+#if WASM_ENABLE_FAST_JIT != 0
+ if (!init_fast_jit_functions(module, error_buf, error_buf_size)) {
+ return false;
+ }
+#endif
+
+#if WASM_ENABLE_JIT != 0
+ if (!init_llvm_jit_functions_stage1(module, error_buf, error_buf_size)) {
+ return false;
+ }
+#if !(WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0)
+ if (!init_llvm_jit_functions_stage2(module, error_buf, error_buf_size)) {
+ return false;
+ }
+#else
+ /* Run aot_compile_wasm in a backend thread, so as not to block the main
+ thread fast jit execution, since applying llvm optimizations in
+ aot_compile_wasm may cost a lot of time.
+ Create thread with enough native stack to apply llvm optimizations */
+ if (os_thread_create(&module->llvm_jit_init_thread,
+ init_llvm_jit_functions_stage2_callback,
+ (void *)module, APP_THREAD_STACK_SIZE_DEFAULT * 8)
+ != 0) {
+ set_error_buf(error_buf, error_buf_size,
+ "create orcjit compile thread failed");
+ return false;
+ }
+#endif
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0
+ /* Create threads to compile the jit functions */
+ if (!compile_jit_functions(module, error_buf, error_buf_size)) {
+ return false;
+ }
+#endif
+
+#if WASM_ENABLE_MEMORY_TRACING != 0
+ wasm_runtime_dump_module_mem_consumption((WASMModuleCommon *)module);
+#endif
+ return true;
+}
+
+static WASMModule *
+create_module(char *error_buf, uint32 error_buf_size)
+{
+ WASMModule *module =
+ loader_malloc(sizeof(WASMModule), error_buf, error_buf_size);
+ bh_list_status ret;
+
+ if (!module) {
+ return NULL;
+ }
+
+ module->module_type = Wasm_Module_Bytecode;
+
+ /* Set start_function to -1, means no start function */
+ module->start_function = (uint32)-1;
+
+#if WASM_ENABLE_FAST_INTERP == 0
+ module->br_table_cache_list = &module->br_table_cache_list_head;
+ ret = bh_list_init(module->br_table_cache_list);
+ bh_assert(ret == BH_LIST_SUCCESS);
+#endif
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+ module->import_module_list = &module->import_module_list_head;
+ ret = bh_list_init(module->import_module_list);
+ bh_assert(ret == BH_LIST_SUCCESS);
+#endif
+
+#if WASM_ENABLE_DEBUG_INTERP != 0
+ ret = bh_list_init(&module->fast_opcode_list);
+ bh_assert(ret == BH_LIST_SUCCESS);
+#endif
+
+#if WASM_ENABLE_DEBUG_INTERP != 0 \
+ || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0)
+ if (os_mutex_init(&module->instance_list_lock) != 0) {
+ set_error_buf(error_buf, error_buf_size,
+ "init instance list lock failed");
+ wasm_runtime_free(module);
+ return NULL;
+ }
+#endif
+
+ (void)ret;
+ return module;
+}
+
+#if WASM_ENABLE_DEBUG_INTERP != 0
+static bool
+record_fast_op(WASMModule *module, uint8 *pos, uint8 orig_op, char *error_buf,
+ uint32 error_buf_size)
+{
+ WASMFastOPCodeNode *fast_op =
+ loader_malloc(sizeof(WASMFastOPCodeNode), error_buf, error_buf_size);
+ if (fast_op) {
+ fast_op->offset = pos - module->load_addr;
+ fast_op->orig_op = orig_op;
+ bh_list_insert(&module->fast_opcode_list, fast_op);
+ }
+ return fast_op ? true : false;
+}
+#endif
+
+WASMModule *
+wasm_loader_load_from_sections(WASMSection *section_list, char *error_buf,
+ uint32 error_buf_size)
+{
+ WASMModule *module = create_module(error_buf, error_buf_size);
+ if (!module)
+ return NULL;
+
+ if (!load_from_sections(module, section_list, false, error_buf,
+ error_buf_size)) {
+ wasm_loader_unload(module);
+ return NULL;
+ }
+
+ LOG_VERBOSE("Load module from sections success.\n");
+ return module;
+}
+
+static void
+destroy_sections(WASMSection *section_list)
+{
+ WASMSection *section = section_list, *next;
+ while (section) {
+ next = section->next;
+ wasm_runtime_free(section);
+ section = next;
+ }
+}
+
+/* clang-format off */
+static uint8 section_ids[] = {
+ SECTION_TYPE_USER,
+ SECTION_TYPE_TYPE,
+ SECTION_TYPE_IMPORT,
+ SECTION_TYPE_FUNC,
+ SECTION_TYPE_TABLE,
+ SECTION_TYPE_MEMORY,
+ SECTION_TYPE_GLOBAL,
+ SECTION_TYPE_EXPORT,
+ SECTION_TYPE_START,
+ SECTION_TYPE_ELEM,
+#if WASM_ENABLE_BULK_MEMORY != 0
+ SECTION_TYPE_DATACOUNT,
+#endif
+ SECTION_TYPE_CODE,
+ SECTION_TYPE_DATA
+};
+/* clang-format on */
+
+static uint8
+get_section_index(uint8 section_type)
+{
+ uint8 max_id = sizeof(section_ids) / sizeof(uint8);
+
+ for (uint8 i = 0; i < max_id; i++) {
+ if (section_type == section_ids[i])
+ return i;
+ }
+
+ return (uint8)-1;
+}
+
+static bool
+create_sections(const uint8 *buf, uint32 size, WASMSection **p_section_list,
+ char *error_buf, uint32 error_buf_size)
+{
+ WASMSection *section_list_end = NULL, *section;
+ const uint8 *p = buf, *p_end = buf + size /*, *section_body*/;
+ uint8 section_type, section_index, last_section_index = (uint8)-1;
+ uint32 section_size;
+
+ bh_assert(!*p_section_list);
+
+ p += 8;
+ while (p < p_end) {
+ CHECK_BUF(p, p_end, 1);
+ section_type = read_uint8(p);
+ section_index = get_section_index(section_type);
+ if (section_index != (uint8)-1) {
+ if (section_type != SECTION_TYPE_USER) {
+ /* Custom sections may be inserted at any place,
+ while other sections must occur at most once
+ and in prescribed order. */
+ if (last_section_index != (uint8)-1
+ && (section_index <= last_section_index)) {
+ set_error_buf(error_buf, error_buf_size,
+ "unexpected content after last section or "
+ "junk after last section");
+ return false;
+ }
+ last_section_index = section_index;
+ }
+ read_leb_uint32(p, p_end, section_size);
+ CHECK_BUF1(p, p_end, section_size);
+
+ if (!(section = loader_malloc(sizeof(WASMSection), error_buf,
+ error_buf_size))) {
+ return false;
+ }
+
+ section->section_type = section_type;
+ section->section_body = (uint8 *)p;
+ section->section_body_size = section_size;
+
+ if (!section_list_end)
+ *p_section_list = section_list_end = section;
+ else {
+ section_list_end->next = section;
+ section_list_end = section;
+ }
+
+ p += section_size;
+ }
+ else {
+ set_error_buf(error_buf, error_buf_size, "invalid section id");
+ return false;
+ }
+ }
+
+ return true;
+fail:
+ return false;
+}
+
+static void
+exchange32(uint8 *p_data)
+{
+ uint8 value = *p_data;
+ *p_data = *(p_data + 3);
+ *(p_data + 3) = value;
+
+ value = *(p_data + 1);
+ *(p_data + 1) = *(p_data + 2);
+ *(p_data + 2) = value;
+}
+
+static union {
+ int a;
+ char b;
+} __ue = { .a = 1 };
+
+#define is_little_endian() (__ue.b == 1)
+
+static bool
+load(const uint8 *buf, uint32 size, WASMModule *module, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *buf_end = buf + size;
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 magic_number, version;
+ WASMSection *section_list = NULL;
+
+ CHECK_BUF1(p, p_end, sizeof(uint32));
+ magic_number = read_uint32(p);
+ if (!is_little_endian())
+ exchange32((uint8 *)&magic_number);
+
+ if (magic_number != WASM_MAGIC_NUMBER) {
+ set_error_buf(error_buf, error_buf_size, "magic header not detected");
+ return false;
+ }
+
+ CHECK_BUF1(p, p_end, sizeof(uint32));
+ version = read_uint32(p);
+ if (!is_little_endian())
+ exchange32((uint8 *)&version);
+
+ if (version != WASM_CURRENT_VERSION) {
+ set_error_buf(error_buf, error_buf_size, "unknown binary version");
+ return false;
+ }
+
+ if (!create_sections(buf, size, &section_list, error_buf, error_buf_size)
+ || !load_from_sections(module, section_list, true, error_buf,
+ error_buf_size)) {
+ destroy_sections(section_list);
+ return false;
+ }
+
+ destroy_sections(section_list);
+ return true;
+fail:
+ return false;
+}
+
+#if WASM_ENABLE_LIBC_WASI != 0
+/**
+ * refer to
+ * https://github.com/WebAssembly/WASI/blob/main/design/application-abi.md
+ */
+static bool
+check_wasi_abi_compatibility(const WASMModule *module,
+#if WASM_ENABLE_MULTI_MODULE != 0
+ bool main_module,
+#endif
+ char *error_buf, uint32 error_buf_size)
+{
+ /**
+ * be careful with:
+ * wasi compatiable modules(command/reactor) which don't import any wasi
+ * APIs. Usually, a command has to import a "prox_exit" at least, but a
+ * reactor can depend on nothing. At the same time, each has its own entry
+ * point.
+ *
+ * observations:
+ * - clang always injects `_start` into a command
+ * - clang always injects `_initialize` into a reactor
+ * - `iwasm -f` allows to run a function in the reactor
+ *
+ * strong assumptions:
+ * - no one will define either `_start` or `_initialize` on purpose
+ * - `_start` should always be `void _start(void)`
+ * - `_initialize` should always be `void _initialize(void)`
+ *
+ */
+
+ /* clang-format off */
+ /**
+ *
+ * | | import_wasi_api True | | import_wasi_api False | |
+ * | ----------- | -------------------- | ---------------- | --------------------- | ---------------- |
+ * | | \_initialize() Y | \_initialize() N | \_initialize() Y | \_initialize() N |
+ * | \_start() Y | N | COMMANDER | N | COMMANDER |
+ * | \_start() N | REACTOR | N | REACTOR | OTHERS |
+ */
+ /* clang-format on */
+
+ WASMExport *initialize = NULL, *memory = NULL, *start = NULL;
+
+ /* (func (export "_start") (...) */
+ start = wasm_loader_find_export(module, "", "_start", EXPORT_KIND_FUNC,
+ error_buf, error_buf_size);
+ if (start) {
+ WASMType *func_type =
+ module->functions[start->index - module->import_function_count]
+ ->func_type;
+ if (func_type->param_count || func_type->result_count) {
+ set_error_buf(error_buf, error_buf_size,
+ "the signature of builtin _start function is wrong");
+ return false;
+ }
+ }
+
+ /* (func (export "_initialize") (...) */
+ initialize = wasm_loader_find_export(
+ module, "", "_initialize", EXPORT_KIND_FUNC, error_buf, error_buf_size);
+ if (initialize) {
+ WASMType *func_type =
+ module->functions[initialize->index - module->import_function_count]
+ ->func_type;
+ if (func_type->param_count || func_type->result_count) {
+ set_error_buf(
+ error_buf, error_buf_size,
+ "the signature of builtin _initialize function is wrong");
+ return false;
+ }
+ }
+
+ /* filter out non-wasi compatiable modules */
+ if (!module->import_wasi_api && !start && !initialize) {
+ return true;
+ }
+
+ /* should have one at least */
+ if (module->import_wasi_api && !start && !initialize) {
+ LOG_WARNING("warning: a module with WASI apis should be either "
+ "a command or a reactor");
+ }
+
+ /*
+ * there is at least one of `_start` and `_initialize` in below cases.
+ * according to the assumption, they should be all wasi compatiable
+ */
+
+ /* always can not have both at the same time */
+ if (start && initialize) {
+ set_error_buf(
+ error_buf, error_buf_size,
+ "neither a command nor a reactor can both have _start function "
+ "and _initialize function at the same time");
+ return false;
+ }
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+ /* filter out commands (with `_start`) cases */
+ if (start && !main_module) {
+ set_error_buf(
+ error_buf, error_buf_size,
+ "a command (with _start function) can not be a sub-module");
+ return false;
+ }
+#endif
+
+ /*
+ * it is ok a reactor acts as a main module,
+ * so skip the check about (with `_initialize`)
+ */
+
+ memory = wasm_loader_find_export(module, "", "memory", EXPORT_KIND_MEMORY,
+ error_buf, error_buf_size);
+ if (!memory
+#if WASM_ENABLE_LIB_WASI_THREADS != 0
+ /*
+ * with wasi-threads, it's still an open question if a memory
+ * should be exported.
+ *
+ * https://github.com/WebAssembly/wasi-threads/issues/22
+ * https://github.com/WebAssembly/WASI/issues/502
+ *
+ * Note: this code assumes the number of memories is at most 1.
+ */
+ && module->import_memory_count == 0
+#endif
+ ) {
+ set_error_buf(error_buf, error_buf_size,
+ "a module with WASI apis must export memory by default");
+ return false;
+ }
+
+ return true;
+}
+#endif
+
+WASMModule *
+wasm_loader_load(uint8 *buf, uint32 size,
+#if WASM_ENABLE_MULTI_MODULE != 0
+ bool main_module,
+#endif
+ char *error_buf, uint32 error_buf_size)
+{
+ WASMModule *module = create_module(error_buf, error_buf_size);
+ if (!module) {
+ return NULL;
+ }
+
+#if WASM_ENABLE_DEBUG_INTERP != 0 || WASM_ENABLE_FAST_JIT != 0
+ module->load_addr = (uint8 *)buf;
+ module->load_size = size;
+#endif
+
+ if (!load(buf, size, module, error_buf, error_buf_size)) {
+ goto fail;
+ }
+
+#if WASM_ENABLE_LIBC_WASI != 0
+ /* Check the WASI application ABI */
+ if (!check_wasi_abi_compatibility(module,
+#if WASM_ENABLE_MULTI_MODULE != 0
+ main_module,
+#endif
+ error_buf, error_buf_size)) {
+ goto fail;
+ }
+#endif
+
+ LOG_VERBOSE("Load module success.\n");
+ return module;
+
+fail:
+ wasm_loader_unload(module);
+ return NULL;
+}
+
+void
+wasm_loader_unload(WASMModule *module)
+{
+ uint32 i;
+
+ if (!module)
+ return;
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0
+ module->orcjit_stop_compiling = true;
+ if (module->llvm_jit_init_thread)
+ os_thread_join(module->llvm_jit_init_thread, NULL);
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0
+ /* Stop Fast/LLVM JIT compilation firstly to avoid accessing
+ module internal data after they were freed */
+ orcjit_stop_compile_threads(module);
+#endif
+
+#if WASM_ENABLE_JIT != 0
+ if (module->func_ptrs)
+ wasm_runtime_free(module->func_ptrs);
+ if (module->comp_ctx)
+ aot_destroy_comp_context(module->comp_ctx);
+ if (module->comp_data)
+ aot_destroy_comp_data(module->comp_data);
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0
+ if (module->tierup_wait_lock_inited) {
+ os_mutex_destroy(&module->tierup_wait_lock);
+ os_cond_destroy(&module->tierup_wait_cond);
+ }
+#endif
+
+ if (module->types) {
+ for (i = 0; i < module->type_count; i++) {
+ if (module->types[i])
+ destroy_wasm_type(module->types[i]);
+ }
+ wasm_runtime_free(module->types);
+ }
+
+ if (module->imports)
+ wasm_runtime_free(module->imports);
+
+ if (module->functions) {
+ for (i = 0; i < module->function_count; i++) {
+ if (module->functions[i]) {
+ if (module->functions[i]->local_offsets)
+ wasm_runtime_free(module->functions[i]->local_offsets);
+#if WASM_ENABLE_FAST_INTERP != 0
+ if (module->functions[i]->code_compiled)
+ wasm_runtime_free(module->functions[i]->code_compiled);
+ if (module->functions[i]->consts)
+ wasm_runtime_free(module->functions[i]->consts);
+#endif
+#if WASM_ENABLE_FAST_JIT != 0
+ if (module->functions[i]->fast_jit_jitted_code) {
+ jit_code_cache_free(
+ module->functions[i]->fast_jit_jitted_code);
+ }
+#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
+ if (module->functions[i]->call_to_fast_jit_from_llvm_jit) {
+ jit_code_cache_free(
+ module->functions[i]->call_to_fast_jit_from_llvm_jit);
+ }
+#endif
+#endif
+ wasm_runtime_free(module->functions[i]);
+ }
+ }
+ wasm_runtime_free(module->functions);
+ }
+
+ if (module->tables)
+ wasm_runtime_free(module->tables);
+
+ if (module->memories)
+ wasm_runtime_free(module->memories);
+
+ if (module->globals)
+ wasm_runtime_free(module->globals);
+
+ if (module->exports)
+ wasm_runtime_free(module->exports);
+
+ if (module->table_segments) {
+ for (i = 0; i < module->table_seg_count; i++) {
+ if (module->table_segments[i].func_indexes)
+ wasm_runtime_free(module->table_segments[i].func_indexes);
+ }
+ wasm_runtime_free(module->table_segments);
+ }
+
+ if (module->data_segments) {
+ for (i = 0; i < module->data_seg_count; i++) {
+ if (module->data_segments[i])
+ wasm_runtime_free(module->data_segments[i]);
+ }
+ wasm_runtime_free(module->data_segments);
+ }
+
+ if (module->const_str_list) {
+ StringNode *node = module->const_str_list, *node_next;
+ while (node) {
+ node_next = node->next;
+ wasm_runtime_free(node);
+ node = node_next;
+ }
+ }
+
+#if WASM_ENABLE_FAST_INTERP == 0
+ if (module->br_table_cache_list) {
+ BrTableCache *node = bh_list_first_elem(module->br_table_cache_list);
+ BrTableCache *node_next;
+ while (node) {
+ node_next = bh_list_elem_next(node);
+ wasm_runtime_free(node);
+ node = node_next;
+ }
+ }
+#endif
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+ /* just release the sub module list */
+ if (module->import_module_list) {
+ WASMRegisteredModule *node =
+ bh_list_first_elem(module->import_module_list);
+ while (node) {
+ WASMRegisteredModule *next = bh_list_elem_next(node);
+ bh_list_remove(module->import_module_list, node);
+ /*
+ * unload(sub_module) will be trigged during runtime_destroy().
+ * every module in the global module list will be unloaded one by
+ * one. so don't worry.
+ */
+ wasm_runtime_free(node);
+ /*
+ * the module file reading buffer will be released
+ * in runtime_destroy()
+ */
+ node = next;
+ }
+ }
+#endif
+
+#if WASM_ENABLE_DEBUG_INTERP != 0
+ WASMFastOPCodeNode *fast_opcode =
+ bh_list_first_elem(&module->fast_opcode_list);
+ while (fast_opcode) {
+ WASMFastOPCodeNode *next = bh_list_elem_next(fast_opcode);
+ wasm_runtime_free(fast_opcode);
+ fast_opcode = next;
+ }
+#endif
+
+#if WASM_ENABLE_DEBUG_INTERP != 0 \
+ || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0)
+ os_mutex_destroy(&module->instance_list_lock);
+#endif
+
+#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
+ wasm_runtime_destroy_custom_sections(module->custom_section_list);
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0
+ if (module->fast_jit_func_ptrs) {
+ wasm_runtime_free(module->fast_jit_func_ptrs);
+ }
+
+ for (i = 0; i < WASM_ORC_JIT_BACKEND_THREAD_NUM; i++) {
+ if (module->fast_jit_thread_locks_inited[i]) {
+ os_mutex_destroy(&module->fast_jit_thread_locks[i]);
+ }
+ }
+#endif
+
+ wasm_runtime_free(module);
+}
+
+bool
+wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
+ const uint8 *start_addr, const uint8 *code_end_addr,
+ uint8 label_type, uint8 **p_else_addr,
+ uint8 **p_end_addr)
+{
+ const uint8 *p = start_addr, *p_end = code_end_addr;
+ uint8 *else_addr = NULL;
+ char error_buf[128];
+ uint32 block_nested_depth = 1, count, i, j, t;
+ uint32 error_buf_size = sizeof(error_buf);
+ uint8 opcode, u8;
+ BlockAddr block_stack[16] = { { 0 } }, *block;
+
+ i = ((uintptr_t)start_addr) & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1);
+ block = block_addr_cache + BLOCK_ADDR_CONFLICT_SIZE * i;
+
+ for (j = 0; j < BLOCK_ADDR_CONFLICT_SIZE; j++) {
+ if (block[j].start_addr == start_addr) {
+ /* Cache hit */
+ *p_else_addr = block[j].else_addr;
+ *p_end_addr = block[j].end_addr;
+ return true;
+ }
+ }
+
+ /* Cache unhit */
+ block_stack[0].start_addr = start_addr;
+
+ while (p < code_end_addr) {
+ opcode = *p++;
+#if WASM_ENABLE_DEBUG_INTERP != 0
+ op_break_retry:
+#endif
+ switch (opcode) {
+ case WASM_OP_UNREACHABLE:
+ case WASM_OP_NOP:
+ break;
+
+ case WASM_OP_BLOCK:
+ case WASM_OP_LOOP:
+ case WASM_OP_IF:
+ /* block result type: 0x40/0x7F/0x7E/0x7D/0x7C */
+ u8 = read_uint8(p);
+ if (block_nested_depth
+ < sizeof(block_stack) / sizeof(BlockAddr)) {
+ block_stack[block_nested_depth].start_addr = p;
+ block_stack[block_nested_depth].else_addr = NULL;
+ }
+ block_nested_depth++;
+ break;
+
+ case EXT_OP_BLOCK:
+ case EXT_OP_LOOP:
+ case EXT_OP_IF:
+ /* block type */
+ skip_leb_uint32(p, p_end);
+ if (block_nested_depth
+ < sizeof(block_stack) / sizeof(BlockAddr)) {
+ block_stack[block_nested_depth].start_addr = p;
+ block_stack[block_nested_depth].else_addr = NULL;
+ }
+ block_nested_depth++;
+ break;
+
+ case WASM_OP_ELSE:
+ if (label_type == LABEL_TYPE_IF && block_nested_depth == 1)
+ else_addr = (uint8 *)(p - 1);
+ if (block_nested_depth - 1
+ < sizeof(block_stack) / sizeof(BlockAddr))
+ block_stack[block_nested_depth - 1].else_addr =
+ (uint8 *)(p - 1);
+ break;
+
+ case WASM_OP_END:
+ if (block_nested_depth == 1) {
+ if (label_type == LABEL_TYPE_IF)
+ *p_else_addr = else_addr;
+ *p_end_addr = (uint8 *)(p - 1);
+
+ block_stack[0].end_addr = (uint8 *)(p - 1);
+ for (t = 0; t < sizeof(block_stack) / sizeof(BlockAddr);
+ t++) {
+ start_addr = block_stack[t].start_addr;
+ if (start_addr) {
+ i = ((uintptr_t)start_addr)
+ & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1);
+ block =
+ block_addr_cache + BLOCK_ADDR_CONFLICT_SIZE * i;
+ for (j = 0; j < BLOCK_ADDR_CONFLICT_SIZE; j++)
+ if (!block[j].start_addr)
+ break;
+
+ if (j == BLOCK_ADDR_CONFLICT_SIZE) {
+ memmove(block + 1, block,
+ (BLOCK_ADDR_CONFLICT_SIZE - 1)
+ * sizeof(BlockAddr));
+ j = 0;
+ }
+ block[j].start_addr = block_stack[t].start_addr;
+ block[j].else_addr = block_stack[t].else_addr;
+ block[j].end_addr = block_stack[t].end_addr;
+ }
+ else
+ break;
+ }
+ return true;
+ }
+ else {
+ block_nested_depth--;
+ if (block_nested_depth
+ < sizeof(block_stack) / sizeof(BlockAddr))
+ block_stack[block_nested_depth].end_addr =
+ (uint8 *)(p - 1);
+ }
+ break;
+
+ case WASM_OP_BR:
+ case WASM_OP_BR_IF:
+ skip_leb_uint32(p, p_end); /* labelidx */
+ break;
+
+ case WASM_OP_BR_TABLE:
+ read_leb_uint32(p, p_end, count); /* lable num */
+#if WASM_ENABLE_FAST_INTERP != 0
+ for (i = 0; i <= count; i++) /* lableidxs */
+ skip_leb_uint32(p, p_end);
+#else
+ p += count + 1;
+ while (*p == WASM_OP_NOP)
+ p++;
+#endif
+ break;
+
+#if WASM_ENABLE_FAST_INTERP == 0
+ case EXT_OP_BR_TABLE_CACHE:
+ read_leb_uint32(p, p_end, count); /* lable num */
+ while (*p == WASM_OP_NOP)
+ p++;
+ break;
+#endif
+
+ case WASM_OP_RETURN:
+ break;
+
+ case WASM_OP_CALL:
+#if WASM_ENABLE_TAIL_CALL != 0
+ case WASM_OP_RETURN_CALL:
+#endif
+ skip_leb_uint32(p, p_end); /* funcidx */
+ break;
+
+ case WASM_OP_CALL_INDIRECT:
+#if WASM_ENABLE_TAIL_CALL != 0
+ case WASM_OP_RETURN_CALL_INDIRECT:
+#endif
+ skip_leb_uint32(p, p_end); /* typeidx */
+ CHECK_BUF(p, p_end, 1);
+ u8 = read_uint8(p); /* 0x00 */
+ break;
+
+ case WASM_OP_DROP:
+ case WASM_OP_SELECT:
+ case WASM_OP_DROP_64:
+ case WASM_OP_SELECT_64:
+ break;
+
+#if WASM_ENABLE_REF_TYPES != 0
+ case WASM_OP_SELECT_T:
+ skip_leb_uint32(p, p_end); /* vec length */
+ CHECK_BUF(p, p_end, 1);
+ u8 = read_uint8(p); /* typeidx */
+ break;
+ case WASM_OP_TABLE_GET:
+ case WASM_OP_TABLE_SET:
+ skip_leb_uint32(p, p_end); /* table index */
+ break;
+ case WASM_OP_REF_NULL:
+ CHECK_BUF(p, p_end, 1);
+ u8 = read_uint8(p); /* type */
+ break;
+ case WASM_OP_REF_IS_NULL:
+ break;
+ case WASM_OP_REF_FUNC:
+ skip_leb_uint32(p, p_end); /* func index */
+ break;
+#endif /* WASM_ENABLE_REF_TYPES */
+ case WASM_OP_GET_LOCAL:
+ case WASM_OP_SET_LOCAL:
+ case WASM_OP_TEE_LOCAL:
+ case WASM_OP_GET_GLOBAL:
+ case WASM_OP_SET_GLOBAL:
+ case WASM_OP_GET_GLOBAL_64:
+ case WASM_OP_SET_GLOBAL_64:
+ case WASM_OP_SET_GLOBAL_AUX_STACK:
+ skip_leb_uint32(p, p_end); /* local index */
+ break;
+
+ case EXT_OP_GET_LOCAL_FAST:
+ case EXT_OP_SET_LOCAL_FAST:
+ case EXT_OP_TEE_LOCAL_FAST:
+ CHECK_BUF(p, p_end, 1);
+ p++;
+ break;
+
+ case WASM_OP_I32_LOAD:
+ case WASM_OP_I64_LOAD:
+ case WASM_OP_F32_LOAD:
+ case WASM_OP_F64_LOAD:
+ case WASM_OP_I32_LOAD8_S:
+ case WASM_OP_I32_LOAD8_U:
+ case WASM_OP_I32_LOAD16_S:
+ case WASM_OP_I32_LOAD16_U:
+ case WASM_OP_I64_LOAD8_S:
+ case WASM_OP_I64_LOAD8_U:
+ case WASM_OP_I64_LOAD16_S:
+ case WASM_OP_I64_LOAD16_U:
+ case WASM_OP_I64_LOAD32_S:
+ case WASM_OP_I64_LOAD32_U:
+ case WASM_OP_I32_STORE:
+ case WASM_OP_I64_STORE:
+ case WASM_OP_F32_STORE:
+ case WASM_OP_F64_STORE:
+ case WASM_OP_I32_STORE8:
+ case WASM_OP_I32_STORE16:
+ case WASM_OP_I64_STORE8:
+ case WASM_OP_I64_STORE16:
+ case WASM_OP_I64_STORE32:
+ skip_leb_uint32(p, p_end); /* align */
+ skip_leb_uint32(p, p_end); /* offset */
+ break;
+
+ case WASM_OP_MEMORY_SIZE:
+ case WASM_OP_MEMORY_GROW:
+ skip_leb_uint32(p, p_end); /* 0x00 */
+ break;
+
+ case WASM_OP_I32_CONST:
+ skip_leb_int32(p, p_end);
+ break;
+ case WASM_OP_I64_CONST:
+ skip_leb_int64(p, p_end);
+ break;
+ case WASM_OP_F32_CONST:
+ p += sizeof(float32);
+ break;
+ case WASM_OP_F64_CONST:
+ p += sizeof(float64);
+ break;
+
+ case WASM_OP_I32_EQZ:
+ case WASM_OP_I32_EQ:
+ case WASM_OP_I32_NE:
+ case WASM_OP_I32_LT_S:
+ case WASM_OP_I32_LT_U:
+ case WASM_OP_I32_GT_S:
+ case WASM_OP_I32_GT_U:
+ case WASM_OP_I32_LE_S:
+ case WASM_OP_I32_LE_U:
+ case WASM_OP_I32_GE_S:
+ case WASM_OP_I32_GE_U:
+ case WASM_OP_I64_EQZ:
+ case WASM_OP_I64_EQ:
+ case WASM_OP_I64_NE:
+ case WASM_OP_I64_LT_S:
+ case WASM_OP_I64_LT_U:
+ case WASM_OP_I64_GT_S:
+ case WASM_OP_I64_GT_U:
+ case WASM_OP_I64_LE_S:
+ case WASM_OP_I64_LE_U:
+ case WASM_OP_I64_GE_S:
+ case WASM_OP_I64_GE_U:
+ case WASM_OP_F32_EQ:
+ case WASM_OP_F32_NE:
+ case WASM_OP_F32_LT:
+ case WASM_OP_F32_GT:
+ case WASM_OP_F32_LE:
+ case WASM_OP_F32_GE:
+ case WASM_OP_F64_EQ:
+ case WASM_OP_F64_NE:
+ case WASM_OP_F64_LT:
+ case WASM_OP_F64_GT:
+ case WASM_OP_F64_LE:
+ case WASM_OP_F64_GE:
+ case WASM_OP_I32_CLZ:
+ case WASM_OP_I32_CTZ:
+ case WASM_OP_I32_POPCNT:
+ case WASM_OP_I32_ADD:
+ case WASM_OP_I32_SUB:
+ case WASM_OP_I32_MUL:
+ case WASM_OP_I32_DIV_S:
+ case WASM_OP_I32_DIV_U:
+ case WASM_OP_I32_REM_S:
+ case WASM_OP_I32_REM_U:
+ case WASM_OP_I32_AND:
+ case WASM_OP_I32_OR:
+ case WASM_OP_I32_XOR:
+ case WASM_OP_I32_SHL:
+ case WASM_OP_I32_SHR_S:
+ case WASM_OP_I32_SHR_U:
+ case WASM_OP_I32_ROTL:
+ case WASM_OP_I32_ROTR:
+ case WASM_OP_I64_CLZ:
+ case WASM_OP_I64_CTZ:
+ case WASM_OP_I64_POPCNT:
+ case WASM_OP_I64_ADD:
+ case WASM_OP_I64_SUB:
+ case WASM_OP_I64_MUL:
+ case WASM_OP_I64_DIV_S:
+ case WASM_OP_I64_DIV_U:
+ case WASM_OP_I64_REM_S:
+ case WASM_OP_I64_REM_U:
+ case WASM_OP_I64_AND:
+ case WASM_OP_I64_OR:
+ case WASM_OP_I64_XOR:
+ case WASM_OP_I64_SHL:
+ case WASM_OP_I64_SHR_S:
+ case WASM_OP_I64_SHR_U:
+ case WASM_OP_I64_ROTL:
+ case WASM_OP_I64_ROTR:
+ case WASM_OP_F32_ABS:
+ case WASM_OP_F32_NEG:
+ case WASM_OP_F32_CEIL:
+ case WASM_OP_F32_FLOOR:
+ case WASM_OP_F32_TRUNC:
+ case WASM_OP_F32_NEAREST:
+ case WASM_OP_F32_SQRT:
+ case WASM_OP_F32_ADD:
+ case WASM_OP_F32_SUB:
+ case WASM_OP_F32_MUL:
+ case WASM_OP_F32_DIV:
+ case WASM_OP_F32_MIN:
+ case WASM_OP_F32_MAX:
+ case WASM_OP_F32_COPYSIGN:
+ case WASM_OP_F64_ABS:
+ case WASM_OP_F64_NEG:
+ case WASM_OP_F64_CEIL:
+ case WASM_OP_F64_FLOOR:
+ case WASM_OP_F64_TRUNC:
+ case WASM_OP_F64_NEAREST:
+ case WASM_OP_F64_SQRT:
+ case WASM_OP_F64_ADD:
+ case WASM_OP_F64_SUB:
+ case WASM_OP_F64_MUL:
+ case WASM_OP_F64_DIV:
+ case WASM_OP_F64_MIN:
+ case WASM_OP_F64_MAX:
+ case WASM_OP_F64_COPYSIGN:
+ case WASM_OP_I32_WRAP_I64:
+ case WASM_OP_I32_TRUNC_S_F32:
+ case WASM_OP_I32_TRUNC_U_F32:
+ case WASM_OP_I32_TRUNC_S_F64:
+ case WASM_OP_I32_TRUNC_U_F64:
+ case WASM_OP_I64_EXTEND_S_I32:
+ case WASM_OP_I64_EXTEND_U_I32:
+ case WASM_OP_I64_TRUNC_S_F32:
+ case WASM_OP_I64_TRUNC_U_F32:
+ case WASM_OP_I64_TRUNC_S_F64:
+ case WASM_OP_I64_TRUNC_U_F64:
+ case WASM_OP_F32_CONVERT_S_I32:
+ case WASM_OP_F32_CONVERT_U_I32:
+ case WASM_OP_F32_CONVERT_S_I64:
+ case WASM_OP_F32_CONVERT_U_I64:
+ case WASM_OP_F32_DEMOTE_F64:
+ case WASM_OP_F64_CONVERT_S_I32:
+ case WASM_OP_F64_CONVERT_U_I32:
+ case WASM_OP_F64_CONVERT_S_I64:
+ case WASM_OP_F64_CONVERT_U_I64:
+ case WASM_OP_F64_PROMOTE_F32:
+ case WASM_OP_I32_REINTERPRET_F32:
+ case WASM_OP_I64_REINTERPRET_F64:
+ case WASM_OP_F32_REINTERPRET_I32:
+ case WASM_OP_F64_REINTERPRET_I64:
+ case WASM_OP_I32_EXTEND8_S:
+ case WASM_OP_I32_EXTEND16_S:
+ case WASM_OP_I64_EXTEND8_S:
+ case WASM_OP_I64_EXTEND16_S:
+ case WASM_OP_I64_EXTEND32_S:
+ break;
+ case WASM_OP_MISC_PREFIX:
+ {
+ uint32 opcode1;
+
+ read_leb_uint32(p, p_end, opcode1);
+
+ switch (opcode1) {
+ case WASM_OP_I32_TRUNC_SAT_S_F32:
+ case WASM_OP_I32_TRUNC_SAT_U_F32:
+ case WASM_OP_I32_TRUNC_SAT_S_F64:
+ case WASM_OP_I32_TRUNC_SAT_U_F64:
+ case WASM_OP_I64_TRUNC_SAT_S_F32:
+ case WASM_OP_I64_TRUNC_SAT_U_F32:
+ case WASM_OP_I64_TRUNC_SAT_S_F64:
+ case WASM_OP_I64_TRUNC_SAT_U_F64:
+ break;
+#if WASM_ENABLE_BULK_MEMORY != 0
+ case WASM_OP_MEMORY_INIT:
+ skip_leb_uint32(p, p_end);
+ /* skip memory idx */
+ p++;
+ break;
+ case WASM_OP_DATA_DROP:
+ skip_leb_uint32(p, p_end);
+ break;
+ case WASM_OP_MEMORY_COPY:
+ /* skip two memory idx */
+ p += 2;
+ break;
+ case WASM_OP_MEMORY_FILL:
+ /* skip memory idx */
+ p++;
+ break;
+#endif /* WASM_ENABLE_BULK_MEMORY */
+#if WASM_ENABLE_REF_TYPES != 0
+ case WASM_OP_TABLE_INIT:
+ case WASM_OP_TABLE_COPY:
+ /* tableidx */
+ skip_leb_uint32(p, p_end);
+ /* elemidx */
+ skip_leb_uint32(p, p_end);
+ break;
+ case WASM_OP_ELEM_DROP:
+ /* elemidx */
+ skip_leb_uint32(p, p_end);
+ break;
+ case WASM_OP_TABLE_SIZE:
+ case WASM_OP_TABLE_GROW:
+ case WASM_OP_TABLE_FILL:
+ skip_leb_uint32(p, p_end); /* table idx */
+ break;
+#endif /* WASM_ENABLE_REF_TYPES */
+ default:
+ return false;
+ }
+ break;
+ }
+
+#if WASM_ENABLE_SIMD != 0
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+ case WASM_OP_SIMD_PREFIX:
+ {
+ /* TODO: shall we ceate a table to be friendly to branch
+ * prediction */
+ opcode = read_uint8(p);
+ /* follow the order of enum WASMSimdEXTOpcode in wasm_opcode.h
+ */
+ switch (opcode) {
+ case SIMD_v128_load:
+ case SIMD_v128_load8x8_s:
+ case SIMD_v128_load8x8_u:
+ case SIMD_v128_load16x4_s:
+ case SIMD_v128_load16x4_u:
+ case SIMD_v128_load32x2_s:
+ case SIMD_v128_load32x2_u:
+ case SIMD_v128_load8_splat:
+ case SIMD_v128_load16_splat:
+ case SIMD_v128_load32_splat:
+ case SIMD_v128_load64_splat:
+ case SIMD_v128_store:
+ /* memarg align */
+ skip_leb_uint32(p, p_end);
+ /* memarg offset*/
+ skip_leb_uint32(p, p_end);
+ break;
+
+ case SIMD_v128_const:
+ case SIMD_v8x16_shuffle:
+ /* immByte[16] immLaneId[16] */
+ CHECK_BUF1(p, p_end, 16);
+ p += 16;
+ break;
+
+ case SIMD_i8x16_extract_lane_s:
+ case SIMD_i8x16_extract_lane_u:
+ case SIMD_i8x16_replace_lane:
+ case SIMD_i16x8_extract_lane_s:
+ case SIMD_i16x8_extract_lane_u:
+ case SIMD_i16x8_replace_lane:
+ case SIMD_i32x4_extract_lane:
+ case SIMD_i32x4_replace_lane:
+ case SIMD_i64x2_extract_lane:
+ case SIMD_i64x2_replace_lane:
+ case SIMD_f32x4_extract_lane:
+ case SIMD_f32x4_replace_lane:
+ case SIMD_f64x2_extract_lane:
+ case SIMD_f64x2_replace_lane:
+ /* ImmLaneId */
+ CHECK_BUF(p, p_end, 1);
+ p++;
+ break;
+
+ case SIMD_v128_load8_lane:
+ case SIMD_v128_load16_lane:
+ case SIMD_v128_load32_lane:
+ case SIMD_v128_load64_lane:
+ case SIMD_v128_store8_lane:
+ case SIMD_v128_store16_lane:
+ case SIMD_v128_store32_lane:
+ case SIMD_v128_store64_lane:
+ /* memarg align */
+ skip_leb_uint32(p, p_end);
+ /* memarg offset*/
+ skip_leb_uint32(p, p_end);
+ /* ImmLaneId */
+ CHECK_BUF(p, p_end, 1);
+ p++;
+ break;
+
+ case SIMD_v128_load32_zero:
+ case SIMD_v128_load64_zero:
+ /* memarg align */
+ skip_leb_uint32(p, p_end);
+ /* memarg offset*/
+ skip_leb_uint32(p, p_end);
+ break;
+
+ default:
+ /*
+ * since latest SIMD specific used almost every value
+ * from 0x00 to 0xff, the default branch will present
+ * all opcodes without imm
+ * https://github.com/WebAssembly/simd/blob/main/proposals/simd/NewOpcodes.md
+ */
+ break;
+ }
+ break;
+ }
+#endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) */
+#endif /* end of WASM_ENABLE_SIMD */
+
+#if WASM_ENABLE_SHARED_MEMORY != 0
+ case WASM_OP_ATOMIC_PREFIX:
+ {
+ /* atomic_op (1 u8) + memarg (2 u32_leb) */
+ opcode = read_uint8(p);
+ if (opcode != WASM_OP_ATOMIC_FENCE) {
+ skip_leb_uint32(p, p_end); /* align */
+ skip_leb_uint32(p, p_end); /* offset */
+ }
+ else {
+ /* atomic.fence doesn't have memarg */
+ p++;
+ }
+ break;
+ }
+#endif
+#if WASM_ENABLE_DEBUG_INTERP != 0
+ case DEBUG_OP_BREAK:
+ {
+ WASMDebugInstance *debug_instance =
+ wasm_exec_env_get_instance(exec_env);
+ char orignal_opcode[1];
+ uint64 size = 1;
+ WASMModuleInstance *module_inst =
+ (WASMModuleInstance *)exec_env->module_inst;
+ uint64 offset = (p - 1) >= module_inst->module->load_addr
+ ? (p - 1) - module_inst->module->load_addr
+ : ~0;
+ if (debug_instance) {
+ if (wasm_debug_instance_get_obj_mem(debug_instance, offset,
+ orignal_opcode, &size)
+ && size == 1) {
+ LOG_VERBOSE("WASM loader find OP_BREAK , recover it "
+ "with %02x: ",
+ orignal_opcode[0]);
+ opcode = orignal_opcode[0];
+ goto op_break_retry;
+ }
+ }
+ break;
+ }
+#endif
+
+ default:
+ return false;
+ }
+ }
+
+ (void)u8;
+ (void)exec_env;
+ return false;
+fail:
+ return false;
+}
+
+#define REF_ANY VALUE_TYPE_ANY
+#define REF_I32 VALUE_TYPE_I32
+#define REF_F32 VALUE_TYPE_F32
+#define REF_I64_1 VALUE_TYPE_I64
+#define REF_I64_2 VALUE_TYPE_I64
+#define REF_F64_1 VALUE_TYPE_F64
+#define REF_F64_2 VALUE_TYPE_F64
+#define REF_V128_1 VALUE_TYPE_V128
+#define REF_V128_2 VALUE_TYPE_V128
+#define REF_V128_3 VALUE_TYPE_V128
+#define REF_V128_4 VALUE_TYPE_V128
+#define REF_FUNCREF VALUE_TYPE_FUNCREF
+#define REF_EXTERNREF VALUE_TYPE_EXTERNREF
+
+#if WASM_ENABLE_FAST_INTERP != 0
+
+#if WASM_DEBUG_PREPROCESSOR != 0
+#define LOG_OP(...) os_printf(__VA_ARGS__)
+#else
+#define LOG_OP(...) (void)0
+#endif
+
+#define PATCH_ELSE 0
+#define PATCH_END 1
+typedef struct BranchBlockPatch {
+ struct BranchBlockPatch *next;
+ uint8 patch_type;
+ uint8 *code_compiled;
+} BranchBlockPatch;
+#endif
+
+typedef struct BranchBlock {
+ uint8 label_type;
+ BlockType block_type;
+ uint8 *start_addr;
+ uint8 *else_addr;
+ uint8 *end_addr;
+ uint32 stack_cell_num;
+#if WASM_ENABLE_FAST_INTERP != 0
+ uint16 dynamic_offset;
+ uint8 *code_compiled;
+ BranchBlockPatch *patch_list;
+ /* This is used to save params frame_offset of of if block */
+ int16 *param_frame_offsets;
+#endif
+
+ /* Indicate the operand stack is in polymorphic state.
+ * If the opcode is one of unreachable/br/br_table/return, stack is marked
+ * to polymorphic state until the block's 'end' opcode is processed.
+ * If stack is in polymorphic state and stack is empty, instruction can
+ * pop any type of value directly without decreasing stack top pointer
+ * and stack cell num. */
+ bool is_stack_polymorphic;
+} BranchBlock;
+
+typedef struct WASMLoaderContext {
+ /* frame ref stack */
+ uint8 *frame_ref;
+ uint8 *frame_ref_bottom;
+ uint8 *frame_ref_boundary;
+ uint32 frame_ref_size;
+ uint32 stack_cell_num;
+ uint32 max_stack_cell_num;
+
+ /* frame csp stack */
+ BranchBlock *frame_csp;
+ BranchBlock *frame_csp_bottom;
+ BranchBlock *frame_csp_boundary;
+ uint32 frame_csp_size;
+ uint32 csp_num;
+ uint32 max_csp_num;
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* frame offset stack */
+ int16 *frame_offset;
+ int16 *frame_offset_bottom;
+ int16 *frame_offset_boundary;
+ uint32 frame_offset_size;
+ int16 dynamic_offset;
+ int16 start_dynamic_offset;
+ int16 max_dynamic_offset;
+
+ /* preserved local offset */
+ int16 preserved_local_offset;
+
+ /* const buffer */
+ uint8 *const_buf;
+ uint16 num_const;
+ uint16 const_cell_num;
+ uint32 const_buf_size;
+
+ /* processed code */
+ uint8 *p_code_compiled;
+ uint8 *p_code_compiled_end;
+ uint32 code_compiled_size;
+ /* If the last opcode will be dropped, the peak memory usage will be larger
+ * than the final code_compiled_size, we record the peak size to ensure
+ * there will not be invalid memory access during second traverse */
+ uint32 code_compiled_peak_size;
+#endif
+} WASMLoaderContext;
+
+typedef struct Const {
+ WASMValue value;
+ uint16 slot_index;
+ uint8 value_type;
+} Const;
+
+static void *
+memory_realloc(void *mem_old, uint32 size_old, uint32 size_new, char *error_buf,
+ uint32 error_buf_size)
+{
+ uint8 *mem_new;
+ bh_assert(size_new > size_old);
+ if ((mem_new = loader_malloc(size_new, error_buf, error_buf_size))) {
+ bh_memcpy_s(mem_new, size_new, mem_old, size_old);
+ memset(mem_new + size_old, 0, size_new - size_old);
+ wasm_runtime_free(mem_old);
+ }
+ return mem_new;
+}
+
+#define MEM_REALLOC(mem, size_old, size_new) \
+ do { \
+ void *mem_new = memory_realloc(mem, size_old, size_new, error_buf, \
+ error_buf_size); \
+ if (!mem_new) \
+ goto fail; \
+ mem = mem_new; \
+ } while (0)
+
+#define CHECK_CSP_PUSH() \
+ do { \
+ if (ctx->frame_csp >= ctx->frame_csp_boundary) { \
+ MEM_REALLOC( \
+ ctx->frame_csp_bottom, ctx->frame_csp_size, \
+ (uint32)(ctx->frame_csp_size + 8 * sizeof(BranchBlock))); \
+ ctx->frame_csp_size += (uint32)(8 * sizeof(BranchBlock)); \
+ ctx->frame_csp_boundary = \
+ ctx->frame_csp_bottom \
+ + ctx->frame_csp_size / sizeof(BranchBlock); \
+ ctx->frame_csp = ctx->frame_csp_bottom + ctx->csp_num; \
+ } \
+ } while (0)
+
+#define CHECK_CSP_POP() \
+ do { \
+ if (ctx->csp_num < 1) { \
+ set_error_buf(error_buf, error_buf_size, \
+ "type mismatch: " \
+ "expect data but block stack was empty"); \
+ goto fail; \
+ } \
+ } while (0)
+
+#if WASM_ENABLE_FAST_INTERP != 0
+static bool
+check_offset_push(WASMLoaderContext *ctx, char *error_buf,
+ uint32 error_buf_size)
+{
+ uint32 cell_num = (uint32)(ctx->frame_offset - ctx->frame_offset_bottom);
+ if (ctx->frame_offset >= ctx->frame_offset_boundary) {
+ MEM_REALLOC(ctx->frame_offset_bottom, ctx->frame_offset_size,
+ ctx->frame_offset_size + 16);
+ ctx->frame_offset_size += 16;
+ ctx->frame_offset_boundary =
+ ctx->frame_offset_bottom + ctx->frame_offset_size / sizeof(int16);
+ ctx->frame_offset = ctx->frame_offset_bottom + cell_num;
+ }
+ return true;
+fail:
+ return false;
+}
+
+static bool
+check_offset_pop(WASMLoaderContext *ctx, uint32 cells)
+{
+ if (ctx->frame_offset - cells < ctx->frame_offset_bottom)
+ return false;
+ return true;
+}
+
+static void
+free_label_patch_list(BranchBlock *frame_csp)
+{
+ BranchBlockPatch *label_patch = frame_csp->patch_list;
+ BranchBlockPatch *next;
+ while (label_patch != NULL) {
+ next = label_patch->next;
+ wasm_runtime_free(label_patch);
+ label_patch = next;
+ }
+ frame_csp->patch_list = NULL;
+}
+
+static void
+free_all_label_patch_lists(BranchBlock *frame_csp, uint32 csp_num)
+{
+ BranchBlock *tmp_csp = frame_csp;
+
+ for (uint32 i = 0; i < csp_num; i++) {
+ free_label_patch_list(tmp_csp);
+ tmp_csp++;
+ }
+}
+
+#endif /* end of WASM_ENABLE_FAST_INTERP */
+
+static bool
+check_stack_push(WASMLoaderContext *ctx, char *error_buf, uint32 error_buf_size)
+{
+ if (ctx->frame_ref >= ctx->frame_ref_boundary) {
+ MEM_REALLOC(ctx->frame_ref_bottom, ctx->frame_ref_size,
+ ctx->frame_ref_size + 16);
+ ctx->frame_ref_size += 16;
+ ctx->frame_ref_boundary = ctx->frame_ref_bottom + ctx->frame_ref_size;
+ ctx->frame_ref = ctx->frame_ref_bottom + ctx->stack_cell_num;
+ }
+ return true;
+fail:
+ return false;
+}
+
+static bool
+check_stack_top_values(uint8 *frame_ref, int32 stack_cell_num, uint8 type,
+ char *error_buf, uint32 error_buf_size)
+{
+ if ((is_32bit_type(type) && stack_cell_num < 1)
+ || (is_64bit_type(type) && stack_cell_num < 2)
+#if WASM_ENABLE_SIMD != 0
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+ || (type == VALUE_TYPE_V128 && stack_cell_num < 4)
+#endif
+#endif
+ ) {
+ set_error_buf(error_buf, error_buf_size,
+ "type mismatch: expect data but stack was empty");
+ return false;
+ }
+
+ if ((is_32bit_type(type) && *(frame_ref - 1) != type)
+ || (is_64bit_type(type)
+ && (*(frame_ref - 2) != type || *(frame_ref - 1) != type))
+#if WASM_ENABLE_SIMD != 0
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+ || (type == VALUE_TYPE_V128
+ && (*(frame_ref - 4) != REF_V128_1 || *(frame_ref - 3) != REF_V128_2
+ || *(frame_ref - 2) != REF_V128_3
+ || *(frame_ref - 1) != REF_V128_4))
+#endif
+#endif
+ ) {
+ set_error_buf_v(error_buf, error_buf_size, "%s%s%s",
+ "type mismatch: expect ", type2str(type),
+ " but got other");
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+check_stack_pop(WASMLoaderContext *ctx, uint8 type, char *error_buf,
+ uint32 error_buf_size)
+{
+ int32 block_stack_cell_num =
+ (int32)(ctx->stack_cell_num - (ctx->frame_csp - 1)->stack_cell_num);
+
+ if (block_stack_cell_num > 0 && *(ctx->frame_ref - 1) == VALUE_TYPE_ANY) {
+ /* the stack top is a value of any type, return success */
+ return true;
+ }
+
+ if (!check_stack_top_values(ctx->frame_ref, block_stack_cell_num, type,
+ error_buf, error_buf_size))
+ return false;
+
+ return true;
+}
+
+static void
+wasm_loader_ctx_destroy(WASMLoaderContext *ctx)
+{
+ if (ctx) {
+ if (ctx->frame_ref_bottom)
+ wasm_runtime_free(ctx->frame_ref_bottom);
+ if (ctx->frame_csp_bottom) {
+#if WASM_ENABLE_FAST_INTERP != 0
+ free_all_label_patch_lists(ctx->frame_csp_bottom, ctx->csp_num);
+#endif
+ wasm_runtime_free(ctx->frame_csp_bottom);
+ }
+#if WASM_ENABLE_FAST_INTERP != 0
+ if (ctx->frame_offset_bottom)
+ wasm_runtime_free(ctx->frame_offset_bottom);
+ if (ctx->const_buf)
+ wasm_runtime_free(ctx->const_buf);
+#endif
+ wasm_runtime_free(ctx);
+ }
+}
+
+static WASMLoaderContext *
+wasm_loader_ctx_init(WASMFunction *func, char *error_buf, uint32 error_buf_size)
+{
+ WASMLoaderContext *loader_ctx =
+ loader_malloc(sizeof(WASMLoaderContext), error_buf, error_buf_size);
+ if (!loader_ctx)
+ return NULL;
+
+ loader_ctx->frame_ref_size = 32;
+ if (!(loader_ctx->frame_ref_bottom = loader_ctx->frame_ref = loader_malloc(
+ loader_ctx->frame_ref_size, error_buf, error_buf_size)))
+ goto fail;
+ loader_ctx->frame_ref_boundary = loader_ctx->frame_ref_bottom + 32;
+
+ loader_ctx->frame_csp_size = sizeof(BranchBlock) * 8;
+ if (!(loader_ctx->frame_csp_bottom = loader_ctx->frame_csp = loader_malloc(
+ loader_ctx->frame_csp_size, error_buf, error_buf_size)))
+ goto fail;
+ loader_ctx->frame_csp_boundary = loader_ctx->frame_csp_bottom + 8;
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ loader_ctx->frame_offset_size = sizeof(int16) * 32;
+ if (!(loader_ctx->frame_offset_bottom = loader_ctx->frame_offset =
+ loader_malloc(loader_ctx->frame_offset_size, error_buf,
+ error_buf_size)))
+ goto fail;
+ loader_ctx->frame_offset_boundary = loader_ctx->frame_offset_bottom + 32;
+
+ loader_ctx->num_const = 0;
+ loader_ctx->const_buf_size = sizeof(Const) * 8;
+ if (!(loader_ctx->const_buf = loader_malloc(loader_ctx->const_buf_size,
+ error_buf, error_buf_size)))
+ goto fail;
+
+ if (func->param_cell_num >= (int32)INT16_MAX - func->local_cell_num) {
+ set_error_buf(error_buf, error_buf_size,
+ "fast interpreter offset overflow");
+ goto fail;
+ }
+
+ loader_ctx->start_dynamic_offset = loader_ctx->dynamic_offset =
+ loader_ctx->max_dynamic_offset =
+ func->param_cell_num + func->local_cell_num;
+#endif
+ return loader_ctx;
+
+fail:
+ wasm_loader_ctx_destroy(loader_ctx);
+ return NULL;
+}
+
+static bool
+wasm_loader_push_frame_ref(WASMLoaderContext *ctx, uint8 type, char *error_buf,
+ uint32 error_buf_size)
+{
+ if (type == VALUE_TYPE_VOID)
+ return true;
+
+ if (!check_stack_push(ctx, error_buf, error_buf_size))
+ return false;
+
+ *ctx->frame_ref++ = type;
+ ctx->stack_cell_num++;
+ if (is_32bit_type(type) || type == VALUE_TYPE_ANY)
+ goto check_stack_and_return;
+
+ if (!check_stack_push(ctx, error_buf, error_buf_size))
+ return false;
+
+ *ctx->frame_ref++ = type;
+ ctx->stack_cell_num++;
+
+#if WASM_ENABLE_SIMD != 0
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+ if (type == VALUE_TYPE_V128) {
+ if (!check_stack_push(ctx, error_buf, error_buf_size))
+ return false;
+ *ctx->frame_ref++ = type;
+ ctx->stack_cell_num++;
+ if (!check_stack_push(ctx, error_buf, error_buf_size))
+ return false;
+ *ctx->frame_ref++ = type;
+ ctx->stack_cell_num++;
+ }
+#endif
+#endif
+
+check_stack_and_return:
+ if (ctx->stack_cell_num > ctx->max_stack_cell_num) {
+ ctx->max_stack_cell_num = ctx->stack_cell_num;
+ if (ctx->max_stack_cell_num > UINT16_MAX) {
+ set_error_buf(error_buf, error_buf_size,
+ "operand stack depth limit exceeded");
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool
+wasm_loader_pop_frame_ref(WASMLoaderContext *ctx, uint8 type, char *error_buf,
+ uint32 error_buf_size)
+{
+ BranchBlock *cur_block = ctx->frame_csp - 1;
+ int32 available_stack_cell =
+ (int32)(ctx->stack_cell_num - cur_block->stack_cell_num);
+
+ /* Directly return success if current block is in stack
+ * polymorphic state while stack is empty. */
+ if (available_stack_cell <= 0 && cur_block->is_stack_polymorphic)
+ return true;
+
+ if (type == VALUE_TYPE_VOID)
+ return true;
+
+ if (!check_stack_pop(ctx, type, error_buf, error_buf_size))
+ return false;
+
+ ctx->frame_ref--;
+ ctx->stack_cell_num--;
+
+ if (is_32bit_type(type) || *ctx->frame_ref == VALUE_TYPE_ANY)
+ return true;
+
+ ctx->frame_ref--;
+ ctx->stack_cell_num--;
+
+#if WASM_ENABLE_SIMD != 0
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+ if (type == VALUE_TYPE_V128) {
+ ctx->frame_ref -= 2;
+ ctx->stack_cell_num -= 2;
+ }
+#endif
+#endif
+ return true;
+}
+
+static bool
+wasm_loader_push_pop_frame_ref(WASMLoaderContext *ctx, uint8 pop_cnt,
+ uint8 type_push, uint8 type_pop, char *error_buf,
+ uint32 error_buf_size)
+{
+ for (int i = 0; i < pop_cnt; i++) {
+ if (!wasm_loader_pop_frame_ref(ctx, type_pop, error_buf,
+ error_buf_size))
+ return false;
+ }
+ if (!wasm_loader_push_frame_ref(ctx, type_push, error_buf, error_buf_size))
+ return false;
+ return true;
+}
+
+static bool
+wasm_loader_push_frame_csp(WASMLoaderContext *ctx, uint8 label_type,
+ BlockType block_type, uint8 *start_addr,
+ char *error_buf, uint32 error_buf_size)
+{
+ CHECK_CSP_PUSH();
+ memset(ctx->frame_csp, 0, sizeof(BranchBlock));
+ ctx->frame_csp->label_type = label_type;
+ ctx->frame_csp->block_type = block_type;
+ ctx->frame_csp->start_addr = start_addr;
+ ctx->frame_csp->stack_cell_num = ctx->stack_cell_num;
+#if WASM_ENABLE_FAST_INTERP != 0
+ ctx->frame_csp->dynamic_offset = ctx->dynamic_offset;
+ ctx->frame_csp->patch_list = NULL;
+#endif
+ ctx->frame_csp++;
+ ctx->csp_num++;
+ if (ctx->csp_num > ctx->max_csp_num) {
+ ctx->max_csp_num = ctx->csp_num;
+ if (ctx->max_csp_num > UINT16_MAX) {
+ set_error_buf(error_buf, error_buf_size,
+ "label stack depth limit exceeded");
+ return false;
+ }
+ }
+ return true;
+fail:
+ return false;
+}
+
+static bool
+wasm_loader_pop_frame_csp(WASMLoaderContext *ctx, char *error_buf,
+ uint32 error_buf_size)
+{
+ CHECK_CSP_POP();
+#if WASM_ENABLE_FAST_INTERP != 0
+ if ((ctx->frame_csp - 1)->param_frame_offsets)
+ wasm_runtime_free((ctx->frame_csp - 1)->param_frame_offsets);
+#endif
+ ctx->frame_csp--;
+ ctx->csp_num--;
+
+ return true;
+fail:
+ return false;
+}
+
+#if WASM_ENABLE_FAST_INTERP != 0
+
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
+#define emit_label(opcode) \
+ do { \
+ wasm_loader_emit_ptr(loader_ctx, handle_table[opcode]); \
+ LOG_OP("\nemit_op [%02x]\t", opcode); \
+ } while (0)
+#define skip_label() \
+ do { \
+ wasm_loader_emit_backspace(loader_ctx, sizeof(void *)); \
+ LOG_OP("\ndelete last op\n"); \
+ } while (0)
+#else /* else of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */
+#define emit_label(opcode) \
+ do { \
+ int32 offset = \
+ (int32)((uint8 *)handle_table[opcode] - (uint8 *)handle_table[0]); \
+ if (!(offset >= INT16_MIN && offset < INT16_MAX)) { \
+ set_error_buf(error_buf, error_buf_size, \
+ "pre-compiled label offset out of range"); \
+ goto fail; \
+ } \
+ wasm_loader_emit_int16(loader_ctx, offset); \
+ LOG_OP("\nemit_op [%02x]\t", opcode); \
+ } while (0)
+#define skip_label() \
+ do { \
+ wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); \
+ LOG_OP("\ndelete last op\n"); \
+ } while (0)
+#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */
+#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
+#define emit_label(opcode) \
+ do { \
+ wasm_loader_emit_uint8(loader_ctx, opcode); \
+ LOG_OP("\nemit_op [%02x]\t", opcode); \
+ } while (0)
+#define skip_label() \
+ do { \
+ wasm_loader_emit_backspace(loader_ctx, sizeof(uint8)); \
+ LOG_OP("\ndelete last op\n"); \
+ } while (0)
+#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */
+
+#define emit_empty_label_addr_and_frame_ip(type) \
+ do { \
+ if (!add_label_patch_to_list(loader_ctx->frame_csp - 1, type, \
+ loader_ctx->p_code_compiled, error_buf, \
+ error_buf_size)) \
+ goto fail; \
+ /* label address, to be patched */ \
+ wasm_loader_emit_ptr(loader_ctx, NULL); \
+ } while (0)
+
+#define emit_br_info(frame_csp) \
+ do { \
+ if (!wasm_loader_emit_br_info(loader_ctx, frame_csp, error_buf, \
+ error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define LAST_OP_OUTPUT_I32() \
+ (last_op >= WASM_OP_I32_EQZ && last_op <= WASM_OP_I32_ROTR) \
+ || (last_op == WASM_OP_I32_LOAD || last_op == WASM_OP_F32_LOAD) \
+ || (last_op >= WASM_OP_I32_LOAD8_S && last_op <= WASM_OP_I32_LOAD16_U) \
+ || (last_op >= WASM_OP_F32_ABS && last_op <= WASM_OP_F32_COPYSIGN) \
+ || (last_op >= WASM_OP_I32_WRAP_I64 \
+ && last_op <= WASM_OP_I32_TRUNC_U_F64) \
+ || (last_op >= WASM_OP_F32_CONVERT_S_I32 \
+ && last_op <= WASM_OP_F32_DEMOTE_F64) \
+ || (last_op == WASM_OP_I32_REINTERPRET_F32) \
+ || (last_op == WASM_OP_F32_REINTERPRET_I32) \
+ || (last_op == EXT_OP_COPY_STACK_TOP)
+
+#define LAST_OP_OUTPUT_I64() \
+ (last_op >= WASM_OP_I64_CLZ && last_op <= WASM_OP_I64_ROTR) \
+ || (last_op >= WASM_OP_F64_ABS && last_op <= WASM_OP_F64_COPYSIGN) \
+ || (last_op == WASM_OP_I64_LOAD || last_op == WASM_OP_F64_LOAD) \
+ || (last_op >= WASM_OP_I64_LOAD8_S && last_op <= WASM_OP_I64_LOAD32_U) \
+ || (last_op >= WASM_OP_I64_EXTEND_S_I32 \
+ && last_op <= WASM_OP_I64_TRUNC_U_F64) \
+ || (last_op >= WASM_OP_F64_CONVERT_S_I32 \
+ && last_op <= WASM_OP_F64_PROMOTE_F32) \
+ || (last_op == WASM_OP_I64_REINTERPRET_F64) \
+ || (last_op == WASM_OP_F64_REINTERPRET_I64) \
+ || (last_op == EXT_OP_COPY_STACK_TOP_I64)
+
+#define GET_CONST_OFFSET(type, val) \
+ do { \
+ if (!(wasm_loader_get_const_offset(loader_ctx, type, &val, \
+ &operand_offset, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define GET_CONST_F32_OFFSET(type, fval) \
+ do { \
+ if (!(wasm_loader_get_const_offset(loader_ctx, type, &fval, \
+ &operand_offset, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define GET_CONST_F64_OFFSET(type, fval) \
+ do { \
+ if (!(wasm_loader_get_const_offset(loader_ctx, type, &fval, \
+ &operand_offset, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define emit_operand(ctx, offset) \
+ do { \
+ wasm_loader_emit_int16(ctx, offset); \
+ LOG_OP("%d\t", offset); \
+ } while (0)
+
+#define emit_byte(ctx, byte) \
+ do { \
+ wasm_loader_emit_uint8(ctx, byte); \
+ LOG_OP("%d\t", byte); \
+ } while (0)
+
+#define emit_uint32(ctx, value) \
+ do { \
+ wasm_loader_emit_uint32(ctx, value); \
+ LOG_OP("%d\t", value); \
+ } while (0)
+
+#define emit_uint64(ctx, value) \
+ do { \
+ wasm_loader_emit_const(ctx, &value, false); \
+ LOG_OP("%lld\t", value); \
+ } while (0)
+
+#define emit_float32(ctx, value) \
+ do { \
+ wasm_loader_emit_const(ctx, &value, true); \
+ LOG_OP("%f\t", value); \
+ } while (0)
+
+#define emit_float64(ctx, value) \
+ do { \
+ wasm_loader_emit_const(ctx, &value, false); \
+ LOG_OP("%f\t", value); \
+ } while (0)
+
+static bool
+wasm_loader_ctx_reinit(WASMLoaderContext *ctx)
+{
+ if (!(ctx->p_code_compiled =
+ loader_malloc(ctx->code_compiled_peak_size, NULL, 0)))
+ return false;
+ ctx->p_code_compiled_end =
+ ctx->p_code_compiled + ctx->code_compiled_peak_size;
+
+ /* clean up frame ref */
+ memset(ctx->frame_ref_bottom, 0, ctx->frame_ref_size);
+ ctx->frame_ref = ctx->frame_ref_bottom;
+ ctx->stack_cell_num = 0;
+
+ /* clean up frame csp */
+ memset(ctx->frame_csp_bottom, 0, ctx->frame_csp_size);
+ ctx->frame_csp = ctx->frame_csp_bottom;
+ ctx->csp_num = 0;
+ ctx->max_csp_num = 0;
+
+ /* clean up frame offset */
+ memset(ctx->frame_offset_bottom, 0, ctx->frame_offset_size);
+ ctx->frame_offset = ctx->frame_offset_bottom;
+ ctx->dynamic_offset = ctx->start_dynamic_offset;
+
+ /* init preserved local offsets */
+ ctx->preserved_local_offset = ctx->max_dynamic_offset;
+
+ /* const buf is reserved */
+ return true;
+}
+
+static void
+increase_compiled_code_space(WASMLoaderContext *ctx, int32 size)
+{
+ ctx->code_compiled_size += size;
+ if (ctx->code_compiled_size >= ctx->code_compiled_peak_size) {
+ ctx->code_compiled_peak_size = ctx->code_compiled_size;
+ }
+}
+
+static void
+wasm_loader_emit_const(WASMLoaderContext *ctx, void *value, bool is_32_bit)
+{
+ uint32 size = is_32_bit ? sizeof(uint32) : sizeof(uint64);
+
+ if (ctx->p_code_compiled) {
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0);
+#endif
+ bh_memcpy_s(ctx->p_code_compiled,
+ (uint32)(ctx->p_code_compiled_end - ctx->p_code_compiled),
+ value, size);
+ ctx->p_code_compiled += size;
+ }
+ else {
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ bh_assert((ctx->code_compiled_size & 1) == 0);
+#endif
+ increase_compiled_code_space(ctx, size);
+ }
+}
+
+static void
+wasm_loader_emit_uint32(WASMLoaderContext *ctx, uint32 value)
+{
+ if (ctx->p_code_compiled) {
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0);
+#endif
+ STORE_U32(ctx->p_code_compiled, value);
+ ctx->p_code_compiled += sizeof(uint32);
+ }
+ else {
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ bh_assert((ctx->code_compiled_size & 1) == 0);
+#endif
+ increase_compiled_code_space(ctx, sizeof(uint32));
+ }
+}
+
+static void
+wasm_loader_emit_int16(WASMLoaderContext *ctx, int16 value)
+{
+ if (ctx->p_code_compiled) {
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0);
+#endif
+ STORE_U16(ctx->p_code_compiled, (uint16)value);
+ ctx->p_code_compiled += sizeof(int16);
+ }
+ else {
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ bh_assert((ctx->code_compiled_size & 1) == 0);
+#endif
+ increase_compiled_code_space(ctx, sizeof(uint16));
+ }
+}
+
+static void
+wasm_loader_emit_uint8(WASMLoaderContext *ctx, uint8 value)
+{
+ if (ctx->p_code_compiled) {
+ *(ctx->p_code_compiled) = value;
+ ctx->p_code_compiled += sizeof(uint8);
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ ctx->p_code_compiled++;
+ bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0);
+#endif
+ }
+ else {
+ increase_compiled_code_space(ctx, sizeof(uint8));
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ increase_compiled_code_space(ctx, sizeof(uint8));
+ bh_assert((ctx->code_compiled_size & 1) == 0);
+#endif
+ }
+}
+
+static void
+wasm_loader_emit_ptr(WASMLoaderContext *ctx, void *value)
+{
+ if (ctx->p_code_compiled) {
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0);
+#endif
+ STORE_PTR(ctx->p_code_compiled, value);
+ ctx->p_code_compiled += sizeof(void *);
+ }
+ else {
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ bh_assert((ctx->code_compiled_size & 1) == 0);
+#endif
+ increase_compiled_code_space(ctx, sizeof(void *));
+ }
+}
+
+static void
+wasm_loader_emit_backspace(WASMLoaderContext *ctx, uint32 size)
+{
+ if (ctx->p_code_compiled) {
+ ctx->p_code_compiled -= size;
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ if (size == sizeof(uint8)) {
+ ctx->p_code_compiled--;
+ bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0);
+ }
+#endif
+ }
+ else {
+ ctx->code_compiled_size -= size;
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ if (size == sizeof(uint8)) {
+ ctx->code_compiled_size--;
+ bh_assert((ctx->code_compiled_size & 1) == 0);
+ }
+#endif
+ }
+}
+
+static bool
+preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode,
+ uint32 local_index, uint32 local_type,
+ bool *preserved, char *error_buf,
+ uint32 error_buf_size)
+{
+ uint32 i = 0;
+ int16 preserved_offset = (int16)local_index;
+
+ *preserved = false;
+ while (i < loader_ctx->stack_cell_num) {
+ uint8 cur_type = loader_ctx->frame_ref_bottom[i];
+
+ /* move previous local into dynamic space before a set/tee_local opcode
+ */
+ if (loader_ctx->frame_offset_bottom[i] == (int16)local_index) {
+ if (!(*preserved)) {
+ *preserved = true;
+ skip_label();
+ preserved_offset = loader_ctx->preserved_local_offset;
+ if (loader_ctx->p_code_compiled) {
+ bh_assert(preserved_offset != (int16)local_index);
+ }
+ if (is_32bit_type(local_type)) {
+ /* Only increase preserve offset in the second traversal */
+ if (loader_ctx->p_code_compiled)
+ loader_ctx->preserved_local_offset++;
+ emit_label(EXT_OP_COPY_STACK_TOP);
+ }
+ else {
+ if (loader_ctx->p_code_compiled)
+ loader_ctx->preserved_local_offset += 2;
+ emit_label(EXT_OP_COPY_STACK_TOP_I64);
+ }
+ emit_operand(loader_ctx, local_index);
+ emit_operand(loader_ctx, preserved_offset);
+ emit_label(opcode);
+ }
+ loader_ctx->frame_offset_bottom[i] = preserved_offset;
+ }
+
+ if (is_32bit_type(cur_type))
+ i++;
+ else
+ i += 2;
+ }
+
+ (void)error_buf;
+ (void)error_buf_size;
+ return true;
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+fail:
+ return false;
+#endif
+#endif
+}
+
+static bool
+preserve_local_for_block(WASMLoaderContext *loader_ctx, uint8 opcode,
+ char *error_buf, uint32 error_buf_size)
+{
+ uint32 i = 0;
+ bool preserve_local;
+
+ /* preserve locals before blocks to ensure that "tee/set_local" inside
+ blocks will not influence the value of these locals */
+ while (i < loader_ctx->stack_cell_num) {
+ int16 cur_offset = loader_ctx->frame_offset_bottom[i];
+ uint8 cur_type = loader_ctx->frame_ref_bottom[i];
+
+ if ((cur_offset < loader_ctx->start_dynamic_offset)
+ && (cur_offset >= 0)) {
+ if (!(preserve_referenced_local(loader_ctx, opcode, cur_offset,
+ cur_type, &preserve_local,
+ error_buf, error_buf_size)))
+ return false;
+ }
+
+ if (is_32bit_type(cur_type)) {
+ i++;
+ }
+ else {
+ i += 2;
+ }
+ }
+
+ return true;
+}
+
+static bool
+add_label_patch_to_list(BranchBlock *frame_csp, uint8 patch_type,
+ uint8 *p_code_compiled, char *error_buf,
+ uint32 error_buf_size)
+{
+ BranchBlockPatch *patch =
+ loader_malloc(sizeof(BranchBlockPatch), error_buf, error_buf_size);
+ if (!patch) {
+ return false;
+ }
+ patch->patch_type = patch_type;
+ patch->code_compiled = p_code_compiled;
+ if (!frame_csp->patch_list) {
+ frame_csp->patch_list = patch;
+ patch->next = NULL;
+ }
+ else {
+ patch->next = frame_csp->patch_list;
+ frame_csp->patch_list = patch;
+ }
+ return true;
+}
+
+static void
+apply_label_patch(WASMLoaderContext *ctx, uint8 depth, uint8 patch_type)
+{
+ BranchBlock *frame_csp = ctx->frame_csp - depth;
+ BranchBlockPatch *node = frame_csp->patch_list;
+ BranchBlockPatch *node_prev = NULL, *node_next;
+
+ if (!ctx->p_code_compiled)
+ return;
+
+ while (node) {
+ node_next = node->next;
+ if (node->patch_type == patch_type) {
+ STORE_PTR(node->code_compiled, ctx->p_code_compiled);
+ if (node_prev == NULL) {
+ frame_csp->patch_list = node_next;
+ }
+ else {
+ node_prev->next = node_next;
+ }
+ wasm_runtime_free(node);
+ }
+ else {
+ node_prev = node;
+ }
+ node = node_next;
+ }
+}
+
+static bool
+wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp,
+ char *error_buf, uint32 error_buf_size)
+{
+ /* br info layout:
+ * a) arity of target block
+ * b) total cell num of arity values
+ * c) each arity value's cell num
+ * d) each arity value's src frame offset
+ * e) each arity values's dst dynamic offset
+ * f) branch target address
+ *
+ * Note: b-e are omitted when arity is 0 so that
+ * interpreter can recover the br info quickly.
+ */
+ BlockType *block_type = &frame_csp->block_type;
+ uint8 *types = NULL, cell;
+ uint32 arity = 0;
+ int32 i;
+ int16 *frame_offset = ctx->frame_offset;
+ uint16 dynamic_offset;
+
+ /* Note: loop's arity is different from if and block. loop's arity is
+ * its parameter count while if and block arity is result count.
+ */
+ if (frame_csp->label_type == LABEL_TYPE_LOOP)
+ arity = block_type_get_param_types(block_type, &types);
+ else
+ arity = block_type_get_result_types(block_type, &types);
+
+ /* Part a */
+ emit_uint32(ctx, arity);
+
+ if (arity) {
+ /* Part b */
+ emit_uint32(ctx, wasm_get_cell_num(types, arity));
+ /* Part c */
+ for (i = (int32)arity - 1; i >= 0; i--) {
+ cell = (uint8)wasm_value_type_cell_num(types[i]);
+ emit_byte(ctx, cell);
+ }
+ /* Part d */
+ for (i = (int32)arity - 1; i >= 0; i--) {
+ cell = (uint8)wasm_value_type_cell_num(types[i]);
+ frame_offset -= cell;
+ emit_operand(ctx, *(int16 *)(frame_offset));
+ }
+ /* Part e */
+ dynamic_offset =
+ frame_csp->dynamic_offset + wasm_get_cell_num(types, arity);
+ for (i = (int32)arity - 1; i >= 0; i--) {
+ cell = (uint8)wasm_value_type_cell_num(types[i]);
+ dynamic_offset -= cell;
+ emit_operand(ctx, dynamic_offset);
+ }
+ }
+
+ /* Part f */
+ if (frame_csp->label_type == LABEL_TYPE_LOOP) {
+ wasm_loader_emit_ptr(ctx, frame_csp->code_compiled);
+ }
+ else {
+ if (!add_label_patch_to_list(frame_csp, PATCH_END, ctx->p_code_compiled,
+ error_buf, error_buf_size))
+ return false;
+ /* label address, to be patched */
+ wasm_loader_emit_ptr(ctx, NULL);
+ }
+
+ return true;
+}
+
+static bool
+wasm_loader_push_frame_offset(WASMLoaderContext *ctx, uint8 type,
+ bool disable_emit, int16 operand_offset,
+ char *error_buf, uint32 error_buf_size)
+{
+ if (type == VALUE_TYPE_VOID)
+ return true;
+
+ /* only check memory overflow in first traverse */
+ if (ctx->p_code_compiled == NULL) {
+ if (!check_offset_push(ctx, error_buf, error_buf_size))
+ return false;
+ }
+
+ if (disable_emit)
+ *(ctx->frame_offset)++ = operand_offset;
+ else {
+ emit_operand(ctx, ctx->dynamic_offset);
+ *(ctx->frame_offset)++ = ctx->dynamic_offset;
+ ctx->dynamic_offset++;
+ if (ctx->dynamic_offset > ctx->max_dynamic_offset) {
+ ctx->max_dynamic_offset = ctx->dynamic_offset;
+ if (ctx->max_dynamic_offset >= INT16_MAX) {
+ goto fail;
+ }
+ }
+ }
+
+ if (is_32bit_type(type))
+ return true;
+
+ if (ctx->p_code_compiled == NULL) {
+ if (!check_offset_push(ctx, error_buf, error_buf_size))
+ return false;
+ }
+
+ ctx->frame_offset++;
+ if (!disable_emit) {
+ ctx->dynamic_offset++;
+ if (ctx->dynamic_offset > ctx->max_dynamic_offset) {
+ ctx->max_dynamic_offset = ctx->dynamic_offset;
+ if (ctx->max_dynamic_offset >= INT16_MAX) {
+ goto fail;
+ }
+ }
+ }
+ return true;
+
+fail:
+ set_error_buf(error_buf, error_buf_size,
+ "fast interpreter offset overflow");
+ return false;
+}
+
+/* This function should be in front of wasm_loader_pop_frame_ref
+ as they both use ctx->stack_cell_num, and ctx->stack_cell_num
+ will be modified by wasm_loader_pop_frame_ref */
+static bool
+wasm_loader_pop_frame_offset(WASMLoaderContext *ctx, uint8 type,
+ char *error_buf, uint32 error_buf_size)
+{
+ /* if ctx->frame_csp equals ctx->frame_csp_bottom,
+ then current block is the function block */
+ uint32 depth = ctx->frame_csp > ctx->frame_csp_bottom ? 1 : 0;
+ BranchBlock *cur_block = ctx->frame_csp - depth;
+ int32 available_stack_cell =
+ (int32)(ctx->stack_cell_num - cur_block->stack_cell_num);
+
+ /* Directly return success if current block is in stack
+ * polymorphic state while stack is empty. */
+ if (available_stack_cell <= 0 && cur_block->is_stack_polymorphic)
+ return true;
+
+ if (type == VALUE_TYPE_VOID)
+ return true;
+
+ if (is_32bit_type(type)) {
+ /* Check the offset stack bottom to ensure the frame offset
+ stack will not go underflow. But we don't thrown error
+ and return true here, because the error msg should be
+ given in wasm_loader_pop_frame_ref */
+ if (!check_offset_pop(ctx, 1))
+ return true;
+
+ ctx->frame_offset -= 1;
+ if ((*(ctx->frame_offset) > ctx->start_dynamic_offset)
+ && (*(ctx->frame_offset) < ctx->max_dynamic_offset))
+ ctx->dynamic_offset -= 1;
+ }
+ else {
+ if (!check_offset_pop(ctx, 2))
+ return true;
+
+ ctx->frame_offset -= 2;
+ if ((*(ctx->frame_offset) > ctx->start_dynamic_offset)
+ && (*(ctx->frame_offset) < ctx->max_dynamic_offset))
+ ctx->dynamic_offset -= 2;
+ }
+ emit_operand(ctx, *(ctx->frame_offset));
+
+ (void)error_buf;
+ (void)error_buf_size;
+ return true;
+}
+
+static bool
+wasm_loader_push_pop_frame_offset(WASMLoaderContext *ctx, uint8 pop_cnt,
+ uint8 type_push, uint8 type_pop,
+ bool disable_emit, int16 operand_offset,
+ char *error_buf, uint32 error_buf_size)
+{
+ uint8 i;
+
+ for (i = 0; i < pop_cnt; i++) {
+ if (!wasm_loader_pop_frame_offset(ctx, type_pop, error_buf,
+ error_buf_size))
+ return false;
+ }
+ if (!wasm_loader_push_frame_offset(ctx, type_push, disable_emit,
+ operand_offset, error_buf,
+ error_buf_size))
+ return false;
+
+ return true;
+}
+
+static bool
+wasm_loader_push_frame_ref_offset(WASMLoaderContext *ctx, uint8 type,
+ bool disable_emit, int16 operand_offset,
+ char *error_buf, uint32 error_buf_size)
+{
+ if (!(wasm_loader_push_frame_offset(ctx, type, disable_emit, operand_offset,
+ error_buf, error_buf_size)))
+ return false;
+ if (!(wasm_loader_push_frame_ref(ctx, type, error_buf, error_buf_size)))
+ return false;
+
+ return true;
+}
+
+static bool
+wasm_loader_pop_frame_ref_offset(WASMLoaderContext *ctx, uint8 type,
+ char *error_buf, uint32 error_buf_size)
+{
+ /* put wasm_loader_pop_frame_offset in front of wasm_loader_pop_frame_ref */
+ if (!wasm_loader_pop_frame_offset(ctx, type, error_buf, error_buf_size))
+ return false;
+ if (!wasm_loader_pop_frame_ref(ctx, type, error_buf, error_buf_size))
+ return false;
+
+ return true;
+}
+
+static bool
+wasm_loader_push_pop_frame_ref_offset(WASMLoaderContext *ctx, uint8 pop_cnt,
+ uint8 type_push, uint8 type_pop,
+ bool disable_emit, int16 operand_offset,
+ char *error_buf, uint32 error_buf_size)
+{
+ if (!wasm_loader_push_pop_frame_offset(ctx, pop_cnt, type_push, type_pop,
+ disable_emit, operand_offset,
+ error_buf, error_buf_size))
+ return false;
+ if (!wasm_loader_push_pop_frame_ref(ctx, pop_cnt, type_push, type_pop,
+ error_buf, error_buf_size))
+ return false;
+
+ return true;
+}
+
+static bool
+wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, void *value,
+ int16 *offset, char *error_buf,
+ uint32 error_buf_size)
+{
+ int8 bytes_to_increase;
+ int16 operand_offset = 0;
+ Const *c;
+
+ /* Search existing constant */
+ for (c = (Const *)ctx->const_buf;
+ (uint8 *)c < ctx->const_buf + ctx->num_const * sizeof(Const); c++) {
+ /* TODO: handle v128 type? */
+ if ((type == c->value_type)
+ && ((type == VALUE_TYPE_I64 && *(int64 *)value == c->value.i64)
+ || (type == VALUE_TYPE_I32 && *(int32 *)value == c->value.i32)
+#if WASM_ENABLE_REF_TYPES != 0
+ || (type == VALUE_TYPE_FUNCREF
+ && *(int32 *)value == c->value.i32)
+ || (type == VALUE_TYPE_EXTERNREF
+ && *(int32 *)value == c->value.i32)
+#endif
+ || (type == VALUE_TYPE_F64
+ && (0 == memcmp(value, &(c->value.f64), sizeof(float64))))
+ || (type == VALUE_TYPE_F32
+ && (0
+ == memcmp(value, &(c->value.f32), sizeof(float32)))))) {
+ operand_offset = c->slot_index;
+ break;
+ }
+ if (is_32bit_type(c->value_type))
+ operand_offset += 1;
+ else
+ operand_offset += 2;
+ }
+
+ if ((uint8 *)c == ctx->const_buf + ctx->num_const * sizeof(Const)) {
+ /* New constant, append to the const buffer */
+ if ((type == VALUE_TYPE_F64) || (type == VALUE_TYPE_I64)) {
+ bytes_to_increase = 2;
+ }
+ else {
+ bytes_to_increase = 1;
+ }
+
+ /* The max cell num of const buffer is 32768 since the valid index range
+ * is -32768 ~ -1. Return an invalid index 0 to indicate the buffer is
+ * full */
+ if (ctx->const_cell_num > INT16_MAX - bytes_to_increase + 1) {
+ *offset = 0;
+ return true;
+ }
+
+ if ((uint8 *)c == ctx->const_buf + ctx->const_buf_size) {
+ MEM_REALLOC(ctx->const_buf, ctx->const_buf_size,
+ ctx->const_buf_size + 4 * sizeof(Const));
+ ctx->const_buf_size += 4 * sizeof(Const);
+ c = (Const *)(ctx->const_buf + ctx->num_const * sizeof(Const));
+ }
+ c->value_type = type;
+ switch (type) {
+ case VALUE_TYPE_F64:
+ bh_memcpy_s(&(c->value.f64), sizeof(WASMValue), value,
+ sizeof(float64));
+ ctx->const_cell_num += 2;
+ /* The const buf will be reversed, we use the second cell */
+ /* of the i64/f64 const so the finnal offset is corrent */
+ operand_offset++;
+ break;
+ case VALUE_TYPE_I64:
+ c->value.i64 = *(int64 *)value;
+ ctx->const_cell_num += 2;
+ operand_offset++;
+ break;
+ case VALUE_TYPE_F32:
+ bh_memcpy_s(&(c->value.f32), sizeof(WASMValue), value,
+ sizeof(float32));
+ ctx->const_cell_num++;
+ break;
+ case VALUE_TYPE_I32:
+ c->value.i32 = *(int32 *)value;
+ ctx->const_cell_num++;
+ break;
+#if WASM_ENABLE_REF_TYPES != 0
+ case VALUE_TYPE_EXTERNREF:
+ case VALUE_TYPE_FUNCREF:
+ c->value.i32 = *(int32 *)value;
+ ctx->const_cell_num++;
+ break;
+#endif
+ default:
+ break;
+ }
+ c->slot_index = operand_offset;
+ ctx->num_const++;
+ LOG_OP("#### new const [%d]: %ld\n", ctx->num_const,
+ (int64)c->value.i64);
+ }
+ /* use negetive index for const */
+ operand_offset = -(operand_offset + 1);
+ *offset = operand_offset;
+ return true;
+fail:
+ return false;
+}
+
+/*
+ PUSH(POP)_XXX = push(pop) frame_ref + push(pop) frame_offset
+ -- Mostly used for the binary / compare operation
+ PUSH(POP)_OFFSET_TYPE only push(pop) the frame_offset stack
+ -- Mostly used in block / control instructions
+
+ The POP will always emit the offset on the top of the frame_offset stack
+ PUSH can be used in two ways:
+ 1. directly PUSH:
+ PUSH_XXX();
+ will allocate a dynamic space and emit
+ 2. silent PUSH:
+ operand_offset = xxx; disable_emit = true;
+ PUSH_XXX();
+ only push the frame_offset stack, no emit
+*/
+
+#define TEMPLATE_PUSH(Type) \
+ do { \
+ if (!wasm_loader_push_frame_ref_offset(loader_ctx, VALUE_TYPE_##Type, \
+ disable_emit, operand_offset, \
+ error_buf, error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define TEMPLATE_POP(Type) \
+ do { \
+ if (!wasm_loader_pop_frame_ref_offset(loader_ctx, VALUE_TYPE_##Type, \
+ error_buf, error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define PUSH_OFFSET_TYPE(type) \
+ do { \
+ if (!(wasm_loader_push_frame_offset(loader_ctx, type, disable_emit, \
+ operand_offset, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define POP_OFFSET_TYPE(type) \
+ do { \
+ if (!(wasm_loader_pop_frame_offset(loader_ctx, type, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define POP_AND_PUSH(type_pop, type_push) \
+ do { \
+ if (!(wasm_loader_push_pop_frame_ref_offset( \
+ loader_ctx, 1, type_push, type_pop, disable_emit, \
+ operand_offset, error_buf, error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+/* type of POPs should be the same */
+#define POP2_AND_PUSH(type_pop, type_push) \
+ do { \
+ if (!(wasm_loader_push_pop_frame_ref_offset( \
+ loader_ctx, 2, type_push, type_pop, disable_emit, \
+ operand_offset, error_buf, error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#else /* WASM_ENABLE_FAST_INTERP */
+
+#define TEMPLATE_PUSH(Type) \
+ do { \
+ if (!(wasm_loader_push_frame_ref(loader_ctx, VALUE_TYPE_##Type, \
+ error_buf, error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define TEMPLATE_POP(Type) \
+ do { \
+ if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_##Type, \
+ error_buf, error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define POP_AND_PUSH(type_pop, type_push) \
+ do { \
+ if (!(wasm_loader_push_pop_frame_ref(loader_ctx, 1, type_push, \
+ type_pop, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+/* type of POPs should be the same */
+#define POP2_AND_PUSH(type_pop, type_push) \
+ do { \
+ if (!(wasm_loader_push_pop_frame_ref(loader_ctx, 2, type_push, \
+ type_pop, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+#endif /* WASM_ENABLE_FAST_INTERP */
+
+#define PUSH_I32() TEMPLATE_PUSH(I32)
+#define PUSH_F32() TEMPLATE_PUSH(F32)
+#define PUSH_I64() TEMPLATE_PUSH(I64)
+#define PUSH_F64() TEMPLATE_PUSH(F64)
+#define PUSH_V128() TEMPLATE_PUSH(V128)
+#define PUSH_FUNCREF() TEMPLATE_PUSH(FUNCREF)
+#define PUSH_EXTERNREF() TEMPLATE_PUSH(EXTERNREF)
+
+#define POP_I32() TEMPLATE_POP(I32)
+#define POP_F32() TEMPLATE_POP(F32)
+#define POP_I64() TEMPLATE_POP(I64)
+#define POP_F64() TEMPLATE_POP(F64)
+#define POP_V128() TEMPLATE_POP(V128)
+#define POP_FUNCREF() TEMPLATE_POP(FUNCREF)
+#define POP_EXTERNREF() TEMPLATE_POP(EXTERNREF)
+
+#if WASM_ENABLE_FAST_INTERP != 0
+
+static bool
+reserve_block_ret(WASMLoaderContext *loader_ctx, uint8 opcode,
+ bool disable_emit, char *error_buf, uint32 error_buf_size)
+{
+ int16 operand_offset = 0;
+ BranchBlock *block = (opcode == WASM_OP_ELSE) ? loader_ctx->frame_csp - 1
+ : loader_ctx->frame_csp;
+ BlockType *block_type = &block->block_type;
+ uint8 *return_types = NULL;
+ uint32 return_count = 0, value_count = 0, total_cel_num = 0;
+ int32 i = 0;
+ int16 dynamic_offset, dynamic_offset_org, *frame_offset = NULL,
+ *frame_offset_org = NULL;
+
+ return_count = block_type_get_result_types(block_type, &return_types);
+
+ /* If there is only one return value, use EXT_OP_COPY_STACK_TOP/_I64 instead
+ * of EXT_OP_COPY_STACK_VALUES for interpreter performance. */
+ if (return_count == 1) {
+ uint8 cell = (uint8)wasm_value_type_cell_num(return_types[0]);
+ if (cell <= 2 /* V128 isn't supported whose cell num is 4 */
+ && block->dynamic_offset != *(loader_ctx->frame_offset - cell)) {
+ /* insert op_copy before else opcode */
+ if (opcode == WASM_OP_ELSE)
+ skip_label();
+ emit_label(cell == 1 ? EXT_OP_COPY_STACK_TOP
+ : EXT_OP_COPY_STACK_TOP_I64);
+ emit_operand(loader_ctx, *(loader_ctx->frame_offset - cell));
+ emit_operand(loader_ctx, block->dynamic_offset);
+
+ if (opcode == WASM_OP_ELSE) {
+ *(loader_ctx->frame_offset - cell) = block->dynamic_offset;
+ }
+ else {
+ loader_ctx->frame_offset -= cell;
+ loader_ctx->dynamic_offset = block->dynamic_offset;
+ PUSH_OFFSET_TYPE(return_types[0]);
+ wasm_loader_emit_backspace(loader_ctx, sizeof(int16));
+ }
+ if (opcode == WASM_OP_ELSE)
+ emit_label(opcode);
+ }
+ return true;
+ }
+
+ /* Copy stack top values to block's results which are in dynamic space.
+ * The instruction format:
+ * Part a: values count
+ * Part b: all values total cell num
+ * Part c: each value's cell_num, src offset and dst offset
+ * Part d: each value's src offset and dst offset
+ * Part e: each value's dst offset
+ */
+ frame_offset = frame_offset_org = loader_ctx->frame_offset;
+ dynamic_offset = dynamic_offset_org =
+ block->dynamic_offset + wasm_get_cell_num(return_types, return_count);
+
+ /* First traversal to get the count of values needed to be copied. */
+ for (i = (int32)return_count - 1; i >= 0; i--) {
+ uint8 cells = (uint8)wasm_value_type_cell_num(return_types[i]);
+
+ frame_offset -= cells;
+ dynamic_offset -= cells;
+ if (dynamic_offset != *frame_offset) {
+ value_count++;
+ total_cel_num += cells;
+ }
+ }
+
+ if (value_count) {
+ uint32 j = 0;
+ uint8 *emit_data = NULL, *cells = NULL;
+ int16 *src_offsets = NULL;
+ uint16 *dst_offsets = NULL;
+ uint64 size =
+ (uint64)value_count
+ * (sizeof(*cells) + sizeof(*src_offsets) + sizeof(*dst_offsets));
+
+ /* Allocate memory for the emit data */
+ if (!(emit_data = loader_malloc(size, error_buf, error_buf_size)))
+ return false;
+
+ cells = emit_data;
+ src_offsets = (int16 *)(cells + value_count);
+ dst_offsets = (uint16 *)(src_offsets + value_count);
+
+ /* insert op_copy before else opcode */
+ if (opcode == WASM_OP_ELSE)
+ skip_label();
+ emit_label(EXT_OP_COPY_STACK_VALUES);
+ /* Part a) */
+ emit_uint32(loader_ctx, value_count);
+ /* Part b) */
+ emit_uint32(loader_ctx, total_cel_num);
+
+ /* Second traversal to get each value's cell num, src offset and dst
+ * offset. */
+ frame_offset = frame_offset_org;
+ dynamic_offset = dynamic_offset_org;
+ for (i = (int32)return_count - 1, j = 0; i >= 0; i--) {
+ uint8 cell = (uint8)wasm_value_type_cell_num(return_types[i]);
+ frame_offset -= cell;
+ dynamic_offset -= cell;
+ if (dynamic_offset != *frame_offset) {
+ /* cell num */
+ cells[j] = cell;
+ /* src offset */
+ src_offsets[j] = *frame_offset;
+ /* dst offset */
+ dst_offsets[j] = dynamic_offset;
+ j++;
+ }
+ if (opcode == WASM_OP_ELSE) {
+ *frame_offset = dynamic_offset;
+ }
+ else {
+ loader_ctx->frame_offset = frame_offset;
+ loader_ctx->dynamic_offset = dynamic_offset;
+ PUSH_OFFSET_TYPE(return_types[i]);
+ wasm_loader_emit_backspace(loader_ctx, sizeof(int16));
+ loader_ctx->frame_offset = frame_offset_org;
+ loader_ctx->dynamic_offset = dynamic_offset_org;
+ }
+ }
+
+ bh_assert(j == value_count);
+
+ /* Emit the cells, src_offsets and dst_offsets */
+ for (j = 0; j < value_count; j++)
+ emit_byte(loader_ctx, cells[j]);
+ for (j = 0; j < value_count; j++)
+ emit_operand(loader_ctx, src_offsets[j]);
+ for (j = 0; j < value_count; j++)
+ emit_operand(loader_ctx, dst_offsets[j]);
+
+ if (opcode == WASM_OP_ELSE)
+ emit_label(opcode);
+
+ wasm_runtime_free(emit_data);
+ }
+
+ return true;
+
+fail:
+ return false;
+}
+#endif /* WASM_ENABLE_FAST_INTERP */
+
+#define RESERVE_BLOCK_RET() \
+ do { \
+ if (!reserve_block_ret(loader_ctx, opcode, disable_emit, error_buf, \
+ error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define PUSH_TYPE(type) \
+ do { \
+ if (!(wasm_loader_push_frame_ref(loader_ctx, type, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define POP_TYPE(type) \
+ do { \
+ if (!(wasm_loader_pop_frame_ref(loader_ctx, type, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define PUSH_CSP(label_type, block_type, _start_addr) \
+ do { \
+ if (!wasm_loader_push_frame_csp(loader_ctx, label_type, block_type, \
+ _start_addr, error_buf, \
+ error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define POP_CSP() \
+ do { \
+ if (!wasm_loader_pop_frame_csp(loader_ctx, error_buf, error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define GET_LOCAL_INDEX_TYPE_AND_OFFSET() \
+ do { \
+ read_leb_uint32(p, p_end, local_idx); \
+ if (local_idx >= param_count + local_count) { \
+ set_error_buf(error_buf, error_buf_size, "unknown local"); \
+ goto fail; \
+ } \
+ local_type = local_idx < param_count \
+ ? param_types[local_idx] \
+ : local_types[local_idx - param_count]; \
+ local_offset = local_offsets[local_idx]; \
+ } while (0)
+
+#define CHECK_BR(depth) \
+ do { \
+ if (!wasm_loader_check_br(loader_ctx, depth, error_buf, \
+ error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+static bool
+check_memory(WASMModule *module, char *error_buf, uint32 error_buf_size)
+{
+ if (module->memory_count == 0 && module->import_memory_count == 0) {
+ set_error_buf(error_buf, error_buf_size, "unknown memory");
+ return false;
+ }
+ return true;
+}
+
+#define CHECK_MEMORY() \
+ do { \
+ if (!check_memory(module, error_buf, error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+static bool
+check_memory_access_align(uint8 opcode, uint32 align, char *error_buf,
+ uint32 error_buf_size)
+{
+ uint8 mem_access_aligns[] = {
+ 2, 3, 2, 3, 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, /* loads */
+ 2, 3, 2, 3, 0, 1, 0, 1, 2 /* stores */
+ };
+ bh_assert(opcode >= WASM_OP_I32_LOAD && opcode <= WASM_OP_I64_STORE32);
+ if (align > mem_access_aligns[opcode - WASM_OP_I32_LOAD]) {
+ set_error_buf(error_buf, error_buf_size,
+ "alignment must not be larger than natural");
+ return false;
+ }
+ return true;
+}
+
+#if WASM_ENABLE_SIMD != 0
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+static bool
+check_simd_memory_access_align(uint8 opcode, uint32 align, char *error_buf,
+ uint32 error_buf_size)
+{
+ uint8 mem_access_aligns[] = {
+ 4, /* load */
+ 3, 3, 3, 3, 3, 3, /* load and extend */
+ 0, 1, 2, 3, /* load and splat */
+ 4, /* store */
+ };
+
+ uint8 mem_access_aligns_load_lane[] = {
+ 0, 1, 2, 3, /* load lane */
+ 0, 1, 2, 3, /* store lane */
+ 2, 3 /* store zero */
+ };
+
+ if (!((opcode <= SIMD_v128_store)
+ || (SIMD_v128_load8_lane <= opcode
+ && opcode <= SIMD_v128_load64_zero))) {
+ set_error_buf(error_buf, error_buf_size,
+ "the opcode doesn't include memarg");
+ return false;
+ }
+
+ if ((opcode <= SIMD_v128_store
+ && align > mem_access_aligns[opcode - SIMD_v128_load])
+ || (SIMD_v128_load8_lane <= opcode && opcode <= SIMD_v128_load64_zero
+ && align > mem_access_aligns_load_lane[opcode
+ - SIMD_v128_load8_lane])) {
+ set_error_buf(error_buf, error_buf_size,
+ "alignment must not be larger than natural");
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+check_simd_access_lane(uint8 opcode, uint8 lane, char *error_buf,
+ uint32 error_buf_size)
+{
+ switch (opcode) {
+ case SIMD_i8x16_extract_lane_s:
+ case SIMD_i8x16_extract_lane_u:
+ case SIMD_i8x16_replace_lane:
+ if (lane >= 16) {
+ goto fail;
+ }
+ break;
+ case SIMD_i16x8_extract_lane_s:
+ case SIMD_i16x8_extract_lane_u:
+ case SIMD_i16x8_replace_lane:
+ if (lane >= 8) {
+ goto fail;
+ }
+ break;
+ case SIMD_i32x4_extract_lane:
+ case SIMD_i32x4_replace_lane:
+ case SIMD_f32x4_extract_lane:
+ case SIMD_f32x4_replace_lane:
+ if (lane >= 4) {
+ goto fail;
+ }
+ break;
+ case SIMD_i64x2_extract_lane:
+ case SIMD_i64x2_replace_lane:
+ case SIMD_f64x2_extract_lane:
+ case SIMD_f64x2_replace_lane:
+ if (lane >= 2) {
+ goto fail;
+ }
+ break;
+
+ case SIMD_v128_load8_lane:
+ case SIMD_v128_load16_lane:
+ case SIMD_v128_load32_lane:
+ case SIMD_v128_load64_lane:
+ case SIMD_v128_store8_lane:
+ case SIMD_v128_store16_lane:
+ case SIMD_v128_store32_lane:
+ case SIMD_v128_store64_lane:
+ case SIMD_v128_load32_zero:
+ case SIMD_v128_load64_zero:
+ {
+ uint8 max_lanes[] = { 16, 8, 4, 2, 16, 8, 4, 2, 4, 2 };
+ if (lane >= max_lanes[opcode - SIMD_v128_load8_lane]) {
+ goto fail;
+ }
+ break;
+ }
+ default:
+ goto fail;
+ }
+
+ return true;
+fail:
+ set_error_buf(error_buf, error_buf_size, "invalid lane index");
+ return false;
+}
+
+static bool
+check_simd_shuffle_mask(V128 mask, char *error_buf, uint32 error_buf_size)
+{
+ uint8 i;
+ for (i = 0; i != 16; ++i) {
+ if (mask.i8x16[i] < 0 || mask.i8x16[i] >= 32) {
+ set_error_buf(error_buf, error_buf_size, "invalid lane index");
+ return false;
+ }
+ }
+ return true;
+}
+#endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) */
+#endif /* end of WASM_ENABLE_SIMD */
+
+#if WASM_ENABLE_SHARED_MEMORY != 0
+static bool
+check_memory_align_equal(uint8 opcode, uint32 align, char *error_buf,
+ uint32 error_buf_size)
+{
+ uint8 wait_notify_aligns[] = { 2, 2, 3 };
+ uint8 mem_access_aligns[] = {
+ 2, 3, 0, 1, 0, 1, 2,
+ };
+ uint8 expect;
+
+ bh_assert((opcode <= WASM_OP_ATOMIC_WAIT64)
+ || (opcode >= WASM_OP_ATOMIC_I32_LOAD
+ && opcode <= WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U));
+ if (opcode <= WASM_OP_ATOMIC_WAIT64) {
+ expect = wait_notify_aligns[opcode - WASM_OP_ATOMIC_NOTIFY];
+ }
+ else {
+ /* 7 opcodes in every group */
+ expect = mem_access_aligns[(opcode - WASM_OP_ATOMIC_I32_LOAD) % 7];
+ }
+ if (align != expect) {
+ set_error_buf(error_buf, error_buf_size,
+ "alignment isn't equal to natural");
+ return false;
+ }
+ return true;
+}
+#endif /* end of WASM_ENABLE_SHARED_MEMORY */
+
+static bool
+wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth,
+ char *error_buf, uint32 error_buf_size)
+{
+ BranchBlock *target_block, *cur_block;
+ BlockType *target_block_type;
+ uint8 *types = NULL, *frame_ref;
+ uint32 arity = 0;
+ int32 i, available_stack_cell;
+ uint16 cell_num;
+
+ if (loader_ctx->csp_num < depth + 1) {
+ set_error_buf(error_buf, error_buf_size,
+ "unknown label, "
+ "unexpected end of section or function");
+ return false;
+ }
+
+ cur_block = loader_ctx->frame_csp - 1;
+ target_block = loader_ctx->frame_csp - (depth + 1);
+ target_block_type = &target_block->block_type;
+ frame_ref = loader_ctx->frame_ref;
+
+ /* Note: loop's arity is different from if and block. loop's arity is
+ * its parameter count while if and block arity is result count.
+ */
+ if (target_block->label_type == LABEL_TYPE_LOOP)
+ arity = block_type_get_param_types(target_block_type, &types);
+ else
+ arity = block_type_get_result_types(target_block_type, &types);
+
+ /* If the stack is in polymorphic state, just clear the stack
+ * and then re-push the values to make the stack top values
+ * match block type. */
+ if (cur_block->is_stack_polymorphic) {
+ for (i = (int32)arity - 1; i >= 0; i--) {
+#if WASM_ENABLE_FAST_INTERP != 0
+ POP_OFFSET_TYPE(types[i]);
+#endif
+ POP_TYPE(types[i]);
+ }
+ for (i = 0; i < (int32)arity; i++) {
+#if WASM_ENABLE_FAST_INTERP != 0
+ bool disable_emit = true;
+ int16 operand_offset = 0;
+ PUSH_OFFSET_TYPE(types[i]);
+#endif
+ PUSH_TYPE(types[i]);
+ }
+ return true;
+ }
+
+ available_stack_cell =
+ (int32)(loader_ctx->stack_cell_num - cur_block->stack_cell_num);
+
+ /* Check stack top values match target block type */
+ for (i = (int32)arity - 1; i >= 0; i--) {
+ if (!check_stack_top_values(frame_ref, available_stack_cell, types[i],
+ error_buf, error_buf_size))
+ return false;
+ cell_num = wasm_value_type_cell_num(types[i]);
+ frame_ref -= cell_num;
+ available_stack_cell -= cell_num;
+ }
+
+ return true;
+
+fail:
+ return false;
+}
+
+static BranchBlock *
+check_branch_block(WASMLoaderContext *loader_ctx, uint8 **p_buf, uint8 *buf_end,
+ char *error_buf, uint32 error_buf_size)
+{
+ uint8 *p = *p_buf, *p_end = buf_end;
+ BranchBlock *frame_csp_tmp;
+ uint32 depth;
+
+ read_leb_uint32(p, p_end, depth);
+ CHECK_BR(depth);
+ frame_csp_tmp = loader_ctx->frame_csp - depth - 1;
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_br_info(frame_csp_tmp);
+#endif
+
+ *p_buf = p;
+ return frame_csp_tmp;
+fail:
+ return NULL;
+}
+
+static bool
+check_block_stack(WASMLoaderContext *loader_ctx, BranchBlock *block,
+ char *error_buf, uint32 error_buf_size)
+{
+ BlockType *block_type = &block->block_type;
+ uint8 *return_types = NULL;
+ uint32 return_count = 0;
+ int32 available_stack_cell, return_cell_num, i;
+ uint8 *frame_ref = NULL;
+
+ available_stack_cell =
+ (int32)(loader_ctx->stack_cell_num - block->stack_cell_num);
+
+ return_count = block_type_get_result_types(block_type, &return_types);
+ return_cell_num =
+ return_count > 0 ? wasm_get_cell_num(return_types, return_count) : 0;
+
+ /* If the stack is in polymorphic state, just clear the stack
+ * and then re-push the values to make the stack top values
+ * match block type. */
+ if (block->is_stack_polymorphic) {
+ for (i = (int32)return_count - 1; i >= 0; i--) {
+#if WASM_ENABLE_FAST_INTERP != 0
+ POP_OFFSET_TYPE(return_types[i]);
+#endif
+ POP_TYPE(return_types[i]);
+ }
+
+ /* Check stack is empty */
+ if (loader_ctx->stack_cell_num != block->stack_cell_num) {
+ set_error_buf(
+ error_buf, error_buf_size,
+ "type mismatch: stack size does not match block type");
+ goto fail;
+ }
+
+ for (i = 0; i < (int32)return_count; i++) {
+#if WASM_ENABLE_FAST_INTERP != 0
+ bool disable_emit = true;
+ int16 operand_offset = 0;
+ PUSH_OFFSET_TYPE(return_types[i]);
+#endif
+ PUSH_TYPE(return_types[i]);
+ }
+ return true;
+ }
+
+ /* Check stack cell num equals return cell num */
+ if (available_stack_cell != return_cell_num) {
+ set_error_buf(error_buf, error_buf_size,
+ "type mismatch: stack size does not match block type");
+ goto fail;
+ }
+
+ /* Check stack values match return types */
+ frame_ref = loader_ctx->frame_ref;
+ for (i = (int32)return_count - 1; i >= 0; i--) {
+ if (!check_stack_top_values(frame_ref, available_stack_cell,
+ return_types[i], error_buf, error_buf_size))
+ return false;
+ frame_ref -= wasm_value_type_cell_num(return_types[i]);
+ available_stack_cell -= wasm_value_type_cell_num(return_types[i]);
+ }
+
+ return true;
+
+fail:
+ return false;
+}
+
+#if WASM_ENABLE_FAST_INTERP != 0
+/* Copy parameters to dynamic space.
+ * 1) POP original parameter out;
+ * 2) Push and copy original values to dynamic space.
+ * The copy instruction format:
+ * Part a: param count
+ * Part b: all param total cell num
+ * Part c: each param's cell_num, src offset and dst offset
+ * Part d: each param's src offset
+ * Part e: each param's dst offset
+ */
+static bool
+copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
+ char *error_buf, uint32 error_buf_size)
+{
+ int16 *frame_offset = NULL;
+ uint8 *cells = NULL, cell;
+ int16 *src_offsets = NULL;
+ uint8 *emit_data = NULL;
+ uint32 i;
+ BranchBlock *block = loader_ctx->frame_csp - 1;
+ BlockType *block_type = &block->block_type;
+ WASMType *wasm_type = block_type->u.type;
+ uint32 param_count = block_type->u.type->param_count;
+ int16 condition_offset = 0;
+ bool disable_emit = false;
+ int16 operand_offset = 0;
+
+ uint64 size = (uint64)param_count * (sizeof(*cells) + sizeof(*src_offsets));
+
+ /* For if block, we also need copy the condition operand offset. */
+ if (is_if_block)
+ size += sizeof(*cells) + sizeof(*src_offsets);
+
+ /* Allocate memory for the emit data */
+ if (!(emit_data = loader_malloc(size, error_buf, error_buf_size)))
+ return false;
+
+ cells = emit_data;
+ src_offsets = (int16 *)(cells + param_count);
+
+ if (is_if_block)
+ condition_offset = *loader_ctx->frame_offset;
+
+ /* POP original parameter out */
+ for (i = 0; i < param_count; i++) {
+ POP_OFFSET_TYPE(wasm_type->types[param_count - i - 1]);
+ wasm_loader_emit_backspace(loader_ctx, sizeof(int16));
+ }
+ frame_offset = loader_ctx->frame_offset;
+
+ /* Get each param's cell num and src offset */
+ for (i = 0; i < param_count; i++) {
+ cell = (uint8)wasm_value_type_cell_num(wasm_type->types[i]);
+ cells[i] = cell;
+ src_offsets[i] = *frame_offset;
+ frame_offset += cell;
+ }
+
+ /* emit copy instruction */
+ emit_label(EXT_OP_COPY_STACK_VALUES);
+ /* Part a) */
+ emit_uint32(loader_ctx, is_if_block ? param_count + 1 : param_count);
+ /* Part b) */
+ emit_uint32(loader_ctx, is_if_block ? wasm_type->param_cell_num + 1
+ : wasm_type->param_cell_num);
+ /* Part c) */
+ for (i = 0; i < param_count; i++)
+ emit_byte(loader_ctx, cells[i]);
+ if (is_if_block)
+ emit_byte(loader_ctx, 1);
+
+ /* Part d) */
+ for (i = 0; i < param_count; i++)
+ emit_operand(loader_ctx, src_offsets[i]);
+ if (is_if_block)
+ emit_operand(loader_ctx, condition_offset);
+
+ /* Part e) */
+ /* Push to dynamic space. The push will emit the dst offset. */
+ for (i = 0; i < param_count; i++)
+ PUSH_OFFSET_TYPE(wasm_type->types[i]);
+ if (is_if_block)
+ PUSH_OFFSET_TYPE(VALUE_TYPE_I32);
+
+ /* Free the emit data */
+ wasm_runtime_free(emit_data);
+
+ return true;
+
+fail:
+ return false;
+}
+#endif
+
+/* reset the stack to the state of before entering the last block */
+#if WASM_ENABLE_FAST_INTERP != 0
+#define RESET_STACK() \
+ do { \
+ loader_ctx->stack_cell_num = \
+ (loader_ctx->frame_csp - 1)->stack_cell_num; \
+ loader_ctx->frame_ref = \
+ loader_ctx->frame_ref_bottom + loader_ctx->stack_cell_num; \
+ loader_ctx->frame_offset = \
+ loader_ctx->frame_offset_bottom + loader_ctx->stack_cell_num; \
+ } while (0)
+#else
+#define RESET_STACK() \
+ do { \
+ loader_ctx->stack_cell_num = \
+ (loader_ctx->frame_csp - 1)->stack_cell_num; \
+ loader_ctx->frame_ref = \
+ loader_ctx->frame_ref_bottom + loader_ctx->stack_cell_num; \
+ } while (0)
+#endif
+
+/* set current block's stack polymorphic state */
+#define SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(flag) \
+ do { \
+ BranchBlock *_cur_block = loader_ctx->frame_csp - 1; \
+ _cur_block->is_stack_polymorphic = flag; \
+ } while (0)
+
+#define BLOCK_HAS_PARAM(block_type) \
+ (!block_type.is_value_type && block_type.u.type->param_count > 0)
+
+#define PRESERVE_LOCAL_FOR_BLOCK() \
+ do { \
+ if (!(preserve_local_for_block(loader_ctx, opcode, error_buf, \
+ error_buf_size))) { \
+ goto fail; \
+ } \
+ } while (0)
+
+#if WASM_ENABLE_REF_TYPES != 0
+static bool
+get_table_elem_type(const WASMModule *module, uint32 table_idx,
+ uint8 *p_elem_type, char *error_buf, uint32 error_buf_size)
+{
+ if (!check_table_index(module, table_idx, error_buf, error_buf_size)) {
+ return false;
+ }
+
+ if (p_elem_type) {
+ if (table_idx < module->import_table_count)
+ *p_elem_type = module->import_tables[table_idx].u.table.elem_type;
+ else
+ *p_elem_type =
+ module->tables[module->import_table_count + table_idx]
+ .elem_type;
+ }
+ return true;
+}
+
+static bool
+get_table_seg_elem_type(const WASMModule *module, uint32 table_seg_idx,
+ uint8 *p_elem_type, char *error_buf,
+ uint32 error_buf_size)
+{
+ if (table_seg_idx >= module->table_seg_count) {
+ set_error_buf_v(error_buf, error_buf_size, "unknown elem segment %u",
+ table_seg_idx);
+ return false;
+ }
+
+ if (p_elem_type) {
+ *p_elem_type = module->table_segments[table_seg_idx].elem_type;
+ }
+ return true;
+}
+#endif
+
+#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
+const uint8 *
+wasm_loader_get_custom_section(WASMModule *module, const char *name,
+ uint32 *len)
+{
+ WASMCustomSection *section = module->custom_section_list;
+
+ while (section) {
+ if ((section->name_len == strlen(name))
+ && (memcmp(section->name_addr, name, section->name_len) == 0)) {
+ if (len) {
+ *len = section->content_len;
+ }
+ return section->content_addr;
+ }
+
+ section = section->next;
+ }
+
+ return false;
+}
+#endif
+
+static bool
+wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
+ uint32 cur_func_idx, char *error_buf,
+ uint32 error_buf_size)
+{
+ uint8 *p = func->code, *p_end = func->code + func->code_size, *p_org;
+ uint32 param_count, local_count, global_count;
+ uint8 *param_types, *local_types, local_type, global_type;
+ BlockType func_block_type;
+ uint16 *local_offsets, local_offset;
+ uint32 type_idx, func_idx, local_idx, global_idx, table_idx;
+ uint32 table_seg_idx, data_seg_idx, count, align, mem_offset, i;
+ int32 i32_const = 0;
+ int64 i64_const;
+ uint8 opcode;
+ bool return_value = false;
+ WASMLoaderContext *loader_ctx;
+ BranchBlock *frame_csp_tmp;
+#if WASM_ENABLE_FAST_INTERP != 0
+ uint8 *func_const_end, *func_const = NULL;
+ int16 operand_offset = 0;
+ uint8 last_op = 0;
+ bool disable_emit, preserve_local = false;
+ float32 f32_const;
+ float64 f64_const;
+
+ LOG_OP("\nProcessing func | [%d] params | [%d] locals | [%d] return\n",
+ func->param_cell_num, func->local_cell_num, func->ret_cell_num);
+#endif
+
+ global_count = module->import_global_count + module->global_count;
+
+ param_count = func->func_type->param_count;
+ param_types = func->func_type->types;
+
+ func_block_type.is_value_type = false;
+ func_block_type.u.type = func->func_type;
+
+ local_count = func->local_count;
+ local_types = func->local_types;
+ local_offsets = func->local_offsets;
+
+ if (!(loader_ctx = wasm_loader_ctx_init(func, error_buf, error_buf_size))) {
+ goto fail;
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* For the first traverse, the initial value of preserved_local_offset has
+ * not been determined, we use the INT16_MAX to represent that a slot has
+ * been copied to preserve space. For second traverse, this field will be
+ * set to the appropriate value in wasm_loader_ctx_reinit.
+ * This is for Issue #1230,
+ * https://github.com/bytecodealliance/wasm-micro-runtime/issues/1230, the
+ * drop opcodes need to know which slots are preserved, so those slots will
+ * not be treated as dynamically allocated slots */
+ loader_ctx->preserved_local_offset = INT16_MAX;
+
+re_scan:
+ if (loader_ctx->code_compiled_size > 0) {
+ if (!wasm_loader_ctx_reinit(loader_ctx)) {
+ set_error_buf(error_buf, error_buf_size, "allocate memory failed");
+ goto fail;
+ }
+ p = func->code;
+ func->code_compiled = loader_ctx->p_code_compiled;
+ func->code_compiled_size = loader_ctx->code_compiled_size;
+ }
+#endif
+
+ PUSH_CSP(LABEL_TYPE_FUNCTION, func_block_type, p);
+
+ while (p < p_end) {
+ opcode = *p++;
+#if WASM_ENABLE_FAST_INTERP != 0
+ p_org = p;
+ disable_emit = false;
+ emit_label(opcode);
+#endif
+
+ switch (opcode) {
+ case WASM_OP_UNREACHABLE:
+ RESET_STACK();
+ SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
+ break;
+
+ case WASM_OP_NOP:
+#if WASM_ENABLE_FAST_INTERP != 0
+ skip_label();
+#endif
+ break;
+
+ case WASM_OP_IF:
+#if WASM_ENABLE_FAST_INTERP != 0
+ PRESERVE_LOCAL_FOR_BLOCK();
+#endif
+ POP_I32();
+ goto handle_op_block_and_loop;
+ case WASM_OP_BLOCK:
+ case WASM_OP_LOOP:
+#if WASM_ENABLE_FAST_INTERP != 0
+ PRESERVE_LOCAL_FOR_BLOCK();
+#endif
+ handle_op_block_and_loop:
+ {
+ uint8 value_type;
+ BlockType block_type;
+
+ p_org = p - 1;
+ value_type = read_uint8(p);
+ if (is_byte_a_type(value_type)) {
+ /* If the first byte is one of these special values:
+ * 0x40/0x7F/0x7E/0x7D/0x7C, take it as the type of
+ * the single return value. */
+ block_type.is_value_type = true;
+ block_type.u.value_type = value_type;
+ }
+ else {
+ uint32 type_index;
+ /* Resolve the leb128 encoded type index as block type */
+ p--;
+ read_leb_uint32(p, p_end, type_index);
+ if (type_index >= module->type_count) {
+ set_error_buf(error_buf, error_buf_size,
+ "unknown type");
+ goto fail;
+ }
+ block_type.is_value_type = false;
+ block_type.u.type = module->types[type_index];
+#if WASM_ENABLE_FAST_INTERP == 0
+ /* If block use type index as block type, change the opcode
+ * to new extended opcode so that interpreter can resolve
+ * the block quickly.
+ */
+#if WASM_ENABLE_DEBUG_INTERP != 0
+ if (!record_fast_op(module, p_org, *p_org, error_buf,
+ error_buf_size)) {
+ goto fail;
+ }
+#endif
+ *p_org = EXT_OP_BLOCK + (opcode - WASM_OP_BLOCK);
+#endif
+ }
+
+ /* Pop block parameters from stack */
+ if (BLOCK_HAS_PARAM(block_type)) {
+ WASMType *wasm_type = block_type.u.type;
+ for (i = 0; i < block_type.u.type->param_count; i++)
+ POP_TYPE(
+ wasm_type->types[wasm_type->param_count - i - 1]);
+ }
+
+ PUSH_CSP(LABEL_TYPE_BLOCK + (opcode - WASM_OP_BLOCK),
+ block_type, p);
+
+ /* Pass parameters to block */
+ if (BLOCK_HAS_PARAM(block_type)) {
+ for (i = 0; i < block_type.u.type->param_count; i++)
+ PUSH_TYPE(block_type.u.type->types[i]);
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ if (opcode == WASM_OP_BLOCK) {
+ skip_label();
+ }
+ else if (opcode == WASM_OP_LOOP) {
+ skip_label();
+ if (BLOCK_HAS_PARAM(block_type)) {
+ /* Make sure params are in dynamic space */
+ if (!copy_params_to_dynamic_space(
+ loader_ctx, false, error_buf, error_buf_size))
+ goto fail;
+ }
+ (loader_ctx->frame_csp - 1)->code_compiled =
+ loader_ctx->p_code_compiled;
+ }
+ else if (opcode == WASM_OP_IF) {
+ /* If block has parameters, we should make sure they are in
+ * dynamic space. Otherwise, when else branch is missing,
+ * the later opcode may consume incorrect operand offset.
+ * Spec case:
+ * (func (export "params-id") (param i32) (result i32)
+ * (i32.const 1)
+ * (i32.const 2)
+ * (if (param i32 i32) (result i32 i32) (local.get 0)
+ * (then)) (i32.add)
+ * )
+ *
+ * So we should emit a copy instruction before the if.
+ *
+ * And we also need to save the parameter offsets and
+ * recover them before entering else branch.
+ *
+ */
+ if (BLOCK_HAS_PARAM(block_type)) {
+ BranchBlock *block = loader_ctx->frame_csp - 1;
+ uint64 size;
+
+ /* skip the if condition operand offset */
+ wasm_loader_emit_backspace(loader_ctx, sizeof(int16));
+ /* skip the if label */
+ skip_label();
+ /* Emit a copy instruction */
+ if (!copy_params_to_dynamic_space(
+ loader_ctx, true, error_buf, error_buf_size))
+ goto fail;
+
+ /* Emit the if instruction */
+ emit_label(opcode);
+ /* Emit the new condition operand offset */
+ POP_OFFSET_TYPE(VALUE_TYPE_I32);
+
+ /* Save top param_count values of frame_offset stack, so
+ * that we can recover it before executing else branch
+ */
+ size = sizeof(int16)
+ * (uint64)block_type.u.type->param_cell_num;
+ if (!(block->param_frame_offsets = loader_malloc(
+ size, error_buf, error_buf_size)))
+ goto fail;
+ bh_memcpy_s(block->param_frame_offsets, (uint32)size,
+ loader_ctx->frame_offset
+ - size / sizeof(int16),
+ (uint32)size);
+ }
+
+ emit_empty_label_addr_and_frame_ip(PATCH_ELSE);
+ emit_empty_label_addr_and_frame_ip(PATCH_END);
+ }
+#endif
+ break;
+ }
+
+ case WASM_OP_ELSE:
+ {
+ BlockType block_type = (loader_ctx->frame_csp - 1)->block_type;
+
+ if (loader_ctx->csp_num < 2
+ || (loader_ctx->frame_csp - 1)->label_type
+ != LABEL_TYPE_IF) {
+ set_error_buf(
+ error_buf, error_buf_size,
+ "opcode else found without matched opcode if");
+ goto fail;
+ }
+
+ /* check whether if branch's stack matches its result type */
+ if (!check_block_stack(loader_ctx, loader_ctx->frame_csp - 1,
+ error_buf, error_buf_size))
+ goto fail;
+
+ (loader_ctx->frame_csp - 1)->else_addr = p - 1;
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* if the result of if branch is in local or const area, add a
+ * copy op */
+ RESERVE_BLOCK_RET();
+
+ emit_empty_label_addr_and_frame_ip(PATCH_END);
+ apply_label_patch(loader_ctx, 1, PATCH_ELSE);
+#endif
+ RESET_STACK();
+ SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(false);
+
+ /* Pass parameters to if-false branch */
+ if (BLOCK_HAS_PARAM(block_type)) {
+ for (i = 0; i < block_type.u.type->param_count; i++)
+ PUSH_TYPE(block_type.u.type->types[i]);
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* Recover top param_count values of frame_offset stack */
+ if (BLOCK_HAS_PARAM((block_type))) {
+ uint32 size;
+ BranchBlock *block = loader_ctx->frame_csp - 1;
+ size = sizeof(int16) * block_type.u.type->param_cell_num;
+ bh_memcpy_s(loader_ctx->frame_offset, size,
+ block->param_frame_offsets, size);
+ loader_ctx->frame_offset += (size / sizeof(int16));
+ }
+#endif
+
+ break;
+ }
+
+ case WASM_OP_END:
+ {
+ BranchBlock *cur_block = loader_ctx->frame_csp - 1;
+
+ /* check whether block stack matches its result type */
+ if (!check_block_stack(loader_ctx, cur_block, error_buf,
+ error_buf_size))
+ goto fail;
+
+ /* if no else branch, and return types do not match param types,
+ * fail */
+ if (cur_block->label_type == LABEL_TYPE_IF
+ && !cur_block->else_addr) {
+ uint32 block_param_count = 0, block_ret_count = 0;
+ uint8 *block_param_types = NULL, *block_ret_types = NULL;
+ BlockType *cur_block_type = &cur_block->block_type;
+ if (cur_block_type->is_value_type) {
+ if (cur_block_type->u.value_type != VALUE_TYPE_VOID) {
+ block_ret_count = 1;
+ block_ret_types = &cur_block_type->u.value_type;
+ }
+ }
+ else {
+ block_param_count = cur_block_type->u.type->param_count;
+ block_ret_count = cur_block_type->u.type->result_count;
+ block_param_types = cur_block_type->u.type->types;
+ block_ret_types =
+ cur_block_type->u.type->types + block_param_count;
+ }
+ if (block_param_count != block_ret_count
+ || (block_param_count
+ && memcmp(block_param_types, block_ret_types,
+ block_param_count))) {
+ set_error_buf(error_buf, error_buf_size,
+ "type mismatch: else branch missing");
+ goto fail;
+ }
+ }
+
+ POP_CSP();
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ skip_label();
+ /* copy the result to the block return address */
+ RESERVE_BLOCK_RET();
+
+ apply_label_patch(loader_ctx, 0, PATCH_END);
+ free_label_patch_list(loader_ctx->frame_csp);
+ if (loader_ctx->frame_csp->label_type == LABEL_TYPE_FUNCTION) {
+ int32 idx;
+ uint8 ret_type;
+
+ emit_label(WASM_OP_RETURN);
+ for (idx = (int32)func->func_type->result_count - 1;
+ idx >= 0; idx--) {
+ ret_type = *(func->func_type->types
+ + func->func_type->param_count + idx);
+ POP_OFFSET_TYPE(ret_type);
+ }
+ }
+#endif
+ if (loader_ctx->csp_num > 0) {
+ loader_ctx->frame_csp->end_addr = p - 1;
+ }
+ else {
+ /* end of function block, function will return */
+ if (p < p_end) {
+ set_error_buf(error_buf, error_buf_size,
+ "section size mismatch");
+ goto fail;
+ }
+ }
+
+ break;
+ }
+
+ case WASM_OP_BR:
+ {
+ if (!(frame_csp_tmp = check_branch_block(
+ loader_ctx, &p, p_end, error_buf, error_buf_size)))
+ goto fail;
+
+ RESET_STACK();
+ SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
+ break;
+ }
+
+ case WASM_OP_BR_IF:
+ {
+ POP_I32();
+
+ if (!(frame_csp_tmp = check_branch_block(
+ loader_ctx, &p, p_end, error_buf, error_buf_size)))
+ goto fail;
+
+ break;
+ }
+
+ case WASM_OP_BR_TABLE:
+ {
+ uint8 *ret_types = NULL;
+ uint32 ret_count = 0;
+#if WASM_ENABLE_FAST_INTERP == 0
+ uint8 *p_depth_begin, *p_depth;
+ uint32 depth, j;
+ BrTableCache *br_table_cache = NULL;
+
+ p_org = p - 1;
+#endif
+
+ read_leb_uint32(p, p_end, count);
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, count);
+#endif
+ POP_I32();
+
+#if WASM_ENABLE_FAST_INTERP == 0
+ p_depth_begin = p_depth = p;
+#endif
+ for (i = 0; i <= count; i++) {
+ if (!(frame_csp_tmp =
+ check_branch_block(loader_ctx, &p, p_end,
+ error_buf, error_buf_size)))
+ goto fail;
+
+ if (i == 0) {
+ if (frame_csp_tmp->label_type != LABEL_TYPE_LOOP)
+ ret_count = block_type_get_result_types(
+ &frame_csp_tmp->block_type, &ret_types);
+ }
+ else {
+ uint8 *tmp_ret_types = NULL;
+ uint32 tmp_ret_count = 0;
+
+ /* Check whether all table items have the same return
+ * type */
+ if (frame_csp_tmp->label_type != LABEL_TYPE_LOOP)
+ tmp_ret_count = block_type_get_result_types(
+ &frame_csp_tmp->block_type, &tmp_ret_types);
+
+ if (ret_count != tmp_ret_count
+ || (ret_count
+ && 0
+ != memcmp(ret_types, tmp_ret_types,
+ ret_count))) {
+ set_error_buf(
+ error_buf, error_buf_size,
+ "type mismatch: br_table targets must "
+ "all use same result type");
+ goto fail;
+ }
+ }
+
+#if WASM_ENABLE_FAST_INTERP == 0
+ depth = (uint32)(loader_ctx->frame_csp - 1 - frame_csp_tmp);
+ if (br_table_cache) {
+ br_table_cache->br_depths[i] = depth;
+ }
+ else {
+ if (depth > 255) {
+ /* The depth cannot be stored in one byte,
+ create br_table cache to store each depth */
+#if WASM_ENABLE_DEBUG_INTERP != 0
+ if (!record_fast_op(module, p_org, *p_org,
+ error_buf, error_buf_size)) {
+ goto fail;
+ }
+#endif
+ if (!(br_table_cache = loader_malloc(
+ offsetof(BrTableCache, br_depths)
+ + sizeof(uint32)
+ * (uint64)(count + 1),
+ error_buf, error_buf_size))) {
+ goto fail;
+ }
+ *p_org = EXT_OP_BR_TABLE_CACHE;
+ br_table_cache->br_table_op_addr = p_org;
+ br_table_cache->br_count = count;
+ /* Copy previous depths which are one byte */
+ for (j = 0; j < i; j++) {
+ br_table_cache->br_depths[j] = p_depth_begin[j];
+ }
+ br_table_cache->br_depths[i] = depth;
+ bh_list_insert(module->br_table_cache_list,
+ br_table_cache);
+ }
+ else {
+ /* The depth can be stored in one byte, use the
+ byte of the leb to store it */
+ *p_depth++ = (uint8)depth;
+ }
+ }
+#endif
+ }
+
+#if WASM_ENABLE_FAST_INTERP == 0
+ /* Set the tailing bytes to nop */
+ if (br_table_cache)
+ p_depth = p_depth_begin;
+ while (p_depth < p)
+ *p_depth++ = WASM_OP_NOP;
+#endif
+
+ RESET_STACK();
+ SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
+ break;
+ }
+
+ case WASM_OP_RETURN:
+ {
+ int32 idx;
+ uint8 ret_type;
+ for (idx = (int32)func->func_type->result_count - 1; idx >= 0;
+ idx--) {
+ ret_type = *(func->func_type->types
+ + func->func_type->param_count + idx);
+ POP_TYPE(ret_type);
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* emit the offset after return opcode */
+ POP_OFFSET_TYPE(ret_type);
+#endif
+ }
+
+ RESET_STACK();
+ SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
+
+ break;
+ }
+
+ case WASM_OP_CALL:
+#if WASM_ENABLE_TAIL_CALL != 0
+ case WASM_OP_RETURN_CALL:
+#endif
+ {
+ WASMType *func_type;
+ int32 idx;
+
+ read_leb_uint32(p, p_end, func_idx);
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* we need to emit func_idx before arguments */
+ emit_uint32(loader_ctx, func_idx);
+#endif
+
+ if (!check_function_index(module, func_idx, error_buf,
+ error_buf_size)) {
+ goto fail;
+ }
+
+ if (func_idx < module->import_function_count)
+ func_type =
+ module->import_functions[func_idx].u.function.func_type;
+ else
+ func_type = module
+ ->functions[func_idx
+ - module->import_function_count]
+ ->func_type;
+
+ if (func_type->param_count > 0) {
+ for (idx = (int32)(func_type->param_count - 1); idx >= 0;
+ idx--) {
+ POP_TYPE(func_type->types[idx]);
+#if WASM_ENABLE_FAST_INTERP != 0
+ POP_OFFSET_TYPE(func_type->types[idx]);
+#endif
+ }
+ }
+
+#if WASM_ENABLE_TAIL_CALL != 0
+ if (opcode == WASM_OP_CALL) {
+#endif
+ for (i = 0; i < func_type->result_count; i++) {
+ PUSH_TYPE(func_type->types[func_type->param_count + i]);
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* Here we emit each return value's dynamic_offset. But
+ * in fact these offsets are continuous, so interpreter
+ * only need to get the first return value's offset.
+ */
+ PUSH_OFFSET_TYPE(
+ func_type->types[func_type->param_count + i]);
+#endif
+ }
+#if WASM_ENABLE_TAIL_CALL != 0
+ }
+ else {
+ uint8 type;
+ if (func_type->result_count
+ != func->func_type->result_count) {
+ set_error_buf_v(error_buf, error_buf_size, "%s%u%s",
+ "type mismatch: expect ",
+ func->func_type->result_count,
+ " return values but got other");
+ goto fail;
+ }
+ for (i = 0; i < func_type->result_count; i++) {
+ type = func->func_type
+ ->types[func->func_type->param_count + i];
+ if (func_type->types[func_type->param_count + i]
+ != type) {
+ set_error_buf_v(error_buf, error_buf_size, "%s%s%s",
+ "type mismatch: expect ",
+ type2str(type), " but got other");
+ goto fail;
+ }
+ }
+ RESET_STACK();
+ SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
+ }
+#endif
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \
+ || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_op_func_call = true;
+#endif
+ break;
+ }
+
+ /*
+ * if disable reference type: call_indirect typeidx, 0x00
+ * if enable reference type: call_indirect typeidx, tableidx
+ */
+ case WASM_OP_CALL_INDIRECT:
+#if WASM_ENABLE_TAIL_CALL != 0
+ case WASM_OP_RETURN_CALL_INDIRECT:
+#endif
+ {
+ int32 idx;
+ WASMType *func_type;
+
+ read_leb_uint32(p, p_end, type_idx);
+#if WASM_ENABLE_REF_TYPES != 0
+ read_leb_uint32(p, p_end, table_idx);
+#else
+ CHECK_BUF(p, p_end, 1);
+ table_idx = read_uint8(p);
+#endif
+ if (!check_table_index(module, table_idx, error_buf,
+ error_buf_size)) {
+ goto fail;
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* we need to emit before arguments */
+#if WASM_ENABLE_TAIL_CALL != 0
+ emit_byte(loader_ctx, opcode);
+#endif
+ emit_uint32(loader_ctx, type_idx);
+ emit_uint32(loader_ctx, table_idx);
+#endif
+
+ /* skip elem idx */
+ POP_I32();
+
+ if (type_idx >= module->type_count) {
+ set_error_buf(error_buf, error_buf_size, "unknown type");
+ goto fail;
+ }
+
+ func_type = module->types[type_idx];
+
+ if (func_type->param_count > 0) {
+ for (idx = (int32)(func_type->param_count - 1); idx >= 0;
+ idx--) {
+ POP_TYPE(func_type->types[idx]);
+#if WASM_ENABLE_FAST_INTERP != 0
+ POP_OFFSET_TYPE(func_type->types[idx]);
+#endif
+ }
+ }
+
+#if WASM_ENABLE_TAIL_CALL != 0
+ if (opcode == WASM_OP_CALL_INDIRECT) {
+#endif
+ for (i = 0; i < func_type->result_count; i++) {
+ PUSH_TYPE(func_type->types[func_type->param_count + i]);
+#if WASM_ENABLE_FAST_INTERP != 0
+ PUSH_OFFSET_TYPE(
+ func_type->types[func_type->param_count + i]);
+#endif
+ }
+#if WASM_ENABLE_TAIL_CALL != 0
+ }
+ else {
+ uint8 type;
+ if (func_type->result_count
+ != func->func_type->result_count) {
+ set_error_buf_v(error_buf, error_buf_size, "%s%u%s",
+ "type mismatch: expect ",
+ func->func_type->result_count,
+ " return values but got other");
+ goto fail;
+ }
+ for (i = 0; i < func_type->result_count; i++) {
+ type = func->func_type
+ ->types[func->func_type->param_count + i];
+ if (func_type->types[func_type->param_count + i]
+ != type) {
+ set_error_buf_v(error_buf, error_buf_size, "%s%s%s",
+ "type mismatch: expect ",
+ type2str(type), " but got other");
+ goto fail;
+ }
+ }
+ RESET_STACK();
+ SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
+ }
+#endif
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \
+ || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_op_func_call = true;
+#endif
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_op_call_indirect = true;
+#endif
+ break;
+ }
+
+ case WASM_OP_DROP:
+ {
+ BranchBlock *cur_block = loader_ctx->frame_csp - 1;
+ int32 available_stack_cell =
+ (int32)(loader_ctx->stack_cell_num
+ - cur_block->stack_cell_num);
+
+ if (available_stack_cell <= 0
+ && !cur_block->is_stack_polymorphic) {
+ set_error_buf(error_buf, error_buf_size,
+ "type mismatch, opcode drop was found "
+ "but stack was empty");
+ goto fail;
+ }
+
+ if (available_stack_cell > 0) {
+ if (is_32bit_type(*(loader_ctx->frame_ref - 1))) {
+ loader_ctx->frame_ref--;
+ loader_ctx->stack_cell_num--;
+#if WASM_ENABLE_FAST_INTERP != 0
+ skip_label();
+ loader_ctx->frame_offset--;
+ if ((*(loader_ctx->frame_offset)
+ > loader_ctx->start_dynamic_offset)
+ && (*(loader_ctx->frame_offset)
+ < loader_ctx->max_dynamic_offset))
+ loader_ctx->dynamic_offset--;
+#endif
+ }
+ else if (is_64bit_type(*(loader_ctx->frame_ref - 1))) {
+ loader_ctx->frame_ref -= 2;
+ loader_ctx->stack_cell_num -= 2;
+#if WASM_ENABLE_FAST_INTERP == 0
+ *(p - 1) = WASM_OP_DROP_64;
+#endif
+#if WASM_ENABLE_FAST_INTERP != 0
+ skip_label();
+ loader_ctx->frame_offset -= 2;
+ if ((*(loader_ctx->frame_offset)
+ > loader_ctx->start_dynamic_offset)
+ && (*(loader_ctx->frame_offset)
+ < loader_ctx->max_dynamic_offset))
+ loader_ctx->dynamic_offset -= 2;
+#endif
+ }
+#if WASM_ENABLE_SIMD != 0
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+ else if (*(loader_ctx->frame_ref - 1) == REF_V128_1) {
+ loader_ctx->frame_ref -= 4;
+ loader_ctx->stack_cell_num -= 4;
+ }
+#endif
+#endif
+ else {
+ set_error_buf(error_buf, error_buf_size,
+ "type mismatch");
+ goto fail;
+ }
+ }
+ else {
+#if WASM_ENABLE_FAST_INTERP != 0
+ skip_label();
+#endif
+ }
+ break;
+ }
+
+ case WASM_OP_SELECT:
+ {
+ uint8 ref_type;
+ BranchBlock *cur_block = loader_ctx->frame_csp - 1;
+ int32 available_stack_cell;
+
+ POP_I32();
+
+ available_stack_cell = (int32)(loader_ctx->stack_cell_num
+ - cur_block->stack_cell_num);
+
+ if (available_stack_cell <= 0
+ && !cur_block->is_stack_polymorphic) {
+ set_error_buf(error_buf, error_buf_size,
+ "type mismatch or invalid result arity, "
+ "opcode select was found "
+ "but stack was empty");
+ goto fail;
+ }
+
+ if (available_stack_cell > 0) {
+ switch (*(loader_ctx->frame_ref - 1)) {
+ case REF_I32:
+ case REF_F32:
+ break;
+ case REF_I64_2:
+ case REF_F64_2:
+#if WASM_ENABLE_FAST_INTERP == 0
+ *(p - 1) = WASM_OP_SELECT_64;
+#endif
+#if WASM_ENABLE_FAST_INTERP != 0
+ if (loader_ctx->p_code_compiled) {
+ uint8 opcode_tmp = WASM_OP_SELECT_64;
+ uint8 *p_code_compiled_tmp =
+ loader_ctx->p_code_compiled - 2;
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
+ *(void **)(p_code_compiled_tmp
+ - sizeof(void *)) =
+ handle_table[opcode_tmp];
+#else
+ int32 offset =
+ (int32)((uint8 *)handle_table[opcode_tmp]
+ - (uint8 *)handle_table[0]);
+ if (!(offset >= INT16_MIN
+ && offset < INT16_MAX)) {
+ set_error_buf(error_buf, error_buf_size,
+ "pre-compiled label offset "
+ "out of range");
+ goto fail;
+ }
+ *(int16 *)(p_code_compiled_tmp
+ - sizeof(int16)) = (int16)offset;
+#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */
+#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
+ *(p_code_compiled_tmp - 1) = opcode_tmp;
+#else
+ *(p_code_compiled_tmp - 2) = opcode_tmp;
+#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */
+#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */
+ }
+#endif /* end of WASM_ENABLE_FAST_INTERP */
+ break;
+#if WASM_ENABLE_SIMD != 0
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+ case REF_V128_4:
+ break;
+#endif /* (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) */
+#endif /* WASM_ENABLE_SIMD != 0 */
+ default:
+ {
+ set_error_buf(error_buf, error_buf_size,
+ "type mismatch");
+ goto fail;
+ }
+ }
+
+ ref_type = *(loader_ctx->frame_ref - 1);
+#if WASM_ENABLE_FAST_INTERP != 0
+ POP_OFFSET_TYPE(ref_type);
+ POP_TYPE(ref_type);
+ POP_OFFSET_TYPE(ref_type);
+ POP_TYPE(ref_type);
+ PUSH_OFFSET_TYPE(ref_type);
+ PUSH_TYPE(ref_type);
+#else
+ POP2_AND_PUSH(ref_type, ref_type);
+#endif
+ }
+ else {
+#if WASM_ENABLE_FAST_INTERP != 0
+ PUSH_OFFSET_TYPE(VALUE_TYPE_ANY);
+#endif
+ PUSH_TYPE(VALUE_TYPE_ANY);
+ }
+ break;
+ }
+
+#if WASM_ENABLE_REF_TYPES != 0
+ case WASM_OP_SELECT_T:
+ {
+ uint8 vec_len, ref_type;
+
+ read_leb_uint32(p, p_end, vec_len);
+ if (!vec_len) {
+ set_error_buf(error_buf, error_buf_size,
+ "invalid result arity");
+ goto fail;
+ }
+
+ CHECK_BUF(p, p_end, 1);
+ ref_type = read_uint8(p);
+ if (!is_value_type(ref_type)) {
+ set_error_buf(error_buf, error_buf_size,
+ "unknown value type");
+ goto fail;
+ }
+
+ POP_I32();
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ if (loader_ctx->p_code_compiled) {
+ uint8 opcode_tmp = WASM_OP_SELECT;
+ uint8 *p_code_compiled_tmp =
+ loader_ctx->p_code_compiled - 2;
+
+ if (ref_type == VALUE_TYPE_V128) {
+#if (WASM_ENABLE_SIMD == 0) \
+ || ((WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0))
+ set_error_buf(error_buf, error_buf_size,
+ "SIMD v128 type isn't supported");
+ goto fail;
+#endif
+ }
+ else {
+ if (ref_type == VALUE_TYPE_F64
+ || ref_type == VALUE_TYPE_I64)
+ opcode_tmp = WASM_OP_SELECT_64;
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
+ *(void **)(p_code_compiled_tmp - sizeof(void *)) =
+ handle_table[opcode_tmp];
+#else
+ int32 offset = (int32)((uint8 *)handle_table[opcode_tmp]
+ - (uint8 *)handle_table[0]);
+ if (!(offset >= INT16_MIN && offset < INT16_MAX)) {
+ set_error_buf(
+ error_buf, error_buf_size,
+ "pre-compiled label offset out of range");
+ goto fail;
+ }
+ *(int16 *)(p_code_compiled_tmp - sizeof(int16)) =
+ (int16)offset;
+#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */
+#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
+ *(p_code_compiled_tmp - 1) = opcode_tmp;
+#else
+ *(p_code_compiled_tmp - 2) = opcode_tmp;
+#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */
+#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */
+ }
+ }
+#endif /* WASM_ENABLE_FAST_INTERP != 0 */
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ POP_OFFSET_TYPE(ref_type);
+ POP_TYPE(ref_type);
+ POP_OFFSET_TYPE(ref_type);
+ POP_TYPE(ref_type);
+ PUSH_OFFSET_TYPE(ref_type);
+ PUSH_TYPE(ref_type);
+#else
+ POP2_AND_PUSH(ref_type, ref_type);
+#endif /* WASM_ENABLE_FAST_INTERP != 0 */
+
+ (void)vec_len;
+ break;
+ }
+
+ /* table.get x. tables[x]. [i32] -> [t] */
+ /* table.set x. tables[x]. [i32 t] -> [] */
+ case WASM_OP_TABLE_GET:
+ case WASM_OP_TABLE_SET:
+ {
+ uint8 decl_ref_type;
+
+ read_leb_uint32(p, p_end, table_idx);
+ if (!get_table_elem_type(module, table_idx, &decl_ref_type,
+ error_buf, error_buf_size))
+ goto fail;
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, table_idx);
+#endif
+
+ if (opcode == WASM_OP_TABLE_GET) {
+ POP_I32();
+#if WASM_ENABLE_FAST_INTERP != 0
+ PUSH_OFFSET_TYPE(decl_ref_type);
+#endif
+ PUSH_TYPE(decl_ref_type);
+ }
+ else {
+#if WASM_ENABLE_FAST_INTERP != 0
+ POP_OFFSET_TYPE(decl_ref_type);
+#endif
+ POP_TYPE(decl_ref_type);
+ POP_I32();
+ }
+ break;
+ }
+ case WASM_OP_REF_NULL:
+ {
+ uint8 ref_type;
+
+ CHECK_BUF(p, p_end, 1);
+ ref_type = read_uint8(p);
+ if (ref_type != VALUE_TYPE_FUNCREF
+ && ref_type != VALUE_TYPE_EXTERNREF) {
+ set_error_buf(error_buf, error_buf_size,
+ "unknown value type");
+ goto fail;
+ }
+#if WASM_ENABLE_FAST_INTERP != 0
+ PUSH_OFFSET_TYPE(ref_type);
+#endif
+ PUSH_TYPE(ref_type);
+ break;
+ }
+ case WASM_OP_REF_IS_NULL:
+ {
+#if WASM_ENABLE_FAST_INTERP != 0
+ if (!wasm_loader_pop_frame_ref_offset(loader_ctx,
+ VALUE_TYPE_FUNCREF,
+ error_buf, error_buf_size)
+ && !wasm_loader_pop_frame_ref_offset(
+ loader_ctx, VALUE_TYPE_EXTERNREF, error_buf,
+ error_buf_size)) {
+ goto fail;
+ }
+#else
+ if (!wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_FUNCREF,
+ error_buf, error_buf_size)
+ && !wasm_loader_pop_frame_ref(loader_ctx,
+ VALUE_TYPE_EXTERNREF,
+ error_buf, error_buf_size)) {
+ goto fail;
+ }
+#endif
+ PUSH_I32();
+ break;
+ }
+ case WASM_OP_REF_FUNC:
+ {
+ read_leb_uint32(p, p_end, func_idx);
+
+ if (!check_function_index(module, func_idx, error_buf,
+ error_buf_size)) {
+ goto fail;
+ }
+
+ /* Refer to a forward-declared function */
+ if (func_idx >= cur_func_idx + module->import_function_count) {
+ WASMTableSeg *table_seg = module->table_segments;
+ bool func_declared = false;
+ uint32 j;
+
+ /* Check whether the function is declared in table segs */
+ for (i = 0; i < module->table_seg_count; i++, table_seg++) {
+ if (table_seg->elem_type == VALUE_TYPE_FUNCREF
+ && wasm_elem_is_declarative(table_seg->mode)) {
+ for (j = 0; j < table_seg->function_count; j++) {
+ if (table_seg->func_indexes[j] == func_idx) {
+ func_declared = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!func_declared) {
+ /* Check whether the function is exported */
+ for (i = 0; i < module->export_count; i++) {
+ if (module->exports[i].kind == EXPORT_KIND_FUNC
+ && module->exports[i].index == func_idx) {
+ func_declared = true;
+ break;
+ }
+ }
+ }
+
+ if (!func_declared) {
+ set_error_buf(error_buf, error_buf_size,
+ "undeclared function reference");
+ goto fail;
+ }
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, func_idx);
+#endif
+ PUSH_FUNCREF();
+ break;
+ }
+#endif /* WASM_ENABLE_REF_TYPES */
+
+ case WASM_OP_GET_LOCAL:
+ {
+ p_org = p - 1;
+ GET_LOCAL_INDEX_TYPE_AND_OFFSET();
+ PUSH_TYPE(local_type);
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* Get Local is optimized out */
+ skip_label();
+ disable_emit = true;
+ operand_offset = local_offset;
+ PUSH_OFFSET_TYPE(local_type);
+#else
+#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) \
+ && (WASM_ENABLE_FAST_JIT == 0) && (WASM_ENABLE_DEBUG_INTERP == 0)
+ if (local_offset < 0x80) {
+ *p_org++ = EXT_OP_GET_LOCAL_FAST;
+ if (is_32bit_type(local_type)) {
+ *p_org++ = (uint8)local_offset;
+ }
+ else {
+ *p_org++ = (uint8)(local_offset | 0x80);
+ }
+ while (p_org < p) {
+ *p_org++ = WASM_OP_NOP;
+ }
+ }
+#endif
+#endif /* end of WASM_ENABLE_FAST_INTERP != 0 */
+ break;
+ }
+
+ case WASM_OP_SET_LOCAL:
+ {
+ p_org = p - 1;
+ GET_LOCAL_INDEX_TYPE_AND_OFFSET();
+ POP_TYPE(local_type);
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ if (!(preserve_referenced_local(
+ loader_ctx, opcode, local_offset, local_type,
+ &preserve_local, error_buf, error_buf_size)))
+ goto fail;
+
+ if (local_offset < 256) {
+ skip_label();
+ if ((!preserve_local) && (LAST_OP_OUTPUT_I32())) {
+ if (loader_ctx->p_code_compiled)
+ STORE_U16(loader_ctx->p_code_compiled - 2,
+ local_offset);
+ loader_ctx->frame_offset--;
+ loader_ctx->dynamic_offset--;
+ }
+ else if ((!preserve_local) && (LAST_OP_OUTPUT_I64())) {
+ if (loader_ctx->p_code_compiled)
+ STORE_U16(loader_ctx->p_code_compiled - 2,
+ local_offset);
+ loader_ctx->frame_offset -= 2;
+ loader_ctx->dynamic_offset -= 2;
+ }
+ else {
+ if (is_32bit_type(local_type)) {
+ emit_label(EXT_OP_SET_LOCAL_FAST);
+ emit_byte(loader_ctx, (uint8)local_offset);
+ }
+ else {
+ emit_label(EXT_OP_SET_LOCAL_FAST_I64);
+ emit_byte(loader_ctx, (uint8)local_offset);
+ }
+ POP_OFFSET_TYPE(local_type);
+ }
+ }
+ else { /* local index larger than 255, reserve leb */
+ emit_uint32(loader_ctx, local_idx);
+ POP_OFFSET_TYPE(local_type);
+ }
+#else
+#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) \
+ && (WASM_ENABLE_FAST_JIT == 0) && (WASM_ENABLE_DEBUG_INTERP == 0)
+ if (local_offset < 0x80) {
+ *p_org++ = EXT_OP_SET_LOCAL_FAST;
+ if (is_32bit_type(local_type)) {
+ *p_org++ = (uint8)local_offset;
+ }
+ else {
+ *p_org++ = (uint8)(local_offset | 0x80);
+ }
+ while (p_org < p) {
+ *p_org++ = WASM_OP_NOP;
+ }
+ }
+#endif
+#endif /* end of WASM_ENABLE_FAST_INTERP != 0 */
+ break;
+ }
+
+ case WASM_OP_TEE_LOCAL:
+ {
+ p_org = p - 1;
+ GET_LOCAL_INDEX_TYPE_AND_OFFSET();
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* If the stack is in polymorphic state, do fake pop and push on
+ offset stack to keep the depth of offset stack to be the
+ same with ref stack */
+ BranchBlock *cur_block = loader_ctx->frame_csp - 1;
+ if (cur_block->is_stack_polymorphic) {
+ POP_OFFSET_TYPE(local_type);
+ PUSH_OFFSET_TYPE(local_type);
+ }
+#endif
+ POP_TYPE(local_type);
+ PUSH_TYPE(local_type);
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ if (!(preserve_referenced_local(
+ loader_ctx, opcode, local_offset, local_type,
+ &preserve_local, error_buf, error_buf_size)))
+ goto fail;
+
+ if (local_offset < 256) {
+ skip_label();
+ if (is_32bit_type(local_type)) {
+ emit_label(EXT_OP_TEE_LOCAL_FAST);
+ emit_byte(loader_ctx, (uint8)local_offset);
+ }
+ else {
+ emit_label(EXT_OP_TEE_LOCAL_FAST_I64);
+ emit_byte(loader_ctx, (uint8)local_offset);
+ }
+ }
+ else { /* local index larger than 255, reserve leb */
+ emit_uint32(loader_ctx, local_idx);
+ }
+ emit_operand(loader_ctx,
+ *(loader_ctx->frame_offset
+ - wasm_value_type_cell_num(local_type)));
+#else
+#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) \
+ && (WASM_ENABLE_FAST_JIT == 0) && (WASM_ENABLE_DEBUG_INTERP == 0)
+ if (local_offset < 0x80) {
+ *p_org++ = EXT_OP_TEE_LOCAL_FAST;
+ if (is_32bit_type(local_type)) {
+ *p_org++ = (uint8)local_offset;
+ }
+ else {
+ *p_org++ = (uint8)(local_offset | 0x80);
+ }
+ while (p_org < p) {
+ *p_org++ = WASM_OP_NOP;
+ }
+ }
+#endif
+#endif /* end of WASM_ENABLE_FAST_INTERP != 0 */
+ break;
+ }
+
+ case WASM_OP_GET_GLOBAL:
+ {
+ p_org = p - 1;
+ read_leb_uint32(p, p_end, global_idx);
+ if (global_idx >= global_count) {
+ set_error_buf(error_buf, error_buf_size, "unknown global");
+ goto fail;
+ }
+
+ global_type =
+ global_idx < module->import_global_count
+ ? module->import_globals[global_idx].u.global.type
+ : module
+ ->globals[global_idx
+ - module->import_global_count]
+ .type;
+
+ PUSH_TYPE(global_type);
+
+#if WASM_ENABLE_FAST_INTERP == 0
+ if (global_type == VALUE_TYPE_I64
+ || global_type == VALUE_TYPE_F64) {
+#if WASM_ENABLE_DEBUG_INTERP != 0
+ if (!record_fast_op(module, p_org, *p_org, error_buf,
+ error_buf_size)) {
+ goto fail;
+ }
+#endif
+ *p_org = WASM_OP_GET_GLOBAL_64;
+ }
+#else /* else of WASM_ENABLE_FAST_INTERP */
+ if (global_type == VALUE_TYPE_I64
+ || global_type == VALUE_TYPE_F64) {
+ skip_label();
+ emit_label(WASM_OP_GET_GLOBAL_64);
+ }
+ emit_uint32(loader_ctx, global_idx);
+ PUSH_OFFSET_TYPE(global_type);
+#endif /* end of WASM_ENABLE_FAST_INTERP */
+ break;
+ }
+
+ case WASM_OP_SET_GLOBAL:
+ {
+ bool is_mutable = false;
+
+ p_org = p - 1;
+ read_leb_uint32(p, p_end, global_idx);
+ if (global_idx >= global_count) {
+ set_error_buf(error_buf, error_buf_size, "unknown global");
+ goto fail;
+ }
+
+ is_mutable =
+ global_idx < module->import_global_count
+ ? module->import_globals[global_idx].u.global.is_mutable
+ : module
+ ->globals[global_idx
+ - module->import_global_count]
+ .is_mutable;
+ if (!is_mutable) {
+ set_error_buf(error_buf, error_buf_size,
+ "global is immutable");
+ goto fail;
+ }
+
+ global_type =
+ global_idx < module->import_global_count
+ ? module->import_globals[global_idx].u.global.type
+ : module
+ ->globals[global_idx
+ - module->import_global_count]
+ .type;
+
+ POP_TYPE(global_type);
+
+#if WASM_ENABLE_FAST_INTERP == 0
+ if (global_type == VALUE_TYPE_I64
+ || global_type == VALUE_TYPE_F64) {
+#if WASM_ENABLE_DEBUG_INTERP != 0
+ if (!record_fast_op(module, p_org, *p_org, error_buf,
+ error_buf_size)) {
+ goto fail;
+ }
+#endif
+ *p_org = WASM_OP_SET_GLOBAL_64;
+ }
+ else if (module->aux_stack_size > 0
+ && global_idx == module->aux_stack_top_global_index) {
+#if WASM_ENABLE_DEBUG_INTERP != 0
+ if (!record_fast_op(module, p_org, *p_org, error_buf,
+ error_buf_size)) {
+ goto fail;
+ }
+#endif
+ *p_org = WASM_OP_SET_GLOBAL_AUX_STACK;
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_op_set_global_aux_stack = true;
+#endif
+ }
+#else /* else of WASM_ENABLE_FAST_INTERP */
+ if (global_type == VALUE_TYPE_I64
+ || global_type == VALUE_TYPE_F64) {
+ skip_label();
+ emit_label(WASM_OP_SET_GLOBAL_64);
+ }
+ else if (module->aux_stack_size > 0
+ && global_idx == module->aux_stack_top_global_index) {
+ skip_label();
+ emit_label(WASM_OP_SET_GLOBAL_AUX_STACK);
+ }
+ emit_uint32(loader_ctx, global_idx);
+ POP_OFFSET_TYPE(global_type);
+#endif /* end of WASM_ENABLE_FAST_INTERP */
+ break;
+ }
+
+ /* load */
+ case WASM_OP_I32_LOAD:
+ case WASM_OP_I32_LOAD8_S:
+ case WASM_OP_I32_LOAD8_U:
+ case WASM_OP_I32_LOAD16_S:
+ case WASM_OP_I32_LOAD16_U:
+ case WASM_OP_I64_LOAD:
+ case WASM_OP_I64_LOAD8_S:
+ case WASM_OP_I64_LOAD8_U:
+ case WASM_OP_I64_LOAD16_S:
+ case WASM_OP_I64_LOAD16_U:
+ case WASM_OP_I64_LOAD32_S:
+ case WASM_OP_I64_LOAD32_U:
+ case WASM_OP_F32_LOAD:
+ case WASM_OP_F64_LOAD:
+ /* store */
+ case WASM_OP_I32_STORE:
+ case WASM_OP_I32_STORE8:
+ case WASM_OP_I32_STORE16:
+ case WASM_OP_I64_STORE:
+ case WASM_OP_I64_STORE8:
+ case WASM_OP_I64_STORE16:
+ case WASM_OP_I64_STORE32:
+ case WASM_OP_F32_STORE:
+ case WASM_OP_F64_STORE:
+ {
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* change F32/F64 into I32/I64 */
+ if (opcode == WASM_OP_F32_LOAD) {
+ skip_label();
+ emit_label(WASM_OP_I32_LOAD);
+ }
+ else if (opcode == WASM_OP_F64_LOAD) {
+ skip_label();
+ emit_label(WASM_OP_I64_LOAD);
+ }
+ else if (opcode == WASM_OP_F32_STORE) {
+ skip_label();
+ emit_label(WASM_OP_I32_STORE);
+ }
+ else if (opcode == WASM_OP_F64_STORE) {
+ skip_label();
+ emit_label(WASM_OP_I64_STORE);
+ }
+#endif
+ CHECK_MEMORY();
+ read_leb_uint32(p, p_end, align); /* align */
+ read_leb_uint32(p, p_end, mem_offset); /* offset */
+ if (!check_memory_access_align(opcode, align, error_buf,
+ error_buf_size)) {
+ goto fail;
+ }
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, mem_offset);
+#endif
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ switch (opcode) {
+ /* load */
+ case WASM_OP_I32_LOAD:
+ case WASM_OP_I32_LOAD8_S:
+ case WASM_OP_I32_LOAD8_U:
+ case WASM_OP_I32_LOAD16_S:
+ case WASM_OP_I32_LOAD16_U:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+ break;
+ case WASM_OP_I64_LOAD:
+ case WASM_OP_I64_LOAD8_S:
+ case WASM_OP_I64_LOAD8_U:
+ case WASM_OP_I64_LOAD16_S:
+ case WASM_OP_I64_LOAD16_U:
+ case WASM_OP_I64_LOAD32_S:
+ case WASM_OP_I64_LOAD32_U:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64);
+ break;
+ case WASM_OP_F32_LOAD:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F32);
+ break;
+ case WASM_OP_F64_LOAD:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F64);
+ break;
+ /* store */
+ case WASM_OP_I32_STORE:
+ case WASM_OP_I32_STORE8:
+ case WASM_OP_I32_STORE16:
+ POP_I32();
+ POP_I32();
+ break;
+ case WASM_OP_I64_STORE:
+ case WASM_OP_I64_STORE8:
+ case WASM_OP_I64_STORE16:
+ case WASM_OP_I64_STORE32:
+ POP_I64();
+ POP_I32();
+ break;
+ case WASM_OP_F32_STORE:
+ POP_F32();
+ POP_I32();
+ break;
+ case WASM_OP_F64_STORE:
+ POP_F64();
+ POP_I32();
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ case WASM_OP_MEMORY_SIZE:
+ CHECK_MEMORY();
+ /* reserved byte 0x00 */
+ if (*p++ != 0x00) {
+ set_error_buf(error_buf, error_buf_size,
+ "zero byte expected");
+ goto fail;
+ }
+ PUSH_I32();
+
+ module->possible_memory_grow = true;
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ break;
+
+ case WASM_OP_MEMORY_GROW:
+ CHECK_MEMORY();
+ /* reserved byte 0x00 */
+ if (*p++ != 0x00) {
+ set_error_buf(error_buf, error_buf_size,
+ "zero byte expected");
+ goto fail;
+ }
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+
+ module->possible_memory_grow = true;
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \
+ || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_op_memory_grow = true;
+#endif
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ break;
+
+ case WASM_OP_I32_CONST:
+ read_leb_int32(p, p_end, i32_const);
+#if WASM_ENABLE_FAST_INTERP != 0
+ skip_label();
+ disable_emit = true;
+ GET_CONST_OFFSET(VALUE_TYPE_I32, i32_const);
+
+ if (operand_offset == 0) {
+ disable_emit = false;
+ emit_label(WASM_OP_I32_CONST);
+ emit_uint32(loader_ctx, i32_const);
+ }
+#else
+ (void)i32_const;
+#endif
+ PUSH_I32();
+ break;
+
+ case WASM_OP_I64_CONST:
+ read_leb_int64(p, p_end, i64_const);
+#if WASM_ENABLE_FAST_INTERP != 0
+ skip_label();
+ disable_emit = true;
+ GET_CONST_OFFSET(VALUE_TYPE_I64, i64_const);
+
+ if (operand_offset == 0) {
+ disable_emit = false;
+ emit_label(WASM_OP_I64_CONST);
+ emit_uint64(loader_ctx, i64_const);
+ }
+#endif
+ PUSH_I64();
+ break;
+
+ case WASM_OP_F32_CONST:
+ p += sizeof(float32);
+#if WASM_ENABLE_FAST_INTERP != 0
+ skip_label();
+ disable_emit = true;
+ bh_memcpy_s((uint8 *)&f32_const, sizeof(float32), p_org,
+ sizeof(float32));
+ GET_CONST_F32_OFFSET(VALUE_TYPE_F32, f32_const);
+
+ if (operand_offset == 0) {
+ disable_emit = false;
+ emit_label(WASM_OP_F32_CONST);
+ emit_float32(loader_ctx, f32_const);
+ }
+#endif
+ PUSH_F32();
+ break;
+
+ case WASM_OP_F64_CONST:
+ p += sizeof(float64);
+#if WASM_ENABLE_FAST_INTERP != 0
+ skip_label();
+ disable_emit = true;
+ /* Some MCU may require 8-byte align */
+ bh_memcpy_s((uint8 *)&f64_const, sizeof(float64), p_org,
+ sizeof(float64));
+ GET_CONST_F64_OFFSET(VALUE_TYPE_F64, f64_const);
+
+ if (operand_offset == 0) {
+ disable_emit = false;
+ emit_label(WASM_OP_F64_CONST);
+ emit_float64(loader_ctx, f64_const);
+ }
+#endif
+ PUSH_F64();
+ break;
+
+ case WASM_OP_I32_EQZ:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I32_EQ:
+ case WASM_OP_I32_NE:
+ case WASM_OP_I32_LT_S:
+ case WASM_OP_I32_LT_U:
+ case WASM_OP_I32_GT_S:
+ case WASM_OP_I32_GT_U:
+ case WASM_OP_I32_LE_S:
+ case WASM_OP_I32_LE_U:
+ case WASM_OP_I32_GE_S:
+ case WASM_OP_I32_GE_U:
+ POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I64_EQZ:
+ POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I64_EQ:
+ case WASM_OP_I64_NE:
+ case WASM_OP_I64_LT_S:
+ case WASM_OP_I64_LT_U:
+ case WASM_OP_I64_GT_S:
+ case WASM_OP_I64_GT_U:
+ case WASM_OP_I64_LE_S:
+ case WASM_OP_I64_LE_U:
+ case WASM_OP_I64_GE_S:
+ case WASM_OP_I64_GE_U:
+ POP2_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_F32_EQ:
+ case WASM_OP_F32_NE:
+ case WASM_OP_F32_LT:
+ case WASM_OP_F32_GT:
+ case WASM_OP_F32_LE:
+ case WASM_OP_F32_GE:
+ POP2_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_F64_EQ:
+ case WASM_OP_F64_NE:
+ case WASM_OP_F64_LT:
+ case WASM_OP_F64_GT:
+ case WASM_OP_F64_LE:
+ case WASM_OP_F64_GE:
+ POP2_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I32_CLZ:
+ case WASM_OP_I32_CTZ:
+ case WASM_OP_I32_POPCNT:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I32_ADD:
+ case WASM_OP_I32_SUB:
+ case WASM_OP_I32_MUL:
+ case WASM_OP_I32_DIV_S:
+ case WASM_OP_I32_DIV_U:
+ case WASM_OP_I32_REM_S:
+ case WASM_OP_I32_REM_U:
+ case WASM_OP_I32_AND:
+ case WASM_OP_I32_OR:
+ case WASM_OP_I32_XOR:
+ case WASM_OP_I32_SHL:
+ case WASM_OP_I32_SHR_S:
+ case WASM_OP_I32_SHR_U:
+ case WASM_OP_I32_ROTL:
+ case WASM_OP_I32_ROTR:
+ POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I64_CLZ:
+ case WASM_OP_I64_CTZ:
+ case WASM_OP_I64_POPCNT:
+ POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I64);
+ break;
+
+ case WASM_OP_I64_ADD:
+ case WASM_OP_I64_SUB:
+ case WASM_OP_I64_MUL:
+ case WASM_OP_I64_DIV_S:
+ case WASM_OP_I64_DIV_U:
+ case WASM_OP_I64_REM_S:
+ case WASM_OP_I64_REM_U:
+ case WASM_OP_I64_AND:
+ case WASM_OP_I64_OR:
+ case WASM_OP_I64_XOR:
+ case WASM_OP_I64_SHL:
+ case WASM_OP_I64_SHR_S:
+ case WASM_OP_I64_SHR_U:
+ case WASM_OP_I64_ROTL:
+ case WASM_OP_I64_ROTR:
+ POP2_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I64);
+ break;
+
+ case WASM_OP_F32_ABS:
+ case WASM_OP_F32_NEG:
+ case WASM_OP_F32_CEIL:
+ case WASM_OP_F32_FLOOR:
+ case WASM_OP_F32_TRUNC:
+ case WASM_OP_F32_NEAREST:
+ case WASM_OP_F32_SQRT:
+ POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_F32);
+ break;
+
+ case WASM_OP_F32_ADD:
+ case WASM_OP_F32_SUB:
+ case WASM_OP_F32_MUL:
+ case WASM_OP_F32_DIV:
+ case WASM_OP_F32_MIN:
+ case WASM_OP_F32_MAX:
+ case WASM_OP_F32_COPYSIGN:
+ POP2_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_F32);
+ break;
+
+ case WASM_OP_F64_ABS:
+ case WASM_OP_F64_NEG:
+ case WASM_OP_F64_CEIL:
+ case WASM_OP_F64_FLOOR:
+ case WASM_OP_F64_TRUNC:
+ case WASM_OP_F64_NEAREST:
+ case WASM_OP_F64_SQRT:
+ POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_F64);
+ break;
+
+ case WASM_OP_F64_ADD:
+ case WASM_OP_F64_SUB:
+ case WASM_OP_F64_MUL:
+ case WASM_OP_F64_DIV:
+ case WASM_OP_F64_MIN:
+ case WASM_OP_F64_MAX:
+ case WASM_OP_F64_COPYSIGN:
+ POP2_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_F64);
+ break;
+
+ case WASM_OP_I32_WRAP_I64:
+ POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I32_TRUNC_S_F32:
+ case WASM_OP_I32_TRUNC_U_F32:
+ POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I32_TRUNC_S_F64:
+ case WASM_OP_I32_TRUNC_U_F64:
+ POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I64_EXTEND_S_I32:
+ case WASM_OP_I64_EXTEND_U_I32:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64);
+ break;
+
+ case WASM_OP_I64_TRUNC_S_F32:
+ case WASM_OP_I64_TRUNC_U_F32:
+ POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I64);
+ break;
+
+ case WASM_OP_I64_TRUNC_S_F64:
+ case WASM_OP_I64_TRUNC_U_F64:
+ POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I64);
+ break;
+
+ case WASM_OP_F32_CONVERT_S_I32:
+ case WASM_OP_F32_CONVERT_U_I32:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F32);
+ break;
+
+ case WASM_OP_F32_CONVERT_S_I64:
+ case WASM_OP_F32_CONVERT_U_I64:
+ POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_F32);
+ break;
+
+ case WASM_OP_F32_DEMOTE_F64:
+ POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_F32);
+ break;
+
+ case WASM_OP_F64_CONVERT_S_I32:
+ case WASM_OP_F64_CONVERT_U_I32:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F64);
+ break;
+
+ case WASM_OP_F64_CONVERT_S_I64:
+ case WASM_OP_F64_CONVERT_U_I64:
+ POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_F64);
+ break;
+
+ case WASM_OP_F64_PROMOTE_F32:
+ POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_F64);
+ break;
+
+ case WASM_OP_I32_REINTERPRET_F32:
+ POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I64_REINTERPRET_F64:
+ POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I64);
+ break;
+
+ case WASM_OP_F32_REINTERPRET_I32:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F32);
+ break;
+
+ case WASM_OP_F64_REINTERPRET_I64:
+ POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_F64);
+ break;
+
+ case WASM_OP_I32_EXTEND8_S:
+ case WASM_OP_I32_EXTEND16_S:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I64_EXTEND8_S:
+ case WASM_OP_I64_EXTEND16_S:
+ case WASM_OP_I64_EXTEND32_S:
+ POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I64);
+ break;
+
+ case WASM_OP_MISC_PREFIX:
+ {
+ uint32 opcode1;
+
+ read_leb_uint32(p, p_end, opcode1);
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_byte(loader_ctx, ((uint8)opcode1));
+#endif
+ switch (opcode1) {
+ case WASM_OP_I32_TRUNC_SAT_S_F32:
+ case WASM_OP_I32_TRUNC_SAT_U_F32:
+ POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I32);
+ break;
+ case WASM_OP_I32_TRUNC_SAT_S_F64:
+ case WASM_OP_I32_TRUNC_SAT_U_F64:
+ POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I32);
+ break;
+ case WASM_OP_I64_TRUNC_SAT_S_F32:
+ case WASM_OP_I64_TRUNC_SAT_U_F32:
+ POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I64);
+ break;
+ case WASM_OP_I64_TRUNC_SAT_S_F64:
+ case WASM_OP_I64_TRUNC_SAT_U_F64:
+ POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I64);
+ break;
+#if WASM_ENABLE_BULK_MEMORY != 0
+ case WASM_OP_MEMORY_INIT:
+ {
+ read_leb_uint32(p, p_end, data_seg_idx);
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, data_seg_idx);
+#endif
+ if (module->import_memory_count == 0
+ && module->memory_count == 0)
+ goto fail_unknown_memory;
+
+ if (*p++ != 0x00)
+ goto fail_zero_byte_expected;
+
+ if (data_seg_idx >= module->data_seg_count) {
+ set_error_buf_v(error_buf, error_buf_size,
+ "unknown data segment %d",
+ data_seg_idx);
+ goto fail;
+ }
+
+ if (module->data_seg_count1 == 0)
+ goto fail_data_cnt_sec_require;
+
+ POP_I32();
+ POP_I32();
+ POP_I32();
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ break;
+ }
+ case WASM_OP_DATA_DROP:
+ {
+ read_leb_uint32(p, p_end, data_seg_idx);
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, data_seg_idx);
+#endif
+ if (data_seg_idx >= module->data_seg_count) {
+ set_error_buf(error_buf, error_buf_size,
+ "unknown data segment");
+ goto fail;
+ }
+
+ if (module->data_seg_count1 == 0)
+ goto fail_data_cnt_sec_require;
+
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ break;
+ }
+ case WASM_OP_MEMORY_COPY:
+ {
+ /* both src and dst memory index should be 0 */
+ if (*(int16 *)p != 0x0000)
+ goto fail_zero_byte_expected;
+ p += 2;
+
+ if (module->import_memory_count == 0
+ && module->memory_count == 0)
+ goto fail_unknown_memory;
+
+ POP_I32();
+ POP_I32();
+ POP_I32();
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ break;
+ }
+ case WASM_OP_MEMORY_FILL:
+ {
+ if (*p++ != 0x00) {
+ goto fail_zero_byte_expected;
+ }
+ if (module->import_memory_count == 0
+ && module->memory_count == 0) {
+ goto fail_unknown_memory;
+ }
+
+ POP_I32();
+ POP_I32();
+ POP_I32();
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ break;
+ }
+ fail_zero_byte_expected:
+ set_error_buf(error_buf, error_buf_size,
+ "zero byte expected");
+ goto fail;
+
+ fail_unknown_memory:
+ set_error_buf(error_buf, error_buf_size,
+ "unknown memory 0");
+ goto fail;
+ fail_data_cnt_sec_require:
+ set_error_buf(error_buf, error_buf_size,
+ "data count section required");
+ goto fail;
+#endif /* WASM_ENABLE_BULK_MEMORY */
+#if WASM_ENABLE_REF_TYPES != 0
+ case WASM_OP_TABLE_INIT:
+ {
+ uint8 seg_ref_type = 0, tbl_ref_type = 0;
+
+ read_leb_uint32(p, p_end, table_seg_idx);
+ read_leb_uint32(p, p_end, table_idx);
+
+ if (!get_table_elem_type(module, table_idx,
+ &tbl_ref_type, error_buf,
+ error_buf_size))
+ goto fail;
+
+ if (!get_table_seg_elem_type(module, table_seg_idx,
+ &seg_ref_type, error_buf,
+ error_buf_size))
+ goto fail;
+
+ if (seg_ref_type != tbl_ref_type) {
+ set_error_buf(error_buf, error_buf_size,
+ "type mismatch");
+ goto fail;
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, table_seg_idx);
+ emit_uint32(loader_ctx, table_idx);
+#endif
+ POP_I32();
+ POP_I32();
+ POP_I32();
+ break;
+ }
+ case WASM_OP_ELEM_DROP:
+ {
+ read_leb_uint32(p, p_end, table_seg_idx);
+ if (!get_table_seg_elem_type(module, table_seg_idx,
+ NULL, error_buf,
+ error_buf_size))
+ goto fail;
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, table_seg_idx);
+#endif
+ break;
+ }
+ case WASM_OP_TABLE_COPY:
+ {
+ uint8 src_ref_type, dst_ref_type;
+ uint32 src_tbl_idx, dst_tbl_idx;
+
+ read_leb_uint32(p, p_end, src_tbl_idx);
+ if (!get_table_elem_type(module, src_tbl_idx,
+ &src_ref_type, error_buf,
+ error_buf_size))
+ goto fail;
+
+ read_leb_uint32(p, p_end, dst_tbl_idx);
+ if (!get_table_elem_type(module, dst_tbl_idx,
+ &dst_ref_type, error_buf,
+ error_buf_size))
+ goto fail;
+
+ if (src_ref_type != dst_ref_type) {
+ set_error_buf(error_buf, error_buf_size,
+ "type mismatch");
+ goto fail;
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, src_tbl_idx);
+ emit_uint32(loader_ctx, dst_tbl_idx);
+#endif
+ POP_I32();
+ POP_I32();
+ POP_I32();
+ break;
+ }
+ case WASM_OP_TABLE_SIZE:
+ {
+ read_leb_uint32(p, p_end, table_idx);
+ /* TODO: shall we create a new function to check
+ table idx instead of using below function? */
+ if (!get_table_elem_type(module, table_idx, NULL,
+ error_buf, error_buf_size))
+ goto fail;
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, table_idx);
+#endif
+
+ PUSH_I32();
+ break;
+ }
+ case WASM_OP_TABLE_GROW:
+ case WASM_OP_TABLE_FILL:
+ {
+ uint8 decl_ref_type;
+
+ read_leb_uint32(p, p_end, table_idx);
+ if (!get_table_elem_type(module, table_idx,
+ &decl_ref_type, error_buf,
+ error_buf_size))
+ goto fail;
+
+ if (opcode1 == WASM_OP_TABLE_GROW) {
+ if (table_idx < module->import_table_count) {
+ module->import_tables[table_idx]
+ .u.table.possible_grow = true;
+ }
+ else {
+ module
+ ->tables[table_idx
+ - module->import_table_count]
+ .possible_grow = true;
+ }
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, table_idx);
+#endif
+
+ POP_I32();
+#if WASM_ENABLE_FAST_INTERP != 0
+ POP_OFFSET_TYPE(decl_ref_type);
+#endif
+ POP_TYPE(decl_ref_type);
+ if (opcode1 == WASM_OP_TABLE_GROW)
+ PUSH_I32();
+ else
+ POP_I32();
+ break;
+ }
+#endif /* WASM_ENABLE_REF_TYPES */
+ default:
+ set_error_buf_v(error_buf, error_buf_size,
+ "%s %02x %02x", "unsupported opcode",
+ 0xfc, opcode1);
+ goto fail;
+ }
+ break;
+ }
+
+#if WASM_ENABLE_SIMD != 0
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+ case WASM_OP_SIMD_PREFIX:
+ {
+ opcode = read_uint8(p);
+ /* follow the order of enum WASMSimdEXTOpcode in wasm_opcode.h
+ */
+ switch (opcode) {
+ /* memory instruction */
+ case SIMD_v128_load:
+ case SIMD_v128_load8x8_s:
+ case SIMD_v128_load8x8_u:
+ case SIMD_v128_load16x4_s:
+ case SIMD_v128_load16x4_u:
+ case SIMD_v128_load32x2_s:
+ case SIMD_v128_load32x2_u:
+ case SIMD_v128_load8_splat:
+ case SIMD_v128_load16_splat:
+ case SIMD_v128_load32_splat:
+ case SIMD_v128_load64_splat:
+ {
+ CHECK_MEMORY();
+
+ read_leb_uint32(p, p_end, align); /* align */
+ if (!check_simd_memory_access_align(
+ opcode, align, error_buf, error_buf_size)) {
+ goto fail;
+ }
+
+ read_leb_uint32(p, p_end, mem_offset); /* offset */
+
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_V128);
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ break;
+ }
+
+ case SIMD_v128_store:
+ {
+ CHECK_MEMORY();
+
+ read_leb_uint32(p, p_end, align); /* align */
+ if (!check_simd_memory_access_align(
+ opcode, align, error_buf, error_buf_size)) {
+ goto fail;
+ }
+
+ read_leb_uint32(p, p_end, mem_offset); /* offset */
+
+ POP_V128();
+ POP_I32();
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ break;
+ }
+
+ /* basic operation */
+ case SIMD_v128_const:
+ {
+ CHECK_BUF1(p, p_end, 16);
+ p += 16;
+ PUSH_V128();
+ break;
+ }
+
+ case SIMD_v8x16_shuffle:
+ {
+ V128 mask;
+
+ CHECK_BUF1(p, p_end, 16);
+ mask = read_i8x16(p, error_buf, error_buf_size);
+ p += 16;
+ if (!check_simd_shuffle_mask(mask, error_buf,
+ error_buf_size)) {
+ goto fail;
+ }
+
+ POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_v8x16_swizzle:
+ {
+ POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ /* splat operation */
+ case SIMD_i8x16_splat:
+ case SIMD_i16x8_splat:
+ case SIMD_i32x4_splat:
+ case SIMD_i64x2_splat:
+ case SIMD_f32x4_splat:
+ case SIMD_f64x2_splat:
+ {
+ uint8 pop_type[] = { VALUE_TYPE_I32, VALUE_TYPE_I32,
+ VALUE_TYPE_I32, VALUE_TYPE_I64,
+ VALUE_TYPE_F32, VALUE_TYPE_F64 };
+ POP_AND_PUSH(pop_type[opcode - SIMD_i8x16_splat],
+ VALUE_TYPE_V128);
+ break;
+ }
+
+ /* lane operation */
+ case SIMD_i8x16_extract_lane_s:
+ case SIMD_i8x16_extract_lane_u:
+ case SIMD_i8x16_replace_lane:
+ case SIMD_i16x8_extract_lane_s:
+ case SIMD_i16x8_extract_lane_u:
+ case SIMD_i16x8_replace_lane:
+ case SIMD_i32x4_extract_lane:
+ case SIMD_i32x4_replace_lane:
+ case SIMD_i64x2_extract_lane:
+ case SIMD_i64x2_replace_lane:
+ case SIMD_f32x4_extract_lane:
+ case SIMD_f32x4_replace_lane:
+ case SIMD_f64x2_extract_lane:
+ case SIMD_f64x2_replace_lane:
+ {
+ uint8 lane;
+ /* clang-format off */
+ uint8 replace[] = {
+ /*i8x16*/ 0x0, 0x0, VALUE_TYPE_I32,
+ /*i16x8*/ 0x0, 0x0, VALUE_TYPE_I32,
+ /*i32x4*/ 0x0, VALUE_TYPE_I32,
+ /*i64x2*/ 0x0, VALUE_TYPE_I64,
+ /*f32x4*/ 0x0, VALUE_TYPE_F32,
+ /*f64x2*/ 0x0, VALUE_TYPE_F64,
+ };
+ uint8 push_type[] = {
+ /*i8x16*/ VALUE_TYPE_I32, VALUE_TYPE_I32,
+ VALUE_TYPE_V128,
+ /*i16x8*/ VALUE_TYPE_I32, VALUE_TYPE_I32,
+ VALUE_TYPE_V128,
+ /*i32x4*/ VALUE_TYPE_I32, VALUE_TYPE_V128,
+ /*i64x2*/ VALUE_TYPE_I64, VALUE_TYPE_V128,
+ /*f32x4*/ VALUE_TYPE_F32, VALUE_TYPE_V128,
+ /*f64x2*/ VALUE_TYPE_F64, VALUE_TYPE_V128,
+ };
+ /* clang-format on */
+
+ CHECK_BUF(p, p_end, 1);
+ lane = read_uint8(p);
+ if (!check_simd_access_lane(opcode, lane, error_buf,
+ error_buf_size)) {
+ goto fail;
+ }
+
+ if (replace[opcode - SIMD_i8x16_extract_lane_s]) {
+ if (!(wasm_loader_pop_frame_ref(
+ loader_ctx,
+ replace[opcode - SIMD_i8x16_extract_lane_s],
+ error_buf, error_buf_size)))
+ goto fail;
+ }
+
+ POP_AND_PUSH(
+ VALUE_TYPE_V128,
+ push_type[opcode - SIMD_i8x16_extract_lane_s]);
+ break;
+ }
+
+ /* i8x16 compare operation */
+ case SIMD_i8x16_eq:
+ case SIMD_i8x16_ne:
+ case SIMD_i8x16_lt_s:
+ case SIMD_i8x16_lt_u:
+ case SIMD_i8x16_gt_s:
+ case SIMD_i8x16_gt_u:
+ case SIMD_i8x16_le_s:
+ case SIMD_i8x16_le_u:
+ case SIMD_i8x16_ge_s:
+ case SIMD_i8x16_ge_u:
+ /* i16x8 compare operation */
+ case SIMD_i16x8_eq:
+ case SIMD_i16x8_ne:
+ case SIMD_i16x8_lt_s:
+ case SIMD_i16x8_lt_u:
+ case SIMD_i16x8_gt_s:
+ case SIMD_i16x8_gt_u:
+ case SIMD_i16x8_le_s:
+ case SIMD_i16x8_le_u:
+ case SIMD_i16x8_ge_s:
+ case SIMD_i16x8_ge_u:
+ /* i32x4 compare operation */
+ case SIMD_i32x4_eq:
+ case SIMD_i32x4_ne:
+ case SIMD_i32x4_lt_s:
+ case SIMD_i32x4_lt_u:
+ case SIMD_i32x4_gt_s:
+ case SIMD_i32x4_gt_u:
+ case SIMD_i32x4_le_s:
+ case SIMD_i32x4_le_u:
+ case SIMD_i32x4_ge_s:
+ case SIMD_i32x4_ge_u:
+ /* f32x4 compare operation */
+ case SIMD_f32x4_eq:
+ case SIMD_f32x4_ne:
+ case SIMD_f32x4_lt:
+ case SIMD_f32x4_gt:
+ case SIMD_f32x4_le:
+ case SIMD_f32x4_ge:
+ /* f64x2 compare operation */
+ case SIMD_f64x2_eq:
+ case SIMD_f64x2_ne:
+ case SIMD_f64x2_lt:
+ case SIMD_f64x2_gt:
+ case SIMD_f64x2_le:
+ case SIMD_f64x2_ge:
+ {
+ POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ /* v128 operation */
+ case SIMD_v128_not:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_v128_and:
+ case SIMD_v128_andnot:
+ case SIMD_v128_or:
+ case SIMD_v128_xor:
+ {
+ POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_v128_bitselect:
+ {
+ POP_V128();
+ POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_v128_any_true:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_I32);
+ break;
+ }
+
+ /* Load Lane Operation */
+ case SIMD_v128_load8_lane:
+ case SIMD_v128_load16_lane:
+ case SIMD_v128_load32_lane:
+ case SIMD_v128_load64_lane:
+ case SIMD_v128_store8_lane:
+ case SIMD_v128_store16_lane:
+ case SIMD_v128_store32_lane:
+ case SIMD_v128_store64_lane:
+ {
+ uint8 lane;
+
+ CHECK_MEMORY();
+
+ read_leb_uint32(p, p_end, align); /* align */
+ if (!check_simd_memory_access_align(
+ opcode, align, error_buf, error_buf_size)) {
+ goto fail;
+ }
+
+ read_leb_uint32(p, p_end, mem_offset); /* offset */
+
+ CHECK_BUF(p, p_end, 1);
+ lane = read_uint8(p);
+ if (!check_simd_access_lane(opcode, lane, error_buf,
+ error_buf_size)) {
+ goto fail;
+ }
+
+ POP_V128();
+ POP_I32();
+ if (opcode < SIMD_v128_store8_lane) {
+ PUSH_V128();
+ }
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ break;
+ }
+
+ case SIMD_v128_load32_zero:
+ case SIMD_v128_load64_zero:
+ {
+ CHECK_MEMORY();
+
+ read_leb_uint32(p, p_end, align); /* align */
+ if (!check_simd_memory_access_align(
+ opcode, align, error_buf, error_buf_size)) {
+ goto fail;
+ }
+
+ read_leb_uint32(p, p_end, mem_offset); /* offset */
+
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_V128);
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ break;
+ }
+
+ /* Float conversion */
+ case SIMD_f32x4_demote_f64x2_zero:
+ case SIMD_f64x2_promote_low_f32x4_zero:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ /* i8x16 Operation */
+ case SIMD_i8x16_abs:
+ case SIMD_i8x16_neg:
+ case SIMD_i8x16_popcnt:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i8x16_all_true:
+ case SIMD_i8x16_bitmask:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_I32);
+ break;
+ }
+
+ case SIMD_i8x16_narrow_i16x8_s:
+ case SIMD_i8x16_narrow_i16x8_u:
+ {
+ POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_f32x4_ceil:
+ case SIMD_f32x4_floor:
+ case SIMD_f32x4_trunc:
+ case SIMD_f32x4_nearest:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i8x16_shl:
+ case SIMD_i8x16_shr_s:
+ case SIMD_i8x16_shr_u:
+ {
+ POP_I32();
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i8x16_add:
+ case SIMD_i8x16_add_sat_s:
+ case SIMD_i8x16_add_sat_u:
+ case SIMD_i8x16_sub:
+ case SIMD_i8x16_sub_sat_s:
+ case SIMD_i8x16_sub_sat_u:
+ {
+ POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_f64x2_ceil:
+ case SIMD_f64x2_floor:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i8x16_min_s:
+ case SIMD_i8x16_min_u:
+ case SIMD_i8x16_max_s:
+ case SIMD_i8x16_max_u:
+ {
+ POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_f64x2_trunc:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i8x16_avgr_u:
+ {
+ POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i16x8_extadd_pairwise_i8x16_s:
+ case SIMD_i16x8_extadd_pairwise_i8x16_u:
+ case SIMD_i32x4_extadd_pairwise_i16x8_s:
+ case SIMD_i32x4_extadd_pairwise_i16x8_u:
+ /* i16x8 operation */
+ case SIMD_i16x8_abs:
+ case SIMD_i16x8_neg:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i16x8_q15mulr_sat_s:
+ {
+ POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i16x8_all_true:
+ case SIMD_i16x8_bitmask:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_I32);
+ break;
+ }
+
+ case SIMD_i16x8_narrow_i32x4_s:
+ case SIMD_i16x8_narrow_i32x4_u:
+ {
+ POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i16x8_extend_low_i8x16_s:
+ case SIMD_i16x8_extend_high_i8x16_s:
+ case SIMD_i16x8_extend_low_i8x16_u:
+ case SIMD_i16x8_extend_high_i8x16_u:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i16x8_shl:
+ case SIMD_i16x8_shr_s:
+ case SIMD_i16x8_shr_u:
+ {
+ POP_I32();
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i16x8_add:
+ case SIMD_i16x8_add_sat_s:
+ case SIMD_i16x8_add_sat_u:
+ case SIMD_i16x8_sub:
+ case SIMD_i16x8_sub_sat_s:
+ case SIMD_i16x8_sub_sat_u:
+ {
+ POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_f64x2_nearest:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i16x8_mul:
+ case SIMD_i16x8_min_s:
+ case SIMD_i16x8_min_u:
+ case SIMD_i16x8_max_s:
+ case SIMD_i16x8_max_u:
+ case SIMD_i16x8_avgr_u:
+ case SIMD_i16x8_extmul_low_i8x16_s:
+ case SIMD_i16x8_extmul_high_i8x16_s:
+ case SIMD_i16x8_extmul_low_i8x16_u:
+ case SIMD_i16x8_extmul_high_i8x16_u:
+ {
+ POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ /* i32x4 operation */
+ case SIMD_i32x4_abs:
+ case SIMD_i32x4_neg:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i32x4_all_true:
+ case SIMD_i32x4_bitmask:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_I32);
+ break;
+ }
+
+ case SIMD_i32x4_narrow_i64x2_s:
+ case SIMD_i32x4_narrow_i64x2_u:
+ {
+ POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i32x4_extend_low_i16x8_s:
+ case SIMD_i32x4_extend_high_i16x8_s:
+ case SIMD_i32x4_extend_low_i16x8_u:
+ case SIMD_i32x4_extend_high_i16x8_u:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i32x4_shl:
+ case SIMD_i32x4_shr_s:
+ case SIMD_i32x4_shr_u:
+ {
+ POP_I32();
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i32x4_add:
+ case SIMD_i32x4_sub:
+ case SIMD_i32x4_mul:
+ case SIMD_i32x4_min_s:
+ case SIMD_i32x4_min_u:
+ case SIMD_i32x4_max_s:
+ case SIMD_i32x4_max_u:
+ case SIMD_i32x4_dot_i16x8_s:
+ case SIMD_i32x4_avgr_u:
+ case SIMD_i32x4_extmul_low_i16x8_s:
+ case SIMD_i32x4_extmul_high_i16x8_s:
+ case SIMD_i32x4_extmul_low_i16x8_u:
+ case SIMD_i32x4_extmul_high_i16x8_u:
+ {
+ POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ /* i64x2 operation */
+ case SIMD_i64x2_abs:
+ case SIMD_i64x2_neg:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i64x2_all_true:
+ case SIMD_i64x2_bitmask:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_I32);
+ break;
+ }
+
+ case SIMD_i64x2_extend_low_i32x4_s:
+ case SIMD_i64x2_extend_high_i32x4_s:
+ case SIMD_i64x2_extend_low_i32x4_u:
+ case SIMD_i64x2_extend_high_i32x4_u:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i64x2_shl:
+ case SIMD_i64x2_shr_s:
+ case SIMD_i64x2_shr_u:
+ {
+ POP_I32();
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i64x2_add:
+ case SIMD_i64x2_sub:
+ case SIMD_i64x2_mul:
+ case SIMD_i64x2_eq:
+ case SIMD_i64x2_ne:
+ case SIMD_i64x2_lt_s:
+ case SIMD_i64x2_gt_s:
+ case SIMD_i64x2_le_s:
+ case SIMD_i64x2_ge_s:
+ case SIMD_i64x2_extmul_low_i32x4_s:
+ case SIMD_i64x2_extmul_high_i32x4_s:
+ case SIMD_i64x2_extmul_low_i32x4_u:
+ case SIMD_i64x2_extmul_high_i32x4_u:
+ {
+ POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ /* f32x4 operation */
+ case SIMD_f32x4_abs:
+ case SIMD_f32x4_neg:
+ case SIMD_f32x4_round:
+ case SIMD_f32x4_sqrt:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_f32x4_add:
+ case SIMD_f32x4_sub:
+ case SIMD_f32x4_mul:
+ case SIMD_f32x4_div:
+ case SIMD_f32x4_min:
+ case SIMD_f32x4_max:
+ case SIMD_f32x4_pmin:
+ case SIMD_f32x4_pmax:
+ {
+ POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ /* f64x2 operation */
+ case SIMD_f64x2_abs:
+ case SIMD_f64x2_neg:
+ case SIMD_f64x2_round:
+ case SIMD_f64x2_sqrt:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_f64x2_add:
+ case SIMD_f64x2_sub:
+ case SIMD_f64x2_mul:
+ case SIMD_f64x2_div:
+ case SIMD_f64x2_min:
+ case SIMD_f64x2_max:
+ case SIMD_f64x2_pmin:
+ case SIMD_f64x2_pmax:
+ {
+ POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ case SIMD_i32x4_trunc_sat_f32x4_s:
+ case SIMD_i32x4_trunc_sat_f32x4_u:
+ case SIMD_f32x4_convert_i32x4_s:
+ case SIMD_f32x4_convert_i32x4_u:
+ case SIMD_i32x4_trunc_sat_f64x2_s_zero:
+ case SIMD_i32x4_trunc_sat_f64x2_u_zero:
+ case SIMD_f64x2_convert_low_i32x4_s:
+ case SIMD_f64x2_convert_low_i32x4_u:
+ {
+ POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128);
+ break;
+ }
+
+ default:
+ {
+ if (error_buf != NULL) {
+ snprintf(error_buf, error_buf_size,
+ "WASM module load failed: "
+ "invalid opcode 0xfd %02x.",
+ opcode);
+ }
+ goto fail;
+ }
+ }
+ break;
+ }
+#endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) */
+#endif /* end of WASM_ENABLE_SIMD */
+
+#if WASM_ENABLE_SHARED_MEMORY != 0
+ case WASM_OP_ATOMIC_PREFIX:
+ {
+ opcode = read_uint8(p);
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_byte(loader_ctx, opcode);
+#endif
+ if (opcode != WASM_OP_ATOMIC_FENCE) {
+ CHECK_MEMORY();
+ read_leb_uint32(p, p_end, align); /* align */
+ read_leb_uint32(p, p_end, mem_offset); /* offset */
+ if (!check_memory_align_equal(opcode, align, error_buf,
+ error_buf_size)) {
+ goto fail;
+ }
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, mem_offset);
+#endif
+ }
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ switch (opcode) {
+ case WASM_OP_ATOMIC_NOTIFY:
+ POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+ break;
+ case WASM_OP_ATOMIC_WAIT32:
+ POP_I64();
+ POP_I32();
+ POP_I32();
+ PUSH_I32();
+ break;
+ case WASM_OP_ATOMIC_WAIT64:
+ POP_I64();
+ POP_I64();
+ POP_I32();
+ PUSH_I32();
+ break;
+ case WASM_OP_ATOMIC_FENCE:
+ /* reserved byte 0x00 */
+ if (*p++ != 0x00) {
+ set_error_buf(error_buf, error_buf_size,
+ "zero byte expected");
+ goto fail;
+ }
+ break;
+ case WASM_OP_ATOMIC_I32_LOAD:
+ case WASM_OP_ATOMIC_I32_LOAD8_U:
+ case WASM_OP_ATOMIC_I32_LOAD16_U:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+ break;
+ case WASM_OP_ATOMIC_I32_STORE:
+ case WASM_OP_ATOMIC_I32_STORE8:
+ case WASM_OP_ATOMIC_I32_STORE16:
+ POP_I32();
+ POP_I32();
+ break;
+ case WASM_OP_ATOMIC_I64_LOAD:
+ case WASM_OP_ATOMIC_I64_LOAD8_U:
+ case WASM_OP_ATOMIC_I64_LOAD16_U:
+ case WASM_OP_ATOMIC_I64_LOAD32_U:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64);
+ break;
+ case WASM_OP_ATOMIC_I64_STORE:
+ case WASM_OP_ATOMIC_I64_STORE8:
+ case WASM_OP_ATOMIC_I64_STORE16:
+ case WASM_OP_ATOMIC_I64_STORE32:
+ POP_I64();
+ POP_I32();
+ break;
+ case WASM_OP_ATOMIC_RMW_I32_ADD:
+ case WASM_OP_ATOMIC_RMW_I32_ADD8_U:
+ case WASM_OP_ATOMIC_RMW_I32_ADD16_U:
+ case WASM_OP_ATOMIC_RMW_I32_SUB:
+ case WASM_OP_ATOMIC_RMW_I32_SUB8_U:
+ case WASM_OP_ATOMIC_RMW_I32_SUB16_U:
+ case WASM_OP_ATOMIC_RMW_I32_AND:
+ case WASM_OP_ATOMIC_RMW_I32_AND8_U:
+ case WASM_OP_ATOMIC_RMW_I32_AND16_U:
+ case WASM_OP_ATOMIC_RMW_I32_OR:
+ case WASM_OP_ATOMIC_RMW_I32_OR8_U:
+ case WASM_OP_ATOMIC_RMW_I32_OR16_U:
+ case WASM_OP_ATOMIC_RMW_I32_XOR:
+ case WASM_OP_ATOMIC_RMW_I32_XOR8_U:
+ case WASM_OP_ATOMIC_RMW_I32_XOR16_U:
+ case WASM_OP_ATOMIC_RMW_I32_XCHG:
+ case WASM_OP_ATOMIC_RMW_I32_XCHG8_U:
+ case WASM_OP_ATOMIC_RMW_I32_XCHG16_U:
+ POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+ break;
+ case WASM_OP_ATOMIC_RMW_I64_ADD:
+ case WASM_OP_ATOMIC_RMW_I64_ADD8_U:
+ case WASM_OP_ATOMIC_RMW_I64_ADD16_U:
+ case WASM_OP_ATOMIC_RMW_I64_ADD32_U:
+ case WASM_OP_ATOMIC_RMW_I64_SUB:
+ case WASM_OP_ATOMIC_RMW_I64_SUB8_U:
+ case WASM_OP_ATOMIC_RMW_I64_SUB16_U:
+ case WASM_OP_ATOMIC_RMW_I64_SUB32_U:
+ case WASM_OP_ATOMIC_RMW_I64_AND:
+ case WASM_OP_ATOMIC_RMW_I64_AND8_U:
+ case WASM_OP_ATOMIC_RMW_I64_AND16_U:
+ case WASM_OP_ATOMIC_RMW_I64_AND32_U:
+ case WASM_OP_ATOMIC_RMW_I64_OR:
+ case WASM_OP_ATOMIC_RMW_I64_OR8_U:
+ case WASM_OP_ATOMIC_RMW_I64_OR16_U:
+ case WASM_OP_ATOMIC_RMW_I64_OR32_U:
+ case WASM_OP_ATOMIC_RMW_I64_XOR:
+ case WASM_OP_ATOMIC_RMW_I64_XOR8_U:
+ case WASM_OP_ATOMIC_RMW_I64_XOR16_U:
+ case WASM_OP_ATOMIC_RMW_I64_XOR32_U:
+ case WASM_OP_ATOMIC_RMW_I64_XCHG:
+ case WASM_OP_ATOMIC_RMW_I64_XCHG8_U:
+ case WASM_OP_ATOMIC_RMW_I64_XCHG16_U:
+ case WASM_OP_ATOMIC_RMW_I64_XCHG32_U:
+ POP_I64();
+ POP_I32();
+ PUSH_I64();
+ break;
+ case WASM_OP_ATOMIC_RMW_I32_CMPXCHG:
+ case WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U:
+ case WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U:
+ POP_I32();
+ POP_I32();
+ POP_I32();
+ PUSH_I32();
+ break;
+ case WASM_OP_ATOMIC_RMW_I64_CMPXCHG:
+ case WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U:
+ case WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U:
+ case WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U:
+ POP_I64();
+ POP_I64();
+ POP_I32();
+ PUSH_I64();
+ break;
+ default:
+ set_error_buf_v(error_buf, error_buf_size,
+ "%s %02x %02x", "unsupported opcode",
+ 0xfe, opcode);
+ goto fail;
+ }
+ break;
+ }
+#endif /* end of WASM_ENABLE_SHARED_MEMORY */
+
+ default:
+ set_error_buf_v(error_buf, error_buf_size, "%s %02x",
+ "unsupported opcode", opcode);
+ goto fail;
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ last_op = opcode;
+#endif
+ }
+
+ if (loader_ctx->csp_num > 0) {
+ if (cur_func_idx < module->function_count - 1)
+ /* Function with missing end marker (between two functions) */
+ set_error_buf(error_buf, error_buf_size, "END opcode expected");
+ else
+ /* Function with missing end marker
+ (at EOF or end of code sections) */
+ set_error_buf(error_buf, error_buf_size,
+ "unexpected end of section or function, "
+ "or section size mismatch");
+ goto fail;
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ if (loader_ctx->p_code_compiled == NULL)
+ goto re_scan;
+
+ func->const_cell_num = loader_ctx->const_cell_num;
+ if (func->const_cell_num > 0) {
+ int32 j;
+
+ if (!(func->consts = func_const = loader_malloc(
+ func->const_cell_num * 4, error_buf, error_buf_size)))
+ goto fail;
+
+ func_const_end = func->consts + func->const_cell_num * 4;
+ /* reverse the const buf */
+ for (j = loader_ctx->num_const - 1; j >= 0; j--) {
+ Const *c = (Const *)(loader_ctx->const_buf + j * sizeof(Const));
+ if (c->value_type == VALUE_TYPE_F64
+ || c->value_type == VALUE_TYPE_I64) {
+ bh_memcpy_s(func_const, (uint32)(func_const_end - func_const),
+ &(c->value.f64), (uint32)sizeof(int64));
+ func_const += sizeof(int64);
+ }
+ else {
+ bh_memcpy_s(func_const, (uint32)(func_const_end - func_const),
+ &(c->value.f32), (uint32)sizeof(int32));
+ func_const += sizeof(int32);
+ }
+ }
+ }
+
+ func->max_stack_cell_num = loader_ctx->preserved_local_offset
+ - loader_ctx->start_dynamic_offset + 1;
+#else
+ func->max_stack_cell_num = loader_ctx->max_stack_cell_num;
+#endif
+ func->max_block_num = loader_ctx->max_csp_num;
+ return_value = true;
+
+fail:
+ wasm_loader_ctx_destroy(loader_ctx);
+
+ (void)table_idx;
+ (void)table_seg_idx;
+ (void)data_seg_idx;
+ (void)i64_const;
+ (void)local_offset;
+ (void)p_org;
+ (void)mem_offset;
+ (void)align;
+ return return_value;
+}
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_loader.h b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_loader.h
new file mode 100644
index 000000000..8b0dc77d6
--- /dev/null
+++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_loader.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+#ifndef _WASM_LOADER_H
+#define _WASM_LOADER_H
+
+#include "wasm.h"
+#include "bh_hashmap.h"
+#include "../common/wasm_runtime_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Load a WASM module from a specified byte buffer.
+ *
+ * @param buf the byte buffer which contains the WASM binary data
+ * @param size the size of the buffer
+ * @param error_buf output of the exception info
+ * @param error_buf_size the size of the exception string
+ *
+ * @return return module loaded, NULL if failed
+ */
+WASMModule *
+wasm_loader_load(uint8 *buf, uint32 size,
+#if WASM_ENABLE_MULTI_MODULE != 0
+ bool main_module,
+#endif
+ char *error_buf, uint32 error_buf_size);
+
+/**
+ * Load a WASM module from a specified WASM section list.
+ *
+ * @param section_list the section list which contains each section data
+ * @param error_buf output of the exception info
+ * @param error_buf_size the size of the exception string
+ *
+ * @return return WASM module loaded, NULL if failed
+ */
+WASMModule *
+wasm_loader_load_from_sections(WASMSection *section_list, char *error_buf,
+ uint32 error_buf_size);
+
+/**
+ * Unload a WASM module.
+ *
+ * @param module the module to be unloaded
+ */
+void
+wasm_loader_unload(WASMModule *module);
+
+/**
+ * Find address of related else opcode and end opcode of opcode block/loop/if
+ * according to the start address of opcode.
+ *
+ * @param module the module to find
+ * @param start_addr the next address of opcode block/loop/if
+ * @param code_end_addr the end address of function code block
+ * @param block_type the type of block, 0/1/2 denotes block/loop/if
+ * @param p_else_addr returns the else addr if found
+ * @param p_end_addr returns the end addr if found
+ * @param error_buf returns the error log for this function
+ * @param error_buf_size returns the error log string length
+ *
+ * @return true if success, false otherwise
+ */
+
+bool
+wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
+ const uint8 *start_addr, const uint8 *code_end_addr,
+ uint8 block_type, uint8 **p_else_addr,
+ uint8 **p_end_addr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end of _WASM_LOADER_H */
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_mini_loader.c b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_mini_loader.c
new file mode 100644
index 000000000..aa5e18f6a
--- /dev/null
+++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_mini_loader.c
@@ -0,0 +1,7544 @@
+/*
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "wasm_loader.h"
+#include "bh_common.h"
+#include "bh_log.h"
+#include "wasm.h"
+#include "wasm_opcode.h"
+#include "wasm_runtime.h"
+#include "../common/wasm_native.h"
+#include "../common/wasm_memory.h"
+#if WASM_ENABLE_FAST_JIT != 0
+#include "../fast-jit/jit_compiler.h"
+#include "../fast-jit/jit_codecache.h"
+#endif
+#if WASM_ENABLE_JIT != 0
+#include "../compilation/aot_llvm.h"
+#endif
+
+/* Read a value of given type from the address pointed to by the given
+ pointer and increase the pointer to the position just after the
+ value being read. */
+#define TEMPLATE_READ_VALUE(Type, p) \
+ (p += sizeof(Type), *(Type *)(p - sizeof(Type)))
+
+static void
+set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
+{
+ if (error_buf != NULL)
+ snprintf(error_buf, error_buf_size, "WASM module load failed: %s",
+ string);
+}
+
+#define CHECK_BUF(buf, buf_end, length) \
+ do { \
+ bh_assert(buf + length >= buf && buf + length <= buf_end); \
+ } while (0)
+
+#define CHECK_BUF1(buf, buf_end, length) \
+ do { \
+ bh_assert(buf + length >= buf && buf + length <= buf_end); \
+ } while (0)
+
+#define skip_leb(p) while (*p++ & 0x80)
+#define skip_leb_int64(p, p_end) skip_leb(p)
+#define skip_leb_uint32(p, p_end) skip_leb(p)
+#define skip_leb_int32(p, p_end) skip_leb(p)
+
+static bool
+is_32bit_type(uint8 type)
+{
+ if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32
+#if WASM_ENABLE_REF_TYPES != 0
+ || type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF
+#endif
+ )
+ return true;
+ return false;
+}
+
+static bool
+is_64bit_type(uint8 type)
+{
+ if (type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64)
+ return true;
+ return false;
+}
+
+static bool
+is_value_type(uint8 type)
+{
+ if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_I64
+ || type == VALUE_TYPE_F32 || type == VALUE_TYPE_F64
+#if WASM_ENABLE_REF_TYPES != 0
+ || type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF
+#endif
+ )
+ return true;
+ return false;
+}
+
+static bool
+is_byte_a_type(uint8 type)
+{
+ return is_value_type(type) || (type == VALUE_TYPE_VOID);
+}
+
+static void
+read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign,
+ uint64 *p_result, char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *buf = *p_buf;
+ uint64 result = 0;
+ uint32 shift = 0;
+ uint32 offset = 0, bcnt = 0;
+ uint64 byte;
+
+ while (true) {
+ bh_assert(bcnt + 1 <= (maxbits + 6) / 7);
+ CHECK_BUF(buf, buf_end, offset + 1);
+ byte = buf[offset];
+ offset += 1;
+ result |= ((byte & 0x7f) << shift);
+ shift += 7;
+ bcnt += 1;
+ if ((byte & 0x80) == 0) {
+ break;
+ }
+ }
+
+ if (!sign && maxbits == 32 && shift >= maxbits) {
+ /* The top bits set represent values > 32 bits */
+ bh_assert(!(((uint8)byte) & 0xf0));
+ }
+ else if (sign && maxbits == 32) {
+ if (shift < maxbits) {
+ /* Sign extend, second highest bit is the sign bit */
+ if ((uint8)byte & 0x40)
+ result |= (~((uint64)0)) << shift;
+ }
+ else {
+ /* The top bits should be a sign-extension of the sign bit */
+ bool sign_bit_set = ((uint8)byte) & 0x8;
+ int top_bits = ((uint8)byte) & 0xf0;
+ bh_assert(!((sign_bit_set && top_bits != 0x70)
+ || (!sign_bit_set && top_bits != 0)));
+ (void)top_bits;
+ (void)sign_bit_set;
+ }
+ }
+ else if (sign && maxbits == 64) {
+ if (shift < maxbits) {
+ /* Sign extend, second highest bit is the sign bit */
+ if ((uint8)byte & 0x40)
+ result |= (~((uint64)0)) << shift;
+ }
+ else {
+ /* The top bits should be a sign-extension of the sign bit */
+ bool sign_bit_set = ((uint8)byte) & 0x1;
+ int top_bits = ((uint8)byte) & 0xfe;
+
+ bh_assert(!((sign_bit_set && top_bits != 0x7e)
+ || (!sign_bit_set && top_bits != 0)));
+ (void)top_bits;
+ (void)sign_bit_set;
+ }
+ }
+
+ *p_buf += offset;
+ *p_result = result;
+}
+
+#define read_uint8(p) TEMPLATE_READ_VALUE(uint8, p)
+#define read_uint32(p) TEMPLATE_READ_VALUE(uint32, p)
+#define read_bool(p) TEMPLATE_READ_VALUE(bool, p)
+
+#define read_leb_int64(p, p_end, res) \
+ do { \
+ uint64 res64; \
+ read_leb((uint8 **)&p, p_end, 64, true, &res64, error_buf, \
+ error_buf_size); \
+ res = (int64)res64; \
+ } while (0)
+
+#define read_leb_uint32(p, p_end, res) \
+ do { \
+ uint64 res64; \
+ read_leb((uint8 **)&p, p_end, 32, false, &res64, error_buf, \
+ error_buf_size); \
+ res = (uint32)res64; \
+ } while (0)
+
+#define read_leb_int32(p, p_end, res) \
+ do { \
+ uint64 res64; \
+ read_leb((uint8 **)&p, p_end, 32, true, &res64, error_buf, \
+ error_buf_size); \
+ res = (int32)res64; \
+ } while (0)
+
+static void *
+loader_malloc(uint64 size, char *error_buf, uint32 error_buf_size)
+{
+ void *mem;
+
+ if (size >= UINT32_MAX || !(mem = wasm_runtime_malloc((uint32)size))) {
+ set_error_buf(error_buf, error_buf_size, "allocate memory failed");
+ return NULL;
+ }
+
+ memset(mem, 0, (uint32)size);
+ return mem;
+}
+
+static char *
+const_str_list_insert(const uint8 *str, uint32 len, WASMModule *module,
+ bool is_load_from_file_buf, char *error_buf,
+ uint32 error_buf_size)
+{
+ StringNode *node, *node_next;
+
+ if (len == 0) {
+ return "";
+ }
+ else if (is_load_from_file_buf) {
+ /* As the file buffer can be referred to after loading, we use
+ the previous byte of leb encoded size to adjust the string:
+ move string 1 byte backward and then append '\0' */
+ char *c_str = (char *)str - 1;
+ bh_memmove_s(c_str, len + 1, c_str + 1, len);
+ c_str[len] = '\0';
+ return c_str;
+ }
+
+ /* Search const str list */
+ node = module->const_str_list;
+ while (node) {
+ node_next = node->next;
+ if (strlen(node->str) == len && !memcmp(node->str, str, len))
+ break;
+ node = node_next;
+ }
+
+ if (node) {
+ LOG_DEBUG("reuse %s", node->str);
+ return node->str;
+ }
+
+ if (!(node = loader_malloc(sizeof(StringNode) + len + 1, error_buf,
+ error_buf_size))) {
+ return NULL;
+ }
+
+ node->str = ((char *)node) + sizeof(StringNode);
+ bh_memcpy_s(node->str, len + 1, str, len);
+ node->str[len] = '\0';
+
+ if (!module->const_str_list) {
+ /* set as head */
+ module->const_str_list = node;
+ node->next = NULL;
+ }
+ else {
+ /* insert it */
+ node->next = module->const_str_list;
+ module->const_str_list = node;
+ }
+
+ return node->str;
+}
+
+static void
+destroy_wasm_type(WASMType *type)
+{
+ if (type->ref_count > 1) {
+ /* The type is referenced by other types
+ of current wasm module */
+ type->ref_count--;
+ return;
+ }
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0
+ if (type->call_to_llvm_jit_from_fast_jit)
+ jit_code_cache_free(type->call_to_llvm_jit_from_fast_jit);
+#endif
+
+ wasm_runtime_free(type);
+}
+
+static bool
+load_init_expr(const uint8 **p_buf, const uint8 *buf_end,
+ InitializerExpression *init_expr, uint8 type, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end;
+ uint8 flag, end_byte, *p_float;
+ uint32 i;
+
+ CHECK_BUF(p, p_end, 1);
+ init_expr->init_expr_type = read_uint8(p);
+ flag = init_expr->init_expr_type;
+
+ switch (flag) {
+ /* i32.const */
+ case INIT_EXPR_TYPE_I32_CONST:
+ bh_assert(type == VALUE_TYPE_I32);
+ read_leb_int32(p, p_end, init_expr->u.i32);
+ break;
+ /* i64.const */
+ case INIT_EXPR_TYPE_I64_CONST:
+ bh_assert(type == VALUE_TYPE_I64);
+ read_leb_int64(p, p_end, init_expr->u.i64);
+ break;
+ /* f32.const */
+ case INIT_EXPR_TYPE_F32_CONST:
+ bh_assert(type == VALUE_TYPE_F32);
+ CHECK_BUF(p, p_end, 4);
+ p_float = (uint8 *)&init_expr->u.f32;
+ for (i = 0; i < sizeof(float32); i++)
+ *p_float++ = *p++;
+ break;
+ /* f64.const */
+ case INIT_EXPR_TYPE_F64_CONST:
+ bh_assert(type == VALUE_TYPE_F64);
+ CHECK_BUF(p, p_end, 8);
+ p_float = (uint8 *)&init_expr->u.f64;
+ for (i = 0; i < sizeof(float64); i++)
+ *p_float++ = *p++;
+ break;
+#if WASM_ENABLE_REF_TYPES != 0
+ case INIT_EXPR_TYPE_FUNCREF_CONST:
+ {
+ bh_assert(type == VALUE_TYPE_FUNCREF);
+ read_leb_uint32(p, p_end, init_expr->u.ref_index);
+ break;
+ }
+ case INIT_EXPR_TYPE_REFNULL_CONST:
+ {
+ uint8 reftype;
+
+ CHECK_BUF(p, p_end, 1);
+ reftype = read_uint8(p);
+
+ bh_assert(type == reftype);
+
+ init_expr->u.ref_index = NULL_REF;
+ (void)reftype;
+ break;
+ }
+#endif /* WASM_ENABLE_REF_TYPES != 0 */
+ /* get_global */
+ case INIT_EXPR_TYPE_GET_GLOBAL:
+ read_leb_uint32(p, p_end, init_expr->u.global_index);
+ break;
+ default:
+ bh_assert(0);
+ break;
+ }
+ CHECK_BUF(p, p_end, 1);
+ end_byte = read_uint8(p);
+ bh_assert(end_byte == 0x0b);
+ *p_buf = p;
+
+ (void)end_byte;
+ return true;
+}
+
+static bool
+load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end, *p_org;
+ uint32 type_count, param_count, result_count, i, j;
+ uint32 param_cell_num, ret_cell_num;
+ uint64 total_size;
+ uint8 flag;
+ WASMType *type;
+
+ read_leb_uint32(p, p_end, type_count);
+
+ if (type_count) {
+ module->type_count = type_count;
+ total_size = sizeof(WASMType *) * (uint64)type_count;
+ if (!(module->types =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ for (i = 0; i < type_count; i++) {
+ CHECK_BUF(p, p_end, 1);
+ flag = read_uint8(p);
+ bh_assert(flag == 0x60);
+
+ read_leb_uint32(p, p_end, param_count);
+
+ /* Resolve param count and result count firstly */
+ p_org = p;
+ CHECK_BUF(p, p_end, param_count);
+ p += param_count;
+ read_leb_uint32(p, p_end, result_count);
+ CHECK_BUF(p, p_end, result_count);
+ p = p_org;
+
+ bh_assert(param_count <= UINT16_MAX && result_count <= UINT16_MAX);
+
+ total_size = offsetof(WASMType, types)
+ + sizeof(uint8) * (uint64)(param_count + result_count);
+ if (!(type = module->types[i] =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ /* Resolve param types and result types */
+ type->ref_count = 1;
+ type->param_count = (uint16)param_count;
+ type->result_count = (uint16)result_count;
+ for (j = 0; j < param_count; j++) {
+ CHECK_BUF(p, p_end, 1);
+ type->types[j] = read_uint8(p);
+ }
+ read_leb_uint32(p, p_end, result_count);
+ for (j = 0; j < result_count; j++) {
+ CHECK_BUF(p, p_end, 1);
+ type->types[param_count + j] = read_uint8(p);
+ }
+ for (j = 0; j < param_count + result_count; j++) {
+ bh_assert(is_value_type(type->types[j]));
+ }
+
+ param_cell_num = wasm_get_cell_num(type->types, param_count);
+ ret_cell_num =
+ wasm_get_cell_num(type->types + param_count, result_count);
+ bh_assert(param_cell_num <= UINT16_MAX
+ && ret_cell_num <= UINT16_MAX);
+ type->param_cell_num = (uint16)param_cell_num;
+ type->ret_cell_num = (uint16)ret_cell_num;
+
+ /* If there is already a same type created, use it instead */
+ for (j = 0; j < i; ++j) {
+ if (wasm_type_equal(type, module->types[j])) {
+ bh_assert(module->types[j]->ref_count != UINT16_MAX);
+ destroy_wasm_type(type);
+ module->types[i] = module->types[j];
+ module->types[j]->ref_count++;
+ break;
+ }
+ }
+ }
+ }
+
+ bh_assert(p == p_end);
+ LOG_VERBOSE("Load type section success.\n");
+ (void)flag;
+ return true;
+}
+
+static void
+adjust_table_max_size(uint32 init_size, uint32 max_size_flag, uint32 *max_size)
+{
+ uint32 default_max_size =
+ init_size * 2 > TABLE_MAX_SIZE ? init_size * 2 : TABLE_MAX_SIZE;
+
+ if (max_size_flag) {
+ /* module defines the table limitation */
+ bh_assert(init_size <= *max_size);
+
+ if (init_size < *max_size) {
+ *max_size =
+ *max_size < default_max_size ? *max_size : default_max_size;
+ }
+ }
+ else {
+ /* partial defined table limitation, gives a default value */
+ *max_size = default_max_size;
+ }
+}
+
+static bool
+load_function_import(const uint8 **p_buf, const uint8 *buf_end,
+ const WASMModule *parent_module,
+ const char *sub_module_name, const char *function_name,
+ WASMFunctionImport *function, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end;
+ uint32 declare_type_index = 0;
+ WASMType *declare_func_type = NULL;
+ WASMFunction *linked_func = NULL;
+ const char *linked_signature = NULL;
+ void *linked_attachment = NULL;
+ bool linked_call_conv_raw = false;
+
+ read_leb_uint32(p, p_end, declare_type_index);
+ *p_buf = p;
+
+ bh_assert(declare_type_index < parent_module->type_count);
+
+ declare_func_type = parent_module->types[declare_type_index];
+
+ /* check built-in modules */
+ linked_func = wasm_native_resolve_symbol(
+ sub_module_name, function_name, declare_func_type, &linked_signature,
+ &linked_attachment, &linked_call_conv_raw);
+
+ function->module_name = (char *)sub_module_name;
+ function->field_name = (char *)function_name;
+ function->func_type = declare_func_type;
+ function->func_ptr_linked = linked_func;
+ function->signature = linked_signature;
+ function->attachment = linked_attachment;
+ function->call_conv_raw = linked_call_conv_raw;
+ return true;
+}
+
+static bool
+load_table_import(const uint8 **p_buf, const uint8 *buf_end,
+ WASMModule *parent_module, const char *sub_module_name,
+ const char *table_name, WASMTableImport *table,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end;
+ uint32 declare_elem_type = 0, declare_max_size_flag = 0,
+ declare_init_size = 0, declare_max_size = 0;
+
+ CHECK_BUF(p, p_end, 1);
+ /* 0x70 or 0x6F */
+ declare_elem_type = read_uint8(p);
+ bh_assert(VALUE_TYPE_FUNCREF == declare_elem_type
+#if WASM_ENABLE_REF_TYPES != 0
+ || VALUE_TYPE_EXTERNREF == declare_elem_type
+#endif
+ );
+
+ read_leb_uint32(p, p_end, declare_max_size_flag);
+ read_leb_uint32(p, p_end, declare_init_size);
+ if (declare_max_size_flag & 1) {
+ read_leb_uint32(p, p_end, declare_max_size);
+ bh_assert(table->init_size <= table->max_size);
+ }
+
+ adjust_table_max_size(declare_init_size, declare_max_size_flag,
+ &declare_max_size);
+ *p_buf = p;
+
+ bh_assert(
+ !((declare_max_size_flag & 1) && declare_init_size > declare_max_size));
+
+ /* now we believe all declaration are ok */
+ table->elem_type = declare_elem_type;
+ table->init_size = declare_init_size;
+ table->flags = declare_max_size_flag;
+ table->max_size = declare_max_size;
+ return true;
+}
+
+static bool
+load_memory_import(const uint8 **p_buf, const uint8 *buf_end,
+ WASMModule *parent_module, const char *sub_module_name,
+ const char *memory_name, WASMMemoryImport *memory,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end;
+#if WASM_ENABLE_APP_FRAMEWORK != 0
+ uint32 pool_size = wasm_runtime_memory_pool_size();
+ uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT
+ / DEFAULT_NUM_BYTES_PER_PAGE;
+#else
+ uint32 max_page_count = DEFAULT_MAX_PAGES;
+#endif /* WASM_ENABLE_APP_FRAMEWORK */
+ uint32 declare_max_page_count_flag = 0;
+ uint32 declare_init_page_count = 0;
+ uint32 declare_max_page_count = 0;
+
+ read_leb_uint32(p, p_end, declare_max_page_count_flag);
+ read_leb_uint32(p, p_end, declare_init_page_count);
+ bh_assert(declare_init_page_count <= 65536);
+
+ if (declare_max_page_count_flag & 1) {
+ read_leb_uint32(p, p_end, declare_max_page_count);
+ bh_assert(declare_init_page_count <= declare_max_page_count);
+ bh_assert(declare_max_page_count <= 65536);
+ if (declare_max_page_count > max_page_count) {
+ declare_max_page_count = max_page_count;
+ }
+ }
+ else {
+ /* Limit the maximum memory size to max_page_count */
+ declare_max_page_count = max_page_count;
+ }
+
+ /* now we believe all declaration are ok */
+ memory->flags = declare_max_page_count_flag;
+ memory->init_page_count = declare_init_page_count;
+ memory->max_page_count = declare_max_page_count;
+ memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE;
+
+ *p_buf = p;
+ return true;
+}
+
+static bool
+load_global_import(const uint8 **p_buf, const uint8 *buf_end,
+ const WASMModule *parent_module, char *sub_module_name,
+ char *global_name, WASMGlobalImport *global, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end;
+ uint8 declare_type = 0;
+ uint8 declare_mutable = 0;
+ bool is_mutable = false;
+ bool ret = false;
+
+ CHECK_BUF(p, p_end, 2);
+ declare_type = read_uint8(p);
+ declare_mutable = read_uint8(p);
+ *p_buf = p;
+
+ bh_assert(declare_mutable < 2);
+
+ is_mutable = declare_mutable & 1 ? true : false;
+
+#if WASM_ENABLE_LIBC_BUILTIN != 0
+ /* check built-in modules */
+ ret = wasm_native_lookup_libc_builtin_global(sub_module_name, global_name,
+ global);
+ if (ret) {
+ bh_assert(global->type == declare_type
+ && global->is_mutable != declare_mutable);
+ }
+#endif /* WASM_ENABLE_LIBC_BUILTIN */
+
+ global->is_linked = ret;
+ global->module_name = sub_module_name;
+ global->field_name = global_name;
+ global->type = declare_type;
+ global->is_mutable = is_mutable;
+ (void)p_end;
+ return true;
+}
+
+static bool
+load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end, *p_org;
+
+ CHECK_BUF(p, p_end, 1);
+ /* 0x70 or 0x6F */
+ table->elem_type = read_uint8(p);
+ bh_assert((VALUE_TYPE_FUNCREF == table->elem_type)
+#if WASM_ENABLE_REF_TYPES != 0
+ || VALUE_TYPE_EXTERNREF == table->elem_type
+#endif
+ );
+
+ p_org = p;
+ read_leb_uint32(p, p_end, table->flags);
+ bh_assert(p - p_org <= 1);
+ bh_assert(table->flags <= 1);
+ (void)p_org;
+
+ read_leb_uint32(p, p_end, table->init_size);
+ if (table->flags == 1) {
+ read_leb_uint32(p, p_end, table->max_size);
+ bh_assert(table->init_size <= table->max_size);
+ }
+
+ adjust_table_max_size(table->init_size, table->flags, &table->max_size);
+
+ *p_buf = p;
+ return true;
+}
+
+static bool
+load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end, *p_org;
+#if WASM_ENABLE_APP_FRAMEWORK != 0
+ uint32 pool_size = wasm_runtime_memory_pool_size();
+ uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT
+ / DEFAULT_NUM_BYTES_PER_PAGE;
+#else
+ uint32 max_page_count = DEFAULT_MAX_PAGES;
+#endif
+
+ p_org = p;
+ read_leb_uint32(p, p_end, memory->flags);
+ bh_assert(p - p_org <= 1);
+ (void)p_org;
+#if WASM_ENABLE_SHARED_MEMORY == 0
+ bh_assert(memory->flags <= 1);
+#else
+ bh_assert(memory->flags <= 3 && memory->flags != 2);
+#endif
+
+ read_leb_uint32(p, p_end, memory->init_page_count);
+ bh_assert(memory->init_page_count <= 65536);
+
+ if (memory->flags & 1) {
+ read_leb_uint32(p, p_end, memory->max_page_count);
+ bh_assert(memory->init_page_count <= memory->max_page_count);
+ bh_assert(memory->max_page_count <= 65536);
+ if (memory->max_page_count > max_page_count)
+ memory->max_page_count = max_page_count;
+ }
+ else {
+ /* Limit the maximum memory size to max_page_count */
+ memory->max_page_count = max_page_count;
+ }
+
+ memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE;
+
+ *p_buf = p;
+ return true;
+}
+
+static bool
+load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
+ bool is_load_from_file_buf, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end, *p_old;
+ uint32 import_count, name_len, type_index, i, u32, flags;
+ uint64 total_size;
+ WASMImport *import;
+ WASMImport *import_functions = NULL, *import_tables = NULL;
+ WASMImport *import_memories = NULL, *import_globals = NULL;
+ char *sub_module_name, *field_name;
+ uint8 u8, kind;
+
+ read_leb_uint32(p, p_end, import_count);
+
+ if (import_count) {
+ module->import_count = import_count;
+ total_size = sizeof(WASMImport) * (uint64)import_count;
+ if (!(module->imports =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ p_old = p;
+
+ /* Scan firstly to get import count of each type */
+ for (i = 0; i < import_count; i++) {
+ /* module name */
+ read_leb_uint32(p, p_end, name_len);
+ CHECK_BUF(p, p_end, name_len);
+ p += name_len;
+
+ /* field name */
+ read_leb_uint32(p, p_end, name_len);
+ CHECK_BUF(p, p_end, name_len);
+ p += name_len;
+
+ CHECK_BUF(p, p_end, 1);
+ /* 0x00/0x01/0x02/0x03 */
+ kind = read_uint8(p);
+
+ switch (kind) {
+ case IMPORT_KIND_FUNC: /* import function */
+ read_leb_uint32(p, p_end, type_index);
+ module->import_function_count++;
+ break;
+
+ case IMPORT_KIND_TABLE: /* import table */
+ CHECK_BUF(p, p_end, 1);
+ /* 0x70 */
+ u8 = read_uint8(p);
+ read_leb_uint32(p, p_end, flags);
+ read_leb_uint32(p, p_end, u32);
+ if (flags & 1)
+ read_leb_uint32(p, p_end, u32);
+ module->import_table_count++;
+#if WASM_ENABLE_REF_TYPES == 0
+ bh_assert(module->import_table_count <= 1);
+#endif
+ break;
+
+ case IMPORT_KIND_MEMORY: /* import memory */
+ read_leb_uint32(p, p_end, flags);
+ read_leb_uint32(p, p_end, u32);
+ if (flags & 1)
+ read_leb_uint32(p, p_end, u32);
+ module->import_memory_count++;
+ bh_assert(module->import_memory_count <= 1);
+ break;
+
+ case IMPORT_KIND_GLOBAL: /* import global */
+ CHECK_BUF(p, p_end, 2);
+ p += 2;
+ module->import_global_count++;
+ break;
+
+ default:
+ bh_assert(0);
+ break;
+ }
+ }
+
+ if (module->import_function_count)
+ import_functions = module->import_functions = module->imports;
+ if (module->import_table_count)
+ import_tables = module->import_tables =
+ module->imports + module->import_function_count;
+ if (module->import_memory_count)
+ import_memories = module->import_memories =
+ module->imports + module->import_function_count
+ + module->import_table_count;
+ if (module->import_global_count)
+ import_globals = module->import_globals =
+ module->imports + module->import_function_count
+ + module->import_table_count + module->import_memory_count;
+
+ p = p_old;
+
+ /* Scan again to resolve the data */
+ for (i = 0; i < import_count; i++) {
+ WASMModule *sub_module = NULL;
+
+ /* load module name */
+ read_leb_uint32(p, p_end, name_len);
+ CHECK_BUF(p, p_end, name_len);
+ if (!(sub_module_name = const_str_list_insert(
+ p, name_len, module, is_load_from_file_buf, error_buf,
+ error_buf_size))) {
+ return false;
+ }
+ p += name_len;
+
+ /* load field name */
+ read_leb_uint32(p, p_end, name_len);
+ CHECK_BUF(p, p_end, name_len);
+ if (!(field_name = const_str_list_insert(
+ p, name_len, module, is_load_from_file_buf, error_buf,
+ error_buf_size))) {
+ return false;
+ }
+ p += name_len;
+
+ CHECK_BUF(p, p_end, 1);
+ /* 0x00/0x01/0x02/0x03 */
+ kind = read_uint8(p);
+
+ LOG_DEBUG("import #%d: (%s, %s), kind: %d", i, sub_module_name,
+ field_name, kind);
+ switch (kind) {
+ case IMPORT_KIND_FUNC: /* import function */
+ bh_assert(import_functions);
+ import = import_functions++;
+ if (!load_function_import(
+ &p, p_end, module, sub_module_name, field_name,
+ &import->u.function, error_buf, error_buf_size)) {
+ return false;
+ }
+ break;
+
+ case IMPORT_KIND_TABLE: /* import table */
+ bh_assert(import_tables);
+ import = import_tables++;
+ if (!load_table_import(&p, p_end, module, sub_module_name,
+ field_name, &import->u.table,
+ error_buf, error_buf_size)) {
+ LOG_DEBUG("can not import such a table (%s,%s)",
+ sub_module_name, field_name);
+ return false;
+ }
+ break;
+
+ case IMPORT_KIND_MEMORY: /* import memory */
+ bh_assert(import_memories);
+ import = import_memories++;
+ if (!load_memory_import(&p, p_end, module, sub_module_name,
+ field_name, &import->u.memory,
+ error_buf, error_buf_size)) {
+ return false;
+ }
+ break;
+
+ case IMPORT_KIND_GLOBAL: /* import global */
+ bh_assert(import_globals);
+ import = import_globals++;
+ if (!load_global_import(&p, p_end, module, sub_module_name,
+ field_name, &import->u.global,
+ error_buf, error_buf_size)) {
+ return false;
+ }
+ break;
+
+ default:
+ bh_assert(0);
+ import = NULL;
+ break;
+ }
+ import->kind = kind;
+ import->u.names.module_name = sub_module_name;
+ import->u.names.field_name = field_name;
+ (void)sub_module;
+ }
+
+#if WASM_ENABLE_LIBC_WASI != 0
+ import = module->import_functions;
+ for (i = 0; i < module->import_function_count; i++, import++) {
+ if (!strcmp(import->u.names.module_name, "wasi_unstable")
+ || !strcmp(import->u.names.module_name,
+ "wasi_snapshot_preview1")) {
+ module->import_wasi_api = true;
+ break;
+ }
+ }
+#endif
+ }
+
+ bh_assert(p == p_end);
+
+ LOG_VERBOSE("Load import section success.\n");
+ (void)u8;
+ (void)u32;
+ (void)type_index;
+ return true;
+}
+
+static bool
+init_function_local_offsets(WASMFunction *func, char *error_buf,
+ uint32 error_buf_size)
+{
+ WASMType *param_type = func->func_type;
+ uint32 param_count = param_type->param_count;
+ uint8 *param_types = param_type->types;
+ uint32 local_count = func->local_count;
+ uint8 *local_types = func->local_types;
+ uint32 i, local_offset = 0;
+ uint64 total_size = sizeof(uint16) * ((uint64)param_count + local_count);
+
+ if (total_size > 0
+ && !(func->local_offsets =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ for (i = 0; i < param_count; i++) {
+ func->local_offsets[i] = (uint16)local_offset;
+ local_offset += wasm_value_type_cell_num(param_types[i]);
+ }
+
+ for (i = 0; i < local_count; i++) {
+ func->local_offsets[param_count + i] = (uint16)local_offset;
+ local_offset += wasm_value_type_cell_num(local_types[i]);
+ }
+
+ bh_assert(local_offset == func->param_cell_num + func->local_cell_num);
+ return true;
+}
+
+static bool
+load_function_section(const uint8 *buf, const uint8 *buf_end,
+ const uint8 *buf_code, const uint8 *buf_code_end,
+ WASMModule *module, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ const uint8 *p_code = buf_code, *p_code_end, *p_code_save;
+ uint32 func_count;
+ uint64 total_size;
+ uint32 code_count = 0, code_size, type_index, i, j, k, local_type_index;
+ uint32 local_count, local_set_count, sub_local_count, local_cell_num;
+ uint8 type;
+ WASMFunction *func;
+
+ read_leb_uint32(p, p_end, func_count);
+
+ if (buf_code)
+ read_leb_uint32(p_code, buf_code_end, code_count);
+
+ bh_assert(func_count == code_count);
+
+ if (func_count) {
+ module->function_count = func_count;
+ total_size = sizeof(WASMFunction *) * (uint64)func_count;
+ if (!(module->functions =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ for (i = 0; i < func_count; i++) {
+ /* Resolve function type */
+ read_leb_uint32(p, p_end, type_index);
+ bh_assert(type_index < module->type_count);
+
+#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
+ type_index = wasm_get_smallest_type_idx(
+ module->types, module->type_count, type_index);
+#endif
+
+ read_leb_uint32(p_code, buf_code_end, code_size);
+ bh_assert(code_size > 0 && p_code + code_size <= buf_code_end);
+
+ /* Resolve local set count */
+ p_code_end = p_code + code_size;
+ local_count = 0;
+ read_leb_uint32(p_code, buf_code_end, local_set_count);
+ p_code_save = p_code;
+
+ /* Calculate total local count */
+ for (j = 0; j < local_set_count; j++) {
+ read_leb_uint32(p_code, buf_code_end, sub_local_count);
+ bh_assert(sub_local_count <= UINT32_MAX - local_count);
+
+ CHECK_BUF(p_code, buf_code_end, 1);
+ /* 0x7F/0x7E/0x7D/0x7C */
+ type = read_uint8(p_code);
+ local_count += sub_local_count;
+ }
+
+ /* Alloc memory, layout: function structure + local types */
+ code_size = (uint32)(p_code_end - p_code);
+
+ total_size = sizeof(WASMFunction) + (uint64)local_count;
+ if (!(func = module->functions[i] =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ /* Set function type, local count, code size and code body */
+ func->func_type = module->types[type_index];
+ func->local_count = local_count;
+ if (local_count > 0)
+ func->local_types = (uint8 *)func + sizeof(WASMFunction);
+ func->code_size = code_size;
+ /*
+ * we shall make a copy of code body [p_code, p_code + code_size]
+ * when we are worrying about inappropriate releasing behaviour.
+ * all code bodies are actually in a buffer which user allocates in
+ * his embedding environment and we don't have power on them.
+ * it will be like:
+ * code_body_cp = malloc(code_size);
+ * memcpy(code_body_cp, p_code, code_size);
+ * func->code = code_body_cp;
+ */
+ func->code = (uint8 *)p_code;
+
+ /* Load each local type */
+ p_code = p_code_save;
+ local_type_index = 0;
+ for (j = 0; j < local_set_count; j++) {
+ read_leb_uint32(p_code, buf_code_end, sub_local_count);
+ /* Note: sub_local_count is allowed to be 0 */
+ bh_assert(local_type_index <= UINT32_MAX - sub_local_count
+ && local_type_index + sub_local_count <= local_count);
+
+ CHECK_BUF(p_code, buf_code_end, 1);
+ /* 0x7F/0x7E/0x7D/0x7C */
+ type = read_uint8(p_code);
+ bh_assert(is_value_type(type));
+ for (k = 0; k < sub_local_count; k++) {
+ func->local_types[local_type_index++] = type;
+ }
+ }
+
+ func->param_cell_num = func->func_type->param_cell_num;
+ func->ret_cell_num = func->func_type->ret_cell_num;
+ local_cell_num =
+ wasm_get_cell_num(func->local_types, func->local_count);
+ bh_assert(local_cell_num <= UINT16_MAX);
+
+ func->local_cell_num = (uint16)local_cell_num;
+
+ if (!init_function_local_offsets(func, error_buf, error_buf_size))
+ return false;
+
+ p_code = p_code_end;
+ }
+ }
+
+ bh_assert(p == p_end);
+ LOG_VERBOSE("Load function section success.\n");
+ (void)code_count;
+ return true;
+}
+
+static bool
+check_function_index(const WASMModule *module, uint32 function_index,
+ char *error_buf, uint32 error_buf_size)
+{
+ return (function_index
+ < module->import_function_count + module->function_count);
+}
+
+static bool
+load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 table_count, i;
+ uint64 total_size;
+ WASMTable *table;
+
+ read_leb_uint32(p, p_end, table_count);
+#if WASM_ENABLE_REF_TYPES == 0
+ bh_assert(module->import_table_count + table_count <= 1);
+#endif
+
+ if (table_count) {
+ module->table_count = table_count;
+ total_size = sizeof(WASMTable) * (uint64)table_count;
+ if (!(module->tables =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ /* load each table */
+ table = module->tables;
+ for (i = 0; i < table_count; i++, table++)
+ if (!load_table(&p, p_end, table, error_buf, error_buf_size))
+ return false;
+ }
+
+ bh_assert(p == p_end);
+ LOG_VERBOSE("Load table section success.\n");
+ return true;
+}
+
+static bool
+load_memory_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 memory_count, i;
+ uint64 total_size;
+ WASMMemory *memory;
+
+ read_leb_uint32(p, p_end, memory_count);
+ bh_assert(module->import_memory_count + memory_count <= 1);
+
+ if (memory_count) {
+ module->memory_count = memory_count;
+ total_size = sizeof(WASMMemory) * (uint64)memory_count;
+ if (!(module->memories =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ /* load each memory */
+ memory = module->memories;
+ for (i = 0; i < memory_count; i++, memory++)
+ if (!load_memory(&p, p_end, memory, error_buf, error_buf_size))
+ return false;
+ }
+
+ bh_assert(p == p_end);
+ LOG_VERBOSE("Load memory section success.\n");
+ return true;
+}
+
+static bool
+load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 global_count, i;
+ uint64 total_size;
+ WASMGlobal *global;
+ uint8 mutable;
+
+ read_leb_uint32(p, p_end, global_count);
+
+ if (global_count) {
+ module->global_count = global_count;
+ total_size = sizeof(WASMGlobal) * (uint64)global_count;
+ if (!(module->globals =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ global = module->globals;
+
+ for (i = 0; i < global_count; i++, global++) {
+ CHECK_BUF(p, p_end, 2);
+ global->type = read_uint8(p);
+ mutable = read_uint8(p);
+ bh_assert(mutable < 2);
+ global->is_mutable = mutable ? true : false;
+
+ /* initialize expression */
+ if (!load_init_expr(&p, p_end, &(global->init_expr), global->type,
+ error_buf, error_buf_size))
+ return false;
+
+ if (INIT_EXPR_TYPE_GET_GLOBAL == global->init_expr.init_expr_type) {
+ /**
+ * Currently, constant expressions occurring as initializers
+ * of globals are further constrained in that contained
+ * global.get instructions are
+ * only allowed to refer to imported globals.
+ */
+ uint32 target_global_index = global->init_expr.u.global_index;
+ bh_assert(target_global_index < module->import_global_count);
+ (void)target_global_index;
+ }
+ else if (INIT_EXPR_TYPE_FUNCREF_CONST
+ == global->init_expr.init_expr_type) {
+ bh_assert(global->init_expr.u.ref_index
+ < module->import_function_count
+ + module->function_count);
+ }
+ }
+ }
+
+ bh_assert(p == p_end);
+ LOG_VERBOSE("Load global section success.\n");
+ return true;
+}
+
+static bool
+load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
+ bool is_load_from_file_buf, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 export_count, i, j, index;
+ uint64 total_size;
+ uint32 str_len;
+ WASMExport *export;
+ const char *name;
+
+ read_leb_uint32(p, p_end, export_count);
+
+ if (export_count) {
+ module->export_count = export_count;
+ total_size = sizeof(WASMExport) * (uint64)export_count;
+ if (!(module->exports =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ export = module->exports;
+ for (i = 0; i < export_count; i++, export ++) {
+ read_leb_uint32(p, p_end, str_len);
+ CHECK_BUF(p, p_end, str_len);
+
+ for (j = 0; j < i; j++) {
+ name = module->exports[j].name;
+ bh_assert(!(strlen(name) == str_len
+ && memcmp(name, p, str_len) == 0));
+ }
+
+ if (!(export->name = const_str_list_insert(
+ p, str_len, module, is_load_from_file_buf, error_buf,
+ error_buf_size))) {
+ return false;
+ }
+
+ p += str_len;
+ CHECK_BUF(p, p_end, 1);
+ export->kind = read_uint8(p);
+ read_leb_uint32(p, p_end, index);
+ export->index = index;
+
+ switch (export->kind) {
+ /* function index */
+ case EXPORT_KIND_FUNC:
+ bh_assert(index < module->function_count
+ + module->import_function_count);
+ break;
+ /* table index */
+ case EXPORT_KIND_TABLE:
+ bh_assert(index < module->table_count
+ + module->import_table_count);
+ break;
+ /* memory index */
+ case EXPORT_KIND_MEMORY:
+ bh_assert(index < module->memory_count
+ + module->import_memory_count);
+ break;
+ /* global index */
+ case EXPORT_KIND_GLOBAL:
+ bh_assert(index < module->global_count
+ + module->import_global_count);
+ break;
+ default:
+ bh_assert(0);
+ break;
+ }
+ }
+ }
+
+ bh_assert(p == p_end);
+ LOG_VERBOSE("Load export section success.\n");
+ (void)name;
+ return true;
+}
+
+static bool
+check_table_index(const WASMModule *module, uint32 table_index, char *error_buf,
+ uint32 error_buf_size)
+{
+#if WASM_ENABLE_REF_TYPES == 0
+ if (table_index != 0) {
+ return false;
+ }
+#endif
+
+ if (table_index >= module->import_table_count + module->table_count) {
+ return false;
+ }
+ return true;
+}
+
+static bool
+load_table_index(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module,
+ uint32 *p_table_index, char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end;
+ uint32 table_index;
+
+ read_leb_uint32(p, p_end, table_index);
+ if (!check_table_index(module, table_index, error_buf, error_buf_size)) {
+ return false;
+ }
+
+ *p_table_index = table_index;
+ *p_buf = p;
+ return true;
+}
+
+#if WASM_ENABLE_REF_TYPES != 0
+static bool
+load_elem_type(const uint8 **p_buf, const uint8 *buf_end, uint32 *p_elem_type,
+ bool elemkind_zero, char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end;
+ uint8 elem_type;
+
+ CHECK_BUF(p, p_end, 1);
+ elem_type = read_uint8(p);
+ if ((elemkind_zero && elem_type != 0)
+ || (!elemkind_zero && elem_type != VALUE_TYPE_FUNCREF
+ && elem_type != VALUE_TYPE_EXTERNREF)) {
+ set_error_buf(error_buf, error_buf_size, "invalid reference type");
+ return false;
+ }
+
+ if (elemkind_zero)
+ *p_elem_type = VALUE_TYPE_FUNCREF;
+ else
+ *p_elem_type = elem_type;
+ *p_buf = p;
+
+ (void)p_end;
+ return true;
+}
+#endif /* WASM_ENABLE_REF_TYPES != 0*/
+
+static bool
+load_func_index_vec(const uint8 **p_buf, const uint8 *buf_end,
+ WASMModule *module, WASMTableSeg *table_segment,
+ bool use_init_expr, char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = *p_buf, *p_end = buf_end;
+ uint32 function_count, function_index = 0, i;
+ uint64 total_size;
+
+ read_leb_uint32(p, p_end, function_count);
+ table_segment->function_count = function_count;
+ total_size = sizeof(uint32) * (uint64)function_count;
+ if (total_size > 0
+ && !(table_segment->func_indexes = (uint32 *)loader_malloc(
+ total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ for (i = 0; i < function_count; i++) {
+ InitializerExpression init_expr = { 0 };
+
+#if WASM_ENABLE_REF_TYPES != 0
+ if (!use_init_expr) {
+ read_leb_uint32(p, p_end, function_index);
+ }
+ else {
+ if (!load_init_expr(&p, p_end, &init_expr, table_segment->elem_type,
+ error_buf, error_buf_size))
+ return false;
+
+ function_index = init_expr.u.ref_index;
+ }
+#else
+ read_leb_uint32(p, p_end, function_index);
+#endif
+
+ /* since we are using -1 to indicate ref.null */
+ if (init_expr.init_expr_type != INIT_EXPR_TYPE_REFNULL_CONST
+ && !check_function_index(module, function_index, error_buf,
+ error_buf_size)) {
+ return false;
+ }
+ table_segment->func_indexes[i] = function_index;
+ }
+
+ *p_buf = p;
+ return true;
+}
+
+static bool
+load_table_segment_section(const uint8 *buf, const uint8 *buf_end,
+ WASMModule *module, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 table_segment_count, i, table_index, function_count;
+ uint64 total_size;
+ WASMTableSeg *table_segment;
+
+ read_leb_uint32(p, p_end, table_segment_count);
+
+ if (table_segment_count) {
+ module->table_seg_count = table_segment_count;
+ total_size = sizeof(WASMTableSeg) * (uint64)table_segment_count;
+ if (!(module->table_segments =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ table_segment = module->table_segments;
+ for (i = 0; i < table_segment_count; i++, table_segment++) {
+ bh_assert(p < p_end);
+
+#if WASM_ENABLE_REF_TYPES != 0
+ read_leb_uint32(p, p_end, table_segment->mode);
+ /* last three bits */
+ table_segment->mode = table_segment->mode & 0x07;
+ switch (table_segment->mode) {
+ /* elemkind/elemtype + active */
+ case 0:
+ case 4:
+ table_segment->elem_type = VALUE_TYPE_FUNCREF;
+ table_segment->table_index = 0;
+
+ if (!check_table_index(module, table_segment->table_index,
+ error_buf, error_buf_size))
+ return false;
+
+ if (!load_init_expr(&p, p_end, &table_segment->base_offset,
+ VALUE_TYPE_I32, error_buf,
+ error_buf_size))
+ return false;
+
+ if (!load_func_index_vec(&p, p_end, module, table_segment,
+ table_segment->mode == 0 ? false
+ : true,
+ error_buf, error_buf_size))
+ return false;
+ break;
+ /* elemkind + passive/declarative */
+ case 1:
+ case 3:
+ if (!load_elem_type(&p, p_end, &table_segment->elem_type,
+ true, error_buf, error_buf_size))
+ return false;
+ if (!load_func_index_vec(&p, p_end, module, table_segment,
+ false, error_buf, error_buf_size))
+ return false;
+ break;
+ /* elemkind/elemtype + table_idx + active */
+ case 2:
+ case 6:
+ if (!load_table_index(&p, p_end, module,
+ &table_segment->table_index,
+ error_buf, error_buf_size))
+ return false;
+ if (!load_init_expr(&p, p_end, &table_segment->base_offset,
+ VALUE_TYPE_I32, error_buf,
+ error_buf_size))
+ return false;
+ if (!load_elem_type(&p, p_end, &table_segment->elem_type,
+ table_segment->mode == 2 ? true : false,
+ error_buf, error_buf_size))
+ return false;
+ if (!load_func_index_vec(&p, p_end, module, table_segment,
+ table_segment->mode == 2 ? false
+ : true,
+ error_buf, error_buf_size))
+ return false;
+ break;
+ case 5:
+ case 7:
+ if (!load_elem_type(&p, p_end, &table_segment->elem_type,
+ false, error_buf, error_buf_size))
+ return false;
+ if (!load_func_index_vec(&p, p_end, module, table_segment,
+ true, error_buf, error_buf_size))
+ return false;
+ break;
+ default:
+ return false;
+ }
+#else
+ /*
+ * like: 00 41 05 0b 04 00 01 00 01
+ * for: (elem 0 (offset (i32.const 5)) $f1 $f2 $f1 $f2)
+ */
+ if (!load_table_index(&p, p_end, module,
+ &table_segment->table_index, error_buf,
+ error_buf_size))
+ return false;
+ if (!load_init_expr(&p, p_end, &table_segment->base_offset,
+ VALUE_TYPE_I32, error_buf, error_buf_size))
+ return false;
+ if (!load_func_index_vec(&p, p_end, module, table_segment, false,
+ error_buf, error_buf_size))
+ return false;
+#endif /* WASM_ENABLE_REF_TYPES != 0 */
+ }
+ }
+
+ (void)table_index;
+ (void)function_count;
+ bh_assert(p == p_end);
+ LOG_VERBOSE("Load table segment section success.\n");
+ return true;
+}
+
+static bool
+load_data_segment_section(const uint8 *buf, const uint8 *buf_end,
+ WASMModule *module, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 data_seg_count, i, mem_index, data_seg_len;
+ uint64 total_size;
+ WASMDataSeg *dataseg;
+ InitializerExpression init_expr;
+#if WASM_ENABLE_BULK_MEMORY != 0
+ bool is_passive = false;
+ uint32 mem_flag;
+#endif
+
+ read_leb_uint32(p, p_end, data_seg_count);
+
+#if WASM_ENABLE_BULK_MEMORY != 0
+ bh_assert(module->data_seg_count1 == 0
+ || data_seg_count == module->data_seg_count1);
+#endif
+
+ if (data_seg_count) {
+ module->data_seg_count = data_seg_count;
+ total_size = sizeof(WASMDataSeg *) * (uint64)data_seg_count;
+ if (!(module->data_segments =
+ loader_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ for (i = 0; i < data_seg_count; i++) {
+ read_leb_uint32(p, p_end, mem_index);
+#if WASM_ENABLE_BULK_MEMORY != 0
+ is_passive = false;
+ mem_flag = mem_index & 0x03;
+ switch (mem_flag) {
+ case 0x01:
+ is_passive = true;
+ break;
+ case 0x00:
+ /* no memory index, treat index as 0 */
+ mem_index = 0;
+ goto check_mem_index;
+ case 0x02:
+ /* read following memory index */
+ read_leb_uint32(p, p_end, mem_index);
+ check_mem_index:
+ bh_assert(mem_index < module->import_memory_count
+ + module->memory_count);
+ break;
+ case 0x03:
+ default:
+ bh_assert(0);
+ break;
+ }
+#else
+ bh_assert(mem_index
+ < module->import_memory_count + module->memory_count);
+#endif /* WASM_ENABLE_BULK_MEMORY */
+
+#if WASM_ENABLE_BULK_MEMORY != 0
+ if (!is_passive)
+#endif
+ if (!load_init_expr(&p, p_end, &init_expr, VALUE_TYPE_I32,
+ error_buf, error_buf_size))
+ return false;
+
+ read_leb_uint32(p, p_end, data_seg_len);
+
+ if (!(dataseg = module->data_segments[i] = loader_malloc(
+ sizeof(WASMDataSeg), error_buf, error_buf_size))) {
+ return false;
+ }
+
+#if WASM_ENABLE_BULK_MEMORY != 0
+ dataseg->is_passive = is_passive;
+ if (!is_passive)
+#endif
+ {
+ bh_memcpy_s(&dataseg->base_offset,
+ sizeof(InitializerExpression), &init_expr,
+ sizeof(InitializerExpression));
+
+ dataseg->memory_index = mem_index;
+ }
+
+ dataseg->data_length = data_seg_len;
+ CHECK_BUF(p, p_end, data_seg_len);
+ dataseg->data = (uint8 *)p;
+ p += data_seg_len;
+ }
+ }
+
+ bh_assert(p == p_end);
+ LOG_VERBOSE("Load data segment section success.\n");
+ return true;
+}
+
+#if WASM_ENABLE_BULK_MEMORY != 0
+static bool
+load_datacount_section(const uint8 *buf, const uint8 *buf_end,
+ WASMModule *module, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 data_seg_count1 = 0;
+
+ read_leb_uint32(p, p_end, data_seg_count1);
+ module->data_seg_count1 = data_seg_count1;
+
+ bh_assert(p == p_end);
+ LOG_VERBOSE("Load datacount section success.\n");
+ return true;
+}
+#endif
+
+static bool
+load_code_section(const uint8 *buf, const uint8 *buf_end, const uint8 *buf_func,
+ const uint8 *buf_func_end, WASMModule *module,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ const uint8 *p_func = buf_func;
+ uint32 func_count = 0, code_count;
+
+ /* code has been loaded in function section, so pass it here, just check
+ * whether function and code section have inconsistent lengths */
+ read_leb_uint32(p, p_end, code_count);
+
+ if (buf_func)
+ read_leb_uint32(p_func, buf_func_end, func_count);
+
+ bh_assert(func_count == code_count);
+ LOG_VERBOSE("Load code segment section success.\n");
+ (void)code_count;
+ (void)func_count;
+ return true;
+}
+
+static bool
+load_start_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
+ char *error_buf, uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ WASMType *type;
+ uint32 start_function;
+
+ read_leb_uint32(p, p_end, start_function);
+
+ bh_assert(start_function
+ < module->function_count + module->import_function_count);
+
+ if (start_function < module->import_function_count)
+ type = module->import_functions[start_function].u.function.func_type;
+ else
+ type = module->functions[start_function - module->import_function_count]
+ ->func_type;
+
+ bh_assert(type->param_count == 0 && type->result_count == 0);
+
+ module->start_function = start_function;
+
+ bh_assert(p == p_end);
+ LOG_VERBOSE("Load start section success.\n");
+ (void)type;
+ return true;
+}
+
+#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
+static bool
+handle_name_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
+ bool is_load_from_file_buf, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 name_type, subsection_size;
+ uint32 previous_name_type = 0;
+ uint32 num_func_name;
+ uint32 func_index;
+ uint32 previous_func_index = ~0U;
+ uint32 func_name_len;
+ uint32 name_index;
+ int i = 0;
+
+ bh_assert(p < p_end);
+
+ while (p < p_end) {
+ read_leb_uint32(p, p_end, name_type);
+ if (i != 0) {
+ bh_assert(name_type > previous_name_type);
+ }
+ previous_name_type = name_type;
+ read_leb_uint32(p, p_end, subsection_size);
+ CHECK_BUF(p, p_end, subsection_size);
+ switch (name_type) {
+ case SUB_SECTION_TYPE_FUNC:
+ if (subsection_size) {
+ read_leb_uint32(p, p_end, num_func_name);
+ for (name_index = 0; name_index < num_func_name;
+ name_index++) {
+ read_leb_uint32(p, p_end, func_index);
+ bh_assert(func_index > previous_func_index);
+ previous_func_index = func_index;
+ read_leb_uint32(p, p_end, func_name_len);
+ CHECK_BUF(p, p_end, func_name_len);
+ /* Skip the import functions */
+ if (func_index >= module->import_function_count) {
+ func_index -= module->import_function_count;
+ bh_assert(func_index < module->function_count);
+ if (!(module->functions[func_index]->field_name =
+ const_str_list_insert(
+ p, func_name_len, module,
+ is_load_from_file_buf, error_buf,
+ error_buf_size))) {
+ return false;
+ }
+ }
+ p += func_name_len;
+ }
+ }
+ break;
+ case SUB_SECTION_TYPE_MODULE: /* TODO: Parse for module subsection
+ */
+ case SUB_SECTION_TYPE_LOCAL: /* TODO: Parse for local subsection */
+ default:
+ p = p + subsection_size;
+ break;
+ }
+ i++;
+ }
+
+ (void)previous_name_type;
+ (void)previous_func_index;
+ return true;
+}
+#endif
+
+static bool
+load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
+ bool is_load_from_file_buf, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 name_len;
+
+ bh_assert(p < p_end);
+
+ read_leb_uint32(p, p_end, name_len);
+
+ bh_assert(name_len > 0 && p + name_len <= p_end);
+
+#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
+ if (memcmp(p, "name", 4) == 0) {
+ p += name_len;
+ handle_name_section(p, p_end, module, is_load_from_file_buf, error_buf,
+ error_buf_size);
+ }
+#endif
+ LOG_VERBOSE("Load custom section success.\n");
+ (void)name_len;
+ return true;
+}
+
+static void
+calculate_global_data_offset(WASMModule *module)
+{
+ uint32 i, data_offset;
+
+ data_offset = 0;
+ for (i = 0; i < module->import_global_count; i++) {
+ WASMGlobalImport *import_global =
+ &((module->import_globals + i)->u.global);
+#if WASM_ENABLE_FAST_JIT != 0
+ import_global->data_offset = data_offset;
+#endif
+ data_offset += wasm_value_type_size(import_global->type);
+ }
+
+ for (i = 0; i < module->global_count; i++) {
+ WASMGlobal *global = module->globals + i;
+#if WASM_ENABLE_FAST_JIT != 0
+ global->data_offset = data_offset;
+#endif
+ data_offset += wasm_value_type_size(global->type);
+ }
+
+ module->global_data_size = data_offset;
+}
+
+#if WASM_ENABLE_FAST_JIT != 0
+static bool
+init_fast_jit_functions(WASMModule *module, char *error_buf,
+ uint32 error_buf_size)
+{
+#if WASM_ENABLE_LAZY_JIT != 0
+ JitGlobals *jit_globals = jit_compiler_get_jit_globals();
+#endif
+ uint32 i;
+
+ if (!module->function_count)
+ return true;
+
+ if (!(module->fast_jit_func_ptrs =
+ loader_malloc(sizeof(void *) * module->function_count, error_buf,
+ error_buf_size))) {
+ return false;
+ }
+
+#if WASM_ENABLE_LAZY_JIT != 0
+ for (i = 0; i < module->function_count; i++) {
+ module->fast_jit_func_ptrs[i] =
+ jit_globals->compile_fast_jit_and_then_call;
+ }
+#endif
+
+ for (i = 0; i < WASM_ORC_JIT_BACKEND_THREAD_NUM; i++) {
+ if (os_mutex_init(&module->fast_jit_thread_locks[i]) != 0) {
+ set_error_buf(error_buf, error_buf_size,
+ "init fast jit thread lock failed");
+ return false;
+ }
+ module->fast_jit_thread_locks_inited[i] = true;
+ }
+
+ return true;
+}
+#endif /* end of WASM_ENABLE_FAST_JIT != 0 */
+
+#if WASM_ENABLE_JIT != 0
+static bool
+init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
+ uint32 error_buf_size)
+{
+ LLVMJITOptions llvm_jit_options = wasm_runtime_get_llvm_jit_options();
+ AOTCompOption option = { 0 };
+ char *aot_last_error;
+ uint64 size;
+
+ if (module->function_count == 0)
+ return true;
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LLVM_JIT != 0
+ if (os_mutex_init(&module->tierup_wait_lock) != 0) {
+ set_error_buf(error_buf, error_buf_size, "init jit tierup lock failed");
+ return false;
+ }
+ if (os_cond_init(&module->tierup_wait_cond) != 0) {
+ set_error_buf(error_buf, error_buf_size, "init jit tierup cond failed");
+ os_mutex_destroy(&module->tierup_wait_lock);
+ return false;
+ }
+ module->tierup_wait_lock_inited = true;
+#endif
+
+ size = sizeof(void *) * (uint64)module->function_count
+ + sizeof(bool) * (uint64)module->function_count;
+ if (!(module->func_ptrs = loader_malloc(size, error_buf, error_buf_size))) {
+ return false;
+ }
+ module->func_ptrs_compiled =
+ (bool *)((uint8 *)module->func_ptrs
+ + sizeof(void *) * module->function_count);
+
+ module->comp_data = aot_create_comp_data(module);
+ if (!module->comp_data) {
+ aot_last_error = aot_get_last_error();
+ bh_assert(aot_last_error != NULL);
+ set_error_buf(error_buf, error_buf_size, aot_last_error);
+ return false;
+ }
+
+ option.is_jit_mode = true;
+ option.opt_level = llvm_jit_options.opt_level;
+ option.size_level = llvm_jit_options.size_level;
+
+#if WASM_ENABLE_BULK_MEMORY != 0
+ option.enable_bulk_memory = true;
+#endif
+#if WASM_ENABLE_THREAD_MGR != 0
+ option.enable_thread_mgr = true;
+#endif
+#if WASM_ENABLE_TAIL_CALL != 0
+ option.enable_tail_call = true;
+#endif
+#if WASM_ENABLE_SIMD != 0
+ option.enable_simd = true;
+#endif
+#if WASM_ENABLE_REF_TYPES != 0
+ option.enable_ref_types = true;
+#endif
+ option.enable_aux_stack_check = true;
+#if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0)
+ option.enable_aux_stack_frame = true;
+#endif
+#if WASM_ENABLE_MEMORY_PROFILING != 0
+ option.enable_stack_estimation = true;
+#endif
+
+ module->comp_ctx = aot_create_comp_context(module->comp_data, &option);
+ if (!module->comp_ctx) {
+ aot_last_error = aot_get_last_error();
+ bh_assert(aot_last_error != NULL);
+ set_error_buf(error_buf, error_buf_size, aot_last_error);
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+init_llvm_jit_functions_stage2(WASMModule *module, char *error_buf,
+ uint32 error_buf_size)
+{
+ char *aot_last_error;
+ uint32 i;
+
+ if (module->function_count == 0)
+ return true;
+
+ if (!aot_compile_wasm(module->comp_ctx)) {
+ aot_last_error = aot_get_last_error();
+ bh_assert(aot_last_error != NULL);
+ set_error_buf(error_buf, error_buf_size, aot_last_error);
+ return false;
+ }
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
+ if (module->orcjit_stop_compiling)
+ return false;
+#endif
+
+ bh_print_time("Begin to lookup llvm jit functions");
+
+ for (i = 0; i < module->function_count; i++) {
+ LLVMOrcJITTargetAddress func_addr = 0;
+ LLVMErrorRef error;
+ char func_name[48];
+
+ snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i);
+ error = LLVMOrcLLLazyJITLookup(module->comp_ctx->orc_jit, &func_addr,
+ func_name);
+ if (error != LLVMErrorSuccess) {
+ char *err_msg = LLVMGetErrorMessage(error);
+ char buf[96];
+ snprintf(buf, sizeof(buf),
+ "failed to compile llvm jit function: %s", err_msg);
+ set_error_buf(error_buf, error_buf_size, buf);
+ LLVMDisposeErrorMessage(err_msg);
+ return false;
+ }
+
+ /**
+ * No need to lock the func_ptr[func_idx] here as it is basic
+ * data type, the load/store for it can be finished by one cpu
+ * instruction, and there can be only one cpu instruction
+ * loading/storing at the same time.
+ */
+ module->func_ptrs[i] = (void *)func_addr;
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
+ module->functions[i]->llvm_jit_func_ptr = (void *)func_addr;
+
+ if (module->orcjit_stop_compiling)
+ return false;
+#endif
+ }
+
+ bh_print_time("End lookup llvm jit functions");
+
+ return true;
+}
+#endif /* end of WASM_ENABLE_JIT != 0 */
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0
+static void *
+init_llvm_jit_functions_stage2_callback(void *arg)
+{
+ WASMModule *module = (WASMModule *)arg;
+ char error_buf[128];
+ uint32 error_buf_size = (uint32)sizeof(error_buf);
+
+ if (!init_llvm_jit_functions_stage2(module, error_buf, error_buf_size)) {
+ module->orcjit_stop_compiling = true;
+ return NULL;
+ }
+
+ os_mutex_lock(&module->tierup_wait_lock);
+ module->llvm_jit_inited = true;
+ os_cond_broadcast(&module->tierup_wait_cond);
+ os_mutex_unlock(&module->tierup_wait_lock);
+
+ return NULL;
+}
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0
+/* The callback function to compile jit functions */
+static void *
+orcjit_thread_callback(void *arg)
+{
+ OrcJitThreadArg *thread_arg = (OrcJitThreadArg *)arg;
+#if WASM_ENABLE_JIT != 0
+ AOTCompContext *comp_ctx = thread_arg->comp_ctx;
+#endif
+ WASMModule *module = thread_arg->module;
+ uint32 group_idx = thread_arg->group_idx;
+ uint32 group_stride = WASM_ORC_JIT_BACKEND_THREAD_NUM;
+ uint32 func_count = module->function_count;
+ uint32 i;
+
+#if WASM_ENABLE_FAST_JIT != 0
+ /* Compile fast jit funcitons of this group */
+ for (i = group_idx; i < func_count; i += group_stride) {
+ if (!jit_compiler_compile(module, i + module->import_function_count)) {
+ os_printf("failed to compile fast jit function %u\n", i);
+ break;
+ }
+
+ if (module->orcjit_stop_compiling) {
+ return NULL;
+ }
+ }
+#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
+ os_mutex_lock(&module->tierup_wait_lock);
+ module->fast_jit_ready_groups++;
+ os_mutex_unlock(&module->tierup_wait_lock);
+#endif
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0
+ /* For JIT tier-up, set each llvm jit func to call_to_fast_jit */
+ for (i = group_idx; i < func_count;
+ i += group_stride * WASM_ORC_JIT_COMPILE_THREAD_NUM) {
+ uint32 j;
+
+ for (j = 0; j < WASM_ORC_JIT_COMPILE_THREAD_NUM; j++) {
+ if (i + j * group_stride < func_count) {
+ if (!jit_compiler_set_call_to_fast_jit(
+ module,
+ i + j * group_stride + module->import_function_count)) {
+ os_printf(
+ "failed to compile call_to_fast_jit for func %u\n",
+ i + j * group_stride + module->import_function_count);
+ module->orcjit_stop_compiling = true;
+ return NULL;
+ }
+ }
+ if (module->orcjit_stop_compiling) {
+ return NULL;
+ }
+ }
+ }
+
+ /* Wait until init_llvm_jit_functions_stage2 finishes and all
+ fast jit functions are compiled */
+ os_mutex_lock(&module->tierup_wait_lock);
+ while (!(module->llvm_jit_inited && module->enable_llvm_jit_compilation
+ && module->fast_jit_ready_groups >= group_stride)) {
+ os_cond_reltimedwait(&module->tierup_wait_cond,
+ &module->tierup_wait_lock, 10000);
+ if (module->orcjit_stop_compiling) {
+ /* init_llvm_jit_functions_stage2 failed */
+ os_mutex_unlock(&module->tierup_wait_lock);
+ return NULL;
+ }
+ }
+ os_mutex_unlock(&module->tierup_wait_lock);
+#endif
+
+#if WASM_ENABLE_JIT != 0
+ /* Compile llvm jit functions of this group */
+ for (i = group_idx; i < func_count;
+ i += group_stride * WASM_ORC_JIT_COMPILE_THREAD_NUM) {
+ LLVMOrcJITTargetAddress func_addr = 0;
+ LLVMErrorRef error;
+ char func_name[48];
+ typedef void (*F)(void);
+ union {
+ F f;
+ void *v;
+ } u;
+ uint32 j;
+
+ snprintf(func_name, sizeof(func_name), "%s%d%s", AOT_FUNC_PREFIX, i,
+ "_wrapper");
+ LOG_DEBUG("compile llvm jit func %s", func_name);
+ error =
+ LLVMOrcLLLazyJITLookup(comp_ctx->orc_jit, &func_addr, func_name);
+ if (error != LLVMErrorSuccess) {
+ char *err_msg = LLVMGetErrorMessage(error);
+ os_printf("failed to compile llvm jit function %u: %s", i, err_msg);
+ LLVMDisposeErrorMessage(err_msg);
+ break;
+ }
+
+ /* Call the jit wrapper function to trigger its compilation, so as
+ to compile the actual jit functions, since we add the latter to
+ function list in the PartitionFunction callback */
+ u.v = (void *)func_addr;
+ u.f();
+
+ for (j = 0; j < WASM_ORC_JIT_COMPILE_THREAD_NUM; j++) {
+ if (i + j * group_stride < func_count) {
+ module->func_ptrs_compiled[i + j * group_stride] = true;
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
+ snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX,
+ i + j * group_stride);
+ error = LLVMOrcLLLazyJITLookup(comp_ctx->orc_jit, &func_addr,
+ func_name);
+ if (error != LLVMErrorSuccess) {
+ char *err_msg = LLVMGetErrorMessage(error);
+ os_printf("failed to compile llvm jit function %u: %s", i,
+ err_msg);
+ LLVMDisposeErrorMessage(err_msg);
+ /* Ignore current llvm jit func, as its func ptr is
+ previous set to call_to_fast_jit, which also works */
+ continue;
+ }
+
+ jit_compiler_set_llvm_jit_func_ptr(
+ module,
+ i + j * group_stride + module->import_function_count,
+ (void *)func_addr);
+
+ /* Try to switch to call this llvm jit funtion instead of
+ fast jit function from fast jit jitted code */
+ jit_compiler_set_call_to_llvm_jit(
+ module,
+ i + j * group_stride + module->import_function_count);
+#endif
+ }
+ }
+
+ if (module->orcjit_stop_compiling) {
+ break;
+ }
+ }
+#endif
+
+ return NULL;
+}
+
+static void
+orcjit_stop_compile_threads(WASMModule *module)
+{
+ uint32 i, thread_num = (uint32)(sizeof(module->orcjit_thread_args)
+ / sizeof(OrcJitThreadArg));
+
+ module->orcjit_stop_compiling = true;
+ for (i = 0; i < thread_num; i++) {
+ if (module->orcjit_threads[i])
+ os_thread_join(module->orcjit_threads[i], NULL);
+ }
+}
+
+static bool
+compile_jit_functions(WASMModule *module, char *error_buf,
+ uint32 error_buf_size)
+{
+ uint32 thread_num =
+ (uint32)(sizeof(module->orcjit_thread_args) / sizeof(OrcJitThreadArg));
+ uint32 i, j;
+
+ bh_print_time("Begin to compile jit functions");
+
+ /* Create threads to compile the jit functions */
+ for (i = 0; i < thread_num && i < module->function_count; i++) {
+#if WASM_ENABLE_JIT != 0
+ module->orcjit_thread_args[i].comp_ctx = module->comp_ctx;
+#endif
+ module->orcjit_thread_args[i].module = module;
+ module->orcjit_thread_args[i].group_idx = i;
+
+ if (os_thread_create(&module->orcjit_threads[i], orcjit_thread_callback,
+ (void *)&module->orcjit_thread_args[i],
+ APP_THREAD_STACK_SIZE_DEFAULT)
+ != 0) {
+ set_error_buf(error_buf, error_buf_size,
+ "create orcjit compile thread failed");
+ /* Terminate the threads created */
+ module->orcjit_stop_compiling = true;
+ for (j = 0; j < i; j++) {
+ os_thread_join(module->orcjit_threads[j], NULL);
+ }
+ return false;
+ }
+ }
+
+#if WASM_ENABLE_LAZY_JIT == 0
+ /* Wait until all jit functions are compiled for eager mode */
+ for (i = 0; i < thread_num; i++) {
+ if (module->orcjit_threads[i])
+ os_thread_join(module->orcjit_threads[i], NULL);
+ }
+
+#if WASM_ENABLE_FAST_JIT != 0
+ /* Ensure all the fast-jit functions are compiled */
+ for (i = 0; i < module->function_count; i++) {
+ if (!jit_compiler_is_compiled(module,
+ i + module->import_function_count)) {
+ set_error_buf(error_buf, error_buf_size,
+ "failed to compile fast jit function");
+ return false;
+ }
+ }
+#endif
+
+#if WASM_ENABLE_JIT != 0
+ /* Ensure all the llvm-jit functions are compiled */
+ for (i = 0; i < module->function_count; i++) {
+ if (!module->func_ptrs_compiled[i]) {
+ set_error_buf(error_buf, error_buf_size,
+ "failed to compile llvm jit function");
+ return false;
+ }
+ }
+#endif
+#endif /* end of WASM_ENABLE_LAZY_JIT == 0 */
+
+ bh_print_time("End compile jit functions");
+
+ return true;
+}
+#endif /* end of WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 */
+
+#if WASM_ENABLE_REF_TYPES != 0
+static bool
+get_table_elem_type(const WASMModule *module, uint32 table_idx,
+ uint8 *p_elem_type, char *error_buf, uint32 error_buf_size)
+{
+ if (!check_table_index(module, table_idx, error_buf, error_buf_size)) {
+ return false;
+ }
+
+ if (p_elem_type) {
+ if (table_idx < module->import_table_count)
+ *p_elem_type = module->import_tables[table_idx].u.table.elem_type;
+ else
+ *p_elem_type =
+ module->tables[module->import_table_count + table_idx]
+ .elem_type;
+ }
+ return true;
+}
+
+static bool
+get_table_seg_elem_type(const WASMModule *module, uint32 table_seg_idx,
+ uint8 *p_elem_type, char *error_buf,
+ uint32 error_buf_size)
+{
+ if (table_seg_idx >= module->table_seg_count) {
+ return false;
+ }
+
+ if (p_elem_type) {
+ *p_elem_type = module->table_segments[table_seg_idx].elem_type;
+ }
+ return true;
+}
+#endif
+
+static bool
+wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
+ uint32 cur_func_idx, char *error_buf,
+ uint32 error_buf_size);
+
+#if WASM_ENABLE_FAST_INTERP != 0 && WASM_ENABLE_LABELS_AS_VALUES != 0
+void **
+wasm_interp_get_handle_table();
+
+static void **handle_table;
+#endif
+
+static bool
+load_from_sections(WASMModule *module, WASMSection *sections,
+ bool is_load_from_file_buf, char *error_buf,
+ uint32 error_buf_size)
+{
+ WASMExport *export;
+ WASMSection *section = sections;
+ const uint8 *buf, *buf_end, *buf_code = NULL, *buf_code_end = NULL,
+ *buf_func = NULL, *buf_func_end = NULL;
+ WASMGlobal *aux_data_end_global = NULL, *aux_heap_base_global = NULL;
+ WASMGlobal *aux_stack_top_global = NULL, *global;
+ uint32 aux_data_end = (uint32)-1, aux_heap_base = (uint32)-1;
+ uint32 aux_stack_top = (uint32)-1, global_index, func_index, i;
+ uint32 aux_data_end_global_index = (uint32)-1;
+ uint32 aux_heap_base_global_index = (uint32)-1;
+ WASMType *func_type;
+
+ /* Find code and function sections if have */
+ while (section) {
+ if (section->section_type == SECTION_TYPE_CODE) {
+ buf_code = section->section_body;
+ buf_code_end = buf_code + section->section_body_size;
+ }
+ else if (section->section_type == SECTION_TYPE_FUNC) {
+ buf_func = section->section_body;
+ buf_func_end = buf_func + section->section_body_size;
+ }
+ section = section->next;
+ }
+
+ section = sections;
+ while (section) {
+ buf = section->section_body;
+ buf_end = buf + section->section_body_size;
+ LOG_DEBUG("load section, type: %d", section->section_type);
+ switch (section->section_type) {
+ case SECTION_TYPE_USER:
+ /* unsupported user section, ignore it. */
+ if (!load_user_section(buf, buf_end, module,
+ is_load_from_file_buf, error_buf,
+ error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_TYPE:
+ if (!load_type_section(buf, buf_end, module, error_buf,
+ error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_IMPORT:
+ if (!load_import_section(buf, buf_end, module,
+ is_load_from_file_buf, error_buf,
+ error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_FUNC:
+ if (!load_function_section(buf, buf_end, buf_code, buf_code_end,
+ module, error_buf, error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_TABLE:
+ if (!load_table_section(buf, buf_end, module, error_buf,
+ error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_MEMORY:
+ if (!load_memory_section(buf, buf_end, module, error_buf,
+ error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_GLOBAL:
+ if (!load_global_section(buf, buf_end, module, error_buf,
+ error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_EXPORT:
+ if (!load_export_section(buf, buf_end, module,
+ is_load_from_file_buf, error_buf,
+ error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_START:
+ if (!load_start_section(buf, buf_end, module, error_buf,
+ error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_ELEM:
+ if (!load_table_segment_section(buf, buf_end, module, error_buf,
+ error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_CODE:
+ if (!load_code_section(buf, buf_end, buf_func, buf_func_end,
+ module, error_buf, error_buf_size))
+ return false;
+ break;
+ case SECTION_TYPE_DATA:
+ if (!load_data_segment_section(buf, buf_end, module, error_buf,
+ error_buf_size))
+ return false;
+ break;
+#if WASM_ENABLE_BULK_MEMORY != 0
+ case SECTION_TYPE_DATACOUNT:
+ if (!load_datacount_section(buf, buf_end, module, error_buf,
+ error_buf_size))
+ return false;
+ break;
+#endif
+ default:
+ set_error_buf(error_buf, error_buf_size, "invalid section id");
+ return false;
+ }
+
+ section = section->next;
+ }
+
+ module->aux_data_end_global_index = (uint32)-1;
+ module->aux_heap_base_global_index = (uint32)-1;
+ module->aux_stack_top_global_index = (uint32)-1;
+
+ /* Resolve auxiliary data/stack/heap info and reset memory info */
+ export = module->exports;
+ for (i = 0; i < module->export_count; i++, export ++) {
+ if (export->kind == EXPORT_KIND_GLOBAL) {
+ if (!strcmp(export->name, "__heap_base")) {
+ global_index = export->index - module->import_global_count;
+ global = module->globals + global_index;
+ if (global->type == VALUE_TYPE_I32 && !global->is_mutable
+ && global->init_expr.init_expr_type
+ == INIT_EXPR_TYPE_I32_CONST) {
+ aux_heap_base_global = global;
+ aux_heap_base = global->init_expr.u.i32;
+ aux_heap_base_global_index = export->index;
+ LOG_VERBOSE("Found aux __heap_base global, value: %d",
+ aux_heap_base);
+ }
+ }
+ else if (!strcmp(export->name, "__data_end")) {
+ global_index = export->index - module->import_global_count;
+ global = module->globals + global_index;
+ if (global->type == VALUE_TYPE_I32 && !global->is_mutable
+ && global->init_expr.init_expr_type
+ == INIT_EXPR_TYPE_I32_CONST) {
+ aux_data_end_global = global;
+ aux_data_end = global->init_expr.u.i32;
+ aux_data_end_global_index = export->index;
+ LOG_VERBOSE("Found aux __data_end global, value: %d",
+ aux_data_end);
+
+ aux_data_end = align_uint(aux_data_end, 16);
+ }
+ }
+
+ /* For module compiled with -pthread option, the global is:
+ [0] stack_top <-- 0
+ [1] tls_pointer
+ [2] tls_size
+ [3] data_end <-- 3
+ [4] global_base
+ [5] heap_base <-- 5
+ [6] dso_handle
+
+ For module compiled without -pthread option:
+ [0] stack_top <-- 0
+ [1] data_end <-- 1
+ [2] global_base
+ [3] heap_base <-- 3
+ [4] dso_handle
+ */
+ if (aux_data_end_global && aux_heap_base_global
+ && aux_data_end <= aux_heap_base) {
+ module->aux_data_end_global_index = aux_data_end_global_index;
+ module->aux_data_end = aux_data_end;
+ module->aux_heap_base_global_index = aux_heap_base_global_index;
+ module->aux_heap_base = aux_heap_base;
+
+ /* Resolve aux stack top global */
+ for (global_index = 0; global_index < module->global_count;
+ global_index++) {
+ global = module->globals + global_index;
+ if (global->is_mutable /* heap_base and data_end is
+ not mutable */
+ && global->type == VALUE_TYPE_I32
+ && global->init_expr.init_expr_type
+ == INIT_EXPR_TYPE_I32_CONST
+ && (uint32)global->init_expr.u.i32 <= aux_heap_base) {
+ aux_stack_top_global = global;
+ aux_stack_top = (uint32)global->init_expr.u.i32;
+ module->aux_stack_top_global_index =
+ module->import_global_count + global_index;
+ module->aux_stack_bottom = aux_stack_top;
+ module->aux_stack_size =
+ aux_stack_top > aux_data_end
+ ? aux_stack_top - aux_data_end
+ : aux_stack_top;
+ LOG_VERBOSE("Found aux stack top global, value: %d, "
+ "global index: %d, stack size: %d",
+ aux_stack_top, global_index,
+ module->aux_stack_size);
+ break;
+ }
+ }
+ if (!aux_stack_top_global) {
+ /* Auxiliary stack global isn't found, it must be unused
+ in the wasm app, as if it is used, the global must be
+ defined. Here we set it to __heap_base global and set
+ its size to 0. */
+ aux_stack_top_global = aux_heap_base_global;
+ aux_stack_top = aux_heap_base;
+ module->aux_stack_top_global_index =
+ module->aux_heap_base_global_index;
+ module->aux_stack_bottom = aux_stack_top;
+ module->aux_stack_size = 0;
+ }
+ break;
+ }
+ }
+ }
+
+ module->malloc_function = (uint32)-1;
+ module->free_function = (uint32)-1;
+ module->retain_function = (uint32)-1;
+
+ /* Resolve malloc/free function exported by wasm module */
+ export = module->exports;
+ for (i = 0; i < module->export_count; i++, export ++) {
+ if (export->kind == EXPORT_KIND_FUNC) {
+ if (!strcmp(export->name, "malloc")
+ && export->index >= module->import_function_count) {
+ func_index = export->index - module->import_function_count;
+ func_type = module->functions[func_index]->func_type;
+ if (func_type->param_count == 1 && func_type->result_count == 1
+ && func_type->types[0] == VALUE_TYPE_I32
+ && func_type->types[1] == VALUE_TYPE_I32) {
+ bh_assert(module->malloc_function == (uint32)-1);
+ module->malloc_function = export->index;
+ LOG_VERBOSE("Found malloc function, name: %s, index: %u",
+ export->name, export->index);
+ }
+ }
+ else if (!strcmp(export->name, "__new")
+ && export->index >= module->import_function_count) {
+ /* __new && __pin for AssemblyScript */
+ func_index = export->index - module->import_function_count;
+ func_type = module->functions[func_index]->func_type;
+ if (func_type->param_count == 2 && func_type->result_count == 1
+ && func_type->types[0] == VALUE_TYPE_I32
+ && func_type->types[1] == VALUE_TYPE_I32
+ && func_type->types[2] == VALUE_TYPE_I32) {
+ uint32 j;
+ WASMExport *export_tmp;
+
+ bh_assert(module->malloc_function == (uint32)-1);
+ module->malloc_function = export->index;
+ LOG_VERBOSE("Found malloc function, name: %s, index: %u",
+ export->name, export->index);
+
+ /* resolve retain function.
+ If not found, reset malloc function index */
+ export_tmp = module->exports;
+ for (j = 0; j < module->export_count; j++, export_tmp++) {
+ if ((export_tmp->kind == EXPORT_KIND_FUNC)
+ && (!strcmp(export_tmp->name, "__retain")
+ || !strcmp(export_tmp->name, "__pin"))
+ && (export_tmp->index
+ >= module->import_function_count)) {
+ func_index = export_tmp->index
+ - module->import_function_count;
+ func_type =
+ module->functions[func_index]->func_type;
+ if (func_type->param_count == 1
+ && func_type->result_count == 1
+ && func_type->types[0] == VALUE_TYPE_I32
+ && func_type->types[1] == VALUE_TYPE_I32) {
+ bh_assert(module->retain_function
+ == (uint32)-1);
+ module->retain_function = export_tmp->index;
+ LOG_VERBOSE("Found retain function, name: %s, "
+ "index: %u",
+ export_tmp->name,
+ export_tmp->index);
+ break;
+ }
+ }
+ }
+ if (j == module->export_count) {
+ module->malloc_function = (uint32)-1;
+ LOG_VERBOSE("Can't find retain function,"
+ "reset malloc function index to -1");
+ }
+ }
+ }
+ else if (((!strcmp(export->name, "free"))
+ || (!strcmp(export->name, "__release"))
+ || (!strcmp(export->name, "__unpin")))
+ && export->index >= module->import_function_count) {
+ func_index = export->index - module->import_function_count;
+ func_type = module->functions[func_index]->func_type;
+ if (func_type->param_count == 1 && func_type->result_count == 0
+ && func_type->types[0] == VALUE_TYPE_I32) {
+ bh_assert(module->free_function == (uint32)-1);
+ module->free_function = export->index;
+ LOG_VERBOSE("Found free function, name: %s, index: %u",
+ export->name, export->index);
+ }
+ }
+ }
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0 && WASM_ENABLE_LABELS_AS_VALUES != 0
+ handle_table = wasm_interp_get_handle_table();
+#endif
+
+ for (i = 0; i < module->function_count; i++) {
+ WASMFunction *func = module->functions[i];
+ if (!wasm_loader_prepare_bytecode(module, func, i, error_buf,
+ error_buf_size)) {
+ return false;
+ }
+
+ if (i == module->function_count - 1) {
+ bh_assert(func->code + func->code_size == buf_code_end);
+ }
+ }
+
+ if (!module->possible_memory_grow) {
+ WASMMemoryImport *memory_import;
+ WASMMemory *memory;
+
+ if (aux_data_end_global && aux_heap_base_global
+ && aux_stack_top_global) {
+ uint64 init_memory_size;
+ uint32 shrunk_memory_size = align_uint(aux_heap_base, 8);
+
+ if (module->import_memory_count) {
+ memory_import = &module->import_memories[0].u.memory;
+ init_memory_size = (uint64)memory_import->num_bytes_per_page
+ * memory_import->init_page_count;
+ if (shrunk_memory_size <= init_memory_size) {
+ /* Reset memory info to decrease memory usage */
+ memory_import->num_bytes_per_page = shrunk_memory_size;
+ memory_import->init_page_count = 1;
+ LOG_VERBOSE("Shrink import memory size to %d",
+ shrunk_memory_size);
+ }
+ }
+ if (module->memory_count) {
+ memory = &module->memories[0];
+ init_memory_size = (uint64)memory->num_bytes_per_page
+ * memory->init_page_count;
+ if (shrunk_memory_size <= init_memory_size) {
+ /* Reset memory info to decrease memory usage */
+ memory->num_bytes_per_page = shrunk_memory_size;
+ memory->init_page_count = 1;
+ LOG_VERBOSE("Shrink memory size to %d", shrunk_memory_size);
+ }
+ }
+ }
+
+ if (module->import_memory_count) {
+ memory_import = &module->import_memories[0].u.memory;
+ if (memory_import->init_page_count < DEFAULT_MAX_PAGES)
+ memory_import->num_bytes_per_page *=
+ memory_import->init_page_count;
+ else
+ memory_import->num_bytes_per_page = UINT32_MAX;
+
+ if (memory_import->init_page_count > 0)
+ memory_import->init_page_count = memory_import->max_page_count =
+ 1;
+ else
+ memory_import->init_page_count = memory_import->max_page_count =
+ 0;
+ }
+
+ if (module->memory_count) {
+ memory = &module->memories[0];
+ if (memory->init_page_count < DEFAULT_MAX_PAGES)
+ memory->num_bytes_per_page *= memory->init_page_count;
+ else
+ memory->num_bytes_per_page = UINT32_MAX;
+
+ if (memory->init_page_count > 0)
+ memory->init_page_count = memory->max_page_count = 1;
+ else
+ memory->init_page_count = memory->max_page_count = 0;
+ }
+ }
+
+ calculate_global_data_offset(module);
+
+#if WASM_ENABLE_FAST_JIT != 0
+ if (!init_fast_jit_functions(module, error_buf, error_buf_size)) {
+ return false;
+ }
+#endif
+
+#if WASM_ENABLE_JIT != 0
+ if (!init_llvm_jit_functions_stage1(module, error_buf, error_buf_size)) {
+ return false;
+ }
+#if !(WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0)
+ if (!init_llvm_jit_functions_stage2(module, error_buf, error_buf_size)) {
+ return false;
+ }
+#else
+ /* Run aot_compile_wasm in a backend thread, so as not to block the main
+ thread fast jit execution, since applying llvm optimizations in
+ aot_compile_wasm may cost a lot of time.
+ Create thread with enough native stack to apply llvm optimizations */
+ if (os_thread_create(&module->llvm_jit_init_thread,
+ init_llvm_jit_functions_stage2_callback,
+ (void *)module, APP_THREAD_STACK_SIZE_DEFAULT * 8)
+ != 0) {
+ set_error_buf(error_buf, error_buf_size,
+ "create orcjit compile thread failed");
+ return false;
+ }
+#endif
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0
+ /* Create threads to compile the jit functions */
+ if (!compile_jit_functions(module, error_buf, error_buf_size)) {
+ return false;
+ }
+#endif
+
+#if WASM_ENABLE_MEMORY_TRACING != 0
+ wasm_runtime_dump_module_mem_consumption(module);
+#endif
+ return true;
+}
+
+static WASMModule *
+create_module(char *error_buf, uint32 error_buf_size)
+{
+ WASMModule *module =
+ loader_malloc(sizeof(WASMModule), error_buf, error_buf_size);
+ bh_list_status ret;
+
+ if (!module) {
+ return NULL;
+ }
+
+ module->module_type = Wasm_Module_Bytecode;
+
+ /* Set start_function to -1, means no start function */
+ module->start_function = (uint32)-1;
+
+#if WASM_ENABLE_FAST_INTERP == 0
+ module->br_table_cache_list = &module->br_table_cache_list_head;
+ ret = bh_list_init(module->br_table_cache_list);
+ bh_assert(ret == BH_LIST_SUCCESS);
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0
+ if (os_mutex_init(&module->instance_list_lock) != 0) {
+ set_error_buf(error_buf, error_buf_size,
+ "init instance list lock failed");
+ wasm_runtime_free(module);
+ return NULL;
+ }
+#endif
+
+ (void)ret;
+ return module;
+}
+
+WASMModule *
+wasm_loader_load_from_sections(WASMSection *section_list, char *error_buf,
+ uint32 error_buf_size)
+{
+ WASMModule *module = create_module(error_buf, error_buf_size);
+ if (!module)
+ return NULL;
+
+ if (!load_from_sections(module, section_list, false, error_buf,
+ error_buf_size)) {
+ wasm_loader_unload(module);
+ return NULL;
+ }
+
+ LOG_VERBOSE("Load module from sections success.\n");
+ return module;
+}
+
+static void
+destroy_sections(WASMSection *section_list)
+{
+ WASMSection *section = section_list, *next;
+ while (section) {
+ next = section->next;
+ wasm_runtime_free(section);
+ section = next;
+ }
+}
+
+/* clang-format off */
+static uint8 section_ids[] = {
+ SECTION_TYPE_USER,
+ SECTION_TYPE_TYPE,
+ SECTION_TYPE_IMPORT,
+ SECTION_TYPE_FUNC,
+ SECTION_TYPE_TABLE,
+ SECTION_TYPE_MEMORY,
+ SECTION_TYPE_GLOBAL,
+ SECTION_TYPE_EXPORT,
+ SECTION_TYPE_START,
+ SECTION_TYPE_ELEM,
+#if WASM_ENABLE_BULK_MEMORY != 0
+ SECTION_TYPE_DATACOUNT,
+#endif
+ SECTION_TYPE_CODE,
+ SECTION_TYPE_DATA
+};
+/* clang-format on */
+
+static uint8
+get_section_index(uint8 section_type)
+{
+ uint8 max_id = sizeof(section_ids) / sizeof(uint8);
+
+ for (uint8 i = 0; i < max_id; i++) {
+ if (section_type == section_ids[i])
+ return i;
+ }
+
+ return (uint8)-1;
+}
+
+static bool
+create_sections(const uint8 *buf, uint32 size, WASMSection **p_section_list,
+ char *error_buf, uint32 error_buf_size)
+{
+ WASMSection *section_list_end = NULL, *section;
+ const uint8 *p = buf, *p_end = buf + size /*, *section_body*/;
+ uint8 section_type, section_index, last_section_index = (uint8)-1;
+ uint32 section_size;
+
+ bh_assert(!*p_section_list);
+
+ p += 8;
+ while (p < p_end) {
+ CHECK_BUF(p, p_end, 1);
+ section_type = read_uint8(p);
+ section_index = get_section_index(section_type);
+ if (section_index != (uint8)-1) {
+ if (section_type != SECTION_TYPE_USER) {
+ /* Custom sections may be inserted at any place,
+ while other sections must occur at most once
+ and in prescribed order. */
+ bh_assert(last_section_index == (uint8)-1
+ || last_section_index < section_index);
+ last_section_index = section_index;
+ }
+ read_leb_uint32(p, p_end, section_size);
+ CHECK_BUF1(p, p_end, section_size);
+
+ if (!(section = loader_malloc(sizeof(WASMSection), error_buf,
+ error_buf_size))) {
+ return false;
+ }
+
+ section->section_type = section_type;
+ section->section_body = (uint8 *)p;
+ section->section_body_size = section_size;
+
+ if (!*p_section_list)
+ *p_section_list = section_list_end = section;
+ else {
+ section_list_end->next = section;
+ section_list_end = section;
+ }
+
+ p += section_size;
+ }
+ else {
+ bh_assert(0);
+ }
+ }
+
+ (void)last_section_index;
+ return true;
+}
+
+static void
+exchange32(uint8 *p_data)
+{
+ uint8 value = *p_data;
+ *p_data = *(p_data + 3);
+ *(p_data + 3) = value;
+
+ value = *(p_data + 1);
+ *(p_data + 1) = *(p_data + 2);
+ *(p_data + 2) = value;
+}
+
+static union {
+ int a;
+ char b;
+} __ue = { .a = 1 };
+
+#define is_little_endian() (__ue.b == 1)
+
+static bool
+load(const uint8 *buf, uint32 size, WASMModule *module, char *error_buf,
+ uint32 error_buf_size)
+{
+ const uint8 *buf_end = buf + size;
+ const uint8 *p = buf, *p_end = buf_end;
+ uint32 magic_number, version;
+ WASMSection *section_list = NULL;
+
+ CHECK_BUF1(p, p_end, sizeof(uint32));
+ magic_number = read_uint32(p);
+ if (!is_little_endian())
+ exchange32((uint8 *)&magic_number);
+
+ bh_assert(magic_number == WASM_MAGIC_NUMBER);
+
+ CHECK_BUF1(p, p_end, sizeof(uint32));
+ version = read_uint32(p);
+ if (!is_little_endian())
+ exchange32((uint8 *)&version);
+
+ if (version != WASM_CURRENT_VERSION) {
+ set_error_buf(error_buf, error_buf_size, "unknown binary version");
+ return false;
+ }
+
+ if (!create_sections(buf, size, &section_list, error_buf, error_buf_size)
+ || !load_from_sections(module, section_list, true, error_buf,
+ error_buf_size)) {
+ destroy_sections(section_list);
+ return false;
+ }
+
+ destroy_sections(section_list);
+ (void)p_end;
+ return true;
+}
+
+WASMModule *
+wasm_loader_load(uint8 *buf, uint32 size, char *error_buf,
+ uint32 error_buf_size)
+{
+ WASMModule *module = create_module(error_buf, error_buf_size);
+ if (!module) {
+ return NULL;
+ }
+
+#if WASM_ENABLE_FAST_JIT != 0
+ module->load_addr = (uint8 *)buf;
+ module->load_size = size;
+#endif
+
+ if (!load(buf, size, module, error_buf, error_buf_size)) {
+ goto fail;
+ }
+
+ LOG_VERBOSE("Load module success.\n");
+ return module;
+
+fail:
+ wasm_loader_unload(module);
+ return NULL;
+}
+
+void
+wasm_loader_unload(WASMModule *module)
+{
+ uint32 i;
+
+ if (!module)
+ return;
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0
+ module->orcjit_stop_compiling = true;
+ if (module->llvm_jit_init_thread)
+ os_thread_join(module->llvm_jit_init_thread, NULL);
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0
+ /* Stop Fast/LLVM JIT compilation firstly to avoid accessing
+ module internal data after they were freed */
+ orcjit_stop_compile_threads(module);
+#endif
+
+#if WASM_ENABLE_JIT != 0
+ if (module->func_ptrs)
+ wasm_runtime_free(module->func_ptrs);
+ if (module->comp_ctx)
+ aot_destroy_comp_context(module->comp_ctx);
+ if (module->comp_data)
+ aot_destroy_comp_data(module->comp_data);
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0
+ if (module->tierup_wait_lock_inited) {
+ os_mutex_destroy(&module->tierup_wait_lock);
+ os_cond_destroy(&module->tierup_wait_cond);
+ }
+#endif
+
+ if (module->types) {
+ for (i = 0; i < module->type_count; i++) {
+ if (module->types[i])
+ destroy_wasm_type(module->types[i]);
+ }
+ wasm_runtime_free(module->types);
+ }
+
+ if (module->imports)
+ wasm_runtime_free(module->imports);
+
+ if (module->functions) {
+ for (i = 0; i < module->function_count; i++) {
+ if (module->functions[i]) {
+ if (module->functions[i]->local_offsets)
+ wasm_runtime_free(module->functions[i]->local_offsets);
+#if WASM_ENABLE_FAST_INTERP != 0
+ if (module->functions[i]->code_compiled)
+ wasm_runtime_free(module->functions[i]->code_compiled);
+ if (module->functions[i]->consts)
+ wasm_runtime_free(module->functions[i]->consts);
+#endif
+#if WASM_ENABLE_FAST_JIT != 0
+ if (module->functions[i]->fast_jit_jitted_code) {
+ jit_code_cache_free(
+ module->functions[i]->fast_jit_jitted_code);
+ }
+#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0
+ if (module->functions[i]->call_to_fast_jit_from_llvm_jit) {
+ jit_code_cache_free(
+ module->functions[i]->call_to_fast_jit_from_llvm_jit);
+ }
+#endif
+#endif
+ wasm_runtime_free(module->functions[i]);
+ }
+ }
+ wasm_runtime_free(module->functions);
+ }
+
+ if (module->tables)
+ wasm_runtime_free(module->tables);
+
+ if (module->memories)
+ wasm_runtime_free(module->memories);
+
+ if (module->globals)
+ wasm_runtime_free(module->globals);
+
+ if (module->exports)
+ wasm_runtime_free(module->exports);
+
+ if (module->table_segments) {
+ for (i = 0; i < module->table_seg_count; i++) {
+ if (module->table_segments[i].func_indexes)
+ wasm_runtime_free(module->table_segments[i].func_indexes);
+ }
+ wasm_runtime_free(module->table_segments);
+ }
+
+ if (module->data_segments) {
+ for (i = 0; i < module->data_seg_count; i++) {
+ if (module->data_segments[i])
+ wasm_runtime_free(module->data_segments[i]);
+ }
+ wasm_runtime_free(module->data_segments);
+ }
+
+ if (module->const_str_list) {
+ StringNode *node = module->const_str_list, *node_next;
+ while (node) {
+ node_next = node->next;
+ wasm_runtime_free(node);
+ node = node_next;
+ }
+ }
+
+#if WASM_ENABLE_FAST_INTERP == 0
+ if (module->br_table_cache_list) {
+ BrTableCache *node = bh_list_first_elem(module->br_table_cache_list);
+ BrTableCache *node_next;
+ while (node) {
+ node_next = bh_list_elem_next(node);
+ wasm_runtime_free(node);
+ node = node_next;
+ }
+ }
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0
+ os_mutex_destroy(&module->instance_list_lock);
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0
+ if (module->fast_jit_func_ptrs) {
+ wasm_runtime_free(module->fast_jit_func_ptrs);
+ }
+
+ for (i = 0; i < WASM_ORC_JIT_BACKEND_THREAD_NUM; i++) {
+ if (module->fast_jit_thread_locks_inited[i]) {
+ os_mutex_destroy(&module->fast_jit_thread_locks[i]);
+ }
+ }
+#endif
+
+ wasm_runtime_free(module);
+}
+
+bool
+wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
+ const uint8 *start_addr, const uint8 *code_end_addr,
+ uint8 label_type, uint8 **p_else_addr,
+ uint8 **p_end_addr)
+{
+ const uint8 *p = start_addr, *p_end = code_end_addr;
+ uint8 *else_addr = NULL;
+ char error_buf[128];
+ uint32 block_nested_depth = 1, count, i, j, t;
+ uint32 error_buf_size = sizeof(error_buf);
+ uint8 opcode, u8;
+ BlockAddr block_stack[16] = { 0 }, *block;
+
+ i = ((uintptr_t)start_addr) & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1);
+ block = block_addr_cache + BLOCK_ADDR_CONFLICT_SIZE * i;
+
+ for (j = 0; j < BLOCK_ADDR_CONFLICT_SIZE; j++) {
+ if (block[j].start_addr == start_addr) {
+ /* Cache hit */
+ *p_else_addr = block[j].else_addr;
+ *p_end_addr = block[j].end_addr;
+ return true;
+ }
+ }
+
+ /* Cache unhit */
+ block_stack[0].start_addr = start_addr;
+
+ while (p < code_end_addr) {
+ opcode = *p++;
+
+ switch (opcode) {
+ case WASM_OP_UNREACHABLE:
+ case WASM_OP_NOP:
+ break;
+
+ case WASM_OP_BLOCK:
+ case WASM_OP_LOOP:
+ case WASM_OP_IF:
+ /* block result type: 0x40/0x7F/0x7E/0x7D/0x7C */
+ u8 = read_uint8(p);
+ if (block_nested_depth
+ < sizeof(block_stack) / sizeof(BlockAddr)) {
+ block_stack[block_nested_depth].start_addr = p;
+ block_stack[block_nested_depth].else_addr = NULL;
+ }
+ block_nested_depth++;
+ break;
+
+ case EXT_OP_BLOCK:
+ case EXT_OP_LOOP:
+ case EXT_OP_IF:
+ /* block type */
+ skip_leb_uint32(p, p_end);
+ if (block_nested_depth
+ < sizeof(block_stack) / sizeof(BlockAddr)) {
+ block_stack[block_nested_depth].start_addr = p;
+ block_stack[block_nested_depth].else_addr = NULL;
+ }
+ block_nested_depth++;
+ break;
+
+ case WASM_OP_ELSE:
+ if (label_type == LABEL_TYPE_IF && block_nested_depth == 1)
+ else_addr = (uint8 *)(p - 1);
+ if (block_nested_depth - 1
+ < sizeof(block_stack) / sizeof(BlockAddr))
+ block_stack[block_nested_depth - 1].else_addr =
+ (uint8 *)(p - 1);
+ break;
+
+ case WASM_OP_END:
+ if (block_nested_depth == 1) {
+ if (label_type == LABEL_TYPE_IF)
+ *p_else_addr = else_addr;
+ *p_end_addr = (uint8 *)(p - 1);
+
+ block_stack[0].end_addr = (uint8 *)(p - 1);
+ for (t = 0; t < sizeof(block_stack) / sizeof(BlockAddr);
+ t++) {
+ start_addr = block_stack[t].start_addr;
+ if (start_addr) {
+ i = ((uintptr_t)start_addr)
+ & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1);
+ block =
+ block_addr_cache + BLOCK_ADDR_CONFLICT_SIZE * i;
+ for (j = 0; j < BLOCK_ADDR_CONFLICT_SIZE; j++)
+ if (!block[j].start_addr)
+ break;
+
+ if (j == BLOCK_ADDR_CONFLICT_SIZE) {
+ memmove(block + 1, block,
+ (BLOCK_ADDR_CONFLICT_SIZE - 1)
+ * sizeof(BlockAddr));
+ j = 0;
+ }
+ block[j].start_addr = block_stack[t].start_addr;
+ block[j].else_addr = block_stack[t].else_addr;
+ block[j].end_addr = block_stack[t].end_addr;
+ }
+ else
+ break;
+ }
+ return true;
+ }
+ else {
+ block_nested_depth--;
+ if (block_nested_depth
+ < sizeof(block_stack) / sizeof(BlockAddr))
+ block_stack[block_nested_depth].end_addr =
+ (uint8 *)(p - 1);
+ }
+ break;
+
+ case WASM_OP_BR:
+ case WASM_OP_BR_IF:
+ skip_leb_uint32(p, p_end); /* labelidx */
+ break;
+
+ case WASM_OP_BR_TABLE:
+ read_leb_uint32(p, p_end, count); /* lable num */
+#if WASM_ENABLE_FAST_INTERP != 0
+ for (i = 0; i <= count; i++) /* lableidxs */
+ skip_leb_uint32(p, p_end);
+#else
+ p += count + 1;
+ while (*p == WASM_OP_NOP)
+ p++;
+#endif
+ break;
+
+#if WASM_ENABLE_FAST_INTERP == 0
+ case EXT_OP_BR_TABLE_CACHE:
+ read_leb_uint32(p, p_end, count); /* lable num */
+ while (*p == WASM_OP_NOP)
+ p++;
+ break;
+#endif
+
+ case WASM_OP_RETURN:
+ break;
+
+ case WASM_OP_CALL:
+#if WASM_ENABLE_TAIL_CALL != 0
+ case WASM_OP_RETURN_CALL:
+#endif
+ skip_leb_uint32(p, p_end); /* funcidx */
+ break;
+
+ case WASM_OP_CALL_INDIRECT:
+#if WASM_ENABLE_TAIL_CALL != 0
+ case WASM_OP_RETURN_CALL_INDIRECT:
+#endif
+ skip_leb_uint32(p, p_end); /* typeidx */
+ CHECK_BUF(p, p_end, 1);
+ u8 = read_uint8(p); /* 0x00 */
+ break;
+
+ case WASM_OP_DROP:
+ case WASM_OP_SELECT:
+ case WASM_OP_DROP_64:
+ case WASM_OP_SELECT_64:
+ break;
+#if WASM_ENABLE_REF_TYPES != 0
+ case WASM_OP_SELECT_T:
+ skip_leb_uint32(p, p_end); /* vec length */
+ CHECK_BUF(p, p_end, 1);
+ u8 = read_uint8(p); /* typeidx */
+ break;
+ case WASM_OP_TABLE_GET:
+ case WASM_OP_TABLE_SET:
+ skip_leb_uint32(p, p_end); /* table index */
+ break;
+ case WASM_OP_REF_NULL:
+ CHECK_BUF(p, p_end, 1);
+ u8 = read_uint8(p); /* type */
+ break;
+ case WASM_OP_REF_IS_NULL:
+ break;
+ case WASM_OP_REF_FUNC:
+ skip_leb_uint32(p, p_end); /* func index */
+ break;
+#endif /* WASM_ENABLE_REF_TYPES */
+ case WASM_OP_GET_LOCAL:
+ case WASM_OP_SET_LOCAL:
+ case WASM_OP_TEE_LOCAL:
+ case WASM_OP_GET_GLOBAL:
+ case WASM_OP_SET_GLOBAL:
+ case WASM_OP_GET_GLOBAL_64:
+ case WASM_OP_SET_GLOBAL_64:
+ case WASM_OP_SET_GLOBAL_AUX_STACK:
+ skip_leb_uint32(p, p_end); /* localidx */
+ break;
+
+ case EXT_OP_GET_LOCAL_FAST:
+ case EXT_OP_SET_LOCAL_FAST:
+ case EXT_OP_TEE_LOCAL_FAST:
+ CHECK_BUF(p, p_end, 1);
+ p++;
+ break;
+
+ case WASM_OP_I32_LOAD:
+ case WASM_OP_I64_LOAD:
+ case WASM_OP_F32_LOAD:
+ case WASM_OP_F64_LOAD:
+ case WASM_OP_I32_LOAD8_S:
+ case WASM_OP_I32_LOAD8_U:
+ case WASM_OP_I32_LOAD16_S:
+ case WASM_OP_I32_LOAD16_U:
+ case WASM_OP_I64_LOAD8_S:
+ case WASM_OP_I64_LOAD8_U:
+ case WASM_OP_I64_LOAD16_S:
+ case WASM_OP_I64_LOAD16_U:
+ case WASM_OP_I64_LOAD32_S:
+ case WASM_OP_I64_LOAD32_U:
+ case WASM_OP_I32_STORE:
+ case WASM_OP_I64_STORE:
+ case WASM_OP_F32_STORE:
+ case WASM_OP_F64_STORE:
+ case WASM_OP_I32_STORE8:
+ case WASM_OP_I32_STORE16:
+ case WASM_OP_I64_STORE8:
+ case WASM_OP_I64_STORE16:
+ case WASM_OP_I64_STORE32:
+ skip_leb_uint32(p, p_end); /* align */
+ skip_leb_uint32(p, p_end); /* offset */
+ break;
+
+ case WASM_OP_MEMORY_SIZE:
+ case WASM_OP_MEMORY_GROW:
+ skip_leb_uint32(p, p_end); /* 0x00 */
+ break;
+
+ case WASM_OP_I32_CONST:
+ skip_leb_int32(p, p_end);
+ break;
+ case WASM_OP_I64_CONST:
+ skip_leb_int64(p, p_end);
+ break;
+ case WASM_OP_F32_CONST:
+ p += sizeof(float32);
+ break;
+ case WASM_OP_F64_CONST:
+ p += sizeof(float64);
+ break;
+
+ case WASM_OP_I32_EQZ:
+ case WASM_OP_I32_EQ:
+ case WASM_OP_I32_NE:
+ case WASM_OP_I32_LT_S:
+ case WASM_OP_I32_LT_U:
+ case WASM_OP_I32_GT_S:
+ case WASM_OP_I32_GT_U:
+ case WASM_OP_I32_LE_S:
+ case WASM_OP_I32_LE_U:
+ case WASM_OP_I32_GE_S:
+ case WASM_OP_I32_GE_U:
+ case WASM_OP_I64_EQZ:
+ case WASM_OP_I64_EQ:
+ case WASM_OP_I64_NE:
+ case WASM_OP_I64_LT_S:
+ case WASM_OP_I64_LT_U:
+ case WASM_OP_I64_GT_S:
+ case WASM_OP_I64_GT_U:
+ case WASM_OP_I64_LE_S:
+ case WASM_OP_I64_LE_U:
+ case WASM_OP_I64_GE_S:
+ case WASM_OP_I64_GE_U:
+ case WASM_OP_F32_EQ:
+ case WASM_OP_F32_NE:
+ case WASM_OP_F32_LT:
+ case WASM_OP_F32_GT:
+ case WASM_OP_F32_LE:
+ case WASM_OP_F32_GE:
+ case WASM_OP_F64_EQ:
+ case WASM_OP_F64_NE:
+ case WASM_OP_F64_LT:
+ case WASM_OP_F64_GT:
+ case WASM_OP_F64_LE:
+ case WASM_OP_F64_GE:
+ case WASM_OP_I32_CLZ:
+ case WASM_OP_I32_CTZ:
+ case WASM_OP_I32_POPCNT:
+ case WASM_OP_I32_ADD:
+ case WASM_OP_I32_SUB:
+ case WASM_OP_I32_MUL:
+ case WASM_OP_I32_DIV_S:
+ case WASM_OP_I32_DIV_U:
+ case WASM_OP_I32_REM_S:
+ case WASM_OP_I32_REM_U:
+ case WASM_OP_I32_AND:
+ case WASM_OP_I32_OR:
+ case WASM_OP_I32_XOR:
+ case WASM_OP_I32_SHL:
+ case WASM_OP_I32_SHR_S:
+ case WASM_OP_I32_SHR_U:
+ case WASM_OP_I32_ROTL:
+ case WASM_OP_I32_ROTR:
+ case WASM_OP_I64_CLZ:
+ case WASM_OP_I64_CTZ:
+ case WASM_OP_I64_POPCNT:
+ case WASM_OP_I64_ADD:
+ case WASM_OP_I64_SUB:
+ case WASM_OP_I64_MUL:
+ case WASM_OP_I64_DIV_S:
+ case WASM_OP_I64_DIV_U:
+ case WASM_OP_I64_REM_S:
+ case WASM_OP_I64_REM_U:
+ case WASM_OP_I64_AND:
+ case WASM_OP_I64_OR:
+ case WASM_OP_I64_XOR:
+ case WASM_OP_I64_SHL:
+ case WASM_OP_I64_SHR_S:
+ case WASM_OP_I64_SHR_U:
+ case WASM_OP_I64_ROTL:
+ case WASM_OP_I64_ROTR:
+ case WASM_OP_F32_ABS:
+ case WASM_OP_F32_NEG:
+ case WASM_OP_F32_CEIL:
+ case WASM_OP_F32_FLOOR:
+ case WASM_OP_F32_TRUNC:
+ case WASM_OP_F32_NEAREST:
+ case WASM_OP_F32_SQRT:
+ case WASM_OP_F32_ADD:
+ case WASM_OP_F32_SUB:
+ case WASM_OP_F32_MUL:
+ case WASM_OP_F32_DIV:
+ case WASM_OP_F32_MIN:
+ case WASM_OP_F32_MAX:
+ case WASM_OP_F32_COPYSIGN:
+ case WASM_OP_F64_ABS:
+ case WASM_OP_F64_NEG:
+ case WASM_OP_F64_CEIL:
+ case WASM_OP_F64_FLOOR:
+ case WASM_OP_F64_TRUNC:
+ case WASM_OP_F64_NEAREST:
+ case WASM_OP_F64_SQRT:
+ case WASM_OP_F64_ADD:
+ case WASM_OP_F64_SUB:
+ case WASM_OP_F64_MUL:
+ case WASM_OP_F64_DIV:
+ case WASM_OP_F64_MIN:
+ case WASM_OP_F64_MAX:
+ case WASM_OP_F64_COPYSIGN:
+ case WASM_OP_I32_WRAP_I64:
+ case WASM_OP_I32_TRUNC_S_F32:
+ case WASM_OP_I32_TRUNC_U_F32:
+ case WASM_OP_I32_TRUNC_S_F64:
+ case WASM_OP_I32_TRUNC_U_F64:
+ case WASM_OP_I64_EXTEND_S_I32:
+ case WASM_OP_I64_EXTEND_U_I32:
+ case WASM_OP_I64_TRUNC_S_F32:
+ case WASM_OP_I64_TRUNC_U_F32:
+ case WASM_OP_I64_TRUNC_S_F64:
+ case WASM_OP_I64_TRUNC_U_F64:
+ case WASM_OP_F32_CONVERT_S_I32:
+ case WASM_OP_F32_CONVERT_U_I32:
+ case WASM_OP_F32_CONVERT_S_I64:
+ case WASM_OP_F32_CONVERT_U_I64:
+ case WASM_OP_F32_DEMOTE_F64:
+ case WASM_OP_F64_CONVERT_S_I32:
+ case WASM_OP_F64_CONVERT_U_I32:
+ case WASM_OP_F64_CONVERT_S_I64:
+ case WASM_OP_F64_CONVERT_U_I64:
+ case WASM_OP_F64_PROMOTE_F32:
+ case WASM_OP_I32_REINTERPRET_F32:
+ case WASM_OP_I64_REINTERPRET_F64:
+ case WASM_OP_F32_REINTERPRET_I32:
+ case WASM_OP_F64_REINTERPRET_I64:
+ case WASM_OP_I32_EXTEND8_S:
+ case WASM_OP_I32_EXTEND16_S:
+ case WASM_OP_I64_EXTEND8_S:
+ case WASM_OP_I64_EXTEND16_S:
+ case WASM_OP_I64_EXTEND32_S:
+ break;
+ case WASM_OP_MISC_PREFIX:
+ {
+ uint32 opcode1;
+
+ read_leb_uint32(p, p_end, opcode1);
+
+ switch (opcode1) {
+ case WASM_OP_I32_TRUNC_SAT_S_F32:
+ case WASM_OP_I32_TRUNC_SAT_U_F32:
+ case WASM_OP_I32_TRUNC_SAT_S_F64:
+ case WASM_OP_I32_TRUNC_SAT_U_F64:
+ case WASM_OP_I64_TRUNC_SAT_S_F32:
+ case WASM_OP_I64_TRUNC_SAT_U_F32:
+ case WASM_OP_I64_TRUNC_SAT_S_F64:
+ case WASM_OP_I64_TRUNC_SAT_U_F64:
+ break;
+#if WASM_ENABLE_BULK_MEMORY != 0
+ case WASM_OP_MEMORY_INIT:
+ skip_leb_uint32(p, p_end);
+ /* skip memory idx */
+ p++;
+ break;
+ case WASM_OP_DATA_DROP:
+ skip_leb_uint32(p, p_end);
+ break;
+ case WASM_OP_MEMORY_COPY:
+ /* skip two memory idx */
+ p += 2;
+ break;
+ case WASM_OP_MEMORY_FILL:
+ /* skip memory idx */
+ p++;
+ break;
+#endif
+#if WASM_ENABLE_REF_TYPES != 0
+ case WASM_OP_TABLE_INIT:
+ case WASM_OP_TABLE_COPY:
+ /* tableidx */
+ skip_leb_uint32(p, p_end);
+ /* elemidx */
+ skip_leb_uint32(p, p_end);
+ break;
+ case WASM_OP_ELEM_DROP:
+ /* elemidx */
+ skip_leb_uint32(p, p_end);
+ break;
+ case WASM_OP_TABLE_SIZE:
+ case WASM_OP_TABLE_GROW:
+ case WASM_OP_TABLE_FILL:
+ skip_leb_uint32(p, p_end); /* table idx */
+ break;
+#endif /* WASM_ENABLE_REF_TYPES */
+ default:
+ bh_assert(0);
+ break;
+ }
+ break;
+ }
+
+#if WASM_ENABLE_SHARED_MEMORY != 0
+ case WASM_OP_ATOMIC_PREFIX:
+ {
+ /* atomic_op (1 u8) + memarg (2 u32_leb) */
+ opcode = read_uint8(p);
+ if (opcode != WASM_OP_ATOMIC_FENCE) {
+ skip_leb_uint32(p, p_end); /* align */
+ skip_leb_uint32(p, p_end); /* offset */
+ }
+ else {
+ /* atomic.fence doesn't have memarg */
+ p++;
+ }
+ break;
+ }
+#endif
+
+ default:
+ bh_assert(0);
+ break;
+ }
+ }
+
+ (void)u8;
+ return false;
+}
+
+#define REF_I32 VALUE_TYPE_I32
+#define REF_F32 VALUE_TYPE_F32
+#define REF_I64_1 VALUE_TYPE_I64
+#define REF_I64_2 VALUE_TYPE_I64
+#define REF_F64_1 VALUE_TYPE_F64
+#define REF_F64_2 VALUE_TYPE_F64
+#define REF_ANY VALUE_TYPE_ANY
+
+#if WASM_ENABLE_FAST_INTERP != 0
+
+#if WASM_DEBUG_PREPROCESSOR != 0
+#define LOG_OP(...) os_printf(__VA_ARGS__)
+#else
+#define LOG_OP(...) (void)0
+#endif
+
+#define PATCH_ELSE 0
+#define PATCH_END 1
+typedef struct BranchBlockPatch {
+ struct BranchBlockPatch *next;
+ uint8 patch_type;
+ uint8 *code_compiled;
+} BranchBlockPatch;
+#endif
+
+typedef struct BranchBlock {
+ uint8 label_type;
+ BlockType block_type;
+ uint8 *start_addr;
+ uint8 *else_addr;
+ uint8 *end_addr;
+ uint32 stack_cell_num;
+#if WASM_ENABLE_FAST_INTERP != 0
+ uint16 dynamic_offset;
+ uint8 *code_compiled;
+ BranchBlockPatch *patch_list;
+ /* This is used to save params frame_offset of of if block */
+ int16 *param_frame_offsets;
+#endif
+
+ /* Indicate the operand stack is in polymorphic state.
+ * If the opcode is one of unreachable/br/br_table/return, stack is marked
+ * to polymorphic state until the block's 'end' opcode is processed.
+ * If stack is in polymorphic state and stack is empty, instruction can
+ * pop any type of value directly without decreasing stack top pointer
+ * and stack cell num. */
+ bool is_stack_polymorphic;
+} BranchBlock;
+
+typedef struct WASMLoaderContext {
+ /* frame ref stack */
+ uint8 *frame_ref;
+ uint8 *frame_ref_bottom;
+ uint8 *frame_ref_boundary;
+ uint32 frame_ref_size;
+ uint32 stack_cell_num;
+ uint32 max_stack_cell_num;
+
+ /* frame csp stack */
+ BranchBlock *frame_csp;
+ BranchBlock *frame_csp_bottom;
+ BranchBlock *frame_csp_boundary;
+ uint32 frame_csp_size;
+ uint32 csp_num;
+ uint32 max_csp_num;
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* frame offset stack */
+ int16 *frame_offset;
+ int16 *frame_offset_bottom;
+ int16 *frame_offset_boundary;
+ uint32 frame_offset_size;
+ int16 dynamic_offset;
+ int16 start_dynamic_offset;
+ int16 max_dynamic_offset;
+
+ /* preserved local offset */
+ int16 preserved_local_offset;
+
+ /* const buffer */
+ uint8 *const_buf;
+ uint16 num_const;
+ uint16 const_cell_num;
+ uint32 const_buf_size;
+
+ /* processed code */
+ uint8 *p_code_compiled;
+ uint8 *p_code_compiled_end;
+ uint32 code_compiled_size;
+ /* If the last opcode will be dropped, the peak memory usage will be larger
+ * than the final code_compiled_size, we record the peak size to ensure
+ * there will not be invalid memory access during second traverse */
+ uint32 code_compiled_peak_size;
+#endif
+} WASMLoaderContext;
+
+typedef struct Const {
+ WASMValue value;
+ uint16 slot_index;
+ uint8 value_type;
+} Const;
+
+static void *
+memory_realloc(void *mem_old, uint32 size_old, uint32 size_new, char *error_buf,
+ uint32 error_buf_size)
+{
+ uint8 *mem_new;
+ bh_assert(size_new > size_old);
+ if ((mem_new = loader_malloc(size_new, error_buf, error_buf_size))) {
+ bh_memcpy_s(mem_new, size_new, mem_old, size_old);
+ memset(mem_new + size_old, 0, size_new - size_old);
+ wasm_runtime_free(mem_old);
+ }
+ return mem_new;
+}
+
+#define MEM_REALLOC(mem, size_old, size_new) \
+ do { \
+ void *mem_new = memory_realloc(mem, size_old, size_new, error_buf, \
+ error_buf_size); \
+ if (!mem_new) \
+ goto fail; \
+ mem = mem_new; \
+ } while (0)
+
+#define CHECK_CSP_PUSH() \
+ do { \
+ if (ctx->frame_csp >= ctx->frame_csp_boundary) { \
+ MEM_REALLOC( \
+ ctx->frame_csp_bottom, ctx->frame_csp_size, \
+ (uint32)(ctx->frame_csp_size + 8 * sizeof(BranchBlock))); \
+ ctx->frame_csp_size += (uint32)(8 * sizeof(BranchBlock)); \
+ ctx->frame_csp_boundary = \
+ ctx->frame_csp_bottom \
+ + ctx->frame_csp_size / sizeof(BranchBlock); \
+ ctx->frame_csp = ctx->frame_csp_bottom + ctx->csp_num; \
+ } \
+ } while (0)
+
+#define CHECK_CSP_POP() \
+ do { \
+ bh_assert(ctx->csp_num >= 1); \
+ } while (0)
+
+#if WASM_ENABLE_FAST_INTERP != 0
+static bool
+check_offset_push(WASMLoaderContext *ctx, char *error_buf,
+ uint32 error_buf_size)
+{
+ uint32 cell_num = (uint32)(ctx->frame_offset - ctx->frame_offset_bottom);
+ if (ctx->frame_offset >= ctx->frame_offset_boundary) {
+ MEM_REALLOC(ctx->frame_offset_bottom, ctx->frame_offset_size,
+ ctx->frame_offset_size + 16);
+ ctx->frame_offset_size += 16;
+ ctx->frame_offset_boundary =
+ ctx->frame_offset_bottom + ctx->frame_offset_size / sizeof(int16);
+ ctx->frame_offset = ctx->frame_offset_bottom + cell_num;
+ }
+ return true;
+fail:
+ return false;
+}
+
+static bool
+check_offset_pop(WASMLoaderContext *ctx, uint32 cells)
+{
+ if (ctx->frame_offset - cells < ctx->frame_offset_bottom)
+ return false;
+ return true;
+}
+
+static void
+free_label_patch_list(BranchBlock *frame_csp)
+{
+ BranchBlockPatch *label_patch = frame_csp->patch_list;
+ BranchBlockPatch *next;
+ while (label_patch != NULL) {
+ next = label_patch->next;
+ wasm_runtime_free(label_patch);
+ label_patch = next;
+ }
+ frame_csp->patch_list = NULL;
+}
+
+static void
+free_all_label_patch_lists(BranchBlock *frame_csp, uint32 csp_num)
+{
+ BranchBlock *tmp_csp = frame_csp;
+
+ for (uint32 i = 0; i < csp_num; i++) {
+ free_label_patch_list(tmp_csp);
+ tmp_csp++;
+ }
+}
+
+#endif
+
+static bool
+check_stack_push(WASMLoaderContext *ctx, char *error_buf, uint32 error_buf_size)
+{
+ if (ctx->frame_ref >= ctx->frame_ref_boundary) {
+ MEM_REALLOC(ctx->frame_ref_bottom, ctx->frame_ref_size,
+ ctx->frame_ref_size + 16);
+ ctx->frame_ref_size += 16;
+ ctx->frame_ref_boundary = ctx->frame_ref_bottom + ctx->frame_ref_size;
+ ctx->frame_ref = ctx->frame_ref_bottom + ctx->stack_cell_num;
+ }
+ return true;
+fail:
+ return false;
+}
+
+static bool
+check_stack_top_values(uint8 *frame_ref, int32 stack_cell_num, uint8 type,
+ char *error_buf, uint32 error_buf_size)
+{
+ bh_assert(!((is_32bit_type(type) && stack_cell_num < 1)
+ || (is_64bit_type(type) && stack_cell_num < 2)));
+
+ bh_assert(!(
+ (type == VALUE_TYPE_I32 && *(frame_ref - 1) != REF_I32)
+ || (type == VALUE_TYPE_F32 && *(frame_ref - 1) != REF_F32)
+ || (type == VALUE_TYPE_I64
+ && (*(frame_ref - 2) != REF_I64_1 || *(frame_ref - 1) != REF_I64_2))
+ || (type == VALUE_TYPE_F64
+ && (*(frame_ref - 2) != REF_F64_1
+ || *(frame_ref - 1) != REF_F64_2))));
+ return true;
+}
+
+static bool
+check_stack_pop(WASMLoaderContext *ctx, uint8 type, char *error_buf,
+ uint32 error_buf_size)
+{
+ int32 block_stack_cell_num =
+ (int32)(ctx->stack_cell_num - (ctx->frame_csp - 1)->stack_cell_num);
+
+ if (block_stack_cell_num > 0 && *(ctx->frame_ref - 1) == VALUE_TYPE_ANY) {
+ /* the stack top is a value of any type, return success */
+ return true;
+ }
+
+ if (!check_stack_top_values(ctx->frame_ref, block_stack_cell_num, type,
+ error_buf, error_buf_size))
+ return false;
+
+ return true;
+}
+
+static void
+wasm_loader_ctx_destroy(WASMLoaderContext *ctx)
+{
+ if (ctx) {
+ if (ctx->frame_ref_bottom)
+ wasm_runtime_free(ctx->frame_ref_bottom);
+ if (ctx->frame_csp_bottom) {
+#if WASM_ENABLE_FAST_INTERP != 0
+ free_all_label_patch_lists(ctx->frame_csp_bottom, ctx->csp_num);
+#endif
+ wasm_runtime_free(ctx->frame_csp_bottom);
+ }
+#if WASM_ENABLE_FAST_INTERP != 0
+ if (ctx->frame_offset_bottom)
+ wasm_runtime_free(ctx->frame_offset_bottom);
+ if (ctx->const_buf)
+ wasm_runtime_free(ctx->const_buf);
+#endif
+ wasm_runtime_free(ctx);
+ }
+}
+
+static WASMLoaderContext *
+wasm_loader_ctx_init(WASMFunction *func, char *error_buf, uint32 error_buf_size)
+{
+ WASMLoaderContext *loader_ctx =
+ loader_malloc(sizeof(WASMLoaderContext), error_buf, error_buf_size);
+ if (!loader_ctx)
+ return NULL;
+
+ loader_ctx->frame_ref_size = 32;
+ if (!(loader_ctx->frame_ref_bottom = loader_ctx->frame_ref = loader_malloc(
+ loader_ctx->frame_ref_size, error_buf, error_buf_size)))
+ goto fail;
+ loader_ctx->frame_ref_boundary = loader_ctx->frame_ref_bottom + 32;
+
+ loader_ctx->frame_csp_size = sizeof(BranchBlock) * 8;
+ if (!(loader_ctx->frame_csp_bottom = loader_ctx->frame_csp = loader_malloc(
+ loader_ctx->frame_csp_size, error_buf, error_buf_size)))
+ goto fail;
+ loader_ctx->frame_csp_boundary = loader_ctx->frame_csp_bottom + 8;
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ loader_ctx->frame_offset_size = sizeof(int16) * 32;
+ if (!(loader_ctx->frame_offset_bottom = loader_ctx->frame_offset =
+ loader_malloc(loader_ctx->frame_offset_size, error_buf,
+ error_buf_size)))
+ goto fail;
+ loader_ctx->frame_offset_boundary = loader_ctx->frame_offset_bottom + 32;
+
+ loader_ctx->num_const = 0;
+ loader_ctx->const_buf_size = sizeof(Const) * 8;
+ if (!(loader_ctx->const_buf = loader_malloc(loader_ctx->const_buf_size,
+ error_buf, error_buf_size)))
+ goto fail;
+
+ if (func->param_cell_num >= (int32)INT16_MAX - func->local_cell_num) {
+ set_error_buf(error_buf, error_buf_size,
+ "fast interpreter offset overflow");
+ goto fail;
+ }
+
+ loader_ctx->start_dynamic_offset = loader_ctx->dynamic_offset =
+ loader_ctx->max_dynamic_offset =
+ func->param_cell_num + func->local_cell_num;
+#endif
+ return loader_ctx;
+
+fail:
+ wasm_loader_ctx_destroy(loader_ctx);
+ return NULL;
+}
+
+static bool
+wasm_loader_push_frame_ref(WASMLoaderContext *ctx, uint8 type, char *error_buf,
+ uint32 error_buf_size)
+{
+ if (type == VALUE_TYPE_VOID)
+ return true;
+
+ if (!check_stack_push(ctx, error_buf, error_buf_size))
+ return false;
+
+ *ctx->frame_ref++ = type;
+ ctx->stack_cell_num++;
+ if (ctx->stack_cell_num > ctx->max_stack_cell_num)
+ ctx->max_stack_cell_num = ctx->stack_cell_num;
+
+ if (is_32bit_type(type))
+ return true;
+
+ if (!check_stack_push(ctx, error_buf, error_buf_size))
+ return false;
+ *ctx->frame_ref++ = type;
+ ctx->stack_cell_num++;
+ if (ctx->stack_cell_num > ctx->max_stack_cell_num) {
+ ctx->max_stack_cell_num = ctx->stack_cell_num;
+ bh_assert(ctx->max_stack_cell_num <= UINT16_MAX);
+ }
+ return true;
+}
+
+static bool
+wasm_loader_pop_frame_ref(WASMLoaderContext *ctx, uint8 type, char *error_buf,
+ uint32 error_buf_size)
+{
+ BranchBlock *cur_block = ctx->frame_csp - 1;
+ int32 available_stack_cell =
+ (int32)(ctx->stack_cell_num - cur_block->stack_cell_num);
+
+ /* Directly return success if current block is in stack
+ * polymorphic state while stack is empty. */
+ if (available_stack_cell <= 0 && cur_block->is_stack_polymorphic)
+ return true;
+
+ if (type == VALUE_TYPE_VOID)
+ return true;
+
+ if (!check_stack_pop(ctx, type, error_buf, error_buf_size))
+ return false;
+
+ ctx->frame_ref--;
+ ctx->stack_cell_num--;
+
+ if (is_32bit_type(type) || *ctx->frame_ref == VALUE_TYPE_ANY)
+ return true;
+
+ ctx->frame_ref--;
+ ctx->stack_cell_num--;
+ return true;
+}
+
+static bool
+wasm_loader_push_pop_frame_ref(WASMLoaderContext *ctx, uint8 pop_cnt,
+ uint8 type_push, uint8 type_pop, char *error_buf,
+ uint32 error_buf_size)
+{
+ for (int i = 0; i < pop_cnt; i++) {
+ if (!wasm_loader_pop_frame_ref(ctx, type_pop, error_buf,
+ error_buf_size))
+ return false;
+ }
+ if (!wasm_loader_push_frame_ref(ctx, type_push, error_buf, error_buf_size))
+ return false;
+ return true;
+}
+
+static bool
+wasm_loader_push_frame_csp(WASMLoaderContext *ctx, uint8 label_type,
+ BlockType block_type, uint8 *start_addr,
+ char *error_buf, uint32 error_buf_size)
+{
+ CHECK_CSP_PUSH();
+ memset(ctx->frame_csp, 0, sizeof(BranchBlock));
+ ctx->frame_csp->label_type = label_type;
+ ctx->frame_csp->block_type = block_type;
+ ctx->frame_csp->start_addr = start_addr;
+ ctx->frame_csp->stack_cell_num = ctx->stack_cell_num;
+#if WASM_ENABLE_FAST_INTERP != 0
+ ctx->frame_csp->dynamic_offset = ctx->dynamic_offset;
+ ctx->frame_csp->patch_list = NULL;
+#endif
+ ctx->frame_csp++;
+ ctx->csp_num++;
+ if (ctx->csp_num > ctx->max_csp_num) {
+ ctx->max_csp_num = ctx->csp_num;
+ bh_assert(ctx->max_csp_num <= UINT16_MAX);
+ }
+ return true;
+fail:
+ return false;
+}
+
+static bool
+wasm_loader_pop_frame_csp(WASMLoaderContext *ctx, char *error_buf,
+ uint32 error_buf_size)
+{
+ CHECK_CSP_POP();
+#if WASM_ENABLE_FAST_INTERP != 0
+ if ((ctx->frame_csp - 1)->param_frame_offsets)
+ wasm_runtime_free((ctx->frame_csp - 1)->param_frame_offsets);
+#endif
+ ctx->frame_csp--;
+ ctx->csp_num--;
+ return true;
+}
+
+#if WASM_ENABLE_FAST_INTERP != 0
+
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
+#define emit_label(opcode) \
+ do { \
+ wasm_loader_emit_ptr(loader_ctx, handle_table[opcode]); \
+ LOG_OP("\nemit_op [%02x]\t", opcode); \
+ } while (0)
+#define skip_label() \
+ do { \
+ wasm_loader_emit_backspace(loader_ctx, sizeof(void *)); \
+ LOG_OP("\ndelete last op\n"); \
+ } while (0)
+#else /* else of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */
+#define emit_label(opcode) \
+ do { \
+ int32 offset = \
+ (int32)((uint8 *)handle_table[opcode] - (uint8 *)handle_table[0]); \
+ if (!(offset >= INT16_MIN && offset < INT16_MAX)) { \
+ set_error_buf(error_buf, error_buf_size, \
+ "pre-compiled label offset out of range"); \
+ goto fail; \
+ } \
+ wasm_loader_emit_int16(loader_ctx, offset); \
+ LOG_OP("\nemit_op [%02x]\t", opcode); \
+ } while (0)
+#define skip_label() \
+ do { \
+ wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); \
+ LOG_OP("\ndelete last op\n"); \
+ } while (0)
+#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */
+#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
+#define emit_label(opcode) \
+ do { \
+ wasm_loader_emit_uint8(loader_ctx, opcode); \
+ LOG_OP("\nemit_op [%02x]\t", opcode); \
+ } while (0)
+#define skip_label() \
+ do { \
+ wasm_loader_emit_backspace(loader_ctx, sizeof(uint8)); \
+ LOG_OP("\ndelete last op\n"); \
+ } while (0)
+#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */
+
+#define emit_empty_label_addr_and_frame_ip(type) \
+ do { \
+ if (!add_label_patch_to_list(loader_ctx->frame_csp - 1, type, \
+ loader_ctx->p_code_compiled, error_buf, \
+ error_buf_size)) \
+ goto fail; \
+ /* label address, to be patched */ \
+ wasm_loader_emit_ptr(loader_ctx, NULL); \
+ } while (0)
+
+#define emit_br_info(frame_csp) \
+ do { \
+ if (!wasm_loader_emit_br_info(loader_ctx, frame_csp, error_buf, \
+ error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define LAST_OP_OUTPUT_I32() \
+ (last_op >= WASM_OP_I32_EQZ && last_op <= WASM_OP_I32_ROTR) \
+ || (last_op == WASM_OP_I32_LOAD || last_op == WASM_OP_F32_LOAD) \
+ || (last_op >= WASM_OP_I32_LOAD8_S && last_op <= WASM_OP_I32_LOAD16_U) \
+ || (last_op >= WASM_OP_F32_ABS && last_op <= WASM_OP_F32_COPYSIGN) \
+ || (last_op >= WASM_OP_I32_WRAP_I64 \
+ && last_op <= WASM_OP_I32_TRUNC_U_F64) \
+ || (last_op >= WASM_OP_F32_CONVERT_S_I32 \
+ && last_op <= WASM_OP_F32_DEMOTE_F64) \
+ || (last_op == WASM_OP_I32_REINTERPRET_F32) \
+ || (last_op == WASM_OP_F32_REINTERPRET_I32) \
+ || (last_op == EXT_OP_COPY_STACK_TOP)
+
+#define LAST_OP_OUTPUT_I64() \
+ (last_op >= WASM_OP_I64_CLZ && last_op <= WASM_OP_I64_ROTR) \
+ || (last_op >= WASM_OP_F64_ABS && last_op <= WASM_OP_F64_COPYSIGN) \
+ || (last_op == WASM_OP_I64_LOAD || last_op == WASM_OP_F64_LOAD) \
+ || (last_op >= WASM_OP_I64_LOAD8_S && last_op <= WASM_OP_I64_LOAD32_U) \
+ || (last_op >= WASM_OP_I64_EXTEND_S_I32 \
+ && last_op <= WASM_OP_I64_TRUNC_U_F64) \
+ || (last_op >= WASM_OP_F64_CONVERT_S_I32 \
+ && last_op <= WASM_OP_F64_PROMOTE_F32) \
+ || (last_op == WASM_OP_I64_REINTERPRET_F64) \
+ || (last_op == WASM_OP_F64_REINTERPRET_I64) \
+ || (last_op == EXT_OP_COPY_STACK_TOP_I64)
+
+#define GET_CONST_OFFSET(type, val) \
+ do { \
+ if (!(wasm_loader_get_const_offset(loader_ctx, type, &val, \
+ &operand_offset, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define GET_CONST_F32_OFFSET(type, fval) \
+ do { \
+ if (!(wasm_loader_get_const_offset(loader_ctx, type, &fval, \
+ &operand_offset, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define GET_CONST_F64_OFFSET(type, fval) \
+ do { \
+ if (!(wasm_loader_get_const_offset(loader_ctx, type, &fval, \
+ &operand_offset, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define emit_operand(ctx, offset) \
+ do { \
+ wasm_loader_emit_int16(ctx, offset); \
+ LOG_OP("%d\t", offset); \
+ } while (0)
+
+#define emit_byte(ctx, byte) \
+ do { \
+ wasm_loader_emit_uint8(ctx, byte); \
+ LOG_OP("%d\t", byte); \
+ } while (0)
+
+#define emit_uint32(ctx, value) \
+ do { \
+ wasm_loader_emit_uint32(ctx, value); \
+ LOG_OP("%d\t", value); \
+ } while (0)
+
+#define emit_uint64(ctx, value) \
+ do { \
+ wasm_loader_emit_const(ctx, &value, false); \
+ LOG_OP("%lld\t", value); \
+ } while (0)
+
+#define emit_float32(ctx, value) \
+ do { \
+ wasm_loader_emit_const(ctx, &value, true); \
+ LOG_OP("%f\t", value); \
+ } while (0)
+
+#define emit_float64(ctx, value) \
+ do { \
+ wasm_loader_emit_const(ctx, &value, false); \
+ LOG_OP("%f\t", value); \
+ } while (0)
+
+static bool
+wasm_loader_ctx_reinit(WASMLoaderContext *ctx)
+{
+ if (!(ctx->p_code_compiled =
+ loader_malloc(ctx->code_compiled_peak_size, NULL, 0)))
+ return false;
+ ctx->p_code_compiled_end =
+ ctx->p_code_compiled + ctx->code_compiled_peak_size;
+
+ /* clean up frame ref */
+ memset(ctx->frame_ref_bottom, 0, ctx->frame_ref_size);
+ ctx->frame_ref = ctx->frame_ref_bottom;
+ ctx->stack_cell_num = 0;
+
+ /* clean up frame csp */
+ memset(ctx->frame_csp_bottom, 0, ctx->frame_csp_size);
+ ctx->frame_csp = ctx->frame_csp_bottom;
+ ctx->csp_num = 0;
+ ctx->max_csp_num = 0;
+
+ /* clean up frame offset */
+ memset(ctx->frame_offset_bottom, 0, ctx->frame_offset_size);
+ ctx->frame_offset = ctx->frame_offset_bottom;
+ ctx->dynamic_offset = ctx->start_dynamic_offset;
+
+ /* init preserved local offsets */
+ ctx->preserved_local_offset = ctx->max_dynamic_offset;
+
+ /* const buf is reserved */
+ return true;
+}
+
+static void
+increase_compiled_code_space(WASMLoaderContext *ctx, int32 size)
+{
+ ctx->code_compiled_size += size;
+ if (ctx->code_compiled_size >= ctx->code_compiled_peak_size) {
+ ctx->code_compiled_peak_size = ctx->code_compiled_size;
+ }
+}
+
+static void
+wasm_loader_emit_const(WASMLoaderContext *ctx, void *value, bool is_32_bit)
+{
+ uint32 size = is_32_bit ? sizeof(uint32) : sizeof(uint64);
+
+ if (ctx->p_code_compiled) {
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0);
+#endif
+ bh_memcpy_s(ctx->p_code_compiled,
+ (uint32)(ctx->p_code_compiled_end - ctx->p_code_compiled),
+ value, size);
+ ctx->p_code_compiled += size;
+ }
+ else {
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ bh_assert((ctx->code_compiled_size & 1) == 0);
+#endif
+ increase_compiled_code_space(ctx, size);
+ }
+}
+
+static void
+wasm_loader_emit_uint32(WASMLoaderContext *ctx, uint32 value)
+{
+ if (ctx->p_code_compiled) {
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0);
+#endif
+ STORE_U32(ctx->p_code_compiled, value);
+ ctx->p_code_compiled += sizeof(uint32);
+ }
+ else {
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ bh_assert((ctx->code_compiled_size & 1) == 0);
+#endif
+ increase_compiled_code_space(ctx, sizeof(uint32));
+ }
+}
+
+static void
+wasm_loader_emit_int16(WASMLoaderContext *ctx, int16 value)
+{
+ if (ctx->p_code_compiled) {
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0);
+#endif
+ STORE_U16(ctx->p_code_compiled, (uint16)value);
+ ctx->p_code_compiled += sizeof(int16);
+ }
+ else {
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ bh_assert((ctx->code_compiled_size & 1) == 0);
+#endif
+ increase_compiled_code_space(ctx, sizeof(uint16));
+ }
+}
+
+static void
+wasm_loader_emit_uint8(WASMLoaderContext *ctx, uint8 value)
+{
+ if (ctx->p_code_compiled) {
+ *(ctx->p_code_compiled) = value;
+ ctx->p_code_compiled += sizeof(uint8);
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ ctx->p_code_compiled++;
+ bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0);
+#endif
+ }
+ else {
+ increase_compiled_code_space(ctx, sizeof(uint8));
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ increase_compiled_code_space(ctx, sizeof(uint8));
+ bh_assert((ctx->code_compiled_size & 1) == 0);
+#endif
+ }
+}
+
+static void
+wasm_loader_emit_ptr(WASMLoaderContext *ctx, void *value)
+{
+ if (ctx->p_code_compiled) {
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0);
+#endif
+ STORE_PTR(ctx->p_code_compiled, value);
+ ctx->p_code_compiled += sizeof(void *);
+ }
+ else {
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ bh_assert((ctx->code_compiled_size & 1) == 0);
+#endif
+ increase_compiled_code_space(ctx, sizeof(void *));
+ }
+}
+
+static void
+wasm_loader_emit_backspace(WASMLoaderContext *ctx, uint32 size)
+{
+ if (ctx->p_code_compiled) {
+ ctx->p_code_compiled -= size;
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ if (size == sizeof(uint8)) {
+ ctx->p_code_compiled--;
+ bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0);
+ }
+#endif
+ }
+ else {
+ ctx->code_compiled_size -= size;
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+ if (size == sizeof(uint8)) {
+ ctx->code_compiled_size--;
+ bh_assert((ctx->code_compiled_size & 1) == 0);
+ }
+#endif
+ }
+}
+
+static bool
+preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode,
+ uint32 local_index, uint32 local_type,
+ bool *preserved, char *error_buf,
+ uint32 error_buf_size)
+{
+ uint32 i = 0;
+ int16 preserved_offset = (int16)local_index;
+
+ *preserved = false;
+ while (i < loader_ctx->stack_cell_num) {
+ uint8 cur_type = loader_ctx->frame_ref_bottom[i];
+
+ /* move previous local into dynamic space before a set/tee_local opcode
+ */
+ if (loader_ctx->frame_offset_bottom[i] == (int16)local_index) {
+ if (!(*preserved)) {
+ *preserved = true;
+ skip_label();
+ preserved_offset = loader_ctx->preserved_local_offset;
+ if (loader_ctx->p_code_compiled) {
+ bh_assert(preserved_offset != (int16)local_index);
+ }
+ if (is_32bit_type(local_type)) {
+ /* Only increase preserve offset in the second traversal */
+ if (loader_ctx->p_code_compiled)
+ loader_ctx->preserved_local_offset++;
+ emit_label(EXT_OP_COPY_STACK_TOP);
+ }
+ else {
+ if (loader_ctx->p_code_compiled)
+ loader_ctx->preserved_local_offset += 2;
+ emit_label(EXT_OP_COPY_STACK_TOP_I64);
+ }
+ emit_operand(loader_ctx, local_index);
+ emit_operand(loader_ctx, preserved_offset);
+ emit_label(opcode);
+ }
+ loader_ctx->frame_offset_bottom[i] = preserved_offset;
+ }
+
+ if (is_32bit_type(cur_type))
+ i++;
+ else
+ i += 2;
+ }
+
+ return true;
+
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
+fail:
+ return false;
+#endif
+#endif
+}
+
+static bool
+preserve_local_for_block(WASMLoaderContext *loader_ctx, uint8 opcode,
+ char *error_buf, uint32 error_buf_size)
+{
+ uint32 i = 0;
+ bool preserve_local;
+
+ /* preserve locals before blocks to ensure that "tee/set_local" inside
+ blocks will not influence the value of these locals */
+ while (i < loader_ctx->stack_cell_num) {
+ int16 cur_offset = loader_ctx->frame_offset_bottom[i];
+ uint8 cur_type = loader_ctx->frame_ref_bottom[i];
+
+ if ((cur_offset < loader_ctx->start_dynamic_offset)
+ && (cur_offset >= 0)) {
+ if (!(preserve_referenced_local(loader_ctx, opcode, cur_offset,
+ cur_type, &preserve_local,
+ error_buf, error_buf_size)))
+ return false;
+ }
+
+ if (is_32bit_type(cur_type == VALUE_TYPE_I32)) {
+ i++;
+ }
+ else {
+ i += 2;
+ }
+ }
+
+ return true;
+}
+
+static bool
+add_label_patch_to_list(BranchBlock *frame_csp, uint8 patch_type,
+ uint8 *p_code_compiled, char *error_buf,
+ uint32 error_buf_size)
+{
+ BranchBlockPatch *patch =
+ loader_malloc(sizeof(BranchBlockPatch), error_buf, error_buf_size);
+ if (!patch) {
+ return false;
+ }
+ patch->patch_type = patch_type;
+ patch->code_compiled = p_code_compiled;
+ if (!frame_csp->patch_list) {
+ frame_csp->patch_list = patch;
+ patch->next = NULL;
+ }
+ else {
+ patch->next = frame_csp->patch_list;
+ frame_csp->patch_list = patch;
+ }
+ return true;
+}
+
+static void
+apply_label_patch(WASMLoaderContext *ctx, uint8 depth, uint8 patch_type)
+{
+ BranchBlock *frame_csp = ctx->frame_csp - depth;
+ BranchBlockPatch *node = frame_csp->patch_list;
+ BranchBlockPatch *node_prev = NULL, *node_next;
+
+ if (!ctx->p_code_compiled)
+ return;
+
+ while (node) {
+ node_next = node->next;
+ if (node->patch_type == patch_type) {
+ STORE_PTR(node->code_compiled, ctx->p_code_compiled);
+ if (node_prev == NULL) {
+ frame_csp->patch_list = node_next;
+ }
+ else {
+ node_prev->next = node_next;
+ }
+ wasm_runtime_free(node);
+ }
+ else {
+ node_prev = node;
+ }
+ node = node_next;
+ }
+}
+
+static bool
+wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp,
+ char *error_buf, uint32 error_buf_size)
+{
+ /* br info layout:
+ * a) arity of target block
+ * b) total cell num of arity values
+ * c) each arity value's cell num
+ * d) each arity value's src frame offset
+ * e) each arity values's dst dynamic offset
+ * f) branch target address
+ *
+ * Note: b-e are omitted when arity is 0 so that
+ * interpreter can recover the br info quickly.
+ */
+ BlockType *block_type = &frame_csp->block_type;
+ uint8 *types = NULL, cell;
+ uint32 arity = 0;
+ int32 i;
+ int16 *frame_offset = ctx->frame_offset;
+ uint16 dynamic_offset;
+
+ /* Note: loop's arity is different from if and block. loop's arity is
+ * its parameter count while if and block arity is result count.
+ */
+ if (frame_csp->label_type == LABEL_TYPE_LOOP)
+ arity = block_type_get_param_types(block_type, &types);
+ else
+ arity = block_type_get_result_types(block_type, &types);
+
+ /* Part a */
+ emit_uint32(ctx, arity);
+
+ if (arity) {
+ /* Part b */
+ emit_uint32(ctx, wasm_get_cell_num(types, arity));
+
+ /* Part c */
+ for (i = (int32)arity - 1; i >= 0; i--) {
+ cell = (uint8)wasm_value_type_cell_num(types[i]);
+ emit_byte(ctx, cell);
+ }
+ /* Part d */
+ for (i = (int32)arity - 1; i >= 0; i--) {
+ cell = (uint8)wasm_value_type_cell_num(types[i]);
+ frame_offset -= cell;
+ emit_operand(ctx, *(int16 *)(frame_offset));
+ }
+ /* Part e */
+ dynamic_offset =
+ frame_csp->dynamic_offset + wasm_get_cell_num(types, arity);
+ for (i = (int32)arity - 1; i >= 0; i--) {
+ cell = (uint8)wasm_value_type_cell_num(types[i]);
+ dynamic_offset -= cell;
+ emit_operand(ctx, dynamic_offset);
+ }
+ }
+
+ /* Part f */
+ if (frame_csp->label_type == LABEL_TYPE_LOOP) {
+ wasm_loader_emit_ptr(ctx, frame_csp->code_compiled);
+ }
+ else {
+ if (!add_label_patch_to_list(frame_csp, PATCH_END, ctx->p_code_compiled,
+ error_buf, error_buf_size))
+ return false;
+ /* label address, to be patched */
+ wasm_loader_emit_ptr(ctx, NULL);
+ }
+
+ return true;
+}
+
+static bool
+wasm_loader_push_frame_offset(WASMLoaderContext *ctx, uint8 type,
+ bool disable_emit, int16 operand_offset,
+ char *error_buf, uint32 error_buf_size)
+{
+ if (type == VALUE_TYPE_VOID)
+ return true;
+
+ /* only check memory overflow in first traverse */
+ if (ctx->p_code_compiled == NULL) {
+ if (!check_offset_push(ctx, error_buf, error_buf_size))
+ return false;
+ }
+
+ if (disable_emit)
+ *(ctx->frame_offset)++ = operand_offset;
+ else {
+ emit_operand(ctx, ctx->dynamic_offset);
+ *(ctx->frame_offset)++ = ctx->dynamic_offset;
+ ctx->dynamic_offset++;
+ if (ctx->dynamic_offset > ctx->max_dynamic_offset) {
+ ctx->max_dynamic_offset = ctx->dynamic_offset;
+ bh_assert(ctx->max_dynamic_offset < INT16_MAX);
+ }
+ }
+
+ if (is_32bit_type(type))
+ return true;
+
+ if (ctx->p_code_compiled == NULL) {
+ if (!check_offset_push(ctx, error_buf, error_buf_size))
+ return false;
+ }
+
+ ctx->frame_offset++;
+ if (!disable_emit) {
+ ctx->dynamic_offset++;
+ if (ctx->dynamic_offset > ctx->max_dynamic_offset) {
+ ctx->max_dynamic_offset = ctx->dynamic_offset;
+ bh_assert(ctx->max_dynamic_offset < INT16_MAX);
+ }
+ }
+ return true;
+}
+
+/* This function should be in front of wasm_loader_pop_frame_ref
+ as they both use ctx->stack_cell_num, and ctx->stack_cell_num
+ will be modified by wasm_loader_pop_frame_ref */
+static bool
+wasm_loader_pop_frame_offset(WASMLoaderContext *ctx, uint8 type,
+ char *error_buf, uint32 error_buf_size)
+{
+ /* if ctx->frame_csp equals ctx->frame_csp_bottom,
+ then current block is the function block */
+ uint32 depth = ctx->frame_csp > ctx->frame_csp_bottom ? 1 : 0;
+ BranchBlock *cur_block = ctx->frame_csp - depth;
+ int32 available_stack_cell =
+ (int32)(ctx->stack_cell_num - cur_block->stack_cell_num);
+
+ /* Directly return success if current block is in stack
+ * polymorphic state while stack is empty. */
+ if (available_stack_cell <= 0 && cur_block->is_stack_polymorphic)
+ return true;
+
+ if (type == VALUE_TYPE_VOID)
+ return true;
+
+ if (is_32bit_type(type)) {
+ /* Check the offset stack bottom to ensure the frame offset
+ stack will not go underflow. But we don't thrown error
+ and return true here, because the error msg should be
+ given in wasm_loader_pop_frame_ref */
+ if (!check_offset_pop(ctx, 1))
+ return true;
+
+ ctx->frame_offset -= 1;
+ if ((*(ctx->frame_offset) > ctx->start_dynamic_offset)
+ && (*(ctx->frame_offset) < ctx->max_dynamic_offset))
+ ctx->dynamic_offset -= 1;
+ }
+ else {
+ if (!check_offset_pop(ctx, 2))
+ return true;
+
+ ctx->frame_offset -= 2;
+ if ((*(ctx->frame_offset) > ctx->start_dynamic_offset)
+ && (*(ctx->frame_offset) < ctx->max_dynamic_offset))
+ ctx->dynamic_offset -= 2;
+ }
+ emit_operand(ctx, *(ctx->frame_offset));
+ return true;
+}
+
+static bool
+wasm_loader_push_pop_frame_offset(WASMLoaderContext *ctx, uint8 pop_cnt,
+ uint8 type_push, uint8 type_pop,
+ bool disable_emit, int16 operand_offset,
+ char *error_buf, uint32 error_buf_size)
+{
+ for (int i = 0; i < pop_cnt; i++) {
+ if (!wasm_loader_pop_frame_offset(ctx, type_pop, error_buf,
+ error_buf_size))
+ return false;
+ }
+ if (!wasm_loader_push_frame_offset(ctx, type_push, disable_emit,
+ operand_offset, error_buf,
+ error_buf_size))
+ return false;
+
+ return true;
+}
+
+static bool
+wasm_loader_push_frame_ref_offset(WASMLoaderContext *ctx, uint8 type,
+ bool disable_emit, int16 operand_offset,
+ char *error_buf, uint32 error_buf_size)
+{
+ if (!(wasm_loader_push_frame_offset(ctx, type, disable_emit, operand_offset,
+ error_buf, error_buf_size)))
+ return false;
+ if (!(wasm_loader_push_frame_ref(ctx, type, error_buf, error_buf_size)))
+ return false;
+
+ return true;
+}
+
+static bool
+wasm_loader_pop_frame_ref_offset(WASMLoaderContext *ctx, uint8 type,
+ char *error_buf, uint32 error_buf_size)
+{
+ /* put wasm_loader_pop_frame_offset in front of wasm_loader_pop_frame_ref */
+ if (!wasm_loader_pop_frame_offset(ctx, type, error_buf, error_buf_size))
+ return false;
+ if (!wasm_loader_pop_frame_ref(ctx, type, error_buf, error_buf_size))
+ return false;
+
+ return true;
+}
+
+static bool
+wasm_loader_push_pop_frame_ref_offset(WASMLoaderContext *ctx, uint8 pop_cnt,
+ uint8 type_push, uint8 type_pop,
+ bool disable_emit, int16 operand_offset,
+ char *error_buf, uint32 error_buf_size)
+{
+ if (!wasm_loader_push_pop_frame_offset(ctx, pop_cnt, type_push, type_pop,
+ disable_emit, operand_offset,
+ error_buf, error_buf_size))
+ return false;
+ if (!wasm_loader_push_pop_frame_ref(ctx, pop_cnt, type_push, type_pop,
+ error_buf, error_buf_size))
+ return false;
+
+ return true;
+}
+
+static bool
+wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, void *value,
+ int16 *offset, char *error_buf,
+ uint32 error_buf_size)
+{
+ int8 bytes_to_increase;
+ int16 operand_offset = 0;
+ Const *c;
+
+ /* Search existing constant */
+ for (c = (Const *)ctx->const_buf;
+ (uint8 *)c < ctx->const_buf + ctx->num_const * sizeof(Const); c++) {
+ if ((type == c->value_type)
+ && ((type == VALUE_TYPE_I64 && *(int64 *)value == c->value.i64)
+ || (type == VALUE_TYPE_I32 && *(int32 *)value == c->value.i32)
+#if WASM_ENABLE_REF_TYPES != 0
+ || (type == VALUE_TYPE_FUNCREF
+ && *(int32 *)value == c->value.i32)
+ || (type == VALUE_TYPE_EXTERNREF
+ && *(int32 *)value == c->value.i32)
+#endif
+ || (type == VALUE_TYPE_F64
+ && (0 == memcmp(value, &(c->value.f64), sizeof(float64))))
+ || (type == VALUE_TYPE_F32
+ && (0
+ == memcmp(value, &(c->value.f32), sizeof(float32)))))) {
+ operand_offset = c->slot_index;
+ break;
+ }
+ if (c->value_type == VALUE_TYPE_I64 || c->value_type == VALUE_TYPE_F64)
+ operand_offset += 2;
+ else
+ operand_offset += 1;
+ }
+
+ if ((uint8 *)c == ctx->const_buf + ctx->num_const * sizeof(Const)) {
+ /* New constant, append to the const buffer */
+ if ((type == VALUE_TYPE_F64) || (type == VALUE_TYPE_I64)) {
+ bytes_to_increase = 2;
+ }
+ else {
+ bytes_to_increase = 1;
+ }
+
+ /* The max cell num of const buffer is 32768 since the valid index range
+ * is -32768 ~ -1. Return an invalid index 0 to indicate the buffer is
+ * full */
+ if (ctx->const_cell_num > INT16_MAX - bytes_to_increase + 1) {
+ *offset = 0;
+ return true;
+ }
+
+ if ((uint8 *)c == ctx->const_buf + ctx->const_buf_size) {
+ MEM_REALLOC(ctx->const_buf, ctx->const_buf_size,
+ ctx->const_buf_size + 4 * sizeof(Const));
+ ctx->const_buf_size += 4 * sizeof(Const);
+ c = (Const *)(ctx->const_buf + ctx->num_const * sizeof(Const));
+ }
+ c->value_type = type;
+ switch (type) {
+ case VALUE_TYPE_F64:
+ bh_memcpy_s(&(c->value.f64), sizeof(WASMValue), value,
+ sizeof(float64));
+ ctx->const_cell_num += 2;
+ /* The const buf will be reversed, we use the second cell */
+ /* of the i64/f64 const so the finnal offset is corrent */
+ operand_offset++;
+ break;
+ case VALUE_TYPE_I64:
+ c->value.i64 = *(int64 *)value;
+ ctx->const_cell_num += 2;
+ operand_offset++;
+ break;
+ case VALUE_TYPE_F32:
+ bh_memcpy_s(&(c->value.f32), sizeof(WASMValue), value,
+ sizeof(float32));
+ ctx->const_cell_num++;
+ break;
+ case VALUE_TYPE_I32:
+ c->value.i32 = *(int32 *)value;
+ ctx->const_cell_num++;
+ break;
+#if WASM_ENABLE_REF_TYPES != 0
+ case VALUE_TYPE_EXTERNREF:
+ case VALUE_TYPE_FUNCREF:
+ c->value.i32 = *(int32 *)value;
+ ctx->const_cell_num++;
+ break;
+#endif
+ default:
+ break;
+ }
+ c->slot_index = operand_offset;
+ ctx->num_const++;
+ LOG_OP("#### new const [%d]: %ld\n", ctx->num_const,
+ (int64)c->value.i64);
+ }
+ /* use negetive index for const */
+ operand_offset = -(operand_offset + 1);
+ *offset = operand_offset;
+ return true;
+fail:
+ return false;
+}
+
+/*
+ PUSH(POP)_XXX = push(pop) frame_ref + push(pop) frame_offset
+ -- Mostly used for the binary / compare operation
+ PUSH(POP)_OFFSET_TYPE only push(pop) the frame_offset stack
+ -- Mostly used in block / control instructions
+
+ The POP will always emit the offset on the top of the frame_offset stack
+ PUSH can be used in two ways:
+ 1. directly PUSH:
+ PUSH_XXX();
+ will allocate a dynamic space and emit
+ 2. silent PUSH:
+ operand_offset = xxx; disable_emit = true;
+ PUSH_XXX();
+ only push the frame_offset stack, no emit
+*/
+#define PUSH_I32() \
+ do { \
+ if (!wasm_loader_push_frame_ref_offset(loader_ctx, VALUE_TYPE_I32, \
+ disable_emit, operand_offset, \
+ error_buf, error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define PUSH_F32() \
+ do { \
+ if (!wasm_loader_push_frame_ref_offset(loader_ctx, VALUE_TYPE_F32, \
+ disable_emit, operand_offset, \
+ error_buf, error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define PUSH_I64() \
+ do { \
+ if (!wasm_loader_push_frame_ref_offset(loader_ctx, VALUE_TYPE_I64, \
+ disable_emit, operand_offset, \
+ error_buf, error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define PUSH_F64() \
+ do { \
+ if (!wasm_loader_push_frame_ref_offset(loader_ctx, VALUE_TYPE_F64, \
+ disable_emit, operand_offset, \
+ error_buf, error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define PUSH_FUNCREF() \
+ do { \
+ if (!wasm_loader_push_frame_ref_offset(loader_ctx, VALUE_TYPE_FUNCREF, \
+ disable_emit, operand_offset, \
+ error_buf, error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define POP_I32() \
+ do { \
+ if (!wasm_loader_pop_frame_ref_offset(loader_ctx, VALUE_TYPE_I32, \
+ error_buf, error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define POP_F32() \
+ do { \
+ if (!wasm_loader_pop_frame_ref_offset(loader_ctx, VALUE_TYPE_F32, \
+ error_buf, error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define POP_I64() \
+ do { \
+ if (!wasm_loader_pop_frame_ref_offset(loader_ctx, VALUE_TYPE_I64, \
+ error_buf, error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define POP_F64() \
+ do { \
+ if (!wasm_loader_pop_frame_ref_offset(loader_ctx, VALUE_TYPE_F64, \
+ error_buf, error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define PUSH_OFFSET_TYPE(type) \
+ do { \
+ if (!(wasm_loader_push_frame_offset(loader_ctx, type, disable_emit, \
+ operand_offset, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define POP_OFFSET_TYPE(type) \
+ do { \
+ if (!(wasm_loader_pop_frame_offset(loader_ctx, type, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define POP_AND_PUSH(type_pop, type_push) \
+ do { \
+ if (!(wasm_loader_push_pop_frame_ref_offset( \
+ loader_ctx, 1, type_push, type_pop, disable_emit, \
+ operand_offset, error_buf, error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+/* type of POPs should be the same */
+#define POP2_AND_PUSH(type_pop, type_push) \
+ do { \
+ if (!(wasm_loader_push_pop_frame_ref_offset( \
+ loader_ctx, 2, type_push, type_pop, disable_emit, \
+ operand_offset, error_buf, error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#else /* WASM_ENABLE_FAST_INTERP */
+
+#define PUSH_I32() \
+ do { \
+ if (!(wasm_loader_push_frame_ref(loader_ctx, VALUE_TYPE_I32, \
+ error_buf, error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define PUSH_F32() \
+ do { \
+ if (!(wasm_loader_push_frame_ref(loader_ctx, VALUE_TYPE_F32, \
+ error_buf, error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define PUSH_I64() \
+ do { \
+ if (!(wasm_loader_push_frame_ref(loader_ctx, VALUE_TYPE_I64, \
+ error_buf, error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define PUSH_F64() \
+ do { \
+ if (!(wasm_loader_push_frame_ref(loader_ctx, VALUE_TYPE_F64, \
+ error_buf, error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define PUSH_FUNCREF() \
+ do { \
+ if (!(wasm_loader_push_frame_ref(loader_ctx, VALUE_TYPE_FUNCREF, \
+ error_buf, error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define POP_I32() \
+ do { \
+ if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_I32, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define POP_F32() \
+ do { \
+ if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_F32, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define POP_I64() \
+ do { \
+ if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_I64, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define POP_F64() \
+ do { \
+ if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_F64, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define POP_FUNCREF() \
+ do { \
+ if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_FUNCREF, \
+ error_buf, error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define POP_AND_PUSH(type_pop, type_push) \
+ do { \
+ if (!(wasm_loader_push_pop_frame_ref(loader_ctx, 1, type_push, \
+ type_pop, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+/* type of POPs should be the same */
+#define POP2_AND_PUSH(type_pop, type_push) \
+ do { \
+ if (!(wasm_loader_push_pop_frame_ref(loader_ctx, 2, type_push, \
+ type_pop, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+#endif /* WASM_ENABLE_FAST_INTERP */
+
+#if WASM_ENABLE_FAST_INTERP != 0
+
+static bool
+reserve_block_ret(WASMLoaderContext *loader_ctx, uint8 opcode,
+ bool disable_emit, char *error_buf, uint32 error_buf_size)
+{
+ int16 operand_offset = 0;
+ BranchBlock *block = (opcode == WASM_OP_ELSE) ? loader_ctx->frame_csp - 1
+ : loader_ctx->frame_csp;
+ BlockType *block_type = &block->block_type;
+ uint8 *return_types = NULL;
+ uint32 return_count = 0, value_count = 0, total_cel_num = 0;
+ int32 i = 0;
+ int16 dynamic_offset, dynamic_offset_org, *frame_offset = NULL,
+ *frame_offset_org = NULL;
+
+ return_count = block_type_get_result_types(block_type, &return_types);
+
+ /* If there is only one return value, use EXT_OP_COPY_STACK_TOP/_I64 instead
+ * of EXT_OP_COPY_STACK_VALUES for interpreter performance. */
+ if (return_count == 1) {
+ uint8 cell = (uint8)wasm_value_type_cell_num(return_types[0]);
+ if (cell <= 2 /* V128 isn't supported whose cell num is 4 */
+ && block->dynamic_offset != *(loader_ctx->frame_offset - cell)) {
+ /* insert op_copy before else opcode */
+ if (opcode == WASM_OP_ELSE)
+ skip_label();
+ emit_label(cell == 1 ? EXT_OP_COPY_STACK_TOP
+ : EXT_OP_COPY_STACK_TOP_I64);
+ emit_operand(loader_ctx, *(loader_ctx->frame_offset - cell));
+ emit_operand(loader_ctx, block->dynamic_offset);
+
+ if (opcode == WASM_OP_ELSE) {
+ *(loader_ctx->frame_offset - cell) = block->dynamic_offset;
+ }
+ else {
+ loader_ctx->frame_offset -= cell;
+ loader_ctx->dynamic_offset = block->dynamic_offset;
+ PUSH_OFFSET_TYPE(return_types[0]);
+ wasm_loader_emit_backspace(loader_ctx, sizeof(int16));
+ }
+ if (opcode == WASM_OP_ELSE)
+ emit_label(opcode);
+ }
+ return true;
+ }
+
+ /* Copy stack top values to block's results which are in dynamic space.
+ * The instruction format:
+ * Part a: values count
+ * Part b: all values total cell num
+ * Part c: each value's cell_num, src offset and dst offset
+ * Part d: each value's src offset and dst offset
+ * Part e: each value's dst offset
+ */
+ frame_offset = frame_offset_org = loader_ctx->frame_offset;
+ dynamic_offset = dynamic_offset_org =
+ block->dynamic_offset + wasm_get_cell_num(return_types, return_count);
+
+ /* First traversal to get the count of values needed to be copied. */
+ for (i = (int32)return_count - 1; i >= 0; i--) {
+ uint8 cells = (uint8)wasm_value_type_cell_num(return_types[i]);
+
+ frame_offset -= cells;
+ dynamic_offset -= cells;
+ if (dynamic_offset != *frame_offset) {
+ value_count++;
+ total_cel_num += cells;
+ }
+ }
+
+ if (value_count) {
+ uint32 j = 0;
+ uint8 *emit_data = NULL, *cells = NULL;
+ int16 *src_offsets = NULL;
+ uint16 *dst_offsets = NULL;
+ uint64 size =
+ (uint64)value_count
+ * (sizeof(*cells) + sizeof(*src_offsets) + sizeof(*dst_offsets));
+
+ /* Allocate memory for the emit data */
+ if (!(emit_data = loader_malloc(size, error_buf, error_buf_size)))
+ return false;
+
+ cells = emit_data;
+ src_offsets = (int16 *)(cells + value_count);
+ dst_offsets = (uint16 *)(src_offsets + value_count);
+
+ /* insert op_copy before else opcode */
+ if (opcode == WASM_OP_ELSE)
+ skip_label();
+ emit_label(EXT_OP_COPY_STACK_VALUES);
+ /* Part a) */
+ emit_uint32(loader_ctx, value_count);
+ /* Part b) */
+ emit_uint32(loader_ctx, total_cel_num);
+
+ /* Second traversal to get each value's cell num, src offset and dst
+ * offset. */
+ frame_offset = frame_offset_org;
+ dynamic_offset = dynamic_offset_org;
+ for (i = (int32)return_count - 1, j = 0; i >= 0; i--) {
+ uint8 cell = (uint8)wasm_value_type_cell_num(return_types[i]);
+ frame_offset -= cell;
+ dynamic_offset -= cell;
+ if (dynamic_offset != *frame_offset) {
+ /* cell num */
+ cells[j] = cell;
+ /* src offset */
+ src_offsets[j] = *frame_offset;
+ /* dst offset */
+ dst_offsets[j] = dynamic_offset;
+ j++;
+ }
+ if (opcode == WASM_OP_ELSE) {
+ *frame_offset = dynamic_offset;
+ }
+ else {
+ loader_ctx->frame_offset = frame_offset;
+ loader_ctx->dynamic_offset = dynamic_offset;
+ PUSH_OFFSET_TYPE(return_types[i]);
+ wasm_loader_emit_backspace(loader_ctx, sizeof(int16));
+ loader_ctx->frame_offset = frame_offset_org;
+ loader_ctx->dynamic_offset = dynamic_offset_org;
+ }
+ }
+
+ bh_assert(j == value_count);
+
+ /* Emit the cells, src_offsets and dst_offsets */
+ for (j = 0; j < value_count; j++)
+ emit_byte(loader_ctx, cells[j]);
+ for (j = 0; j < value_count; j++)
+ emit_operand(loader_ctx, src_offsets[j]);
+ for (j = 0; j < value_count; j++)
+ emit_operand(loader_ctx, dst_offsets[j]);
+
+ if (opcode == WASM_OP_ELSE)
+ emit_label(opcode);
+
+ wasm_runtime_free(emit_data);
+ }
+
+ return true;
+
+fail:
+ return false;
+}
+
+#endif /* WASM_ENABLE_FAST_INTERP */
+
+#define RESERVE_BLOCK_RET() \
+ do { \
+ if (!reserve_block_ret(loader_ctx, opcode, disable_emit, error_buf, \
+ error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define PUSH_TYPE(type) \
+ do { \
+ if (!(wasm_loader_push_frame_ref(loader_ctx, type, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define POP_TYPE(type) \
+ do { \
+ if (!(wasm_loader_pop_frame_ref(loader_ctx, type, error_buf, \
+ error_buf_size))) \
+ goto fail; \
+ } while (0)
+
+#define PUSH_CSP(label_type, block_type, _start_addr) \
+ do { \
+ if (!wasm_loader_push_frame_csp(loader_ctx, label_type, block_type, \
+ _start_addr, error_buf, \
+ error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define POP_CSP() \
+ do { \
+ if (!wasm_loader_pop_frame_csp(loader_ctx, error_buf, error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define GET_LOCAL_INDEX_TYPE_AND_OFFSET() \
+ do { \
+ read_leb_uint32(p, p_end, local_idx); \
+ bh_assert(local_idx < param_count + local_count); \
+ local_type = local_idx < param_count \
+ ? param_types[local_idx] \
+ : local_types[local_idx - param_count]; \
+ local_offset = local_offsets[local_idx]; \
+ } while (0)
+
+#define CHECK_BR(depth) \
+ do { \
+ if (!wasm_loader_check_br(loader_ctx, depth, error_buf, \
+ error_buf_size)) \
+ goto fail; \
+ } while (0)
+
+#define CHECK_MEMORY() \
+ do { \
+ bh_assert(module->import_memory_count + module->memory_count > 0); \
+ } while (0)
+
+static bool
+wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth,
+ char *error_buf, uint32 error_buf_size)
+{
+ BranchBlock *target_block, *cur_block;
+ BlockType *target_block_type;
+ uint8 *types = NULL, *frame_ref;
+ uint32 arity = 0;
+ int32 i, available_stack_cell;
+ uint16 cell_num;
+
+ if (loader_ctx->csp_num < depth + 1) {
+ set_error_buf(error_buf, error_buf_size,
+ "unknown label, "
+ "unexpected end of section or function");
+ return false;
+ }
+
+ cur_block = loader_ctx->frame_csp - 1;
+ target_block = loader_ctx->frame_csp - (depth + 1);
+ target_block_type = &target_block->block_type;
+ frame_ref = loader_ctx->frame_ref;
+
+ /* Note: loop's arity is different from if and block. loop's arity is
+ * its parameter count while if and block arity is result count.
+ */
+ if (target_block->label_type == LABEL_TYPE_LOOP)
+ arity = block_type_get_param_types(target_block_type, &types);
+ else
+ arity = block_type_get_result_types(target_block_type, &types);
+
+ /* If the stack is in polymorphic state, just clear the stack
+ * and then re-push the values to make the stack top values
+ * match block type. */
+ if (cur_block->is_stack_polymorphic) {
+ for (i = (int32)arity - 1; i >= 0; i--) {
+#if WASM_ENABLE_FAST_INTERP != 0
+ POP_OFFSET_TYPE(types[i]);
+#endif
+ POP_TYPE(types[i]);
+ }
+ for (i = 0; i < (int32)arity; i++) {
+#if WASM_ENABLE_FAST_INTERP != 0
+ bool disable_emit = true;
+ int16 operand_offset = 0;
+ PUSH_OFFSET_TYPE(types[i]);
+#endif
+ PUSH_TYPE(types[i]);
+ }
+ return true;
+ }
+
+ available_stack_cell =
+ (int32)(loader_ctx->stack_cell_num - cur_block->stack_cell_num);
+
+ /* Check stack top values match target block type */
+ for (i = (int32)arity - 1; i >= 0; i--) {
+ if (!check_stack_top_values(frame_ref, available_stack_cell, types[i],
+ error_buf, error_buf_size))
+ return false;
+ cell_num = wasm_value_type_cell_num(types[i]);
+ frame_ref -= cell_num;
+ available_stack_cell -= cell_num;
+ }
+
+ return true;
+
+fail:
+ return false;
+}
+
+static BranchBlock *
+check_branch_block(WASMLoaderContext *loader_ctx, uint8 **p_buf, uint8 *buf_end,
+ char *error_buf, uint32 error_buf_size)
+{
+ uint8 *p = *p_buf, *p_end = buf_end;
+ BranchBlock *frame_csp_tmp;
+ uint32 depth;
+
+ read_leb_uint32(p, p_end, depth);
+ CHECK_BR(depth);
+ frame_csp_tmp = loader_ctx->frame_csp - depth - 1;
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_br_info(frame_csp_tmp);
+#endif
+
+ *p_buf = p;
+ return frame_csp_tmp;
+fail:
+ return NULL;
+}
+
+static bool
+check_block_stack(WASMLoaderContext *loader_ctx, BranchBlock *block,
+ char *error_buf, uint32 error_buf_size)
+{
+ BlockType *block_type = &block->block_type;
+ uint8 *return_types = NULL;
+ uint32 return_count = 0;
+ int32 available_stack_cell, return_cell_num, i;
+ uint8 *frame_ref = NULL;
+
+ available_stack_cell =
+ (int32)(loader_ctx->stack_cell_num - block->stack_cell_num);
+
+ return_count = block_type_get_result_types(block_type, &return_types);
+ return_cell_num =
+ return_count > 0 ? wasm_get_cell_num(return_types, return_count) : 0;
+
+ /* If the stack is in polymorphic state, just clear the stack
+ * and then re-push the values to make the stack top values
+ * match block type. */
+ if (block->is_stack_polymorphic) {
+ for (i = (int32)return_count - 1; i >= 0; i--) {
+#if WASM_ENABLE_FAST_INTERP != 0
+ POP_OFFSET_TYPE(return_types[i]);
+#endif
+ POP_TYPE(return_types[i]);
+ }
+
+ /* Check stack is empty */
+ bh_assert(loader_ctx->stack_cell_num == block->stack_cell_num);
+
+ for (i = 0; i < (int32)return_count; i++) {
+#if WASM_ENABLE_FAST_INTERP != 0
+ bool disable_emit = true;
+ int16 operand_offset = 0;
+ PUSH_OFFSET_TYPE(return_types[i]);
+#endif
+ PUSH_TYPE(return_types[i]);
+ }
+ return true;
+ }
+
+ /* Check stack cell num equals return cell num */
+ bh_assert(available_stack_cell == return_cell_num);
+
+ /* Check stack values match return types */
+ frame_ref = loader_ctx->frame_ref;
+ for (i = (int32)return_count - 1; i >= 0; i--) {
+ if (!check_stack_top_values(frame_ref, available_stack_cell,
+ return_types[i], error_buf, error_buf_size))
+ return false;
+ frame_ref -= wasm_value_type_cell_num(return_types[i]);
+ available_stack_cell -= wasm_value_type_cell_num(return_types[i]);
+ }
+
+ (void)return_cell_num;
+ return true;
+
+fail:
+ return false;
+}
+
+#if WASM_ENABLE_FAST_INTERP != 0
+/* Copy parameters to dynamic space.
+ * 1) POP original parameter out;
+ * 2) Push and copy original values to dynamic space.
+ * The copy instruction format:
+ * Part a: param count
+ * Part b: all param total cell num
+ * Part c: each param's cell_num, src offset and dst offset
+ * Part d: each param's src offset
+ * Part e: each param's dst offset
+ */
+static bool
+copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
+ char *error_buf, uint32 error_buf_size)
+{
+ int16 *frame_offset = NULL;
+ uint8 *cells = NULL, cell;
+ int16 *src_offsets = NULL;
+ uint8 *emit_data = NULL;
+ uint32 i;
+ BranchBlock *block = loader_ctx->frame_csp - 1;
+ BlockType *block_type = &block->block_type;
+ WASMType *wasm_type = block_type->u.type;
+ uint32 param_count = block_type->u.type->param_count;
+ int16 condition_offset = 0;
+ bool disable_emit = false;
+ int16 operand_offset = 0;
+
+ uint64 size = (uint64)param_count * (sizeof(*cells) + sizeof(*src_offsets));
+
+ /* For if block, we also need copy the condition operand offset. */
+ if (is_if_block)
+ size += sizeof(*cells) + sizeof(*src_offsets);
+
+ /* Allocate memory for the emit data */
+ if (!(emit_data = loader_malloc(size, error_buf, error_buf_size)))
+ return false;
+
+ cells = emit_data;
+ src_offsets = (int16 *)(cells + param_count);
+
+ if (is_if_block)
+ condition_offset = *loader_ctx->frame_offset;
+
+ /* POP original parameter out */
+ for (i = 0; i < param_count; i++) {
+ POP_OFFSET_TYPE(wasm_type->types[param_count - i - 1]);
+ wasm_loader_emit_backspace(loader_ctx, sizeof(int16));
+ }
+ frame_offset = loader_ctx->frame_offset;
+
+ /* Get each param's cell num and src offset */
+ for (i = 0; i < param_count; i++) {
+ cell = (uint8)wasm_value_type_cell_num(wasm_type->types[i]);
+ cells[i] = cell;
+ src_offsets[i] = *frame_offset;
+ frame_offset += cell;
+ }
+
+ /* emit copy instruction */
+ emit_label(EXT_OP_COPY_STACK_VALUES);
+ /* Part a) */
+ emit_uint32(loader_ctx, is_if_block ? param_count + 1 : param_count);
+ /* Part b) */
+ emit_uint32(loader_ctx, is_if_block ? wasm_type->param_cell_num + 1
+ : wasm_type->param_cell_num);
+ /* Part c) */
+ for (i = 0; i < param_count; i++)
+ emit_byte(loader_ctx, cells[i]);
+ if (is_if_block)
+ emit_byte(loader_ctx, 1);
+
+ /* Part d) */
+ for (i = 0; i < param_count; i++)
+ emit_operand(loader_ctx, src_offsets[i]);
+ if (is_if_block)
+ emit_operand(loader_ctx, condition_offset);
+
+ /* Part e) */
+ /* Push to dynamic space. The push will emit the dst offset. */
+ for (i = 0; i < param_count; i++)
+ PUSH_OFFSET_TYPE(wasm_type->types[i]);
+ if (is_if_block)
+ PUSH_OFFSET_TYPE(VALUE_TYPE_I32);
+
+ /* Free the emit data */
+ wasm_runtime_free(emit_data);
+ return true;
+
+fail:
+ /* Free the emit data */
+ wasm_runtime_free(emit_data);
+ return false;
+}
+#endif
+
+/* reset the stack to the state of before entering the last block */
+#if WASM_ENABLE_FAST_INTERP != 0
+#define RESET_STACK() \
+ do { \
+ loader_ctx->stack_cell_num = \
+ (loader_ctx->frame_csp - 1)->stack_cell_num; \
+ loader_ctx->frame_ref = \
+ loader_ctx->frame_ref_bottom + loader_ctx->stack_cell_num; \
+ loader_ctx->frame_offset = \
+ loader_ctx->frame_offset_bottom + loader_ctx->stack_cell_num; \
+ } while (0)
+#else
+#define RESET_STACK() \
+ do { \
+ loader_ctx->stack_cell_num = \
+ (loader_ctx->frame_csp - 1)->stack_cell_num; \
+ loader_ctx->frame_ref = \
+ loader_ctx->frame_ref_bottom + loader_ctx->stack_cell_num; \
+ } while (0)
+#endif
+
+/* set current block's stack polymorphic state */
+#define SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(flag) \
+ do { \
+ BranchBlock *_cur_block = loader_ctx->frame_csp - 1; \
+ _cur_block->is_stack_polymorphic = flag; \
+ } while (0)
+
+#define BLOCK_HAS_PARAM(block_type) \
+ (!block_type.is_value_type && block_type.u.type->param_count > 0)
+
+#define PRESERVE_LOCAL_FOR_BLOCK() \
+ do { \
+ if (!(preserve_local_for_block(loader_ctx, opcode, error_buf, \
+ error_buf_size))) { \
+ goto fail; \
+ } \
+ } while (0)
+
+static bool
+wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
+ uint32 cur_func_idx, char *error_buf,
+ uint32 error_buf_size)
+{
+ uint8 *p = func->code, *p_end = func->code + func->code_size, *p_org;
+ uint32 param_count, local_count, global_count;
+ uint8 *param_types, *local_types, local_type, global_type;
+ BlockType func_block_type;
+ uint16 *local_offsets, local_offset;
+ uint32 count, local_idx, global_idx, u32, align, mem_offset, i;
+ int32 i32, i32_const = 0;
+ int64 i64_const;
+ uint8 opcode, u8;
+ bool return_value = false;
+ WASMLoaderContext *loader_ctx;
+ BranchBlock *frame_csp_tmp;
+#if WASM_ENABLE_BULK_MEMORY != 0
+ uint32 segment_index;
+#endif
+#if WASM_ENABLE_FAST_INTERP != 0
+ uint8 *func_const_end, *func_const = NULL;
+ int16 operand_offset = 0;
+ uint8 last_op = 0;
+ bool disable_emit, preserve_local = false;
+ float32 f32_const;
+ float64 f64_const;
+
+ LOG_OP("\nProcessing func | [%d] params | [%d] locals | [%d] return\n",
+ func->param_cell_num, func->local_cell_num, func->ret_cell_num);
+#endif
+
+ global_count = module->import_global_count + module->global_count;
+
+ param_count = func->func_type->param_count;
+ param_types = func->func_type->types;
+
+ func_block_type.is_value_type = false;
+ func_block_type.u.type = func->func_type;
+
+ local_count = func->local_count;
+ local_types = func->local_types;
+ local_offsets = func->local_offsets;
+
+ if (!(loader_ctx = wasm_loader_ctx_init(func, error_buf, error_buf_size))) {
+ goto fail;
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* For the first traverse, the initial value of preserved_local_offset has
+ * not been determined, we use the INT16_MAX to represent that a slot has
+ * been copied to preserve space. For second traverse, this field will be
+ * set to the appropriate value in wasm_loader_ctx_reinit.
+ * This is for Issue #1230,
+ * https://github.com/bytecodealliance/wasm-micro-runtime/issues/1230, the
+ * drop opcodes need to know which slots are preserved, so those slots will
+ * not be treated as dynamically allocated slots */
+ loader_ctx->preserved_local_offset = INT16_MAX;
+
+re_scan:
+ if (loader_ctx->code_compiled_size > 0) {
+ if (!wasm_loader_ctx_reinit(loader_ctx)) {
+ set_error_buf(error_buf, error_buf_size, "allocate memory failed");
+ goto fail;
+ }
+ p = func->code;
+ func->code_compiled = loader_ctx->p_code_compiled;
+ func->code_compiled_size = loader_ctx->code_compiled_size;
+ }
+#endif
+
+ PUSH_CSP(LABEL_TYPE_FUNCTION, func_block_type, p);
+
+ while (p < p_end) {
+ opcode = *p++;
+#if WASM_ENABLE_FAST_INTERP != 0
+ p_org = p;
+ disable_emit = false;
+ emit_label(opcode);
+#endif
+
+ switch (opcode) {
+ case WASM_OP_UNREACHABLE:
+ RESET_STACK();
+ SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
+ break;
+
+ case WASM_OP_NOP:
+#if WASM_ENABLE_FAST_INTERP != 0
+ skip_label();
+#endif
+ break;
+
+ case WASM_OP_IF:
+#if WASM_ENABLE_FAST_INTERP != 0
+ PRESERVE_LOCAL_FOR_BLOCK();
+#endif
+ POP_I32();
+ goto handle_op_block_and_loop;
+ case WASM_OP_BLOCK:
+ case WASM_OP_LOOP:
+#if WASM_ENABLE_FAST_INTERP != 0
+ PRESERVE_LOCAL_FOR_BLOCK();
+#endif
+ handle_op_block_and_loop:
+ {
+ uint8 value_type;
+ BlockType block_type;
+
+ p_org = p - 1;
+ value_type = read_uint8(p);
+ if (is_byte_a_type(value_type)) {
+ /* If the first byte is one of these special values:
+ * 0x40/0x7F/0x7E/0x7D/0x7C, take it as the type of
+ * the single return value. */
+ block_type.is_value_type = true;
+ block_type.u.value_type = value_type;
+ }
+ else {
+ uint32 type_index;
+ /* Resolve the leb128 encoded type index as block type */
+ p--;
+ read_leb_uint32(p, p_end, type_index);
+ bh_assert(type_index < module->type_count);
+ block_type.is_value_type = false;
+ block_type.u.type = module->types[type_index];
+#if WASM_ENABLE_FAST_INTERP == 0
+ /* If block use type index as block type, change the opcode
+ * to new extended opcode so that interpreter can resolve
+ * the block quickly.
+ */
+ *p_org = EXT_OP_BLOCK + (opcode - WASM_OP_BLOCK);
+#endif
+ }
+
+ /* Pop block parameters from stack */
+ if (BLOCK_HAS_PARAM(block_type)) {
+ WASMType *wasm_type = block_type.u.type;
+ for (i = 0; i < block_type.u.type->param_count; i++)
+ POP_TYPE(
+ wasm_type->types[wasm_type->param_count - i - 1]);
+ }
+
+ PUSH_CSP(LABEL_TYPE_BLOCK + (opcode - WASM_OP_BLOCK),
+ block_type, p);
+
+ /* Pass parameters to block */
+ if (BLOCK_HAS_PARAM(block_type)) {
+ for (i = 0; i < block_type.u.type->param_count; i++)
+ PUSH_TYPE(block_type.u.type->types[i]);
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ if (opcode == WASM_OP_BLOCK) {
+ skip_label();
+ }
+ else if (opcode == WASM_OP_LOOP) {
+ skip_label();
+ if (BLOCK_HAS_PARAM(block_type)) {
+ /* Make sure params are in dynamic space */
+ if (!copy_params_to_dynamic_space(
+ loader_ctx, false, error_buf, error_buf_size))
+ goto fail;
+ }
+ (loader_ctx->frame_csp - 1)->code_compiled =
+ loader_ctx->p_code_compiled;
+ }
+ else if (opcode == WASM_OP_IF) {
+ /* If block has parameters, we should make sure they are in
+ * dynamic space. Otherwise, when else branch is missing,
+ * the later opcode may consume incorrect operand offset.
+ * Spec case:
+ * (func (export "params-id") (param i32) (result i32)
+ * (i32.const 1)
+ * (i32.const 2)
+ * (if (param i32 i32) (result i32 i32) (local.get 0)
+ * (then)) (i32.add)
+ * )
+ *
+ * So we should emit a copy instruction before the if.
+ *
+ * And we also need to save the parameter offsets and
+ * recover them before entering else branch.
+ *
+ */
+ if (BLOCK_HAS_PARAM(block_type)) {
+ BranchBlock *block = loader_ctx->frame_csp - 1;
+ uint64 size;
+
+ /* skip the if condition operand offset */
+ wasm_loader_emit_backspace(loader_ctx, sizeof(int16));
+ /* skip the if label */
+ skip_label();
+ /* Emit a copy instruction */
+ if (!copy_params_to_dynamic_space(
+ loader_ctx, true, error_buf, error_buf_size))
+ goto fail;
+
+ /* Emit the if instruction */
+ emit_label(opcode);
+ /* Emit the new condition operand offset */
+ POP_OFFSET_TYPE(VALUE_TYPE_I32);
+
+ /* Save top param_count values of frame_offset stack, so
+ * that we can recover it before executing else branch
+ */
+ size = sizeof(int16)
+ * (uint64)block_type.u.type->param_cell_num;
+ if (!(block->param_frame_offsets = loader_malloc(
+ size, error_buf, error_buf_size)))
+ goto fail;
+ bh_memcpy_s(block->param_frame_offsets, (uint32)size,
+ loader_ctx->frame_offset
+ - size / sizeof(int16),
+ (uint32)size);
+ }
+
+ emit_empty_label_addr_and_frame_ip(PATCH_ELSE);
+ emit_empty_label_addr_and_frame_ip(PATCH_END);
+ }
+#endif
+ break;
+ }
+
+ case WASM_OP_ELSE:
+ {
+ BlockType block_type = (loader_ctx->frame_csp - 1)->block_type;
+ bh_assert(loader_ctx->csp_num >= 2
+ && (loader_ctx->frame_csp - 1)->label_type
+ == LABEL_TYPE_IF);
+
+ /* check whether if branch's stack matches its result type */
+ if (!check_block_stack(loader_ctx, loader_ctx->frame_csp - 1,
+ error_buf, error_buf_size))
+ goto fail;
+
+ (loader_ctx->frame_csp - 1)->else_addr = p - 1;
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* if the result of if branch is in local or const area, add a
+ * copy op */
+ RESERVE_BLOCK_RET();
+
+ emit_empty_label_addr_and_frame_ip(PATCH_END);
+ apply_label_patch(loader_ctx, 1, PATCH_ELSE);
+#endif
+ RESET_STACK();
+ SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(false);
+
+ /* Pass parameters to if-false branch */
+ if (BLOCK_HAS_PARAM(block_type)) {
+ for (i = 0; i < block_type.u.type->param_count; i++)
+ PUSH_TYPE(block_type.u.type->types[i]);
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* Recover top param_count values of frame_offset stack */
+ if (BLOCK_HAS_PARAM((block_type))) {
+ uint32 size;
+ BranchBlock *block = loader_ctx->frame_csp - 1;
+ size = sizeof(int16) * block_type.u.type->param_cell_num;
+ bh_memcpy_s(loader_ctx->frame_offset, size,
+ block->param_frame_offsets, size);
+ loader_ctx->frame_offset += (size / sizeof(int16));
+ }
+#endif
+
+ break;
+ }
+
+ case WASM_OP_END:
+ {
+ BranchBlock *cur_block = loader_ctx->frame_csp - 1;
+
+ /* check whether block stack matches its result type */
+ if (!check_block_stack(loader_ctx, cur_block, error_buf,
+ error_buf_size))
+ goto fail;
+
+ /* if no else branch, and return types do not match param types,
+ * fail */
+ if (cur_block->label_type == LABEL_TYPE_IF
+ && !cur_block->else_addr) {
+ uint32 block_param_count = 0, block_ret_count = 0;
+ uint8 *block_param_types = NULL, *block_ret_types = NULL;
+ BlockType *cur_block_type = &cur_block->block_type;
+ if (cur_block_type->is_value_type) {
+ if (cur_block_type->u.value_type != VALUE_TYPE_VOID) {
+ block_ret_count = 1;
+ block_ret_types = &cur_block_type->u.value_type;
+ }
+ }
+ else {
+ block_param_count = cur_block_type->u.type->param_count;
+ block_ret_count = cur_block_type->u.type->result_count;
+ block_param_types = cur_block_type->u.type->types;
+ block_ret_types =
+ cur_block_type->u.type->types + block_param_count;
+ }
+ bh_assert(block_param_count == block_ret_count
+ && (!block_param_count
+ || !memcmp(block_param_types, block_ret_types,
+ block_param_count)));
+ (void)block_ret_types;
+ (void)block_ret_count;
+ (void)block_param_types;
+ }
+
+ POP_CSP();
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ skip_label();
+ /* copy the result to the block return address */
+ RESERVE_BLOCK_RET();
+
+ apply_label_patch(loader_ctx, 0, PATCH_END);
+ free_label_patch_list(loader_ctx->frame_csp);
+ if (loader_ctx->frame_csp->label_type == LABEL_TYPE_FUNCTION) {
+ int32 idx;
+ uint8 ret_type;
+
+ emit_label(WASM_OP_RETURN);
+ for (idx = (int32)func->func_type->result_count - 1;
+ idx >= 0; idx--) {
+ ret_type = *(func->func_type->types
+ + func->func_type->param_count + idx);
+ POP_OFFSET_TYPE(ret_type);
+ }
+ }
+#endif
+ if (loader_ctx->csp_num > 0) {
+ loader_ctx->frame_csp->end_addr = p - 1;
+ }
+ else {
+ /* end of function block, function will return */
+ bh_assert(p == p_end);
+ }
+
+ break;
+ }
+
+ case WASM_OP_BR:
+ {
+ if (!(frame_csp_tmp = check_branch_block(
+ loader_ctx, &p, p_end, error_buf, error_buf_size)))
+ goto fail;
+
+ RESET_STACK();
+ SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
+ break;
+ }
+
+ case WASM_OP_BR_IF:
+ {
+ POP_I32();
+
+ if (!(frame_csp_tmp = check_branch_block(
+ loader_ctx, &p, p_end, error_buf, error_buf_size)))
+ goto fail;
+
+ break;
+ }
+
+ case WASM_OP_BR_TABLE:
+ {
+ uint8 *ret_types = NULL;
+ uint32 ret_count = 0;
+#if WASM_ENABLE_FAST_INTERP == 0
+ uint8 *p_depth_begin, *p_depth;
+ uint32 depth, j;
+ BrTableCache *br_table_cache = NULL;
+
+ p_org = p - 1;
+#endif
+
+ read_leb_uint32(p, p_end, count);
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, count);
+#endif
+ POP_I32();
+
+#if WASM_ENABLE_FAST_INTERP == 0
+ p_depth_begin = p_depth = p;
+#endif
+ for (i = 0; i <= count; i++) {
+ if (!(frame_csp_tmp =
+ check_branch_block(loader_ctx, &p, p_end,
+ error_buf, error_buf_size)))
+ goto fail;
+
+#if WASM_ENABLE_FAST_INTERP == 0
+ depth = (uint32)(loader_ctx->frame_csp - 1 - frame_csp_tmp);
+ if (br_table_cache) {
+ br_table_cache->br_depths[i] = depth;
+ }
+ else {
+ if (depth > 255) {
+ /* The depth cannot be stored in one byte,
+ create br_table cache to store each depth */
+ if (!(br_table_cache = loader_malloc(
+ offsetof(BrTableCache, br_depths)
+ + sizeof(uint32)
+ * (uint64)(count + 1),
+ error_buf, error_buf_size))) {
+ goto fail;
+ }
+ *p_org = EXT_OP_BR_TABLE_CACHE;
+ br_table_cache->br_table_op_addr = p_org;
+ br_table_cache->br_count = count;
+ /* Copy previous depths which are one byte */
+ for (j = 0; j < i; j++) {
+ br_table_cache->br_depths[j] = p_depth_begin[j];
+ }
+ br_table_cache->br_depths[i] = depth;
+ bh_list_insert(module->br_table_cache_list,
+ br_table_cache);
+ }
+ else {
+ /* The depth can be stored in one byte, use the
+ byte of the leb to store it */
+ *p_depth++ = (uint8)depth;
+ }
+ }
+#endif
+ }
+
+#if WASM_ENABLE_FAST_INTERP == 0
+ /* Set the tailing bytes to nop */
+ if (br_table_cache)
+ p_depth = p_depth_begin;
+ while (p_depth < p)
+ *p_depth++ = WASM_OP_NOP;
+#endif
+
+ RESET_STACK();
+ SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
+
+ (void)ret_count;
+ (void)ret_types;
+ break;
+ }
+
+ case WASM_OP_RETURN:
+ {
+ int32 idx;
+ uint8 ret_type;
+ for (idx = (int32)func->func_type->result_count - 1; idx >= 0;
+ idx--) {
+ ret_type = *(func->func_type->types
+ + func->func_type->param_count + idx);
+ POP_TYPE(ret_type);
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* emit the offset after return opcode */
+ POP_OFFSET_TYPE(ret_type);
+#endif
+ }
+
+ RESET_STACK();
+ SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
+
+ break;
+ }
+
+ case WASM_OP_CALL:
+#if WASM_ENABLE_TAIL_CALL != 0
+ case WASM_OP_RETURN_CALL:
+#endif
+ {
+ WASMType *func_type;
+ uint32 func_idx;
+ int32 idx;
+
+ read_leb_uint32(p, p_end, func_idx);
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* we need to emit func_idx before arguments */
+ emit_uint32(loader_ctx, func_idx);
+#endif
+
+ bh_assert(func_idx < module->import_function_count
+ + module->function_count);
+
+ if (func_idx < module->import_function_count)
+ func_type =
+ module->import_functions[func_idx].u.function.func_type;
+ else
+ func_type = module
+ ->functions[func_idx
+ - module->import_function_count]
+ ->func_type;
+
+ if (func_type->param_count > 0) {
+ for (idx = (int32)(func_type->param_count - 1); idx >= 0;
+ idx--) {
+ POP_TYPE(func_type->types[idx]);
+#if WASM_ENABLE_FAST_INTERP != 0
+ POP_OFFSET_TYPE(func_type->types[idx]);
+#endif
+ }
+ }
+
+#if WASM_ENABLE_TAIL_CALL != 0
+ if (opcode == WASM_OP_CALL) {
+#endif
+ for (i = 0; i < func_type->result_count; i++) {
+ PUSH_TYPE(func_type->types[func_type->param_count + i]);
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* Here we emit each return value's dynamic_offset. But
+ * in fact these offsets are continuous, so interpreter
+ * only need to get the first return value's offset.
+ */
+ PUSH_OFFSET_TYPE(
+ func_type->types[func_type->param_count + i]);
+#endif
+ }
+#if WASM_ENABLE_TAIL_CALL != 0
+ }
+ else {
+ bh_assert(func_type->result_count
+ == func->func_type->result_count);
+ for (i = 0; i < func_type->result_count; i++) {
+ bh_assert(
+ func_type->types[func_type->param_count + i]
+ == func->func_type
+ ->types[func->func_type->param_count + i]);
+ }
+ }
+#endif
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \
+ || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_op_func_call = true;
+#endif
+ break;
+ }
+
+ case WASM_OP_CALL_INDIRECT:
+#if WASM_ENABLE_TAIL_CALL != 0
+ case WASM_OP_RETURN_CALL_INDIRECT:
+#endif
+ {
+ int32 idx;
+ WASMType *func_type;
+ uint32 type_idx, table_idx;
+
+ bh_assert(module->import_table_count + module->table_count > 0);
+
+ read_leb_uint32(p, p_end, type_idx);
+
+#if WASM_ENABLE_REF_TYPES != 0
+ read_leb_uint32(p, p_end, table_idx);
+#else
+ CHECK_BUF(p, p_end, 1);
+ table_idx = read_uint8(p);
+#endif
+ if (!check_table_index(module, table_idx, error_buf,
+ error_buf_size)) {
+ goto fail;
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* we need to emit before arguments */
+ emit_uint32(loader_ctx, type_idx);
+ emit_uint32(loader_ctx, table_idx);
+#endif
+
+ /* skip elem idx */
+ POP_I32();
+
+ bh_assert(type_idx < module->type_count);
+
+ func_type = module->types[type_idx];
+
+ if (func_type->param_count > 0) {
+ for (idx = (int32)(func_type->param_count - 1); idx >= 0;
+ idx--) {
+ POP_TYPE(func_type->types[idx]);
+#if WASM_ENABLE_FAST_INTERP != 0
+ POP_OFFSET_TYPE(func_type->types[idx]);
+#endif
+ }
+ }
+
+#if WASM_ENABLE_TAIL_CALL != 0
+ if (opcode == WASM_OP_CALL) {
+#endif
+ for (i = 0; i < func_type->result_count; i++) {
+ PUSH_TYPE(func_type->types[func_type->param_count + i]);
+#if WASM_ENABLE_FAST_INTERP != 0
+ PUSH_OFFSET_TYPE(
+ func_type->types[func_type->param_count + i]);
+#endif
+ }
+#if WASM_ENABLE_TAIL_CALL != 0
+ }
+ else {
+ bh_assert(func_type->result_count
+ == func->func_type->result_count);
+ for (i = 0; i < func_type->result_count; i++) {
+ bh_assert(
+ func_type->types[func_type->param_count + i]
+ == func->func_type
+ ->types[func->func_type->param_count + i]);
+ }
+ }
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \
+ || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_op_func_call = true;
+#endif
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_op_call_indirect = true;
+#endif
+ break;
+ }
+
+ case WASM_OP_DROP:
+ {
+ BranchBlock *cur_block = loader_ctx->frame_csp - 1;
+ int32 available_stack_cell =
+ (int32)(loader_ctx->stack_cell_num
+ - cur_block->stack_cell_num);
+
+ bh_assert(!(available_stack_cell <= 0
+ && !cur_block->is_stack_polymorphic));
+
+ if (available_stack_cell > 0) {
+ if (is_32bit_type(*(loader_ctx->frame_ref - 1))) {
+ loader_ctx->frame_ref--;
+ loader_ctx->stack_cell_num--;
+#if WASM_ENABLE_FAST_INTERP != 0
+ skip_label();
+ loader_ctx->frame_offset--;
+ if ((*(loader_ctx->frame_offset)
+ > loader_ctx->start_dynamic_offset)
+ && (*(loader_ctx->frame_offset)
+ < loader_ctx->max_dynamic_offset))
+ loader_ctx->dynamic_offset--;
+#endif
+ }
+ else if (is_64bit_type(*(loader_ctx->frame_ref - 1))) {
+ loader_ctx->frame_ref -= 2;
+ loader_ctx->stack_cell_num -= 2;
+#if WASM_ENABLE_FAST_INTERP == 0
+ *(p - 1) = WASM_OP_DROP_64;
+#endif
+#if WASM_ENABLE_FAST_INTERP != 0
+ skip_label();
+ loader_ctx->frame_offset -= 2;
+ if ((*(loader_ctx->frame_offset)
+ > loader_ctx->start_dynamic_offset)
+ && (*(loader_ctx->frame_offset)
+ < loader_ctx->max_dynamic_offset))
+ loader_ctx->dynamic_offset -= 2;
+#endif
+ }
+ else {
+ bh_assert(0);
+ }
+ }
+ else {
+#if WASM_ENABLE_FAST_INTERP != 0
+ skip_label();
+#endif
+ }
+ break;
+ }
+
+ case WASM_OP_SELECT:
+ {
+ uint8 ref_type;
+ BranchBlock *cur_block = loader_ctx->frame_csp - 1;
+ int32 available_stack_cell;
+
+ POP_I32();
+
+ available_stack_cell = (int32)(loader_ctx->stack_cell_num
+ - cur_block->stack_cell_num);
+
+ bh_assert(!(available_stack_cell <= 0
+ && !cur_block->is_stack_polymorphic));
+
+ if (available_stack_cell > 0) {
+ switch (*(loader_ctx->frame_ref - 1)) {
+ case REF_I32:
+ case REF_F32:
+ break;
+ case REF_I64_2:
+ case REF_F64_2:
+#if WASM_ENABLE_FAST_INTERP == 0
+ *(p - 1) = WASM_OP_SELECT_64;
+#endif
+#if WASM_ENABLE_FAST_INTERP != 0
+ if (loader_ctx->p_code_compiled) {
+ uint8 opcode_tmp = WASM_OP_SELECT_64;
+ uint8 *p_code_compiled_tmp =
+ loader_ctx->p_code_compiled - 2;
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
+ *(void **)(p_code_compiled_tmp
+ - sizeof(void *)) =
+ handle_table[opcode_tmp];
+#else
+ int32 offset =
+ (int32)((uint8 *)handle_table[opcode_tmp]
+ - (uint8 *)handle_table[0]);
+ if (!(offset >= INT16_MIN
+ && offset < INT16_MAX)) {
+ set_error_buf(error_buf, error_buf_size,
+ "pre-compiled label offset "
+ "out of range");
+ goto fail;
+ }
+ *(int16 *)(p_code_compiled_tmp
+ - sizeof(int16)) = (int16)offset;
+#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */
+#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
+ *(p_code_compiled_tmp - 1) = opcode_tmp;
+#else
+ *(p_code_compiled_tmp - 2) = opcode_tmp;
+#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */
+#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */
+ }
+#endif
+ break;
+ }
+
+ ref_type = *(loader_ctx->frame_ref - 1);
+#if WASM_ENABLE_FAST_INTERP != 0
+ POP_OFFSET_TYPE(ref_type);
+#endif
+ POP_TYPE(ref_type);
+#if WASM_ENABLE_FAST_INTERP != 0
+ POP_OFFSET_TYPE(ref_type);
+#endif
+ POP_TYPE(ref_type);
+#if WASM_ENABLE_FAST_INTERP != 0
+ PUSH_OFFSET_TYPE(ref_type);
+#endif
+ PUSH_TYPE(ref_type);
+ }
+ else {
+#if WASM_ENABLE_FAST_INTERP != 0
+ PUSH_OFFSET_TYPE(VALUE_TYPE_ANY);
+#endif
+ PUSH_TYPE(VALUE_TYPE_ANY);
+ }
+ break;
+ }
+
+#if WASM_ENABLE_REF_TYPES != 0
+ case WASM_OP_SELECT_T:
+ {
+ uint8 vec_len, ref_type;
+
+ read_leb_uint32(p, p_end, vec_len);
+ if (!vec_len) {
+ set_error_buf(error_buf, error_buf_size,
+ "invalid result arity");
+ goto fail;
+ }
+
+ CHECK_BUF(p, p_end, 1);
+ ref_type = read_uint8(p);
+ if (!is_value_type(ref_type)) {
+ set_error_buf(error_buf, error_buf_size,
+ "unknown value type");
+ goto fail;
+ }
+
+ POP_I32();
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ if (loader_ctx->p_code_compiled) {
+ uint8 opcode_tmp = WASM_OP_SELECT;
+ uint8 *p_code_compiled_tmp =
+ loader_ctx->p_code_compiled - 2;
+
+ if (ref_type == VALUE_TYPE_F64
+ || ref_type == VALUE_TYPE_I64)
+ opcode_tmp = WASM_OP_SELECT_64;
+
+#if WASM_ENABLE_LABELS_AS_VALUES != 0
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
+ *(void **)(p_code_compiled_tmp - sizeof(void *)) =
+ handle_table[opcode_tmp];
+#else
+ int32 offset = (int32)((uint8 *)handle_table[opcode_tmp]
+ - (uint8 *)handle_table[0]);
+ if (!(offset >= INT16_MIN && offset < INT16_MAX)) {
+ set_error_buf(error_buf, error_buf_size,
+ "pre-compiled label offset out of range");
+ goto fail;
+ }
+ *(int16 *)(p_code_compiled_tmp - sizeof(int16)) =
+ (int16)offset;
+#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */
+#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
+#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
+ *(p_code_compiled_tmp - 1) = opcode_tmp;
+#else
+ *(p_code_compiled_tmp - 2) = opcode_tmp;
+#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */
+#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */
+ }
+#endif /* WASM_ENABLE_FAST_INTERP != 0 */
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ POP_OFFSET_TYPE(ref_type);
+ POP_TYPE(ref_type);
+ POP_OFFSET_TYPE(ref_type);
+ POP_TYPE(ref_type);
+ PUSH_OFFSET_TYPE(ref_type);
+ PUSH_TYPE(ref_type);
+#else
+ POP2_AND_PUSH(ref_type, ref_type);
+#endif /* WASM_ENABLE_FAST_INTERP != 0 */
+
+ (void)vec_len;
+ break;
+ }
+
+ /* table.get x. tables[x]. [i32] -> [t] */
+ /* table.set x. tables[x]. [i32 t] -> [] */
+ case WASM_OP_TABLE_GET:
+ case WASM_OP_TABLE_SET:
+ {
+ uint8 decl_ref_type;
+ uint32 table_idx;
+
+ read_leb_uint32(p, p_end, table_idx);
+ if (!get_table_elem_type(module, table_idx, &decl_ref_type,
+ error_buf, error_buf_size))
+ goto fail;
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, table_idx);
+#endif
+
+ if (opcode == WASM_OP_TABLE_GET) {
+ POP_I32();
+#if WASM_ENABLE_FAST_INTERP != 0
+ PUSH_OFFSET_TYPE(decl_ref_type);
+#endif
+ PUSH_TYPE(decl_ref_type);
+ }
+ else {
+#if WASM_ENABLE_FAST_INTERP != 0
+ POP_OFFSET_TYPE(decl_ref_type);
+#endif
+ POP_TYPE(decl_ref_type);
+ POP_I32();
+ }
+ break;
+ }
+ case WASM_OP_REF_NULL:
+ {
+ uint8 ref_type;
+
+ CHECK_BUF(p, p_end, 1);
+ ref_type = read_uint8(p);
+ if (ref_type != VALUE_TYPE_FUNCREF
+ && ref_type != VALUE_TYPE_EXTERNREF) {
+ set_error_buf(error_buf, error_buf_size,
+ "unknown value type");
+ goto fail;
+ }
+#if WASM_ENABLE_FAST_INTERP != 0
+ PUSH_OFFSET_TYPE(ref_type);
+#endif
+ PUSH_TYPE(ref_type);
+ break;
+ }
+ case WASM_OP_REF_IS_NULL:
+ {
+#if WASM_ENABLE_FAST_INTERP != 0
+ if (!wasm_loader_pop_frame_ref_offset(loader_ctx,
+ VALUE_TYPE_FUNCREF,
+ error_buf, error_buf_size)
+ && !wasm_loader_pop_frame_ref_offset(
+ loader_ctx, VALUE_TYPE_EXTERNREF, error_buf,
+ error_buf_size)) {
+ goto fail;
+ }
+#else
+ if (!wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_FUNCREF,
+ error_buf, error_buf_size)
+ && !wasm_loader_pop_frame_ref(loader_ctx,
+ VALUE_TYPE_EXTERNREF,
+ error_buf, error_buf_size)) {
+ goto fail;
+ }
+#endif
+ PUSH_I32();
+ break;
+ }
+ case WASM_OP_REF_FUNC:
+ {
+ uint32 func_idx = 0;
+ read_leb_uint32(p, p_end, func_idx);
+
+ if (!check_function_index(module, func_idx, error_buf,
+ error_buf_size)) {
+ goto fail;
+ }
+
+ /* Refer to a forward-declared function */
+ if (func_idx >= cur_func_idx + module->import_function_count) {
+ WASMTableSeg *table_seg = module->table_segments;
+ bool func_declared = false;
+ uint32 j;
+
+ /* Check whether the function is declared in table segs */
+ for (i = 0; i < module->table_seg_count; i++, table_seg++) {
+ if (table_seg->elem_type == VALUE_TYPE_FUNCREF
+ && wasm_elem_is_declarative(table_seg->mode)) {
+ for (j = 0; j < table_seg->function_count; j++) {
+ if (table_seg->func_indexes[j] == func_idx) {
+ func_declared = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!func_declared) {
+ /* Check whether the function is exported */
+ for (i = 0; i < module->export_count; i++) {
+ if (module->exports[i].kind == EXPORT_KIND_FUNC
+ && module->exports[i].index == func_idx) {
+ func_declared = true;
+ break;
+ }
+ }
+ }
+ bh_assert(func_declared);
+ (void)func_declared;
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, func_idx);
+#endif
+ PUSH_FUNCREF();
+ break;
+ }
+#endif /* WASM_ENABLE_REF_TYPES */
+
+ case WASM_OP_GET_LOCAL:
+ {
+ p_org = p - 1;
+ GET_LOCAL_INDEX_TYPE_AND_OFFSET();
+ PUSH_TYPE(local_type);
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* Get Local is optimized out */
+ skip_label();
+ disable_emit = true;
+ operand_offset = local_offset;
+ PUSH_OFFSET_TYPE(local_type);
+#else
+#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) \
+ && (WASM_ENABLE_FAST_JIT == 0)
+ if (local_offset < 0x80) {
+ *p_org++ = EXT_OP_GET_LOCAL_FAST;
+ if (is_32bit_type(local_type))
+ *p_org++ = (uint8)local_offset;
+ else
+ *p_org++ = (uint8)(local_offset | 0x80);
+ while (p_org < p)
+ *p_org++ = WASM_OP_NOP;
+ }
+#endif
+#endif
+ break;
+ }
+
+ case WASM_OP_SET_LOCAL:
+ {
+ p_org = p - 1;
+ GET_LOCAL_INDEX_TYPE_AND_OFFSET();
+ POP_TYPE(local_type);
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ if (!(preserve_referenced_local(
+ loader_ctx, opcode, local_offset, local_type,
+ &preserve_local, error_buf, error_buf_size)))
+ goto fail;
+
+ if (local_offset < 256) {
+ skip_label();
+ if ((!preserve_local) && (LAST_OP_OUTPUT_I32())) {
+ if (loader_ctx->p_code_compiled)
+ STORE_U16(loader_ctx->p_code_compiled - 2,
+ local_offset);
+ loader_ctx->frame_offset--;
+ loader_ctx->dynamic_offset--;
+ }
+ else if ((!preserve_local) && (LAST_OP_OUTPUT_I64())) {
+ if (loader_ctx->p_code_compiled)
+ STORE_U16(loader_ctx->p_code_compiled - 2,
+ local_offset);
+ loader_ctx->frame_offset -= 2;
+ loader_ctx->dynamic_offset -= 2;
+ }
+ else {
+ if (is_32bit_type(local_type)) {
+ emit_label(EXT_OP_SET_LOCAL_FAST);
+ emit_byte(loader_ctx, (uint8)local_offset);
+ }
+ else {
+ emit_label(EXT_OP_SET_LOCAL_FAST_I64);
+ emit_byte(loader_ctx, (uint8)local_offset);
+ }
+ POP_OFFSET_TYPE(local_type);
+ }
+ }
+ else { /* local index larger than 255, reserve leb */
+ emit_uint32(loader_ctx, local_idx);
+ POP_OFFSET_TYPE(local_type);
+ }
+#else
+#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) \
+ && (WASM_ENABLE_FAST_JIT == 0)
+ if (local_offset < 0x80) {
+ *p_org++ = EXT_OP_SET_LOCAL_FAST;
+ if (is_32bit_type(local_type))
+ *p_org++ = (uint8)local_offset;
+ else
+ *p_org++ = (uint8)(local_offset | 0x80);
+ while (p_org < p)
+ *p_org++ = WASM_OP_NOP;
+ }
+#endif
+#endif
+ break;
+ }
+
+ case WASM_OP_TEE_LOCAL:
+ {
+ p_org = p - 1;
+ GET_LOCAL_INDEX_TYPE_AND_OFFSET();
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* If the stack is in polymorphic state, do fake pop and push on
+ offset stack to keep the depth of offset stack to be the
+ same with ref stack */
+ BranchBlock *cur_block = loader_ctx->frame_csp - 1;
+ if (cur_block->is_stack_polymorphic) {
+ POP_OFFSET_TYPE(local_type);
+ PUSH_OFFSET_TYPE(local_type);
+ }
+#endif
+ POP_TYPE(local_type);
+ PUSH_TYPE(local_type);
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ if (!(preserve_referenced_local(
+ loader_ctx, opcode, local_offset, local_type,
+ &preserve_local, error_buf, error_buf_size)))
+ goto fail;
+
+ if (local_offset < 256) {
+ skip_label();
+ if (is_32bit_type(local_type)) {
+ emit_label(EXT_OP_TEE_LOCAL_FAST);
+ emit_byte(loader_ctx, (uint8)local_offset);
+ }
+ else {
+ emit_label(EXT_OP_TEE_LOCAL_FAST_I64);
+ emit_byte(loader_ctx, (uint8)local_offset);
+ }
+ }
+ else { /* local index larger than 255, reserve leb */
+ emit_uint32(loader_ctx, local_idx);
+ }
+ emit_operand(loader_ctx,
+ *(loader_ctx->frame_offset
+ - wasm_value_type_cell_num(local_type)));
+#else
+#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) \
+ && (WASM_ENABLE_FAST_JIT == 0)
+ if (local_offset < 0x80) {
+ *p_org++ = EXT_OP_TEE_LOCAL_FAST;
+ if (is_32bit_type(local_type))
+ *p_org++ = (uint8)local_offset;
+ else
+ *p_org++ = (uint8)(local_offset | 0x80);
+ while (p_org < p)
+ *p_org++ = WASM_OP_NOP;
+ }
+#endif
+#endif
+ break;
+ }
+
+ case WASM_OP_GET_GLOBAL:
+ {
+ p_org = p - 1;
+ read_leb_uint32(p, p_end, global_idx);
+ bh_assert(global_idx < global_count);
+
+ global_type =
+ global_idx < module->import_global_count
+ ? module->import_globals[global_idx].u.global.type
+ : module
+ ->globals[global_idx
+ - module->import_global_count]
+ .type;
+
+ PUSH_TYPE(global_type);
+
+#if WASM_ENABLE_FAST_INTERP == 0
+ if (global_type == VALUE_TYPE_I64
+ || global_type == VALUE_TYPE_F64) {
+ *p_org = WASM_OP_GET_GLOBAL_64;
+ }
+#else /* else of WASM_ENABLE_FAST_INTERP */
+ if (is_64bit_type(global_type)) {
+ skip_label();
+ emit_label(WASM_OP_GET_GLOBAL_64);
+ }
+ emit_uint32(loader_ctx, global_idx);
+ PUSH_OFFSET_TYPE(global_type);
+#endif /* end of WASM_ENABLE_FAST_INTERP */
+ break;
+ }
+
+ case WASM_OP_SET_GLOBAL:
+ {
+ bool is_mutable = false;
+
+ p_org = p - 1;
+ read_leb_uint32(p, p_end, global_idx);
+ bh_assert(global_idx < global_count);
+
+ is_mutable =
+ global_idx < module->import_global_count
+ ? module->import_globals[global_idx].u.global.is_mutable
+ : module
+ ->globals[global_idx
+ - module->import_global_count]
+ .is_mutable;
+ bh_assert(is_mutable);
+
+ global_type =
+ global_idx < module->import_global_count
+ ? module->import_globals[global_idx].u.global.type
+ : module
+ ->globals[global_idx
+ - module->import_global_count]
+ .type;
+
+ POP_TYPE(global_type);
+
+#if WASM_ENABLE_FAST_INTERP == 0
+ if (is_64bit_type(global_type)) {
+ *p_org = WASM_OP_SET_GLOBAL_64;
+ }
+ else if (module->aux_stack_size > 0
+ && global_idx == module->aux_stack_top_global_index) {
+ *p_org = WASM_OP_SET_GLOBAL_AUX_STACK;
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_op_set_global_aux_stack = true;
+#endif
+ }
+#else /* else of WASM_ENABLE_FAST_INTERP */
+ if (is_64bit_type(global_type)) {
+ skip_label();
+ emit_label(WASM_OP_SET_GLOBAL_64);
+ }
+ else if (module->aux_stack_size > 0
+ && global_idx == module->aux_stack_top_global_index) {
+ skip_label();
+ emit_label(WASM_OP_SET_GLOBAL_AUX_STACK);
+ }
+ emit_uint32(loader_ctx, global_idx);
+ POP_OFFSET_TYPE(global_type);
+#endif /* end of WASM_ENABLE_FAST_INTERP */
+
+ (void)is_mutable;
+ break;
+ }
+
+ /* load */
+ case WASM_OP_I32_LOAD:
+ case WASM_OP_I32_LOAD8_S:
+ case WASM_OP_I32_LOAD8_U:
+ case WASM_OP_I32_LOAD16_S:
+ case WASM_OP_I32_LOAD16_U:
+ case WASM_OP_I64_LOAD:
+ case WASM_OP_I64_LOAD8_S:
+ case WASM_OP_I64_LOAD8_U:
+ case WASM_OP_I64_LOAD16_S:
+ case WASM_OP_I64_LOAD16_U:
+ case WASM_OP_I64_LOAD32_S:
+ case WASM_OP_I64_LOAD32_U:
+ case WASM_OP_F32_LOAD:
+ case WASM_OP_F64_LOAD:
+ /* store */
+ case WASM_OP_I32_STORE:
+ case WASM_OP_I32_STORE8:
+ case WASM_OP_I32_STORE16:
+ case WASM_OP_I64_STORE:
+ case WASM_OP_I64_STORE8:
+ case WASM_OP_I64_STORE16:
+ case WASM_OP_I64_STORE32:
+ case WASM_OP_F32_STORE:
+ case WASM_OP_F64_STORE:
+ {
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* change F32/F64 into I32/I64 */
+ if (opcode == WASM_OP_F32_LOAD) {
+ skip_label();
+ emit_label(WASM_OP_I32_LOAD);
+ }
+ else if (opcode == WASM_OP_F64_LOAD) {
+ skip_label();
+ emit_label(WASM_OP_I64_LOAD);
+ }
+ else if (opcode == WASM_OP_F32_STORE) {
+ skip_label();
+ emit_label(WASM_OP_I32_STORE);
+ }
+ else if (opcode == WASM_OP_F64_STORE) {
+ skip_label();
+ emit_label(WASM_OP_I64_STORE);
+ }
+#endif
+ CHECK_MEMORY();
+ read_leb_uint32(p, p_end, align); /* align */
+ read_leb_uint32(p, p_end, mem_offset); /* offset */
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, mem_offset);
+#endif
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ switch (opcode) {
+ /* load */
+ case WASM_OP_I32_LOAD:
+ case WASM_OP_I32_LOAD8_S:
+ case WASM_OP_I32_LOAD8_U:
+ case WASM_OP_I32_LOAD16_S:
+ case WASM_OP_I32_LOAD16_U:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+ break;
+ case WASM_OP_I64_LOAD:
+ case WASM_OP_I64_LOAD8_S:
+ case WASM_OP_I64_LOAD8_U:
+ case WASM_OP_I64_LOAD16_S:
+ case WASM_OP_I64_LOAD16_U:
+ case WASM_OP_I64_LOAD32_S:
+ case WASM_OP_I64_LOAD32_U:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64);
+ break;
+ case WASM_OP_F32_LOAD:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F32);
+ break;
+ case WASM_OP_F64_LOAD:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F64);
+ break;
+ /* store */
+ case WASM_OP_I32_STORE:
+ case WASM_OP_I32_STORE8:
+ case WASM_OP_I32_STORE16:
+ POP_I32();
+ POP_I32();
+ break;
+ case WASM_OP_I64_STORE:
+ case WASM_OP_I64_STORE8:
+ case WASM_OP_I64_STORE16:
+ case WASM_OP_I64_STORE32:
+ POP_I64();
+ POP_I32();
+ break;
+ case WASM_OP_F32_STORE:
+ POP_F32();
+ POP_I32();
+ break;
+ case WASM_OP_F64_STORE:
+ POP_F64();
+ POP_I32();
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ case WASM_OP_MEMORY_SIZE:
+ CHECK_MEMORY();
+ /* reserved byte 0x00 */
+ bh_assert(*p == 0x00);
+ p++;
+ PUSH_I32();
+
+ module->possible_memory_grow = true;
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ break;
+
+ case WASM_OP_MEMORY_GROW:
+ CHECK_MEMORY();
+ /* reserved byte 0x00 */
+ bh_assert(*p == 0x00);
+ p++;
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+
+ module->possible_memory_grow = true;
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \
+ || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_op_memory_grow = true;
+#endif
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ break;
+
+ case WASM_OP_I32_CONST:
+ read_leb_int32(p, p_end, i32_const);
+#if WASM_ENABLE_FAST_INTERP != 0
+ skip_label();
+ disable_emit = true;
+ GET_CONST_OFFSET(VALUE_TYPE_I32, i32_const);
+
+ if (operand_offset == 0) {
+ disable_emit = false;
+ emit_label(WASM_OP_I32_CONST);
+ emit_uint32(loader_ctx, i32_const);
+ }
+#else
+ (void)i32_const;
+#endif
+ PUSH_I32();
+ break;
+
+ case WASM_OP_I64_CONST:
+ read_leb_int64(p, p_end, i64_const);
+#if WASM_ENABLE_FAST_INTERP != 0
+ skip_label();
+ disable_emit = true;
+ GET_CONST_OFFSET(VALUE_TYPE_I64, i64_const);
+
+ if (operand_offset == 0) {
+ disable_emit = false;
+ emit_label(WASM_OP_I64_CONST);
+ emit_uint64(loader_ctx, i64_const);
+ }
+#endif
+ PUSH_I64();
+ break;
+
+ case WASM_OP_F32_CONST:
+ p += sizeof(float32);
+#if WASM_ENABLE_FAST_INTERP != 0
+ skip_label();
+ disable_emit = true;
+ bh_memcpy_s((uint8 *)&f32_const, sizeof(float32), p_org,
+ sizeof(float32));
+ GET_CONST_F32_OFFSET(VALUE_TYPE_F32, f32_const);
+
+ if (operand_offset == 0) {
+ disable_emit = false;
+ emit_label(WASM_OP_F32_CONST);
+ emit_float32(loader_ctx, f32_const);
+ }
+#endif
+ PUSH_F32();
+ break;
+
+ case WASM_OP_F64_CONST:
+ p += sizeof(float64);
+#if WASM_ENABLE_FAST_INTERP != 0
+ skip_label();
+ disable_emit = true;
+ /* Some MCU may require 8-byte align */
+ bh_memcpy_s((uint8 *)&f64_const, sizeof(float64), p_org,
+ sizeof(float64));
+ GET_CONST_F64_OFFSET(VALUE_TYPE_F64, f64_const);
+
+ if (operand_offset == 0) {
+ disable_emit = false;
+ emit_label(WASM_OP_F64_CONST);
+ emit_float64(loader_ctx, f64_const);
+ }
+#endif
+ PUSH_F64();
+ break;
+
+ case WASM_OP_I32_EQZ:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I32_EQ:
+ case WASM_OP_I32_NE:
+ case WASM_OP_I32_LT_S:
+ case WASM_OP_I32_LT_U:
+ case WASM_OP_I32_GT_S:
+ case WASM_OP_I32_GT_U:
+ case WASM_OP_I32_LE_S:
+ case WASM_OP_I32_LE_U:
+ case WASM_OP_I32_GE_S:
+ case WASM_OP_I32_GE_U:
+ POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I64_EQZ:
+ POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I64_EQ:
+ case WASM_OP_I64_NE:
+ case WASM_OP_I64_LT_S:
+ case WASM_OP_I64_LT_U:
+ case WASM_OP_I64_GT_S:
+ case WASM_OP_I64_GT_U:
+ case WASM_OP_I64_LE_S:
+ case WASM_OP_I64_LE_U:
+ case WASM_OP_I64_GE_S:
+ case WASM_OP_I64_GE_U:
+ POP2_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_F32_EQ:
+ case WASM_OP_F32_NE:
+ case WASM_OP_F32_LT:
+ case WASM_OP_F32_GT:
+ case WASM_OP_F32_LE:
+ case WASM_OP_F32_GE:
+ POP2_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_F64_EQ:
+ case WASM_OP_F64_NE:
+ case WASM_OP_F64_LT:
+ case WASM_OP_F64_GT:
+ case WASM_OP_F64_LE:
+ case WASM_OP_F64_GE:
+ POP2_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I32_CLZ:
+ case WASM_OP_I32_CTZ:
+ case WASM_OP_I32_POPCNT:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I32_ADD:
+ case WASM_OP_I32_SUB:
+ case WASM_OP_I32_MUL:
+ case WASM_OP_I32_DIV_S:
+ case WASM_OP_I32_DIV_U:
+ case WASM_OP_I32_REM_S:
+ case WASM_OP_I32_REM_U:
+ case WASM_OP_I32_AND:
+ case WASM_OP_I32_OR:
+ case WASM_OP_I32_XOR:
+ case WASM_OP_I32_SHL:
+ case WASM_OP_I32_SHR_S:
+ case WASM_OP_I32_SHR_U:
+ case WASM_OP_I32_ROTL:
+ case WASM_OP_I32_ROTR:
+ POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I64_CLZ:
+ case WASM_OP_I64_CTZ:
+ case WASM_OP_I64_POPCNT:
+ POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I64);
+ break;
+
+ case WASM_OP_I64_ADD:
+ case WASM_OP_I64_SUB:
+ case WASM_OP_I64_MUL:
+ case WASM_OP_I64_DIV_S:
+ case WASM_OP_I64_DIV_U:
+ case WASM_OP_I64_REM_S:
+ case WASM_OP_I64_REM_U:
+ case WASM_OP_I64_AND:
+ case WASM_OP_I64_OR:
+ case WASM_OP_I64_XOR:
+ case WASM_OP_I64_SHL:
+ case WASM_OP_I64_SHR_S:
+ case WASM_OP_I64_SHR_U:
+ case WASM_OP_I64_ROTL:
+ case WASM_OP_I64_ROTR:
+ POP2_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I64);
+ break;
+
+ case WASM_OP_F32_ABS:
+ case WASM_OP_F32_NEG:
+ case WASM_OP_F32_CEIL:
+ case WASM_OP_F32_FLOOR:
+ case WASM_OP_F32_TRUNC:
+ case WASM_OP_F32_NEAREST:
+ case WASM_OP_F32_SQRT:
+ POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_F32);
+ break;
+
+ case WASM_OP_F32_ADD:
+ case WASM_OP_F32_SUB:
+ case WASM_OP_F32_MUL:
+ case WASM_OP_F32_DIV:
+ case WASM_OP_F32_MIN:
+ case WASM_OP_F32_MAX:
+ case WASM_OP_F32_COPYSIGN:
+ POP2_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_F32);
+ break;
+
+ case WASM_OP_F64_ABS:
+ case WASM_OP_F64_NEG:
+ case WASM_OP_F64_CEIL:
+ case WASM_OP_F64_FLOOR:
+ case WASM_OP_F64_TRUNC:
+ case WASM_OP_F64_NEAREST:
+ case WASM_OP_F64_SQRT:
+ POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_F64);
+ break;
+
+ case WASM_OP_F64_ADD:
+ case WASM_OP_F64_SUB:
+ case WASM_OP_F64_MUL:
+ case WASM_OP_F64_DIV:
+ case WASM_OP_F64_MIN:
+ case WASM_OP_F64_MAX:
+ case WASM_OP_F64_COPYSIGN:
+ POP2_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_F64);
+ break;
+
+ case WASM_OP_I32_WRAP_I64:
+ POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I32_TRUNC_S_F32:
+ case WASM_OP_I32_TRUNC_U_F32:
+ POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I32_TRUNC_S_F64:
+ case WASM_OP_I32_TRUNC_U_F64:
+ POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I64_EXTEND_S_I32:
+ case WASM_OP_I64_EXTEND_U_I32:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64);
+ break;
+
+ case WASM_OP_I64_TRUNC_S_F32:
+ case WASM_OP_I64_TRUNC_U_F32:
+ POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I64);
+ break;
+
+ case WASM_OP_I64_TRUNC_S_F64:
+ case WASM_OP_I64_TRUNC_U_F64:
+ POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I64);
+ break;
+
+ case WASM_OP_F32_CONVERT_S_I32:
+ case WASM_OP_F32_CONVERT_U_I32:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F32);
+ break;
+
+ case WASM_OP_F32_CONVERT_S_I64:
+ case WASM_OP_F32_CONVERT_U_I64:
+ POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_F32);
+ break;
+
+ case WASM_OP_F32_DEMOTE_F64:
+ POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_F32);
+ break;
+
+ case WASM_OP_F64_CONVERT_S_I32:
+ case WASM_OP_F64_CONVERT_U_I32:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F64);
+ break;
+
+ case WASM_OP_F64_CONVERT_S_I64:
+ case WASM_OP_F64_CONVERT_U_I64:
+ POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_F64);
+ break;
+
+ case WASM_OP_F64_PROMOTE_F32:
+ POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_F64);
+ break;
+
+ case WASM_OP_I32_REINTERPRET_F32:
+ POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I64_REINTERPRET_F64:
+ POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I64);
+ break;
+
+ case WASM_OP_F32_REINTERPRET_I32:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F32);
+ break;
+
+ case WASM_OP_F64_REINTERPRET_I64:
+ POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_F64);
+ break;
+
+ case WASM_OP_I32_EXTEND8_S:
+ case WASM_OP_I32_EXTEND16_S:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+ break;
+
+ case WASM_OP_I64_EXTEND8_S:
+ case WASM_OP_I64_EXTEND16_S:
+ case WASM_OP_I64_EXTEND32_S:
+ POP_AND_PUSH(VALUE_TYPE_I64, VALUE_TYPE_I64);
+ break;
+
+ case WASM_OP_MISC_PREFIX:
+ {
+ uint32 opcode1;
+
+ read_leb_uint32(p, p_end, opcode1);
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_byte(loader_ctx, ((uint8)opcode1));
+#endif
+ switch (opcode1) {
+ case WASM_OP_I32_TRUNC_SAT_S_F32:
+ case WASM_OP_I32_TRUNC_SAT_U_F32:
+ POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I32);
+ break;
+ case WASM_OP_I32_TRUNC_SAT_S_F64:
+ case WASM_OP_I32_TRUNC_SAT_U_F64:
+ POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I32);
+ break;
+ case WASM_OP_I64_TRUNC_SAT_S_F32:
+ case WASM_OP_I64_TRUNC_SAT_U_F32:
+ POP_AND_PUSH(VALUE_TYPE_F32, VALUE_TYPE_I64);
+ break;
+ case WASM_OP_I64_TRUNC_SAT_S_F64:
+ case WASM_OP_I64_TRUNC_SAT_U_F64:
+ POP_AND_PUSH(VALUE_TYPE_F64, VALUE_TYPE_I64);
+ break;
+#if WASM_ENABLE_BULK_MEMORY != 0
+ case WASM_OP_MEMORY_INIT:
+ {
+ read_leb_uint32(p, p_end, segment_index);
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, segment_index);
+#endif
+ bh_assert(module->import_memory_count
+ + module->memory_count
+ > 0);
+
+ bh_assert(*p == 0x00);
+ p++;
+
+ bh_assert(segment_index < module->data_seg_count);
+ bh_assert(module->data_seg_count1 > 0);
+
+ POP_I32();
+ POP_I32();
+ POP_I32();
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ break;
+ }
+ case WASM_OP_DATA_DROP:
+ {
+ read_leb_uint32(p, p_end, segment_index);
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, segment_index);
+#endif
+ bh_assert(segment_index < module->data_seg_count);
+ bh_assert(module->data_seg_count1 > 0);
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ break;
+ }
+ case WASM_OP_MEMORY_COPY:
+ {
+ /* both src and dst memory index should be 0 */
+ bh_assert(*(int16 *)p == 0x0000);
+ p += 2;
+
+ bh_assert(module->import_memory_count
+ + module->memory_count
+ > 0);
+
+ POP_I32();
+ POP_I32();
+ POP_I32();
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ break;
+ }
+ case WASM_OP_MEMORY_FILL:
+ {
+ bh_assert(*p == 0);
+ p++;
+
+ bh_assert(module->import_memory_count
+ + module->memory_count
+ > 0);
+
+ POP_I32();
+ POP_I32();
+ POP_I32();
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ break;
+ }
+#endif /* WASM_ENABLE_BULK_MEMORY */
+#if WASM_ENABLE_REF_TYPES != 0
+ case WASM_OP_TABLE_INIT:
+ {
+ uint8 seg_ref_type, tbl_ref_type;
+ uint32 table_seg_idx, table_idx;
+
+ read_leb_uint32(p, p_end, table_seg_idx);
+ read_leb_uint32(p, p_end, table_idx);
+
+ if (!get_table_elem_type(module, table_idx,
+ &tbl_ref_type, error_buf,
+ error_buf_size))
+ goto fail;
+
+ if (!get_table_seg_elem_type(module, table_seg_idx,
+ &seg_ref_type, error_buf,
+ error_buf_size))
+ goto fail;
+
+ if (seg_ref_type != tbl_ref_type) {
+ set_error_buf(error_buf, error_buf_size,
+ "type mismatch");
+ goto fail;
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, table_seg_idx);
+ emit_uint32(loader_ctx, table_idx);
+#endif
+ POP_I32();
+ POP_I32();
+ POP_I32();
+ break;
+ }
+ case WASM_OP_ELEM_DROP:
+ {
+ uint32 table_seg_idx;
+ read_leb_uint32(p, p_end, table_seg_idx);
+ if (!get_table_seg_elem_type(module, table_seg_idx,
+ NULL, error_buf,
+ error_buf_size))
+ goto fail;
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, table_seg_idx);
+#endif
+ break;
+ }
+ case WASM_OP_TABLE_COPY:
+ {
+ uint8 src_ref_type, dst_ref_type;
+ uint32 src_tbl_idx, dst_tbl_idx;
+
+ read_leb_uint32(p, p_end, src_tbl_idx);
+ if (!get_table_elem_type(module, src_tbl_idx,
+ &src_ref_type, error_buf,
+ error_buf_size))
+ goto fail;
+
+ read_leb_uint32(p, p_end, dst_tbl_idx);
+ if (!get_table_elem_type(module, dst_tbl_idx,
+ &dst_ref_type, error_buf,
+ error_buf_size))
+ goto fail;
+
+ if (src_ref_type != dst_ref_type) {
+ set_error_buf(error_buf, error_buf_size,
+ "type mismatch");
+ goto fail;
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, src_tbl_idx);
+ emit_uint32(loader_ctx, dst_tbl_idx);
+#endif
+ POP_I32();
+ POP_I32();
+ POP_I32();
+ break;
+ }
+ case WASM_OP_TABLE_SIZE:
+ {
+ uint32 table_idx;
+
+ read_leb_uint32(p, p_end, table_idx);
+ /* TODO: shall we create a new function to check
+ table idx instead of using below function? */
+ if (!get_table_elem_type(module, table_idx, NULL,
+ error_buf, error_buf_size))
+ goto fail;
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, table_idx);
+#endif
+
+ PUSH_I32();
+ break;
+ }
+ case WASM_OP_TABLE_GROW:
+ case WASM_OP_TABLE_FILL:
+ {
+ uint8 decl_ref_type;
+ uint32 table_idx;
+
+ read_leb_uint32(p, p_end, table_idx);
+ if (!get_table_elem_type(module, table_idx,
+ &decl_ref_type, error_buf,
+ error_buf_size))
+ goto fail;
+
+ if (opcode1 == WASM_OP_TABLE_GROW) {
+ if (table_idx < module->import_table_count) {
+ module->import_tables[table_idx]
+ .u.table.possible_grow = true;
+ }
+ else {
+ module
+ ->tables[table_idx
+ - module->import_table_count]
+ .possible_grow = true;
+ }
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, table_idx);
+#endif
+
+ POP_I32();
+#if WASM_ENABLE_FAST_INTERP != 0
+ POP_OFFSET_TYPE(decl_ref_type);
+#endif
+ POP_TYPE(decl_ref_type);
+ if (opcode1 == WASM_OP_TABLE_GROW)
+ PUSH_I32();
+ else
+ POP_I32();
+ break;
+ }
+#endif /* WASM_ENABLE_REF_TYPES */
+ default:
+ bh_assert(0);
+ break;
+ }
+ break;
+ }
+
+#if WASM_ENABLE_SHARED_MEMORY != 0
+ case WASM_OP_ATOMIC_PREFIX:
+ {
+ opcode = read_uint8(p);
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_byte(loader_ctx, opcode);
+#endif
+ if (opcode != WASM_OP_ATOMIC_FENCE) {
+ CHECK_MEMORY();
+ read_leb_uint32(p, p_end, align); /* align */
+ read_leb_uint32(p, p_end, mem_offset); /* offset */
+#if WASM_ENABLE_FAST_INTERP != 0
+ emit_uint32(loader_ctx, mem_offset);
+#endif
+ }
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+ func->has_memory_operations = true;
+#endif
+ switch (opcode) {
+ case WASM_OP_ATOMIC_NOTIFY:
+ POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+ break;
+ case WASM_OP_ATOMIC_WAIT32:
+ POP_I64();
+ POP_I32();
+ POP_I32();
+ PUSH_I32();
+ break;
+ case WASM_OP_ATOMIC_WAIT64:
+ POP_I64();
+ POP_I64();
+ POP_I32();
+ PUSH_I32();
+ break;
+ case WASM_OP_ATOMIC_FENCE:
+ /* reserved byte 0x00 */
+ bh_assert(*p == 0x00);
+ p++;
+ break;
+ case WASM_OP_ATOMIC_I32_LOAD:
+ case WASM_OP_ATOMIC_I32_LOAD8_U:
+ case WASM_OP_ATOMIC_I32_LOAD16_U:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+ break;
+ case WASM_OP_ATOMIC_I32_STORE:
+ case WASM_OP_ATOMIC_I32_STORE8:
+ case WASM_OP_ATOMIC_I32_STORE16:
+ POP_I32();
+ POP_I32();
+ break;
+ case WASM_OP_ATOMIC_I64_LOAD:
+ case WASM_OP_ATOMIC_I64_LOAD8_U:
+ case WASM_OP_ATOMIC_I64_LOAD16_U:
+ case WASM_OP_ATOMIC_I64_LOAD32_U:
+ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64);
+ break;
+ case WASM_OP_ATOMIC_I64_STORE:
+ case WASM_OP_ATOMIC_I64_STORE8:
+ case WASM_OP_ATOMIC_I64_STORE16:
+ case WASM_OP_ATOMIC_I64_STORE32:
+ POP_I64();
+ POP_I32();
+ break;
+ case WASM_OP_ATOMIC_RMW_I32_ADD:
+ case WASM_OP_ATOMIC_RMW_I32_ADD8_U:
+ case WASM_OP_ATOMIC_RMW_I32_ADD16_U:
+ case WASM_OP_ATOMIC_RMW_I32_SUB:
+ case WASM_OP_ATOMIC_RMW_I32_SUB8_U:
+ case WASM_OP_ATOMIC_RMW_I32_SUB16_U:
+ case WASM_OP_ATOMIC_RMW_I32_AND:
+ case WASM_OP_ATOMIC_RMW_I32_AND8_U:
+ case WASM_OP_ATOMIC_RMW_I32_AND16_U:
+ case WASM_OP_ATOMIC_RMW_I32_OR:
+ case WASM_OP_ATOMIC_RMW_I32_OR8_U:
+ case WASM_OP_ATOMIC_RMW_I32_OR16_U:
+ case WASM_OP_ATOMIC_RMW_I32_XOR:
+ case WASM_OP_ATOMIC_RMW_I32_XOR8_U:
+ case WASM_OP_ATOMIC_RMW_I32_XOR16_U:
+ case WASM_OP_ATOMIC_RMW_I32_XCHG:
+ case WASM_OP_ATOMIC_RMW_I32_XCHG8_U:
+ case WASM_OP_ATOMIC_RMW_I32_XCHG16_U:
+ POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32);
+ break;
+ case WASM_OP_ATOMIC_RMW_I64_ADD:
+ case WASM_OP_ATOMIC_RMW_I64_ADD8_U:
+ case WASM_OP_ATOMIC_RMW_I64_ADD16_U:
+ case WASM_OP_ATOMIC_RMW_I64_ADD32_U:
+ case WASM_OP_ATOMIC_RMW_I64_SUB:
+ case WASM_OP_ATOMIC_RMW_I64_SUB8_U:
+ case WASM_OP_ATOMIC_RMW_I64_SUB16_U:
+ case WASM_OP_ATOMIC_RMW_I64_SUB32_U:
+ case WASM_OP_ATOMIC_RMW_I64_AND:
+ case WASM_OP_ATOMIC_RMW_I64_AND8_U:
+ case WASM_OP_ATOMIC_RMW_I64_AND16_U:
+ case WASM_OP_ATOMIC_RMW_I64_AND32_U:
+ case WASM_OP_ATOMIC_RMW_I64_OR:
+ case WASM_OP_ATOMIC_RMW_I64_OR8_U:
+ case WASM_OP_ATOMIC_RMW_I64_OR16_U:
+ case WASM_OP_ATOMIC_RMW_I64_OR32_U:
+ case WASM_OP_ATOMIC_RMW_I64_XOR:
+ case WASM_OP_ATOMIC_RMW_I64_XOR8_U:
+ case WASM_OP_ATOMIC_RMW_I64_XOR16_U:
+ case WASM_OP_ATOMIC_RMW_I64_XOR32_U:
+ case WASM_OP_ATOMIC_RMW_I64_XCHG:
+ case WASM_OP_ATOMIC_RMW_I64_XCHG8_U:
+ case WASM_OP_ATOMIC_RMW_I64_XCHG16_U:
+ case WASM_OP_ATOMIC_RMW_I64_XCHG32_U:
+ POP_I64();
+ POP_I32();
+ PUSH_I64();
+ break;
+ case WASM_OP_ATOMIC_RMW_I32_CMPXCHG:
+ case WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U:
+ case WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U:
+ POP_I32();
+ POP_I32();
+ POP_I32();
+ PUSH_I32();
+ break;
+ case WASM_OP_ATOMIC_RMW_I64_CMPXCHG:
+ case WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U:
+ case WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U:
+ case WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U:
+ POP_I64();
+ POP_I64();
+ POP_I32();
+ PUSH_I64();
+ break;
+ default:
+ bh_assert(0);
+ break;
+ }
+ break;
+ }
+#endif /* end of WASM_ENABLE_SHARED_MEMORY */
+
+ default:
+ bh_assert(0);
+ break;
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ last_op = opcode;
+#endif
+ }
+
+ if (loader_ctx->csp_num > 0) {
+ set_error_buf(error_buf, error_buf_size,
+ "function body must end with END opcode");
+ goto fail;
+ }
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ if (loader_ctx->p_code_compiled == NULL)
+ goto re_scan;
+
+ func->const_cell_num = loader_ctx->const_cell_num;
+ if (func->const_cell_num > 0) {
+ int32 j;
+
+ if (!(func->consts = func_const = loader_malloc(
+ func->const_cell_num * 4, error_buf, error_buf_size)))
+ goto fail;
+
+ func_const_end = func->consts + func->const_cell_num * 4;
+ /* reverse the const buf */
+ for (j = loader_ctx->num_const - 1; j >= 0; j--) {
+ Const *c = (Const *)(loader_ctx->const_buf + j * sizeof(Const));
+ if (c->value_type == VALUE_TYPE_F64
+ || c->value_type == VALUE_TYPE_I64) {
+ bh_memcpy_s(func_const, (uint32)(func_const_end - func_const),
+ &(c->value.f64), (uint32)sizeof(int64));
+ func_const += sizeof(int64);
+ }
+ else {
+ bh_memcpy_s(func_const, (uint32)(func_const_end - func_const),
+ &(c->value.f32), (uint32)sizeof(int32));
+ func_const += sizeof(int32);
+ }
+ }
+ }
+
+ func->max_stack_cell_num = loader_ctx->preserved_local_offset
+ - loader_ctx->start_dynamic_offset + 1;
+#else
+ func->max_stack_cell_num = loader_ctx->max_stack_cell_num;
+#endif
+ func->max_block_num = loader_ctx->max_csp_num;
+ return_value = true;
+
+fail:
+ wasm_loader_ctx_destroy(loader_ctx);
+
+ (void)u8;
+ (void)u32;
+ (void)i32;
+ (void)i64_const;
+ (void)global_count;
+ (void)local_count;
+ (void)local_offset;
+ (void)p_org;
+ (void)mem_offset;
+ (void)align;
+#if WASM_ENABLE_BULK_MEMORY != 0
+ (void)segment_index;
+#endif
+ return return_value;
+}
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_opcode.h b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_opcode.h
new file mode 100644
index 000000000..ce5e358a2
--- /dev/null
+++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_opcode.h
@@ -0,0 +1,917 @@
+/*
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef _WASM_OPCODE_H
+#define _WASM_OPCODE_H
+
+#include "wasm.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum WASMOpcode {
+ /* control instructions */
+ WASM_OP_UNREACHABLE = 0x00, /* unreachable */
+ WASM_OP_NOP = 0x01, /* nop */
+ WASM_OP_BLOCK = 0x02, /* block */
+ WASM_OP_LOOP = 0x03, /* loop */
+ WASM_OP_IF = 0x04, /* if */
+ WASM_OP_ELSE = 0x05, /* else */
+
+ WASM_OP_UNUSED_0x06 = 0x06,
+ WASM_OP_UNUSED_0x07 = 0x07,
+ WASM_OP_UNUSED_0x08 = 0x08,
+ WASM_OP_UNUSED_0x09 = 0x09,
+ WASM_OP_UNUSED_0x0a = 0x0a,
+
+ WASM_OP_END = 0x0b, /* end */
+ WASM_OP_BR = 0x0c, /* br */
+ WASM_OP_BR_IF = 0x0d, /* br if */
+ WASM_OP_BR_TABLE = 0x0e, /* br table */
+ WASM_OP_RETURN = 0x0f, /* return */
+ WASM_OP_CALL = 0x10, /* call */
+ WASM_OP_CALL_INDIRECT = 0x11, /* call_indirect */
+ WASM_OP_RETURN_CALL = 0x12, /* return_call */
+ WASM_OP_RETURN_CALL_INDIRECT = 0x13, /* return_call_indirect */
+
+ WASM_OP_UNUSED_0x14 = 0x14,
+ WASM_OP_UNUSED_0x15 = 0x15,
+ WASM_OP_UNUSED_0x16 = 0x16,
+ WASM_OP_UNUSED_0x17 = 0x17,
+ WASM_OP_UNUSED_0x18 = 0x18,
+ WASM_OP_UNUSED_0x19 = 0x19,
+
+ /* parametric instructions */
+ WASM_OP_DROP = 0x1a, /* drop */
+ WASM_OP_SELECT = 0x1b, /* select */
+ WASM_OP_SELECT_T = 0x1c, /* select t */
+
+ WASM_OP_GET_GLOBAL_64 = 0x1d,
+ WASM_OP_SET_GLOBAL_64 = 0x1e,
+ WASM_OP_SET_GLOBAL_AUX_STACK = 0x1f,
+
+ /* variable instructions */
+ WASM_OP_GET_LOCAL = 0x20, /* get_local */
+ WASM_OP_SET_LOCAL = 0x21, /* set_local */
+ WASM_OP_TEE_LOCAL = 0x22, /* tee_local */
+ WASM_OP_GET_GLOBAL = 0x23, /* get_global */
+ WASM_OP_SET_GLOBAL = 0x24, /* set_global */
+
+ WASM_OP_TABLE_GET = 0x25, /* table.get */
+ WASM_OP_TABLE_SET = 0x26, /* table.set */
+ WASM_OP_UNUSED_0x27 = 0x27,
+
+ /* memory instructions */
+ WASM_OP_I32_LOAD = 0x28, /* i32.load */
+ WASM_OP_I64_LOAD = 0x29, /* i64.load */
+ WASM_OP_F32_LOAD = 0x2a, /* f32.load */
+ WASM_OP_F64_LOAD = 0x2b, /* f64.load */
+ WASM_OP_I32_LOAD8_S = 0x2c, /* i32.load8_s */
+ WASM_OP_I32_LOAD8_U = 0x2d, /* i32.load8_u */
+ WASM_OP_I32_LOAD16_S = 0x2e, /* i32.load16_s */
+ WASM_OP_I32_LOAD16_U = 0x2f, /* i32.load16_u */
+ WASM_OP_I64_LOAD8_S = 0x30, /* i64.load8_s */
+ WASM_OP_I64_LOAD8_U = 0x31, /* i64.load8_u */
+ WASM_OP_I64_LOAD16_S = 0x32, /* i64.load16_s */
+ WASM_OP_I64_LOAD16_U = 0x33, /* i64.load16_u */
+ WASM_OP_I64_LOAD32_S = 0x34, /* i32.load32_s */
+ WASM_OP_I64_LOAD32_U = 0x35, /* i32.load32_u */
+ WASM_OP_I32_STORE = 0x36, /* i32.store */
+ WASM_OP_I64_STORE = 0x37, /* i64.store */
+ WASM_OP_F32_STORE = 0x38, /* f32.store */
+ WASM_OP_F64_STORE = 0x39, /* f64.store */
+ WASM_OP_I32_STORE8 = 0x3a, /* i32.store8 */
+ WASM_OP_I32_STORE16 = 0x3b, /* i32.store16 */
+ WASM_OP_I64_STORE8 = 0x3c, /* i64.store8 */
+ WASM_OP_I64_STORE16 = 0x3d, /* i64.sotre16 */
+ WASM_OP_I64_STORE32 = 0x3e, /* i64.store32 */
+ WASM_OP_MEMORY_SIZE = 0x3f, /* memory.size */
+ WASM_OP_MEMORY_GROW = 0x40, /* memory.grow */
+
+ /* constant instructions */
+ WASM_OP_I32_CONST = 0x41, /* i32.const */
+ WASM_OP_I64_CONST = 0x42, /* i64.const */
+ WASM_OP_F32_CONST = 0x43, /* f32.const */
+ WASM_OP_F64_CONST = 0x44, /* f64.const */
+
+ /* comparison instructions */
+ WASM_OP_I32_EQZ = 0x45, /* i32.eqz */
+ WASM_OP_I32_EQ = 0x46, /* i32.eq */
+ WASM_OP_I32_NE = 0x47, /* i32.ne */
+ WASM_OP_I32_LT_S = 0x48, /* i32.lt_s */
+ WASM_OP_I32_LT_U = 0x49, /* i32.lt_u */
+ WASM_OP_I32_GT_S = 0x4a, /* i32.gt_s */
+ WASM_OP_I32_GT_U = 0x4b, /* i32.gt_u */
+ WASM_OP_I32_LE_S = 0x4c, /* i32.le_s */
+ WASM_OP_I32_LE_U = 0x4d, /* i32.le_u */
+ WASM_OP_I32_GE_S = 0x4e, /* i32.ge_s */
+ WASM_OP_I32_GE_U = 0x4f, /* i32.ge_u */
+
+ WASM_OP_I64_EQZ = 0x50, /* i64.eqz */
+ WASM_OP_I64_EQ = 0x51, /* i64.eq */
+ WASM_OP_I64_NE = 0x52, /* i64.ne */
+ WASM_OP_I64_LT_S = 0x53, /* i64.lt_s */
+ WASM_OP_I64_LT_U = 0x54, /* i64.lt_u */
+ WASM_OP_I64_GT_S = 0x55, /* i64.gt_s */
+ WASM_OP_I64_GT_U = 0x56, /* i64.gt_u */
+ WASM_OP_I64_LE_S = 0x57, /* i64.le_s */
+ WASM_OP_I64_LE_U = 0x58, /* i64.le_u */
+ WASM_OP_I64_GE_S = 0x59, /* i64.ge_s */
+ WASM_OP_I64_GE_U = 0x5a, /* i64.ge_u */
+
+ WASM_OP_F32_EQ = 0x5b, /* f32.eq */
+ WASM_OP_F32_NE = 0x5c, /* f32.ne */
+ WASM_OP_F32_LT = 0x5d, /* f32.lt */
+ WASM_OP_F32_GT = 0x5e, /* f32.gt */
+ WASM_OP_F32_LE = 0x5f, /* f32.le */
+ WASM_OP_F32_GE = 0x60, /* f32.ge */
+
+ WASM_OP_F64_EQ = 0x61, /* f64.eq */
+ WASM_OP_F64_NE = 0x62, /* f64.ne */
+ WASM_OP_F64_LT = 0x63, /* f64.lt */
+ WASM_OP_F64_GT = 0x64, /* f64.gt */
+ WASM_OP_F64_LE = 0x65, /* f64.le */
+ WASM_OP_F64_GE = 0x66, /* f64.ge */
+
+ /* numeric operators */
+ WASM_OP_I32_CLZ = 0x67, /* i32.clz */
+ WASM_OP_I32_CTZ = 0x68, /* i32.ctz */
+ WASM_OP_I32_POPCNT = 0x69, /* i32.popcnt */
+ WASM_OP_I32_ADD = 0x6a, /* i32.add */
+ WASM_OP_I32_SUB = 0x6b, /* i32.sub */
+ WASM_OP_I32_MUL = 0x6c, /* i32.mul */
+ WASM_OP_I32_DIV_S = 0x6d, /* i32.div_s */
+ WASM_OP_I32_DIV_U = 0x6e, /* i32.div_u */
+ WASM_OP_I32_REM_S = 0x6f, /* i32.rem_s */
+ WASM_OP_I32_REM_U = 0x70, /* i32.rem_u */
+ WASM_OP_I32_AND = 0x71, /* i32.and */
+ WASM_OP_I32_OR = 0x72, /* i32.or */
+ WASM_OP_I32_XOR = 0x73, /* i32.xor */
+ WASM_OP_I32_SHL = 0x74, /* i32.shl */
+ WASM_OP_I32_SHR_S = 0x75, /* i32.shr_s */
+ WASM_OP_I32_SHR_U = 0x76, /* i32.shr_u */
+ WASM_OP_I32_ROTL = 0x77, /* i32.rotl */
+ WASM_OP_I32_ROTR = 0x78, /* i32.rotr */
+
+ WASM_OP_I64_CLZ = 0x79, /* i64.clz */
+ WASM_OP_I64_CTZ = 0x7a, /* i64.ctz */
+ WASM_OP_I64_POPCNT = 0x7b, /* i64.popcnt */
+ WASM_OP_I64_ADD = 0x7c, /* i64.add */
+ WASM_OP_I64_SUB = 0x7d, /* i64.sub */
+ WASM_OP_I64_MUL = 0x7e, /* i64.mul */
+ WASM_OP_I64_DIV_S = 0x7f, /* i64.div_s */
+ WASM_OP_I64_DIV_U = 0x80, /* i64.div_u */
+ WASM_OP_I64_REM_S = 0x81, /* i64.rem_s */
+ WASM_OP_I64_REM_U = 0x82, /* i64.rem_u */
+ WASM_OP_I64_AND = 0x83, /* i64.and */
+ WASM_OP_I64_OR = 0x84, /* i64.or */
+ WASM_OP_I64_XOR = 0x85, /* i64.xor */
+ WASM_OP_I64_SHL = 0x86, /* i64.shl */
+ WASM_OP_I64_SHR_S = 0x87, /* i64.shr_s */
+ WASM_OP_I64_SHR_U = 0x88, /* i64.shr_u */
+ WASM_OP_I64_ROTL = 0x89, /* i64.rotl */
+ WASM_OP_I64_ROTR = 0x8a, /* i64.rotr */
+
+ WASM_OP_F32_ABS = 0x8b, /* f32.abs */
+ WASM_OP_F32_NEG = 0x8c, /* f32.neg */
+ WASM_OP_F32_CEIL = 0x8d, /* f32.ceil */
+ WASM_OP_F32_FLOOR = 0x8e, /* f32.floor */
+ WASM_OP_F32_TRUNC = 0x8f, /* f32.trunc */
+ WASM_OP_F32_NEAREST = 0x90, /* f32.nearest */
+ WASM_OP_F32_SQRT = 0x91, /* f32.sqrt */
+ WASM_OP_F32_ADD = 0x92, /* f32.add */
+ WASM_OP_F32_SUB = 0x93, /* f32.sub */
+ WASM_OP_F32_MUL = 0x94, /* f32.mul */
+ WASM_OP_F32_DIV = 0x95, /* f32.div */
+ WASM_OP_F32_MIN = 0x96, /* f32.min */
+ WASM_OP_F32_MAX = 0x97, /* f32.max */
+ WASM_OP_F32_COPYSIGN = 0x98, /* f32.copysign */
+
+ WASM_OP_F64_ABS = 0x99, /* f64.abs */
+ WASM_OP_F64_NEG = 0x9a, /* f64.neg */
+ WASM_OP_F64_CEIL = 0x9b, /* f64.ceil */
+ WASM_OP_F64_FLOOR = 0x9c, /* f64.floor */
+ WASM_OP_F64_TRUNC = 0x9d, /* f64.trunc */
+ WASM_OP_F64_NEAREST = 0x9e, /* f64.nearest */
+ WASM_OP_F64_SQRT = 0x9f, /* f64.sqrt */
+ WASM_OP_F64_ADD = 0xa0, /* f64.add */
+ WASM_OP_F64_SUB = 0xa1, /* f64.sub */
+ WASM_OP_F64_MUL = 0xa2, /* f64.mul */
+ WASM_OP_F64_DIV = 0xa3, /* f64.div */
+ WASM_OP_F64_MIN = 0xa4, /* f64.min */
+ WASM_OP_F64_MAX = 0xa5, /* f64.max */
+ WASM_OP_F64_COPYSIGN = 0xa6, /* f64.copysign */
+
+ /* conversions */
+ WASM_OP_I32_WRAP_I64 = 0xa7, /* i32.wrap/i64 */
+ WASM_OP_I32_TRUNC_S_F32 = 0xa8, /* i32.trunc_s/f32 */
+ WASM_OP_I32_TRUNC_U_F32 = 0xa9, /* i32.trunc_u/f32 */
+ WASM_OP_I32_TRUNC_S_F64 = 0xaa, /* i32.trunc_s/f64 */
+ WASM_OP_I32_TRUNC_U_F64 = 0xab, /* i32.trunc_u/f64 */
+
+ WASM_OP_I64_EXTEND_S_I32 = 0xac, /* i64.extend_s/i32 */
+ WASM_OP_I64_EXTEND_U_I32 = 0xad, /* i64.extend_u/i32 */
+ WASM_OP_I64_TRUNC_S_F32 = 0xae, /* i64.trunc_s/f32 */
+ WASM_OP_I64_TRUNC_U_F32 = 0xaf, /* i64.trunc_u/f32 */
+ WASM_OP_I64_TRUNC_S_F64 = 0xb0, /* i64.trunc_s/f64 */
+ WASM_OP_I64_TRUNC_U_F64 = 0xb1, /* i64.trunc_u/f64 */
+
+ WASM_OP_F32_CONVERT_S_I32 = 0xb2, /* f32.convert_s/i32 */
+ WASM_OP_F32_CONVERT_U_I32 = 0xb3, /* f32.convert_u/i32 */
+ WASM_OP_F32_CONVERT_S_I64 = 0xb4, /* f32.convert_s/i64 */
+ WASM_OP_F32_CONVERT_U_I64 = 0xb5, /* f32.convert_u/i64 */
+ WASM_OP_F32_DEMOTE_F64 = 0xb6, /* f32.demote/f64 */
+
+ WASM_OP_F64_CONVERT_S_I32 = 0xb7, /* f64.convert_s/i32 */
+ WASM_OP_F64_CONVERT_U_I32 = 0xb8, /* f64.convert_u/i32 */
+ WASM_OP_F64_CONVERT_S_I64 = 0xb9, /* f64.convert_s/i64 */
+ WASM_OP_F64_CONVERT_U_I64 = 0xba, /* f64.convert_u/i64 */
+ WASM_OP_F64_PROMOTE_F32 = 0xbb, /* f64.promote/f32 */
+
+ /* reinterpretations */
+ WASM_OP_I32_REINTERPRET_F32 = 0xbc, /* i32.reinterpret/f32 */
+ WASM_OP_I64_REINTERPRET_F64 = 0xbd, /* i64.reinterpret/f64 */
+ WASM_OP_F32_REINTERPRET_I32 = 0xbe, /* f32.reinterpret/i32 */
+ WASM_OP_F64_REINTERPRET_I64 = 0xbf, /* f64.reinterpret/i64 */
+
+ WASM_OP_I32_EXTEND8_S = 0xc0, /* i32.extend8_s */
+ WASM_OP_I32_EXTEND16_S = 0xc1, /* i32.extend16_s */
+ WASM_OP_I64_EXTEND8_S = 0xc2, /* i64.extend8_s */
+ WASM_OP_I64_EXTEND16_S = 0xc3, /* i64.extend16_s */
+ WASM_OP_I64_EXTEND32_S = 0xc4, /* i64.extend32_s */
+
+ /* drop/select specified types*/
+ WASM_OP_DROP_64 = 0xc5,
+ WASM_OP_SELECT_64 = 0xc6,
+
+ /* extend op code */
+ EXT_OP_GET_LOCAL_FAST = 0xc7,
+ EXT_OP_SET_LOCAL_FAST_I64 = 0xc8,
+ EXT_OP_SET_LOCAL_FAST = 0xc9,
+ EXT_OP_TEE_LOCAL_FAST = 0xca,
+ EXT_OP_TEE_LOCAL_FAST_I64 = 0xcb,
+ EXT_OP_COPY_STACK_TOP = 0xcc,
+ EXT_OP_COPY_STACK_TOP_I64 = 0xcd,
+ EXT_OP_COPY_STACK_VALUES = 0xce,
+
+ WASM_OP_IMPDEP = 0xcf,
+
+ WASM_OP_REF_NULL = 0xd0, /* ref.null */
+ WASM_OP_REF_IS_NULL = 0xd1, /* ref.is_null */
+ WASM_OP_REF_FUNC = 0xd2, /* ref.func */
+
+ EXT_OP_BLOCK = 0xd3, /* block with blocktype */
+ EXT_OP_LOOP = 0xd4, /* loop with blocktype */
+ EXT_OP_IF = 0xd5, /* if with blocktype */
+ EXT_OP_BR_TABLE_CACHE = 0xd6, /* br_table from cache */
+
+#if WASM_ENABLE_DEBUG_INTERP != 0
+ DEBUG_OP_BREAK = 0xd7, /* debug break point */
+#endif
+
+ /* Post-MVP extend op prefix */
+ WASM_OP_MISC_PREFIX = 0xfc,
+ WASM_OP_SIMD_PREFIX = 0xfd,
+ WASM_OP_ATOMIC_PREFIX = 0xfe,
+} WASMOpcode;
+
+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,
+ WASM_OP_I32_TRUNC_SAT_U_F64 = 0x03,
+ WASM_OP_I64_TRUNC_SAT_S_F32 = 0x04,
+ WASM_OP_I64_TRUNC_SAT_U_F32 = 0x05,
+ WASM_OP_I64_TRUNC_SAT_S_F64 = 0x06,
+ WASM_OP_I64_TRUNC_SAT_U_F64 = 0x07,
+ 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,
+ WASM_OP_TABLE_GROW = 0x0f,
+ WASM_OP_TABLE_SIZE = 0x10,
+ WASM_OP_TABLE_FILL = 0x11,
+} WASMMiscEXTOpcode;
+
+typedef enum WASMSimdEXTOpcode {
+ /* memory instruction */
+ SIMD_v128_load = 0x00,
+ SIMD_v128_load8x8_s = 0x01,
+ SIMD_v128_load8x8_u = 0x02,
+ SIMD_v128_load16x4_s = 0x03,
+ SIMD_v128_load16x4_u = 0x04,
+ SIMD_v128_load32x2_s = 0x05,
+ SIMD_v128_load32x2_u = 0x06,
+ SIMD_v128_load8_splat = 0x07,
+ SIMD_v128_load16_splat = 0x08,
+ SIMD_v128_load32_splat = 0x09,
+ SIMD_v128_load64_splat = 0x0a,
+ SIMD_v128_store = 0x0b,
+
+ /* basic operation */
+ SIMD_v128_const = 0x0c,
+ SIMD_v8x16_shuffle = 0x0d,
+ SIMD_v8x16_swizzle = 0x0e,
+
+ /* splat operation */
+ SIMD_i8x16_splat = 0x0f,
+ SIMD_i16x8_splat = 0x10,
+ SIMD_i32x4_splat = 0x11,
+ SIMD_i64x2_splat = 0x12,
+ SIMD_f32x4_splat = 0x13,
+ SIMD_f64x2_splat = 0x14,
+
+ /* lane operation */
+ SIMD_i8x16_extract_lane_s = 0x15,
+ SIMD_i8x16_extract_lane_u = 0x16,
+ SIMD_i8x16_replace_lane = 0x17,
+ SIMD_i16x8_extract_lane_s = 0x18,
+ SIMD_i16x8_extract_lane_u = 0x19,
+ SIMD_i16x8_replace_lane = 0x1a,
+ SIMD_i32x4_extract_lane = 0x1b,
+ SIMD_i32x4_replace_lane = 0x1c,
+ SIMD_i64x2_extract_lane = 0x1d,
+ SIMD_i64x2_replace_lane = 0x1e,
+ SIMD_f32x4_extract_lane = 0x1f,
+ SIMD_f32x4_replace_lane = 0x20,
+ SIMD_f64x2_extract_lane = 0x21,
+ SIMD_f64x2_replace_lane = 0x22,
+
+ /* i8x16 compare operation */
+ SIMD_i8x16_eq = 0x23,
+ SIMD_i8x16_ne = 0x24,
+ SIMD_i8x16_lt_s = 0x25,
+ SIMD_i8x16_lt_u = 0x26,
+ SIMD_i8x16_gt_s = 0x27,
+ SIMD_i8x16_gt_u = 0x28,
+ SIMD_i8x16_le_s = 0x29,
+ SIMD_i8x16_le_u = 0x2a,
+ SIMD_i8x16_ge_s = 0x2b,
+ SIMD_i8x16_ge_u = 0x2c,
+
+ /* i16x8 compare operation */
+ SIMD_i16x8_eq = 0x2d,
+ SIMD_i16x8_ne = 0x2e,
+ SIMD_i16x8_lt_s = 0x2f,
+ SIMD_i16x8_lt_u = 0x30,
+ SIMD_i16x8_gt_s = 0x31,
+ SIMD_i16x8_gt_u = 0x32,
+ SIMD_i16x8_le_s = 0x33,
+ SIMD_i16x8_le_u = 0x34,
+ SIMD_i16x8_ge_s = 0x35,
+ SIMD_i16x8_ge_u = 0x36,
+
+ /* i32x4 compare operation */
+ SIMD_i32x4_eq = 0x37,
+ SIMD_i32x4_ne = 0x38,
+ SIMD_i32x4_lt_s = 0x39,
+ SIMD_i32x4_lt_u = 0x3a,
+ SIMD_i32x4_gt_s = 0x3b,
+ SIMD_i32x4_gt_u = 0x3c,
+ SIMD_i32x4_le_s = 0x3d,
+ SIMD_i32x4_le_u = 0x3e,
+ SIMD_i32x4_ge_s = 0x3f,
+ SIMD_i32x4_ge_u = 0x40,
+
+ /* f32x4 compare operation */
+ SIMD_f32x4_eq = 0x41,
+ SIMD_f32x4_ne = 0x42,
+ SIMD_f32x4_lt = 0x43,
+ SIMD_f32x4_gt = 0x44,
+ SIMD_f32x4_le = 0x45,
+ SIMD_f32x4_ge = 0x46,
+
+ /* f64x2 compare operation */
+ SIMD_f64x2_eq = 0x47,
+ SIMD_f64x2_ne = 0x48,
+ SIMD_f64x2_lt = 0x49,
+ SIMD_f64x2_gt = 0x4a,
+ SIMD_f64x2_le = 0x4b,
+ SIMD_f64x2_ge = 0x4c,
+
+ /* v128 operation */
+ SIMD_v128_not = 0x4d,
+ SIMD_v128_and = 0x4e,
+ SIMD_v128_andnot = 0x4f,
+ SIMD_v128_or = 0x50,
+ SIMD_v128_xor = 0x51,
+ SIMD_v128_bitselect = 0x52,
+ SIMD_v128_any_true = 0x53,
+
+ /* Load Lane Operation */
+ SIMD_v128_load8_lane = 0x54,
+ SIMD_v128_load16_lane = 0x55,
+ SIMD_v128_load32_lane = 0x56,
+ SIMD_v128_load64_lane = 0x57,
+ SIMD_v128_store8_lane = 0x58,
+ SIMD_v128_store16_lane = 0x59,
+ SIMD_v128_store32_lane = 0x5a,
+ SIMD_v128_store64_lane = 0x5b,
+ SIMD_v128_load32_zero = 0x5c,
+ SIMD_v128_load64_zero = 0x5d,
+
+ /* Float conversion */
+ SIMD_f32x4_demote_f64x2_zero = 0x5e,
+ SIMD_f64x2_promote_low_f32x4_zero = 0x5f,
+
+ /* i8x16 Operation */
+ SIMD_i8x16_abs = 0x60,
+ SIMD_i8x16_neg = 0x61,
+ SIMD_i8x16_popcnt = 0x62,
+ SIMD_i8x16_all_true = 0x63,
+ SIMD_i8x16_bitmask = 0x64,
+ SIMD_i8x16_narrow_i16x8_s = 0x65,
+ SIMD_i8x16_narrow_i16x8_u = 0x66,
+ SIMD_f32x4_ceil = 0x67,
+ SIMD_f32x4_floor = 0x68,
+ SIMD_f32x4_trunc = 0x69,
+ SIMD_f32x4_nearest = 0x6a,
+ SIMD_i8x16_shl = 0x6b,
+ SIMD_i8x16_shr_s = 0x6c,
+ SIMD_i8x16_shr_u = 0x6d,
+ SIMD_i8x16_add = 0x6e,
+ SIMD_i8x16_add_sat_s = 0x6f,
+ SIMD_i8x16_add_sat_u = 0x70,
+ SIMD_i8x16_sub = 0x71,
+ SIMD_i8x16_sub_sat_s = 0x72,
+ SIMD_i8x16_sub_sat_u = 0x73,
+ SIMD_f64x2_ceil = 0x74,
+ SIMD_f64x2_floor = 0x75,
+ SIMD_i8x16_min_s = 0x76,
+ SIMD_i8x16_min_u = 0x77,
+ SIMD_i8x16_max_s = 0x78,
+ SIMD_i8x16_max_u = 0x79,
+ SIMD_f64x2_trunc = 0x7a,
+ SIMD_i8x16_avgr_u = 0x7b,
+ SIMD_i16x8_extadd_pairwise_i8x16_s = 0x7c,
+ SIMD_i16x8_extadd_pairwise_i8x16_u = 0x7d,
+ SIMD_i32x4_extadd_pairwise_i16x8_s = 0x7e,
+ SIMD_i32x4_extadd_pairwise_i16x8_u = 0x7f,
+
+ /* i16x8 operation */
+ SIMD_i16x8_abs = 0x80,
+ SIMD_i16x8_neg = 0x81,
+ SIMD_i16x8_q15mulr_sat_s = 0x82,
+ SIMD_i16x8_all_true = 0x83,
+ SIMD_i16x8_bitmask = 0x84,
+ SIMD_i16x8_narrow_i32x4_s = 0x85,
+ SIMD_i16x8_narrow_i32x4_u = 0x86,
+ SIMD_i16x8_extend_low_i8x16_s = 0x87,
+ SIMD_i16x8_extend_high_i8x16_s = 0x88,
+ SIMD_i16x8_extend_low_i8x16_u = 0x89,
+ SIMD_i16x8_extend_high_i8x16_u = 0x8a,
+ SIMD_i16x8_shl = 0x8b,
+ SIMD_i16x8_shr_s = 0x8c,
+ SIMD_i16x8_shr_u = 0x8d,
+ SIMD_i16x8_add = 0x8e,
+ SIMD_i16x8_add_sat_s = 0x8f,
+ SIMD_i16x8_add_sat_u = 0x90,
+ SIMD_i16x8_sub = 0x91,
+ SIMD_i16x8_sub_sat_s = 0x92,
+ SIMD_i16x8_sub_sat_u = 0x93,
+ SIMD_f64x2_nearest = 0x94,
+ SIMD_i16x8_mul = 0x95,
+ SIMD_i16x8_min_s = 0x96,
+ SIMD_i16x8_min_u = 0x97,
+ SIMD_i16x8_max_s = 0x98,
+ SIMD_i16x8_max_u = 0x99,
+ /* placeholder = 0x9a */
+ SIMD_i16x8_avgr_u = 0x9b,
+ SIMD_i16x8_extmul_low_i8x16_s = 0x9c,
+ SIMD_i16x8_extmul_high_i8x16_s = 0x9d,
+ SIMD_i16x8_extmul_low_i8x16_u = 0x9e,
+ SIMD_i16x8_extmul_high_i8x16_u = 0x9f,
+
+ /* i32x4 operation */
+ SIMD_i32x4_abs = 0xa0,
+ SIMD_i32x4_neg = 0xa1,
+ /* placeholder = 0xa2 */
+ SIMD_i32x4_all_true = 0xa3,
+ SIMD_i32x4_bitmask = 0xa4,
+ SIMD_i32x4_narrow_i64x2_s = 0xa5,
+ SIMD_i32x4_narrow_i64x2_u = 0xa6,
+ SIMD_i32x4_extend_low_i16x8_s = 0xa7,
+ SIMD_i32x4_extend_high_i16x8_s = 0xa8,
+ SIMD_i32x4_extend_low_i16x8_u = 0xa9,
+ SIMD_i32x4_extend_high_i16x8_u = 0xaa,
+ SIMD_i32x4_shl = 0xab,
+ SIMD_i32x4_shr_s = 0xac,
+ SIMD_i32x4_shr_u = 0xad,
+ SIMD_i32x4_add = 0xae,
+ SIMD_i32x4_add_sat_s = 0xaf,
+ SIMD_i32x4_add_sat_u = 0xb0,
+ SIMD_i32x4_sub = 0xb1,
+ SIMD_i32x4_sub_sat_s = 0xb2,
+ SIMD_i32x4_sub_sat_u = 0xb3,
+ /* placeholder = 0xb4 */
+ SIMD_i32x4_mul = 0xb5,
+ SIMD_i32x4_min_s = 0xb6,
+ SIMD_i32x4_min_u = 0xb7,
+ SIMD_i32x4_max_s = 0xb8,
+ SIMD_i32x4_max_u = 0xb9,
+ SIMD_i32x4_dot_i16x8_s = 0xba,
+ SIMD_i32x4_avgr_u = 0xbb,
+ SIMD_i32x4_extmul_low_i16x8_s = 0xbc,
+ SIMD_i32x4_extmul_high_i16x8_s = 0xbd,
+ SIMD_i32x4_extmul_low_i16x8_u = 0xbe,
+ SIMD_i32x4_extmul_high_i16x8_u = 0xbf,
+
+ /* i64x2 operation */
+ SIMD_i64x2_abs = 0xc0,
+ SIMD_i64x2_neg = 0xc1,
+ /* placeholder = 0xc2 */
+ SIMD_i64x2_all_true = 0xc3,
+ SIMD_i64x2_bitmask = 0xc4,
+ /* placeholder = 0xc5 */
+ /* placeholder = 0xc6 */
+ SIMD_i64x2_extend_low_i32x4_s = 0xc7,
+ SIMD_i64x2_extend_high_i32x4_s = 0xc8,
+ SIMD_i64x2_extend_low_i32x4_u = 0xc9,
+ SIMD_i64x2_extend_high_i32x4_u = 0xca,
+ SIMD_i64x2_shl = 0xcb,
+ SIMD_i64x2_shr_s = 0xcc,
+ SIMD_i64x2_shr_u = 0xcd,
+ SIMD_i64x2_add = 0xce,
+ /* placeholder = 0xcf */
+ /* placeholder = 0xd0 */
+ SIMD_i64x2_sub = 0xd1,
+ /* placeholder = 0xd2 */
+ /* placeholder = 0xd3 */
+ /* placeholder = 0xd4 */
+ SIMD_i64x2_mul = 0xd5,
+ SIMD_i64x2_eq = 0xd6,
+ SIMD_i64x2_ne = 0xd7,
+ SIMD_i64x2_lt_s = 0xd8,
+ SIMD_i64x2_gt_s = 0xd9,
+ SIMD_i64x2_le_s = 0xda,
+ SIMD_i64x2_ge_s = 0xdb,
+ SIMD_i64x2_extmul_low_i32x4_s = 0xdc,
+ SIMD_i64x2_extmul_high_i32x4_s = 0xdd,
+ SIMD_i64x2_extmul_low_i32x4_u = 0xde,
+ SIMD_i64x2_extmul_high_i32x4_u = 0xdf,
+
+ /* f32x4 operation */
+ SIMD_f32x4_abs = 0xe0,
+ SIMD_f32x4_neg = 0xe1,
+ SIMD_f32x4_round = 0xe2,
+ SIMD_f32x4_sqrt = 0xe3,
+ SIMD_f32x4_add = 0xe4,
+ SIMD_f32x4_sub = 0xe5,
+ SIMD_f32x4_mul = 0xe6,
+ SIMD_f32x4_div = 0xe7,
+ SIMD_f32x4_min = 0xe8,
+ SIMD_f32x4_max = 0xe9,
+ SIMD_f32x4_pmin = 0xea,
+ SIMD_f32x4_pmax = 0xeb,
+
+ /* f64x2 operation */
+ SIMD_f64x2_abs = 0xec,
+ SIMD_f64x2_neg = 0xed,
+ SIMD_f64x2_round = 0xee,
+ SIMD_f64x2_sqrt = 0xef,
+ SIMD_f64x2_add = 0xf0,
+ SIMD_f64x2_sub = 0xf1,
+ SIMD_f64x2_mul = 0xf2,
+ SIMD_f64x2_div = 0xf3,
+ SIMD_f64x2_min = 0xf4,
+ SIMD_f64x2_max = 0xf5,
+ SIMD_f64x2_pmin = 0xf6,
+ SIMD_f64x2_pmax = 0xf7,
+
+ /* conversion operation */
+ SIMD_i32x4_trunc_sat_f32x4_s = 0xf8,
+ SIMD_i32x4_trunc_sat_f32x4_u = 0xf9,
+ SIMD_f32x4_convert_i32x4_s = 0xfa,
+ SIMD_f32x4_convert_i32x4_u = 0xfb,
+ SIMD_i32x4_trunc_sat_f64x2_s_zero = 0xfc,
+ SIMD_i32x4_trunc_sat_f64x2_u_zero = 0xfd,
+ SIMD_f64x2_convert_low_i32x4_s = 0xfe,
+ SIMD_f64x2_convert_low_i32x4_u = 0xff,
+} WASMSimdEXTOpcode;
+
+typedef enum WASMAtomicEXTOpcode {
+ /* atomic wait and notify */
+ WASM_OP_ATOMIC_NOTIFY = 0x00,
+ WASM_OP_ATOMIC_WAIT32 = 0x01,
+ WASM_OP_ATOMIC_WAIT64 = 0x02,
+ WASM_OP_ATOMIC_FENCE = 0x03,
+ /* atomic load and store */
+ WASM_OP_ATOMIC_I32_LOAD = 0x10,
+ WASM_OP_ATOMIC_I64_LOAD = 0x11,
+ WASM_OP_ATOMIC_I32_LOAD8_U = 0x12,
+ WASM_OP_ATOMIC_I32_LOAD16_U = 0x13,
+ WASM_OP_ATOMIC_I64_LOAD8_U = 0x14,
+ WASM_OP_ATOMIC_I64_LOAD16_U = 0x15,
+ WASM_OP_ATOMIC_I64_LOAD32_U = 0x16,
+ WASM_OP_ATOMIC_I32_STORE = 0x17,
+ WASM_OP_ATOMIC_I64_STORE = 0x18,
+ WASM_OP_ATOMIC_I32_STORE8 = 0x19,
+ WASM_OP_ATOMIC_I32_STORE16 = 0x1a,
+ WASM_OP_ATOMIC_I64_STORE8 = 0x1b,
+ WASM_OP_ATOMIC_I64_STORE16 = 0x1c,
+ WASM_OP_ATOMIC_I64_STORE32 = 0x1d,
+ /* atomic add */
+ WASM_OP_ATOMIC_RMW_I32_ADD = 0x1e,
+ WASM_OP_ATOMIC_RMW_I64_ADD = 0x1f,
+ WASM_OP_ATOMIC_RMW_I32_ADD8_U = 0x20,
+ WASM_OP_ATOMIC_RMW_I32_ADD16_U = 0x21,
+ WASM_OP_ATOMIC_RMW_I64_ADD8_U = 0x22,
+ WASM_OP_ATOMIC_RMW_I64_ADD16_U = 0x23,
+ WASM_OP_ATOMIC_RMW_I64_ADD32_U = 0x24,
+ /* atomic sub */
+ WASM_OP_ATOMIC_RMW_I32_SUB = 0x25,
+ WASM_OP_ATOMIC_RMW_I64_SUB = 0x26,
+ WASM_OP_ATOMIC_RMW_I32_SUB8_U = 0x27,
+ WASM_OP_ATOMIC_RMW_I32_SUB16_U = 0x28,
+ WASM_OP_ATOMIC_RMW_I64_SUB8_U = 0x29,
+ WASM_OP_ATOMIC_RMW_I64_SUB16_U = 0x2a,
+ WASM_OP_ATOMIC_RMW_I64_SUB32_U = 0x2b,
+ /* atomic and */
+ WASM_OP_ATOMIC_RMW_I32_AND = 0x2c,
+ WASM_OP_ATOMIC_RMW_I64_AND = 0x2d,
+ WASM_OP_ATOMIC_RMW_I32_AND8_U = 0x2e,
+ WASM_OP_ATOMIC_RMW_I32_AND16_U = 0x2f,
+ WASM_OP_ATOMIC_RMW_I64_AND8_U = 0x30,
+ WASM_OP_ATOMIC_RMW_I64_AND16_U = 0x31,
+ WASM_OP_ATOMIC_RMW_I64_AND32_U = 0x32,
+ /* atomic or */
+ WASM_OP_ATOMIC_RMW_I32_OR = 0x33,
+ WASM_OP_ATOMIC_RMW_I64_OR = 0x34,
+ WASM_OP_ATOMIC_RMW_I32_OR8_U = 0x35,
+ WASM_OP_ATOMIC_RMW_I32_OR16_U = 0x36,
+ WASM_OP_ATOMIC_RMW_I64_OR8_U = 0x37,
+ WASM_OP_ATOMIC_RMW_I64_OR16_U = 0x38,
+ WASM_OP_ATOMIC_RMW_I64_OR32_U = 0x39,
+ /* atomic xor */
+ WASM_OP_ATOMIC_RMW_I32_XOR = 0x3a,
+ WASM_OP_ATOMIC_RMW_I64_XOR = 0x3b,
+ WASM_OP_ATOMIC_RMW_I32_XOR8_U = 0x3c,
+ WASM_OP_ATOMIC_RMW_I32_XOR16_U = 0x3d,
+ WASM_OP_ATOMIC_RMW_I64_XOR8_U = 0x3e,
+ WASM_OP_ATOMIC_RMW_I64_XOR16_U = 0x3f,
+ WASM_OP_ATOMIC_RMW_I64_XOR32_U = 0x40,
+ /* atomic xchg */
+ WASM_OP_ATOMIC_RMW_I32_XCHG = 0x41,
+ WASM_OP_ATOMIC_RMW_I64_XCHG = 0x42,
+ WASM_OP_ATOMIC_RMW_I32_XCHG8_U = 0x43,
+ WASM_OP_ATOMIC_RMW_I32_XCHG16_U = 0x44,
+ WASM_OP_ATOMIC_RMW_I64_XCHG8_U = 0x45,
+ WASM_OP_ATOMIC_RMW_I64_XCHG16_U = 0x46,
+ WASM_OP_ATOMIC_RMW_I64_XCHG32_U = 0x47,
+ /* atomic cmpxchg */
+ WASM_OP_ATOMIC_RMW_I32_CMPXCHG = 0x48,
+ WASM_OP_ATOMIC_RMW_I64_CMPXCHG = 0x49,
+ WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U = 0x4a,
+ WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U = 0x4b,
+ WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U = 0x4c,
+ WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U = 0x4d,
+ WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U = 0x4e,
+} WASMAtomicEXTOpcode;
+
+#if WASM_ENABLE_DEBUG_INTERP != 0
+#define DEF_DEBUG_BREAK_HANDLE() \
+ [DEBUG_OP_BREAK] = HANDLE_OPCODE(DEBUG_OP_BREAK), /* 0xd7 */
+#else
+#define DEF_DEBUG_BREAK_HANDLE()
+#endif
+
+#define SET_GOTO_TABLE_ELEM(opcode) [opcode] = HANDLE_OPCODE(opcode)
+
+/*
+ * Macro used to generate computed goto tables for the C interpreter.
+ */
+#define WASM_INSTRUCTION_NUM 256
+
+#define DEFINE_GOTO_TABLE(type, _name) \
+ static type _name[WASM_INSTRUCTION_NUM] = { \
+ HANDLE_OPCODE(WASM_OP_UNREACHABLE), /* 0x00 */ \
+ HANDLE_OPCODE(WASM_OP_NOP), /* 0x01 */ \
+ HANDLE_OPCODE(WASM_OP_BLOCK), /* 0x02 */ \
+ HANDLE_OPCODE(WASM_OP_LOOP), /* 0x03 */ \
+ HANDLE_OPCODE(WASM_OP_IF), /* 0x04 */ \
+ HANDLE_OPCODE(WASM_OP_ELSE), /* 0x05 */ \
+ HANDLE_OPCODE(WASM_OP_UNUSED_0x06), /* 0x06 */ \
+ HANDLE_OPCODE(WASM_OP_UNUSED_0x07), /* 0x07 */ \
+ HANDLE_OPCODE(WASM_OP_UNUSED_0x08), /* 0x08 */ \
+ HANDLE_OPCODE(WASM_OP_UNUSED_0x09), /* 0x09 */ \
+ HANDLE_OPCODE(WASM_OP_UNUSED_0x0a), /* 0x0a */ \
+ HANDLE_OPCODE(WASM_OP_END), /* 0x0b */ \
+ HANDLE_OPCODE(WASM_OP_BR), /* 0x0c */ \
+ HANDLE_OPCODE(WASM_OP_BR_IF), /* 0x0d */ \
+ HANDLE_OPCODE(WASM_OP_BR_TABLE), /* 0x0e */ \
+ HANDLE_OPCODE(WASM_OP_RETURN), /* 0x0f */ \
+ HANDLE_OPCODE(WASM_OP_CALL), /* 0x10 */ \
+ HANDLE_OPCODE(WASM_OP_CALL_INDIRECT), /* 0x11 */ \
+ HANDLE_OPCODE(WASM_OP_RETURN_CALL), /* 0x12 */ \
+ HANDLE_OPCODE(WASM_OP_RETURN_CALL_INDIRECT), /* 0x13 */ \
+ HANDLE_OPCODE(WASM_OP_UNUSED_0x14), /* 0x14 */ \
+ HANDLE_OPCODE(WASM_OP_UNUSED_0x15), /* 0x15 */ \
+ HANDLE_OPCODE(WASM_OP_UNUSED_0x16), /* 0x16 */ \
+ HANDLE_OPCODE(WASM_OP_UNUSED_0x17), /* 0x17 */ \
+ HANDLE_OPCODE(WASM_OP_UNUSED_0x18), /* 0x18 */ \
+ HANDLE_OPCODE(WASM_OP_UNUSED_0x19), /* 0x19 */ \
+ HANDLE_OPCODE(WASM_OP_DROP), /* 0x1a */ \
+ HANDLE_OPCODE(WASM_OP_SELECT), /* 0x1b */ \
+ HANDLE_OPCODE(WASM_OP_SELECT_T), /* 0x1c */ \
+ HANDLE_OPCODE(WASM_OP_GET_GLOBAL_64), /* 0x1d */ \
+ HANDLE_OPCODE(WASM_OP_SET_GLOBAL_64), /* 0x1e */ \
+ HANDLE_OPCODE(WASM_OP_SET_GLOBAL_AUX_STACK), /* 0x1f */ \
+ HANDLE_OPCODE(WASM_OP_GET_LOCAL), /* 0x20 */ \
+ HANDLE_OPCODE(WASM_OP_SET_LOCAL), /* 0x21 */ \
+ HANDLE_OPCODE(WASM_OP_TEE_LOCAL), /* 0x22 */ \
+ HANDLE_OPCODE(WASM_OP_GET_GLOBAL), /* 0x23 */ \
+ HANDLE_OPCODE(WASM_OP_SET_GLOBAL), /* 0x24 */ \
+ HANDLE_OPCODE(WASM_OP_TABLE_GET), /* 0x25 */ \
+ HANDLE_OPCODE(WASM_OP_TABLE_SET), /* 0x26 */ \
+ HANDLE_OPCODE(WASM_OP_UNUSED_0x27), /* 0x27 */ \
+ HANDLE_OPCODE(WASM_OP_I32_LOAD), /* 0x28 */ \
+ HANDLE_OPCODE(WASM_OP_I64_LOAD), /* 0x29 */ \
+ HANDLE_OPCODE(WASM_OP_F32_LOAD), /* 0x2a */ \
+ HANDLE_OPCODE(WASM_OP_F64_LOAD), /* 0x2b */ \
+ HANDLE_OPCODE(WASM_OP_I32_LOAD8_S), /* 0x2c */ \
+ HANDLE_OPCODE(WASM_OP_I32_LOAD8_U), /* 0x2d */ \
+ HANDLE_OPCODE(WASM_OP_I32_LOAD16_S), /* 0x2e */ \
+ HANDLE_OPCODE(WASM_OP_I32_LOAD16_U), /* 0x2f */ \
+ HANDLE_OPCODE(WASM_OP_I64_LOAD8_S), /* 0x30 */ \
+ HANDLE_OPCODE(WASM_OP_I64_LOAD8_U), /* 0x31 */ \
+ HANDLE_OPCODE(WASM_OP_I64_LOAD16_S), /* 0x32 */ \
+ HANDLE_OPCODE(WASM_OP_I64_LOAD16_U), /* 0x33 */ \
+ HANDLE_OPCODE(WASM_OP_I64_LOAD32_S), /* 0x34 */ \
+ HANDLE_OPCODE(WASM_OP_I64_LOAD32_U), /* 0x35 */ \
+ HANDLE_OPCODE(WASM_OP_I32_STORE), /* 0x36 */ \
+ HANDLE_OPCODE(WASM_OP_I64_STORE), /* 0x37 */ \
+ HANDLE_OPCODE(WASM_OP_F32_STORE), /* 0x38 */ \
+ HANDLE_OPCODE(WASM_OP_F64_STORE), /* 0x39 */ \
+ HANDLE_OPCODE(WASM_OP_I32_STORE8), /* 0x3a */ \
+ HANDLE_OPCODE(WASM_OP_I32_STORE16), /* 0x3b */ \
+ HANDLE_OPCODE(WASM_OP_I64_STORE8), /* 0x3c */ \
+ HANDLE_OPCODE(WASM_OP_I64_STORE16), /* 0x3d */ \
+ HANDLE_OPCODE(WASM_OP_I64_STORE32), /* 0x3e */ \
+ HANDLE_OPCODE(WASM_OP_MEMORY_SIZE), /* 0x3f */ \
+ HANDLE_OPCODE(WASM_OP_MEMORY_GROW), /* 0x40 */ \
+ HANDLE_OPCODE(WASM_OP_I32_CONST), /* 0x41 */ \
+ HANDLE_OPCODE(WASM_OP_I64_CONST), /* 0x42 */ \
+ HANDLE_OPCODE(WASM_OP_F32_CONST), /* 0x43 */ \
+ HANDLE_OPCODE(WASM_OP_F64_CONST), /* 0x44 */ \
+ HANDLE_OPCODE(WASM_OP_I32_EQZ), /* 0x45 */ \
+ HANDLE_OPCODE(WASM_OP_I32_EQ), /* 0x46 */ \
+ HANDLE_OPCODE(WASM_OP_I32_NE), /* 0x47 */ \
+ HANDLE_OPCODE(WASM_OP_I32_LT_S), /* 0x48 */ \
+ HANDLE_OPCODE(WASM_OP_I32_LT_U), /* 0x49 */ \
+ HANDLE_OPCODE(WASM_OP_I32_GT_S), /* 0x4a */ \
+ HANDLE_OPCODE(WASM_OP_I32_GT_U), /* 0x4b */ \
+ HANDLE_OPCODE(WASM_OP_I32_LE_S), /* 0x4c */ \
+ HANDLE_OPCODE(WASM_OP_I32_LE_U), /* 0x4d */ \
+ HANDLE_OPCODE(WASM_OP_I32_GE_S), /* 0x4e */ \
+ HANDLE_OPCODE(WASM_OP_I32_GE_U), /* 0x4f */ \
+ HANDLE_OPCODE(WASM_OP_I64_EQZ), /* 0x50 */ \
+ HANDLE_OPCODE(WASM_OP_I64_EQ), /* 0x51 */ \
+ HANDLE_OPCODE(WASM_OP_I64_NE), /* 0x52 */ \
+ HANDLE_OPCODE(WASM_OP_I64_LT_S), /* 0x53 */ \
+ HANDLE_OPCODE(WASM_OP_I64_LT_U), /* 0x54 */ \
+ HANDLE_OPCODE(WASM_OP_I64_GT_S), /* 0x55 */ \
+ HANDLE_OPCODE(WASM_OP_I64_GT_U), /* 0x56 */ \
+ HANDLE_OPCODE(WASM_OP_I64_LE_S), /* 0x57 */ \
+ HANDLE_OPCODE(WASM_OP_I64_LE_U), /* 0x58 */ \
+ HANDLE_OPCODE(WASM_OP_I64_GE_S), /* 0x59 */ \
+ HANDLE_OPCODE(WASM_OP_I64_GE_U), /* 0x5a */ \
+ HANDLE_OPCODE(WASM_OP_F32_EQ), /* 0x5b */ \
+ HANDLE_OPCODE(WASM_OP_F32_NE), /* 0x5c */ \
+ HANDLE_OPCODE(WASM_OP_F32_LT), /* 0x5d */ \
+ HANDLE_OPCODE(WASM_OP_F32_GT), /* 0x5e */ \
+ HANDLE_OPCODE(WASM_OP_F32_LE), /* 0x5f */ \
+ HANDLE_OPCODE(WASM_OP_F32_GE), /* 0x60 */ \
+ HANDLE_OPCODE(WASM_OP_F64_EQ), /* 0x61 */ \
+ HANDLE_OPCODE(WASM_OP_F64_NE), /* 0x62 */ \
+ HANDLE_OPCODE(WASM_OP_F64_LT), /* 0x63 */ \
+ HANDLE_OPCODE(WASM_OP_F64_GT), /* 0x64 */ \
+ HANDLE_OPCODE(WASM_OP_F64_LE), /* 0x65 */ \
+ HANDLE_OPCODE(WASM_OP_F64_GE), /* 0x66 */ \
+ HANDLE_OPCODE(WASM_OP_I32_CLZ), /* 0x67 */ \
+ HANDLE_OPCODE(WASM_OP_I32_CTZ), /* 0x68 */ \
+ HANDLE_OPCODE(WASM_OP_I32_POPCNT), /* 0x69 */ \
+ HANDLE_OPCODE(WASM_OP_I32_ADD), /* 0x6a */ \
+ HANDLE_OPCODE(WASM_OP_I32_SUB), /* 0x6b */ \
+ HANDLE_OPCODE(WASM_OP_I32_MUL), /* 0x6c */ \
+ HANDLE_OPCODE(WASM_OP_I32_DIV_S), /* 0x6d */ \
+ HANDLE_OPCODE(WASM_OP_I32_DIV_U), /* 0x6e */ \
+ HANDLE_OPCODE(WASM_OP_I32_REM_S), /* 0x6f */ \
+ HANDLE_OPCODE(WASM_OP_I32_REM_U), /* 0x70 */ \
+ HANDLE_OPCODE(WASM_OP_I32_AND), /* 0x71 */ \
+ HANDLE_OPCODE(WASM_OP_I32_OR), /* 0x72 */ \
+ HANDLE_OPCODE(WASM_OP_I32_XOR), /* 0x73 */ \
+ HANDLE_OPCODE(WASM_OP_I32_SHL), /* 0x74 */ \
+ HANDLE_OPCODE(WASM_OP_I32_SHR_S), /* 0x75 */ \
+ HANDLE_OPCODE(WASM_OP_I32_SHR_U), /* 0x76 */ \
+ HANDLE_OPCODE(WASM_OP_I32_ROTL), /* 0x77 */ \
+ HANDLE_OPCODE(WASM_OP_I32_ROTR), /* 0x78 */ \
+ HANDLE_OPCODE(WASM_OP_I64_CLZ), /* 0x79 */ \
+ HANDLE_OPCODE(WASM_OP_I64_CTZ), /* 0x7a */ \
+ HANDLE_OPCODE(WASM_OP_I64_POPCNT), /* 0x7b */ \
+ HANDLE_OPCODE(WASM_OP_I64_ADD), /* 0x7c */ \
+ HANDLE_OPCODE(WASM_OP_I64_SUB), /* 0x7d */ \
+ HANDLE_OPCODE(WASM_OP_I64_MUL), /* 0x7e */ \
+ HANDLE_OPCODE(WASM_OP_I64_DIV_S), /* 0x7f */ \
+ HANDLE_OPCODE(WASM_OP_I64_DIV_U), /* 0x80 */ \
+ HANDLE_OPCODE(WASM_OP_I64_REM_S), /* 0x81 */ \
+ HANDLE_OPCODE(WASM_OP_I64_REM_U), /* 0x82 */ \
+ HANDLE_OPCODE(WASM_OP_I64_AND), /* 0x83 */ \
+ HANDLE_OPCODE(WASM_OP_I64_OR), /* 0x84 */ \
+ HANDLE_OPCODE(WASM_OP_I64_XOR), /* 0x85 */ \
+ HANDLE_OPCODE(WASM_OP_I64_SHL), /* 0x86 */ \
+ HANDLE_OPCODE(WASM_OP_I64_SHR_S), /* 0x87 */ \
+ HANDLE_OPCODE(WASM_OP_I64_SHR_U), /* 0x88 */ \
+ HANDLE_OPCODE(WASM_OP_I64_ROTL), /* 0x89 */ \
+ HANDLE_OPCODE(WASM_OP_I64_ROTR), /* 0x8a */ \
+ HANDLE_OPCODE(WASM_OP_F32_ABS), /* 0x8b */ \
+ HANDLE_OPCODE(WASM_OP_F32_NEG), /* 0x8c */ \
+ HANDLE_OPCODE(WASM_OP_F32_CEIL), /* 0x8d */ \
+ HANDLE_OPCODE(WASM_OP_F32_FLOOR), /* 0x8e */ \
+ HANDLE_OPCODE(WASM_OP_F32_TRUNC), /* 0x8f */ \
+ HANDLE_OPCODE(WASM_OP_F32_NEAREST), /* 0x90 */ \
+ HANDLE_OPCODE(WASM_OP_F32_SQRT), /* 0x91 */ \
+ HANDLE_OPCODE(WASM_OP_F32_ADD), /* 0x92 */ \
+ HANDLE_OPCODE(WASM_OP_F32_SUB), /* 0x93 */ \
+ HANDLE_OPCODE(WASM_OP_F32_MUL), /* 0x94 */ \
+ HANDLE_OPCODE(WASM_OP_F32_DIV), /* 0x95 */ \
+ HANDLE_OPCODE(WASM_OP_F32_MIN), /* 0x96 */ \
+ HANDLE_OPCODE(WASM_OP_F32_MAX), /* 0x97 */ \
+ HANDLE_OPCODE(WASM_OP_F32_COPYSIGN), /* 0x98 */ \
+ HANDLE_OPCODE(WASM_OP_F64_ABS), /* 0x99 */ \
+ HANDLE_OPCODE(WASM_OP_F64_NEG), /* 0x9a */ \
+ HANDLE_OPCODE(WASM_OP_F64_CEIL), /* 0x9b */ \
+ HANDLE_OPCODE(WASM_OP_F64_FLOOR), /* 0x9c */ \
+ HANDLE_OPCODE(WASM_OP_F64_TRUNC), /* 0x9d */ \
+ HANDLE_OPCODE(WASM_OP_F64_NEAREST), /* 0x9e */ \
+ HANDLE_OPCODE(WASM_OP_F64_SQRT), /* 0x9f */ \
+ HANDLE_OPCODE(WASM_OP_F64_ADD), /* 0xa0 */ \
+ HANDLE_OPCODE(WASM_OP_F64_SUB), /* 0xa1 */ \
+ HANDLE_OPCODE(WASM_OP_F64_MUL), /* 0xa2 */ \
+ HANDLE_OPCODE(WASM_OP_F64_DIV), /* 0xa3 */ \
+ HANDLE_OPCODE(WASM_OP_F64_MIN), /* 0xa4 */ \
+ HANDLE_OPCODE(WASM_OP_F64_MAX), /* 0xa5 */ \
+ HANDLE_OPCODE(WASM_OP_F64_COPYSIGN), /* 0xa6 */ \
+ HANDLE_OPCODE(WASM_OP_I32_WRAP_I64), /* 0xa7 */ \
+ HANDLE_OPCODE(WASM_OP_I32_TRUNC_S_F32), /* 0xa8 */ \
+ HANDLE_OPCODE(WASM_OP_I32_TRUNC_U_F32), /* 0xa9 */ \
+ HANDLE_OPCODE(WASM_OP_I32_TRUNC_S_F64), /* 0xaa */ \
+ HANDLE_OPCODE(WASM_OP_I32_TRUNC_U_F64), /* 0xab */ \
+ HANDLE_OPCODE(WASM_OP_I64_EXTEND_S_I32), /* 0xac */ \
+ HANDLE_OPCODE(WASM_OP_I64_EXTEND_U_I32), /* 0xad */ \
+ HANDLE_OPCODE(WASM_OP_I64_TRUNC_S_F32), /* 0xae */ \
+ HANDLE_OPCODE(WASM_OP_I64_TRUNC_U_F32), /* 0xaf */ \
+ HANDLE_OPCODE(WASM_OP_I64_TRUNC_S_F64), /* 0xb0 */ \
+ HANDLE_OPCODE(WASM_OP_I64_TRUNC_U_F64), /* 0xb1 */ \
+ HANDLE_OPCODE(WASM_OP_F32_CONVERT_S_I32), /* 0xb2 */ \
+ HANDLE_OPCODE(WASM_OP_F32_CONVERT_U_I32), /* 0xb3 */ \
+ HANDLE_OPCODE(WASM_OP_F32_CONVERT_S_I64), /* 0xb4 */ \
+ HANDLE_OPCODE(WASM_OP_F32_CONVERT_U_I64), /* 0xb5 */ \
+ HANDLE_OPCODE(WASM_OP_F32_DEMOTE_F64), /* 0xb6 */ \
+ HANDLE_OPCODE(WASM_OP_F64_CONVERT_S_I32), /* 0xb7 */ \
+ HANDLE_OPCODE(WASM_OP_F64_CONVERT_U_I32), /* 0xb8 */ \
+ HANDLE_OPCODE(WASM_OP_F64_CONVERT_S_I64), /* 0xb9 */ \
+ HANDLE_OPCODE(WASM_OP_F64_CONVERT_U_I64), /* 0xba */ \
+ HANDLE_OPCODE(WASM_OP_F64_PROMOTE_F32), /* 0xbb */ \
+ HANDLE_OPCODE(WASM_OP_I32_REINTERPRET_F32), /* 0xbc */ \
+ HANDLE_OPCODE(WASM_OP_I64_REINTERPRET_F64), /* 0xbd */ \
+ HANDLE_OPCODE(WASM_OP_F32_REINTERPRET_I32), /* 0xbe */ \
+ HANDLE_OPCODE(WASM_OP_F64_REINTERPRET_I64), /* 0xbf */ \
+ HANDLE_OPCODE(WASM_OP_I32_EXTEND8_S), /* 0xc0 */ \
+ HANDLE_OPCODE(WASM_OP_I32_EXTEND16_S), /* 0xc1 */ \
+ HANDLE_OPCODE(WASM_OP_I64_EXTEND8_S), /* 0xc2 */ \
+ HANDLE_OPCODE(WASM_OP_I64_EXTEND16_S), /* 0xc3 */ \
+ HANDLE_OPCODE(WASM_OP_I64_EXTEND32_S), /* 0xc4 */ \
+ HANDLE_OPCODE(WASM_OP_DROP_64), /* 0xc5 */ \
+ HANDLE_OPCODE(WASM_OP_SELECT_64), /* 0xc6 */ \
+ HANDLE_OPCODE(EXT_OP_GET_LOCAL_FAST), /* 0xc7 */ \
+ HANDLE_OPCODE(EXT_OP_SET_LOCAL_FAST_I64), /* 0xc8 */ \
+ HANDLE_OPCODE(EXT_OP_SET_LOCAL_FAST), /* 0xc9 */ \
+ HANDLE_OPCODE(EXT_OP_TEE_LOCAL_FAST), /* 0xca */ \
+ HANDLE_OPCODE(EXT_OP_TEE_LOCAL_FAST_I64), /* 0xcb */ \
+ HANDLE_OPCODE(EXT_OP_COPY_STACK_TOP), /* 0xcc */ \
+ HANDLE_OPCODE(EXT_OP_COPY_STACK_TOP_I64), /* 0xcd */ \
+ HANDLE_OPCODE(EXT_OP_COPY_STACK_VALUES), /* 0xce */ \
+ HANDLE_OPCODE(WASM_OP_IMPDEP), /* 0xcf */ \
+ HANDLE_OPCODE(WASM_OP_REF_NULL), /* 0xd0 */ \
+ HANDLE_OPCODE(WASM_OP_REF_IS_NULL), /* 0xd1 */ \
+ HANDLE_OPCODE(WASM_OP_REF_FUNC), /* 0xd2 */ \
+ HANDLE_OPCODE(EXT_OP_BLOCK), /* 0xd3 */ \
+ HANDLE_OPCODE(EXT_OP_LOOP), /* 0xd4 */ \
+ HANDLE_OPCODE(EXT_OP_IF), /* 0xd5 */ \
+ HANDLE_OPCODE(EXT_OP_BR_TABLE_CACHE), /* 0xd6 */ \
+ SET_GOTO_TABLE_ELEM(WASM_OP_MISC_PREFIX), /* 0xfc */ \
+ SET_GOTO_TABLE_ELEM(WASM_OP_ATOMIC_PREFIX), /* 0xfe */ \
+ DEF_DEBUG_BREAK_HANDLE() \
+ };
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end of _WASM_OPCODE_H */
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_runtime.c b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_runtime.c
new file mode 100644
index 000000000..29365024d
--- /dev/null
+++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_runtime.c
@@ -0,0 +1,3532 @@
+/*
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "wasm_runtime.h"
+#include "wasm_loader.h"
+#include "wasm_interp.h"
+#include "bh_common.h"
+#include "bh_log.h"
+#include "mem_alloc.h"
+#include "../common/wasm_runtime_common.h"
+#if WASM_ENABLE_SHARED_MEMORY != 0
+#include "../common/wasm_shared_memory.h"
+#endif
+#if WASM_ENABLE_THREAD_MGR != 0
+#include "../libraries/thread-mgr/thread_manager.h"
+#endif
+#if WASM_ENABLE_DEBUG_INTERP != 0
+#include "../libraries/debug-engine/debug_engine.h"
+#endif
+#if WASM_ENABLE_FAST_JIT != 0
+#include "../fast-jit/jit_compiler.h"
+#endif
+#if WASM_ENABLE_JIT != 0
+#include "../aot/aot_runtime.h"
+#endif
+
+static void
+set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
+{
+ if (error_buf != NULL) {
+ snprintf(error_buf, error_buf_size,
+ "WASM module instantiate failed: %s", string);
+ }
+}
+
+static void
+set_error_buf_v(char *error_buf, uint32 error_buf_size, const char *format, ...)
+{
+ va_list args;
+ char buf[128];
+
+ if (error_buf != NULL) {
+ va_start(args, format);
+ vsnprintf(buf, sizeof(buf), format, args);
+ va_end(args);
+ snprintf(error_buf, error_buf_size,
+ "WASM module instantiate failed: %s", buf);
+ }
+}
+
+WASMModule *
+wasm_load(uint8 *buf, uint32 size, char *error_buf, uint32 error_buf_size)
+{
+ return wasm_loader_load(buf, size,
+#if WASM_ENABLE_MULTI_MODULE != 0
+ true,
+#endif
+ error_buf, error_buf_size);
+}
+
+WASMModule *
+wasm_load_from_sections(WASMSection *section_list, char *error_buf,
+ uint32 error_buf_size)
+{
+ return wasm_loader_load_from_sections(section_list, error_buf,
+ error_buf_size);
+}
+
+void
+wasm_unload(WASMModule *module)
+{
+ wasm_loader_unload(module);
+}
+
+static void *
+runtime_malloc(uint64 size, char *error_buf, uint32 error_buf_size)
+{
+ void *mem;
+
+ if (size >= UINT32_MAX || !(mem = wasm_runtime_malloc((uint32)size))) {
+ set_error_buf(error_buf, error_buf_size, "allocate memory failed");
+ return NULL;
+ }
+
+ memset(mem, 0, (uint32)size);
+ return mem;
+}
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+static WASMModuleInstance *
+get_sub_module_inst(const WASMModuleInstance *parent_module_inst,
+ const WASMModule *sub_module)
+{
+ bh_list *sub_module_inst_list = parent_module_inst->e->sub_module_inst_list;
+ WASMSubModInstNode *node = bh_list_first_elem(sub_module_inst_list);
+
+ while (node && sub_module != node->module_inst->module) {
+ node = bh_list_elem_next(node);
+ }
+ return node ? node->module_inst : NULL;
+}
+#endif
+
+/**
+ * Destroy memory instances.
+ */
+static void
+memories_deinstantiate(WASMModuleInstance *module_inst,
+ WASMMemoryInstance **memories, uint32 count)
+{
+ uint32 i;
+ if (memories) {
+ for (i = 0; i < count; i++) {
+ if (memories[i]) {
+#if WASM_ENABLE_MULTI_MODULE != 0
+ WASMModule *module = module_inst->module;
+ if (i < module->import_memory_count
+ && module->import_memories[i].u.memory.import_module) {
+ continue;
+ }
+#endif
+#if WASM_ENABLE_SHARED_MEMORY != 0
+ if (memories[i]->is_shared) {
+ int32 ref_count = shared_memory_dec_reference(
+ (WASMModuleCommon *)module_inst->module);
+ bh_assert(ref_count >= 0);
+
+ /* if the reference count is not zero,
+ don't free the memory */
+ if (ref_count > 0)
+ continue;
+ }
+#endif
+ if (memories[i]->heap_handle) {
+ mem_allocator_destroy(memories[i]->heap_handle);
+ wasm_runtime_free(memories[i]->heap_handle);
+ memories[i]->heap_handle = NULL;
+ }
+ if (memories[i]->memory_data) {
+#ifndef OS_ENABLE_HW_BOUND_CHECK
+ wasm_runtime_free(memories[i]->memory_data);
+#else
+#ifdef BH_PLATFORM_WINDOWS
+ os_mem_decommit(memories[i]->memory_data,
+ memories[i]->num_bytes_per_page
+ * memories[i]->cur_page_count);
+#endif
+ os_munmap((uint8 *)memories[i]->memory_data,
+ 8 * (uint64)BH_GB);
+#endif
+ }
+ }
+ }
+ wasm_runtime_free(memories);
+ }
+ (void)module_inst;
+}
+
+static WASMMemoryInstance *
+memory_instantiate(WASMModuleInstance *module_inst, WASMMemoryInstance *memory,
+ uint32 num_bytes_per_page, uint32 init_page_count,
+ uint32 max_page_count, uint32 heap_size, uint32 flags,
+ char *error_buf, uint32 error_buf_size)
+{
+ WASMModule *module = module_inst->module;
+ uint64 memory_data_size;
+ uint32 heap_offset = num_bytes_per_page * init_page_count;
+ uint32 inc_page_count, aux_heap_base, global_idx;
+ uint32 bytes_of_last_page, bytes_to_page_end;
+ uint8 *global_addr;
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ uint8 *mapped_mem;
+ uint64 map_size = 8 * (uint64)BH_GB;
+ uint64 page_size = os_getpagesize();
+#endif
+
+#if WASM_ENABLE_SHARED_MEMORY != 0
+ bool is_shared_memory = flags & 0x02 ? true : false;
+
+ /* shared memory */
+ if (is_shared_memory) {
+ WASMSharedMemNode *node = wasm_module_get_shared_memory(
+ (WASMModuleCommon *)module_inst->module);
+ /* If the memory of this module has been instantiated,
+ return the memory instance directly */
+ if (node) {
+ uint32 ref_count;
+ ref_count = shared_memory_inc_reference(
+ (WASMModuleCommon *)module_inst->module);
+ bh_assert(ref_count > 0);
+ memory = (WASMMemoryInstance *)shared_memory_get_memory_inst(node);
+ bh_assert(memory);
+
+ (void)ref_count;
+ return memory;
+ }
+ }
+#endif /* end of WASM_ENABLE_SHARED_MEMORY */
+
+ if (heap_size > 0 && module_inst->module->malloc_function != (uint32)-1
+ && module_inst->module->free_function != (uint32)-1) {
+ /* Disable app heap, use malloc/free function exported
+ by wasm app to allocate/free memory instead */
+ heap_size = 0;
+ }
+
+ if (init_page_count == max_page_count && init_page_count == 1) {
+ /* If only one page and at most one page, we just append
+ the app heap to the end of linear memory, enlarge the
+ num_bytes_per_page, and don't change the page count */
+ heap_offset = num_bytes_per_page;
+ num_bytes_per_page += heap_size;
+ if (num_bytes_per_page < heap_size) {
+ set_error_buf(error_buf, error_buf_size,
+ "failed to insert app heap into linear memory, "
+ "try using `--heap_size=0` option");
+ return NULL;
+ }
+ }
+ else if (heap_size > 0) {
+ if (init_page_count == max_page_count && init_page_count == 0) {
+ /* If the memory data size is always 0, we resize it to
+ one page for app heap */
+ num_bytes_per_page = heap_size;
+ heap_offset = 0;
+ inc_page_count = 1;
+ }
+ else if (module->aux_heap_base_global_index != (uint32)-1
+ && module->aux_heap_base
+ < num_bytes_per_page * init_page_count) {
+ /* Insert app heap before __heap_base */
+ aux_heap_base = module->aux_heap_base;
+ bytes_of_last_page = aux_heap_base % num_bytes_per_page;
+ if (bytes_of_last_page == 0)
+ bytes_of_last_page = num_bytes_per_page;
+ bytes_to_page_end = num_bytes_per_page - bytes_of_last_page;
+ inc_page_count =
+ (heap_size - bytes_to_page_end + num_bytes_per_page - 1)
+ / num_bytes_per_page;
+ heap_offset = aux_heap_base;
+ aux_heap_base += heap_size;
+
+ bytes_of_last_page = aux_heap_base % num_bytes_per_page;
+ if (bytes_of_last_page == 0)
+ bytes_of_last_page = num_bytes_per_page;
+ bytes_to_page_end = num_bytes_per_page - bytes_of_last_page;
+ if (bytes_to_page_end < 1 * BH_KB) {
+ aux_heap_base += 1 * BH_KB;
+ inc_page_count++;
+ }
+
+ /* Adjust __heap_base global value */
+ global_idx = module->aux_heap_base_global_index;
+ bh_assert(module_inst->e->globals
+ && global_idx < module_inst->e->global_count);
+ global_addr = module_inst->global_data
+ + module_inst->e->globals[global_idx].data_offset;
+ *(uint32 *)global_addr = aux_heap_base;
+ LOG_VERBOSE("Reset __heap_base global to %u", aux_heap_base);
+ }
+ else {
+ /* Insert app heap before new page */
+ inc_page_count =
+ (heap_size + num_bytes_per_page - 1) / num_bytes_per_page;
+ heap_offset = num_bytes_per_page * init_page_count;
+ heap_size = num_bytes_per_page * inc_page_count;
+ if (heap_size > 0)
+ heap_size -= 1 * BH_KB;
+ }
+ init_page_count += inc_page_count;
+ max_page_count += inc_page_count;
+ if (init_page_count > DEFAULT_MAX_PAGES) {
+ set_error_buf(error_buf, error_buf_size,
+ "failed to insert app heap into linear memory, "
+ "try using `--heap_size=0` option");
+ return NULL;
+ }
+ else if (init_page_count == DEFAULT_MAX_PAGES) {
+ num_bytes_per_page = UINT32_MAX;
+ init_page_count = max_page_count = 1;
+ }
+ if (max_page_count > DEFAULT_MAX_PAGES)
+ max_page_count = DEFAULT_MAX_PAGES;
+ }
+
+ LOG_VERBOSE("Memory instantiate:");
+ LOG_VERBOSE(" page bytes: %u, init pages: %u, max pages: %u",
+ num_bytes_per_page, init_page_count, max_page_count);
+ LOG_VERBOSE(" heap offset: %u, heap size: %d\n", heap_offset, heap_size);
+
+ memory_data_size = (uint64)num_bytes_per_page * init_page_count;
+#if WASM_ENABLE_SHARED_MEMORY != 0
+ if (is_shared_memory) {
+ /* Allocate max page for shared memory */
+ memory_data_size = (uint64)num_bytes_per_page * max_page_count;
+ }
+#endif
+ bh_assert(memory_data_size <= 4 * (uint64)BH_GB);
+
+ bh_assert(memory != NULL);
+#ifndef OS_ENABLE_HW_BOUND_CHECK
+ if (memory_data_size > 0
+ && !(memory->memory_data =
+ runtime_malloc(memory_data_size, error_buf, error_buf_size))) {
+ goto fail1;
+ }
+#else
+ memory_data_size = (memory_data_size + page_size - 1) & ~(page_size - 1);
+
+ /* Totally 8G is mapped, the opcode load/store address range is 0 to 8G:
+ * ea = i + memarg.offset
+ * both i and memarg.offset are u32 in range 0 to 4G
+ * so the range of ea is 0 to 8G
+ */
+ if (!(memory->memory_data = mapped_mem =
+ os_mmap(NULL, map_size, MMAP_PROT_NONE, MMAP_MAP_NONE))) {
+ set_error_buf(error_buf, error_buf_size, "mmap memory failed");
+ goto fail1;
+ }
+
+#ifdef BH_PLATFORM_WINDOWS
+ if (!os_mem_commit(mapped_mem, memory_data_size,
+ MMAP_PROT_READ | MMAP_PROT_WRITE)) {
+ set_error_buf(error_buf, error_buf_size, "commit memory failed");
+ os_munmap(mapped_mem, map_size);
+ goto fail1;
+ }
+#endif
+
+ if (os_mprotect(mapped_mem, memory_data_size,
+ MMAP_PROT_READ | MMAP_PROT_WRITE)
+ != 0) {
+ set_error_buf(error_buf, error_buf_size, "mprotect memory failed");
+ goto fail2;
+ }
+ /* Newly allocated pages are filled with zero by the OS, we don't fill it
+ * again here */
+#endif /* end of OS_ENABLE_HW_BOUND_CHECK */
+
+ if (memory_data_size > UINT32_MAX)
+ memory_data_size = (uint32)memory_data_size;
+
+ memory->module_type = Wasm_Module_Bytecode;
+ memory->num_bytes_per_page = num_bytes_per_page;
+ memory->cur_page_count = init_page_count;
+ memory->max_page_count = max_page_count;
+ memory->memory_data_size = (uint32)memory_data_size;
+
+ memory->heap_data = memory->memory_data + heap_offset;
+ memory->heap_data_end = memory->heap_data + heap_size;
+ memory->memory_data_end = memory->memory_data + (uint32)memory_data_size;
+
+ /* Initialize heap */
+ if (heap_size > 0) {
+ uint32 heap_struct_size = mem_allocator_get_heap_struct_size();
+
+ if (!(memory->heap_handle = runtime_malloc(
+ (uint64)heap_struct_size, error_buf, error_buf_size))) {
+ goto fail2;
+ }
+ if (!mem_allocator_create_with_struct_and_pool(
+ memory->heap_handle, heap_struct_size, memory->heap_data,
+ heap_size)) {
+ set_error_buf(error_buf, error_buf_size, "init app heap failed");
+ goto fail3;
+ }
+ }
+
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0
+ if (memory_data_size > 0) {
+#if UINTPTR_MAX == UINT64_MAX
+ memory->mem_bound_check_1byte.u64 = memory_data_size - 1;
+ memory->mem_bound_check_2bytes.u64 = memory_data_size - 2;
+ memory->mem_bound_check_4bytes.u64 = memory_data_size - 4;
+ memory->mem_bound_check_8bytes.u64 = memory_data_size - 8;
+ memory->mem_bound_check_16bytes.u64 = memory_data_size - 16;
+#else
+ memory->mem_bound_check_1byte.u32[0] = (uint32)memory_data_size - 1;
+ memory->mem_bound_check_2bytes.u32[0] = (uint32)memory_data_size - 2;
+ memory->mem_bound_check_4bytes.u32[0] = (uint32)memory_data_size - 4;
+ memory->mem_bound_check_8bytes.u32[0] = (uint32)memory_data_size - 8;
+ memory->mem_bound_check_16bytes.u32[0] = (uint32)memory_data_size - 16;
+#endif
+ }
+#endif
+
+#if WASM_ENABLE_SHARED_MEMORY != 0
+ if (is_shared_memory) {
+ memory->is_shared = true;
+ if (!shared_memory_set_memory_inst(
+ (WASMModuleCommon *)module_inst->module,
+ (WASMMemoryInstanceCommon *)memory)) {
+ set_error_buf(error_buf, error_buf_size, "allocate memory failed");
+ goto fail4;
+ }
+ }
+#endif
+
+ LOG_VERBOSE("Memory instantiate success.");
+ return memory;
+
+#if WASM_ENABLE_SHARED_MEMORY != 0
+fail4:
+ if (heap_size > 0)
+ mem_allocator_destroy(memory->heap_handle);
+#endif
+fail3:
+ if (heap_size > 0)
+ wasm_runtime_free(memory->heap_handle);
+fail2:
+#ifndef OS_ENABLE_HW_BOUND_CHECK
+ if (memory->memory_data)
+ wasm_runtime_free(memory->memory_data);
+#else
+#ifdef BH_PLATFORM_WINDOWS
+ os_mem_decommit(mapped_mem, memory_data_size);
+#endif
+ os_munmap(mapped_mem, map_size);
+#endif
+fail1:
+ return NULL;
+}
+
+/**
+ * Instantiate memories in a module.
+ */
+static WASMMemoryInstance **
+memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
+ uint32 heap_size, char *error_buf, uint32 error_buf_size)
+{
+ WASMImport *import;
+ uint32 mem_index = 0, i,
+ memory_count = module->import_memory_count + module->memory_count;
+ uint64 total_size;
+ WASMMemoryInstance **memories, *memory;
+
+ total_size = sizeof(WASMMemoryInstance *) * (uint64)memory_count;
+
+ if (!(memories = runtime_malloc(total_size, error_buf, error_buf_size))) {
+ return NULL;
+ }
+
+ memory = module_inst->global_table_data.memory_instances;
+
+ /* instantiate memories from import section */
+ import = module->import_memories;
+ for (i = 0; i < module->import_memory_count; i++, import++, memory++) {
+ uint32 num_bytes_per_page = import->u.memory.num_bytes_per_page;
+ uint32 init_page_count = import->u.memory.init_page_count;
+ uint32 max_page_count = import->u.memory.max_page_count;
+ uint32 flags = import->u.memory.flags;
+ uint32 actual_heap_size = heap_size;
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+ if (import->u.memory.import_module != NULL) {
+ WASMModuleInstance *module_inst_linked;
+
+ if (!(module_inst_linked = get_sub_module_inst(
+ module_inst, import->u.memory.import_module))) {
+ set_error_buf(error_buf, error_buf_size, "unknown memory");
+ memories_deinstantiate(module_inst, memories, memory_count);
+ return NULL;
+ }
+
+ if (!(memories[mem_index++] = wasm_lookup_memory(
+ module_inst_linked, import->u.memory.field_name))) {
+ set_error_buf(error_buf, error_buf_size, "unknown memory");
+ memories_deinstantiate(module_inst, memories, memory_count);
+ return NULL;
+ }
+ }
+ else
+#endif
+ {
+ if (!(memories[mem_index++] = memory_instantiate(
+ module_inst, memory, num_bytes_per_page, init_page_count,
+ max_page_count, actual_heap_size, flags, error_buf,
+ error_buf_size))) {
+ memories_deinstantiate(module_inst, memories, memory_count);
+ return NULL;
+ }
+ }
+ }
+
+ /* instantiate memories from memory section */
+ for (i = 0; i < module->memory_count; i++, memory++) {
+ if (!(memories[mem_index++] = memory_instantiate(
+ module_inst, memory, module->memories[i].num_bytes_per_page,
+ module->memories[i].init_page_count,
+ module->memories[i].max_page_count, heap_size,
+ module->memories[i].flags, error_buf, error_buf_size))) {
+ memories_deinstantiate(module_inst, memories, memory_count);
+ return NULL;
+ }
+ }
+
+ bh_assert(mem_index == memory_count);
+ (void)module_inst;
+ return memories;
+}
+
+/**
+ * Destroy table instances.
+ */
+static void
+tables_deinstantiate(WASMModuleInstance *module_inst)
+{
+ if (module_inst->tables) {
+ wasm_runtime_free(module_inst->tables);
+ }
+#if WASM_ENABLE_MULTI_MODULE != 0
+ if (module_inst->e->table_insts_linked) {
+ wasm_runtime_free(module_inst->e->table_insts_linked);
+ }
+#endif
+}
+
+/**
+ * Instantiate tables in a module.
+ */
+static WASMTableInstance **
+tables_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
+ WASMTableInstance *first_table, char *error_buf,
+ uint32 error_buf_size)
+{
+ WASMImport *import;
+ uint32 table_index = 0, i;
+ uint32 table_count = module->import_table_count + module->table_count;
+ uint64 total_size = (uint64)sizeof(WASMTableInstance *) * table_count;
+ WASMTableInstance **tables, *table = first_table;
+#if WASM_ENABLE_MULTI_MODULE != 0
+ uint64 total_size_of_tables_linked =
+ (uint64)sizeof(WASMTableInstance *) * module->import_table_count;
+ WASMTableInstance **table_linked = NULL;
+#endif
+
+ if (!(tables = runtime_malloc(total_size, error_buf, error_buf_size))) {
+ return NULL;
+ }
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+ if (module->import_table_count > 0
+ && !(module_inst->e->table_insts_linked = table_linked = runtime_malloc(
+ total_size_of_tables_linked, error_buf, error_buf_size))) {
+ goto fail;
+ }
+#endif
+
+ /* instantiate tables from import section */
+ import = module->import_tables;
+ for (i = 0; i < module->import_table_count; i++, import++) {
+ uint32 max_size_fixed = 0;
+#if WASM_ENABLE_MULTI_MODULE != 0
+ WASMTableInstance *table_inst_linked = NULL;
+ WASMModuleInstance *module_inst_linked = NULL;
+
+ if (import->u.table.import_module) {
+ if (!(module_inst_linked = get_sub_module_inst(
+ module_inst, import->u.table.import_module))) {
+ set_error_buf(error_buf, error_buf_size, "unknown table");
+ goto fail;
+ }
+
+ if (!(table_inst_linked = wasm_lookup_table(
+ module_inst_linked, import->u.table.field_name))) {
+ set_error_buf(error_buf, error_buf_size, "unknown table");
+ goto fail;
+ }
+
+ total_size = offsetof(WASMTableInstance, elems);
+ }
+ else
+#endif
+ {
+ /* in order to save memory, alloc resource as few as possible */
+ max_size_fixed = import->u.table.possible_grow
+ ? import->u.table.max_size
+ : import->u.table.init_size;
+
+ /* it is a built-in table, every module has its own */
+ total_size = offsetof(WASMTableInstance, elems);
+ total_size += (uint64)max_size_fixed * sizeof(uint32);
+ }
+
+ tables[table_index++] = table;
+
+ /* Set all elements to -1 to mark them as uninitialized elements */
+ memset(table, -1, (uint32)total_size);
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+ *table_linked = table_inst_linked;
+ if (table_inst_linked != NULL) {
+ table->cur_size = table_inst_linked->cur_size;
+ table->max_size = table_inst_linked->max_size;
+ }
+ else
+#endif
+ {
+ table->cur_size = import->u.table.init_size;
+ table->max_size = max_size_fixed;
+ }
+
+ table = (WASMTableInstance *)((uint8 *)table + (uint32)total_size);
+#if WASM_ENABLE_MULTI_MODULE != 0
+ table_linked++;
+#endif
+ }
+
+ /* instantiate tables from table section */
+ for (i = 0; i < module->table_count; i++) {
+ uint32 max_size_fixed = 0;
+
+ total_size = offsetof(WASMTableInstance, elems);
+#if WASM_ENABLE_MULTI_MODULE != 0
+ /* in case, a module which imports this table will grow it */
+ max_size_fixed = module->tables[i].max_size;
+#else
+ max_size_fixed = module->tables[i].possible_grow
+ ? module->tables[i].max_size
+ : module->tables[i].init_size;
+#endif
+ total_size += sizeof(uint32) * (uint64)max_size_fixed;
+
+ tables[table_index++] = table;
+
+ /* Set all elements to -1 to mark them as uninitialized elements */
+ memset(table, -1, (uint32)total_size);
+ table->cur_size = module->tables[i].init_size;
+ table->max_size = max_size_fixed;
+
+ table = (WASMTableInstance *)((uint8 *)table + (uint32)total_size);
+ }
+
+ bh_assert(table_index == table_count);
+ (void)module_inst;
+ return tables;
+#if WASM_ENABLE_MULTI_MODULE != 0
+fail:
+ wasm_runtime_free(tables);
+ return NULL;
+#endif
+}
+
+/**
+ * Destroy function instances.
+ */
+static void
+functions_deinstantiate(WASMFunctionInstance *functions, uint32 count)
+{
+ if (functions) {
+ wasm_runtime_free(functions);
+ }
+}
+
+/**
+ * Instantiate functions in a module.
+ */
+static WASMFunctionInstance *
+functions_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
+ char *error_buf, uint32 error_buf_size)
+{
+ WASMImport *import;
+ uint32 i,
+ function_count = module->import_function_count + module->function_count;
+ uint64 total_size = sizeof(WASMFunctionInstance) * (uint64)function_count;
+ WASMFunctionInstance *functions, *function;
+
+ if (!(functions = runtime_malloc(total_size, error_buf, error_buf_size))) {
+ return NULL;
+ }
+
+ total_size = sizeof(void *) * (uint64)module->import_function_count;
+ if (total_size > 0
+ && !(module_inst->import_func_ptrs =
+ runtime_malloc(total_size, error_buf, error_buf_size))) {
+ wasm_runtime_free(functions);
+ return NULL;
+ }
+
+ /* instantiate functions from import section */
+ function = functions;
+ import = module->import_functions;
+ for (i = 0; i < module->import_function_count; i++, import++) {
+ function->is_import_func = true;
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+ if (import->u.function.import_module) {
+ function->import_module_inst = get_sub_module_inst(
+ module_inst, import->u.function.import_module);
+
+ if (function->import_module_inst) {
+ function->import_func_inst =
+ wasm_lookup_function(function->import_module_inst,
+ import->u.function.field_name, NULL);
+ }
+ }
+#endif /* WASM_ENABLE_MULTI_MODULE */
+ function->u.func_import = &import->u.function;
+ function->param_cell_num = import->u.function.func_type->param_cell_num;
+ function->ret_cell_num = import->u.function.func_type->ret_cell_num;
+ function->param_count =
+ (uint16)function->u.func_import->func_type->param_count;
+ function->param_types = function->u.func_import->func_type->types;
+ function->local_cell_num = 0;
+ function->local_count = 0;
+ function->local_types = NULL;
+
+ /* Copy the function pointer to current instance */
+ module_inst->import_func_ptrs[i] =
+ function->u.func_import->func_ptr_linked;
+
+ function++;
+ }
+
+ /* instantiate functions from function section */
+ for (i = 0; i < module->function_count; i++) {
+ function->is_import_func = false;
+ function->u.func = module->functions[i];
+
+ function->param_cell_num = function->u.func->param_cell_num;
+ function->ret_cell_num = function->u.func->ret_cell_num;
+ function->local_cell_num = function->u.func->local_cell_num;
+
+ function->param_count =
+ (uint16)function->u.func->func_type->param_count;
+ function->local_count = (uint16)function->u.func->local_count;
+ function->param_types = function->u.func->func_type->types;
+ function->local_types = function->u.func->local_types;
+
+ function->local_offsets = function->u.func->local_offsets;
+
+#if WASM_ENABLE_FAST_INTERP != 0
+ function->const_cell_num = function->u.func->const_cell_num;
+#endif
+
+ function++;
+ }
+ bh_assert((uint32)(function - functions) == function_count);
+
+#if WASM_ENABLE_FAST_JIT != 0
+ module_inst->fast_jit_func_ptrs = module->fast_jit_func_ptrs;
+#endif
+
+ return functions;
+}
+
+/**
+ * Destroy global instances.
+ */
+static void
+globals_deinstantiate(WASMGlobalInstance *globals)
+{
+ if (globals)
+ wasm_runtime_free(globals);
+}
+
+static bool
+check_global_init_expr(const WASMModule *module, uint32 global_index,
+ char *error_buf, uint32 error_buf_size)
+{
+ if (global_index >= module->import_global_count + module->global_count) {
+ set_error_buf_v(error_buf, error_buf_size, "unknown global %d",
+ global_index);
+ return false;
+ }
+
+ /**
+ * Currently, constant expressions occurring as initializers of
+ * globals are further constrained in that contained global.get
+ * instructions are only allowed to refer to imported globals.
+ *
+ * And initializer expression cannot reference a mutable global.
+ */
+ if (global_index >= module->import_global_count
+ || (module->import_globals + global_index)->u.global.is_mutable) {
+ set_error_buf(error_buf, error_buf_size,
+ "constant expression required");
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Instantiate globals in a module.
+ */
+static WASMGlobalInstance *
+globals_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
+ char *error_buf, uint32 error_buf_size)
+{
+ WASMImport *import;
+ uint32 global_data_offset = 0;
+ uint32 i, global_count = module->import_global_count + module->global_count;
+ uint64 total_size = sizeof(WASMGlobalInstance) * (uint64)global_count;
+ WASMGlobalInstance *globals, *global;
+
+ if (!(globals = runtime_malloc(total_size, error_buf, error_buf_size))) {
+ return NULL;
+ }
+
+ /* instantiate globals from import section */
+ global = globals;
+ import = module->import_globals;
+ for (i = 0; i < module->import_global_count; i++, import++) {
+ WASMGlobalImport *global_import = &import->u.global;
+ global->type = global_import->type;
+ global->is_mutable = global_import->is_mutable;
+#if WASM_ENABLE_MULTI_MODULE != 0
+ if (global_import->import_module) {
+ if (!(global->import_module_inst = get_sub_module_inst(
+ module_inst, global_import->import_module))) {
+ set_error_buf(error_buf, error_buf_size, "unknown global");
+ goto fail;
+ }
+
+ if (!(global->import_global_inst = wasm_lookup_global(
+ global->import_module_inst, global_import->field_name))) {
+ set_error_buf(error_buf, error_buf_size, "unknown global");
+ goto fail;
+ }
+
+ /* The linked global instance has been initialized, we
+ just need to copy the value. */
+ bh_memcpy_s(&(global->initial_value), sizeof(WASMValue),
+ &(global_import->import_global_linked->init_expr),
+ sizeof(WASMValue));
+ }
+ else
+#endif
+ {
+ /* native globals share their initial_values in one module */
+ bh_memcpy_s(&(global->initial_value), sizeof(WASMValue),
+ &(global_import->global_data_linked),
+ sizeof(WASMValue));
+ }
+#if WASM_ENABLE_FAST_JIT != 0
+ bh_assert(global_data_offset == global_import->data_offset);
+#endif
+ global->data_offset = global_data_offset;
+ global_data_offset += wasm_value_type_size(global->type);
+
+ global++;
+ }
+
+ /* instantiate globals from global section */
+ for (i = 0; i < module->global_count; i++) {
+ InitializerExpression *init_expr = &(module->globals[i].init_expr);
+
+ global->type = module->globals[i].type;
+ global->is_mutable = module->globals[i].is_mutable;
+#if WASM_ENABLE_FAST_JIT != 0
+ bh_assert(global_data_offset == module->globals[i].data_offset);
+#endif
+ global->data_offset = global_data_offset;
+ global_data_offset += wasm_value_type_size(global->type);
+
+ if (init_expr->init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) {
+ if (!check_global_init_expr(module, init_expr->u.global_index,
+ error_buf, error_buf_size)) {
+ goto fail;
+ }
+
+ bh_memcpy_s(
+ &(global->initial_value), sizeof(WASMValue),
+ &(globals[init_expr->u.global_index].initial_value),
+ sizeof(globals[init_expr->u.global_index].initial_value));
+ }
+#if WASM_ENABLE_REF_TYPES != 0
+ else if (init_expr->init_expr_type == INIT_EXPR_TYPE_REFNULL_CONST) {
+ global->initial_value.u32 = (uint32)NULL_REF;
+ }
+#endif
+ else {
+ bh_memcpy_s(&(global->initial_value), sizeof(WASMValue),
+ &(init_expr->u), sizeof(init_expr->u));
+ }
+ global++;
+ }
+
+ bh_assert((uint32)(global - globals) == global_count);
+ bh_assert(global_data_offset == module->global_data_size);
+ (void)module_inst;
+ return globals;
+fail:
+ wasm_runtime_free(globals);
+ return NULL;
+}
+
+/**
+ * Return export function count in module export section.
+ */
+static uint32
+get_export_count(const WASMModule *module, uint8 kind)
+{
+ WASMExport *export = module->exports;
+ uint32 count = 0, i;
+
+ for (i = 0; i < module->export_count; i++, export ++)
+ if (export->kind == kind)
+ count++;
+
+ return count;
+}
+
+/**
+ * Destroy export function instances.
+ */
+static void
+export_functions_deinstantiate(WASMExportFuncInstance *functions)
+{
+ if (functions)
+ wasm_runtime_free(functions);
+}
+
+/**
+ * Instantiate export functions in a module.
+ */
+static WASMExportFuncInstance *
+export_functions_instantiate(const WASMModule *module,
+ WASMModuleInstance *module_inst,
+ uint32 export_func_count, char *error_buf,
+ uint32 error_buf_size)
+{
+ WASMExportFuncInstance *export_funcs, *export_func;
+ WASMExport *export = module->exports;
+ uint32 i;
+ uint64 total_size =
+ sizeof(WASMExportFuncInstance) * (uint64)export_func_count;
+
+ if (!(export_func = export_funcs =
+ runtime_malloc(total_size, error_buf, error_buf_size))) {
+ return NULL;
+ }
+
+ for (i = 0; i < module->export_count; i++, export ++)
+ if (export->kind == EXPORT_KIND_FUNC) {
+ export_func->name = export->name;
+ export_func->function = &module_inst->e->functions[export->index];
+ export_func++;
+ }
+
+ bh_assert((uint32)(export_func - export_funcs) == export_func_count);
+ return export_funcs;
+}
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+static void
+export_globals_deinstantiate(WASMExportGlobInstance *globals)
+{
+ if (globals)
+ wasm_runtime_free(globals);
+}
+
+static WASMExportGlobInstance *
+export_globals_instantiate(const WASMModule *module,
+ WASMModuleInstance *module_inst,
+ uint32 export_glob_count, char *error_buf,
+ uint32 error_buf_size)
+{
+ WASMExportGlobInstance *export_globals, *export_global;
+ WASMExport *export = module->exports;
+ uint32 i;
+ uint64 total_size =
+ sizeof(WASMExportGlobInstance) * (uint64)export_glob_count;
+
+ if (!(export_global = export_globals =
+ runtime_malloc(total_size, error_buf, error_buf_size))) {
+ return NULL;
+ }
+
+ for (i = 0; i < module->export_count; i++, export ++)
+ if (export->kind == EXPORT_KIND_GLOBAL) {
+ export_global->name = export->name;
+ export_global->global = &module_inst->e->globals[export->index];
+ export_global++;
+ }
+
+ bh_assert((uint32)(export_global - export_globals) == export_glob_count);
+ return export_globals;
+}
+#endif
+
+static WASMFunctionInstance *
+lookup_post_instantiate_func(WASMModuleInstance *module_inst,
+ const char *func_name)
+{
+ WASMFunctionInstance *func;
+ WASMType *func_type;
+
+ if (!(func = wasm_lookup_function(module_inst, func_name, NULL)))
+ /* Not found */
+ return NULL;
+
+ func_type = func->u.func->func_type;
+ if (!(func_type->param_count == 0 && func_type->result_count == 0))
+ /* Not a valid function type, ignore it */
+ return NULL;
+
+ return func;
+}
+
+static bool
+execute_post_instantiate_functions(WASMModuleInstance *module_inst,
+ bool is_sub_inst, WASMExecEnv *exec_env_main)
+{
+ WASMFunctionInstance *start_func = module_inst->e->start_function;
+ WASMFunctionInstance *initialize_func = NULL;
+ WASMFunctionInstance *post_inst_func = NULL;
+ WASMFunctionInstance *call_ctors_func = NULL;
+#if WASM_ENABLE_LIBC_WASI != 0
+ WASMModule *module = module_inst->module;
+#endif
+ WASMModuleInstanceCommon *module_inst_main = NULL;
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ WASMExecEnv *exec_env_tls = wasm_runtime_get_exec_env_tls();
+#endif
+ WASMExecEnv *exec_env = NULL, *exec_env_created = NULL;
+ bool ret = false;
+
+#if WASM_ENABLE_LIBC_WASI != 0
+ /*
+ * WASI reactor instances may assume that _initialize will be called by
+ * the environment at most once, and that none of their other exports
+ * are accessed before that call.
+ */
+ if (!is_sub_inst && module->import_wasi_api) {
+ initialize_func =
+ lookup_post_instantiate_func(module_inst, "_initialize");
+ }
+#endif
+
+ /* Execute possible "__post_instantiate" function if wasm app is
+ compiled by emsdk's early version */
+ if (!is_sub_inst) {
+ post_inst_func =
+ lookup_post_instantiate_func(module_inst, "__post_instantiate");
+ }
+
+#if WASM_ENABLE_BULK_MEMORY != 0
+ /* Only execute the memory init function for main instance since
+ the data segments will be dropped once initialized */
+ if (!is_sub_inst
+#if WASM_ENABLE_LIBC_WASI != 0
+ && !module->import_wasi_api
+#endif
+ ) {
+ call_ctors_func =
+ lookup_post_instantiate_func(module_inst, "__wasm_call_ctors");
+ }
+#endif
+
+ if (!start_func && !initialize_func && !post_inst_func
+ && !call_ctors_func) {
+ /* No post instantiation functions to call */
+ return true;
+ }
+
+ if (is_sub_inst) {
+ bh_assert(exec_env_main);
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ bh_assert(exec_env_tls == exec_env_main);
+ (void)exec_env_tls;
+#endif
+ exec_env = exec_env_main;
+
+ /* Temporarily replace parent exec_env's module inst to current
+ module inst to avoid checking failure when calling the
+ wasm functions, and ensure that the exec_env's module inst
+ is the correct one. */
+ module_inst_main = exec_env_main->module_inst;
+ exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
+ }
+ else {
+ /* Try using the existing exec_env */
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ exec_env = exec_env_tls;
+#endif
+#if WASM_ENABLE_THREAD_MGR != 0
+ if (!exec_env)
+ exec_env = wasm_clusters_search_exec_env(
+ (WASMModuleInstanceCommon *)module_inst);
+#endif
+ if (!exec_env) {
+ if (!(exec_env = exec_env_created = wasm_exec_env_create(
+ (WASMModuleInstanceCommon *)module_inst,
+ module_inst->default_wasm_stack_size))) {
+ wasm_set_exception(module_inst, "allocate memory failed");
+ return false;
+ }
+ }
+ else {
+ /* Temporarily replace exec_env's module inst with current
+ module inst to ensure that the exec_env's module inst
+ is the correct one. */
+ module_inst_main = exec_env->module_inst;
+ exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
+ }
+ }
+
+ /* Execute start function for both main insance and sub instance */
+ if (start_func && !wasm_call_function(exec_env, start_func, 0, NULL)) {
+ goto fail;
+ }
+
+ if (initialize_func
+ && !wasm_call_function(exec_env, initialize_func, 0, NULL)) {
+ goto fail;
+ }
+
+ if (post_inst_func
+ && !wasm_call_function(exec_env, post_inst_func, 0, NULL)) {
+ goto fail;
+ }
+
+ if (call_ctors_func
+ && !wasm_call_function(exec_env, call_ctors_func, 0, NULL)) {
+ goto fail;
+ }
+
+ ret = true;
+
+fail:
+ if (is_sub_inst) {
+ /* Restore the parent exec_env's module inst */
+ exec_env_main->module_inst = module_inst_main;
+ }
+ else {
+ if (module_inst_main)
+ /* Restore the existing exec_env's module inst */
+ exec_env->module_inst = module_inst_main;
+ if (exec_env_created)
+ wasm_exec_env_destroy(exec_env_created);
+ }
+
+ return ret;
+}
+
+static bool
+execute_malloc_function(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
+ WASMFunctionInstance *malloc_func,
+ WASMFunctionInstance *retain_func, uint32 size,
+ uint32 *p_result)
+{
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ WASMExecEnv *exec_env_tls = wasm_runtime_get_exec_env_tls();
+#endif
+ WASMExecEnv *exec_env_created = NULL;
+ WASMModuleInstanceCommon *module_inst_old = NULL;
+ uint32 argv[2], argc;
+ bool ret;
+
+ argv[0] = size;
+ argc = 1;
+
+ /* if __retain is exported, then this module is compiled by
+ assemblyscript, the memory should be managed by as's runtime,
+ in this case we need to call the retain function after malloc
+ the memory */
+ if (retain_func) {
+ /* the malloc functino from assemblyscript is:
+ function __new(size: usize, id: u32)
+ id = 0 means this is an ArrayBuffer object */
+ argv[1] = 0;
+ argc = 2;
+ }
+
+ if (exec_env) {
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ if (exec_env_tls) {
+ bh_assert(exec_env_tls == exec_env);
+ }
+#endif
+ bh_assert(exec_env->module_inst
+ == (WASMModuleInstanceCommon *)module_inst);
+ }
+ else {
+ /* Try using the existing exec_env */
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ exec_env = exec_env_tls;
+#endif
+#if WASM_ENABLE_THREAD_MGR != 0
+ if (!exec_env)
+ exec_env = wasm_clusters_search_exec_env(
+ (WASMModuleInstanceCommon *)module_inst);
+#endif
+ if (!exec_env) {
+ if (!(exec_env = exec_env_created = wasm_exec_env_create(
+ (WASMModuleInstanceCommon *)module_inst,
+ module_inst->default_wasm_stack_size))) {
+ wasm_set_exception(module_inst, "allocate memory failed");
+ return false;
+ }
+ }
+ else {
+ /* Temporarily replace exec_env's module inst with current
+ module inst to ensure that the exec_env's module inst
+ is the correct one. */
+ module_inst_old = exec_env->module_inst;
+ exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
+ }
+ }
+
+ ret = wasm_call_function(exec_env, malloc_func, argc, argv);
+
+ if (retain_func && ret)
+ ret = wasm_call_function(exec_env, retain_func, 1, argv);
+
+ if (module_inst_old)
+ /* Restore the existing exec_env's module inst */
+ exec_env->module_inst = module_inst_old;
+
+ if (exec_env_created)
+ wasm_exec_env_destroy(exec_env_created);
+
+ if (ret)
+ *p_result = argv[0];
+ return ret;
+}
+
+static bool
+execute_free_function(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
+ WASMFunctionInstance *free_func, uint32 offset)
+{
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ WASMExecEnv *exec_env_tls = wasm_runtime_get_exec_env_tls();
+#endif
+ WASMExecEnv *exec_env_created = NULL;
+ WASMModuleInstanceCommon *module_inst_old = NULL;
+ uint32 argv[2];
+ bool ret;
+
+ argv[0] = offset;
+
+ if (exec_env) {
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ if (exec_env_tls) {
+ bh_assert(exec_env_tls == exec_env);
+ }
+#endif
+ bh_assert(exec_env->module_inst
+ == (WASMModuleInstanceCommon *)module_inst);
+ }
+ else {
+ /* Try using the existing exec_env */
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ exec_env = exec_env_tls;
+#endif
+#if WASM_ENABLE_THREAD_MGR != 0
+ if (!exec_env)
+ exec_env = wasm_clusters_search_exec_env(
+ (WASMModuleInstanceCommon *)module_inst);
+#endif
+ if (!exec_env) {
+ if (!(exec_env = exec_env_created = wasm_exec_env_create(
+ (WASMModuleInstanceCommon *)module_inst,
+ module_inst->default_wasm_stack_size))) {
+ wasm_set_exception(module_inst, "allocate memory failed");
+ return false;
+ }
+ }
+ else {
+ /* Temporarily replace exec_env's module inst with current
+ module inst to ensure that the exec_env's module inst
+ is the correct one. */
+ module_inst_old = exec_env->module_inst;
+ exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
+ }
+ }
+
+ ret = wasm_call_function(exec_env, free_func, 1, argv);
+
+ if (module_inst_old)
+ /* Restore the existing exec_env's module inst */
+ exec_env->module_inst = module_inst_old;
+
+ if (exec_env_created)
+ wasm_exec_env_destroy(exec_env_created);
+
+ return ret;
+}
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+static bool
+sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst,
+ uint32 stack_size, uint32 heap_size, char *error_buf,
+ uint32 error_buf_size)
+{
+ bh_list *sub_module_inst_list = module_inst->e->sub_module_inst_list;
+ WASMRegisteredModule *sub_module_list_node =
+ bh_list_first_elem(module->import_module_list);
+
+ while (sub_module_list_node) {
+ WASMSubModInstNode *sub_module_inst_list_node = NULL;
+ WASMModule *sub_module = (WASMModule *)sub_module_list_node->module;
+ WASMModuleInstance *sub_module_inst = NULL;
+
+ sub_module_inst =
+ wasm_instantiate(sub_module, false, NULL, stack_size, heap_size,
+ error_buf, error_buf_size);
+ if (!sub_module_inst) {
+ LOG_DEBUG("instantiate %s failed",
+ sub_module_list_node->module_name);
+ goto failed;
+ }
+
+ sub_module_inst_list_node = runtime_malloc(sizeof(WASMSubModInstNode),
+ error_buf, error_buf_size);
+ if (!sub_module_inst_list_node) {
+ LOG_DEBUG("Malloc WASMSubModInstNode failed, SZ:%d",
+ sizeof(WASMSubModInstNode));
+ goto failed;
+ }
+
+ sub_module_inst_list_node->module_inst = sub_module_inst;
+ sub_module_inst_list_node->module_name =
+ sub_module_list_node->module_name;
+ bh_list_status ret =
+ bh_list_insert(sub_module_inst_list, sub_module_inst_list_node);
+ bh_assert(BH_LIST_SUCCESS == ret);
+ (void)ret;
+
+ sub_module_list_node = bh_list_elem_next(sub_module_list_node);
+
+ continue;
+ failed:
+ if (sub_module_inst_list_node) {
+ bh_list_remove(sub_module_inst_list, sub_module_inst_list_node);
+ wasm_runtime_free(sub_module_inst_list_node);
+ }
+
+ if (sub_module_inst)
+ wasm_deinstantiate(sub_module_inst, false);
+ return false;
+ }
+
+ return true;
+}
+
+static void
+sub_module_deinstantiate(WASMModuleInstance *module_inst)
+{
+ bh_list *list = module_inst->e->sub_module_inst_list;
+ WASMSubModInstNode *node = bh_list_first_elem(list);
+ while (node) {
+ WASMSubModInstNode *next_node = bh_list_elem_next(node);
+ bh_list_remove(list, node);
+ wasm_deinstantiate(node->module_inst, false);
+ wasm_runtime_free(node);
+ node = next_node;
+ }
+}
+#endif
+
+static bool
+check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf,
+ uint32 error_buf_size)
+{
+ WASMModule *module = module_inst->module;
+ uint32 i;
+
+ for (i = 0; i < module->import_function_count; i++) {
+ WASMFunctionImport *func =
+ &((module->import_functions + i)->u.function);
+ if (!func->func_ptr_linked
+#if WASM_ENABLE_MULTI_MODULE != 0
+ && !func->import_func_linked
+#endif
+ ) {
+#if WASM_ENABLE_WAMR_COMPILER == 0
+ LOG_WARNING("warning: failed to link import function (%s, %s)",
+ func->module_name, func->field_name);
+ /* will throw exception only if calling */
+#else
+ /* do nothing to avoid confused message */
+#endif /* WASM_ENABLE_WAMR_COMPILER == 0 */
+ }
+ }
+
+ for (i = 0; i < module->import_global_count; i++) {
+ WASMGlobalImport *global = &((module->import_globals + i)->u.global);
+ if (!global->is_linked) {
+#if WASM_ENABLE_SPEC_TEST != 0
+ set_error_buf(error_buf, error_buf_size,
+ "unknown import or incompatible import type");
+ return false;
+#else
+#if WASM_ENABLE_WAMR_COMPILER == 0
+ set_error_buf_v(error_buf, error_buf_size,
+ "failed to link import global (%s, %s)",
+ global->module_name, global->field_name);
+ return false;
+#else
+ /* do nothing to avoid confused message */
+#endif /* WASM_ENABLE_WAMR_COMPILER == 0 */
+#endif /* WASM_ENABLE_SPEC_TEST != 0 */
+ }
+ }
+
+ return true;
+}
+
+#if WASM_ENABLE_JIT != 0
+static bool
+init_func_ptrs(WASMModuleInstance *module_inst, WASMModule *module,
+ char *error_buf, uint32 error_buf_size)
+{
+ uint32 i;
+ void **func_ptrs;
+ uint64 total_size = (uint64)sizeof(void *) * module_inst->e->function_count;
+
+ /* Allocate memory */
+ if (!(func_ptrs = module_inst->func_ptrs =
+ runtime_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ /* Set import function pointers */
+ for (i = 0; i < module->import_function_count; i++, func_ptrs++) {
+ WASMFunctionImport *import_func =
+ &module->import_functions[i].u.function;
+ /* TODO: handle multi module */
+ *func_ptrs = import_func->func_ptr_linked;
+ }
+
+ /* The defined function pointers will be set in
+ wasm_runtime_set_running_mode, no need to set them here */
+ return true;
+}
+#endif /* end of WASM_ENABLE_JIT != 0 */
+
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0
+static uint32
+get_smallest_type_idx(WASMModule *module, WASMType *func_type)
+{
+ uint32 i;
+
+ for (i = 0; i < module->type_count; i++) {
+ if (func_type == module->types[i])
+ return i;
+ }
+
+ bh_assert(0);
+ return -1;
+}
+
+static bool
+init_func_type_indexes(WASMModuleInstance *module_inst, char *error_buf,
+ uint32 error_buf_size)
+{
+ uint32 i;
+ uint64 total_size = (uint64)sizeof(uint32) * module_inst->e->function_count;
+
+ /* Allocate memory */
+ if (!(module_inst->func_type_indexes =
+ runtime_malloc(total_size, error_buf, error_buf_size))) {
+ return false;
+ }
+
+ for (i = 0; i < module_inst->e->function_count; i++) {
+ WASMFunctionInstance *func_inst = module_inst->e->functions + i;
+ WASMType *func_type = func_inst->is_import_func
+ ? func_inst->u.func_import->func_type
+ : func_inst->u.func->func_type;
+ module_inst->func_type_indexes[i] =
+ get_smallest_type_idx(module_inst->module, func_type);
+ }
+
+ return true;
+}
+#endif /* end of WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 */
+
+static bool
+set_running_mode(WASMModuleInstance *module_inst, RunningMode running_mode,
+ bool first_time_set)
+{
+ WASMModule *module = module_inst->module;
+
+ if (running_mode == Mode_Default) {
+#if WASM_ENABLE_FAST_JIT == 0 && WASM_ENABLE_JIT == 0
+ running_mode = Mode_Interp;
+#elif WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT == 0
+ running_mode = Mode_Fast_JIT;
+#elif WASM_ENABLE_FAST_JIT == 0 && WASM_ENABLE_JIT != 0
+ running_mode = Mode_LLVM_JIT;
+#else /* WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 */
+#if WASM_ENABLE_LAZY_JIT == 0
+ running_mode = Mode_LLVM_JIT;
+#else
+ running_mode = Mode_Multi_Tier_JIT;
+#endif
+#endif
+ }
+
+ if (!wasm_runtime_is_running_mode_supported(running_mode))
+ return false;
+
+#if !(WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0) /* No possible multi-tier JIT */
+ module_inst->e->running_mode = running_mode;
+
+ if (running_mode == Mode_Interp) {
+ /* Do nothing for Mode_Interp */
+ }
+ else if (running_mode == Mode_Fast_JIT) {
+ /* Do nothing for Mode_Fast_JIT since
+ module_inst->fast_jit_func_ptrs is same as
+ module->fast_jit_func_ptrs */
+ }
+#if WASM_ENABLE_JIT != 0
+ else if (running_mode == Mode_LLVM_JIT) {
+ /* Set defined function pointers */
+ bh_memcpy_s(module_inst->func_ptrs + module->import_function_count,
+ sizeof(void *) * module->function_count, module->func_ptrs,
+ sizeof(void *) * module->function_count);
+ }
+#endif
+ else {
+ bh_assert(0);
+ }
+#else /* Possible multi-tier JIT */
+ os_mutex_lock(&module->instance_list_lock);
+
+ module_inst->e->running_mode = running_mode;
+
+ if (running_mode == Mode_Interp) {
+ /* Do nothing for Mode_Interp */
+ }
+#if WASM_ENABLE_FAST_JIT != 0
+ else if (running_mode == Mode_Fast_JIT) {
+ JitGlobals *jit_globals = jit_compiler_get_jit_globals();
+ uint32 i;
+
+ /* Allocate memory for fast_jit_func_ptrs if needed */
+ if (!module_inst->fast_jit_func_ptrs
+ || module_inst->fast_jit_func_ptrs == module->fast_jit_func_ptrs) {
+ uint64 total_size = (uint64)sizeof(void *) * module->function_count;
+ if (!(module_inst->fast_jit_func_ptrs =
+ runtime_malloc(total_size, NULL, 0))) {
+ os_mutex_unlock(&module->instance_list_lock);
+ return false;
+ }
+ }
+
+ for (i = 0; i < module->function_count; i++) {
+ if (module->functions[i]->fast_jit_jitted_code) {
+ /* current fast jit function has been compiled */
+ module_inst->fast_jit_func_ptrs[i] =
+ module->functions[i]->fast_jit_jitted_code;
+ }
+ else {
+ module_inst->fast_jit_func_ptrs[i] =
+ jit_globals->compile_fast_jit_and_then_call;
+ }
+ }
+ }
+#endif
+#if WASM_ENABLE_JIT != 0
+ else if (running_mode == Mode_LLVM_JIT) {
+ void **llvm_jit_func_ptrs;
+ uint32 i;
+
+ /* Notify backend threads to start llvm jit compilation */
+ module->enable_llvm_jit_compilation = true;
+
+ /* Wait until llvm jit finishes initialization */
+ os_mutex_lock(&module->tierup_wait_lock);
+ while (!module->llvm_jit_inited) {
+ os_cond_reltimedwait(&module->tierup_wait_cond,
+ &module->tierup_wait_lock, 10000);
+ if (module->orcjit_stop_compiling) {
+ /* init_llvm_jit_functions_stage2 failed */
+ os_mutex_unlock(&module->tierup_wait_lock);
+ os_mutex_unlock(&module->instance_list_lock);
+ return false;
+ }
+ }
+ os_mutex_unlock(&module->tierup_wait_lock);
+
+ llvm_jit_func_ptrs =
+ module_inst->func_ptrs + module->import_function_count;
+ for (i = 0; i < module->function_count; i++) {
+ llvm_jit_func_ptrs[i] = module->functions[i]->llvm_jit_func_ptr;
+ }
+ }
+#endif
+ else if (running_mode == Mode_Multi_Tier_JIT) {
+ /* Notify backend threads to start llvm jit compilation */
+ module->enable_llvm_jit_compilation = true;
+
+ /* Free fast_jit_func_ptrs if it is allocated before */
+ if (module_inst->fast_jit_func_ptrs
+ && module_inst->fast_jit_func_ptrs != module->fast_jit_func_ptrs) {
+ wasm_runtime_free(module_inst->fast_jit_func_ptrs);
+ }
+ module_inst->fast_jit_func_ptrs = module->fast_jit_func_ptrs;
+
+ /* Copy all llvm jit func ptrs from the module */
+ bh_memcpy_s(module_inst->func_ptrs + module->import_function_count,
+ sizeof(void *) * module->function_count, module->func_ptrs,
+ sizeof(void *) * module->function_count);
+ }
+ else {
+ bh_assert(0);
+ }
+
+ /* Add module instance into module's instance list if not added */
+ if (first_time_set) {
+ bool found = false;
+ WASMModuleInstance *node = module->instance_list;
+
+ while (node) {
+ if (node == module_inst) {
+ found = true;
+ break;
+ }
+ node = node->e->next;
+ }
+
+ if (!found) {
+ module_inst->e->next = module->instance_list;
+ module->instance_list = module_inst;
+ }
+ }
+
+ os_mutex_unlock(&module->instance_list_lock);
+#endif /* end of !(WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0) */
+
+ (void)module;
+ return true;
+}
+
+bool
+wasm_set_running_mode(WASMModuleInstance *module_inst, RunningMode running_mode)
+{
+ return set_running_mode(module_inst, running_mode, false);
+}
+
+/**
+ * Instantiate module
+ */
+WASMModuleInstance *
+wasm_instantiate(WASMModule *module, bool is_sub_inst,
+ WASMExecEnv *exec_env_main, uint32 stack_size,
+ uint32 heap_size, char *error_buf, uint32 error_buf_size)
+{
+ WASMModuleInstance *module_inst;
+ WASMGlobalInstance *globals = NULL, *global;
+ WASMTableInstance *first_table;
+ uint32 global_count, i;
+ uint32 base_offset, length, extra_info_offset;
+ uint32 module_inst_struct_size =
+ offsetof(WASMModuleInstance, global_table_data.bytes);
+ uint64 module_inst_mem_inst_size;
+ uint64 total_size, table_size = 0;
+ uint8 *global_data, *global_data_end;
+#if WASM_ENABLE_MULTI_MODULE != 0
+ bool ret = false;
+#endif
+
+ if (!module)
+ return NULL;
+
+ /* Check the heap size */
+ heap_size = align_uint(heap_size, 8);
+ if (heap_size > APP_HEAP_SIZE_MAX)
+ heap_size = APP_HEAP_SIZE_MAX;
+
+ module_inst_mem_inst_size =
+ (uint64)sizeof(WASMMemoryInstance)
+ * (module->import_memory_count + module->memory_count);
+
+#if WASM_ENABLE_JIT != 0
+ /* If the module dosen't have memory, reserve one mem_info space
+ with empty content to align with llvm jit compiler */
+ if (module_inst_mem_inst_size == 0)
+ module_inst_mem_inst_size = (uint64)sizeof(WASMMemoryInstance);
+#endif
+
+ /* Size of module inst, memory instances and global data */
+ total_size = (uint64)module_inst_struct_size + module_inst_mem_inst_size
+ + module->global_data_size;
+
+ /* Calculate the size of table data */
+ for (i = 0; i < module->import_table_count; i++) {
+ WASMTableImport *import_table = &module->import_tables[i].u.table;
+ table_size += offsetof(WASMTableInstance, elems);
+#if WASM_ENABLE_MULTI_MODULE != 0
+ table_size += (uint64)sizeof(uint32) * import_table->max_size;
+#else
+ table_size += (uint64)sizeof(uint32)
+ * (import_table->possible_grow ? import_table->max_size
+ : import_table->init_size);
+#endif
+ }
+ for (i = 0; i < module->table_count; i++) {
+ WASMTable *table = module->tables + i;
+ table_size += offsetof(WASMTableInstance, elems);
+#if WASM_ENABLE_MULTI_MODULE != 0
+ table_size += (uint64)sizeof(uint32) * table->max_size;
+#else
+ table_size +=
+ (uint64)sizeof(uint32)
+ * (table->possible_grow ? table->max_size : table->init_size);
+#endif
+ }
+ total_size += table_size;
+
+ /* The offset of WASMModuleInstanceExtra, make it 8-byte aligned */
+ total_size = (total_size + 7LL) & ~7LL;
+ extra_info_offset = (uint32)total_size;
+ total_size += sizeof(WASMModuleInstanceExtra);
+
+ /* Allocate the memory for module instance with memory instances,
+ global data, table data appended at the end */
+ if (!(module_inst =
+ runtime_malloc(total_size, error_buf, error_buf_size))) {
+ return NULL;
+ }
+
+ module_inst->module_type = Wasm_Module_Bytecode;
+ module_inst->module = module;
+ module_inst->e =
+ (WASMModuleInstanceExtra *)((uint8 *)module_inst + extra_info_offset);
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+ module_inst->e->sub_module_inst_list =
+ &module_inst->e->sub_module_inst_list_head;
+ ret = sub_module_instantiate(module, module_inst, stack_size, heap_size,
+ error_buf, error_buf_size);
+ if (!ret) {
+ LOG_DEBUG("build a sub module list failed");
+ goto fail;
+ }
+#endif
+
+#if WASM_ENABLE_DUMP_CALL_STACK != 0
+ if (!(module_inst->frames = runtime_malloc((uint64)sizeof(Vector),
+ error_buf, error_buf_size))) {
+ goto fail;
+ }
+#endif
+
+ /* Instantiate global firstly to get the mutable data size */
+ global_count = module->import_global_count + module->global_count;
+ if (global_count
+ && !(globals = globals_instantiate(module, module_inst, error_buf,
+ error_buf_size))) {
+ goto fail;
+ }
+ module_inst->e->global_count = global_count;
+ module_inst->e->globals = globals;
+ module_inst->global_data = (uint8 *)module_inst + module_inst_struct_size
+ + module_inst_mem_inst_size;
+ module_inst->global_data_size = module->global_data_size;
+ first_table = (WASMTableInstance *)(module_inst->global_data
+ + module->global_data_size);
+
+ module_inst->memory_count =
+ module->import_memory_count + module->memory_count;
+ module_inst->table_count = module->import_table_count + module->table_count;
+ module_inst->e->function_count =
+ module->import_function_count + module->function_count;
+
+ /* export */
+ module_inst->export_func_count = get_export_count(module, EXPORT_KIND_FUNC);
+#if WASM_ENABLE_MULTI_MODULE != 0
+ module_inst->export_table_count =
+ get_export_count(module, EXPORT_KIND_TABLE);
+ module_inst->export_memory_count =
+ get_export_count(module, EXPORT_KIND_MEMORY);
+ module_inst->export_global_count =
+ get_export_count(module, EXPORT_KIND_GLOBAL);
+#endif
+
+ /* Instantiate memories/tables/functions */
+ if ((module_inst->memory_count > 0
+ && !(module_inst->memories = memories_instantiate(
+ module, module_inst, heap_size, error_buf, error_buf_size)))
+ || (module_inst->table_count > 0
+ && !(module_inst->tables =
+ tables_instantiate(module, module_inst, first_table,
+ error_buf, error_buf_size)))
+ || (module_inst->e->function_count > 0
+ && !(module_inst->e->functions = functions_instantiate(
+ module, module_inst, error_buf, error_buf_size)))
+ || (module_inst->export_func_count > 0
+ && !(module_inst->export_functions = export_functions_instantiate(
+ module, module_inst, module_inst->export_func_count,
+ error_buf, error_buf_size)))
+#if WASM_ENABLE_MULTI_MODULE != 0
+ || (module_inst->export_global_count > 0
+ && !(module_inst->export_globals = export_globals_instantiate(
+ module, module_inst, module_inst->export_global_count,
+ error_buf, error_buf_size)))
+#endif
+#if WASM_ENABLE_JIT != 0
+ || (module_inst->e->function_count > 0
+ && !init_func_ptrs(module_inst, module, error_buf, error_buf_size))
+#endif
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0
+ || (module_inst->e->function_count > 0
+ && !init_func_type_indexes(module_inst, error_buf, error_buf_size))
+#endif
+ ) {
+ goto fail;
+ }
+
+ if (global_count > 0) {
+ /* Initialize the global data */
+ global_data = module_inst->global_data;
+ global_data_end = global_data + module->global_data_size;
+ global = globals;
+ for (i = 0; i < global_count; i++, global++) {
+ switch (global->type) {
+ case VALUE_TYPE_I32:
+ case VALUE_TYPE_F32:
+#if WASM_ENABLE_REF_TYPES != 0
+ case VALUE_TYPE_FUNCREF:
+ case VALUE_TYPE_EXTERNREF:
+#endif
+ *(int32 *)global_data = global->initial_value.i32;
+ global_data += sizeof(int32);
+ break;
+ case VALUE_TYPE_I64:
+ case VALUE_TYPE_F64:
+ bh_memcpy_s(global_data,
+ (uint32)(global_data_end - global_data),
+ &global->initial_value.i64, sizeof(int64));
+ global_data += sizeof(int64);
+ break;
+#if WASM_ENABLE_SIMD != 0
+ case VALUE_TYPE_V128:
+ bh_memcpy_s(global_data, (uint32)sizeof(V128),
+ &global->initial_value.v128, sizeof(V128));
+ global_data += sizeof(V128);
+ break;
+#endif
+ default:
+ bh_assert(0);
+ }
+ }
+ bh_assert(global_data == global_data_end);
+ }
+
+ if (!check_linked_symbol(module_inst, error_buf, error_buf_size)) {
+ goto fail;
+ }
+
+ /* Initialize the memory data with data segment section */
+ for (i = 0; i < module->data_seg_count; i++) {
+ WASMMemoryInstance *memory = NULL;
+ uint8 *memory_data = NULL;
+ uint32 memory_size = 0;
+ WASMDataSeg *data_seg = module->data_segments[i];
+
+#if WASM_ENABLE_BULK_MEMORY != 0
+ if (data_seg->is_passive)
+ continue;
+#endif
+
+ /* has check it in loader */
+ memory = module_inst->memories[data_seg->memory_index];
+ bh_assert(memory);
+
+ memory_data = memory->memory_data;
+ memory_size = memory->num_bytes_per_page * memory->cur_page_count;
+ bh_assert(memory_data || memory_size == 0);
+
+ bh_assert(data_seg->base_offset.init_expr_type
+ == INIT_EXPR_TYPE_I32_CONST
+ || data_seg->base_offset.init_expr_type
+ == INIT_EXPR_TYPE_GET_GLOBAL);
+
+ if (data_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) {
+ if (!check_global_init_expr(module,
+ data_seg->base_offset.u.global_index,
+ error_buf, error_buf_size)) {
+ goto fail;
+ }
+
+ if (!globals
+ || globals[data_seg->base_offset.u.global_index].type
+ != VALUE_TYPE_I32) {
+ set_error_buf(error_buf, error_buf_size,
+ "data segment does not fit");
+ goto fail;
+ }
+
+ base_offset =
+ globals[data_seg->base_offset.u.global_index].initial_value.i32;
+ }
+ else {
+ base_offset = (uint32)data_seg->base_offset.u.i32;
+ }
+
+ /* check offset */
+ if (base_offset > memory_size) {
+ LOG_DEBUG("base_offset(%d) > memory_size(%d)", base_offset,
+ memory_size);
+#if WASM_ENABLE_REF_TYPES != 0
+ set_error_buf(error_buf, error_buf_size,
+ "out of bounds memory access");
+#else
+ set_error_buf(error_buf, error_buf_size,
+ "data segment does not fit");
+#endif
+ goto fail;
+ }
+
+ /* check offset + length(could be zero) */
+ length = data_seg->data_length;
+ if (base_offset + length > memory_size) {
+ LOG_DEBUG("base_offset(%d) + length(%d) > memory_size(%d)",
+ base_offset, length, memory_size);
+#if WASM_ENABLE_REF_TYPES != 0
+ set_error_buf(error_buf, error_buf_size,
+ "out of bounds memory access");
+#else
+ set_error_buf(error_buf, error_buf_size,
+ "data segment does not fit");
+#endif
+ goto fail;
+ }
+
+ if (memory_data) {
+ bh_memcpy_s(memory_data + base_offset, memory_size - base_offset,
+ data_seg->data, length);
+ }
+ }
+
+ /* Initialize the table data with table segment section */
+ for (i = 0; module_inst->table_count > 0 && i < module->table_seg_count;
+ i++) {
+ WASMTableSeg *table_seg = module->table_segments + i;
+ /* has check it in loader */
+ WASMTableInstance *table = module_inst->tables[table_seg->table_index];
+ uint32 *table_data;
+#if WASM_ENABLE_REF_TYPES != 0
+ uint8 tbl_elem_type;
+ uint32 tbl_init_size, tbl_max_size;
+#endif
+
+ bh_assert(table);
+
+#if WASM_ENABLE_REF_TYPES != 0
+ (void)wasm_runtime_get_table_inst_elem_type(
+ (WASMModuleInstanceCommon *)module_inst, table_seg->table_index,
+ &tbl_elem_type, &tbl_init_size, &tbl_max_size);
+ if (tbl_elem_type != VALUE_TYPE_FUNCREF
+ && tbl_elem_type != VALUE_TYPE_EXTERNREF) {
+ set_error_buf(error_buf, error_buf_size,
+ "elements segment does not fit");
+ goto fail;
+ }
+ (void)tbl_init_size;
+ (void)tbl_max_size;
+#endif
+
+ table_data = table->elems;
+#if WASM_ENABLE_MULTI_MODULE != 0
+ if (table_seg->table_index < module->import_table_count
+ && module_inst->e->table_insts_linked[table_seg->table_index]) {
+ table_data =
+ module_inst->e->table_insts_linked[table_seg->table_index]
+ ->elems;
+ }
+#endif
+ bh_assert(table_data);
+
+#if WASM_ENABLE_REF_TYPES != 0
+ if (!wasm_elem_is_active(table_seg->mode))
+ continue;
+#endif
+
+#if WASM_ENABLE_REF_TYPES != 0
+ bh_assert(table_seg->base_offset.init_expr_type
+ == INIT_EXPR_TYPE_I32_CONST
+ || table_seg->base_offset.init_expr_type
+ == INIT_EXPR_TYPE_GET_GLOBAL
+ || table_seg->base_offset.init_expr_type
+ == INIT_EXPR_TYPE_FUNCREF_CONST
+ || table_seg->base_offset.init_expr_type
+ == INIT_EXPR_TYPE_REFNULL_CONST);
+#else
+ bh_assert(table_seg->base_offset.init_expr_type
+ == INIT_EXPR_TYPE_I32_CONST
+ || table_seg->base_offset.init_expr_type
+ == INIT_EXPR_TYPE_GET_GLOBAL);
+#endif
+
+ /* init vec(funcidx) or vec(expr) */
+ if (table_seg->base_offset.init_expr_type
+ == INIT_EXPR_TYPE_GET_GLOBAL) {
+ if (!check_global_init_expr(module,
+ table_seg->base_offset.u.global_index,
+ error_buf, error_buf_size)) {
+ goto fail;
+ }
+
+ if (!globals
+ || globals[table_seg->base_offset.u.global_index].type
+ != VALUE_TYPE_I32) {
+ set_error_buf(error_buf, error_buf_size,
+ "elements segment does not fit");
+ goto fail;
+ }
+
+ table_seg->base_offset.u.i32 =
+ globals[table_seg->base_offset.u.global_index]
+ .initial_value.i32;
+ }
+
+ /* check offset since length might negative */
+ if ((uint32)table_seg->base_offset.u.i32 > table->cur_size) {
+ LOG_DEBUG("base_offset(%d) > table->cur_size(%d)",
+ table_seg->base_offset.u.i32, table->cur_size);
+#if WASM_ENABLE_REF_TYPES != 0
+ set_error_buf(error_buf, error_buf_size,
+ "out of bounds table access");
+#else
+ set_error_buf(error_buf, error_buf_size,
+ "elements segment does not fit");
+#endif
+ goto fail;
+ }
+
+ /* check offset + length(could be zero) */
+ length = table_seg->function_count;
+ if ((uint32)table_seg->base_offset.u.i32 + length > table->cur_size) {
+ LOG_DEBUG("base_offset(%d) + length(%d)> table->cur_size(%d)",
+ table_seg->base_offset.u.i32, length, table->cur_size);
+#if WASM_ENABLE_REF_TYPES != 0
+ set_error_buf(error_buf, error_buf_size,
+ "out of bounds table access");
+#else
+ set_error_buf(error_buf, error_buf_size,
+ "elements segment does not fit");
+#endif
+ goto fail;
+ }
+
+ /**
+ * Check function index in the current module inst for now.
+ * will check the linked table inst owner in future.
+ * so loader check is enough
+ */
+ bh_memcpy_s(
+ table_data + table_seg->base_offset.u.i32,
+ (uint32)((table->cur_size - (uint32)table_seg->base_offset.u.i32)
+ * sizeof(uint32)),
+ table_seg->func_indexes, (uint32)(length * sizeof(uint32)));
+ }
+
+ /* Initialize the thread related data */
+ if (stack_size == 0)
+ stack_size = DEFAULT_WASM_STACK_SIZE;
+#if WASM_ENABLE_SPEC_TEST != 0
+ if (stack_size < 128 * 1024)
+ stack_size = 128 * 1024;
+#endif
+ module_inst->default_wasm_stack_size = stack_size;
+
+ if (module->malloc_function != (uint32)-1) {
+ module_inst->e->malloc_function =
+ &module_inst->e->functions[module->malloc_function];
+ }
+
+ if (module->free_function != (uint32)-1) {
+ module_inst->e->free_function =
+ &module_inst->e->functions[module->free_function];
+ }
+
+ if (module->retain_function != (uint32)-1) {
+ module_inst->e->retain_function =
+ &module_inst->e->functions[module->retain_function];
+ }
+
+#if WASM_ENABLE_LIBC_WASI != 0
+ /* The sub-instance will get the wasi_ctx from main-instance */
+ if (!is_sub_inst) {
+ if (!wasm_runtime_init_wasi(
+ (WASMModuleInstanceCommon *)module_inst,
+ module->wasi_args.dir_list, module->wasi_args.dir_count,
+ module->wasi_args.map_dir_list, module->wasi_args.map_dir_count,
+ module->wasi_args.env, module->wasi_args.env_count,
+ module->wasi_args.addr_pool, module->wasi_args.addr_count,
+ module->wasi_args.ns_lookup_pool,
+ module->wasi_args.ns_lookup_count, module->wasi_args.argv,
+ module->wasi_args.argc, module->wasi_args.stdio[0],
+ module->wasi_args.stdio[1], module->wasi_args.stdio[2],
+ error_buf, error_buf_size)) {
+ goto fail;
+ }
+ }
+#endif
+
+#if WASM_ENABLE_WASI_NN != 0
+ if (!is_sub_inst) {
+ if (!(module_inst->e->wasi_nn_ctx = wasi_nn_initialize())) {
+ set_error_buf(error_buf, error_buf_size,
+ "wasi nn initialization failed");
+ goto fail;
+ }
+ }
+#endif
+
+#if WASM_ENABLE_DEBUG_INTERP != 0
+ if (!is_sub_inst) {
+ /* Add module instance into module's instance list */
+ os_mutex_lock(&module->instance_list_lock);
+ if (module->instance_list) {
+ LOG_WARNING(
+ "warning: multiple instances referencing to the same module "
+ "may cause unexpected behaviour during debugging");
+ }
+ module_inst->e->next = module->instance_list;
+ module->instance_list = module_inst;
+ os_mutex_unlock(&module->instance_list_lock);
+ }
+#endif
+
+ /* Set running mode before executing wasm functions */
+ if (!set_running_mode(module_inst, wasm_runtime_get_default_running_mode(),
+ true)) {
+ set_error_buf(error_buf, error_buf_size,
+ "set instance running mode failed");
+ goto fail;
+ }
+
+ if (module->start_function != (uint32)-1) {
+ /* TODO: fix start function can be import function issue */
+ if (module->start_function >= module->import_function_count)
+ module_inst->e->start_function =
+ &module_inst->e->functions[module->start_function];
+ }
+
+ if (!execute_post_instantiate_functions(module_inst, is_sub_inst,
+ exec_env_main)) {
+ set_error_buf(error_buf, error_buf_size, module_inst->cur_exception);
+ goto fail;
+ }
+
+#if WASM_ENABLE_MEMORY_TRACING != 0
+ wasm_runtime_dump_module_inst_mem_consumption(
+ (WASMModuleInstanceCommon *)module_inst);
+#endif
+
+ (void)global_data_end;
+ return module_inst;
+
+fail:
+ wasm_deinstantiate(module_inst, false);
+ return NULL;
+}
+
+void
+wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
+{
+ if (!module_inst)
+ return;
+
+ if (module_inst->exec_env_singleton) {
+ /* wasm_exec_env_destroy will call
+ wasm_cluster_wait_for_all_except_self to wait for other
+ threads, so as to destroy their exec_envs and module
+ instances first, and avoid accessing the shared resources
+ of current module instance after it is deinstantiated. */
+ wasm_exec_env_destroy(module_inst->exec_env_singleton);
+ }
+
+#if WASM_ENABLE_DEBUG_INTERP != 0 \
+ || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0)
+ /* Remove instance from module's instance list before freeing
+ func_ptrs and fast_jit_func_ptrs of the instance, to avoid
+ accessing the freed memory in the jit backend compilation
+ threads */
+ {
+ WASMModule *module = module_inst->module;
+ WASMModuleInstance *instance_prev = NULL, *instance;
+ os_mutex_lock(&module->instance_list_lock);
+
+ instance = module->instance_list;
+ while (instance) {
+ if (instance == module_inst) {
+ if (!instance_prev)
+ module->instance_list = instance->e->next;
+ else
+ instance_prev->e->next = instance->e->next;
+ break;
+ }
+ instance_prev = instance;
+ instance = instance->e->next;
+ }
+
+ os_mutex_unlock(&module->instance_list_lock);
+ }
+#endif
+
+#if WASM_ENABLE_JIT != 0
+ if (module_inst->func_ptrs)
+ wasm_runtime_free(module_inst->func_ptrs);
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0
+ if (module_inst->fast_jit_func_ptrs
+ && module_inst->fast_jit_func_ptrs
+ != module_inst->module->fast_jit_func_ptrs)
+ wasm_runtime_free(module_inst->fast_jit_func_ptrs);
+#endif
+
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0
+ if (module_inst->func_type_indexes)
+ wasm_runtime_free(module_inst->func_type_indexes);
+#endif
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+ sub_module_deinstantiate(module_inst);
+#endif
+
+#if WASM_ENABLE_LIBC_WASI != 0
+ /* Destroy wasi resource before freeing app heap, since some fields of
+ wasi contex are allocated from app heap, and if app heap is freed,
+ these fields will be set to NULL, we cannot free their internal data
+ which may allocated from global heap. */
+ /* Only destroy wasi ctx in the main module instance */
+ if (!is_sub_inst)
+ wasm_runtime_destroy_wasi((WASMModuleInstanceCommon *)module_inst);
+#endif
+
+ if (module_inst->memory_count > 0)
+ memories_deinstantiate(module_inst, module_inst->memories,
+ module_inst->memory_count);
+
+ if (module_inst->import_func_ptrs) {
+ wasm_runtime_free(module_inst->import_func_ptrs);
+ }
+
+ tables_deinstantiate(module_inst);
+ functions_deinstantiate(module_inst->e->functions,
+ module_inst->e->function_count);
+ globals_deinstantiate(module_inst->e->globals);
+ export_functions_deinstantiate(module_inst->export_functions);
+#if WASM_ENABLE_MULTI_MODULE != 0
+ export_globals_deinstantiate(module_inst->export_globals);
+#endif
+
+#if WASM_ENABLE_REF_TYPES != 0
+ wasm_externref_cleanup((WASMModuleInstanceCommon *)module_inst);
+#endif
+
+#if WASM_ENABLE_DUMP_CALL_STACK != 0
+ if (module_inst->frames) {
+ bh_vector_destroy(module_inst->frames);
+ wasm_runtime_free(module_inst->frames);
+ module_inst->frames = NULL;
+ }
+#endif
+
+ if (module_inst->e->c_api_func_imports)
+ wasm_runtime_free(module_inst->e->c_api_func_imports);
+
+#if WASM_ENABLE_WASI_NN != 0
+ if (!is_sub_inst) {
+ WASINNContext *wasi_nn_ctx = module_inst->e->wasi_nn_ctx;
+ if (wasi_nn_ctx)
+ wasi_nn_destroy(wasi_nn_ctx);
+ }
+#endif
+
+ wasm_runtime_free(module_inst);
+}
+
+WASMFunctionInstance *
+wasm_lookup_function(const WASMModuleInstance *module_inst, const char *name,
+ const char *signature)
+{
+ uint32 i;
+ for (i = 0; i < module_inst->export_func_count; i++)
+ if (!strcmp(module_inst->export_functions[i].name, name))
+ return module_inst->export_functions[i].function;
+ (void)signature;
+ return NULL;
+}
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+WASMGlobalInstance *
+wasm_lookup_global(const WASMModuleInstance *module_inst, const char *name)
+{
+ uint32 i;
+ for (i = 0; i < module_inst->export_global_count; i++)
+ if (!strcmp(module_inst->export_globals[i].name, name))
+ return module_inst->export_globals[i].global;
+ return NULL;
+}
+
+WASMMemoryInstance *
+wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name)
+{
+ /**
+ * using a strong assumption that one module instance only has
+ * one memory instance
+ */
+ (void)module_inst->export_memories;
+ return module_inst->memories[0];
+}
+
+WASMTableInstance *
+wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name)
+{
+ /**
+ * using a strong assumption that one module instance only has
+ * one table instance
+ */
+ (void)module_inst->export_tables;
+ return module_inst->tables[0];
+}
+#endif
+
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+
+static void
+call_wasm_with_hw_bound_check(WASMModuleInstance *module_inst,
+ WASMExecEnv *exec_env,
+ WASMFunctionInstance *function, unsigned argc,
+ uint32 argv[])
+{
+ WASMExecEnv *exec_env_tls = wasm_runtime_get_exec_env_tls();
+ WASMJmpBuf jmpbuf_node = { 0 }, *jmpbuf_node_pop;
+ uint32 page_size = os_getpagesize();
+ uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT;
+ WASMRuntimeFrame *prev_frame = wasm_exec_env_get_cur_frame(exec_env);
+ uint8 *prev_top = exec_env->wasm_stack.s.top;
+#ifdef BH_PLATFORM_WINDOWS
+ int result;
+ bool has_exception;
+ char exception[EXCEPTION_BUF_LEN];
+#endif
+ bool ret = true;
+
+ /* Check native stack overflow firstly to ensure we have enough
+ native stack to run the following codes before actually calling
+ the aot function in invokeNative function. */
+ RECORD_STACK_USAGE(exec_env, (uint8 *)&exec_env_tls);
+ if ((uint8 *)&exec_env_tls < exec_env->native_stack_boundary
+ + page_size * (guard_page_count + 1)) {
+ wasm_set_exception(module_inst, "native stack overflow");
+ return;
+ }
+
+ if (exec_env_tls && (exec_env_tls != exec_env)) {
+ wasm_set_exception(module_inst, "invalid exec env");
+ return;
+ }
+
+ if (!os_thread_signal_inited()) {
+ wasm_set_exception(module_inst, "thread signal env not inited");
+ return;
+ }
+
+ wasm_exec_env_push_jmpbuf(exec_env, &jmpbuf_node);
+
+ wasm_runtime_set_exec_env_tls(exec_env);
+ if (os_setjmp(jmpbuf_node.jmpbuf) == 0) {
+#ifndef BH_PLATFORM_WINDOWS
+ wasm_interp_call_wasm(module_inst, exec_env, function, argc, argv);
+#else
+ __try {
+ wasm_interp_call_wasm(module_inst, exec_env, function, argc, argv);
+ } __except (wasm_copy_exception(module_inst, NULL)
+ ? EXCEPTION_EXECUTE_HANDLER
+ : EXCEPTION_CONTINUE_SEARCH) {
+ /* exception was thrown in wasm_exception_handler */
+ ret = false;
+ }
+ has_exception = wasm_copy_exception(module_inst, exception);
+ if (has_exception && strstr(exception, "native stack overflow")) {
+ /* After a stack overflow, the stack was left
+ in a damaged state, let the CRT repair it */
+ result = _resetstkoflw();
+ bh_assert(result != 0);
+ }
+#endif
+ }
+ else {
+ /* Exception has been set in signal handler before calling longjmp */
+ ret = false;
+ }
+
+ /* Note: can't check wasm_get_exception(module_inst) here, there may be
+ * exception which is not caught by hardware (e.g. uninitialized elements),
+ * then the stack-frame is already freed inside wasm_interp_call_wasm */
+ if (!ret) {
+#if WASM_ENABLE_DUMP_CALL_STACK != 0
+ if (wasm_interp_create_call_stack(exec_env)) {
+ wasm_interp_dump_call_stack(exec_env, true, NULL, 0);
+ }
+#endif
+ /* Restore operand frames */
+ wasm_exec_env_set_cur_frame(exec_env, prev_frame);
+ exec_env->wasm_stack.s.top = prev_top;
+ }
+
+ jmpbuf_node_pop = wasm_exec_env_pop_jmpbuf(exec_env);
+ bh_assert(&jmpbuf_node == jmpbuf_node_pop);
+ if (!exec_env->jmpbuf_stack_top) {
+ wasm_runtime_set_exec_env_tls(NULL);
+ }
+ if (!ret) {
+ os_sigreturn();
+ os_signal_unmask();
+ }
+ (void)jmpbuf_node_pop;
+}
+#define interp_call_wasm call_wasm_with_hw_bound_check
+#else
+#define interp_call_wasm wasm_interp_call_wasm
+#endif
+
+bool
+wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function,
+ unsigned argc, uint32 argv[])
+{
+ WASMModuleInstance *module_inst =
+ (WASMModuleInstance *)exec_env->module_inst;
+
+ /* set thread handle and stack boundary */
+ wasm_exec_env_set_thread_info(exec_env);
+
+ interp_call_wasm(module_inst, exec_env, function, argc, argv);
+ return !wasm_copy_exception(module_inst, NULL);
+}
+
+#if WASM_ENABLE_PERF_PROFILING != 0
+void
+wasm_dump_perf_profiling(const WASMModuleInstance *module_inst)
+{
+ WASMExportFuncInstance *export_func;
+ WASMFunctionInstance *func_inst;
+ char *func_name;
+ uint32 i, j;
+
+ os_printf("Performance profiler data:\n");
+ for (i = 0; i < module_inst->e->function_count; i++) {
+ func_inst = module_inst->e->functions + i;
+ if (func_inst->is_import_func) {
+ func_name = func_inst->u.func_import->field_name;
+ }
+#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
+ else if (func_inst->u.func->field_name) {
+ func_name = func_inst->u.func->field_name;
+ }
+#endif
+ else {
+ func_name = NULL;
+ for (j = 0; j < module_inst->export_func_count; j++) {
+ export_func = module_inst->export_functions + j;
+ if (export_func->function == func_inst) {
+ func_name = export_func->name;
+ break;
+ }
+ }
+ }
+
+ if (func_name)
+ os_printf(" func %s, execution time: %.3f ms, execution count: %d "
+ "times\n",
+ func_name,
+ module_inst->e->functions[i].total_exec_time / 1000.0f,
+ module_inst->e->functions[i].total_exec_cnt);
+ else
+ os_printf(" func %d, execution time: %.3f ms, execution count: %d "
+ "times\n",
+ i, module_inst->e->functions[i].total_exec_time / 1000.0f,
+ module_inst->e->functions[i].total_exec_cnt);
+ }
+}
+#endif
+
+uint32
+wasm_module_malloc_internal(WASMModuleInstance *module_inst,
+ WASMExecEnv *exec_env, uint32 size,
+ void **p_native_addr)
+{
+ WASMMemoryInstance *memory = wasm_get_default_memory(module_inst);
+ uint8 *addr = NULL;
+ uint32 offset = 0;
+
+ if (!memory) {
+ wasm_set_exception(module_inst, "uninitialized memory");
+ return 0;
+ }
+
+ if (memory->heap_handle) {
+ addr = mem_allocator_malloc(memory->heap_handle, size);
+ }
+ else if (module_inst->e->malloc_function && module_inst->e->free_function) {
+ if (!execute_malloc_function(
+ module_inst, exec_env, module_inst->e->malloc_function,
+ module_inst->e->retain_function, size, &offset)) {
+ return 0;
+ }
+ /* If we use app's malloc function,
+ the default memory may be changed while memory growing */
+ memory = wasm_get_default_memory(module_inst);
+ addr = offset ? memory->memory_data + offset : NULL;
+ }
+
+ if (!addr) {
+ if (memory->heap_handle
+ && mem_allocator_is_heap_corrupted(memory->heap_handle)) {
+ wasm_runtime_show_app_heap_corrupted_prompt();
+ wasm_set_exception(module_inst, "app heap corrupted");
+ }
+ else {
+ LOG_WARNING("warning: allocate %u bytes memory failed", size);
+ }
+ return 0;
+ }
+ if (p_native_addr)
+ *p_native_addr = addr;
+
+ return (uint32)(addr - memory->memory_data);
+}
+
+uint32
+wasm_module_realloc_internal(WASMModuleInstance *module_inst,
+ WASMExecEnv *exec_env, uint32 ptr, uint32 size,
+ void **p_native_addr)
+{
+ WASMMemoryInstance *memory = wasm_get_default_memory(module_inst);
+ uint8 *addr = NULL;
+
+ if (!memory) {
+ wasm_set_exception(module_inst, "uninitialized memory");
+ return 0;
+ }
+
+ if (memory->heap_handle) {
+ addr = mem_allocator_realloc(
+ memory->heap_handle, ptr ? memory->memory_data + ptr : NULL, size);
+ }
+
+ /* Only support realloc in WAMR's app heap */
+ (void)exec_env;
+
+ if (!addr) {
+ if (memory->heap_handle
+ && mem_allocator_is_heap_corrupted(memory->heap_handle)) {
+ wasm_set_exception(module_inst, "app heap corrupted");
+ }
+ else {
+ wasm_set_exception(module_inst, "out of memory");
+ }
+ return 0;
+ }
+ if (p_native_addr)
+ *p_native_addr = addr;
+
+ return (uint32)(addr - memory->memory_data);
+}
+
+void
+wasm_module_free_internal(WASMModuleInstance *module_inst,
+ WASMExecEnv *exec_env, uint32 ptr)
+{
+ if (ptr) {
+ WASMMemoryInstance *memory = wasm_get_default_memory(module_inst);
+ uint8 *addr;
+
+ if (!memory) {
+ return;
+ }
+
+ addr = memory->memory_data + ptr;
+
+ if (memory->heap_handle && memory->heap_data <= addr
+ && addr < memory->heap_data_end) {
+ mem_allocator_free(memory->heap_handle, addr);
+ }
+ else if (module_inst->e->malloc_function
+ && module_inst->e->free_function && memory->memory_data <= addr
+ && addr < memory->memory_data_end) {
+ execute_free_function(module_inst, exec_env,
+ module_inst->e->free_function, ptr);
+ }
+ }
+}
+
+uint32
+wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size,
+ void **p_native_addr)
+{
+ return wasm_module_malloc_internal(module_inst, NULL, size, p_native_addr);
+}
+
+uint32
+wasm_module_realloc(WASMModuleInstance *module_inst, uint32 ptr, uint32 size,
+ void **p_native_addr)
+{
+ return wasm_module_realloc_internal(module_inst, NULL, ptr, size,
+ p_native_addr);
+}
+
+void
+wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr)
+{
+ wasm_module_free_internal(module_inst, NULL, ptr);
+}
+
+uint32
+wasm_module_dup_data(WASMModuleInstance *module_inst, const char *src,
+ uint32 size)
+{
+ char *buffer;
+ uint32 buffer_offset =
+ wasm_module_malloc(module_inst, size, (void **)&buffer);
+ if (buffer_offset != 0) {
+ buffer = wasm_runtime_addr_app_to_native(
+ (WASMModuleInstanceCommon *)module_inst, buffer_offset);
+ bh_memcpy_s(buffer, size, src, size);
+ }
+ return buffer_offset;
+}
+
+#if WASM_ENABLE_REF_TYPES != 0
+bool
+wasm_enlarge_table(WASMModuleInstance *module_inst, uint32 table_idx,
+ uint32 inc_size, uint32 init_val)
+{
+ uint32 total_size, *new_table_data_start, i;
+ WASMTableInstance *table_inst;
+
+ if (!inc_size) {
+ return true;
+ }
+
+ bh_assert(table_idx < module_inst->table_count);
+ table_inst = wasm_get_table_inst(module_inst, table_idx);
+ if (!table_inst) {
+ return false;
+ }
+
+ if (inc_size > UINT32_MAX - table_inst->cur_size) {
+ return false;
+ }
+
+ total_size = table_inst->cur_size + inc_size;
+ if (total_size > table_inst->max_size) {
+ return false;
+ }
+
+ /* fill in */
+ new_table_data_start = table_inst->elems + table_inst->cur_size;
+ for (i = 0; i < inc_size; ++i) {
+ new_table_data_start[i] = init_val;
+ }
+
+ table_inst->cur_size = total_size;
+ return true;
+}
+#endif /* WASM_ENABLE_REF_TYPES != 0 */
+
+static bool
+call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx,
+ uint32 argc, uint32 argv[], bool check_type_idx, uint32 type_idx)
+{
+ WASMModuleInstance *module_inst = NULL;
+ WASMTableInstance *table_inst = NULL;
+ uint32 func_idx = 0;
+ WASMFunctionInstance *func_inst = NULL;
+
+ module_inst = (WASMModuleInstance *)exec_env->module_inst;
+ bh_assert(module_inst);
+
+ table_inst = module_inst->tables[tbl_idx];
+ if (!table_inst) {
+ wasm_set_exception(module_inst, "unknown table");
+ goto got_exception;
+ }
+
+ if (elem_idx >= table_inst->cur_size) {
+ wasm_set_exception(module_inst, "undefined element");
+ goto got_exception;
+ }
+
+ func_idx = table_inst->elems[elem_idx];
+ if (func_idx == NULL_REF) {
+ wasm_set_exception(module_inst, "uninitialized element");
+ goto got_exception;
+ }
+
+ /**
+ * we insist to call functions owned by the module itself
+ **/
+ if (func_idx >= module_inst->e->function_count) {
+ wasm_set_exception(module_inst, "unknown function");
+ goto got_exception;
+ }
+
+ func_inst = module_inst->e->functions + func_idx;
+
+ if (check_type_idx) {
+ WASMType *cur_type = module_inst->module->types[type_idx];
+ WASMType *cur_func_type;
+
+ if (func_inst->is_import_func)
+ cur_func_type = func_inst->u.func_import->func_type;
+ else
+ cur_func_type = func_inst->u.func->func_type;
+
+ if (cur_type != cur_func_type) {
+ wasm_set_exception(module_inst, "indirect call type mismatch");
+ goto got_exception;
+ }
+ }
+
+ interp_call_wasm(module_inst, exec_env, func_inst, argc, argv);
+
+ return !wasm_copy_exception(module_inst, NULL);
+
+got_exception:
+ return false;
+}
+
+bool
+wasm_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx,
+ uint32 argc, uint32 argv[])
+{
+ return call_indirect(exec_env, tbl_idx, elem_idx, argc, argv, false, 0);
+}
+
+#if WASM_ENABLE_THREAD_MGR != 0
+bool
+wasm_set_aux_stack(WASMExecEnv *exec_env, uint32 start_offset, uint32 size)
+{
+ WASMModuleInstance *module_inst =
+ (WASMModuleInstance *)exec_env->module_inst;
+ uint32 stack_top_idx = module_inst->module->aux_stack_top_global_index;
+
+#if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION == 0
+ /* Check the aux stack space */
+ uint32 data_end = module_inst->module->aux_data_end;
+ uint32 stack_bottom = module_inst->module->aux_stack_bottom;
+ bool is_stack_before_data = stack_bottom < data_end ? true : false;
+ if ((is_stack_before_data && (size > start_offset))
+ || ((!is_stack_before_data) && (start_offset - data_end < size)))
+ return false;
+#endif
+
+ if (stack_top_idx != (uint32)-1) {
+ /* The aux stack top is a wasm global,
+ set the initial value for the global */
+ uint8 *global_addr =
+ module_inst->global_data
+ + module_inst->e->globals[stack_top_idx].data_offset;
+ *(int32 *)global_addr = start_offset;
+ /* The aux stack boundary is a constant value,
+ set the value to exec_env */
+ exec_env->aux_stack_boundary.boundary = start_offset - size;
+ exec_env->aux_stack_bottom.bottom = start_offset;
+ return true;
+ }
+
+ return false;
+}
+
+bool
+wasm_get_aux_stack(WASMExecEnv *exec_env, uint32 *start_offset, uint32 *size)
+{
+ WASMModuleInstance *module_inst =
+ (WASMModuleInstance *)exec_env->module_inst;
+
+ /* The aux stack information is resolved in loader
+ and store in module */
+ uint32 stack_bottom = module_inst->module->aux_stack_bottom;
+ uint32 total_aux_stack_size = module_inst->module->aux_stack_size;
+
+ if (stack_bottom != 0 && total_aux_stack_size != 0) {
+ if (start_offset)
+ *start_offset = stack_bottom;
+ if (size)
+ *size = total_aux_stack_size;
+ return true;
+ }
+ return false;
+}
+#endif
+
+#if (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_MEMORY_TRACING != 0)
+void
+wasm_get_module_mem_consumption(const WASMModule *module,
+ WASMModuleMemConsumption *mem_conspn)
+{
+ uint32 i, size;
+
+ memset(mem_conspn, 0, sizeof(*mem_conspn));
+
+ mem_conspn->module_struct_size = sizeof(WASMModule);
+
+ mem_conspn->types_size = sizeof(WASMType *) * module->type_count;
+ for (i = 0; i < module->type_count; i++) {
+ WASMType *type = module->types[i];
+ size = offsetof(WASMType, types)
+ + sizeof(uint8) * (type->param_count + type->result_count);
+ mem_conspn->types_size += size;
+ }
+
+ mem_conspn->imports_size = sizeof(WASMImport) * module->import_count;
+
+ mem_conspn->functions_size =
+ sizeof(WASMFunction *) * module->function_count;
+ for (i = 0; i < module->function_count; i++) {
+ WASMFunction *func = module->functions[i];
+ WASMType *type = func->func_type;
+ size = sizeof(WASMFunction) + func->local_count
+ + sizeof(uint16) * (type->param_count + func->local_count);
+#if WASM_ENABLE_FAST_INTERP != 0
+ size +=
+ func->code_compiled_size + sizeof(uint32) * func->const_cell_num;
+#endif
+ mem_conspn->functions_size += size;
+ }
+
+ mem_conspn->tables_size = sizeof(WASMTable) * module->table_count;
+ mem_conspn->memories_size = sizeof(WASMMemory) * module->memory_count;
+ mem_conspn->globals_size = sizeof(WASMGlobal) * module->global_count;
+ mem_conspn->exports_size = sizeof(WASMExport) * module->export_count;
+
+ mem_conspn->table_segs_size =
+ sizeof(WASMTableSeg) * module->table_seg_count;
+ for (i = 0; i < module->table_seg_count; i++) {
+ WASMTableSeg *table_seg = &module->table_segments[i];
+ mem_conspn->tables_size += sizeof(uint32) * table_seg->function_count;
+ }
+
+ mem_conspn->data_segs_size = sizeof(WASMDataSeg *) * module->data_seg_count;
+ for (i = 0; i < module->data_seg_count; i++) {
+ mem_conspn->data_segs_size += sizeof(WASMDataSeg);
+ }
+
+ if (module->const_str_list) {
+ StringNode *node = module->const_str_list, *node_next;
+ while (node) {
+ node_next = node->next;
+ mem_conspn->const_strs_size +=
+ sizeof(StringNode) + strlen(node->str) + 1;
+ node = node_next;
+ }
+ }
+
+ mem_conspn->total_size += mem_conspn->module_struct_size;
+ mem_conspn->total_size += mem_conspn->types_size;
+ mem_conspn->total_size += mem_conspn->imports_size;
+ mem_conspn->total_size += mem_conspn->functions_size;
+ mem_conspn->total_size += mem_conspn->tables_size;
+ mem_conspn->total_size += mem_conspn->memories_size;
+ mem_conspn->total_size += mem_conspn->globals_size;
+ mem_conspn->total_size += mem_conspn->exports_size;
+ mem_conspn->total_size += mem_conspn->table_segs_size;
+ mem_conspn->total_size += mem_conspn->data_segs_size;
+ mem_conspn->total_size += mem_conspn->const_strs_size;
+}
+
+void
+wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module_inst,
+ WASMModuleInstMemConsumption *mem_conspn)
+{
+ uint32 i, size;
+
+ memset(mem_conspn, 0, sizeof(*mem_conspn));
+
+ mem_conspn->module_inst_struct_size = (uint8 *)module_inst->e
+ - (uint8 *)module_inst
+ + sizeof(WASMModuleInstanceExtra);
+
+ mem_conspn->memories_size =
+ sizeof(WASMMemoryInstance *) * module_inst->memory_count;
+ for (i = 0; i < module_inst->memory_count; i++) {
+ WASMMemoryInstance *memory = module_inst->memories[i];
+ size = memory->num_bytes_per_page * memory->cur_page_count;
+ mem_conspn->memories_size += size;
+ mem_conspn->app_heap_size += memory->heap_data_end - memory->heap_data;
+ /* size of app heap structure */
+ mem_conspn->memories_size += mem_allocator_get_heap_struct_size();
+ /* Module instance structures have been appened into the end of
+ module instance */
+ }
+
+ mem_conspn->tables_size =
+ sizeof(WASMTableInstance *) * module_inst->table_count;
+ /* Table instance structures and table elements have been appened into
+ the end of module instance */
+
+ mem_conspn->functions_size =
+ sizeof(WASMFunctionInstance) * module_inst->e->function_count;
+
+ mem_conspn->globals_size =
+ sizeof(WASMGlobalInstance) * module_inst->e->global_count;
+ /* Global data has been appened into the end of module instance */
+
+ mem_conspn->exports_size =
+ sizeof(WASMExportFuncInstance) * module_inst->export_func_count;
+
+ mem_conspn->total_size += mem_conspn->module_inst_struct_size;
+ mem_conspn->total_size += mem_conspn->memories_size;
+ mem_conspn->total_size += mem_conspn->functions_size;
+ mem_conspn->total_size += mem_conspn->tables_size;
+ mem_conspn->total_size += mem_conspn->globals_size;
+ mem_conspn->total_size += mem_conspn->exports_size;
+}
+#endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0) \
+ || (WASM_ENABLE_MEMORY_TRACING != 0) */
+
+#if WASM_ENABLE_DUMP_CALL_STACK != 0
+bool
+wasm_interp_create_call_stack(struct WASMExecEnv *exec_env)
+{
+ WASMModuleInstance *module_inst =
+ (WASMModuleInstance *)wasm_exec_env_get_module_inst(exec_env);
+ WASMInterpFrame *first_frame,
+ *cur_frame = wasm_exec_env_get_cur_frame(exec_env);
+ uint32 n = 0;
+
+ /* count frames includes a function */
+ first_frame = cur_frame;
+ while (cur_frame) {
+ if (cur_frame->function) {
+ n++;
+ }
+ cur_frame = cur_frame->prev_frame;
+ }
+
+ /* release previous stack frames and create new ones */
+ if (!bh_vector_destroy(module_inst->frames)
+ || !bh_vector_init(module_inst->frames, n, sizeof(WASMCApiFrame),
+ false)) {
+ return false;
+ }
+
+ cur_frame = first_frame;
+ n = 0;
+
+ while (cur_frame) {
+ WASMCApiFrame frame = { 0 };
+ WASMFunctionInstance *func_inst = cur_frame->function;
+ const char *func_name = NULL;
+ const uint8 *func_code_base = NULL;
+
+ if (!func_inst) {
+ cur_frame = cur_frame->prev_frame;
+ continue;
+ }
+
+ /* place holder, will overwrite it in wasm_c_api */
+ frame.instance = module_inst;
+ frame.module_offset = 0;
+ frame.func_index = (uint32)(func_inst - module_inst->e->functions);
+
+ func_code_base = wasm_get_func_code(func_inst);
+ if (!cur_frame->ip || !func_code_base) {
+ frame.func_offset = 0;
+ }
+ else {
+ frame.func_offset = (uint32)(cur_frame->ip - func_code_base);
+ }
+
+ /* look for the function name */
+ if (func_inst->is_import_func) {
+ func_name = func_inst->u.func_import->field_name;
+ }
+ else {
+#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
+ func_name = func_inst->u.func->field_name;
+#endif
+ /* if custom name section is not generated,
+ search symbols from export table */
+ if (!func_name) {
+ uint32 i;
+ for (i = 0; i < module_inst->export_func_count; i++) {
+ WASMExportFuncInstance *export_func =
+ module_inst->export_functions + i;
+ if (export_func->function == func_inst) {
+ func_name = export_func->name;
+ break;
+ }
+ }
+ }
+ }
+
+ frame.func_name_wp = func_name;
+
+ if (!bh_vector_append(module_inst->frames, &frame)) {
+ bh_vector_destroy(module_inst->frames);
+ return false;
+ }
+
+ cur_frame = cur_frame->prev_frame;
+ n++;
+ }
+
+ return true;
+}
+
+#define PRINT_OR_DUMP() \
+ do { \
+ total_len += \
+ wasm_runtime_dump_line_buf_impl(line_buf, print, &buf, &len); \
+ if ((!print) && buf && (len == 0)) { \
+ return total_len; \
+ } \
+ } while (0)
+
+uint32
+wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env, bool print, char *buf,
+ uint32 len)
+{
+ WASMModuleInstance *module_inst =
+ (WASMModuleInstance *)wasm_exec_env_get_module_inst(exec_env);
+ uint32 n = 0, total_len = 0, total_frames;
+ /* reserve 256 bytes for line buffer, any line longer than 256 bytes
+ * will be truncated */
+ char line_buf[256];
+
+ if (!module_inst->frames) {
+ return 0;
+ }
+
+ total_frames = (uint32)bh_vector_size(module_inst->frames);
+ if (total_frames == 0) {
+ return 0;
+ }
+
+ snprintf(line_buf, sizeof(line_buf), "\n");
+ PRINT_OR_DUMP();
+
+ while (n < total_frames) {
+ WASMCApiFrame frame = { 0 };
+ uint32 line_length, i;
+
+ if (!bh_vector_get(module_inst->frames, n, &frame)) {
+ return 0;
+ }
+
+ /* function name not exported, print number instead */
+ if (frame.func_name_wp == NULL) {
+ line_length = snprintf(line_buf, sizeof(line_buf), "#%02d $f%d\n",
+ n, frame.func_index);
+ }
+ else {
+ line_length = snprintf(line_buf, sizeof(line_buf), "#%02d %s\n", n,
+ frame.func_name_wp);
+ }
+
+ if (line_length >= sizeof(line_buf)) {
+ uint32 line_buffer_len = sizeof(line_buf);
+ /* If line too long, ensure the last character is '\n' */
+ for (i = line_buffer_len - 5; i < line_buffer_len - 2; i++) {
+ line_buf[i] = '.';
+ }
+ line_buf[line_buffer_len - 2] = '\n';
+ }
+
+ PRINT_OR_DUMP();
+
+ n++;
+ }
+ snprintf(line_buf, sizeof(line_buf), "\n");
+ PRINT_OR_DUMP();
+
+ return total_len + 1;
+}
+#endif /* end of WASM_ENABLE_DUMP_CALL_STACK */
+
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \
+ || WASM_ENABLE_WAMR_COMPILER != 0
+void
+jit_set_exception_with_id(WASMModuleInstance *module_inst, uint32 id)
+{
+ if (id != EXCE_ALREADY_THROWN)
+ wasm_set_exception_with_id(module_inst, id);
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ wasm_runtime_access_exce_check_guard_page();
+#endif
+}
+
+bool
+jit_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
+ uint32 app_buf_addr, uint32 app_buf_size,
+ void **p_native_addr)
+{
+ bool ret = wasm_check_app_addr_and_convert(
+ module_inst, is_str, app_buf_addr, app_buf_size, p_native_addr);
+
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ if (!ret)
+ wasm_runtime_access_exce_check_guard_page();
+#endif
+
+ return ret;
+}
+#endif /* end of WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \
+ || WASM_ENABLE_WAMR_COMPILER != 0 */
+
+#if WASM_ENABLE_FAST_JIT != 0
+bool
+fast_jit_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx,
+ uint32 type_idx, uint32 argc, uint32 *argv)
+{
+ return call_indirect(exec_env, tbl_idx, elem_idx, argc, argv, true,
+ type_idx);
+}
+#endif /* end of WASM_ENABLE_FAST_JIT != 0 */
+
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+
+bool
+llvm_jit_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx,
+ uint32 argc, uint32 *argv)
+{
+ bool ret;
+
+#if WASM_ENABLE_JIT != 0
+ if (Wasm_Module_AoT == exec_env->module_inst->module_type) {
+ return aot_call_indirect(exec_env, tbl_idx, elem_idx, argc, argv);
+ }
+#endif
+
+ ret = call_indirect(exec_env, tbl_idx, elem_idx, argc, argv, false, 0);
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ if (!ret)
+ wasm_runtime_access_exce_check_guard_page();
+#endif
+ return ret;
+}
+
+bool
+llvm_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
+ uint32 *argv)
+{
+ WASMModuleInstance *module_inst;
+ WASMModule *module;
+ uint32 *func_type_indexes;
+ uint32 func_type_idx;
+ WASMType *func_type;
+ void *func_ptr;
+ WASMFunctionImport *import_func;
+ CApiFuncImport *c_api_func_import = NULL;
+ const char *signature;
+ void *attachment;
+ char buf[96];
+ bool ret = false;
+
+#if WASM_ENABLE_JIT != 0
+ if (Wasm_Module_AoT == exec_env->module_inst->module_type) {
+ return aot_invoke_native(exec_env, func_idx, argc, argv);
+ }
+#endif
+
+ module_inst = (WASMModuleInstance *)wasm_runtime_get_module_inst(exec_env);
+ module = module_inst->module;
+ func_type_indexes = module_inst->func_type_indexes;
+ func_type_idx = func_type_indexes[func_idx];
+ func_type = module->types[func_type_idx];
+ func_ptr = module_inst->func_ptrs[func_idx];
+
+ bh_assert(func_idx < module->import_function_count);
+
+ import_func = &module->import_functions[func_idx].u.function;
+ if (import_func->call_conv_wasm_c_api) {
+ if (module_inst->e->c_api_func_imports) {
+ c_api_func_import = module_inst->e->c_api_func_imports + func_idx;
+ func_ptr = c_api_func_import->func_ptr_linked;
+ }
+ else {
+ c_api_func_import = NULL;
+ func_ptr = NULL;
+ }
+ }
+
+ if (!func_ptr) {
+ snprintf(buf, sizeof(buf),
+ "failed to call unlinked import function (%s, %s)",
+ import_func->module_name, import_func->field_name);
+ wasm_set_exception(module_inst, buf);
+ goto fail;
+ }
+
+ attachment = import_func->attachment;
+ if (import_func->call_conv_wasm_c_api) {
+ ret = wasm_runtime_invoke_c_api_native(
+ (WASMModuleInstanceCommon *)module_inst, func_ptr, func_type, argc,
+ argv, c_api_func_import->with_env_arg, c_api_func_import->env_arg);
+ }
+ else if (!import_func->call_conv_raw) {
+ signature = import_func->signature;
+ ret =
+ wasm_runtime_invoke_native(exec_env, func_ptr, func_type, signature,
+ attachment, argv, argc, argv);
+ }
+ else {
+ signature = import_func->signature;
+ ret = wasm_runtime_invoke_native_raw(exec_env, func_ptr, func_type,
+ signature, attachment, argv, argc,
+ argv);
+ }
+
+fail:
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+ if (!ret)
+ wasm_runtime_access_exce_check_guard_page();
+#endif
+ return ret;
+}
+
+#if WASM_ENABLE_BULK_MEMORY != 0
+bool
+llvm_jit_memory_init(WASMModuleInstance *module_inst, uint32 seg_index,
+ uint32 offset, uint32 len, uint32 dst)
+{
+ WASMMemoryInstance *memory_inst;
+ WASMModule *module;
+ uint8 *data = NULL;
+ uint8 *maddr;
+ uint64 seg_len = 0;
+
+#if WASM_ENABLE_JIT != 0
+ if (Wasm_Module_AoT == module_inst->module_type) {
+ return aot_memory_init(module_inst, seg_index, offset, len, dst);
+ }
+#endif
+
+ memory_inst = wasm_get_default_memory(module_inst);
+ module = module_inst->module;
+ seg_len = module->data_segments[seg_index]->data_length;
+ data = module->data_segments[seg_index]->data;
+
+ if (!wasm_runtime_validate_app_addr((WASMModuleInstanceCommon *)module_inst,
+ dst, len))
+ return false;
+
+ if ((uint64)offset + (uint64)len > seg_len) {
+ wasm_set_exception(module_inst, "out of bounds memory access");
+ return false;
+ }
+
+ maddr = wasm_runtime_addr_app_to_native(
+ (WASMModuleInstanceCommon *)module_inst, dst);
+
+ bh_memcpy_s(maddr, memory_inst->memory_data_size - dst, data + offset, len);
+ return true;
+}
+
+bool
+llvm_jit_data_drop(WASMModuleInstance *module_inst, uint32 seg_index)
+{
+#if WASM_ENABLE_JIT != 0
+ if (Wasm_Module_AoT == module_inst->module_type) {
+ return aot_data_drop(module_inst, seg_index);
+ }
+#endif
+
+ module_inst->module->data_segments[seg_index]->data_length = 0;
+ /* Currently we can't free the dropped data segment
+ as they are stored in wasm bytecode */
+ return true;
+}
+#endif /* end of WASM_ENABLE_BULK_MEMORY != 0 */
+
+#if WASM_ENABLE_REF_TYPES != 0
+void
+llvm_jit_drop_table_seg(WASMModuleInstance *module_inst, uint32 tbl_seg_idx)
+{
+ WASMTableSeg *tbl_segs;
+
+#if WASM_ENABLE_JIT != 0
+ if (Wasm_Module_AoT == module_inst->module_type) {
+ return aot_drop_table_seg(module_inst, tbl_seg_idx);
+ }
+#endif
+
+ tbl_segs = module_inst->module->table_segments;
+ tbl_segs[tbl_seg_idx].is_dropped = true;
+}
+
+void
+llvm_jit_table_init(WASMModuleInstance *module_inst, uint32 tbl_idx,
+ uint32 tbl_seg_idx, uint32 length, uint32 src_offset,
+ uint32 dst_offset)
+{
+ WASMTableInstance *tbl_inst;
+ WASMTableSeg *tbl_seg;
+
+#if WASM_ENABLE_JIT != 0
+ if (Wasm_Module_AoT == module_inst->module_type) {
+ return aot_table_init(module_inst, tbl_idx, tbl_seg_idx, length,
+ src_offset, dst_offset);
+ }
+#endif
+
+ tbl_inst = wasm_get_table_inst(module_inst, tbl_idx);
+ tbl_seg = module_inst->module->table_segments + tbl_seg_idx;
+
+ bh_assert(tbl_inst);
+ bh_assert(tbl_seg);
+
+ if (!length) {
+ return;
+ }
+
+ if (length + src_offset > tbl_seg->function_count
+ || dst_offset + length > tbl_inst->cur_size) {
+ jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
+ return;
+ }
+
+ if (tbl_seg->is_dropped) {
+ jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
+ return;
+ }
+
+ if (!wasm_elem_is_passive(tbl_seg->mode)) {
+ jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
+ return;
+ }
+
+ bh_memcpy_s((uint8 *)tbl_inst + offsetof(WASMTableInstance, elems)
+ + dst_offset * sizeof(uint32),
+ (uint32)sizeof(uint32) * (tbl_inst->cur_size - dst_offset),
+ tbl_seg->func_indexes + src_offset,
+ (uint32)(length * sizeof(uint32)));
+}
+
+void
+llvm_jit_table_copy(WASMModuleInstance *module_inst, uint32 src_tbl_idx,
+ uint32 dst_tbl_idx, uint32 length, uint32 src_offset,
+ uint32 dst_offset)
+{
+ WASMTableInstance *src_tbl_inst;
+ WASMTableInstance *dst_tbl_inst;
+
+#if WASM_ENABLE_JIT != 0
+ if (Wasm_Module_AoT == module_inst->module_type) {
+ aot_table_copy(module_inst, src_tbl_idx, dst_tbl_idx, length,
+ src_offset, dst_offset);
+ return;
+ }
+#endif
+
+ src_tbl_inst = wasm_get_table_inst(module_inst, src_tbl_idx);
+ dst_tbl_inst = wasm_get_table_inst(module_inst, dst_tbl_idx);
+ bh_assert(src_tbl_inst);
+ bh_assert(dst_tbl_inst);
+
+ if ((uint64)dst_offset + length > dst_tbl_inst->cur_size
+ || (uint64)src_offset + length > src_tbl_inst->cur_size) {
+ jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
+ return;
+ }
+
+ /* if src_offset >= dst_offset, copy from front to back */
+ /* if src_offset < dst_offset, copy from back to front */
+ /* merge all together */
+ bh_memmove_s((uint8 *)dst_tbl_inst + offsetof(WASMTableInstance, elems)
+ + sizeof(uint32) * dst_offset,
+ (uint32)sizeof(uint32) * (dst_tbl_inst->cur_size - dst_offset),
+ (uint8 *)src_tbl_inst + offsetof(WASMTableInstance, elems)
+ + sizeof(uint32) * src_offset,
+ (uint32)sizeof(uint32) * length);
+}
+
+void
+llvm_jit_table_fill(WASMModuleInstance *module_inst, uint32 tbl_idx,
+ uint32 length, uint32 val, uint32 data_offset)
+{
+ WASMTableInstance *tbl_inst;
+
+#if WASM_ENABLE_JIT != 0
+ if (Wasm_Module_AoT == module_inst->module_type) {
+ aot_table_fill(module_inst, tbl_idx, length, val, data_offset);
+ return;
+ }
+#endif
+
+ tbl_inst = wasm_get_table_inst(module_inst, tbl_idx);
+ bh_assert(tbl_inst);
+
+ if (data_offset + length > tbl_inst->cur_size) {
+ jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
+ return;
+ }
+
+ for (; length != 0; data_offset++, length--) {
+ tbl_inst->elems[data_offset] = val;
+ }
+}
+
+uint32
+llvm_jit_table_grow(WASMModuleInstance *module_inst, uint32 tbl_idx,
+ uint32 inc_size, uint32 init_val)
+{
+ WASMTableInstance *tbl_inst;
+ uint32 i, orig_size, total_size;
+
+#if WASM_ENABLE_JIT != 0
+ if (Wasm_Module_AoT == module_inst->module_type) {
+ return aot_table_grow(module_inst, tbl_idx, inc_size, init_val);
+ }
+#endif
+
+ tbl_inst = wasm_get_table_inst(module_inst, tbl_idx);
+ if (!tbl_inst) {
+ return (uint32)-1;
+ }
+
+ orig_size = tbl_inst->cur_size;
+
+ if (!inc_size) {
+ return orig_size;
+ }
+
+ if (tbl_inst->cur_size > UINT32_MAX - inc_size) { /* integer overflow */
+ return (uint32)-1;
+ }
+
+ total_size = tbl_inst->cur_size + inc_size;
+ if (total_size > tbl_inst->max_size) {
+ return (uint32)-1;
+ }
+
+ /* fill in */
+ for (i = 0; i < inc_size; ++i) {
+ tbl_inst->elems[tbl_inst->cur_size + i] = init_val;
+ }
+
+ tbl_inst->cur_size = total_size;
+ return orig_size;
+}
+#endif /* end of WASM_ENABLE_REF_TYPES != 0 */
+
+#if WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_PERF_PROFILING != 0
+bool
+llvm_jit_alloc_frame(WASMExecEnv *exec_env, uint32 func_index)
+{
+ WASMModuleInstance *module_inst;
+ WASMInterpFrame *frame;
+ uint32 size;
+
+#if WASM_ENABLE_JIT != 0
+ if (Wasm_Module_AoT == exec_env->module_inst->module_type) {
+ return aot_alloc_frame(exec_env, func_index);
+ }
+#endif
+
+ module_inst = (WASMModuleInstance *)exec_env->module_inst;
+ size = wasm_interp_interp_frame_size(0);
+
+ frame = wasm_exec_env_alloc_wasm_frame(exec_env, size);
+ if (!frame) {
+ wasm_set_exception(module_inst, "wasm operand stack overflow");
+ return false;
+ }
+
+ frame->function = module_inst->e->functions + func_index;
+ frame->ip = NULL;
+ frame->sp = frame->lp;
+#if WASM_ENABLE_PERF_PROFILING != 0
+ frame->time_started = os_time_get_boot_microsecond();
+#endif
+ frame->prev_frame = wasm_exec_env_get_cur_frame(exec_env);
+ wasm_exec_env_set_cur_frame(exec_env, frame);
+
+ return true;
+}
+
+void
+llvm_jit_free_frame(WASMExecEnv *exec_env)
+{
+ WASMInterpFrame *frame;
+ WASMInterpFrame *prev_frame;
+
+#if WASM_ENABLE_JIT != 0
+ if (Wasm_Module_AoT == exec_env->module_inst->module_type) {
+ aot_free_frame(exec_env);
+ return;
+ }
+#endif
+
+ frame = wasm_exec_env_get_cur_frame(exec_env);
+ prev_frame = frame->prev_frame;
+
+#if WASM_ENABLE_PERF_PROFILING != 0
+ if (frame->function) {
+ frame->function->total_exec_time +=
+ os_time_get_boot_microsecond() - frame->time_started;
+ frame->function->total_exec_cnt++;
+ }
+#endif
+ wasm_exec_env_free_wasm_frame(exec_env, frame);
+ wasm_exec_env_set_cur_frame(exec_env, prev_frame);
+}
+#endif /* end of WASM_ENABLE_DUMP_CALL_STACK != 0 \
+ || WASM_ENABLE_PERF_PROFILING != 0 */
+
+#endif /* end of WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 */
+
+#if WASM_ENABLE_LIBC_WASI != 0 && WASM_ENABLE_MULTI_MODULE != 0
+void
+wasm_propagate_wasi_args(WASMModule *module)
+{
+ if (!module->import_count)
+ return;
+
+ bh_assert(&module->import_module_list_head);
+
+ WASMRegisteredModule *node =
+ bh_list_first_elem(&module->import_module_list_head);
+ while (node) {
+ WASIArguments *wasi_args_impt_mod =
+ &((WASMModule *)(node->module))->wasi_args;
+ bh_assert(wasi_args_impt_mod);
+
+ bh_memcpy_s(wasi_args_impt_mod, sizeof(WASIArguments),
+ &module->wasi_args, sizeof(WASIArguments));
+ node = bh_list_elem_next(node);
+ }
+}
+#endif
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_runtime.h b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_runtime.h
new file mode 100644
index 000000000..15169433e
--- /dev/null
+++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_runtime.h
@@ -0,0 +1,668 @@
+/*
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef _WASM_RUNTIME_H
+#define _WASM_RUNTIME_H
+
+#include "wasm.h"
+#include "bh_hashmap.h"
+#include "../common/wasm_runtime_common.h"
+#include "../common/wasm_exec_env.h"
+
+#if WASM_ENABLE_WASI_NN != 0
+#include "../libraries/wasi-nn/src/wasi_nn_private.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EXCEPTION_BUF_LEN 128
+
+typedef struct WASMModuleInstance WASMModuleInstance;
+typedef struct WASMFunctionInstance WASMFunctionInstance;
+typedef struct WASMMemoryInstance WASMMemoryInstance;
+typedef struct WASMTableInstance WASMTableInstance;
+typedef struct WASMGlobalInstance WASMGlobalInstance;
+
+/**
+ * When LLVM JIT, WAMR compiler or AOT is enabled, we should ensure that
+ * some offsets of the same field in the interpreter module instance and
+ * aot module instance are the same, so that the LLVM JITed/AOTed code
+ * can smoothly access the interpreter module instance.
+ * Same for the memory instance and table instance.
+ * We use the macro DefPointer to define some related pointer fields.
+ */
+#if (WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 \
+ || WASM_ENABLE_AOT != 0) \
+ && UINTPTR_MAX == UINT32_MAX
+/* Add u32 padding if LLVM JIT, WAMR compiler or AOT is enabled on
+ 32-bit platform */
+#define DefPointer(type, field) \
+ type field; \
+ uint32 field##_padding
+#else
+#define DefPointer(type, field) type field
+#endif
+
+typedef enum WASMExceptionID {
+ EXCE_UNREACHABLE = 0,
+ EXCE_OUT_OF_MEMORY,
+ EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS,
+ EXCE_INTEGER_OVERFLOW,
+ EXCE_INTEGER_DIVIDE_BY_ZERO,
+ EXCE_INVALID_CONVERSION_TO_INTEGER,
+ EXCE_INVALID_FUNCTION_TYPE_INDEX,
+ EXCE_INVALID_FUNCTION_INDEX,
+ EXCE_UNDEFINED_ELEMENT,
+ EXCE_UNINITIALIZED_ELEMENT,
+ EXCE_CALL_UNLINKED_IMPORT_FUNC,
+ EXCE_NATIVE_STACK_OVERFLOW,
+ EXCE_UNALIGNED_ATOMIC,
+ EXCE_AUX_STACK_OVERFLOW,
+ EXCE_AUX_STACK_UNDERFLOW,
+ EXCE_OUT_OF_BOUNDS_TABLE_ACCESS,
+ EXCE_OPERAND_STACK_OVERFLOW,
+ EXCE_FAILED_TO_COMPILE_FAST_JIT_FUNC,
+ EXCE_ALREADY_THROWN,
+ EXCE_NUM,
+} WASMExceptionID;
+
+typedef union {
+ uint64 u64;
+ uint32 u32[2];
+} MemBound;
+
+struct WASMMemoryInstance {
+ /* Module type */
+ uint32 module_type;
+ /* Shared memory flag */
+ bool is_shared;
+
+ /* Number bytes per page */
+ uint32 num_bytes_per_page;
+ /* Current page count */
+ uint32 cur_page_count;
+ /* Maximum page count */
+ uint32 max_page_count;
+ /* Memory data size */
+ uint32 memory_data_size;
+ /**
+ * Memory data begin address, Note:
+ * the app-heap might be inserted in to the linear memory,
+ * when memory is re-allocated, the heap data and memory data
+ * must be copied to new memory also
+ */
+ DefPointer(uint8 *, memory_data);
+ /* Memory data end address */
+ DefPointer(uint8 *, memory_data_end);
+
+ /* Heap data base address */
+ DefPointer(uint8 *, heap_data);
+ /* Heap data end address */
+ DefPointer(uint8 *, heap_data_end);
+ /* The heap created */
+ DefPointer(void *, heap_handle);
+
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \
+ || WASM_ENABLE_WAMR_COMPILER != 0 || WASM_ENABLE_AOT != 0
+ MemBound mem_bound_check_1byte;
+ MemBound mem_bound_check_2bytes;
+ MemBound mem_bound_check_4bytes;
+ MemBound mem_bound_check_8bytes;
+ MemBound mem_bound_check_16bytes;
+#endif
+};
+
+struct WASMTableInstance {
+ /* Current size */
+ uint32 cur_size;
+ /* Maximum size */
+ uint32 max_size;
+ /* Table elements */
+ uint32 elems[1];
+};
+
+struct WASMGlobalInstance {
+ /* value type, VALUE_TYPE_I32/I64/F32/F64 */
+ uint8 type;
+ /* mutable or constant */
+ bool is_mutable;
+ /* data offset to base_addr of WASMMemoryInstance */
+ 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
+};
+
+struct WASMFunctionInstance {
+ /* whether it is import function or WASM function */
+ bool is_import_func;
+ /* parameter count */
+ uint16 param_count;
+ /* local variable count, 0 for import function */
+ uint16 local_count;
+ /* cell num of parameters */
+ uint16 param_cell_num;
+ /* cell num of return type */
+ uint16 ret_cell_num;
+ /* cell num of local variables, 0 for import function */
+ uint16 local_cell_num;
+#if WASM_ENABLE_FAST_INTERP != 0
+ /* cell num of consts */
+ uint16 const_cell_num;
+#endif
+ uint16 *local_offsets;
+ /* parameter types */
+ uint8 *param_types;
+ /* local types, NULL for import function */
+ uint8 *local_types;
+ union {
+ WASMFunctionImport *func_import;
+ WASMFunction *func;
+ } u;
+#if WASM_ENABLE_MULTI_MODULE != 0
+ WASMModuleInstance *import_module_inst;
+ WASMFunctionInstance *import_func_inst;
+#endif
+#if WASM_ENABLE_PERF_PROFILING != 0
+ /* total execution time */
+ uint64 total_exec_time;
+ /* total execution count */
+ uint32 total_exec_cnt;
+#endif
+};
+
+typedef struct WASMExportFuncInstance {
+ char *name;
+ WASMFunctionInstance *function;
+} WASMExportFuncInstance;
+
+typedef struct WASMExportGlobInstance {
+ char *name;
+ WASMGlobalInstance *global;
+} WASMExportGlobInstance;
+
+typedef struct WASMExportTabInstance {
+ char *name;
+ WASMTableInstance *table;
+} WASMExportTabInstance;
+
+typedef struct WASMExportMemInstance {
+ char *name;
+ WASMMemoryInstance *memory;
+} WASMExportMemInstance;
+
+/* wasm-c-api import function info */
+typedef struct CApiFuncImport {
+ /* host func pointer after linked */
+ void *func_ptr_linked;
+ /* whether the host func has env argument */
+ bool with_env_arg;
+ /* the env argument of the host func */
+ void *env_arg;
+} CApiFuncImport;
+
+/* Extra info of WASM module instance for interpreter/jit mode */
+typedef struct WASMModuleInstanceExtra {
+ WASMGlobalInstance *globals;
+ WASMFunctionInstance *functions;
+
+ uint32 global_count;
+ uint32 function_count;
+
+ WASMFunctionInstance *start_function;
+ WASMFunctionInstance *malloc_function;
+ WASMFunctionInstance *free_function;
+ WASMFunctionInstance *retain_function;
+
+ CApiFuncImport *c_api_func_imports;
+ RunningMode running_mode;
+
+#if WASM_ENABLE_MULTI_MODULE != 0
+ bh_list sub_module_inst_list_head;
+ bh_list *sub_module_inst_list;
+ /* linked table instances of import table instances */
+ WASMTableInstance **table_insts_linked;
+#endif
+
+#if WASM_ENABLE_MEMORY_PROFILING != 0
+ uint32 max_aux_stack_used;
+#endif
+
+#if WASM_ENABLE_DEBUG_INTERP != 0 \
+ || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
+ && WASM_ENABLE_LAZY_JIT != 0)
+ WASMModuleInstance *next;
+#endif
+
+#if WASM_ENABLE_WASI_NN != 0
+ WASINNContext *wasi_nn_ctx;
+#endif
+} WASMModuleInstanceExtra;
+
+struct AOTFuncPerfProfInfo;
+
+struct WASMModuleInstance {
+ /* Module instance type, for module instance loaded from
+ WASM bytecode binary, this field is Wasm_Module_Bytecode;
+ for module instance loaded from AOT file, this field is
+ Wasm_Module_AoT, and this structure should be treated as
+ AOTModuleInstance structure. */
+ uint32 module_type;
+
+ uint32 memory_count;
+ DefPointer(WASMMemoryInstance **, memories);
+
+ /* global and table info */
+ uint32 global_data_size;
+ uint32 table_count;
+ DefPointer(uint8 *, global_data);
+ /* For AOTModuleInstance, it denotes `AOTTableInstance *` */
+ DefPointer(WASMTableInstance **, tables);
+
+ /* import func ptrs + llvm jit func ptrs */
+ DefPointer(void **, func_ptrs);
+
+ /* function type indexes */
+ DefPointer(uint32 *, func_type_indexes);
+
+ uint32 export_func_count;
+ uint32 export_global_count;
+ uint32 export_memory_count;
+ uint32 export_table_count;
+ /* For AOTModuleInstance, it denotes `AOTFunctionInstance *` */
+ DefPointer(WASMExportFuncInstance *, export_functions);
+ DefPointer(WASMExportGlobInstance *, export_globals);
+ DefPointer(WASMExportMemInstance *, export_memories);
+ DefPointer(WASMExportTabInstance *, export_tables);
+
+ /* The exception buffer of wasm interpreter for current thread. */
+ char cur_exception[EXCEPTION_BUF_LEN];
+
+ /* The WASM module or AOT module, for AOTModuleInstance,
+ it denotes `AOTModule *` */
+ DefPointer(WASMModule *, module);
+
+#if WASM_ENABLE_LIBC_WASI
+ /* WASI context */
+ DefPointer(WASIContext *, wasi_ctx);
+#else
+ DefPointer(void *, wasi_ctx);
+#endif
+ DefPointer(WASMExecEnv *, exec_env_singleton);
+ /* Array of function pointers to import functions,
+ not available in AOTModuleInstance */
+ DefPointer(void **, import_func_ptrs);
+ /* Array of function pointers to fast jit functions,
+ not available in AOTModuleInstance:
+ Only when the multi-tier JIT macros are all enabled and the running
+ mode of current module instance is set to Mode_Fast_JIT, runtime
+ will allocate new memory for it, otherwise it always points to the
+ module->fast_jit_func_ptrs */
+ DefPointer(void **, fast_jit_func_ptrs);
+ /* The custom data that can be set/get by wasm_{get|set}_custom_data */
+ DefPointer(void *, custom_data);
+ /* Stack frames, used in call stack dump and perf profiling */
+ DefPointer(Vector *, frames);
+ /* Function performance profiling info list, only available
+ in AOTModuleInstance */
+ DefPointer(struct AOTFuncPerfProfInfo *, func_perf_profilings);
+ /* WASM/AOT module extra info, for AOTModuleInstance,
+ it denotes `AOTModuleInstanceExtra *` */
+ DefPointer(WASMModuleInstanceExtra *, e);
+
+ /* Default WASM operand stack size */
+ uint32 default_wasm_stack_size;
+ uint32 reserved[3];
+
+ /*
+ * +------------------------------+ <-- memories
+ * | WASMMemoryInstance[mem_count], mem_count is always 1 for LLVM JIT/AOT
+ * +------------------------------+ <-- global_data
+ * | global data
+ * +------------------------------+ <-- tables
+ * | WASMTableInstance[table_count]
+ * +------------------------------+ <-- e
+ * | WASMModuleInstanceExtra
+ * +------------------------------+
+ */
+ union {
+ uint64 _make_it_8_byte_aligned_;
+ WASMMemoryInstance memory_instances[1];
+ uint8 bytes[1];
+ } global_table_data;
+};
+
+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.
+ *
+ * @param func the WASM function instance
+ *
+ * @return the code block of the function
+ */
+static inline uint8 *
+wasm_get_func_code(WASMFunctionInstance *func)
+{
+#if WASM_ENABLE_FAST_INTERP == 0
+ return func->is_import_func ? NULL : func->u.func->code;
+#else
+ return func->is_import_func ? NULL : func->u.func->code_compiled;
+#endif
+}
+
+/**
+ * Return the code block end of a function.
+ *
+ * @param func the WASM function instance
+ *
+ * @return the code block end of the function
+ */
+static inline uint8 *
+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;
+#else
+ return func->is_import_func
+ ? NULL
+ : func->u.func->code_compiled + func->u.func->code_compiled_size;
+#endif
+}
+
+WASMModule *
+wasm_load(uint8 *buf, uint32 size, char *error_buf, uint32 error_buf_size);
+
+WASMModule *
+wasm_load_from_sections(WASMSection *section_list, char *error_buf,
+ uint32 error_buf_size);
+
+void
+wasm_unload(WASMModule *module);
+
+WASMModuleInstance *
+wasm_instantiate(WASMModule *module, bool is_sub_inst,
+ WASMExecEnv *exec_env_main, uint32 stack_size,
+ uint32 heap_size, char *error_buf, uint32 error_buf_size);
+
+void
+wasm_dump_perf_profiling(const WASMModuleInstance *module_inst);
+
+void
+wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst);
+
+bool
+wasm_set_running_mode(WASMModuleInstance *module_inst,
+ RunningMode running_mode);
+
+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,
+ unsigned argc, uint32 argv[]);
+
+void
+wasm_set_exception(WASMModuleInstance *module, const char *exception);
+
+void
+wasm_set_exception_with_id(WASMModuleInstance *module_inst, uint32 id);
+
+const char *
+wasm_get_exception(WASMModuleInstance *module);
+
+/**
+ * @brief Copy exception in buffer passed as parameter. Thread-safe version of
+ * `wasm_get_exception()`
+ * @note Buffer size must be no smaller than EXCEPTION_BUF_LEN
+ * @return true if exception found
+ */
+bool
+wasm_copy_exception(WASMModuleInstance *module_inst, char *exception_buf);
+
+uint32
+wasm_module_malloc_internal(WASMModuleInstance *module_inst,
+ WASMExecEnv *exec_env, uint32 size,
+ void **p_native_addr);
+
+uint32
+wasm_module_realloc_internal(WASMModuleInstance *module_inst,
+ WASMExecEnv *exec_env, uint32 ptr, uint32 size,
+ void **p_native_addr);
+
+void
+wasm_module_free_internal(WASMModuleInstance *module_inst,
+ WASMExecEnv *exec_env, uint32 ptr);
+
+uint32
+wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size,
+ void **p_native_addr);
+
+uint32
+wasm_module_realloc(WASMModuleInstance *module_inst, uint32 ptr, uint32 size,
+ void **p_native_addr);
+
+void
+wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr);
+
+uint32
+wasm_module_dup_data(WASMModuleInstance *module_inst, const char *src,
+ uint32 size);
+
+/**
+ * Check whether the app address and the buf is inside the linear memory,
+ * and convert the app address into native address
+ */
+bool
+wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
+ uint32 app_buf_addr, uint32 app_buf_size,
+ void **p_native_addr);
+
+WASMMemoryInstance *
+wasm_get_default_memory(WASMModuleInstance *module_inst);
+
+bool
+wasm_enlarge_memory(WASMModuleInstance *module_inst, uint32 inc_page_count);
+
+bool
+wasm_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx,
+ uint32 argc, uint32 argv[]);
+
+#if WASM_ENABLE_THREAD_MGR != 0
+bool
+wasm_set_aux_stack(WASMExecEnv *exec_env, uint32 start_offset, uint32 size);
+
+bool
+wasm_get_aux_stack(WASMExecEnv *exec_env, uint32 *start_offset, uint32 *size);
+#endif
+
+void
+wasm_get_module_mem_consumption(const WASMModule *module,
+ WASMModuleMemConsumption *mem_conspn);
+
+void
+wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module,
+ WASMModuleInstMemConsumption *mem_conspn);
+
+#if WASM_ENABLE_REF_TYPES != 0
+static inline bool
+wasm_elem_is_active(uint32 mode)
+{
+ return (mode & 0x1) == 0x0;
+}
+
+static inline bool
+wasm_elem_is_passive(uint32 mode)
+{
+ return (mode & 0x1) == 0x1;
+}
+
+static inline bool
+wasm_elem_is_declarative(uint32 mode)
+{
+ return (mode & 0x3) == 0x3;
+}
+
+bool
+wasm_enlarge_table(WASMModuleInstance *module_inst, uint32 table_idx,
+ uint32 inc_entries, uint32 init_val);
+#endif /* WASM_ENABLE_REF_TYPES != 0 */
+
+static inline WASMTableInstance *
+wasm_get_table_inst(const WASMModuleInstance *module_inst, uint32 tbl_idx)
+{
+ /* careful, it might be a table in another module */
+ WASMTableInstance *tbl_inst = module_inst->tables[tbl_idx];
+#if WASM_ENABLE_MULTI_MODULE != 0
+ if (tbl_idx < module_inst->module->import_table_count
+ && module_inst->e->table_insts_linked[tbl_idx]) {
+ tbl_inst = module_inst->e->table_insts_linked[tbl_idx];
+ }
+#endif
+ bh_assert(tbl_inst);
+ return tbl_inst;
+}
+
+#if WASM_ENABLE_DUMP_CALL_STACK != 0
+bool
+wasm_interp_create_call_stack(struct WASMExecEnv *exec_env);
+
+/**
+ * @brief Dump wasm call stack or get the size
+ *
+ * @param exec_env the execution environment
+ * @param print whether to print to stdout or not
+ * @param buf buffer to store the dumped content
+ * @param len length of the buffer
+ *
+ * @return when print is true, return the bytes printed out to stdout; when
+ * print is false and buf is NULL, return the size required to store the
+ * callstack content; when print is false and buf is not NULL, return the size
+ * dumped to the buffer, 0 means error and data in buf may be invalid
+ */
+uint32
+wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env, bool print, char *buf,
+ uint32 len);
+#endif
+
+const uint8 *
+wasm_loader_get_custom_section(WASMModule *module, const char *name,
+ uint32 *len);
+
+#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \
+ || WASM_ENABLE_WAMR_COMPILER != 0
+void
+jit_set_exception_with_id(WASMModuleInstance *module_inst, uint32 id);
+
+/**
+ * Check whether the app address and the buf is inside the linear memory,
+ * and convert the app address into native address
+ */
+bool
+jit_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
+ uint32 app_buf_addr, uint32 app_buf_size,
+ void **p_native_addr);
+#endif /* end of WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \
+ || WASM_ENABLE_WAMR_COMPILER != 0 */
+
+#if WASM_ENABLE_FAST_JIT != 0
+bool
+fast_jit_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx,
+ uint32 type_idx, uint32 argc, uint32 *argv);
+
+bool
+fast_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx,
+ struct WASMInterpFrame *prev_frame);
+#endif
+
+#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
+bool
+llvm_jit_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx,
+ uint32 argc, uint32 *argv);
+
+bool
+llvm_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
+ uint32 *argv);
+
+#if WASM_ENABLE_BULK_MEMORY != 0
+bool
+llvm_jit_memory_init(WASMModuleInstance *module_inst, uint32 seg_index,
+ uint32 offset, uint32 len, uint32 dst);
+
+bool
+llvm_jit_data_drop(WASMModuleInstance *module_inst, uint32 seg_index);
+#endif
+
+#if WASM_ENABLE_REF_TYPES != 0
+void
+llvm_jit_drop_table_seg(WASMModuleInstance *module_inst, uint32 tbl_seg_idx);
+
+void
+llvm_jit_table_init(WASMModuleInstance *module_inst, uint32 tbl_idx,
+ uint32 tbl_seg_idx, uint32 length, uint32 src_offset,
+ uint32 dst_offset);
+
+void
+llvm_jit_table_copy(WASMModuleInstance *module_inst, uint32 src_tbl_idx,
+ uint32 dst_tbl_idx, uint32 length, uint32 src_offset,
+ uint32 dst_offset);
+
+void
+llvm_jit_table_fill(WASMModuleInstance *module_inst, uint32 tbl_idx,
+ uint32 length, uint32 val, uint32 data_offset);
+
+uint32
+llvm_jit_table_grow(WASMModuleInstance *module_inst, uint32 tbl_idx,
+ uint32 inc_entries, uint32 init_val);
+#endif
+
+#if WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_PERF_PROFILING != 0
+bool
+llvm_jit_alloc_frame(WASMExecEnv *exec_env, uint32 func_index);
+
+void
+llvm_jit_free_frame(WASMExecEnv *exec_env);
+#endif
+#endif /* end of WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 */
+
+#if WASM_ENABLE_LIBC_WASI != 0 && WASM_ENABLE_MULTI_MODULE != 0
+void
+wasm_propagate_wasi_args(WASMModule *module);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end of _WASM_RUNTIME_H */