Refine code, fix some issues and add codegen framework ()

Add more return value checks and set lass error
Implement exception throw and add operand stack overflow check
Remove lower_fe pass
Use cc->cmp_reg for cmp/branch IRs
Fix jit dump issues
Fix some compile warnings
Add part of codegen framework
Remove some unused JIT IRs
This commit is contained in:
Wenyong Huang 2022-03-14 15:32:32 +08:00 committed by GitHub
parent 24aae4f0d6
commit eb518c0423
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 3801 additions and 322 deletions

View File

@ -94,6 +94,14 @@
#define WASM_ENABLE_LAZY_JIT 0 #define WASM_ENABLE_LAZY_JIT 0
#endif #endif
#ifndef WASM_ENABLE_FAST_JIT
#define WASM_ENABLE_FAST_JIT 0
#endif
#ifndef WASM_ENABLE_FAST_JIT_DUMP
#define WASM_ENABLE_FAST_JIT_DUMP 0
#endif
#ifndef WASM_ENABLE_WAMR_COMPILER #ifndef WASM_ENABLE_WAMR_COMPILER
#define WASM_ENABLE_WAMR_COMPILER 0 #define WASM_ENABLE_WAMR_COMPILER 0
#endif #endif

View File

@ -1,120 +0,0 @@
/*
* Copyright (C) 2021 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "jit_codegen.h"
bool
jit_codegen_init()
{
return true;
}
void
jit_codegen_destroy()
{}
/* clang-format off */
static const uint8 hreg_info_I4[3][7] = {
/* ebp, eax, ebx, ecx, edx, edi, esi */
{ 1, 0, 0, 0, 0, 0, 1 }, /* fixed, esi is freely used */
{ 0, 1, 0, 1, 1, 0, 0 }, /* caller_saved_native */
{ 0, 1, 0, 1, 1, 1, 0 } /* caller_saved_jitted */
};
static const uint8 hreg_info_I8[3][16] = {
/* rbp, rax, rbx, rcx, rdx, rdi, rsi, rsp,
r8, r9, r10, r11, r12, r13, r14, r15 */
{ 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 1 }, /* fixed, rsi is freely used */
{ 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 0, 0, 0, 0 }, /* caller_saved_native */
{ 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 0, 0, 0, 0 }, /* caller_saved_jitted */
};
static uint8 hreg_info_F4[3][16] = {
{ 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1 }, /* fixed, rsi is freely used */
{ 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 }, /* caller_saved_native */
{ 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 }, /* caller_saved_jitted */
};
static uint8 hreg_info_F8[3][16] = {
{ 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0 }, /* fixed, rsi is freely used */
{ 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 }, /* caller_saved_native */
{ 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1 }, /* caller_saved_jitted */
};
static const JitHardRegInfo hreg_info = {
{
{ 0, NULL, NULL, NULL }, /* VOID */
{ sizeof(hreg_info_I4[0]), /* I4 */
hreg_info_I4[0],
hreg_info_I4[1],
hreg_info_I4[2] },
{ sizeof(hreg_info_I8[0]), /* I8 */
hreg_info_I8[0],
hreg_info_I8[1],
hreg_info_I8[2] },
{ sizeof(hreg_info_F4[0]), /* F4 */
hreg_info_F4[0],
hreg_info_F4[1],
hreg_info_F4[2] },
{ sizeof(hreg_info_F8[0]), /* F8 */
hreg_info_F8[0],
hreg_info_F8[1],
hreg_info_F8[2] },
{ 0, NULL, NULL, NULL }, /* V8 */
{ 0, NULL, NULL, NULL }, /* V16 */
{ 0, NULL, NULL, NULL } /* V32 */
},
/* frame pointer hreg index: rbp */
0,
/* exec_env hreg index: r15 */
15,
/* cmp hreg index: esi */
6
};
/* clang-format on */
const JitHardRegInfo *
jit_codegen_get_hreg_info()
{
return &hreg_info;
}
bool
jit_codegen_gen_native(JitCompContext *cc)
{
jit_set_last_error(cc, "jit_codegen_gen_native failed");
return false;
}
bool
jit_codegen_lower(JitCompContext *cc)
{
return true;
}
void
jit_codegen_dump_native(void *begin_addr, void *end_addr)
{}
bool
jit_codegen_call_func_jitted(void *exec_env, void *frame, void *func_inst,
void *target)
{
return false;
}

File diff suppressed because it is too large Load Diff

View File

@ -27,13 +27,14 @@
} \ } \
} while (0) } while (0)
#define BUILD_COND_BR(value_if, block_then, block_else) \ #define BUILD_COND_BR(value_if, block_then, block_else) \
do { \ do { \
if (!GEN_INSN(BNE, value_if, jit_basic_block_label(block_then), \ if (!GEN_INSN(CMP, cc->cmp_reg, value_if, NEW_CONST(cc, 0)) \
jit_basic_block_label(block_else))) { \ || !GEN_INSN(BNE, cc->cmp_reg, jit_basic_block_label(block_then), \
jit_set_last_error(cc, "generate bne insn failed"); \ jit_basic_block_label(block_else))) { \
goto fail; \ jit_set_last_error(cc, "generate bne insn failed"); \
} \ goto fail; \
} \
} while (0) } while (0)
#define SET_BUILDER_POS(basic_block) \ #define SET_BUILDER_POS(basic_block) \
@ -73,7 +74,7 @@ load_block_params(JitCompContext *cc, JitBlock *block)
{ {
JitFrame *jit_frame = cc->jit_frame; JitFrame *jit_frame = cc->jit_frame;
uint32 offset, i; uint32 offset, i;
JitReg value; JitReg value = 0;
/* Clear jit frame's locals and stacks */ /* Clear jit frame's locals and stacks */
clear_values(jit_frame); clear_values(jit_frame);
@ -181,8 +182,9 @@ push_jit_block_to_stack_and_pass_params(JitCompContext *cc, JitBlock *block,
BUILD_BR(basic_block); BUILD_BR(basic_block);
} }
else { /* IF block with condition br insn */ else { /* IF block with condition br insn */
if (!(insn = GEN_INSN(BNE, cond, jit_basic_block_label(basic_block), if (!GEN_INSN(CMP, cc->cmp_reg, cond, NEW_CONST(I32, 0))
0))) { || !(insn = GEN_INSN(BNE, cc->cmp_reg,
jit_basic_block_label(basic_block), 0))) {
jit_set_last_error(cc, "generate cond br failed"); jit_set_last_error(cc, "generate cond br failed");
goto fail; goto fail;
} }
@ -318,7 +320,7 @@ handle_func_return(JitCompContext *cc, JitBlock *block)
/* fp_reg = prev_frame */ /* fp_reg = prev_frame */
GEN_INSN(MOV, cc->fp_reg, prev_frame); GEN_INSN(MOV, cc->fp_reg, prev_frame);
/* return 0 */ /* return 0 */
GEN_INSN(RETURN, NEW_CONST(I32, 0)); GEN_INSN(RETURNBC, NEW_CONST(I32, 0));
} }
static bool static bool
@ -836,7 +838,9 @@ jit_compile_op_br_if(JitCompContext *cc, uint32 br_depth, uint8 **p_frame_ip)
clear_values(jit_frame); clear_values(jit_frame);
CREATE_BASIC_BLOCK(if_basic_block); CREATE_BASIC_BLOCK(if_basic_block);
if (!GEN_INSN(BNE, cond, jit_basic_block_label(if_basic_block), 0)) { if (!GEN_INSN(CMP, cc->cmp_reg, cond, NEW_CONST(I32, 0))
|| !GEN_INSN(BNE, cc->cmp_reg, jit_basic_block_label(if_basic_block),
0)) {
jit_set_last_error(cc, "generate bne insn failed"); jit_set_last_error(cc, "generate bne insn failed");
goto fail; goto fail;
} }

View File

@ -7,8 +7,72 @@
#include "../jit_frontend.h" #include "../jit_frontend.h"
bool bool
jit_emit_exception(JitCompContext *cc, int32 exception_id, bool is_cond_br, jit_emit_exception(JitCompContext *cc, int32 exception_id, uint8 jit_opcode,
JitReg cond_br_if, JitBasicBlock *cond_br_else_block) JitReg cond_br_if, JitBasicBlock *cond_br_else_block)
{ {
return false; JitInsn *insn = NULL;
JitIncomingInsn *incoming_insn;
JitReg else_label;
bh_assert(exception_id < EXCE_NUM);
if (jit_opcode >= JIT_OP_BNE && jit_opcode <= JIT_OP_BLEU) {
bh_assert(cond_br_if == cc->cmp_reg);
else_label =
cond_br_else_block ? jit_basic_block_label(cond_br_else_block) : 0;
switch (jit_opcode) {
case JIT_OP_BEQ:
insn = GEN_INSN(BEQ, cond_br_if, 0, else_label);
break;
case JIT_OP_BNE:
insn = GEN_INSN(BNE, cond_br_if, 0, else_label);
break;
case JIT_OP_BGTS:
insn = GEN_INSN(BGTS, cond_br_if, 0, else_label);
break;
case JIT_OP_BGES:
insn = GEN_INSN(BGES, cond_br_if, 0, else_label);
break;
case JIT_OP_BLTS:
insn = GEN_INSN(BLTS, cond_br_if, 0, else_label);
break;
case JIT_OP_BLES:
insn = GEN_INSN(BLES, cond_br_if, 0, else_label);
break;
case JIT_OP_BGTU:
insn = GEN_INSN(BGTU, cond_br_if, 0, else_label);
break;
case JIT_OP_BGEU:
insn = GEN_INSN(BGEU, cond_br_if, 0, else_label);
break;
case JIT_OP_BLTU:
insn = GEN_INSN(BLTU, cond_br_if, 0, else_label);
break;
case JIT_OP_BLEU:
insn = GEN_INSN(BLEU, cond_br_if, 0, else_label);
break;
}
if (!insn) {
jit_set_last_error(cc, "generate cond br insn failed");
return false;
}
}
else if (jit_opcode == JIT_OP_JMP) {
insn = GEN_INSN(JMP, 0);
if (!insn) {
jit_set_last_error(cc, "generate jmp insn failed");
return false;
}
}
incoming_insn = jit_calloc(sizeof(JitIncomingInsn));
if (!incoming_insn) {
jit_set_last_error(cc, "allocate memory failed");
return false;
}
incoming_insn->insn = insn;
incoming_insn->next = cc->incoming_insns_for_exec_bbs[exception_id];
cc->incoming_insns_for_exec_bbs[exception_id] = incoming_insn;
return true;
} }

View File

@ -13,7 +13,7 @@ extern "C" {
#endif #endif
bool bool
jit_emit_exception(JitCompContext *cc, int32 exception_id, bool is_cond_br, jit_emit_exception(JitCompContext *cc, int32 exception_id, uint8 jit_opcode,
JitReg cond_br_if, JitBasicBlock *cond_br_else_block); JitReg cond_br_if, JitBasicBlock *cond_br_else_block);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -31,7 +31,7 @@ jit_compile_op_get_local(JitCompContext *cc, uint32 local_idx)
uint16 *local_offsets = wasm_func->local_offsets; uint16 *local_offsets = wasm_func->local_offsets;
uint16 local_offset; uint16 local_offset;
uint8 local_type; uint8 local_type;
JitReg value; JitReg value = 0;
CHECK_LOCAL(local_idx); CHECK_LOCAL(local_idx);
@ -119,7 +119,7 @@ jit_compile_op_tee_local(JitCompContext *cc, uint32 local_idx)
uint16 *local_offsets = wasm_func->local_offsets; uint16 *local_offsets = wasm_func->local_offsets;
uint16 local_offset; uint16 local_offset;
uint8 local_type; uint8 local_type;
JitReg value; JitReg value = 0;
CHECK_LOCAL(local_idx); CHECK_LOCAL(local_idx);

View File

@ -3,16 +3,84 @@
set (IWASM_FAST_JIT_DIR ${CMAKE_CURRENT_LIST_DIR}) set (IWASM_FAST_JIT_DIR ${CMAKE_CURRENT_LIST_DIR})
add_definitions (-DWASM_ENABLE_FAST_JIT=1) add_definitions(-DWASM_ENABLE_FAST_JIT=1)
if (WAMR_BUILD_FAST_JIT_DUMP EQUAL 1)
add_definitions(-DWASM_ENABLE_FAST_JIT_DUMP=1)
endif ()
include_directories (${IWASM_FAST_JIT_DIR}) include_directories (${IWASM_FAST_JIT_DIR})
if (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64")
include(FetchContent)
FetchContent_Declare(
asmjit
GIT_REPOSITORY https://github.com/asmjit/asmjit.git
)
FetchContent_GetProperties(asmjit)
if (NOT asmjit_POPULATED)
message ("-- Fetching asmjit ..")
FetchContent_Populate(asmjit)
add_definitions(-DASMJIT_STATIC)
add_definitions(-DASMJIT_NO_DEPRECATED)
add_definitions(-DASMJIT_NO_BUILDER)
add_definitions(-DASMJIT_NO_COMPILER)
add_definitions(-DASMJIT_NO_JIT)
add_definitions(-DASMJIT_NO_LOGGING)
add_definitions(-DASMJIT_NO_TEXT)
add_definitions(-DASMJIT_NO_VALIDATION)
add_definitions(-DASMJIT_NO_INTROSPECTION)
add_definitions(-DASMJIT_NO_INTRINSICS)
add_definitions(-DASMJIT_NO_AARCH64)
add_definitions(-DASMJIT_NO_AARCH32)
include_directories("${asmjit_SOURCE_DIR}/src")
add_subdirectory(${asmjit_SOURCE_DIR} ${asmjit_BINARY_DIR} EXCLUDE_FROM_ALL)
file (GLOB_RECURSE cpp_source_asmjit
${asmjit_SOURCE_DIR}/src/asmjit/core/*.cpp
${asmjit_SOURCE_DIR}/src/asmjit/x86/*.cpp
)
endif ()
if (WAMR_BUILD_FAST_JIT_DUMP EQUAL 1)
FetchContent_Declare(
zycore
GIT_REPOSITORY https://github.com/zyantific/zycore-c.git
)
FetchContent_GetProperties(zycore)
if (NOT zycore_POPULATED)
message ("-- Fetching zycore ..")
FetchContent_Populate(zycore)
option(ZYDIS_BUILD_TOOLS "" OFF)
option(ZYDIS_BUILD_EXAMPLES "" OFF)
include_directories("${zycore_SOURCE_DIR}/include")
include_directories("${zycore_BINARY_DIR}")
add_subdirectory(${zycore_SOURCE_DIR} ${zycore_BINARY_DIR} EXCLUDE_FROM_ALL)
file (GLOB_RECURSE c_source_zycore ${zycore_SOURCE_DIR}/src/*.c)
endif ()
FetchContent_Declare(
zydis
GIT_REPOSITORY https://github.com/zyantific/zydis.git
)
FetchContent_GetProperties(zydis)
if (NOT zydis_POPULATED)
message ("-- Fetching zydis ..")
FetchContent_Populate(zydis)
option(ZYDIS_BUILD_TOOLS "" OFF)
option(ZYDIS_BUILD_EXAMPLES "" OFF)
include_directories("${zydis_BINARY_DIR}")
include_directories("${zydis_SOURCE_DIR}/include")
include_directories("${zydis_SOURCE_DIR}/src")
add_subdirectory(${zydis_SOURCE_DIR} ${zydis_BINARY_DIR} EXCLUDE_FROM_ALL)
file (GLOB_RECURSE c_source_zydis ${zydis_SOURCE_DIR}/src/*.c)
endif ()
endif ()
endif ()
file (GLOB c_source_jit ${IWASM_FAST_JIT_DIR}/*.c ${IWASM_FAST_JIT_DIR}/fe/*.c) file (GLOB c_source_jit ${IWASM_FAST_JIT_DIR}/*.c ${IWASM_FAST_JIT_DIR}/fe/*.c)
if (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") if (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64")
file (GLOB_RECURSE c_source_jit_cg ${IWASM_FAST_JIT_DIR}/cg/x86-64/*.c) file (GLOB_RECURSE cpp_source_jit_cg ${IWASM_FAST_JIT_DIR}/cg/x86-64/*.cpp)
else () else ()
message (FATAL_ERROR "Fast JIT codegen for target ${WAMR_BUILD_TARGET} isn't implemented") message (FATAL_ERROR "Fast JIT codegen for target ${WAMR_BUILD_TARGET} isn't implemented")
endif () endif ()
set (IWASM_FAST_JIT_SOURCE ${c_source_jit} ${c_source_jit_cg}) set (IWASM_FAST_JIT_SOURCE ${c_source_jit} ${cpp_source_jit_cg}
${cpp_source_asmjit} ${c_source_zycore} ${c_source_zydis})

View File

@ -41,7 +41,7 @@ jit_code_cache_destroy()
} }
void * void *
jit_code_cache_malloc(uint32 size) jit_code_cache_alloc(uint32 size)
{ {
return mem_allocator_malloc(code_cache_pool_allocator, size); return mem_allocator_malloc(code_cache_pool_allocator, size);
} }

View File

@ -7,7 +7,7 @@
#define _JIT_CODEGEN_H_ #define _JIT_CODEGEN_H_
#include "bh_platform.h" #include "bh_platform.h"
#include "jit_ir.h" #include "jit_compiler.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -64,14 +64,8 @@ jit_codegen_lower(JitCompContext *cc);
void void
jit_codegen_dump_native(void *begin_addr, void *end_addr); jit_codegen_dump_native(void *begin_addr, void *end_addr);
/** int
* Call jitted code jit_codegen_interp_jitted_glue(void *self, JitInterpSwitchInfo *info, void *pc);
*
* @param exec_env the current exec_env
*/
bool
jit_codegen_call_func_jitted(void *exec_env, void *frame, void *func_inst,
void *target);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -9,13 +9,6 @@
#include "jit_codecache.h" #include "jit_codecache.h"
#include "../interpreter/wasm.h" #include "../interpreter/wasm.h"
typedef struct JitGlobals {
/* Compiler pass sequence. The last element must be 0. */
const uint8 *passes;
/* Code cache size. */
uint32 code_cache_size;
} JitGlobals;
typedef struct JitCompilerPass { typedef struct JitCompilerPass {
/* Name of the pass. */ /* Name of the pass. */
const char *name; const char *name;
@ -30,7 +23,6 @@ static JitCompilerPass compiler_passes[] = {
REG_PASS(dump), REG_PASS(dump),
REG_PASS(update_cfg), REG_PASS(update_cfg),
REG_PASS(frontend), REG_PASS(frontend),
REG_PASS(lower_fe),
REG_PASS(lower_cg), REG_PASS(lower_cg),
REG_PASS(regalloc), REG_PASS(regalloc),
REG_PASS(codegen), REG_PASS(codegen),
@ -41,20 +33,18 @@ static JitCompilerPass compiler_passes[] = {
/* Number of compiler passes. */ /* Number of compiler passes. */
#define COMPILER_PASS_NUM (sizeof(compiler_passes) / sizeof(compiler_passes[0])) #define COMPILER_PASS_NUM (sizeof(compiler_passes) / sizeof(compiler_passes[0]))
#define WASM_ENABLE_FAST_JIT_DUMP 1
#if WASM_ENABLE_FAST_JIT_DUMP == 0 #if WASM_ENABLE_FAST_JIT_DUMP == 0
static const uint8 compiler_passes_without_dump[] = { static const uint8 compiler_passes_without_dump[] = {
3, 4, 5, 6, 7, 8, 0 3, 4, 5, 6, 7, 0
}; };
#else #else
static const uint8 compiler_passes_with_dump[] = { static const uint8 compiler_passes_with_dump[] = {
3, 2, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 0 3, 2, 1, 4, 1, 5, 1, 6, 1, 7, 0
}; };
#endif #endif
/* The exported global data of JIT compiler. */ /* The exported global data of JIT compiler. */
JitGlobals jit_globals = { static JitGlobals jit_globals = {
#if WASM_ENABLE_FAST_JIT_DUMP == 0 #if WASM_ENABLE_FAST_JIT_DUMP == 0
.passes = compiler_passes_without_dump, .passes = compiler_passes_without_dump,
#else #else
@ -109,6 +99,12 @@ jit_compiler_destroy()
jit_code_cache_destroy(); jit_code_cache_destroy();
} }
const JitGlobals *
jit_compiler_get_jit_globals()
{
return &jit_globals;
}
const char * const char *
jit_compiler_get_pass_name(unsigned i) jit_compiler_get_pass_name(unsigned i)
{ {
@ -119,6 +115,7 @@ bool
jit_compiler_compile(WASMModule *module, uint32 func_idx) jit_compiler_compile(WASMModule *module, uint32 func_idx)
{ {
JitCompContext *cc; JitCompContext *cc;
char *last_error;
bool ret = true; bool ret = true;
/* Initialize compilation context. */ /* Initialize compilation context. */
@ -138,8 +135,10 @@ jit_compiler_compile(WASMModule *module, uint32 func_idx)
|| (!module->possible_memory_grow); || (!module->possible_memory_grow);
/* Apply compiler passes. */ /* Apply compiler passes. */
if (!apply_compiler_passes(cc)) { if (!apply_compiler_passes(cc) || jit_get_last_error(cc)) {
os_printf("fast jit compilation failed: %s\n", jit_get_last_error(cc)); last_error = jit_get_last_error(cc);
os_printf("fast jit compilation failed: %s\n",
last_error ? last_error : "unknown error");
ret = false; ret = false;
} }
@ -153,6 +152,7 @@ bool
jit_compiler_compile_all(WASMModule *module) jit_compiler_compile_all(WASMModule *module)
{ {
JitCompContext *cc; JitCompContext *cc;
char *last_error;
bool ret = false; bool ret = false;
uint32 i; uint32 i;
@ -174,9 +174,10 @@ jit_compiler_compile_all(WASMModule *module)
|| (!module->possible_memory_grow); || (!module->possible_memory_grow);
/* Apply compiler passes. */ /* Apply compiler passes. */
if (!apply_compiler_passes(cc)) { if (!apply_compiler_passes(cc) || jit_get_last_error(cc)) {
last_error = jit_get_last_error(cc);
os_printf("fast jit compilation failed: %s\n", os_printf("fast jit compilation failed: %s\n",
jit_get_last_error(cc)); last_error ? last_error : "unknown error");
ret = false; ret = false;
break; break;
} }
@ -188,9 +189,8 @@ jit_compiler_compile_all(WASMModule *module)
return ret; return ret;
} }
bool int
jit_interp_switch_to_jitted(void *exec_env, void *frame, jit_interp_switch_to_jitted(void *exec_env, JitInterpSwitchInfo *info, void *pc)
WASMFunctionInstance *func_inst, void *target)
{ {
return jit_codegen_call_func_jitted(exec_env, func_inst, frame, target); return jit_codegen_interp_jitted_glue(exec_env, info, pc);
} }

View File

@ -14,12 +14,31 @@
extern "C" { extern "C" {
#endif #endif
typedef struct JitGlobals {
/* Compiler pass sequence, the last element must be 0 */
const uint8 *passes;
/* Code cache size. */
uint32 code_cache_size;
} JitGlobals;
/**
* Information exchanged between JITed code and interpreter.
*/
typedef struct JitInterpSwitchInfo {
/* Points to the frame that is passed to JITed code and the frame
that is returned from JITed code. */
void *frame;
} JitInterpSwitchInfo;
bool bool
jit_compiler_init(); jit_compiler_init();
void void
jit_compiler_destroy(); jit_compiler_destroy();
const JitGlobals *
jit_compiler_get_jit_globals();
const char * const char *
jit_compiler_get_pass_name(unsigned i); jit_compiler_get_pass_name(unsigned i);
@ -29,9 +48,8 @@ jit_compiler_compile(WASMModule *module, uint32 func_idx);
bool bool
jit_compiler_compile_all(WASMModule *module); jit_compiler_compile_all(WASMModule *module);
bool int
jit_interp_switch_to_jitted(void *exec_env, void *frame, jit_interp_switch_to_jitted(void *self, JitInterpSwitchInfo *info, void *pc);
WASMFunctionInstance *func_inst, void *target);
/* /*
* Pass declarations: * Pass declarations:
@ -55,11 +73,13 @@ jit_pass_update_cfg(JitCompContext *cc);
bool bool
jit_pass_frontend(JitCompContext *cc); jit_pass_frontend(JitCompContext *cc);
#if 0
/** /**
* Convert MIR to LIR. * Convert MIR to LIR.
*/ */
bool bool
jit_pass_lower_fe(JitCompContext *cc); jit_pass_lower_fe(JitCompContext *cc);
#endif
/** /**
* Lower unsupported operations into supported ones. * Lower unsupported operations into supported ones.

View File

@ -89,6 +89,7 @@ jit_dump_insn_VReg(JitCompContext *cc, JitInsn *insn, unsigned opnd_num)
os_printf("\n"); os_printf("\n");
} }
#if 0
static void static void
jit_dump_insn_TableSwitch(JitCompContext *cc, JitInsn *insn, unsigned opnd_num) jit_dump_insn_TableSwitch(JitCompContext *cc, JitInsn *insn, unsigned opnd_num)
{ {
@ -107,6 +108,7 @@ jit_dump_insn_TableSwitch(JitCompContext *cc, JitInsn *insn, unsigned opnd_num)
os_printf("\n"); os_printf("\n");
} }
} }
#endif
static void static void
jit_dump_insn_LookupSwitch(JitCompContext *cc, JitInsn *insn, unsigned opnd_num) jit_dump_insn_LookupSwitch(JitCompContext *cc, JitInsn *insn, unsigned opnd_num)
@ -307,9 +309,14 @@ jit_dump_cc(JitCompContext *cc)
bool bool
jit_pass_dump(JitCompContext *cc) jit_pass_dump(JitCompContext *cc)
{ {
os_printf("JIT.COMPILER.DUMP: PASS_NO=%d PREV_PASS=%s\n\n", cc->cur_pass_no, const JitGlobals *jit_globals = jit_compiler_get_jit_globals();
(cc->cur_pass_no > 0 ? jit_compiler_get_pass_name(cc->cur_pass_no) const uint8 *passes = jit_globals->passes;
: "NULL")); uint8 pass_no = cc->cur_pass_no;
const char *pass_name =
pass_no > 0 ? jit_compiler_get_pass_name(passes[pass_no - 1]) : "NULL";
os_printf("JIT.COMPILER.DUMP: PASS_NO=%d PREV_PASS=%s\n\n", pass_no,
pass_name);
jit_dump_cc(cc); jit_dump_cc(cc);
os_printf("\n"); os_printf("\n");
return true; return true;

View File

@ -20,6 +20,28 @@
#include "../interpreter/wasm_opcode.h" #include "../interpreter/wasm_opcode.h"
#include "../common/wasm_exec_env.h" #include "../common/wasm_exec_env.h"
/* clang-format off */
static const char *jit_exception_msgs[] = {
"unreachable", /* EXCE_UNREACHABLE */
"allocate memory failed", /* EXCE_OUT_OF_MEMORY */
"out of bounds memory access", /* EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS */
"integer overflow", /* EXCE_INTEGER_OVERFLOW */
"integer divide by zero", /* EXCE_INTEGER_DIVIDE_BY_ZERO */
"invalid conversion to integer", /* EXCE_INVALID_CONVERSION_TO_INTEGER */
"indirect call type mismatch", /* EXCE_INVALID_FUNCTION_TYPE_INDEX */
"invalid function index", /* EXCE_INVALID_FUNCTION_INDEX */
"undefined element", /* EXCE_UNDEFINED_ELEMENT */
"uninitialized element", /* EXCE_UNINITIALIZED_ELEMENT */
"failed to call unlinked import function", /* EXCE_CALL_UNLINKED_IMPORT_FUNC */
"native stack overflow", /* EXCE_NATIVE_STACK_OVERFLOW */
"unaligned atomic", /* EXCE_UNALIGNED_ATOMIC */
"wasm auxiliary stack overflow", /* EXCE_AUX_STACK_OVERFLOW */
"wasm auxiliary stack underflow", /* EXCE_AUX_STACK_UNDERFLOW */
"out of bounds table access", /* EXCE_OUT_OF_BOUNDS_TABLE_ACCESS */
"wasm operand stack overflow", /* EXCE_OPERAND_STACK_OVERFLOW */
};
/* clang-format on */
JitReg JitReg
gen_load_i32(JitFrame *frame, unsigned n) gen_load_i32(JitFrame *frame, unsigned n)
{ {
@ -124,29 +146,41 @@ gen_commit_sp_ip(JitFrame *frame)
JitReg sp; JitReg sp;
if (frame->sp != frame->committed_sp) { if (frame->sp != frame->committed_sp) {
#if UINTPTR_MAX == UINT32_MAX #if UINTPTR_MAX == UINT64_MAX
GEN_INSN_NORM(I32, sp, ADD, 0, cc->fp_reg, sp = jit_cc_new_reg_I64(cc);
NEW_CONST(I32, offset_of_local(frame->sp - frame->lp))); GEN_INSN(ADD, sp, cc->fp_reg,
GEN_INSN(STI32, sp, cc->fp_reg, NEW_CONST(I32, offset_of_local(frame->sp - frame->lp)));
GEN_INSN(STI64, sp, cc->fp_reg,
NEW_CONST(I32, offsetof(WASMInterpFrame, sp))); NEW_CONST(I32, offsetof(WASMInterpFrame, sp)));
#else #else
GEN_INSN_NORM(I64, sp, ADD, 0, cc->fp_reg, sp = jit_cc_new_reg_I32(cc);
NEW_CONST(I32, offset_of_local(frame->sp - frame->lp))); GEN_INSN(ADD, sp, cc->fp_reg,
GEN_INSN(STI64, sp, cc->fp_reg, NEW_CONST(I32, offset_of_local(frame->sp - frame->lp)));
GEN_INSN(STI32, sp, cc->fp_reg,
NEW_CONST(I32, offsetof(WASMInterpFrame, sp))); NEW_CONST(I32, offsetof(WASMInterpFrame, sp)));
#endif #endif
frame->committed_sp = frame->sp; frame->committed_sp = frame->sp;
} }
#if 0 if (frame->ip != frame->committed_ip) {
if (frame->ip != frame->committed_ip) { #if UINTPTR_MAX == UINT64_MAX
GEN_INSN (STI32, GEN_INSN(STI64, NEW_CONST(I64, (uint64)(uintptr_t)frame->ip),
NEW_REL (BCIP, NONE, offset_of_addr (frame, frame->ip), frame->ip), cc->fp_reg, NEW_CONST(I32, offsetof(WASMInterpFrame, ip)));
cc->fp_reg, #else
NEW_CONST (I32, offsetof (WASMInterpFrame, ip))); GEN_INSN(STI32, NEW_CONST(I32, (uint32)(uintptr_t)frame->ip),
frame->committed_ip = frame->ip; cc->fp_reg, NEW_CONST(I32, offsetof(WASMInterpFrame, ip)));
}
#endif #endif
frame->committed_ip = frame->ip;
}
}
static void
jit_set_exception_with_id(WASMModuleInstance *module_inst, uint32 id)
{
if (id < EXCE_NUM)
wasm_set_exception(module_inst, jit_exception_msgs[id]);
else
wasm_set_exception(module_inst, "unknown exception");
} }
static bool static bool
@ -154,7 +188,9 @@ form_and_translate_func(JitCompContext *cc)
{ {
JitBasicBlock *func_entry_basic_block; JitBasicBlock *func_entry_basic_block;
JitReg func_entry_label; JitReg func_entry_label;
JitInsn *jmp_insn; JitInsn *insn;
JitIncomingInsn *incoming_insn, *incoming_insn_next;
uint32 i;
if (!(func_entry_basic_block = jit_frontend_translate_func(cc))) if (!(func_entry_basic_block = jit_frontend_translate_func(cc)))
return false; return false;
@ -165,11 +201,58 @@ form_and_translate_func(JitCompContext *cc)
func_entry_label = jit_basic_block_label(func_entry_basic_block); func_entry_label = jit_basic_block_label(func_entry_basic_block);
/* Create a JMP instruction jumping to the func entry. */ /* Create a JMP instruction jumping to the func entry. */
if (!(jmp_insn = jit_cc_new_insn(cc, JMP, func_entry_label))) if (!(insn = jit_cc_new_insn(cc, JMP, func_entry_label)))
return false; return false;
/* Insert the instruction into the cc entry block. */ /* Insert the instruction into the cc entry block. */
jit_basic_block_append_insn(jit_cc_entry_basic_block(cc), jmp_insn); jit_basic_block_append_insn(jit_cc_entry_basic_block(cc), insn);
/* Patch INSNs jumping to exception basic blocks. */
for (i = 0; i < EXCE_NUM; i++) {
incoming_insn = cc->incoming_insns_for_exec_bbs[i];
if (incoming_insn) {
if (!(cc->exce_basic_blocks[i] = jit_cc_new_basic_block(cc, 0))) {
jit_set_last_error(cc, "create basic block failed");
return false;
}
while (incoming_insn) {
incoming_insn_next = incoming_insn->next;
insn = incoming_insn->insn;
if (insn->opcode == JIT_OP_JMP) {
*(jit_insn_opnd(insn, 0)) =
jit_basic_block_label(cc->exce_basic_blocks[i]);
}
else if (insn->opcode >= JIT_OP_BNE
&& insn->opcode <= JIT_OP_BLEU) {
*(jit_insn_opnd(insn, 1)) =
jit_basic_block_label(cc->exce_basic_blocks[i]);
}
incoming_insn = incoming_insn_next;
}
cc->cur_basic_block = cc->exce_basic_blocks[i];
#if UINTPTR_MAX == UINT64_MAX
insn = GEN_INSN(
CALLNATIVE, 0,
NEW_CONST(I64, (uint64)(uintptr_t)jit_set_exception_with_id),
1);
#else
insn = GEN_INSN(
CALLNATIVE, 0,
NEW_CONST(I32, (uint32)(uintptr_t)jit_set_exception_with_id),
1);
#endif
if (insn) {
*(jit_insn_opndv(insn, 2)) = NEW_CONST(I32, i);
}
GEN_INSN(RETURNBC, NEW_CONST(I32, i));
*(jit_annl_begin_bcip(cc,
jit_basic_block_label(cc->cur_basic_block))) =
*(jit_annl_end_bcip(
cc, jit_basic_block_label(cc->cur_basic_block))) =
cc->cur_wasm_module->load_addr;
}
}
*(jit_annl_begin_bcip(cc, cc->entry_label)) = *(jit_annl_begin_bcip(cc, cc->entry_label)) =
*(jit_annl_end_bcip(cc, cc->entry_label)) = *(jit_annl_end_bcip(cc, cc->entry_label)) =
@ -199,11 +282,13 @@ jit_pass_frontend(JitCompContext *cc)
return true; return true;
} }
#if 0
bool bool
jit_pass_lower_fe(JitCompContext *cc) jit_pass_lower_fe(JitCompContext *cc)
{ {
return true; return true;
} }
#endif
static JitFrame * static JitFrame *
init_func_translation(JitCompContext *cc) init_func_translation(JitCompContext *cc)
@ -239,6 +324,7 @@ init_func_translation(JitCompContext *cc)
jit_frame->max_locals = max_locals; jit_frame->max_locals = max_locals;
jit_frame->max_stacks = max_stacks; jit_frame->max_stacks = max_stacks;
jit_frame->sp = jit_frame->lp + max_locals; jit_frame->sp = jit_frame->lp + max_locals;
jit_frame->ip = cur_wasm_func->code;
cc->jit_frame = jit_frame; cc->jit_frame = jit_frame;
cc->cur_basic_block = jit_cc_entry_basic_block(cc); cc->cur_basic_block = jit_cc_entry_basic_block(cc);
@ -266,9 +352,14 @@ init_func_translation(JitCompContext *cc)
NEW_CONST(I32, offsetof(WASMExecEnv, wasm_stack.s.top_boundary))); NEW_CONST(I32, offsetof(WASMExecEnv, wasm_stack.s.top_boundary)));
/* frame_boundary = top + frame_size + outs_size */ /* frame_boundary = top + frame_size + outs_size */
GEN_INSN(ADD, frame_boundary, top, NEW_CONST(I32, frame_size + outs_size)); GEN_INSN(ADD, frame_boundary, top, NEW_CONST(I32, frame_size + outs_size));
GEN_INSN(CHECK_SOE, NEW_CONST(I32, 0), frame_boundary, top_boundary); /* if frame_boundary > top_boundary, throw stack overflow exception */
GEN_INSN(CMP, cc->cmp_reg, frame_boundary, top_boundary);
if (!jit_emit_exception(cc, EXCE_OPERAND_STACK_OVERFLOW, JIT_OP_BGTU,
cc->cmp_reg, 0)) {
return NULL;
}
/* Add first and then sub to reduce one used register. */ /* Add first and then sub to reduce one used register */
/* new_top = frame_boundary - outs_size = top + frame_size */ /* new_top = frame_boundary - outs_size = top + frame_size */
GEN_INSN(SUB, new_top, frame_boundary, NEW_CONST(I32, outs_size)); GEN_INSN(SUB, new_top, frame_boundary, NEW_CONST(I32, outs_size));
/* exec_env->wasm_stack.s.top = new_top */ /* exec_env->wasm_stack.s.top = new_top */
@ -283,6 +374,7 @@ init_func_translation(JitCompContext *cc)
/* frame->prev_frame = fp_reg */ /* frame->prev_frame = fp_reg */
GEN_INSN(STI64, cc->fp_reg, top, GEN_INSN(STI64, cc->fp_reg, top,
NEW_CONST(I32, offsetof(WASMInterpFrame, prev_frame))); NEW_CONST(I32, offsetof(WASMInterpFrame, prev_frame)));
/* TODO: do we need to set frame->function? */
/* /*
GEN_INSN(STI64, func_inst, top, GEN_INSN(STI64, func_inst, top,
NEW_CONST(I32, offsetof(WASMInterpFrame, function))); NEW_CONST(I32, offsetof(WASMInterpFrame, function)));
@ -293,6 +385,52 @@ init_func_translation(JitCompContext *cc)
/* fp_reg = top */ /* fp_reg = top */
GEN_INSN(MOV, cc->fp_reg, top); GEN_INSN(MOV, cc->fp_reg, top);
#else #else
top = jit_cc_new_reg_I32(cc);
top_boundary = jit_cc_new_reg_I32(cc);
new_top = jit_cc_new_reg_I32(cc);
frame_boundary = jit_cc_new_reg_I32(cc);
frame_sp = jit_cc_new_reg_I32(cc);
/* top = exec_env->wasm_stack.s.top */
GEN_INSN(LDI32, top, cc->exec_env_reg,
NEW_CONST(I32, offsetof(WASMExecEnv, wasm_stack.s.top)));
/* top_boundary = exec_env->wasm_stack.s.top_boundary */
GEN_INSN(LDI32, top_boundary, cc->exec_env_reg,
NEW_CONST(I32, offsetof(WASMExecEnv, wasm_stack.s.top_boundary)));
/* frame_boundary = top + frame_size + outs_size */
GEN_INSN(ADD, frame_boundary, top, NEW_CONST(I32, frame_size + outs_size));
/* if frame_boundary > top_boundary, throw stack overflow exception */
GEN_INSN(CMP, cc->cmp_reg, frame_boundary, top_boundary);
if (!jit_emit_exception(cc, EXCE_OPERAND_STACK_OVERFLOW, JIT_OP_BGTU,
cc->cmp_reg, 0)) {
return NULL;
}
/* Add first and then sub to reduce one used register */
/* new_top = frame_boundary - outs_size = top + frame_size */
GEN_INSN(SUB, new_top, frame_boundary, NEW_CONST(I32, outs_size));
/* exec_env->wasm_stack.s.top = new_top */
GEN_INSN(STI32, new_top, cc->exec_env_reg,
NEW_CONST(I32, offsetof(WASMExecEnv, wasm_stack.s.top)));
/* frame_sp = frame->lp + local_size */
GEN_INSN(ADD, frame_sp, top,
NEW_CONST(I32, offsetof(WASMInterpFrame, lp) + local_size));
/* frame->sp = frame_sp */
GEN_INSN(STI32, frame_sp, top,
NEW_CONST(I32, offsetof(WASMInterpFrame, sp)));
/* frame->prev_frame = fp_reg */
GEN_INSN(STI32, cc->fp_reg, top,
NEW_CONST(I32, offsetof(WASMInterpFrame, prev_frame)));
/* TODO: do we need to set frame->function? */
/*
GEN_INSN(STI32, func_inst, top,
NEW_CONST(I32, offsetof(WASMInterpFrame, function)));
*/
/* exec_env->cur_frame = top */
GEN_INSN(STI32, top, cc->exec_env_reg,
NEW_CONST(I32, offsetof(WASMExecEnv, cur_frame)));
/* fp_reg = top */
GEN_INSN(MOV, cc->fp_reg, top);
#endif #endif
return jit_frame; return jit_frame;
@ -1535,6 +1673,12 @@ jit_compile_func(JitCompContext *cc)
jit_set_last_error(cc, "unsupported opcode"); jit_set_last_error(cc, "unsupported opcode");
return false; return false;
} }
/* Error may occur when creating registers, basic blocks, insns,
consts and labels, in which the return value may be unchecked,
here we check again */
if (jit_get_last_error(cc)) {
return false;
}
} }
(void)func_idx; (void)func_idx;

View File

@ -308,6 +308,7 @@ static inline void
gen_commit_for_exception(JitFrame *frame) gen_commit_for_exception(JitFrame *frame)
{ {
gen_commit_values(frame, frame->lp, frame->lp + frame->max_locals); gen_commit_values(frame, frame->lp, frame->lp + frame->max_locals);
gen_commit_sp_ip(frame);
} }
/** /**

View File

@ -315,6 +315,9 @@ JitBasicBlock *
jit_basic_block_new(JitReg label, int n) jit_basic_block_new(JitReg label, int n)
{ {
JitBasicBlock *block = jit_insn_new_PHI(label, n); JitBasicBlock *block = jit_insn_new_PHI(label, n);
if (!block)
return NULL;
block->prev = block->next = block; block->prev = block->next = block;
return block; return block;
} }
@ -380,7 +383,7 @@ jit_basic_block_succs(JitBasicBlock *block)
vec._base = jit_insn_opnd(last_insn, 1); vec._base = jit_insn_opnd(last_insn, 1);
break; break;
case JIT_OP_LOOKUP_SWITCH: case JIT_OP_LOOKUPSWITCH:
{ {
JitOpndLookupSwitch *opnd = jit_insn_opndls(last_insn); JitOpndLookupSwitch *opnd = jit_insn_opndls(last_insn);
vec.num = opnd->match_pairs_num + 1; vec.num = opnd->match_pairs_num + 1;
@ -412,10 +415,14 @@ jit_cc_init(JitCompContext *cc, unsigned htab_size)
|| !(exit_block = jit_cc_new_basic_block(cc, 0))) || !(exit_block = jit_cc_new_basic_block(cc, 0)))
goto fail; goto fail;
if (!(cc->exception_basic_blocks = if (!(cc->exce_basic_blocks =
jit_calloc(sizeof(JitBasicBlock *) * EXCE_NUM))) jit_calloc(sizeof(JitBasicBlock *) * EXCE_NUM)))
goto fail; goto fail;
if (!(cc->incoming_insns_for_exec_bbs =
jit_calloc(sizeof(JitIncomingInsnList) * EXCE_NUM)))
goto fail;
/* Record the entry and exit labels, whose indexes must be 0 and 1 /* Record the entry and exit labels, whose indexes must be 0 and 1
respectively. */ respectively. */
cc->entry_label = jit_basic_block_label(entry_block); cc->entry_label = jit_basic_block_label(entry_block);
@ -437,14 +444,14 @@ jit_cc_init(JitCompContext *cc, unsigned htab_size)
} }
/* Create registers for frame pointer, exec_env and cmp. */ /* Create registers for frame pointer, exec_env and cmp. */
#if UINTPTR_MAX == UINT32_MAX #if UINTPTR_MAX == UINT64_MAX
cc->fp_reg = jit_reg_new(JIT_REG_KIND_I32, cc->hreg_info->fp_hreg_index);
cc->exec_env_reg =
jit_reg_new(JIT_REG_KIND_I32, cc->hreg_info->exec_env_hreg_index);
#else
cc->fp_reg = jit_reg_new(JIT_REG_KIND_I64, cc->hreg_info->fp_hreg_index); cc->fp_reg = jit_reg_new(JIT_REG_KIND_I64, cc->hreg_info->fp_hreg_index);
cc->exec_env_reg = cc->exec_env_reg =
jit_reg_new(JIT_REG_KIND_I64, cc->hreg_info->exec_env_hreg_index); jit_reg_new(JIT_REG_KIND_I64, cc->hreg_info->exec_env_hreg_index);
#else
cc->fp_reg = jit_reg_new(JIT_REG_KIND_I32, cc->hreg_info->fp_hreg_index);
cc->exec_env_reg =
jit_reg_new(JIT_REG_KIND_I32, cc->hreg_info->exec_env_hreg_index);
#endif #endif
cc->cmp_reg = jit_reg_new(JIT_REG_KIND_I32, cc->hreg_info->cmp_hreg_index); cc->cmp_reg = jit_reg_new(JIT_REG_KIND_I32, cc->hreg_info->cmp_hreg_index);
@ -466,6 +473,7 @@ jit_cc_destroy(JitCompContext *cc)
{ {
unsigned i, end; unsigned i, end;
JitBasicBlock *block; JitBasicBlock *block;
JitIncomingInsn *incoming_insn, *incoming_insn_next;
jit_block_stack_destroy(&cc->block_stack); jit_block_stack_destroy(&cc->block_stack);
@ -476,7 +484,19 @@ jit_cc_destroy(JitCompContext *cc)
/* Release the instruction hash table. */ /* Release the instruction hash table. */
jit_cc_disable_insn_hash(cc); jit_cc_disable_insn_hash(cc);
jit_free(cc->exception_basic_blocks); jit_free(cc->exce_basic_blocks);
if (cc->incoming_insns_for_exec_bbs) {
for (i = 0; i < EXCE_NUM; i++) {
incoming_insn = cc->incoming_insns_for_exec_bbs[i];
while (incoming_insn) {
incoming_insn_next = incoming_insn->next;
jit_free(incoming_insn);
incoming_insn = incoming_insn_next;
}
}
jit_free(cc->incoming_insns_for_exec_bbs);
}
/* Release entry and exit blocks. */ /* Release entry and exit blocks. */
jit_basic_block_delete(jit_cc_entry_basic_block(cc)); jit_basic_block_delete(jit_cc_entry_basic_block(cc));
@ -619,6 +639,7 @@ _jit_cc_new_const(JitCompContext *cc, int kind, unsigned size, void *val)
cc->_const_val._next[kind] = new_next; cc->_const_val._next[kind] = new_next;
} }
else { else {
jit_set_last_error(cc, "create const register failed");
jit_free(new_value); jit_free(new_value);
jit_free(new_next); jit_free(new_next);
return 0; return 0;
@ -770,8 +791,10 @@ jit_cc_new_label(JitCompContext *cc)
#undef ANN_LABEL #undef ANN_LABEL
#undef EMPTY_POSTFIX #undef EMPTY_POSTFIX
if (!successful) if (!successful) {
jit_set_last_error(cc, "create label register failed");
return 0; return 0;
}
cc->_ann._label_capacity = capacity; cc->_ann._label_capacity = capacity;
} }
@ -790,6 +813,8 @@ jit_cc_new_basic_block(JitCompContext *cc, int n)
if (label && (block = jit_basic_block_new(label, n))) if (label && (block = jit_basic_block_new(label, n)))
/* Void 0 register indicates error in creation. */ /* Void 0 register indicates error in creation. */
*(jit_annl_basic_block(cc, label)) = block; *(jit_annl_basic_block(cc, label)) = block;
else
jit_set_last_error(cc, "create basic block failed");
return block; return block;
} }
@ -801,8 +826,10 @@ jit_cc_resize_basic_block(JitCompContext *cc, JitBasicBlock *block, int n)
JitInsn *insn = jit_basic_block_first_insn(block); JitInsn *insn = jit_basic_block_first_insn(block);
JitBasicBlock *new_block = jit_basic_block_new(label, n); JitBasicBlock *new_block = jit_basic_block_new(label, n);
if (!new_block) if (!new_block) {
jit_set_last_error(cc, "resize basic block failed");
return NULL; return NULL;
}
jit_insn_unlink(block); jit_insn_unlink(block);
@ -877,8 +904,10 @@ jit_cc_set_insn_uid(JitCompContext *cc, JitInsn *insn)
#undef ANN_INSN #undef ANN_INSN
#undef EMPTY_POSTFIX #undef EMPTY_POSTFIX
if (!successful) if (!successful) {
jit_set_last_error(cc, "set insn uid failed");
return NULL; return NULL;
}
cc->_ann._insn_capacity = capacity; cc->_ann._insn_capacity = capacity;
} }
@ -900,6 +929,7 @@ _jit_cc_set_insn_uid_for_new_insn(JitCompContext *cc, JitInsn *insn)
return NULL; return NULL;
} }
#if 0
static JitReg static JitReg
normalize_insn(JitCompContext *cc, JitInsn **pinsn) normalize_insn(JitCompContext *cc, JitInsn **pinsn)
{ {
@ -1059,6 +1089,7 @@ _gen_insn_norm_1(JitCompContext *cc, JitBasicBlock *block, unsigned kind,
return NULL; return NULL;
} }
#endif
JitReg JitReg
jit_cc_new_reg(JitCompContext *cc, unsigned kind) jit_cc_new_reg(JitCompContext *cc, unsigned kind)
@ -1080,8 +1111,10 @@ jit_cc_new_reg(JitCompContext *cc, unsigned kind)
#include "jit_ir.def" #include "jit_ir.def"
#undef ANN_REG #undef ANN_REG
if (!successful) if (!successful) {
jit_set_last_error(cc, "create register failed");
return 0; return 0;
}
cc->_ann._reg_capacity[kind] = capacity; cc->_ann._reg_capacity[kind] = capacity;
} }
@ -1093,33 +1126,37 @@ jit_cc_new_reg(JitCompContext *cc, unsigned kind)
#undef _JIT_REALLOC_ANN #undef _JIT_REALLOC_ANN
#define ANN_LABEL(TYPE, NAME) \ #define ANN_LABEL(TYPE, NAME) \
bool jit_annl_enable_##NAME(JitCompContext *cc) \ bool jit_annl_enable_##NAME(JitCompContext *cc) \
{ \ { \
if (cc->_ann._label_##NAME##_enabled) \ if (cc->_ann._label_##NAME##_enabled) \
return true; \ return true; \
\ \
if (cc->_ann._label_capacity > 0 \ if (cc->_ann._label_capacity > 0 \
&& !(cc->_ann._label_##NAME = \ && !(cc->_ann._label_##NAME = \
jit_calloc(cc->_ann._label_capacity * sizeof(TYPE)))) \ jit_calloc(cc->_ann._label_capacity * sizeof(TYPE)))) { \
return false; \ jit_set_last_error(cc, "annl enable " #NAME "failed"); \
\ return false; \
cc->_ann._label_##NAME##_enabled = 1; \ } \
return true; \ \
cc->_ann._label_##NAME##_enabled = 1; \
return true; \
} }
#define ANN_INSN(TYPE, NAME) \ #define ANN_INSN(TYPE, NAME) \
bool jit_anni_enable_##NAME(JitCompContext *cc) \ bool jit_anni_enable_##NAME(JitCompContext *cc) \
{ \ { \
if (cc->_ann._insn_##NAME##_enabled) \ if (cc->_ann._insn_##NAME##_enabled) \
return true; \ return true; \
\ \
if (cc->_ann._insn_capacity > 0 \ if (cc->_ann._insn_capacity > 0 \
&& !(cc->_ann._insn_##NAME = \ && !(cc->_ann._insn_##NAME = \
jit_calloc(cc->_ann._insn_capacity * sizeof(TYPE)))) \ jit_calloc(cc->_ann._insn_capacity * sizeof(TYPE)))) { \
return false; \ jit_set_last_error(cc, "anni enable " #NAME "failed"); \
\ return false; \
cc->_ann._insn_##NAME##_enabled = 1; \ } \
return true; \ \
cc->_ann._insn_##NAME##_enabled = 1; \
return true; \
} }
#define ANN_REG(TYPE, NAME) \ #define ANN_REG(TYPE, NAME) \
bool jit_annr_enable_##NAME(JitCompContext *cc) \ bool jit_annr_enable_##NAME(JitCompContext *cc) \
@ -1133,6 +1170,7 @@ jit_cc_new_reg(JitCompContext *cc, unsigned kind)
if (cc->_ann._reg_capacity[k] > 0 \ if (cc->_ann._reg_capacity[k] > 0 \
&& !(cc->_ann._reg_##NAME[k] = jit_calloc( \ && !(cc->_ann._reg_##NAME[k] = jit_calloc( \
cc->_ann._reg_capacity[k] * sizeof(TYPE)))) { \ cc->_ann._reg_capacity[k] * sizeof(TYPE)))) { \
jit_set_last_error(cc, "annr enable " #NAME "failed"); \
jit_annr_disable_##NAME(cc); \ jit_annr_disable_##NAME(cc); \
return false; \ return false; \
} \ } \
@ -1179,7 +1217,7 @@ jit_cc_new_reg(JitCompContext *cc, unsigned kind)
char * char *
jit_get_last_error(JitCompContext *cc) jit_get_last_error(JitCompContext *cc)
{ {
return cc->last_error[0] == '\0' ? "" : cc->last_error; return cc->last_error[0] == '\0' ? NULL : cc->last_error;
} }
void void
@ -1385,8 +1423,8 @@ to_stack_value_type(uint8 type)
bool bool
jit_cc_pop_value(JitCompContext *cc, uint8 type, JitReg *p_value) jit_cc_pop_value(JitCompContext *cc, uint8 type, JitReg *p_value)
{ {
JitValue *jit_value; JitValue *jit_value = NULL;
JitReg value; JitReg value = 0;
if (!cc->block_stack.block_list_end) { if (!cc->block_stack.block_list_end) {
jit_set_last_error(cc, "WASM block stack underflow"); jit_set_last_error(cc, "WASM block stack underflow");

View File

@ -72,78 +72,10 @@
#define INSN(NAME, OPND_KIND, OPND_NUM, FIRST_USE) #define INSN(NAME, OPND_KIND, OPND_NUM, FIRST_USE)
#endif #endif
/* Comparison instructions */
INSN(I32_EQZ, Reg, 3, 1)
INSN(I32_EQ, Reg, 3, 1)
INSN(I32_NE, Reg, 3, 1)
INSN(I32_LT_S, Reg, 3, 1)
INSN(I32_LT_U, Reg, 3, 1)
INSN(I32_GT_S, Reg, 3, 1)
INSN(I32_GT_U, Reg, 3, 1)
INSN(I32_LE_S, Reg, 3, 1)
INSN(I32_LE_U, Reg, 3, 1)
INSN(I32_GE_S, Reg, 3, 1)
INSN(I32_GE_U, Reg, 3, 1)
INSN(I64_EQZ, Reg, 3, 1)
INSN(I64_EQ, Reg, 3, 1)
INSN(I64_NE, Reg, 3, 1)
INSN(I64_LT_S, Reg, 3, 1)
INSN(I64_LT_U, Reg, 3, 1)
INSN(I64_GT_S, Reg, 3, 1)
INSN(I64_GT_U, Reg, 3, 1)
INSN(I64_LE_S, Reg, 3, 1)
INSN(I64_LE_U, Reg, 3, 1)
INSN(I64_GE_S, Reg, 3, 1)
INSN(I64_GE_U, Reg, 3, 1)
INSN(F32_EQ, Reg, 3, 1)
INSN(F32_NE, Reg, 3, 1)
INSN(F32_LT, Reg, 3, 1)
INSN(F32_GT, Reg, 3, 1)
INSN(F32_LE, Reg, 3, 1)
INSN(F32_GE, Reg, 3, 1)
INSN(F64_EQ, Reg, 3, 1)
INSN(F64_NE, Reg, 3, 1)
INSN(F64_LT, Reg, 3, 1)
INSN(F64_GT, Reg, 3, 1)
INSN(F64_LE, Reg, 3, 1)
INSN(F64_GE, Reg, 3, 1)
/* Select instruction */
INSN(SELECT, Reg, 4, 1)
/* Control instructions */
INSN(JMP, Reg, 1, 0)
INSN(BEQ, Reg, 3, 0)
INSN(BNE, Reg, 3, 0)
INSN(BGTS, Reg, 3, 0)
INSN(BGES, Reg, 3, 0)
INSN(BLTS, Reg, 3, 0)
INSN(BLES, Reg, 3, 0)
INSN(BGTU, Reg, 3, 0)
INSN(BGEU, Reg, 3, 0)
INSN(BLTU, Reg, 3, 0)
INSN(BLEU, Reg, 3, 0)
INSN(TABLE_SWITCH, TableSwitch, 1, 0)
INSN(LOOKUP_SWITCH, LookupSwitch, 1, 0)
/* check zero divisor */
INSN(CHECK_DIV_ZERO, Reg, 3, 0)
/* check stack overflow */
INSN(CHECK_SOE, Reg, 3, 0)
/* Call and return instructions */
INSN(CALLNATIVE, VReg, 2, 1)
INSN(CALLBC, Reg, 3, 0)
INSN(RETURN, Reg, 1, 0)
/* Move and conversion instructions that transfer values among /* Move and conversion instructions that transfer values among
registers of the same kind (move) or different kinds (convert) */ registers of the same kind (move) or different kinds (convert) */
INSN(MOV, Reg, 2, 1) INSN(MOV, Reg, 2, 1)
INSN(PHI, VReg, 1, 1) INSN(PHI, VReg, 1, 1)
INSN(I32TOI8, Reg, 2, 1) INSN(I32TOI8, Reg, 2, 1)
INSN(I32TOU8, Reg, 2, 1) INSN(I32TOU8, Reg, 2, 1)
INSN(I32TOI16, Reg, 2, 1) INSN(I32TOI16, Reg, 2, 1)
@ -193,7 +125,7 @@ INSN(SELECTLTU, Reg, 4, 1)
INSN(SELECTLEU, Reg, 4, 1) INSN(SELECTLEU, Reg, 4, 1)
/* Memory access instructions: */ /* Memory access instructions: */
INSN(LDSELF, Reg, 1, 1) INSN(LDEXECENV, Reg, 1, 1)
INSN(LDJITINFO, Reg, 1, 1) INSN(LDJITINFO, Reg, 1, 1)
INSN(LDI8, Reg, 3, 1) INSN(LDI8, Reg, 3, 1)
INSN(LDU8, Reg, 3, 1) INSN(LDU8, Reg, 3, 1)
@ -218,7 +150,69 @@ INSN(STV64, Reg, 3, 1)
INSN(STV128, Reg, 3, 1) INSN(STV128, Reg, 3, 1)
INSN(STV256, Reg, 3, 1) INSN(STV256, Reg, 3, 1)
/* Control instructions */
INSN(JMP, Reg, 1, 0)
INSN(BEQ, Reg, 3, 0)
INSN(BNE, Reg, 3, 0)
INSN(BGTS, Reg, 3, 0)
INSN(BGES, Reg, 3, 0)
INSN(BLTS, Reg, 3, 0)
INSN(BLES, Reg, 3, 0)
INSN(BGTU, Reg, 3, 0)
INSN(BGEU, Reg, 3, 0)
INSN(BLTU, Reg, 3, 0)
INSN(BLEU, Reg, 3, 0)
INSN(LOOKUPSWITCH, LookupSwitch, 1, 0)
/* INSN(TABLESWITCH, TableSwitch, 1, 0) */
/* Call and return instructions */
INSN(CALLNATIVE, VReg, 2, 1)
INSN(CALLBC, Reg, 3, 0)
INSN(RETURNBC, Reg, 1, 0)
#if 0 #if 0
/* Comparison instructions, can be translate to SELECTXXX */
INSN(I32_EQZ, Reg, 3, 1)
INSN(I32_EQ, Reg, 3, 1)
INSN(I32_NE, Reg, 3, 1)
INSN(I32_LT_S, Reg, 3, 1)
INSN(I32_LT_U, Reg, 3, 1)
INSN(I32_GT_S, Reg, 3, 1)
INSN(I32_GT_U, Reg, 3, 1)
INSN(I32_LE_S, Reg, 3, 1)
INSN(I32_LE_U, Reg, 3, 1)
INSN(I32_GE_S, Reg, 3, 1)
INSN(I32_GE_U, Reg, 3, 1)
INSN(I64_EQZ, Reg, 3, 1)
INSN(I64_EQ, Reg, 3, 1)
INSN(I64_NE, Reg, 3, 1)
INSN(I64_LT_S, Reg, 3, 1)
INSN(I64_LT_U, Reg, 3, 1)
INSN(I64_GT_S, Reg, 3, 1)
INSN(I64_GT_U, Reg, 3, 1)
INSN(I64_LE_S, Reg, 3, 1)
INSN(I64_LE_U, Reg, 3, 1)
INSN(I64_GE_S, Reg, 3, 1)
INSN(I64_GE_U, Reg, 3, 1)
INSN(F32_EQ, Reg, 3, 1)
INSN(F32_NE, Reg, 3, 1)
INSN(F32_LT, Reg, 3, 1)
INSN(F32_GT, Reg, 3, 1)
INSN(F32_LE, Reg, 3, 1)
INSN(F32_GE, Reg, 3, 1)
INSN(F64_EQ, Reg, 3, 1)
INSN(F64_NE, Reg, 3, 1)
INSN(F64_LT, Reg, 3, 1)
INSN(F64_GT, Reg, 3, 1)
INSN(F64_LE, Reg, 3, 1)
INSN(F64_GE, Reg, 3, 1)
/* Select instruction */
INSN(SELECT, Reg, 4, 1)
/* Memory instructions */ /* Memory instructions */
INSN(I32_LOAD, Reg, 2, 1) INSN(I32_LOAD, Reg, 2, 1)
INSN(I64_LOAD, Reg, 2, 1) INSN(I64_LOAD, Reg, 2, 1)

View File

@ -907,9 +907,15 @@ typedef struct JitFrame {
/* Max operand stack slot number. */ /* Max operand stack slot number. */
uint32 max_stacks; uint32 max_stacks;
/* Instruction pointer */
uint8 *ip;
/* Stack top pointer */ /* Stack top pointer */
JitValueSlot *sp; JitValueSlot *sp;
/* Committed instruction pointer */
uint8 *committed_ip;
/* Committed stack top pointer */ /* Committed stack top pointer */
JitValueSlot *committed_sp; JitValueSlot *committed_sp;
@ -998,7 +1004,8 @@ typedef struct JitCompContext {
be 0 and 1 respectively (see JIT_FOREACH_BLOCK). */ be 0 and 1 respectively (see JIT_FOREACH_BLOCK). */
JitReg entry_label; JitReg entry_label;
JitReg exit_label; JitReg exit_label;
JitBasicBlock *exception_basic_blocks; JitBasicBlock **exce_basic_blocks;
JitIncomingInsnList *incoming_insns_for_exec_bbs;
/* The current basic block to generate instructions */ /* The current basic block to generate instructions */
JitBasicBlock *cur_basic_block; JitBasicBlock *cur_basic_block;
@ -1229,6 +1236,15 @@ jit_cc_inc_ref(JitCompContext *cc)
void void
jit_cc_delete(JitCompContext *cc); jit_cc_delete(JitCompContext *cc);
char *
jit_get_last_error(JitCompContext *cc);
void
jit_set_last_error(JitCompContext *cc, const char *error);
void
jit_set_last_error_v(JitCompContext *cc, const char *format, ...);
/** /**
* Create a I32 constant value with relocatable into the compilation * Create a I32 constant value with relocatable into the compilation
* context. A constant value that has relocation info cannot be * context. A constant value that has relocation info cannot be
@ -1520,6 +1536,8 @@ _gen_insn(JitCompContext *cc, JitInsn *insn)
{ {
if (insn) if (insn)
jit_basic_block_append_insn(cc->cur_basic_block, insn); jit_basic_block_append_insn(cc->cur_basic_block, insn);
else
jit_set_last_error(cc, "generate insn failed");
return insn; return insn;
} }
@ -1529,6 +1547,7 @@ _gen_insn(JitCompContext *cc, JitInsn *insn)
*/ */
#define GEN_INSN(...) _gen_insn(cc, jit_cc_new_insn(cc, __VA_ARGS__)) #define GEN_INSN(...) _gen_insn(cc, jit_cc_new_insn(cc, __VA_ARGS__))
#if 0
/** /**
* Helper function for GEN_INSN_NORM_1 * Helper function for GEN_INSN_NORM_1
* *
@ -1559,6 +1578,7 @@ _gen_insn_norm_1(JitCompContext *cc, JitBasicBlock *block, unsigned kind,
*/ */
#define GEN_INSN_NORM(Type, result, ...) \ #define GEN_INSN_NORM(Type, result, ...) \
GEN_INSN_NORM_1(JIT_REG_KIND_##Type, result, __VA_ARGS__) GEN_INSN_NORM_1(JIT_REG_KIND_##Type, result, __VA_ARGS__)
#endif
/** /**
* Create a constant register without relocation info. * Create a constant register without relocation info.
@ -1737,15 +1757,6 @@ jit_cc_exit_basic_block(JitCompContext *cc)
return *(jit_annl_basic_block(cc, cc->exit_label)); return *(jit_annl_basic_block(cc, cc->exit_label));
} }
char *
jit_get_last_error(JitCompContext *cc);
void
jit_set_last_error(JitCompContext *cc, const char *error);
void
jit_set_last_error_v(JitCompContext *cc, const char *format, ...);
void void
jit_value_stack_push(JitValueStack *stack, JitValue *value); jit_value_stack_push(JitValueStack *stack, JitValue *value);

View File

@ -312,8 +312,11 @@ rc_init(RegallocContext *rc, JitCompContext *cc)
const unsigned vreg_num = jit_cc_reg_num(cc, i); const unsigned vreg_num = jit_cc_reg_num(cc, i);
const unsigned hreg_num = jit_cc_hreg_num(cc, i); const unsigned hreg_num = jit_cc_hreg_num(cc, i);
if (!(rc->vregs[i] = jit_calloc(sizeof(VirtualReg) * vreg_num)) if (vreg_num > 0
|| !(rc->hregs[i] = jit_calloc(sizeof(HardReg) * hreg_num))) && !(rc->vregs[i] = jit_calloc(sizeof(VirtualReg) * vreg_num)))
goto fail;
if (hreg_num > 0
&& !(rc->hregs[i] = jit_calloc(sizeof(HardReg) * hreg_num)))
goto fail; goto fail;
/* Hard registers can only be allocated to themselves. */ /* Hard registers can only be allocated to themselves. */
@ -407,8 +410,8 @@ reload_vreg(RegallocContext *rc, JitReg vreg, JitInsn *cur_insn)
JitInsn *insn = NULL; JitInsn *insn = NULL;
if (vreg == rc->cc->exec_env_reg) if (vreg == rc->cc->exec_env_reg)
/* Reload exec_env_reg with LDSELF. */ /* Reload exec_env_reg with LDEXECENV. */
insn = jit_cc_new_insn(rc->cc, LDSELF, vr->hreg); insn = jit_cc_new_insn(rc->cc, LDEXECENV, vr->hreg);
else else
/* Allocate spill slot if not yet and reload from there. */ /* Allocate spill slot if not yet and reload from there. */
{ {

View File

@ -3767,8 +3767,11 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
#if WASM_ENABLE_FAST_JIT == 0 #if WASM_ENABLE_FAST_JIT == 0
wasm_interp_call_func_bytecode(module_inst, exec_env, function, frame); wasm_interp_call_func_bytecode(module_inst, exec_env, function, frame);
#else #else
jit_interp_switch_to_jitted(exec_env, frame, function, JitInterpSwitchInfo info;
info.frame = frame;
jit_interp_switch_to_jitted(exec_env, &info,
function->u.func->jitted_code); function->u.func->jitted_code);
(void)wasm_interp_call_func_bytecode;
#endif #endif
} }

View File

@ -123,11 +123,15 @@ set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security -W
if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64")
if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang"))
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mindirect-branch-register")
# UNDEFINED BEHAVIOR, refer to https://en.cppreference.com/w/cpp/language/ub # UNDEFINED BEHAVIOR, refer to https://en.cppreference.com/w/cpp/language/ub
if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT WAMR_BUILD_JIT EQUAL 1) if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT WAMR_BUILD_JIT EQUAL 1)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined \ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined \
-fno-sanitize=bounds,bounds-strict,alignment \ -fno-sanitize=bounds,bounds-strict,alignment \
-fno-sanitize-recover") -fno-sanitize-recover")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined \
-fno-sanitize=bounds,bounds-strict,alignment \
-fno-sanitize-recover")
endif() endif()
else () else ()
# UNDEFINED BEHAVIOR, refer to https://en.cppreference.com/w/cpp/language/ub # UNDEFINED BEHAVIOR, refer to https://en.cppreference.com/w/cpp/language/ub
@ -135,6 +139,9 @@ if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined \ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined \
-fno-sanitize=bounds,alignment \ -fno-sanitize=bounds,alignment \
-fno-sanitize-recover") -fno-sanitize-recover")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined \
-fno-sanitize=bounds,alignment \
-fno-sanitize-recover")
endif() endif()
endif () endif ()
endif () endif ()