mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
Merge pull request #3407 from rtfeldman/dylib-roc-benchmarks
Dylib roc benchmarks
This commit is contained in:
commit
85d87ab431
11 changed files with 330 additions and 129 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -47,3 +47,8 @@ roc_linux_x86_64.tar.gz
|
|||
|
||||
# macOS .DS_Store files
|
||||
.DS_Store
|
||||
|
||||
# files geneated when formatting fails
|
||||
*.roc-format-failed
|
||||
*.roc-format-failed-ast-after
|
||||
*.roc-format-failed-ast-before
|
||||
|
|
60
Cargo.lock
generated
60
Cargo.lock
generated
|
@ -524,7 +524,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"bumpalo",
|
||||
"const_format",
|
||||
"criterion 0.3.5 (git+https://github.com/Anton-4/criterion.rs)",
|
||||
"criterion",
|
||||
"rlimit",
|
||||
"roc_cli",
|
||||
"roc_collections",
|
||||
|
@ -916,32 +916,6 @@ dependencies = [
|
|||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"cast",
|
||||
"clap 2.34.0",
|
||||
"criterion-plot 0.4.4",
|
||||
"csv",
|
||||
"itertools 0.10.3",
|
||||
"lazy_static",
|
||||
"num-traits",
|
||||
"oorandom",
|
||||
"plotters 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_cbor",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"tinytemplate",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion"
|
||||
version = "0.3.5"
|
||||
|
@ -950,13 +924,13 @@ dependencies = [
|
|||
"atty",
|
||||
"cast",
|
||||
"clap 2.34.0",
|
||||
"criterion-plot 0.4.3",
|
||||
"criterion-plot",
|
||||
"csv",
|
||||
"itertools 0.10.3",
|
||||
"lazy_static",
|
||||
"num-traits",
|
||||
"oorandom",
|
||||
"plotters 0.3.1 (git+https://github.com/Anton-4/plotters)",
|
||||
"plotters",
|
||||
"rayon",
|
||||
"regex",
|
||||
"serde",
|
||||
|
@ -976,16 +950,6 @@ dependencies = [
|
|||
"itertools 0.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion-plot"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57"
|
||||
dependencies = [
|
||||
"cast",
|
||||
"itertools 0.10.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam"
|
||||
version = "0.8.1"
|
||||
|
@ -2893,19 +2857,6 @@ version = "0.3.25"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"plotters-backend",
|
||||
"plotters-svg",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.1"
|
||||
|
@ -3471,7 +3422,7 @@ dependencies = [
|
|||
"clap 3.2.8",
|
||||
"cli_utils",
|
||||
"const_format",
|
||||
"criterion 0.3.5 (git+https://github.com/Anton-4/criterion.rs)",
|
||||
"criterion",
|
||||
"errno",
|
||||
"indoc",
|
||||
"libc",
|
||||
|
@ -3877,7 +3828,7 @@ name = "roc_parse"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"criterion 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"criterion",
|
||||
"encode_unicode",
|
||||
"indoc",
|
||||
"pretty_assertions",
|
||||
|
@ -4762,6 +4713,7 @@ name = "test_gen"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"criterion",
|
||||
"either",
|
||||
"indoc",
|
||||
"inkwell 0.1.0",
|
||||
|
|
|
@ -3525,15 +3525,31 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>(
|
|||
|
||||
let mut arguments_for_call = Vec::with_capacity_in(args.len(), env.arena);
|
||||
|
||||
let it = args.iter().zip(roc_function.get_type().get_param_types());
|
||||
for (arg, fastcc_type) in it {
|
||||
let it = args
|
||||
.iter()
|
||||
.zip(roc_function.get_type().get_param_types())
|
||||
.zip(arguments);
|
||||
for ((arg, fastcc_type), layout) in it {
|
||||
let arg_type = arg.get_type();
|
||||
if arg_type == fastcc_type {
|
||||
// the C and Fast calling conventions agree
|
||||
arguments_for_call.push(*arg);
|
||||
} else {
|
||||
let cast = complex_bitcast_check_size(env, *arg, fastcc_type, "to_fastcc_type");
|
||||
arguments_for_call.push(cast);
|
||||
match layout {
|
||||
Layout::Builtin(Builtin::List(_)) => {
|
||||
let loaded = env
|
||||
.builder
|
||||
.build_load(arg.into_pointer_value(), "load_list_pointer");
|
||||
let cast =
|
||||
complex_bitcast_check_size(env, loaded, fastcc_type, "to_fastcc_type_1");
|
||||
arguments_for_call.push(cast);
|
||||
}
|
||||
_ => {
|
||||
let cast =
|
||||
complex_bitcast_check_size(env, *arg, fastcc_type, "to_fastcc_type_1");
|
||||
arguments_for_call.push(cast);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3657,7 +3673,7 @@ fn expose_function_to_host_help_c_abi_v2<'a, 'ctx, 'env>(
|
|||
// the C and Fast calling conventions agree
|
||||
*arg
|
||||
} else {
|
||||
complex_bitcast_check_size(env, *arg, *fastcc_type, "to_fastcc_type")
|
||||
complex_bitcast_check_size(env, *arg, *fastcc_type, "to_fastcc_type_2")
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -12,6 +12,26 @@ pub struct RocCallResult<T> {
|
|||
value: MaybeUninit<T>,
|
||||
}
|
||||
|
||||
impl<T> RocCallResult<T> {
|
||||
pub fn new(value: T) -> Self {
|
||||
Self {
|
||||
tag: 0,
|
||||
error_msg: std::ptr::null_mut(),
|
||||
value: MaybeUninit::new(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> Default for RocCallResult<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
tag: 0,
|
||||
error_msg: std::ptr::null_mut(),
|
||||
value: MaybeUninit::new(Default::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Sized> From<RocCallResult<T>> for Result<T, String> {
|
||||
fn from(call_result: RocCallResult<T>) -> Self {
|
||||
match call_result.tag {
|
||||
|
@ -30,6 +50,29 @@ impl<T: Sized> From<RocCallResult<T>> for Result<T, String> {
|
|||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! run_roc_dylib {
|
||||
($lib:expr, $main_fn_name:expr, $argument_type:ty, $return_type:ty, $errors:expr) => {{
|
||||
use inkwell::context::Context;
|
||||
use roc_builtins::bitcode;
|
||||
use roc_gen_llvm::run_roc::RocCallResult;
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
// NOTE: return value is not first argument currently (may/should change in the future)
|
||||
type Main = unsafe extern "C" fn($argument_type, *mut RocCallResult<$return_type>);
|
||||
|
||||
unsafe {
|
||||
let main: libloading::Symbol<Main> = $lib
|
||||
.get($main_fn_name.as_bytes())
|
||||
.ok()
|
||||
.ok_or(format!("Unable to JIT compile `{}`", $main_fn_name))
|
||||
.expect("errored");
|
||||
|
||||
main
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! run_jit_function {
|
||||
($lib: expr, $main_fn_name: expr, $ty:ty, $transform:expr) => {{
|
||||
|
|
|
@ -16,7 +16,7 @@ bumpalo = { version = "3.8.0", features = ["collections"] }
|
|||
encode_unicode = "0.3.6"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.3.5", features = ["html_reports"] }
|
||||
criterion = { git = "https://github.com/Anton-4/criterion.rs", features = ["html_reports"]}
|
||||
pretty_assertions = "1.0.0"
|
||||
indoc = "1.0.3"
|
||||
quickcheck = "1.0.3"
|
||||
|
|
|
@ -43,6 +43,7 @@ libloading = "0.7.1"
|
|||
wasmer-wasi = "2.2.1"
|
||||
tempfile = "3.2.0"
|
||||
indoc = "1.0.3"
|
||||
criterion = { git = "https://github.com/Anton-4/criterion.rs" }
|
||||
|
||||
# Wasmer singlepass compiler only works on x86_64.
|
||||
[target.'cfg(target_arch = "x86_64")'.dev-dependencies]
|
||||
|
@ -57,3 +58,7 @@ gen-llvm = []
|
|||
gen-dev = []
|
||||
gen-wasm = []
|
||||
wasm-cli-run = []
|
||||
|
||||
[[bench]]
|
||||
name = "list_map"
|
||||
harness = false
|
||||
|
|
119
crates/compiler/test_gen/benches/list_map.rs
Normal file
119
crates/compiler/test_gen/benches/list_map.rs
Normal file
|
@ -0,0 +1,119 @@
|
|||
#[path = "../src/helpers/mod.rs"]
|
||||
mod helpers;
|
||||
|
||||
// defines roc_alloc and friends
|
||||
pub use helpers::platform_functions::*;
|
||||
|
||||
use bumpalo::Bump;
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use roc_gen_llvm::{run_roc::RocCallResult, run_roc_dylib};
|
||||
use roc_mono::ir::OptLevel;
|
||||
use roc_std::RocList;
|
||||
|
||||
// results July 6th, 2022
|
||||
//
|
||||
// roc sum map time: [612.73 ns 614.24 ns 615.98 ns]
|
||||
// roc sum map_with_index time: [5.3177 us 5.3218 us 5.3255 us]
|
||||
// rust (debug) time: [24.081 us 24.163 us 24.268 us]
|
||||
|
||||
type Input = RocList<i64>;
|
||||
type Output = i64;
|
||||
|
||||
type Main<I, O> = unsafe extern "C" fn(I, *mut RocCallResult<O>);
|
||||
|
||||
const ROC_LIST_MAP: &str = indoc::indoc!(
|
||||
r#"
|
||||
app "bench" provides [main] to "./platform"
|
||||
|
||||
main : List I64 -> Nat
|
||||
main = \list ->
|
||||
list
|
||||
|> List.map (\x -> x + 2)
|
||||
|> List.len
|
||||
"#
|
||||
);
|
||||
|
||||
const ROC_LIST_MAP_WITH_INDEX: &str = indoc::indoc!(
|
||||
r#"
|
||||
app "bench" provides [main] to "./platform"
|
||||
|
||||
main : List I64 -> Nat
|
||||
main = \list ->
|
||||
list
|
||||
|> List.mapWithIndex (\x, _ -> x + 2)
|
||||
|> List.len
|
||||
"#
|
||||
);
|
||||
|
||||
fn roc_function<'a, 'b>(
|
||||
arena: &'a Bump,
|
||||
source: &str,
|
||||
) -> libloading::Symbol<'a, Main<&'b Input, Output>> {
|
||||
let config = helpers::llvm::HelperConfig {
|
||||
is_gen_test: true,
|
||||
ignore_problems: false,
|
||||
add_debug_info: true,
|
||||
opt_level: OptLevel::Optimize,
|
||||
};
|
||||
|
||||
let context = inkwell::context::Context::create();
|
||||
let (main_fn_name, errors, lib) =
|
||||
helpers::llvm::helper(arena, config, source, arena.alloc(context));
|
||||
|
||||
assert!(errors.is_empty(), "Encountered errors:\n{}", errors);
|
||||
|
||||
run_roc_dylib!(arena.alloc(lib), main_fn_name, &Input, Output, errors)
|
||||
}
|
||||
|
||||
fn rust_main(argument: &RocList<i64>, output: &mut RocCallResult<i64>) {
|
||||
let mut answer = 0;
|
||||
|
||||
for x in argument.iter() {
|
||||
answer += x;
|
||||
}
|
||||
|
||||
*output = RocCallResult::new(answer);
|
||||
}
|
||||
|
||||
fn create_input_list() -> RocList<i64> {
|
||||
let numbers = Vec::from_iter(0..1_000);
|
||||
|
||||
RocList::from_slice(&numbers)
|
||||
}
|
||||
|
||||
pub fn criterion_benchmark(c: &mut Criterion) {
|
||||
let arena = Bump::new();
|
||||
|
||||
let list_map_with_index_main = roc_function(&arena, ROC_LIST_MAP_WITH_INDEX);
|
||||
let list_map_main = roc_function(&arena, ROC_LIST_MAP);
|
||||
|
||||
let input = &*arena.alloc(create_input_list());
|
||||
|
||||
c.bench_function("roc sum map", |b| {
|
||||
b.iter(|| unsafe {
|
||||
let mut main_result = RocCallResult::default();
|
||||
|
||||
list_map_main(black_box(input), &mut main_result);
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function("roc sum map_with_index", |b| {
|
||||
b.iter(|| unsafe {
|
||||
let mut main_result = RocCallResult::default();
|
||||
|
||||
list_map_with_index_main(black_box(input), &mut main_result);
|
||||
})
|
||||
});
|
||||
|
||||
let input = &*arena.alloc(create_input_list());
|
||||
c.bench_function("rust", |b| {
|
||||
b.iter(|| {
|
||||
let mut main_result = RocCallResult::default();
|
||||
|
||||
rust_main(black_box(input), &mut main_result);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, criterion_benchmark);
|
||||
criterion_main!(benches);
|
|
@ -246,39 +246,84 @@ fn create_llvm_module<'a>(
|
|||
(main_fn_name, delayed_errors.join("\n"), env.module)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct HelperConfig {
|
||||
pub is_gen_test: bool,
|
||||
pub ignore_problems: bool,
|
||||
pub add_debug_info: bool,
|
||||
pub opt_level: OptLevel,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline(never)]
|
||||
pub fn helper<'a>(
|
||||
arena: &'a bumpalo::Bump,
|
||||
config: HelperConfig,
|
||||
src: &str,
|
||||
is_gen_test: bool,
|
||||
ignore_problems: bool,
|
||||
context: &'a inkwell::context::Context,
|
||||
) -> (&'static str, String, Library) {
|
||||
let target = target_lexicon::Triple::host();
|
||||
|
||||
let opt_level = if cfg!(debug_assertions) {
|
||||
OptLevel::Normal
|
||||
} else {
|
||||
OptLevel::Optimize
|
||||
};
|
||||
|
||||
let (main_fn_name, delayed_errors, module) = create_llvm_module(
|
||||
arena,
|
||||
src,
|
||||
is_gen_test,
|
||||
ignore_problems,
|
||||
config.is_gen_test,
|
||||
config.ignore_problems,
|
||||
context,
|
||||
&target,
|
||||
opt_level,
|
||||
config.opt_level,
|
||||
);
|
||||
|
||||
let lib = llvm_module_to_dylib(module, &target, opt_level)
|
||||
.expect("Error loading compiled dylib for test");
|
||||
let res_lib = if config.add_debug_info {
|
||||
let module = annotate_with_debug_info(module, context);
|
||||
llvm_module_to_dylib(&module, &target, config.opt_level)
|
||||
} else {
|
||||
llvm_module_to_dylib(module, &target, config.opt_level)
|
||||
};
|
||||
|
||||
let lib = res_lib.expect("Error loading compiled dylib for test");
|
||||
|
||||
(main_fn_name, delayed_errors, lib)
|
||||
}
|
||||
|
||||
fn annotate_with_debug_info<'ctx>(
|
||||
module: &Module<'ctx>,
|
||||
context: &'ctx inkwell::context::Context,
|
||||
) -> Module<'ctx> {
|
||||
use std::process::Command;
|
||||
|
||||
let app_ll_file = "/tmp/roc-debugir.ll";
|
||||
let app_dbg_ll_file = "/tmp/roc-debugir.dbg.ll";
|
||||
let app_bc_file = "/tmp/roc-debugir.bc";
|
||||
|
||||
// write the ll code to a file, so we can modify it
|
||||
module.print_to_file(&app_ll_file).unwrap();
|
||||
|
||||
// run the debugir https://github.com/vaivaswatha/debugir tool
|
||||
match Command::new("debugir")
|
||||
.args(&["-instnamer", app_ll_file])
|
||||
.output()
|
||||
{
|
||||
Ok(_) => {}
|
||||
Err(error) => {
|
||||
use std::io::ErrorKind;
|
||||
match error.kind() {
|
||||
ErrorKind::NotFound => panic!(
|
||||
r"I could not find the `debugir` tool on the PATH, install it from https://github.com/vaivaswatha/debugir"
|
||||
),
|
||||
_ => panic!("{:?}", error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Command::new("llvm-as")
|
||||
.args(&[app_dbg_ll_file, "-o", app_bc_file])
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
inkwell::module::Module::parse_bitcode_from_path(&app_bc_file, context).unwrap()
|
||||
}
|
||||
|
||||
fn wasm32_target_tripple() -> Triple {
|
||||
use target_lexicon::{Architecture, BinaryFormat};
|
||||
|
||||
|
@ -513,13 +558,26 @@ macro_rules! assert_llvm_evals_to {
|
|||
use bumpalo::Bump;
|
||||
use inkwell::context::Context;
|
||||
use roc_gen_llvm::run_jit_function;
|
||||
use roc_mono::ir::OptLevel;
|
||||
|
||||
let arena = Bump::new();
|
||||
let context = Context::create();
|
||||
|
||||
let is_gen_test = true;
|
||||
let opt_level = if cfg!(debug_assertions) {
|
||||
OptLevel::Normal
|
||||
} else {
|
||||
OptLevel::Optimize
|
||||
};
|
||||
|
||||
let config = $crate::helpers::llvm::HelperConfig {
|
||||
is_gen_test: true,
|
||||
add_debug_info: false,
|
||||
ignore_problems: $ignore_problems,
|
||||
opt_level,
|
||||
};
|
||||
|
||||
let (main_fn_name, errors, lib) =
|
||||
$crate::helpers::llvm::helper(&arena, $src, is_gen_test, $ignore_problems, &context);
|
||||
$crate::helpers::llvm::helper(&arena, config, $src, &context);
|
||||
|
||||
let transform = |success| {
|
||||
let expected = $expected;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
extern crate bumpalo;
|
||||
|
||||
pub mod platform_functions;
|
||||
|
||||
#[cfg(feature = "gen-dev")]
|
||||
pub mod dev;
|
||||
pub mod from_wasmer_memory;
|
||||
|
|
54
crates/compiler/test_gen/src/helpers/platform_functions.rs
Normal file
54
crates/compiler/test_gen/src/helpers/platform_functions.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
use core::ffi::c_void;
|
||||
|
||||
/// # Safety
|
||||
/// The Roc application needs this.
|
||||
#[no_mangle]
|
||||
pub unsafe fn roc_alloc(size: usize, _alignment: u32) -> *mut c_void {
|
||||
libc::malloc(size)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// The Roc application needs this.
|
||||
#[no_mangle]
|
||||
pub unsafe fn roc_memcpy(dest: *mut c_void, src: *const c_void, bytes: usize) -> *mut c_void {
|
||||
libc::memcpy(dest, src, bytes)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// The Roc application needs this.
|
||||
#[no_mangle]
|
||||
pub unsafe 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
|
||||
/// The Roc application needs this.
|
||||
#[no_mangle]
|
||||
pub unsafe fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) {
|
||||
libc::free(c_ptr)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// The Roc application needs this.
|
||||
#[no_mangle]
|
||||
pub unsafe fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||
use roc_gen_llvm::llvm::build::PanicTagId;
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::c_char;
|
||||
|
||||
match PanicTagId::try_from(tag_id) {
|
||||
Ok(PanicTagId::NullTerminatedString) => {
|
||||
let slice = CStr::from_ptr(c_ptr as *const c_char);
|
||||
let string = slice.to_str().unwrap();
|
||||
eprintln!("Roc hit a panic: {}", string);
|
||||
std::process::exit(1);
|
||||
}
|
||||
Err(_) => unreachable!(),
|
||||
}
|
||||
}
|
|
@ -22,57 +22,4 @@ pub mod wasm_str;
|
|||
#[cfg(feature = "gen-wasm")]
|
||||
pub mod wasm_linking;
|
||||
|
||||
use core::ffi::c_void;
|
||||
|
||||
/// # Safety
|
||||
/// The Roc application needs this.
|
||||
#[no_mangle]
|
||||
pub unsafe fn roc_alloc(size: usize, _alignment: u32) -> *mut c_void {
|
||||
libc::malloc(size)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// The Roc application needs this.
|
||||
#[no_mangle]
|
||||
pub unsafe fn roc_memcpy(dest: *mut c_void, src: *const c_void, bytes: usize) -> *mut c_void {
|
||||
libc::memcpy(dest, src, bytes)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// The Roc application needs this.
|
||||
#[no_mangle]
|
||||
pub unsafe 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
|
||||
/// The Roc application needs this.
|
||||
#[no_mangle]
|
||||
pub unsafe fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) {
|
||||
libc::free(c_ptr)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// The Roc application needs this.
|
||||
#[no_mangle]
|
||||
pub unsafe fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||
use roc_gen_llvm::llvm::build::PanicTagId;
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::c_char;
|
||||
|
||||
match PanicTagId::try_from(tag_id) {
|
||||
Ok(PanicTagId::NullTerminatedString) => {
|
||||
let slice = CStr::from_ptr(c_ptr as *const c_char);
|
||||
let string = slice.to_str().unwrap();
|
||||
eprintln!("Roc hit a panic: {}", string);
|
||||
std::process::exit(1);
|
||||
}
|
||||
Err(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
pub use helpers::platform_functions::*;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue