mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-22 08:17:40 +03:00
Merge pull request #4220 from roc-lang/roc-dev-inline-expects
Roc dev inline expects
This commit is contained in:
commit
0a37431f36
1
.github/workflows/markdown_link_check.yml
vendored
1
.github/workflows/markdown_link_check.yml
vendored
@ -18,6 +18,7 @@ jobs:
|
||||
with:
|
||||
use-quiet-mode: 'yes'
|
||||
use-verbose-mode: 'yes'
|
||||
check-modified-files-only: 'yes'
|
||||
base-branch: 'main'
|
||||
check-modified-files-only: 'yes'
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -3413,6 +3413,7 @@ dependencies = [
|
||||
"roc_fmt",
|
||||
"roc_gen_llvm",
|
||||
"roc_glue",
|
||||
"roc_intern",
|
||||
"roc_linker",
|
||||
"roc_load",
|
||||
"roc_module",
|
||||
@ -3960,6 +3961,7 @@ dependencies = [
|
||||
"roc_builtins",
|
||||
"roc_can",
|
||||
"roc_collections",
|
||||
"roc_error_macros",
|
||||
"roc_gen_llvm",
|
||||
"roc_intern",
|
||||
"roc_load",
|
||||
|
@ -60,6 +60,7 @@ roc_editor = { path = "../editor", optional = true }
|
||||
roc_linker = { path = "../linker" }
|
||||
roc_repl_cli = { path = "../repl_cli", optional = true }
|
||||
roc_tracing = { path = "../tracing" }
|
||||
roc_intern = { path = "../compiler/intern" }
|
||||
clap = { version = "3.2.20", default-features = false, features = ["std", "color", "suggestions"] }
|
||||
const_format = { version = "0.2.23", features = ["const_generics"] }
|
||||
bumpalo = { version = "3.11.0", features = ["collections"] }
|
||||
|
@ -1,15 +1,13 @@
|
||||
use bumpalo::Bump;
|
||||
use roc_build::{
|
||||
link::{link, preprocess_host_wasm32, rebuild_host, LinkType, LinkingStrategy},
|
||||
program::{self, Problems},
|
||||
program::{self, CodeGenOptions, Problems},
|
||||
};
|
||||
use roc_builtins::bitcode;
|
||||
use roc_collections::VecMap;
|
||||
use roc_load::{
|
||||
EntryPoint, ExecutionMode, Expectations, LoadConfig, LoadMonomorphizedError, LoadedModule,
|
||||
EntryPoint, ExecutionMode, ExpectMetadata, LoadConfig, LoadMonomorphizedError, LoadedModule,
|
||||
LoadingProblem, Threading,
|
||||
};
|
||||
use roc_module::symbol::{Interns, ModuleId};
|
||||
use roc_mono::ir::OptLevel;
|
||||
use roc_reporting::report::RenderTarget;
|
||||
use roc_target::TargetInfo;
|
||||
@ -30,12 +28,11 @@ fn report_timing(buf: &mut String, label: &str, duration: Duration) {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub struct BuiltFile {
|
||||
pub struct BuiltFile<'a> {
|
||||
pub binary_path: PathBuf,
|
||||
pub problems: Problems,
|
||||
pub total_time: Duration,
|
||||
pub expectations: VecMap<ModuleId, Expectations>,
|
||||
pub interns: Interns,
|
||||
pub expect_metadata: ExpectMetadata<'a>,
|
||||
}
|
||||
|
||||
pub enum BuildOrdering {
|
||||
@ -60,8 +57,7 @@ pub fn build_file<'a>(
|
||||
arena: &'a Bump,
|
||||
target: &Triple,
|
||||
app_module_path: PathBuf,
|
||||
opt_level: OptLevel,
|
||||
emit_debug_info: bool,
|
||||
code_gen_options: CodeGenOptions,
|
||||
emit_timings: bool,
|
||||
link_type: LinkType,
|
||||
linking_strategy: LinkingStrategy,
|
||||
@ -69,7 +65,7 @@ pub fn build_file<'a>(
|
||||
threading: Threading,
|
||||
wasm_dev_stack_bytes: Option<u32>,
|
||||
order: BuildOrdering,
|
||||
) -> Result<BuiltFile, BuildFileError<'a>> {
|
||||
) -> Result<BuiltFile<'a>, BuildFileError<'a>> {
|
||||
let compilation_start = Instant::now();
|
||||
let target_info = TargetInfo::from(target);
|
||||
|
||||
@ -121,7 +117,7 @@ pub fn build_file<'a>(
|
||||
|
||||
match roc_target::OperatingSystem::from(target.operating_system) {
|
||||
Wasi => {
|
||||
if matches!(opt_level, OptLevel::Development) {
|
||||
if matches!(code_gen_options.opt_level, OptLevel::Development) {
|
||||
("wasm", "wasm", Some("wasm"))
|
||||
} else {
|
||||
("zig", "bc", Some("wasm"))
|
||||
@ -180,7 +176,7 @@ pub fn build_file<'a>(
|
||||
};
|
||||
|
||||
let rebuild_thread = spawn_rebuild_thread(
|
||||
opt_level,
|
||||
code_gen_options.opt_level,
|
||||
linking_strategy,
|
||||
prebuilt,
|
||||
host_input_path.clone(),
|
||||
@ -241,11 +237,8 @@ pub fn build_file<'a>(
|
||||
// inside a nested scope without causing a borrow error!
|
||||
let mut loaded = loaded;
|
||||
let problems = program::report_problems_monomorphized(&mut loaded);
|
||||
let expectations = std::mem::take(&mut loaded.expectations);
|
||||
let loaded = loaded;
|
||||
|
||||
let interns = loaded.interns.clone();
|
||||
|
||||
enum HostRebuildTiming {
|
||||
BeforeApp(u128),
|
||||
ConcurrentWithApp(JoinHandle<u128>),
|
||||
@ -266,13 +259,12 @@ pub fn build_file<'a>(
|
||||
HostRebuildTiming::ConcurrentWithApp(rebuild_thread)
|
||||
};
|
||||
|
||||
let (roc_app_bytes, code_gen_timing) = program::gen_from_mono_module(
|
||||
let (roc_app_bytes, code_gen_timing, expect_metadata) = program::gen_from_mono_module(
|
||||
arena,
|
||||
loaded,
|
||||
&app_module_path,
|
||||
target,
|
||||
opt_level,
|
||||
emit_debug_info,
|
||||
code_gen_options,
|
||||
&preprocessed_host_path,
|
||||
wasm_dev_stack_bytes,
|
||||
);
|
||||
@ -351,7 +343,7 @@ pub fn build_file<'a>(
|
||||
|
||||
let str_host_obj_path = bitcode::get_builtins_host_obj_path();
|
||||
|
||||
if matches!(opt_level, OptLevel::Development) {
|
||||
if matches!(code_gen_options.backend, program::CodeGenBackend::Assembly) {
|
||||
inputs.push(&str_host_obj_path);
|
||||
}
|
||||
|
||||
@ -388,8 +380,7 @@ pub fn build_file<'a>(
|
||||
binary_path,
|
||||
problems,
|
||||
total_time,
|
||||
interns,
|
||||
expectations,
|
||||
expect_metadata,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -7,11 +7,9 @@ use build::BuiltFile;
|
||||
use bumpalo::Bump;
|
||||
use clap::{Arg, ArgMatches, Command, ValueSource};
|
||||
use roc_build::link::{LinkType, LinkingStrategy};
|
||||
use roc_build::program::Problems;
|
||||
use roc_collections::VecMap;
|
||||
use roc_build::program::{CodeGenBackend, CodeGenOptions, Problems};
|
||||
use roc_error_macros::{internal_error, user_error};
|
||||
use roc_load::{Expectations, LoadingProblem, Threading};
|
||||
use roc_module::symbol::{Interns, ModuleId};
|
||||
use roc_load::{ExpectMetadata, LoadingProblem, Threading};
|
||||
use roc_mono::ir::OptLevel;
|
||||
use std::env;
|
||||
use std::ffi::{CString, OsStr};
|
||||
@ -432,7 +430,7 @@ pub fn test(matches: &ArgMatches, triple: Triple) -> io::Result<i32> {
|
||||
|
||||
let mut writer = std::io::stdout();
|
||||
|
||||
let (failed, passed) = roc_repl_expect::run::run_expects(
|
||||
let (failed, passed) = roc_repl_expect::run::run_toplevel_expects(
|
||||
&mut writer,
|
||||
roc_reporting::report::RenderTarget::ColorTerminal,
|
||||
arena,
|
||||
@ -481,18 +479,33 @@ pub fn build(
|
||||
use build::build_file;
|
||||
use BuildConfig::*;
|
||||
|
||||
let arena = Bump::new();
|
||||
let filename = matches.value_of_os(ROC_FILE).unwrap();
|
||||
let opt_level = match (
|
||||
matches.is_present(FLAG_OPTIMIZE),
|
||||
matches.is_present(FLAG_OPT_SIZE),
|
||||
matches.is_present(FLAG_DEV),
|
||||
) {
|
||||
(true, false, false) => OptLevel::Optimize,
|
||||
(false, true, false) => OptLevel::Size,
|
||||
(false, false, true) => OptLevel::Development,
|
||||
(false, false, false) => OptLevel::Normal,
|
||||
_ => user_error!("build can be only one of `--dev`, `--optimize`, or `--opt-size`"),
|
||||
// the process will end after this function,
|
||||
// so we don't want to spend time freeing these values
|
||||
let arena = ManuallyDrop::new(Bump::new());
|
||||
|
||||
let code_gen_backend = if matches!(triple.architecture, Architecture::Wasm32) {
|
||||
CodeGenBackend::Wasm
|
||||
} else {
|
||||
match matches.is_present(FLAG_DEV) {
|
||||
true => CodeGenBackend::Assembly,
|
||||
false => CodeGenBackend::Llvm,
|
||||
}
|
||||
};
|
||||
|
||||
let opt_level = if let BuildConfig::BuildAndRunIfNoErrors = config {
|
||||
OptLevel::Development
|
||||
} else {
|
||||
match (
|
||||
matches.is_present(FLAG_OPTIMIZE),
|
||||
matches.is_present(FLAG_OPT_SIZE),
|
||||
) {
|
||||
(true, false) => OptLevel::Optimize,
|
||||
(false, true) => OptLevel::Size,
|
||||
(false, false) => OptLevel::Normal,
|
||||
(true, true) => {
|
||||
user_error!("build can be only one of `--optimize` and `--opt-size`")
|
||||
}
|
||||
}
|
||||
};
|
||||
let emit_debug_info = matches.is_present(FLAG_DEBUG);
|
||||
let emit_timings = matches.is_present(FLAG_TIME);
|
||||
@ -508,7 +521,7 @@ pub fn build(
|
||||
};
|
||||
|
||||
let wasm_dev_backend = matches!(opt_level, OptLevel::Development)
|
||||
&& matches!(triple.architecture, Architecture::Wasm32);
|
||||
&& matches!(code_gen_backend, CodeGenBackend::Wasm);
|
||||
|
||||
let linking_strategy = if wasm_dev_backend {
|
||||
LinkingStrategy::Additive
|
||||
@ -528,6 +541,8 @@ pub fn build(
|
||||
// We make an exception for Wasm, because cross-compiling is the norm in that case.
|
||||
triple != Triple::host() && !matches!(triple.architecture, Architecture::Wasm32)
|
||||
};
|
||||
|
||||
let filename = matches.value_of_os(ROC_FILE).unwrap();
|
||||
let path = Path::new(filename);
|
||||
|
||||
// Spawn the root task
|
||||
@ -559,12 +574,18 @@ pub fn build(
|
||||
BuildAndRunIfNoErrors => BuildOrdering::BuildIfChecks,
|
||||
_ => BuildOrdering::AlwaysBuild,
|
||||
};
|
||||
|
||||
let code_gen_options = CodeGenOptions {
|
||||
backend: code_gen_backend,
|
||||
opt_level,
|
||||
emit_debug_info,
|
||||
};
|
||||
|
||||
let res_binary_path = build_file(
|
||||
&arena,
|
||||
&triple,
|
||||
path.to_path_buf(),
|
||||
opt_level,
|
||||
emit_debug_info,
|
||||
code_gen_options,
|
||||
emit_timings,
|
||||
link_type,
|
||||
linking_strategy,
|
||||
@ -579,8 +600,7 @@ pub fn build(
|
||||
binary_path,
|
||||
problems,
|
||||
total_time,
|
||||
expectations,
|
||||
interns,
|
||||
expect_metadata,
|
||||
}) => {
|
||||
match config {
|
||||
BuildOnly => {
|
||||
@ -593,7 +613,7 @@ pub fn build(
|
||||
|
||||
// No need to waste time freeing this memory,
|
||||
// since the process is about to exit anyway.
|
||||
std::mem::forget(arena);
|
||||
// std::mem::forget(arena);
|
||||
|
||||
print_problems(problems, total_time);
|
||||
println!(" while successfully building:\n\n {generated_filename}");
|
||||
@ -616,7 +636,7 @@ pub fn build(
|
||||
// ManuallyDrop will leak the bytes because we don't drop manually
|
||||
let bytes = &ManuallyDrop::new(std::fs::read(&binary_path).unwrap());
|
||||
|
||||
roc_run(arena, opt_level, triple, args, bytes, expectations, interns)
|
||||
roc_run(&arena, opt_level, triple, args, bytes, expect_metadata)
|
||||
}
|
||||
BuildAndRunIfNoErrors => {
|
||||
debug_assert!(
|
||||
@ -637,7 +657,7 @@ pub fn build(
|
||||
// ManuallyDrop will leak the bytes because we don't drop manually
|
||||
let bytes = &ManuallyDrop::new(std::fs::read(&binary_path).unwrap());
|
||||
|
||||
roc_run(arena, opt_level, triple, args, bytes, expectations, interns)
|
||||
roc_run(&arena, opt_level, triple, args, bytes, expect_metadata)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -703,13 +723,12 @@ fn print_problems(problems: Problems, total_time: std::time::Duration) {
|
||||
}
|
||||
|
||||
fn roc_run<'a, I: IntoIterator<Item = &'a OsStr>>(
|
||||
arena: Bump, // This should be passed an owned value, not a reference, so we can usefully mem::forget it!
|
||||
arena: &Bump,
|
||||
opt_level: OptLevel,
|
||||
triple: Triple,
|
||||
args: I,
|
||||
binary_bytes: &[u8],
|
||||
expectations: VecMap<ModuleId, Expectations>,
|
||||
interns: Interns,
|
||||
expect_metadata: ExpectMetadata,
|
||||
) -> io::Result<i32> {
|
||||
match triple.architecture {
|
||||
Architecture::Wasm32 => {
|
||||
@ -720,10 +739,6 @@ fn roc_run<'a, I: IntoIterator<Item = &'a OsStr>>(
|
||||
.strip_prefix(env::current_dir().unwrap())
|
||||
.unwrap_or(path);
|
||||
|
||||
// No need to waste time freeing this memory,
|
||||
// since the process is about to exit anyway.
|
||||
std::mem::forget(arena);
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
{
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
@ -748,7 +763,7 @@ fn roc_run<'a, I: IntoIterator<Item = &'a OsStr>>(
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
_ => roc_run_native(arena, opt_level, args, binary_bytes, expectations, interns),
|
||||
_ => roc_run_native(arena, opt_level, args, binary_bytes, expect_metadata),
|
||||
}
|
||||
}
|
||||
|
||||
@ -848,35 +863,32 @@ fn make_argv_envp_windows<'a, I: IntoIterator<Item = S>, S: AsRef<OsStr>>(
|
||||
/// Run on the native OS (not on wasm)
|
||||
#[cfg(target_family = "unix")]
|
||||
fn roc_run_native<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(
|
||||
arena: Bump,
|
||||
arena: &Bump,
|
||||
opt_level: OptLevel,
|
||||
args: I,
|
||||
binary_bytes: &[u8],
|
||||
expectations: VecMap<ModuleId, Expectations>,
|
||||
interns: Interns,
|
||||
expect_metadata: ExpectMetadata,
|
||||
) -> std::io::Result<i32> {
|
||||
use bumpalo::collections::CollectIn;
|
||||
|
||||
unsafe {
|
||||
let executable = roc_run_executable_file_path(binary_bytes)?;
|
||||
let (argv_cstrings, envp_cstrings) = make_argv_envp(&arena, &executable, args);
|
||||
let (argv_cstrings, envp_cstrings) = make_argv_envp(arena, &executable, args);
|
||||
|
||||
let argv: bumpalo::collections::Vec<*const c_char> = argv_cstrings
|
||||
.iter()
|
||||
.map(|s| s.as_ptr())
|
||||
.chain([std::ptr::null()])
|
||||
.collect_in(&arena);
|
||||
.collect_in(arena);
|
||||
|
||||
let envp: bumpalo::collections::Vec<*const c_char> = envp_cstrings
|
||||
.iter()
|
||||
.map(|s| s.as_ptr())
|
||||
.chain([std::ptr::null()])
|
||||
.collect_in(&arena);
|
||||
.collect_in(arena);
|
||||
|
||||
match opt_level {
|
||||
OptLevel::Development => {
|
||||
roc_run_native_debug(executable, &argv, &envp, expectations, interns)
|
||||
}
|
||||
OptLevel::Development => roc_dev_native(arena, executable, argv, envp, expect_metadata),
|
||||
OptLevel::Normal | OptLevel::Size | OptLevel::Optimize => {
|
||||
roc_run_native_fast(executable, &argv, &envp);
|
||||
}
|
||||
@ -950,14 +962,76 @@ impl ExecutableFile {
|
||||
|
||||
// with Expect
|
||||
#[cfg(target_family = "unix")]
|
||||
unsafe fn roc_run_native_debug(
|
||||
_executable: ExecutableFile,
|
||||
_argv: &[*const c_char],
|
||||
_envp: &[*const c_char],
|
||||
_expectations: VecMap<ModuleId, Expectations>,
|
||||
_interns: Interns,
|
||||
) {
|
||||
todo!()
|
||||
fn roc_dev_native(
|
||||
arena: &Bump,
|
||||
executable: ExecutableFile,
|
||||
argv: bumpalo::collections::Vec<*const c_char>,
|
||||
envp: bumpalo::collections::Vec<*const c_char>,
|
||||
expect_metadata: ExpectMetadata,
|
||||
) -> ! {
|
||||
use roc_repl_expect::run::ExpectMemory;
|
||||
use signal_hook::{consts::signal::SIGCHLD, consts::signal::SIGUSR1, iterator::Signals};
|
||||
|
||||
let ExpectMetadata {
|
||||
mut expectations,
|
||||
interns,
|
||||
layout_interner,
|
||||
} = expect_metadata;
|
||||
|
||||
let mut signals = Signals::new(&[SIGCHLD, SIGUSR1]).unwrap();
|
||||
|
||||
// let shm_name =
|
||||
let shm_name = format!("/roc_expect_buffer_{}", std::process::id());
|
||||
let memory = ExpectMemory::create_or_reuse_mmap(&shm_name);
|
||||
|
||||
let layout_interner = layout_interner.into_global();
|
||||
|
||||
let mut writer = std::io::stdout();
|
||||
|
||||
match unsafe { libc::fork() } {
|
||||
0 => unsafe {
|
||||
// we are the child
|
||||
|
||||
executable.execve(&argv, &envp);
|
||||
|
||||
// Display a human-friendly error message
|
||||
println!("Error {:?}", std::io::Error::last_os_error());
|
||||
|
||||
std::process::exit(1);
|
||||
},
|
||||
-1 => {
|
||||
// something failed
|
||||
|
||||
// Display a human-friendly error message
|
||||
println!("Error {:?}", std::io::Error::last_os_error());
|
||||
|
||||
std::process::exit(1)
|
||||
}
|
||||
1.. => {
|
||||
for sig in &mut signals {
|
||||
match sig {
|
||||
SIGCHLD => break,
|
||||
SIGUSR1 => {
|
||||
// this is the signal we use for an expect failure. Let's see what the child told us
|
||||
|
||||
roc_repl_expect::run::render_expects_in_memory(
|
||||
&mut writer,
|
||||
arena,
|
||||
&mut expectations,
|
||||
&interns,
|
||||
&layout_interner,
|
||||
&memory,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
_ => println!("received signal {}", sig),
|
||||
}
|
||||
}
|
||||
|
||||
std::process::exit(0)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
@ -1036,12 +1110,11 @@ fn roc_run_executable_file_path(binary_bytes: &[u8]) -> std::io::Result<Executab
|
||||
/// Run on the native OS (not on wasm)
|
||||
#[cfg(not(target_family = "unix"))]
|
||||
fn roc_run_native<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(
|
||||
arena: Bump, // This should be passed an owned value, not a reference, so we can usefully mem::forget it!
|
||||
arena: &Bump, // This should be passed an owned value, not a reference, so we can usefully mem::forget it!
|
||||
opt_level: OptLevel,
|
||||
args: I,
|
||||
binary_bytes: &[u8],
|
||||
_expectations: VecMap<ModuleId, Expectations>,
|
||||
_interns: Interns,
|
||||
_expect_metadata: ExpectMetadata,
|
||||
) -> io::Result<i32> {
|
||||
use bumpalo::collections::CollectIn;
|
||||
|
||||
@ -1055,18 +1128,18 @@ fn roc_run_native<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(
|
||||
.iter()
|
||||
.map(|s| s.as_ptr())
|
||||
.chain([std::ptr::null()])
|
||||
.collect_in(&arena);
|
||||
.collect_in(arena);
|
||||
|
||||
let envp: bumpalo::collections::Vec<*const c_char> = envp_cstrings
|
||||
.iter()
|
||||
.map(|s| s.as_ptr())
|
||||
.chain([std::ptr::null()])
|
||||
.collect_in(&arena);
|
||||
.collect_in(arena);
|
||||
|
||||
match opt_level {
|
||||
OptLevel::Development => {
|
||||
// roc_run_native_debug(executable, &argv, &envp, expectations, interns)
|
||||
todo!()
|
||||
internal_error!("running `expect`s does not currently work on windows")
|
||||
}
|
||||
OptLevel::Normal | OptLevel::Size | OptLevel::Optimize => {
|
||||
roc_run_native_fast(executable, &argv, &envp);
|
||||
|
@ -65,6 +65,34 @@ export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
|
||||
std.process.exit(0);
|
||||
}
|
||||
|
||||
extern fn kill(pid: c_int, sig: c_int) c_int;
|
||||
extern fn shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int;
|
||||
extern fn mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque;
|
||||
extern fn getppid() c_int;
|
||||
|
||||
fn roc_getppid() callconv(.C) c_int {
|
||||
return getppid();
|
||||
}
|
||||
|
||||
fn roc_send_signal(pid: c_int, sig: c_int) callconv(.C) c_int {
|
||||
return kill(pid, sig);
|
||||
}
|
||||
fn roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) callconv(.C) c_int {
|
||||
return shm_open(name, oflag, mode);
|
||||
}
|
||||
fn roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) callconv(.C) *anyopaque {
|
||||
return mmap(addr, length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
comptime {
|
||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
@export(roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||
@export(roc_mmap, .{ .name = "roc_mmap", .linkage = .Strong });
|
||||
@export(roc_send_signal, .{ .name = "roc_send_signal", .linkage = .Strong });
|
||||
@export(roc_shm_open, .{ .name = "roc_shm_open", .linkage = .Strong });
|
||||
}
|
||||
}
|
||||
|
||||
const Unit = extern struct {};
|
||||
|
||||
pub export fn main() i32 {
|
||||
|
@ -64,6 +64,34 @@ export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
|
||||
std.process.exit(0);
|
||||
}
|
||||
|
||||
extern fn kill(pid: c_int, sig: c_int) c_int;
|
||||
extern fn shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int;
|
||||
extern fn mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque;
|
||||
extern fn getppid() c_int;
|
||||
|
||||
fn roc_getppid() callconv(.C) c_int {
|
||||
return getppid();
|
||||
}
|
||||
|
||||
fn roc_send_signal(pid: c_int, sig: c_int) callconv(.C) c_int {
|
||||
return kill(pid, sig);
|
||||
}
|
||||
fn roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) callconv(.C) c_int {
|
||||
return shm_open(name, oflag, mode);
|
||||
}
|
||||
fn roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) callconv(.C) *anyopaque {
|
||||
return mmap(addr, length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
comptime {
|
||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
@export(roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||
@export(roc_mmap, .{ .name = "roc_mmap", .linkage = .Strong });
|
||||
@export(roc_send_signal, .{ .name = "roc_send_signal", .linkage = .Strong });
|
||||
@export(roc_shm_open, .{ .name = "roc_shm_open", .linkage = .Strong });
|
||||
}
|
||||
}
|
||||
|
||||
const Unit = extern struct {};
|
||||
|
||||
pub export fn main() i32 {
|
||||
|
@ -1,4 +1,5 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const testing = std.testing;
|
||||
const expectEqual = testing.expectEqual;
|
||||
const expect = testing.expect;
|
||||
@ -13,7 +14,6 @@ comptime {
|
||||
// -fcompiler-rt in link.rs instead of doing this. Note that this
|
||||
// workaround is present in many host.zig files, so make sure to undo
|
||||
// it everywhere!
|
||||
const builtin = @import("builtin");
|
||||
if (builtin.os.tag == .macos) {
|
||||
_ = @import("compiler_rt");
|
||||
}
|
||||
@ -81,6 +81,34 @@ export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||
return memset(dst, value, size);
|
||||
}
|
||||
|
||||
extern fn kill(pid: c_int, sig: c_int) c_int;
|
||||
extern fn shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int;
|
||||
extern fn mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque;
|
||||
extern fn getppid() c_int;
|
||||
|
||||
fn roc_getppid() callconv(.C) c_int {
|
||||
return getppid();
|
||||
}
|
||||
|
||||
fn roc_send_signal(pid: c_int, sig: c_int) callconv(.C) c_int {
|
||||
return kill(pid, sig);
|
||||
}
|
||||
fn roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) callconv(.C) c_int {
|
||||
return shm_open(name, oflag, mode);
|
||||
}
|
||||
fn roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) callconv(.C) *anyopaque {
|
||||
return mmap(addr, length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
comptime {
|
||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
@export(roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||
@export(roc_mmap, .{ .name = "roc_mmap", .linkage = .Strong });
|
||||
@export(roc_send_signal, .{ .name = "roc_send_signal", .linkage = .Strong });
|
||||
@export(roc_shm_open, .{ .name = "roc_shm_open", .linkage = .Strong });
|
||||
}
|
||||
}
|
||||
|
||||
pub export fn main() u8 {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
|
||||
|
@ -80,6 +80,34 @@ export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||
return memset(dst, value, size);
|
||||
}
|
||||
|
||||
extern fn kill(pid: c_int, sig: c_int) c_int;
|
||||
extern fn shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int;
|
||||
extern fn mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque;
|
||||
extern fn getppid() c_int;
|
||||
|
||||
fn roc_getppid() callconv(.C) c_int {
|
||||
return getppid();
|
||||
}
|
||||
|
||||
fn roc_send_signal(pid: c_int, sig: c_int) callconv(.C) c_int {
|
||||
return kill(pid, sig);
|
||||
}
|
||||
fn roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) callconv(.C) c_int {
|
||||
return shm_open(name, oflag, mode);
|
||||
}
|
||||
fn roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) callconv(.C) *anyopaque {
|
||||
return mmap(addr, length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
comptime {
|
||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
@export(roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||
@export(roc_mmap, .{ .name = "roc_mmap", .linkage = .Strong });
|
||||
@export(roc_send_signal, .{ .name = "roc_send_signal", .linkage = .Strong });
|
||||
@export(roc_shm_open, .{ .name = "roc_shm_open", .linkage = .Strong });
|
||||
}
|
||||
}
|
||||
|
||||
// warning! the array is currently stack-allocated so don't make this too big
|
||||
const NUM_NUMS = 100;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
const std = @import("std");
|
||||
const str = @import("str");
|
||||
const builtin = @import("builtin");
|
||||
const str = @import("str");
|
||||
const RocStr = str.RocStr;
|
||||
const testing = std.testing;
|
||||
const expectEqual = testing.expectEqual;
|
||||
@ -85,9 +85,39 @@ export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||
return memset(dst, value, size);
|
||||
}
|
||||
|
||||
extern fn kill(pid: c_int, sig: c_int) c_int;
|
||||
extern fn shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int;
|
||||
extern fn mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque;
|
||||
extern fn getppid() c_int;
|
||||
|
||||
fn roc_getppid() callconv(.C) c_int {
|
||||
return getppid();
|
||||
}
|
||||
|
||||
fn roc_send_signal(pid: c_int, sig: c_int) callconv(.C) c_int {
|
||||
return kill(pid, sig);
|
||||
}
|
||||
fn roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) callconv(.C) c_int {
|
||||
return shm_open(name, oflag, mode);
|
||||
}
|
||||
fn roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) callconv(.C) *anyopaque {
|
||||
return mmap(addr, length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
comptime {
|
||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
@export(roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||
@export(roc_mmap, .{ .name = "roc_mmap", .linkage = .Strong });
|
||||
@export(roc_send_signal, .{ .name = "roc_send_signal", .linkage = .Strong });
|
||||
@export(roc_shm_open, .{ .name = "roc_shm_open", .linkage = .Strong });
|
||||
}
|
||||
}
|
||||
|
||||
const Unit = extern struct {};
|
||||
|
||||
pub export fn main() callconv(.C) u8 {
|
||||
pub fn main() !u8 {
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
|
||||
// The size might be zero; if so, make it at least 8 so that we don't have a nullptr
|
||||
const size = std.math.max(@intCast(usize, roc__mainForHost_size()), 8);
|
||||
const raw_output = roc_alloc(@intCast(usize, size), @alignOf(u64)).?;
|
||||
@ -108,7 +138,6 @@ pub export fn main() callconv(.C) u8 {
|
||||
const nanos = timer.read();
|
||||
const seconds = (@intToFloat(f64, nanos) / 1_000_000_000.0);
|
||||
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
stderr.print("runtime: {d:.3}ms\n", .{seconds * 1000}) catch unreachable;
|
||||
|
||||
return 0;
|
||||
|
@ -3,7 +3,7 @@ use roc_error_macros::internal_error;
|
||||
pub use roc_gen_llvm::llvm::build::FunctionIterator;
|
||||
use roc_gen_llvm::llvm::build::{module_from_builtins, LlvmBackendMode};
|
||||
use roc_gen_llvm::llvm::externs::add_default_roc_externs;
|
||||
use roc_load::{EntryPoint, LoadedModule, MonomorphizedModule};
|
||||
use roc_load::{EntryPoint, ExpectMetadata, LoadedModule, MonomorphizedModule};
|
||||
use roc_module::symbol::{Interns, ModuleId};
|
||||
use roc_mono::ir::OptLevel;
|
||||
use roc_region::all::LineInfo;
|
||||
@ -174,47 +174,60 @@ impl Deref for CodeObject {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum CodeGenBackend {
|
||||
Assembly,
|
||||
Llvm,
|
||||
Wasm,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct CodeGenOptions {
|
||||
pub backend: CodeGenBackend,
|
||||
pub opt_level: OptLevel,
|
||||
pub emit_debug_info: bool,
|
||||
}
|
||||
|
||||
type GenFromMono<'a> = (CodeObject, CodeGenTiming, ExpectMetadata<'a>);
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn gen_from_mono_module(
|
||||
arena: &bumpalo::Bump,
|
||||
loaded: MonomorphizedModule,
|
||||
pub fn gen_from_mono_module<'a>(
|
||||
arena: &'a bumpalo::Bump,
|
||||
loaded: MonomorphizedModule<'a>,
|
||||
roc_file_path: &Path,
|
||||
target: &target_lexicon::Triple,
|
||||
opt_level: OptLevel,
|
||||
emit_debug_info: bool,
|
||||
code_gen_options: CodeGenOptions,
|
||||
preprocessed_host_path: &Path,
|
||||
wasm_dev_stack_bytes: Option<u32>,
|
||||
) -> (CodeObject, CodeGenTiming) {
|
||||
match opt_level {
|
||||
OptLevel::Normal | OptLevel::Size | OptLevel::Optimize => gen_from_mono_module_llvm(
|
||||
arena,
|
||||
loaded,
|
||||
roc_file_path,
|
||||
target,
|
||||
opt_level,
|
||||
emit_debug_info,
|
||||
),
|
||||
OptLevel::Development => gen_from_mono_module_dev(
|
||||
) -> GenFromMono<'a> {
|
||||
match code_gen_options.backend {
|
||||
CodeGenBackend::Assembly => gen_from_mono_module_dev(
|
||||
arena,
|
||||
loaded,
|
||||
target,
|
||||
preprocessed_host_path,
|
||||
wasm_dev_stack_bytes,
|
||||
),
|
||||
CodeGenBackend::Llvm => {
|
||||
gen_from_mono_module_llvm(arena, loaded, roc_file_path, target, code_gen_options)
|
||||
}
|
||||
CodeGenBackend::Wasm => {
|
||||
// emit wasm via the llvm backend
|
||||
gen_from_mono_module_llvm(arena, loaded, roc_file_path, target, code_gen_options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO how should imported modules factor into this? What if those use builtins too?
|
||||
// TODO this should probably use more helper functions
|
||||
// TODO make this polymorphic in the llvm functions so it can be reused for another backend.
|
||||
fn gen_from_mono_module_llvm(
|
||||
arena: &bumpalo::Bump,
|
||||
loaded: MonomorphizedModule,
|
||||
fn gen_from_mono_module_llvm<'a>(
|
||||
arena: &'a bumpalo::Bump,
|
||||
loaded: MonomorphizedModule<'a>,
|
||||
roc_file_path: &Path,
|
||||
target: &target_lexicon::Triple,
|
||||
opt_level: OptLevel,
|
||||
emit_debug_info: bool,
|
||||
) -> (CodeObject, CodeGenTiming) {
|
||||
code_gen_options: CodeGenOptions,
|
||||
) -> GenFromMono<'a> {
|
||||
use crate::target::{self, convert_opt_level};
|
||||
use inkwell::attributes::{Attribute, AttributeLoc};
|
||||
use inkwell::context::Context;
|
||||
@ -263,6 +276,12 @@ fn gen_from_mono_module_llvm(
|
||||
}
|
||||
}
|
||||
|
||||
let CodeGenOptions {
|
||||
backend: _,
|
||||
opt_level,
|
||||
emit_debug_info,
|
||||
} = code_gen_options;
|
||||
|
||||
let builder = context.create_builder();
|
||||
let (dibuilder, compile_unit) = roc_gen_llvm::llvm::build::Env::new_debug_info(module);
|
||||
let (mpm, _fpm) = roc_gen_llvm::llvm::build::construct_optimization_passes(module, opt_level);
|
||||
@ -278,7 +297,11 @@ fn gen_from_mono_module_llvm(
|
||||
interns: loaded.interns,
|
||||
module,
|
||||
target_info,
|
||||
mode: LlvmBackendMode::Binary,
|
||||
mode: match opt_level {
|
||||
OptLevel::Development => LlvmBackendMode::BinaryDev,
|
||||
OptLevel::Normal | OptLevel::Size | OptLevel::Optimize => LlvmBackendMode::Binary,
|
||||
},
|
||||
|
||||
exposed_to_host: loaded.exposed_to_host.values.keys().copied().collect(),
|
||||
};
|
||||
|
||||
@ -430,17 +453,22 @@ fn gen_from_mono_module_llvm(
|
||||
(
|
||||
CodeObject::MemoryBuffer(memory_buffer),
|
||||
CodeGenTiming { code_gen },
|
||||
ExpectMetadata {
|
||||
interns: env.interns,
|
||||
layout_interner: loaded.layout_interner,
|
||||
expectations: loaded.expectations,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "target-wasm32")]
|
||||
fn gen_from_mono_module_dev(
|
||||
arena: &bumpalo::Bump,
|
||||
loaded: MonomorphizedModule,
|
||||
fn gen_from_mono_module_dev<'a>(
|
||||
arena: &'a bumpalo::Bump,
|
||||
loaded: MonomorphizedModule<'a>,
|
||||
target: &target_lexicon::Triple,
|
||||
preprocessed_host_path: &Path,
|
||||
wasm_dev_stack_bytes: Option<u32>,
|
||||
) -> (CodeObject, CodeGenTiming) {
|
||||
) -> GenFromMono<'a> {
|
||||
use target_lexicon::Architecture;
|
||||
|
||||
match target.architecture {
|
||||
@ -458,13 +486,13 @@ fn gen_from_mono_module_dev(
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "target-wasm32"))]
|
||||
pub fn gen_from_mono_module_dev(
|
||||
arena: &bumpalo::Bump,
|
||||
loaded: MonomorphizedModule,
|
||||
pub fn gen_from_mono_module_dev<'a>(
|
||||
arena: &'a bumpalo::Bump,
|
||||
loaded: MonomorphizedModule<'a>,
|
||||
target: &target_lexicon::Triple,
|
||||
_host_input_path: &Path,
|
||||
_wasm_dev_stack_bytes: Option<u32>,
|
||||
) -> (CodeObject, CodeGenTiming) {
|
||||
) -> GenFromMono<'a> {
|
||||
use target_lexicon::Architecture;
|
||||
|
||||
match target.architecture {
|
||||
@ -476,12 +504,12 @@ pub fn gen_from_mono_module_dev(
|
||||
}
|
||||
|
||||
#[cfg(feature = "target-wasm32")]
|
||||
fn gen_from_mono_module_dev_wasm32(
|
||||
arena: &bumpalo::Bump,
|
||||
loaded: MonomorphizedModule,
|
||||
fn gen_from_mono_module_dev_wasm32<'a>(
|
||||
arena: &'a bumpalo::Bump,
|
||||
loaded: MonomorphizedModule<'a>,
|
||||
preprocessed_host_path: &Path,
|
||||
wasm_dev_stack_bytes: Option<u32>,
|
||||
) -> (CodeObject, CodeGenTiming) {
|
||||
) -> GenFromMono<'a> {
|
||||
let code_gen_start = Instant::now();
|
||||
let MonomorphizedModule {
|
||||
module_id,
|
||||
@ -530,14 +558,19 @@ fn gen_from_mono_module_dev_wasm32(
|
||||
(
|
||||
CodeObject::Vector(final_binary_bytes),
|
||||
CodeGenTiming { code_gen },
|
||||
ExpectMetadata {
|
||||
interns,
|
||||
layout_interner,
|
||||
expectations: loaded.expectations,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn gen_from_mono_module_dev_assembly(
|
||||
arena: &bumpalo::Bump,
|
||||
loaded: MonomorphizedModule,
|
||||
fn gen_from_mono_module_dev_assembly<'a>(
|
||||
arena: &'a bumpalo::Bump,
|
||||
loaded: MonomorphizedModule<'a>,
|
||||
target: &target_lexicon::Triple,
|
||||
) -> (CodeObject, CodeGenTiming) {
|
||||
) -> GenFromMono<'a> {
|
||||
let code_gen_start = Instant::now();
|
||||
|
||||
let lazy_literals = true;
|
||||
@ -569,5 +602,13 @@ fn gen_from_mono_module_dev_assembly(
|
||||
.write()
|
||||
.expect("failed to build output object");
|
||||
|
||||
(CodeObject::Vector(module_out), CodeGenTiming { code_gen })
|
||||
(
|
||||
CodeObject::Vector(module_out),
|
||||
CodeGenTiming { code_gen },
|
||||
ExpectMetadata {
|
||||
interns,
|
||||
layout_interner,
|
||||
expectations: loaded.expectations,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const SIGUSR1: c_int = 10;
|
||||
|
||||
@ -18,6 +19,71 @@ pub fn setSharedBuffer(ptr: [*]u8, length: usize) callconv(.C) usize {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pub fn expectFailedStart() callconv(.C) [*]u8 {
|
||||
pub fn expectFailedStartSharedBuffer() callconv(.C) [*]u8 {
|
||||
return SHARED_BUFFER.ptr;
|
||||
}
|
||||
|
||||
pub fn expectFailedStartSharedFile() callconv(.C) [*]u8 {
|
||||
// IMPORTANT: shared memory object names must begin with / and contain no other slashes!
|
||||
var name: [100]u8 = undefined;
|
||||
_ = std.fmt.bufPrint(name[0..100], "/roc_expect_buffer_{}\x00", .{roc_getppid()}) catch unreachable;
|
||||
|
||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
const shared_fd = roc_shm_open(@ptrCast(*const i8, &name), O_RDWR | O_CREAT, 0o666);
|
||||
|
||||
const length = 4096;
|
||||
|
||||
const shared_ptr = roc_mmap(
|
||||
null,
|
||||
length,
|
||||
PROT_WRITE,
|
||||
MAP_SHARED,
|
||||
shared_fd,
|
||||
0,
|
||||
);
|
||||
|
||||
const ptr = @ptrCast([*]u8, shared_ptr);
|
||||
|
||||
return ptr;
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
extern fn roc_send_signal(pid: c_int, sig: c_int) c_int;
|
||||
extern fn roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int;
|
||||
extern fn roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque;
|
||||
extern fn roc_getppid() c_int;
|
||||
|
||||
pub fn readSharedBufferEnv() callconv(.C) void {
|
||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
|
||||
// IMPORTANT: shared memory object names must begin with / and contain no other slashes!
|
||||
var name: [100]u8 = undefined;
|
||||
_ = std.fmt.bufPrint(name[0..100], "/roc_expect_buffer_{}\x00", .{roc_getppid()}) catch unreachable;
|
||||
|
||||
const shared_fd = roc_shm_open(@ptrCast(*const i8, &name), O_RDWR | O_CREAT, 0o666);
|
||||
const length = 4096;
|
||||
|
||||
const shared_ptr = roc_mmap(
|
||||
null,
|
||||
length,
|
||||
PROT_WRITE,
|
||||
MAP_SHARED,
|
||||
shared_fd,
|
||||
0,
|
||||
);
|
||||
|
||||
const ptr = @ptrCast([*]u8, shared_ptr);
|
||||
|
||||
SHARED_BUFFER = ptr[0..length];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expectFailedFinalize() callconv(.C) void {
|
||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
const parent_pid = roc_getppid();
|
||||
|
||||
_ = roc_send_signal(parent_pid, SIGUSR1);
|
||||
}
|
||||
}
|
||||
|
@ -169,10 +169,14 @@ comptime {
|
||||
@export(utils.panic, .{ .name = "roc_builtins.utils." ++ "panic", .linkage = .Weak });
|
||||
|
||||
if (builtin.target.cpu.arch != .wasm32) {
|
||||
exportUtilsFn(expect.expectFailedStart, "expect_failed_start");
|
||||
exportUtilsFn(expect.expectFailedStartSharedBuffer, "expect_failed_start_shared_buffer");
|
||||
exportUtilsFn(expect.expectFailedStartSharedFile, "expect_failed_start_shared_file");
|
||||
exportUtilsFn(expect.expectFailedFinalize, "expect_failed_finalize");
|
||||
|
||||
// sets the buffer used for expect failures
|
||||
@export(expect.setSharedBuffer, .{ .name = "set_shared_buffer", .linkage = .Weak });
|
||||
|
||||
exportUtilsFn(expect.readSharedBufferEnv, "read_env_shared_buffer");
|
||||
}
|
||||
|
||||
if (builtin.target.cpu.arch == .aarch64) {
|
||||
|
@ -22,6 +22,24 @@ extern fn roc_panic(c_ptr: *const anyopaque, tag_id: u32) callconv(.C) void;
|
||||
// should work just like libc memcpy (we can't assume libc is present)
|
||||
extern fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
|
||||
|
||||
extern fn kill(pid: c_int, sig: c_int) c_int;
|
||||
extern fn shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int;
|
||||
extern fn mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque;
|
||||
extern fn getppid() c_int;
|
||||
|
||||
fn testing_roc_getppid() callconv(.C) c_int {
|
||||
return getppid();
|
||||
}
|
||||
fn testing_roc_send_signal(pid: c_int, sig: c_int) callconv(.C) c_int {
|
||||
return kill(pid, sig);
|
||||
}
|
||||
fn testing_roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) callconv(.C) c_int {
|
||||
return shm_open(name, oflag, mode);
|
||||
}
|
||||
fn testing_roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) callconv(.C) *anyopaque {
|
||||
return mmap(addr, length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
comptime {
|
||||
const builtin = @import("builtin");
|
||||
// During tests, use the testing allocators to satisfy these functions.
|
||||
@ -31,6 +49,13 @@ comptime {
|
||||
@export(testing_roc_dealloc, .{ .name = "roc_dealloc", .linkage = .Strong });
|
||||
@export(testing_roc_panic, .{ .name = "roc_panic", .linkage = .Strong });
|
||||
@export(testing_roc_memcpy, .{ .name = "roc_memcpy", .linkage = .Strong });
|
||||
|
||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
@export(testing_roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||
@export(testing_roc_mmap, .{ .name = "roc_mmap", .linkage = .Strong });
|
||||
@export(testing_roc_send_signal, .{ .name = "roc_send_signal", .linkage = .Strong });
|
||||
@export(testing_roc_shm_open, .{ .name = "roc_shm_open", .linkage = .Strong });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,8 +404,12 @@ pub const UTILS_INCREF: &str = "roc_builtins.utils.incref";
|
||||
pub const UTILS_DECREF: &str = "roc_builtins.utils.decref";
|
||||
pub const UTILS_DECREF_CHECK_NULL: &str = "roc_builtins.utils.decref_check_null";
|
||||
|
||||
pub const UTILS_EXPECT_FAILED_START: &str = "roc_builtins.utils.expect_failed_start";
|
||||
pub const UTILS_EXPECT_FAILED_START_SHARED_BUFFER: &str =
|
||||
"roc_builtins.utils.expect_failed_start_shared_buffer";
|
||||
pub const UTILS_EXPECT_FAILED_START_SHARED_FILE: &str =
|
||||
"roc_builtins.utils.expect_failed_start_shared_file";
|
||||
pub const UTILS_EXPECT_FAILED_FINALIZE: &str = "roc_builtins.utils.expect_failed_finalize";
|
||||
pub const UTILS_EXPECT_READ_ENV_SHARED_BUFFER: &str = "roc_builtins.utils.read_env_shared_buffer";
|
||||
|
||||
pub const UTILS_LONGJMP: &str = "longjmp";
|
||||
pub const UTILS_SETJMP: &str = "setjmp";
|
||||
|
@ -163,6 +163,7 @@ impl<'a, 'ctx> Scope<'a, 'ctx> {
|
||||
pub enum LlvmBackendMode {
|
||||
/// Assumes primitives (roc_alloc, roc_panic, etc) are provided by the host
|
||||
Binary,
|
||||
BinaryDev,
|
||||
/// Creates a test wrapper around the main roc function to catch and report panics.
|
||||
/// Provides a testing implementation of primitives (roc_alloc, roc_panic, etc)
|
||||
GenTest,
|
||||
@ -174,6 +175,7 @@ impl LlvmBackendMode {
|
||||
pub(crate) fn has_host(self) -> bool {
|
||||
match self {
|
||||
LlvmBackendMode::Binary => true,
|
||||
LlvmBackendMode::BinaryDev => true,
|
||||
LlvmBackendMode::GenTest => false,
|
||||
LlvmBackendMode::WasmGenTest => true,
|
||||
LlvmBackendMode::CliTest => false,
|
||||
@ -184,6 +186,7 @@ impl LlvmBackendMode {
|
||||
fn returns_roc_result(self) -> bool {
|
||||
match self {
|
||||
LlvmBackendMode::Binary => false,
|
||||
LlvmBackendMode::BinaryDev => false,
|
||||
LlvmBackendMode::GenTest => true,
|
||||
LlvmBackendMode::WasmGenTest => true,
|
||||
LlvmBackendMode::CliTest => true,
|
||||
@ -193,6 +196,7 @@ impl LlvmBackendMode {
|
||||
fn runs_expects(self) -> bool {
|
||||
match self {
|
||||
LlvmBackendMode::Binary => false,
|
||||
LlvmBackendMode::BinaryDev => true,
|
||||
LlvmBackendMode::GenTest => false,
|
||||
LlvmBackendMode::WasmGenTest => false,
|
||||
LlvmBackendMode::CliTest => true,
|
||||
@ -2824,6 +2828,10 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||
lookups,
|
||||
);
|
||||
|
||||
if let LlvmBackendMode::BinaryDev = env.mode {
|
||||
crate::llvm::expect::finalize(env);
|
||||
}
|
||||
|
||||
bd.build_unconditional_branch(then_block);
|
||||
}
|
||||
roc_target::PtrWidth::Bytes4 => {
|
||||
@ -3925,7 +3933,7 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
|
||||
)
|
||||
}
|
||||
|
||||
LlvmBackendMode::Binary => {}
|
||||
LlvmBackendMode::Binary | LlvmBackendMode::BinaryDev => {}
|
||||
}
|
||||
|
||||
// a generic version that writes the result into a passed *u8 pointer
|
||||
@ -3976,7 +3984,9 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
|
||||
roc_result_type(env, roc_function.get_type().get_return_type().unwrap()).into()
|
||||
}
|
||||
|
||||
LlvmBackendMode::Binary => basic_type_from_layout(env, &return_layout),
|
||||
LlvmBackendMode::Binary | LlvmBackendMode::BinaryDev => {
|
||||
basic_type_from_layout(env, &return_layout)
|
||||
}
|
||||
};
|
||||
|
||||
let size: BasicValueEnum = return_type.size_of().unwrap().into();
|
||||
@ -4948,7 +4958,7 @@ pub fn build_proc<'a, 'ctx, 'env>(
|
||||
GenTest | WasmGenTest | CliTest => {
|
||||
/* no host, or exposing types is not supported */
|
||||
}
|
||||
Binary => {
|
||||
Binary | BinaryDev => {
|
||||
for (alias_name, (generated_function, top_level, layout)) in aliases.iter() {
|
||||
expose_alias_to_host(
|
||||
env,
|
||||
|
@ -14,7 +14,8 @@ use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
||||
use roc_region::all::Region;
|
||||
|
||||
use super::build::{
|
||||
add_func, load_roc_value, load_symbol_and_layout, use_roc_value, FunctionSpec, Scope,
|
||||
add_func, load_roc_value, load_symbol_and_layout, use_roc_value, FunctionSpec, LlvmBackendMode,
|
||||
Scope,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
@ -93,6 +94,16 @@ fn write_state<'a, 'ctx, 'env>(
|
||||
env.builder.build_store(offset_ptr, offset);
|
||||
}
|
||||
|
||||
pub(crate) fn finalize(env: &Env) {
|
||||
let func = env
|
||||
.module
|
||||
.get_function(bitcode::UTILS_EXPECT_FAILED_FINALIZE)
|
||||
.unwrap();
|
||||
|
||||
env.builder
|
||||
.build_call(func, &[], "call_expect_failed_finalize");
|
||||
}
|
||||
|
||||
pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
scope: &Scope<'a, 'ctx>,
|
||||
@ -101,10 +112,13 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
||||
region: Region,
|
||||
lookups: &[Symbol],
|
||||
) {
|
||||
let func = env
|
||||
.module
|
||||
.get_function(bitcode::UTILS_EXPECT_FAILED_START)
|
||||
.unwrap();
|
||||
let start_function = if let LlvmBackendMode::BinaryDev = env.mode {
|
||||
bitcode::UTILS_EXPECT_FAILED_START_SHARED_FILE
|
||||
} else {
|
||||
bitcode::UTILS_EXPECT_FAILED_START_SHARED_BUFFER
|
||||
};
|
||||
|
||||
let func = env.module.get_function(start_function).unwrap();
|
||||
|
||||
let call_result = env
|
||||
.builder
|
||||
|
@ -155,10 +155,32 @@ pub fn add_default_roc_externs(env: &Env<'_, '_, '_>) {
|
||||
}
|
||||
}
|
||||
|
||||
unreachable_function(env, "roc_getppid");
|
||||
unreachable_function(env, "roc_mmap");
|
||||
unreachable_function(env, "roc_send_signal");
|
||||
unreachable_function(env, "roc_shm_open");
|
||||
|
||||
add_sjlj_roc_panic(env)
|
||||
}
|
||||
}
|
||||
|
||||
fn unreachable_function(env: &Env, name: &str) {
|
||||
// The type of this function (but not the implementation) should have
|
||||
// already been defined by the builtins, which rely on it.
|
||||
let fn_val = env.module.get_function(name).unwrap();
|
||||
|
||||
// Add a basic block for the entry point
|
||||
let entry = env.context.append_basic_block(fn_val, "entry");
|
||||
|
||||
env.builder.position_at_end(entry);
|
||||
|
||||
env.builder.build_unreachable();
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
crate::llvm::build::verify_fn(fn_val);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_sjlj_roc_panic(env: &Env<'_, '_, '_>) {
|
||||
let ctx = env.context;
|
||||
let module = env.module;
|
||||
|
@ -15,8 +15,8 @@ const SKIP_SUBS_CACHE: bool = {
|
||||
|
||||
pub use roc_load_internal::docs;
|
||||
pub use roc_load_internal::file::{
|
||||
EntryPoint, ExecutionMode, Expectations, LoadConfig, LoadResult, LoadStart, LoadedModule,
|
||||
LoadingProblem, MonomorphizedModule, Phase, Threading,
|
||||
EntryPoint, ExecutionMode, ExpectMetadata, Expectations, LoadConfig, LoadResult, LoadStart,
|
||||
LoadedModule, LoadingProblem, MonomorphizedModule, Phase, Threading,
|
||||
};
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
@ -705,6 +705,13 @@ pub struct MonomorphizedModule<'a> {
|
||||
pub expectations: VecMap<ModuleId, Expectations>,
|
||||
}
|
||||
|
||||
/// Values used to render expect output
|
||||
pub struct ExpectMetadata<'a> {
|
||||
pub interns: Interns,
|
||||
pub layout_interner: SingleThreadedInterner<'a, Layout<'a>>,
|
||||
pub expectations: VecMap<ModuleId, Expectations>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum EntryPoint<'a> {
|
||||
Executable {
|
||||
|
@ -244,6 +244,7 @@ fn create_llvm_module<'a>(
|
||||
};
|
||||
let (main_fn_name, main_fn) = match config.mode {
|
||||
LlvmBackendMode::Binary => unreachable!(),
|
||||
LlvmBackendMode::BinaryDev => unreachable!(),
|
||||
LlvmBackendMode::CliTest => unreachable!(),
|
||||
LlvmBackendMode::WasmGenTest => roc_gen_llvm::llvm::build::build_wasm_test_wrapper(
|
||||
&env,
|
||||
|
@ -76,13 +76,23 @@ fn collect_roc_definitions<'a>(object: &object::File<'a, &'a [u8]>) -> MutMap<St
|
||||
|
||||
let address = sym.address() as u64;
|
||||
|
||||
// special exceptions for memcpy and memset.
|
||||
if name == "roc_memcpy" {
|
||||
vaddresses.insert("memcpy".to_string(), address);
|
||||
} else if name == "roc_memset" {
|
||||
vaddresses.insert("memset".to_string(), address);
|
||||
} else if name == "roc_memmove" {
|
||||
vaddresses.insert("memmove".to_string(), address);
|
||||
// special exceptions for roc_ functions that map to libc symbols
|
||||
let direct_mapping = match name {
|
||||
"roc_memcpy" => Some("memcpy"),
|
||||
"roc_memset" => Some("memset"),
|
||||
"roc_memmove" => Some("memmove"),
|
||||
|
||||
// for expects
|
||||
"roc_mmap" => Some("mmap"),
|
||||
"roc_getppid" => Some("getppid"),
|
||||
"roc_send_signal" => Some("kill"),
|
||||
"roc_shm_open" => Some("shm_open"),
|
||||
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(libc_symbol) = direct_mapping {
|
||||
vaddresses.insert(libc_symbol.to_string(), address);
|
||||
}
|
||||
|
||||
vaddresses.insert(name.to_string(), address);
|
||||
|
@ -25,6 +25,7 @@ roc_types = {path = "../compiler/types"}
|
||||
roc_gen_llvm = {path = "../compiler/gen_llvm"}
|
||||
roc_region = { path = "../compiler/region" }
|
||||
roc_build = { path = "../compiler/build" }
|
||||
roc_error_macros = { path = "../error_macros" }
|
||||
|
||||
libloading = "0.7.1"
|
||||
inkwell = { path = "../vendor/inkwell" }
|
||||
|
@ -6,6 +6,7 @@ use inkwell::context::Context;
|
||||
use roc_build::link::llvm_module_to_dylib;
|
||||
use roc_can::expr::ExpectLookup;
|
||||
use roc_collections::{MutSet, VecMap};
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_gen_llvm::{
|
||||
llvm::{build::LlvmBackendMode, externs::add_default_roc_externs},
|
||||
run_roc::RocCallResult,
|
||||
@ -21,7 +22,7 @@ use roc_target::TargetInfo;
|
||||
use roc_types::subs::{Subs, Variable};
|
||||
use target_lexicon::Triple;
|
||||
|
||||
pub(crate) struct ExpectMemory<'a> {
|
||||
pub struct ExpectMemory<'a> {
|
||||
ptr: *mut u8,
|
||||
length: usize,
|
||||
shm_name: Option<std::ffi::CString>,
|
||||
@ -41,7 +42,7 @@ impl<'a> ExpectMemory<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn create_or_reuse_mmap(shm_name: &str) -> Self {
|
||||
pub fn create_or_reuse_mmap(shm_name: &str) -> Self {
|
||||
let cstring = std::ffi::CString::new(shm_name).unwrap();
|
||||
Self::mmap_help(cstring, libc::O_RDWR | libc::O_CREAT)
|
||||
}
|
||||
@ -54,19 +55,38 @@ impl<'a> ExpectMemory<'a> {
|
||||
fn mmap_help(cstring: std::ffi::CString, shm_flags: i32) -> Self {
|
||||
let ptr = unsafe {
|
||||
let shared_fd = libc::shm_open(cstring.as_ptr().cast(), shm_flags, 0o666);
|
||||
if shared_fd == -1 {
|
||||
internal_error!("failed to shm_open fd");
|
||||
}
|
||||
|
||||
libc::ftruncate(shared_fd, Self::SHM_SIZE as _);
|
||||
// NOTE: we can only call `ftruncate` once on this file descriptor on mac
|
||||
if libc::ftruncate(shared_fd, Self::SHM_SIZE as _) == -1 {
|
||||
internal_error!("failed to truncate shared file, are the permissions wrong?");
|
||||
}
|
||||
|
||||
libc::mmap(
|
||||
let ptr = libc::mmap(
|
||||
std::ptr::null_mut(),
|
||||
Self::SHM_SIZE,
|
||||
libc::PROT_WRITE | libc::PROT_READ,
|
||||
libc::MAP_SHARED,
|
||||
shared_fd,
|
||||
0,
|
||||
)
|
||||
);
|
||||
|
||||
if ptr as usize == usize::MAX {
|
||||
// ptr = -1
|
||||
roc_error_macros::internal_error!("failed to mmap shared pointer")
|
||||
}
|
||||
|
||||
// fill the buffer with a fill pattern
|
||||
libc::memset(ptr, 0xAA, Self::SHM_SIZE);
|
||||
|
||||
ptr
|
||||
};
|
||||
|
||||
// puts in the initial header
|
||||
let _ = ExpectSequence::new(ptr as *mut u8);
|
||||
|
||||
Self {
|
||||
ptr: ptr.cast(),
|
||||
length: Self::SHM_SIZE,
|
||||
@ -83,7 +103,34 @@ impl<'a> ExpectMemory<'a> {
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn run_expects<'a, W: std::io::Write>(
|
||||
pub fn run_inline_expects<'a, W: std::io::Write>(
|
||||
writer: &mut W,
|
||||
render_target: RenderTarget,
|
||||
arena: &'a Bump,
|
||||
interns: &'a Interns,
|
||||
layout_interner: &Arc<GlobalInterner<'a, Layout<'a>>>,
|
||||
lib: &libloading::Library,
|
||||
expectations: &mut VecMap<ModuleId, Expectations>,
|
||||
expects: ExpectFunctions<'_>,
|
||||
) -> std::io::Result<(usize, usize)> {
|
||||
let shm_name = format!("/roc_expect_buffer_{}", std::process::id());
|
||||
let mut memory = ExpectMemory::create_or_reuse_mmap(&shm_name);
|
||||
|
||||
run_expects_with_memory(
|
||||
writer,
|
||||
render_target,
|
||||
arena,
|
||||
interns,
|
||||
layout_interner,
|
||||
lib,
|
||||
expectations,
|
||||
expects,
|
||||
&mut memory,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn run_toplevel_expects<'a, W: std::io::Write>(
|
||||
writer: &mut W,
|
||||
render_target: RenderTarget,
|
||||
arena: &'a Bump,
|
||||
@ -325,14 +372,16 @@ fn run_expect_fx<'a, W: std::io::Write>(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn roc_dev_expect<'a>(
|
||||
pub fn render_expects_in_memory<'a>(
|
||||
writer: &mut impl std::io::Write,
|
||||
arena: &'a Bump,
|
||||
expectations: &mut VecMap<ModuleId, Expectations>,
|
||||
interns: &'a Interns,
|
||||
layout_interner: &Arc<GlobalInterner<'a, Layout<'a>>>,
|
||||
shared_ptr: *mut u8,
|
||||
memory: &ExpectMemory,
|
||||
) -> std::io::Result<usize> {
|
||||
let shared_ptr = memory.ptr;
|
||||
|
||||
let frame = ExpectFrame::at_offset(shared_ptr, ExpectSequence::START_OFFSET);
|
||||
let module_id = frame.module_id;
|
||||
|
||||
|
@ -73,6 +73,41 @@ pub unsafe extern "C" fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn roc_getppid() -> libc::pid_t {
|
||||
libc::getppid()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn roc_mmap(
|
||||
addr: *mut libc::c_void,
|
||||
len: libc::size_t,
|
||||
prot: libc::c_int,
|
||||
flags: libc::c_int,
|
||||
fd: libc::c_int,
|
||||
offset: libc::off_t,
|
||||
) -> *mut libc::c_void {
|
||||
libc::mmap(addr, len, prot, flags, fd, offset)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn roc_shm_open(
|
||||
name: *const libc::c_char,
|
||||
oflag: libc::c_int,
|
||||
mode: libc::mode_t,
|
||||
) -> libc::c_int {
|
||||
libc::shm_open(name, oflag, mode as libc::c_uint)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn roc_send_signal(pid: libc::pid_t, sig: libc::c_int) -> libc::c_int {
|
||||
libc::kill(pid, sig)
|
||||
}
|
||||
|
||||
fn print_backtrace() {
|
||||
eprintln!("Here is the call stack that led to the crash:\n");
|
||||
|
||||
@ -263,7 +298,7 @@ pub extern "C" fn roc_fx_exePath(roc_str: &RocStr) -> RocResult<RocList<u8>, ()>
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn roc_fx_stdinLine() -> RocStr {
|
||||
use std::io::{self, BufRead};
|
||||
use std::io::BufRead;
|
||||
|
||||
let stdin = io::stdin();
|
||||
let line1 = stdin.lock().lines().next().unwrap().unwrap();
|
||||
|
@ -1,6 +1,6 @@
|
||||
const std = @import("std");
|
||||
const str = @import("str");
|
||||
const builtin = @import("builtin");
|
||||
const str = @import("str");
|
||||
const RocStr = str.RocStr;
|
||||
const testing = std.testing;
|
||||
const expectEqual = testing.expectEqual;
|
||||
@ -85,6 +85,34 @@ export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||
return memset(dst, value, size);
|
||||
}
|
||||
|
||||
extern fn kill(pid: c_int, sig: c_int) c_int;
|
||||
extern fn shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int;
|
||||
extern fn mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque;
|
||||
extern fn getppid() c_int;
|
||||
|
||||
fn roc_getppid() callconv(.C) c_int {
|
||||
return getppid();
|
||||
}
|
||||
|
||||
fn roc_send_signal(pid: c_int, sig: c_int) callconv(.C) c_int {
|
||||
return kill(pid, sig);
|
||||
}
|
||||
fn roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) callconv(.C) c_int {
|
||||
return shm_open(name, oflag, mode);
|
||||
}
|
||||
fn roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) callconv(.C) *anyopaque {
|
||||
return mmap(addr, length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
comptime {
|
||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
@export(roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||
@export(roc_mmap, .{ .name = "roc_mmap", .linkage = .Strong });
|
||||
@export(roc_send_signal, .{ .name = "roc_send_signal", .linkage = .Strong });
|
||||
@export(roc_shm_open, .{ .name = "roc_shm_open", .linkage = .Strong });
|
||||
}
|
||||
}
|
||||
|
||||
const Unit = extern struct {};
|
||||
|
||||
pub export fn main() u8 {
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use core::alloc::Layout;
|
||||
use core::ffi::c_void;
|
||||
use core::mem::{ManuallyDrop, MaybeUninit};
|
||||
use core::mem::MaybeUninit;
|
||||
use libc;
|
||||
use roc_std::{RocList, RocStr};
|
||||
use std::env;
|
||||
@ -72,6 +72,41 @@ pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut
|
||||
libc::memset(dst, c, n)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn roc_getppid() -> libc::pid_t {
|
||||
libc::getppid()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn roc_mmap(
|
||||
addr: *mut libc::c_void,
|
||||
len: libc::size_t,
|
||||
prot: libc::c_int,
|
||||
flags: libc::c_int,
|
||||
fd: libc::c_int,
|
||||
offset: libc::off_t,
|
||||
) -> *mut libc::c_void {
|
||||
libc::mmap(addr, len, prot, flags, fd, offset)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn roc_shm_open(
|
||||
name: *const libc::c_char,
|
||||
oflag: libc::c_int,
|
||||
mode: libc::mode_t,
|
||||
) -> libc::c_int {
|
||||
libc::shm_open(name, oflag, mode as libc::c_uint)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn roc_send_signal(pid: libc::pid_t, sig: libc::c_int) -> libc::c_int {
|
||||
libc::kill(pid, sig)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_main() -> i32 {
|
||||
let arg = env::args()
|
||||
@ -122,9 +157,7 @@ unsafe fn call_the_closure(closure_data_ptr: *const u8) -> i64 {
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn roc_fx_getLine() -> RocStr {
|
||||
use std::io::{self, BufRead};
|
||||
|
||||
let stdin = io::stdin();
|
||||
let stdin = std::io::stdin();
|
||||
let line1 = stdin.lock().lines().next().unwrap().unwrap();
|
||||
|
||||
RocStr::from(line1.as_str())
|
||||
@ -132,11 +165,10 @@ pub extern "C" fn roc_fx_getLine() -> RocStr {
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn roc_fx_getChar() -> u8 {
|
||||
use std::io::{self, BufRead};
|
||||
let mut buffer = [0];
|
||||
|
||||
if let Err(ioerr) = io::stdin().lock().read_exact(&mut buffer[..]) {
|
||||
if ioerr.kind() == io::ErrorKind::UnexpectedEof {
|
||||
if let Err(ioerr) = std::io::stdin().lock().read_exact(&mut buffer[..]) {
|
||||
if ioerr.kind() == std::io::ErrorKind::UnexpectedEof {
|
||||
u8::MAX
|
||||
} else {
|
||||
panic!("Got an unexpected error while reading char from stdin");
|
||||
|
@ -1,6 +1,6 @@
|
||||
const std = @import("std");
|
||||
const str = @import("str");
|
||||
const builtin = @import("builtin");
|
||||
const str = @import("str");
|
||||
const RocStr = str.RocStr;
|
||||
const testing = std.testing;
|
||||
const expectEqual = testing.expectEqual;
|
||||
@ -144,6 +144,34 @@ export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||
return memset(dst, value, size);
|
||||
}
|
||||
|
||||
extern fn kill(pid: c_int, sig: c_int) c_int;
|
||||
extern fn shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int;
|
||||
extern fn mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque;
|
||||
extern fn getppid() c_int;
|
||||
|
||||
fn roc_getppid() callconv(.C) c_int {
|
||||
return getppid();
|
||||
}
|
||||
|
||||
fn roc_send_signal(pid: c_int, sig: c_int) callconv(.C) c_int {
|
||||
return kill(pid, sig);
|
||||
}
|
||||
fn roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) callconv(.C) c_int {
|
||||
return shm_open(name, oflag, mode);
|
||||
}
|
||||
fn roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) callconv(.C) *anyopaque {
|
||||
return mmap(addr, length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
comptime {
|
||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
@export(roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||
@export(roc_mmap, .{ .name = "roc_mmap", .linkage = .Strong });
|
||||
@export(roc_send_signal, .{ .name = "roc_send_signal", .linkage = .Strong });
|
||||
@export(roc_shm_open, .{ .name = "roc_shm_open", .linkage = .Strong });
|
||||
}
|
||||
}
|
||||
|
||||
const Unit = extern struct {};
|
||||
|
||||
pub export fn main() callconv(.C) u8 {
|
||||
|
@ -95,6 +95,11 @@ void *roc_memset(void *str, int c, size_t n) {
|
||||
return memset(str, c, n);
|
||||
}
|
||||
|
||||
int roc_send_signal(int pid, int sig) { return kill(pid, sig); }
|
||||
int roc_shm_open(char* name, int oflag, int mode) { return shm_open(name, oflag, mode); }
|
||||
void* roc_mmap(void* addr, int length, int prot, int flags, int fd, int offset) { return mmap(addr, length, prot, flags, fd, offset); }
|
||||
int roc_getppid() { return getppid(); }
|
||||
|
||||
struct RocStr {
|
||||
char *bytes;
|
||||
size_t len;
|
||||
|
@ -27,6 +27,12 @@ void* roc_memcpy(void* dest, const void* src, size_t n) {
|
||||
|
||||
void* roc_memset(void* str, int c, size_t n) { return memset(str, c, n); }
|
||||
|
||||
|
||||
int roc_send_signal(int pid, int sig) { return kill(pid, sig); }
|
||||
int roc_shm_open(char* name, int oflag, int mode) { return shm_open(name, oflag, mode); }
|
||||
void* roc_mmap(void* addr, int length, int prot, int flags, int fd, int offset) { return mmap(addr, length, prot, flags, fd, offset); }
|
||||
int roc_getppid() { return getppid(); }
|
||||
|
||||
struct RocStr {
|
||||
char* bytes;
|
||||
size_t len;
|
||||
|
@ -54,6 +54,41 @@ pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut
|
||||
libc::memset(dst, c, n)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn roc_getppid() -> libc::pid_t {
|
||||
libc::getppid()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn roc_mmap(
|
||||
addr: *mut libc::c_void,
|
||||
len: libc::size_t,
|
||||
prot: libc::c_int,
|
||||
flags: libc::c_int,
|
||||
fd: libc::c_int,
|
||||
offset: libc::off_t,
|
||||
) -> *mut libc::c_void {
|
||||
libc::mmap(addr, len, prot, flags, fd, offset)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn roc_shm_open(
|
||||
name: *const libc::c_char,
|
||||
oflag: libc::c_int,
|
||||
mode: libc::mode_t,
|
||||
) -> libc::c_int {
|
||||
libc::shm_open(name, oflag, mode as libc::c_uint)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn roc_send_signal(pid: libc::pid_t, sig: libc::c_int) -> libc::c_int {
|
||||
libc::kill(pid, sig)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_main() -> i32 {
|
||||
let mut roc_str = RocStr::default();
|
||||
|
@ -75,6 +75,34 @@ export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||
return memset(dst, value, size);
|
||||
}
|
||||
|
||||
extern fn kill(pid: c_int, sig: c_int) c_int;
|
||||
extern fn shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int;
|
||||
extern fn mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque;
|
||||
extern fn getppid() c_int;
|
||||
|
||||
fn roc_getppid() callconv(.C) c_int {
|
||||
return getppid();
|
||||
}
|
||||
|
||||
fn roc_send_signal(pid: c_int, sig: c_int) callconv(.C) c_int {
|
||||
return kill(pid, sig);
|
||||
}
|
||||
fn roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) callconv(.C) c_int {
|
||||
return shm_open(name, oflag, mode);
|
||||
}
|
||||
fn roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) callconv(.C) *anyopaque {
|
||||
return mmap(addr, length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
comptime {
|
||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
@export(roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||
@export(roc_mmap, .{ .name = "roc_mmap", .linkage = .Strong });
|
||||
@export(roc_send_signal, .{ .name = "roc_send_signal", .linkage = .Strong });
|
||||
@export(roc_shm_open, .{ .name = "roc_shm_open", .linkage = .Strong });
|
||||
}
|
||||
}
|
||||
|
||||
const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
@ -103,4 +131,4 @@ pub fn main() u8 {
|
||||
stderr.print("runtime: {d:.3}ms\n", .{seconds * 1000}) catch unreachable;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,11 @@ void* roc_memcpy(void* dest, const void* src, size_t n) {
|
||||
|
||||
void* roc_memset(void* str, int c, size_t n) { return memset(str, c, n); }
|
||||
|
||||
int roc_send_signal(int pid, int sig) { return kill(pid, sig); }
|
||||
int roc_shm_open(char* name, int oflag, int mode) { return shm_open(name, oflag, mode); }
|
||||
void* roc_mmap(void* addr, int length, int prot, int flags, int fd, int offset) { return mmap(addr, length, prot, flags, fd, offset); }
|
||||
int roc_getppid() { return getppid(); }
|
||||
|
||||
struct RocStr {
|
||||
char* bytes;
|
||||
size_t len;
|
||||
|
@ -33,6 +33,41 @@ pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) {
|
||||
libc::free(c_ptr)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn roc_getppid() -> libc::pid_t {
|
||||
libc::getppid()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn roc_mmap(
|
||||
addr: *mut libc::c_void,
|
||||
len: libc::size_t,
|
||||
prot: libc::c_int,
|
||||
flags: libc::c_int,
|
||||
fd: libc::c_int,
|
||||
offset: libc::off_t,
|
||||
) -> *mut libc::c_void {
|
||||
libc::mmap(addr, len, prot, flags, fd, offset)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn roc_shm_open(
|
||||
name: *const libc::c_char,
|
||||
oflag: libc::c_int,
|
||||
mode: libc::mode_t,
|
||||
) -> libc::c_int {
|
||||
libc::shm_open(name, oflag, mode as libc::c_uint)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn roc_send_signal(pid: libc::pid_t, sig: libc::c_int) -> libc::c_int {
|
||||
libc::kill(pid, sig)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_main() -> i32 {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
|
Loading…
Reference in New Issue
Block a user