mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
Return panic tag from roc_panic to test platform
This commit is contained in:
parent
9201cf0b32
commit
a8122662c2
5 changed files with 80 additions and 36 deletions
|
@ -3349,7 +3349,7 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
builder.position_at_end(entry);
|
builder.position_at_end(entry);
|
||||||
|
|
||||||
let wrapped_layout = roc_result_layout(env.arena, return_layout, env.target_info);
|
let wrapped_layout = roc_call_result_layout(env.arena, return_layout, env.target_info);
|
||||||
call_roc_function(env, roc_function, &wrapped_layout, arguments_for_call)
|
call_roc_function(env, roc_function, &wrapped_layout, arguments_for_call)
|
||||||
} else {
|
} else {
|
||||||
call_roc_function(env, roc_function, &return_layout, arguments_for_call)
|
call_roc_function(env, roc_function, &return_layout, arguments_for_call)
|
||||||
|
@ -3379,7 +3379,8 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>(
|
||||||
// a tagged union to indicate to the test loader that a panic occurred.
|
// a tagged union to indicate to the test loader that a panic occurred.
|
||||||
// especially when running 32-bit binaries on a 64-bit machine, there
|
// especially when running 32-bit binaries on a 64-bit machine, there
|
||||||
// does not seem to be a smarter solution
|
// does not seem to be a smarter solution
|
||||||
let wrapper_return_type = roc_result_type(env, basic_type_from_layout(env, &return_layout));
|
let wrapper_return_type =
|
||||||
|
roc_call_result_type(env, basic_type_from_layout(env, &return_layout));
|
||||||
|
|
||||||
let mut cc_argument_types = Vec::with_capacity_in(arguments.len(), env.arena);
|
let mut cc_argument_types = Vec::with_capacity_in(arguments.len(), env.arena);
|
||||||
for layout in arguments {
|
for layout in arguments {
|
||||||
|
@ -3768,7 +3769,7 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let return_type = match env.mode {
|
let return_type = match env.mode {
|
||||||
LlvmBackendMode::GenTest | LlvmBackendMode::WasmGenTest | LlvmBackendMode::CliTest => {
|
LlvmBackendMode::GenTest | LlvmBackendMode::WasmGenTest | LlvmBackendMode::CliTest => {
|
||||||
roc_result_type(env, roc_function.get_type().get_return_type().unwrap()).into()
|
roc_call_result_type(env, roc_function.get_type().get_return_type().unwrap()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
LlvmBackendMode::Binary | LlvmBackendMode::BinaryDev => {
|
LlvmBackendMode::Binary | LlvmBackendMode::BinaryDev => {
|
||||||
|
@ -3889,6 +3890,21 @@ pub fn get_panic_msg_ptr<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> PointerVa
|
||||||
global.as_pointer_value()
|
global.as_pointer_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pointer to the panic tag.
|
||||||
|
/// Only non-zero values must be written into here.
|
||||||
|
pub fn get_panic_tag_ptr<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> PointerValue<'ctx> {
|
||||||
|
let i64_typ = env.context.i64_type();
|
||||||
|
|
||||||
|
let global_name = "roc_panic_msg_tag";
|
||||||
|
let global = env.module.get_global(global_name).unwrap_or_else(|| {
|
||||||
|
let global = env.module.add_global(i64_typ, None, global_name);
|
||||||
|
global.set_initializer(&i64_typ.const_zero());
|
||||||
|
global
|
||||||
|
});
|
||||||
|
|
||||||
|
global.as_pointer_value()
|
||||||
|
}
|
||||||
|
|
||||||
fn set_jump_and_catch_long_jump<'a, 'ctx, 'env>(
|
fn set_jump_and_catch_long_jump<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
|
@ -3900,7 +3916,7 @@ fn set_jump_and_catch_long_jump<'a, 'ctx, 'env>(
|
||||||
let builder = env.builder;
|
let builder = env.builder;
|
||||||
|
|
||||||
let return_type = basic_type_from_layout(env, &return_layout);
|
let return_type = basic_type_from_layout(env, &return_layout);
|
||||||
let call_result_type = roc_result_type(env, return_type.as_basic_type_enum());
|
let call_result_type = roc_call_result_type(env, return_type.as_basic_type_enum());
|
||||||
let result_alloca = builder.build_alloca(call_result_type, "result");
|
let result_alloca = builder.build_alloca(call_result_type, "result");
|
||||||
|
|
||||||
let then_block = context.append_basic_block(parent, "then_block");
|
let then_block = context.append_basic_block(parent, "then_block");
|
||||||
|
@ -3937,16 +3953,16 @@ fn set_jump_and_catch_long_jump<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
// RocStr* global
|
// RocStr* global
|
||||||
let error_msg_ptr = get_panic_msg_ptr(env);
|
let error_msg_ptr = get_panic_msg_ptr(env);
|
||||||
|
// i64* global
|
||||||
|
let error_tag_ptr = get_panic_tag_ptr(env);
|
||||||
|
|
||||||
let return_value = {
|
let return_value = {
|
||||||
let v1 = call_result_type.const_zero();
|
let v1 = call_result_type.const_zero();
|
||||||
|
|
||||||
// flag is non-zero, indicating failure
|
// tag must be non-zero, indicating failure
|
||||||
let flag = context.i64_type().const_int(1, false);
|
let tag = builder.build_load(error_tag_ptr, "load_panic_tag");
|
||||||
|
|
||||||
let v2 = builder
|
let v2 = builder.build_insert_value(v1, tag, 0, "set_error").unwrap();
|
||||||
.build_insert_value(v1, flag, 0, "set_error")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let v3 = builder
|
let v3 = builder
|
||||||
.build_insert_value(v2, error_msg_ptr, 1, "set_exception")
|
.build_insert_value(v2, error_msg_ptr, 1, "set_exception")
|
||||||
|
@ -3979,7 +3995,7 @@ fn make_exception_catcher<'a, 'ctx, 'env>(
|
||||||
function_value
|
function_value
|
||||||
}
|
}
|
||||||
|
|
||||||
fn roc_result_layout<'a>(
|
fn roc_call_result_layout<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
return_layout: Layout<'a>,
|
return_layout: Layout<'a>,
|
||||||
target_info: TargetInfo,
|
target_info: TargetInfo,
|
||||||
|
@ -3989,14 +4005,14 @@ fn roc_result_layout<'a>(
|
||||||
Layout::struct_no_name_order(arena.alloc(elements))
|
Layout::struct_no_name_order(arena.alloc(elements))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn roc_result_type<'a, 'ctx, 'env>(
|
fn roc_call_result_type<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
return_type: BasicTypeEnum<'ctx>,
|
return_type: BasicTypeEnum<'ctx>,
|
||||||
) -> StructType<'ctx> {
|
) -> StructType<'ctx> {
|
||||||
env.context.struct_type(
|
env.context.struct_type(
|
||||||
&[
|
&[
|
||||||
env.context.i64_type().into(),
|
env.context.i64_type().into(),
|
||||||
env.context.i8_type().ptr_type(AddressSpace::Generic).into(),
|
zig_str_type(env).ptr_type(AddressSpace::Generic).into(),
|
||||||
return_type,
|
return_type,
|
||||||
],
|
],
|
||||||
false,
|
false,
|
||||||
|
@ -4011,7 +4027,7 @@ fn make_good_roc_result<'a, 'ctx, 'env>(
|
||||||
let context = env.context;
|
let context = env.context;
|
||||||
let builder = env.builder;
|
let builder = env.builder;
|
||||||
|
|
||||||
let v1 = roc_result_type(env, basic_type_from_layout(env, &return_layout)).const_zero();
|
let v1 = roc_call_result_type(env, basic_type_from_layout(env, &return_layout)).const_zero();
|
||||||
|
|
||||||
let v2 = builder
|
let v2 = builder
|
||||||
.build_insert_value(v1, context.i64_type().const_zero(), 0, "set_no_error")
|
.build_insert_value(v1, context.i64_type().const_zero(), 0, "set_no_error")
|
||||||
|
@ -4058,7 +4074,8 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let wrapper_return_type = roc_result_type(env, basic_type_from_layout(env, &return_layout));
|
let wrapper_return_type =
|
||||||
|
roc_call_result_type(env, basic_type_from_layout(env, &return_layout));
|
||||||
|
|
||||||
// argument_types.push(wrapper_return_type.ptr_type(AddressSpace::Generic).into());
|
// argument_types.push(wrapper_return_type.ptr_type(AddressSpace::Generic).into());
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::llvm::bitcode::call_void_bitcode_fn;
|
use crate::llvm::bitcode::call_void_bitcode_fn;
|
||||||
use crate::llvm::build::{add_func, get_panic_msg_ptr, C_CALL_CONV};
|
use crate::llvm::build::{add_func, get_panic_msg_ptr, get_panic_tag_ptr, C_CALL_CONV};
|
||||||
use crate::llvm::build::{CCReturn, Env, FunctionSpec};
|
use crate::llvm::build::{CCReturn, Env, FunctionSpec};
|
||||||
use inkwell::module::Linkage;
|
use inkwell::module::Linkage;
|
||||||
use inkwell::types::BasicType;
|
use inkwell::types::BasicType;
|
||||||
|
@ -195,8 +195,7 @@ pub fn add_sjlj_roc_panic(env: &Env<'_, '_, '_>) {
|
||||||
let mut params = fn_val.get_param_iter();
|
let mut params = fn_val.get_param_iter();
|
||||||
let roc_str_arg = params.next().unwrap();
|
let roc_str_arg = params.next().unwrap();
|
||||||
|
|
||||||
// in debug mode, this is assumed to be NullTerminatedString
|
let tag_id_arg = params.next().unwrap();
|
||||||
let _tag_id_arg = params.next().unwrap();
|
|
||||||
|
|
||||||
debug_assert!(params.next().is_none());
|
debug_assert!(params.next().is_none());
|
||||||
|
|
||||||
|
@ -210,6 +209,8 @@ pub fn add_sjlj_roc_panic(env: &Env<'_, '_, '_>) {
|
||||||
|
|
||||||
builder.position_at_end(entry);
|
builder.position_at_end(entry);
|
||||||
|
|
||||||
|
// write our error message to the RocStr pointer
|
||||||
|
{
|
||||||
let loaded_roc_str = match env.target_info.ptr_width() {
|
let loaded_roc_str = match env.target_info.ptr_width() {
|
||||||
roc_target::PtrWidth::Bytes4 => roc_str_arg,
|
roc_target::PtrWidth::Bytes4 => roc_str_arg,
|
||||||
// On 64-bit we pass RocStrs by reference internally
|
// On 64-bit we pass RocStrs by reference internally
|
||||||
|
@ -218,9 +219,28 @@ pub fn add_sjlj_roc_panic(env: &Env<'_, '_, '_>) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// write our error message to the RocStr pointer
|
|
||||||
env.builder
|
env.builder
|
||||||
.build_store(get_panic_msg_ptr(env), loaded_roc_str);
|
.build_store(get_panic_msg_ptr(env), loaded_roc_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the panic tag.
|
||||||
|
// increment by 1, since the tag we'll get from the Roc program is 0-based,
|
||||||
|
// but we use 0 for marking a successful call.
|
||||||
|
{
|
||||||
|
let cast_tag_id = builder.build_int_z_extend(
|
||||||
|
tag_id_arg.into_int_value(),
|
||||||
|
env.context.i64_type(),
|
||||||
|
"zext_panic_tag",
|
||||||
|
);
|
||||||
|
|
||||||
|
let inc_tag_id = builder.build_int_add(
|
||||||
|
cast_tag_id,
|
||||||
|
env.context.i64_type().const_int(1, false),
|
||||||
|
"inc_panic_tag",
|
||||||
|
);
|
||||||
|
|
||||||
|
env.builder.build_store(get_panic_tag_ptr(env), inc_tag_id);
|
||||||
|
}
|
||||||
|
|
||||||
build_longjmp_call(env);
|
build_longjmp_call(env);
|
||||||
|
|
||||||
|
|
|
@ -32,13 +32,13 @@ impl<T: Default> Default for RocCallResult<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Sized> From<RocCallResult<T>> for Result<T, String> {
|
impl<T: Sized> From<RocCallResult<T>> for Result<T, (String, u32)> {
|
||||||
fn from(call_result: RocCallResult<T>) -> Self {
|
fn from(call_result: RocCallResult<T>) -> Self {
|
||||||
match call_result.tag {
|
match call_result.tag {
|
||||||
0 => Ok(unsafe { call_result.value.assume_init() }),
|
0 => Ok(unsafe { call_result.value.assume_init() }),
|
||||||
_ => Err({
|
n => Err({
|
||||||
let msg: &RocStr = unsafe { &*call_result.error_msg };
|
let msg: &RocStr = unsafe { &*call_result.error_msg };
|
||||||
msg.as_str().to_owned()
|
(msg.as_str().to_owned(), (n - 1) as _)
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::helpers::wasm::expect_runtime_error_panic;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
#[should_panic = r#"Roc failed with message: "hello crash""#]
|
#[should_panic = r#"User crash with message: "hello crash""#]
|
||||||
fn crash_literal() {
|
fn crash_literal() {
|
||||||
expect_runtime_error_panic!(indoc!(
|
expect_runtime_error_panic!(indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
@ -21,7 +21,7 @@ fn crash_literal() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
#[should_panic = r#"Roc failed with message: "hello crash""#]
|
#[should_panic = r#"User crash with message: "hello crash""#]
|
||||||
fn crash_variable() {
|
fn crash_variable() {
|
||||||
expect_runtime_error_panic!(indoc!(
|
expect_runtime_error_panic!(indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
@ -36,7 +36,7 @@ fn crash_variable() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
#[should_panic = r#"Roc failed with message: "turns out this was fallible""#]
|
#[should_panic = r#"User crash with message: "turns out this was fallible""#]
|
||||||
fn crash_in_call() {
|
fn crash_in_call() {
|
||||||
expect_runtime_error_panic!(indoc!(
|
expect_runtime_error_panic!(indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
@ -56,7 +56,7 @@ fn crash_in_call() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
#[should_panic = r#"Roc failed with message: "no new even primes""#]
|
#[should_panic = r#"User crash with message: "no new even primes""#]
|
||||||
fn crash_in_passed_closure() {
|
fn crash_in_passed_closure() {
|
||||||
expect_runtime_error_panic!(indoc!(
|
expect_runtime_error_panic!(indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
|
|
@ -544,7 +544,10 @@ macro_rules! assert_wasm_evals_to {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn try_run_lib_function<T>(main_fn_name: &str, lib: &libloading::Library) -> Result<T, String> {
|
pub fn try_run_lib_function<T>(
|
||||||
|
main_fn_name: &str,
|
||||||
|
lib: &libloading::Library,
|
||||||
|
) -> Result<T, (String, u32)> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let main: libloading::Symbol<unsafe extern "C" fn(*mut RocCallResult<T>)> = lib
|
let main: libloading::Symbol<unsafe extern "C" fn(*mut RocCallResult<T>)> = lib
|
||||||
.get(main_fn_name.as_bytes())
|
.get(main_fn_name.as_bytes())
|
||||||
|
@ -594,7 +597,11 @@ macro_rules! assert_llvm_evals_to {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
std::mem::forget(given);
|
std::mem::forget(given);
|
||||||
}
|
}
|
||||||
Err(msg) => panic!("Roc failed with message: \"{}\"", msg),
|
Err((msg, tag)) => match tag {
|
||||||
|
0 => panic!(r#"Roc failed with message: "{}""#, msg),
|
||||||
|
1 => panic!(r#"User crash with message: "{}""#, msg),
|
||||||
|
_ => panic!(r#"Got an invalid panic tag: "{}""#, tag),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// artificially extend the lifetime of `lib`
|
// artificially extend the lifetime of `lib`
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue