Implement post-MVP features and native stack overflow check (#243)
Implement native thread stack overflow check Implement post-MVP: Non-trapping float-to-int conversions Implement post-MVP: Sign-extension operators Enhance WASM loader checks
This commit is contained in:
@ -595,14 +595,14 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
||||
case WASM_OP_I32_TRUNC_S_F32:
|
||||
case WASM_OP_I32_TRUNC_U_F32:
|
||||
sign = (opcode == WASM_OP_I32_TRUNC_S_F32) ? true : false;
|
||||
if (!aot_compile_op_i32_trunc_f32(comp_ctx, func_ctx, sign))
|
||||
if (!aot_compile_op_i32_trunc_f32(comp_ctx, func_ctx, sign, false))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I32_TRUNC_S_F64:
|
||||
case WASM_OP_I32_TRUNC_U_F64:
|
||||
sign = (opcode == WASM_OP_I32_TRUNC_S_F64) ? true : false;
|
||||
if (!aot_compile_op_i32_trunc_f64(comp_ctx, func_ctx, sign))
|
||||
if (!aot_compile_op_i32_trunc_f64(comp_ctx, func_ctx, sign, false))
|
||||
return false;
|
||||
break;
|
||||
|
||||
@ -616,14 +616,14 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
||||
case WASM_OP_I64_TRUNC_S_F32:
|
||||
case WASM_OP_I64_TRUNC_U_F32:
|
||||
sign = (opcode == WASM_OP_I64_TRUNC_S_F32) ? true : false;
|
||||
if (!aot_compile_op_i64_trunc_f32(comp_ctx, func_ctx, sign))
|
||||
if (!aot_compile_op_i64_trunc_f32(comp_ctx, func_ctx, sign, false))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I64_TRUNC_S_F64:
|
||||
case WASM_OP_I64_TRUNC_U_F64:
|
||||
sign = (opcode == WASM_OP_I64_TRUNC_S_F64) ? true : false;
|
||||
if (!aot_compile_op_i64_trunc_f64(comp_ctx, func_ctx, sign))
|
||||
if (!aot_compile_op_i64_trunc_f64(comp_ctx, func_ctx, sign, false))
|
||||
return false;
|
||||
break;
|
||||
|
||||
@ -685,6 +685,67 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I32_EXTEND8_S:
|
||||
if (!aot_compile_op_i32_extend_i32(comp_ctx, func_ctx, 8))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I32_EXTEND16_S:
|
||||
if (!aot_compile_op_i32_extend_i32(comp_ctx, func_ctx, 16))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I64_EXTEND8_S:
|
||||
if (!aot_compile_op_i64_extend_i64(comp_ctx, func_ctx, 8))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I64_EXTEND16_S:
|
||||
if (!aot_compile_op_i64_extend_i64(comp_ctx, func_ctx, 16))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_I64_EXTEND32_S:
|
||||
if (!aot_compile_op_i64_extend_i64(comp_ctx, func_ctx, 32))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case WASM_OP_MISC_PREFIX:
|
||||
{
|
||||
if (frame_ip < frame_ip_end) {
|
||||
opcode = *frame_ip++;
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case WASM_OP_I32_TRUNC_SAT_S_F32:
|
||||
case WASM_OP_I32_TRUNC_SAT_U_F32:
|
||||
sign = (opcode == WASM_OP_I32_TRUNC_SAT_S_F32) ? true : false;
|
||||
if (!aot_compile_op_i32_trunc_f32(comp_ctx, func_ctx, sign, true))
|
||||
return false;
|
||||
break;
|
||||
case WASM_OP_I32_TRUNC_SAT_S_F64:
|
||||
case WASM_OP_I32_TRUNC_SAT_U_F64:
|
||||
sign = (opcode == WASM_OP_I32_TRUNC_SAT_S_F64) ? true : false;
|
||||
if (!aot_compile_op_i32_trunc_f64(comp_ctx, func_ctx, sign, true))
|
||||
return false;
|
||||
break;
|
||||
case WASM_OP_I64_TRUNC_SAT_S_F32:
|
||||
case WASM_OP_I64_TRUNC_SAT_U_F32:
|
||||
sign = (opcode == WASM_OP_I64_TRUNC_SAT_S_F32) ? true : false;
|
||||
if (!aot_compile_op_i64_trunc_f32(comp_ctx, func_ctx, sign, true))
|
||||
return false;
|
||||
break;
|
||||
case WASM_OP_I64_TRUNC_SAT_S_F64:
|
||||
case WASM_OP_I64_TRUNC_SAT_U_F64:
|
||||
sign = (opcode == WASM_OP_I64_TRUNC_SAT_S_F64) ? true : false;
|
||||
if (!aot_compile_op_i64_trunc_f64(comp_ctx, func_ctx, sign, true))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@ -89,6 +89,156 @@ fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
#define ADD_BASIC_BLOCK(block, name) do { \
|
||||
if (!(block = LLVMAppendBasicBlockInContext(comp_ctx->context, \
|
||||
func_ctx->func, \
|
||||
name))) { \
|
||||
aot_set_last_error("llvm add basic block failed."); \
|
||||
goto fail; \
|
||||
} \
|
||||
\
|
||||
LLVMMoveBasicBlockAfter(block, LLVMGetInsertBlock(comp_ctx->builder)); \
|
||||
} while (0)
|
||||
|
||||
static bool
|
||||
trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
LLVMValueRef operand, LLVMTypeRef dest_type,
|
||||
LLVMValueRef min_value, LLVMValueRef max_value,
|
||||
char *name, bool sign)
|
||||
{
|
||||
LLVMBasicBlockRef check_nan_succ, check_less_succ, check_greater_succ;
|
||||
LLVMBasicBlockRef is_nan_block, is_less_block, is_greater_block, res_block;
|
||||
LLVMValueRef is_less, is_greater, res, phi;
|
||||
LLVMValueRef zero = (dest_type == I32_TYPE) ? I32_ZERO : I64_ZERO;
|
||||
LLVMValueRef vmin, vmax;
|
||||
|
||||
if (!(res = LLVMBuildFCmp(comp_ctx->builder, LLVMRealUNO,
|
||||
operand, operand, "fcmp_is_nan"))) {
|
||||
aot_set_last_error("llvm build fcmp failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ADD_BASIC_BLOCK(check_nan_succ, "check_nan_succ");
|
||||
ADD_BASIC_BLOCK(is_nan_block, "is_nan_block");
|
||||
ADD_BASIC_BLOCK(check_less_succ, "check_less_succ");
|
||||
ADD_BASIC_BLOCK(is_less_block, "is_less_block");
|
||||
ADD_BASIC_BLOCK(check_greater_succ, "check_greater_succ");
|
||||
ADD_BASIC_BLOCK(is_greater_block, "is_greater_block");
|
||||
ADD_BASIC_BLOCK(res_block, "res_block");
|
||||
|
||||
if (!LLVMBuildCondBr(comp_ctx->builder, res,
|
||||
is_nan_block, check_nan_succ)) {
|
||||
aot_set_last_error("llvm build cond br failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Start to translate is_nan block */
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, is_nan_block);
|
||||
if (!LLVMBuildBr(comp_ctx->builder, res_block)) {
|
||||
aot_set_last_error("llvm build br failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Start to translate check_nan_succ block */
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, check_nan_succ);
|
||||
if (!(is_less = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOLE, operand,
|
||||
min_value, "fcmp_min_value"))) {
|
||||
aot_set_last_error("llvm build fcmp failed.");
|
||||
goto fail;
|
||||
}
|
||||
if (!LLVMBuildCondBr(comp_ctx->builder, is_less,
|
||||
is_less_block, check_less_succ)) {
|
||||
aot_set_last_error("llvm build cond br failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Start to translate is_less block */
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, is_less_block);
|
||||
if (!LLVMBuildBr(comp_ctx->builder, res_block)) {
|
||||
aot_set_last_error("llvm build br failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Start to translate check_less_succ block */
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, check_less_succ);
|
||||
if (!(is_greater = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOGE, operand,
|
||||
max_value, "fcmp_max_value"))) {
|
||||
aot_set_last_error("llvm build fcmp failed.");
|
||||
goto fail;
|
||||
}
|
||||
if (!LLVMBuildCondBr(comp_ctx->builder, is_greater,
|
||||
is_greater_block, check_greater_succ)) {
|
||||
aot_set_last_error("llvm build cond br failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Start to translate is_greater block */
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, is_greater_block);
|
||||
if (!LLVMBuildBr(comp_ctx->builder, res_block)) {
|
||||
aot_set_last_error("llvm build br failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Start to translate check_greater_succ block */
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, check_greater_succ);
|
||||
if (sign)
|
||||
res = LLVMBuildFPToSI(comp_ctx->builder, operand, dest_type, name);
|
||||
else
|
||||
res = LLVMBuildFPToUI(comp_ctx->builder, operand, dest_type, name);
|
||||
if (!res) {
|
||||
aot_set_last_error("llvm build conversion failed.");
|
||||
return false;
|
||||
}
|
||||
if (!LLVMBuildBr(comp_ctx->builder, res_block)) {
|
||||
aot_set_last_error("llvm build br failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Start to translate res_block */
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, res_block);
|
||||
/* Create result phi */
|
||||
if (!(phi = LLVMBuildPhi(comp_ctx->builder,
|
||||
dest_type,
|
||||
"trunc_sat_result_phi"))) {
|
||||
aot_set_last_error("llvm build phi failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Add phi incoming values */
|
||||
if (dest_type == I32_TYPE) {
|
||||
if (sign) {
|
||||
vmin = I32_CONST(INT32_MIN);
|
||||
vmax = I32_CONST(INT32_MAX);
|
||||
}
|
||||
else {
|
||||
vmin = I32_CONST(0);
|
||||
vmax = I32_CONST(UINT32_MAX);
|
||||
}
|
||||
}
|
||||
else if (dest_type == I64_TYPE) {
|
||||
if (sign) {
|
||||
vmin = I64_CONST(INT64_MIN);
|
||||
vmax = I64_CONST(INT64_MAX);
|
||||
}
|
||||
else {
|
||||
vmin = I64_CONST(0);
|
||||
vmax = I64_CONST(UINT64_MAX);
|
||||
}
|
||||
}
|
||||
LLVMAddIncoming(phi, &zero, &is_nan_block, 1);
|
||||
LLVMAddIncoming(phi, &vmin, &is_less_block, 1);
|
||||
LLVMAddIncoming(phi, &vmax, &is_greater_block, 1);
|
||||
LLVMAddIncoming(phi, &res, &check_greater_succ, 1);
|
||||
|
||||
if (dest_type == I32_TYPE)
|
||||
PUSH_I32(phi);
|
||||
else if (dest_type == I64_TYPE)
|
||||
PUSH_I64(phi);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_wrap_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
@ -109,7 +259,7 @@ fail:
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign)
|
||||
bool sign, bool saturating)
|
||||
{
|
||||
LLVMValueRef value;
|
||||
LLVMValueRef min_value, max_value;
|
||||
@ -125,16 +275,22 @@ aot_compile_op_i32_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
max_value = F32_CONST(4294967296.0f);
|
||||
}
|
||||
|
||||
return trunc_float_to_int(comp_ctx, func_ctx, value,
|
||||
I32_TYPE, min_value, max_value,
|
||||
sign ? "i32_trunc_f32_s" : "i32_trunc_f32_u", sign);
|
||||
if (!saturating)
|
||||
return trunc_float_to_int(comp_ctx, func_ctx, value,
|
||||
I32_TYPE, min_value, max_value,
|
||||
sign ? "i32_trunc_f32_s" : "i32_trunc_f32_u", sign);
|
||||
else
|
||||
return trunc_sat_float_to_int(comp_ctx, func_ctx, value,
|
||||
I32_TYPE, min_value, max_value,
|
||||
sign ? "i32_trunc_sat_f32_s" :
|
||||
"i32_trunc_sat_f32_u", sign);
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign)
|
||||
bool sign, bool saturating)
|
||||
{
|
||||
LLVMValueRef value;
|
||||
LLVMValueRef min_value, max_value;
|
||||
@ -150,9 +306,15 @@ aot_compile_op_i32_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
max_value = F64_CONST(4294967296.0);
|
||||
}
|
||||
|
||||
return trunc_float_to_int(comp_ctx, func_ctx, value,
|
||||
I32_TYPE, min_value, max_value,
|
||||
sign ? "i32_trunc_f64_s" : "i32_trunc_f64_u", sign);
|
||||
if (!saturating)
|
||||
return trunc_float_to_int(comp_ctx, func_ctx, value,
|
||||
I32_TYPE, min_value, max_value,
|
||||
sign ? "i32_trunc_f64_s" : "i32_trunc_f64_u", sign);
|
||||
else
|
||||
return trunc_sat_float_to_int(comp_ctx, func_ctx, value,
|
||||
I32_TYPE, min_value, max_value,
|
||||
sign ? "i32_trunc_sat_f64_s" :
|
||||
"i32_trunc_sat_f64_u", sign);
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
@ -180,9 +342,83 @@ fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_extend_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
int8 bitwidth)
|
||||
{
|
||||
LLVMValueRef value, res, cast_value = NULL;
|
||||
|
||||
POP_I64(value);
|
||||
|
||||
if (bitwidth == 8) {
|
||||
cast_value = LLVMBuildIntCast2(comp_ctx->builder, value,
|
||||
INT8_TYPE, true, "i8_intcast_i64");
|
||||
}
|
||||
else if (bitwidth == 16) {
|
||||
cast_value = LLVMBuildIntCast2(comp_ctx->builder, value,
|
||||
INT16_TYPE, true, "i16_intcast_i64");
|
||||
}
|
||||
else if (bitwidth == 32) {
|
||||
cast_value = LLVMBuildIntCast2(comp_ctx->builder, value,
|
||||
I32_TYPE, true, "i32_intcast_i64");
|
||||
}
|
||||
|
||||
if (!cast_value) {
|
||||
aot_set_last_error("llvm build conversion failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
res = LLVMBuildSExt(comp_ctx->builder, cast_value, I64_TYPE, "i64_extend_i64_s");
|
||||
|
||||
if (!res) {
|
||||
aot_set_last_error("llvm build conversion failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PUSH_I64(res);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_extend_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
int8 bitwidth)
|
||||
{
|
||||
LLVMValueRef value, res, cast_value = NULL;
|
||||
|
||||
POP_I32(value);
|
||||
|
||||
if (bitwidth == 8) {
|
||||
cast_value = LLVMBuildIntCast2(comp_ctx->builder, value,
|
||||
INT8_TYPE, true, "i8_intcast_i32");
|
||||
}
|
||||
else if (bitwidth == 16) {
|
||||
cast_value = LLVMBuildIntCast2(comp_ctx->builder, value,
|
||||
INT16_TYPE, true, "i16_intcast_i32");
|
||||
}
|
||||
|
||||
if (!cast_value) {
|
||||
aot_set_last_error("llvm build conversion failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
res = LLVMBuildSExt(comp_ctx->builder, cast_value, I32_TYPE, "i32_extend_i32_s");
|
||||
|
||||
if (!res) {
|
||||
aot_set_last_error("llvm build conversion failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PUSH_I32(res);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign)
|
||||
bool sign, bool saturating)
|
||||
{
|
||||
LLVMValueRef value;
|
||||
LLVMValueRef min_value, max_value;
|
||||
@ -198,16 +434,22 @@ aot_compile_op_i64_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
max_value = F32_CONST(18446744073709551616.0f);
|
||||
}
|
||||
|
||||
return trunc_float_to_int(comp_ctx, func_ctx, value,
|
||||
I64_TYPE, min_value, max_value,
|
||||
sign ? "i64_trunc_f32_s" : "i64_trunc_f32_u", sign);
|
||||
if (!saturating)
|
||||
return trunc_float_to_int(comp_ctx, func_ctx, value,
|
||||
I64_TYPE, min_value, max_value,
|
||||
sign ? "i64_trunc_f32_s" : "i64_trunc_f32_u", sign);
|
||||
else
|
||||
return trunc_sat_float_to_int(comp_ctx, func_ctx, value,
|
||||
I64_TYPE, min_value, max_value,
|
||||
sign ? "i64_trunc_sat_f32_s" :
|
||||
"i64_trunc_sat_f32_u", sign);
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign)
|
||||
bool sign, bool saturating)
|
||||
{
|
||||
LLVMValueRef value;
|
||||
LLVMValueRef min_value, max_value;
|
||||
@ -223,9 +465,16 @@ aot_compile_op_i64_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
max_value = F64_CONST(18446744073709551616.0);
|
||||
}
|
||||
|
||||
return trunc_float_to_int(comp_ctx, func_ctx, value,
|
||||
I64_TYPE, min_value, max_value,
|
||||
sign ? "i64_trunc_f64_s" : "i64_trunc_f64_u", sign);
|
||||
if (!saturating)
|
||||
return trunc_float_to_int(comp_ctx, func_ctx, value,
|
||||
I64_TYPE, min_value, max_value,
|
||||
sign ? "i64_trunc_f64_s" : "i64_trunc_f64_u", sign);
|
||||
else
|
||||
return trunc_sat_float_to_int(comp_ctx, func_ctx, value,
|
||||
I64_TYPE, min_value, max_value,
|
||||
sign ? "i64_trunc_sat_f64_s" :
|
||||
"i64_trunc_sat_f64_u", sign);
|
||||
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -17,23 +17,31 @@ aot_compile_op_i32_wrap_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign);
|
||||
bool sign, bool saturating);
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign);
|
||||
bool sign, bool saturating);
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_extend_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign);
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_extend_i64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
int8 bitwidth);
|
||||
|
||||
bool
|
||||
aot_compile_op_i32_extend_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
int8 bitwidth);
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_trunc_f32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign);
|
||||
bool sign, bool saturating);
|
||||
|
||||
bool
|
||||
aot_compile_op_i64_trunc_f64(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
bool sign);
|
||||
bool sign, bool saturating);
|
||||
|
||||
bool
|
||||
aot_compile_op_f32_convert_i32(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
|
||||
@ -17,7 +17,8 @@ static char *exce_block_names[] = {
|
||||
"exce_invalid_func_idx", /* EXCE_INVALID_FUNCTION_INDEX */
|
||||
"exce_undefined_element", /* EXCE_UNDEFINED_ELEMENT */
|
||||
"exce_uninit_element", /* EXCE_UNINITIALIZED_ELEMENT */
|
||||
"exce_call_unlinked" /* EXCE_CALL_UNLINKED_IMPORT_FUNC */
|
||||
"exce_call_unlinked", /* EXCE_CALL_UNLINKED_IMPORT_FUNC */
|
||||
"exce_native_stack_overflow" /* EXCE_NATIVE_STACK_OVERFLOW */
|
||||
};
|
||||
|
||||
bool
|
||||
|
||||
@ -255,6 +255,39 @@ call_aot_invoke_native_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
LLVMBasicBlockRef check_stack;
|
||||
LLVMValueRef cmp;
|
||||
|
||||
if (!(check_stack = LLVMAppendBasicBlockInContext(comp_ctx->context,
|
||||
func_ctx->func,
|
||||
"check_stack"))) {
|
||||
aot_set_last_error("llvm add basic block failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
LLVMMoveBasicBlockAfter(check_stack, block_curr);
|
||||
|
||||
if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntULT,
|
||||
func_ctx->last_alloca, func_ctx->native_stack_bound,
|
||||
"cmp"))) {
|
||||
aot_set_last_error("llvm build icmp failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!aot_emit_exception(comp_ctx, func_ctx,
|
||||
EXCE_NATIVE_STACK_OVERFLOW,
|
||||
true, cmp, check_stack)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, check_stack);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
uint32 func_idx, uint8 **p_frame_ip)
|
||||
@ -347,6 +380,9 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
else {
|
||||
func = func_ctxes[func_idx - import_func_count]->func;
|
||||
|
||||
if (!check_stack_boundary(comp_ctx, func_ctx))
|
||||
goto fail;
|
||||
|
||||
/* Call the function */
|
||||
if (!(value_ret = LLVMBuildCall(comp_ctx->builder, func,
|
||||
param_values, (uint32)param_count + 1,
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
#define ADD_BASIC_BLOCK(block, name) do { \
|
||||
if (!(block = LLVMAppendBasicBlockInContext(comp_ctx->context, \
|
||||
func_ctx->func, \
|
||||
name))) { \
|
||||
name))) { \
|
||||
aot_set_last_error("llvm add basic block failed."); \
|
||||
goto fail; \
|
||||
} \
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
|
||||
#include "aot_llvm.h"
|
||||
#include "aot_compiler.h"
|
||||
#include "aot_emit_exception.h"
|
||||
#include "../aot/aot_runtime.h"
|
||||
|
||||
|
||||
@ -451,6 +452,7 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx,
|
||||
LLVMTypeRef int8_ptr_type, int32_ptr_type;
|
||||
LLVMValueRef aot_inst_offset = I32_TWO, aot_inst_addr;
|
||||
LLVMValueRef argv_buf_offset = I32_THREE, argv_buf_addr;
|
||||
LLVMValueRef stack_bound_offset = I32_FOUR, stack_bound_addr;
|
||||
char local_name[32];
|
||||
uint64 size;
|
||||
uint32 i, j = 0;
|
||||
@ -526,6 +528,21 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Get native stack boundary address */
|
||||
if (!(stack_bound_addr =
|
||||
LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->exec_env,
|
||||
&stack_bound_offset, 1, "stack_bound_addr"))) {
|
||||
aot_set_last_error("llvm build in bounds gep failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(func_ctx->native_stack_bound =
|
||||
LLVMBuildLoad(comp_ctx->builder,
|
||||
stack_bound_addr, "native_stack_bound"))) {
|
||||
aot_set_last_error("llvm build load failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < aot_func_type->param_count; i++, j++) {
|
||||
snprintf(local_name, sizeof(local_name), "l%d", i);
|
||||
func_ctx->locals[i] =
|
||||
@ -580,6 +597,24 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx,
|
||||
}
|
||||
}
|
||||
|
||||
if (aot_func_type->param_count + func->local_count > 0) {
|
||||
func_ctx->last_alloca = func_ctx->locals[aot_func_type->param_count
|
||||
+ func->local_count - 1];
|
||||
if (!(func_ctx->last_alloca =
|
||||
LLVMBuildBitCast(comp_ctx->builder, func_ctx->last_alloca,
|
||||
INT8_PTR_TYPE, "stack_ptr"))) {
|
||||
aot_set_last_error("llvm build bit cast failed.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!(func_ctx->last_alloca = LLVMBuildAlloca(comp_ctx->builder, INT8_TYPE,
|
||||
"stack_ptr"))) {
|
||||
aot_set_last_error("llvm build alloca failed.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(int8_ptr_type = LLVMPointerType(INT8_PTR_TYPE, 0))) {
|
||||
aot_set_last_error("llvm add pointer type failed.");
|
||||
goto fail;
|
||||
|
||||
@ -102,6 +102,8 @@ typedef struct AOTFuncContext {
|
||||
LLVMValueRef aot_inst;
|
||||
LLVMValueRef table_base;
|
||||
LLVMValueRef argv_buf;
|
||||
LLVMValueRef native_stack_bound;
|
||||
LLVMValueRef last_alloca;
|
||||
|
||||
LLVMValueRef heap_base_offset;
|
||||
LLVMValueRef mem_base_addr;
|
||||
|
||||
Reference in New Issue
Block a user