diff --git a/crates/compiler/gen_llvm/src/llvm/build.rs b/crates/compiler/gen_llvm/src/llvm/build.rs index 0f7d37b30d..3d1d5658b3 100644 --- a/crates/compiler/gen_llvm/src/llvm/build.rs +++ b/crates/compiler/gen_llvm/src/llvm/build.rs @@ -344,7 +344,7 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> { ) } - pub fn call_panic(&self, message: PointerValue<'ctx>, tag_id: PanicTagId) { + pub fn call_panic(&self, message: BasicValueEnum<'ctx>, tag_id: PanicTagId) { let function = self.module.get_function("roc_panic").unwrap(); let tag_id = self .context @@ -2626,7 +2626,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( } roc_target::PtrWidth::Bytes4 => { // temporary WASM implementation - throw_exception(env, "An expectation failed!"); + throw_exception(env, parent, "An expectation failed!"); } } } else { @@ -2688,7 +2688,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( } roc_target::PtrWidth::Bytes4 => { // temporary WASM implementation - throw_exception(env, "An expectation failed!"); + throw_exception(env, parent, "An expectation failed!"); } } } else { @@ -2709,7 +2709,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( } RuntimeError(error_msg) => { - throw_exception(env, error_msg); + throw_exception(env, parent, error_msg); // unused value (must return a BasicValue) let zero = env.context.i64_type().const_zero(); @@ -3867,14 +3867,14 @@ pub fn build_setjmp_call<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValu } } -/// Pointer to pointer of the panic message. +/// Pointer to RocStr which is the panic message. pub fn get_panic_msg_ptr<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> PointerValue<'ctx> { - let ptr_to_u8_ptr = env.context.i8_type().ptr_type(AddressSpace::Generic); + let str_typ = zig_str_type(env); - let global_name = "roc_panic_msg_ptr"; + let global_name = "roc_panic_msg_str"; let global = env.module.get_global(global_name).unwrap_or_else(|| { - let global = env.module.add_global(ptr_to_u8_ptr, None, global_name); - global.set_initializer(&ptr_to_u8_ptr.const_zero()); + let global = env.module.add_global(str_typ, None, global_name); + global.set_initializer(&str_typ.const_zero()); global }); @@ -3927,12 +3927,10 @@ fn set_jump_and_catch_long_jump<'a, 'ctx, 'env>( { builder.position_at_end(catch_block); - let error_msg = { - // u8** - let ptr_int_ptr = get_panic_msg_ptr(env); - - // u8* again - builder.build_load(ptr_int_ptr, "ptr_int") + let error_msg_ptr = { + // RocStr* global + let ptr_roc_str = get_panic_msg_ptr(env); + ptr_roc_str }; let return_value = { @@ -3946,7 +3944,7 @@ fn set_jump_and_catch_long_jump<'a, 'ctx, 'env>( .unwrap(); let v3 = builder - .build_insert_value(v2, error_msg, 1, "set_exception") + .build_insert_value(v2, error_msg_ptr, 1, "set_exception") .unwrap(); v3 }; @@ -5549,23 +5547,16 @@ fn define_global_error_str<'a, 'ctx, 'env>( } } -pub(crate) fn throw_exception<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>, message: &str) { +pub(crate) fn throw_exception<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + parent: FunctionValue<'ctx>, + message: &str, +) { let builder = env.builder; - // define the error message as a global - // (a hash is used such that the same value is not defined repeatedly) - let error_msg_global = define_global_error_str(env, message); + let str = build_string_literal(env, parent, message); - let cast = env - .builder - .build_bitcast( - error_msg_global.as_pointer_value(), - env.context.i8_type().ptr_type(AddressSpace::Generic), - "cast_void", - ) - .into_pointer_value(); - - env.call_panic(cast, PanicTagId::NullTerminatedString); + env.call_panic(str, PanicTagId::NullTerminatedString); builder.build_unreachable(); } diff --git a/crates/compiler/gen_llvm/src/llvm/externs.rs b/crates/compiler/gen_llvm/src/llvm/externs.rs index 42f386ba60..1bd60d808c 100644 --- a/crates/compiler/gen_llvm/src/llvm/externs.rs +++ b/crates/compiler/gen_llvm/src/llvm/externs.rs @@ -193,7 +193,7 @@ pub fn add_sjlj_roc_panic(env: &Env<'_, '_, '_>) { // already been defined by the builtins, which rely on it. let fn_val = module.get_function("roc_panic").unwrap(); let mut params = fn_val.get_param_iter(); - let ptr_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(); @@ -210,8 +210,17 @@ pub fn add_sjlj_roc_panic(env: &Env<'_, '_, '_>) { builder.position_at_end(entry); - // write our error message pointer - env.builder.build_store(get_panic_msg_ptr(env), ptr_arg); + let loaded_roc_str = match env.target_info.ptr_width() { + roc_target::PtrWidth::Bytes4 => roc_str_arg, + // On 64-bit we pass RocStrs by reference internally + roc_target::PtrWidth::Bytes8 => { + builder.build_load(roc_str_arg.into_pointer_value(), "load_roc_str") + } + }; + + // write our error message to the RocStr pointer + env.builder + .build_store(get_panic_msg_ptr(env), loaded_roc_str); build_longjmp_call(env); diff --git a/crates/compiler/gen_llvm/src/llvm/lowlevel.rs b/crates/compiler/gen_llvm/src/llvm/lowlevel.rs index acc3c1efbe..9edd6ee0fb 100644 --- a/crates/compiler/gen_llvm/src/llvm/lowlevel.rs +++ b/crates/compiler/gen_llvm/src/llvm/lowlevel.rs @@ -1557,7 +1557,7 @@ fn throw_on_overflow<'a, 'ctx, 'env>( bd.position_at_end(throw_block); - throw_exception(env, message); + throw_exception(env, parent, message); bd.position_at_end(then_block); @@ -2005,6 +2005,7 @@ fn int_neg_raise_on_overflow<'a, 'ctx, 'env>( throw_exception( env, + parent, "integer negation overflowed because its argument is the minimum value", ); @@ -2035,6 +2036,7 @@ fn int_abs_raise_on_overflow<'a, 'ctx, 'env>( throw_exception( env, + parent, "integer absolute overflowed because its argument is the minimum value", ); diff --git a/crates/compiler/gen_llvm/src/run_roc.rs b/crates/compiler/gen_llvm/src/run_roc.rs index d4954c7e5f..5687f7eda1 100644 --- a/crates/compiler/gen_llvm/src/run_roc.rs +++ b/crates/compiler/gen_llvm/src/run_roc.rs @@ -2,13 +2,15 @@ use std::ffi::CStr; use std::mem::MaybeUninit; use std::os::raw::c_char; +use roc_std::RocStr; + /// This must have the same size as the repr() of RocCallResult! pub const ROC_CALL_RESULT_DISCRIMINANT_SIZE: usize = std::mem::size_of::(); #[repr(C)] pub struct RocCallResult { tag: u64, - error_msg: *mut c_char, + error_msg: *mut RocStr, value: MaybeUninit, } @@ -37,9 +39,8 @@ impl From> for Result { match call_result.tag { 0 => Ok(unsafe { call_result.value.assume_init() }), _ => Err({ - let raw = unsafe { CStr::from_ptr(call_result.error_msg) }; - - raw.to_str().unwrap().to_owned() + let msg: &RocStr = unsafe { &*call_result.error_msg }; + msg.as_str().to_owned() }), } }