diff --git a/crates/compiler/gen_llvm/src/llvm/externs.rs b/crates/compiler/gen_llvm/src/llvm/externs.rs index 6bf96f83d3..bdfebdc7ff 100644 --- a/crates/compiler/gen_llvm/src/llvm/externs.rs +++ b/crates/compiler/gen_llvm/src/llvm/externs.rs @@ -41,6 +41,8 @@ pub fn add_default_roc_externs(env: &Env<'_, '_, '_>) { // The type of this function (but not the implementation) should have // already been defined by the builtins, which rely on it. let fn_val = module.get_function("roc_alloc").unwrap(); + fn_val.set_linkage(Linkage::Internal); + let mut params = fn_val.get_param_iter(); let size_arg = params.next().unwrap(); let _alignment_arg = params.next().unwrap(); @@ -135,6 +137,8 @@ pub fn add_default_roc_externs(env: &Env<'_, '_, '_>) { // The type of this function (but not the implementation) should have // already been defined by the builtins, which rely on it. let fn_val = module.get_function("roc_dealloc").unwrap(); + fn_val.set_linkage(Linkage::Internal); + let mut params = fn_val.get_param_iter(); let ptr_arg = params.next().unwrap(); let _alignment_arg = params.next().unwrap(); diff --git a/crates/glue/src/lib.rs b/crates/glue/src/lib.rs index f1d0fbeac2..ab707d978c 100644 --- a/crates/glue/src/lib.rs +++ b/crates/glue/src/lib.rs @@ -4,7 +4,6 @@ //! the plan is to support any language via a plugin model. pub mod enums; pub mod load; -pub mod roc_helpers; pub mod roc_type; pub mod rust_glue; pub mod structs; @@ -14,3 +13,34 @@ pub mod types; pub mod glue; pub use load::generate; + +// required because we use roc_std here +mod roc_externs { + use core::ffi::c_void; + + /// # Safety + /// This just delegates to libc::malloc, so it's equally safe. + #[no_mangle] + pub unsafe extern "C" fn roc_alloc(size: usize, _alignment: u32) -> *mut c_void { + libc::malloc(size) + } + + /// # Safety + /// This just delegates to libc::realloc, so it's equally safe. + #[no_mangle] + pub unsafe extern "C" fn roc_realloc( + c_ptr: *mut c_void, + new_size: usize, + _old_size: usize, + _alignment: u32, + ) -> *mut c_void { + libc::realloc(c_ptr, new_size) + } + + /// # Safety + /// This just delegates to libc::free, so it's equally safe. + #[no_mangle] + pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { + libc::free(c_ptr) + } +} diff --git a/crates/glue/src/roc_helpers.rs b/crates/glue/src/roc_helpers.rs deleted file mode 100644 index 3e117ad667..0000000000 --- a/crates/glue/src/roc_helpers.rs +++ /dev/null @@ -1,234 +0,0 @@ -use libc::{c_char, c_int, c_void, size_t}; -#[cfg(unix)] -use libc::{c_uint, mode_t, off_t, pid_t}; - -use roc_std::RocStr; - -// These are required to ensure rust adds these functions to the final binary even though they are never used. -#[used] -pub static ROC_ALLOC: unsafe extern "C" fn(usize, u32) -> *mut c_void = roc_alloc; - -#[used] -pub static ROC_REALLOC: unsafe extern "C" fn(*mut c_void, usize, usize, u32) -> *mut c_void = - roc_realloc; - -#[used] -pub static ROC_DEALLOC: unsafe extern "C" fn(*mut c_void, u32) = roc_dealloc; - -#[used] -pub static ROC_PANIC: unsafe extern "C" fn(&RocStr, u32) = roc_panic; - -#[cfg(unix)] -#[used] -pub static ROC_GETPPID: unsafe extern "C" fn() -> pid_t = roc_getppid; - -#[cfg(unix)] -#[used] -pub static ROC_MMAP: unsafe extern "C" fn( - *mut c_void, - size_t, - c_int, - c_int, - c_int, - off_t, -) -> *mut c_void = roc_mmap; - -#[cfg(unix)] -#[used] -pub static ROC_SHM_OPEN: unsafe extern "C" fn(*const c_char, c_int, mode_t) -> c_int = roc_shm_open; - -#[used] -pub static ROC_MEMCPY: unsafe extern "C" fn(*mut c_void, *mut c_void, usize) -> *mut c_void = - roc_memcpy; - -#[used] -pub static ROC_MEMSET: unsafe extern "C" fn(*mut c_void, i32, usize) -> *mut c_void = roc_memset; - -/// # Safety -/// This just delegates to libc::malloc, so it's equally safe. -#[no_mangle] -pub unsafe extern "C" fn roc_alloc(size: usize, _alignment: u32) -> *mut c_void { - libc::malloc(size) -} - -/// # Safety -/// This just delegates to libc::realloc, so it's equally safe. -#[no_mangle] -pub unsafe extern "C" fn roc_realloc( - c_ptr: *mut c_void, - new_size: usize, - _old_size: usize, - _alignment: u32, -) -> *mut c_void { - libc::realloc(c_ptr, new_size) -} - -/// # Safety -/// This just delegates to libc::free, so it's equally safe. -#[no_mangle] -pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { - libc::free(c_ptr) -} - -#[no_mangle] -pub extern "C" fn roc_panic(msg: &RocStr, tag_id: u32) { - match tag_id { - 0 => { - eprintln!("Roc crashed with:\n\n\t{}\n", msg.as_str()); - - print_backtrace(); - std::process::exit(1); - } - 1 => { - eprintln!("The program crashed with:\n\n\t{}\n", msg.as_str()); - - print_backtrace(); - std::process::exit(1); - } - code => { - eprintln!("Roc crashed with error code:\n\n\t{}\n", code); - - print_backtrace(); - std::process::exit(1); - } - } -} - -#[cfg(unix)] -#[no_mangle] -pub extern "C" fn roc_getppid() -> pid_t { - unsafe { libc::getppid() } -} - -/// # Safety -/// This just delegates to libc::mmap, and so is equally safe. -#[cfg(unix)] -#[no_mangle] -pub unsafe extern "C" fn roc_mmap( - addr: *mut c_void, - len: size_t, - prot: c_int, - flags: c_int, - fd: c_int, - offset: off_t, -) -> *mut c_void { - libc::mmap(addr, len, prot, flags, fd, offset) -} - -/// # Safety -/// This just delegates to libc::shm_open, and so is equally safe. -#[cfg(unix)] -#[no_mangle] -pub unsafe extern "C" fn roc_shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int { - libc::shm_open(name, oflag, mode as c_uint) -} - -fn print_backtrace() { - eprintln!("Here is the call stack that led to the crash:\n"); - - let mut entries = Vec::new(); - - #[derive(Default)] - struct Entry { - pub fn_name: String, - pub filename: Option, - pub line: Option, - pub col: Option, - } - - backtrace::trace(|frame| { - backtrace::resolve_frame(frame, |symbol| { - if let Some(fn_name) = symbol.name() { - let fn_name = fn_name.to_string(); - - if should_show_in_backtrace(&fn_name) { - let mut entry: Entry = Entry { - fn_name: format_fn_name(&fn_name), - ..Default::default() - }; - - if let Some(path) = symbol.filename() { - entry.filename = Some(path.to_string_lossy().into_owned()); - }; - - entry.line = symbol.lineno(); - entry.col = symbol.colno(); - - entries.push(entry); - } - } else { - entries.push(Entry { - fn_name: "???".to_string(), - ..Default::default() - }); - } - }); - - true // keep going to the next frame - }); - - for entry in entries { - eprintln!("\t{}", entry.fn_name); - - if let Some(filename) = entry.filename { - eprintln!("\t\t{filename}"); - } - } - - eprintln!("\nOptimizations can make this list inaccurate! If it looks wrong, try running without `--optimize` and with `--linker=legacy`\n"); -} - -fn should_show_in_backtrace(fn_name: &str) -> bool { - let is_from_rust = fn_name.contains("::"); - let is_host_fn = fn_name.starts_with("roc_panic") - || fn_name.starts_with("_Effect_effect") - || fn_name.starts_with("_roc__") - || fn_name.starts_with("rust_main") - || fn_name == "_main"; - - !is_from_rust && !is_host_fn -} - -fn format_fn_name(fn_name: &str) -> String { - // e.g. convert "_Num_sub_a0c29024d3ec6e3a16e414af99885fbb44fa6182331a70ab4ca0886f93bad5" - // to ["Num", "sub", "a0c29024d3ec6e3a16e414af99885fbb44fa6182331a70ab4ca0886f93bad5"] - let mut pieces_iter = fn_name.split('_'); - - if let (_, Some(module_name), Some(name)) = - (pieces_iter.next(), pieces_iter.next(), pieces_iter.next()) - { - display_roc_fn(module_name, name) - } else { - "???".to_string() - } -} - -fn display_roc_fn(module_name: &str, fn_name: &str) -> String { - let module_name = if module_name == "#UserApp" { - "app" - } else { - module_name - }; - - let fn_name = if fn_name.parse::().is_ok() { - "(anonymous function)" - } else { - fn_name - }; - - format!("\u{001B}[36m{module_name}\u{001B}[39m.{fn_name}") -} - -/// # Safety -/// This just delegates to libc::memcpy, so it's equally safe. -#[no_mangle] -pub unsafe extern "C" fn roc_memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void { - libc::memcpy(dst, src, n) -} - -/// # Safety -/// This just delegates to libc::memset, so it's equally safe. -#[no_mangle] -pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void { - libc::memset(dst, c, n) -}