mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 19:58:18 +00:00
thread layout interner to repl_expect
This commit is contained in:
parent
a5cb759a82
commit
67494e9df2
6 changed files with 123 additions and 25 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -3452,6 +3452,7 @@ dependencies = [
|
|||
"roc_fmt",
|
||||
"roc_gen_llvm",
|
||||
"roc_glue",
|
||||
"roc_intern",
|
||||
"roc_linker",
|
||||
"roc_load",
|
||||
"roc_module",
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -5,6 +5,7 @@ use roc_build::{
|
|||
};
|
||||
use roc_builtins::bitcode;
|
||||
use roc_collections::VecMap;
|
||||
use roc_intern::SingleThreadedInterner;
|
||||
use roc_load::{
|
||||
EntryPoint, ExecutionMode, Expectations, LoadConfig, LoadMonomorphizedError, LoadedModule,
|
||||
LoadingProblem, Threading,
|
||||
|
@ -30,12 +31,13 @@ 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 layout_interner: SingleThreadedInterner<'a, roc_mono::layout::Layout<'a>>,
|
||||
}
|
||||
|
||||
pub enum BuildOrdering {
|
||||
|
@ -69,7 +71,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);
|
||||
|
||||
|
@ -242,6 +244,7 @@ pub fn build_file<'a>(
|
|||
let mut loaded = loaded;
|
||||
let problems = program::report_problems_monomorphized(&mut loaded);
|
||||
let expectations = std::mem::take(&mut loaded.expectations);
|
||||
let layout_interner = loaded.layout_interner.clone();
|
||||
let loaded = loaded;
|
||||
|
||||
let interns = loaded.interns.clone();
|
||||
|
@ -388,6 +391,7 @@ pub fn build_file<'a>(
|
|||
total_time,
|
||||
interns,
|
||||
expectations,
|
||||
layout_interner,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,11 @@ use roc_build::link::{LinkType, LinkingStrategy};
|
|||
use roc_build::program::Problems;
|
||||
use roc_collections::VecMap;
|
||||
use roc_error_macros::{internal_error, user_error};
|
||||
use roc_intern::SingleThreadedInterner;
|
||||
use roc_load::{Expectations, LoadingProblem, Threading};
|
||||
use roc_module::symbol::{Interns, ModuleId};
|
||||
use roc_mono::ir::OptLevel;
|
||||
use roc_mono::layout::Layout;
|
||||
use std::env;
|
||||
use std::ffi::{CString, OsStr};
|
||||
use std::io;
|
||||
|
@ -561,6 +563,7 @@ pub fn build(
|
|||
total_time,
|
||||
expectations,
|
||||
interns,
|
||||
layout_interner,
|
||||
}) => {
|
||||
match config {
|
||||
BuildOnly => {
|
||||
|
@ -573,7 +576,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}");
|
||||
|
@ -596,7 +599,16 @@ 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,
|
||||
expectations,
|
||||
interns,
|
||||
layout_interner,
|
||||
)
|
||||
}
|
||||
BuildAndRunIfNoErrors => {
|
||||
debug_assert!(
|
||||
|
@ -617,7 +629,16 @@ 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,
|
||||
expectations,
|
||||
interns,
|
||||
layout_interner,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -683,13 +704,14 @@ 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, // This should be passed an owned value, not a reference, so we can usefully mem::forget it!
|
||||
opt_level: OptLevel,
|
||||
triple: Triple,
|
||||
args: I,
|
||||
binary_bytes: &[u8],
|
||||
expectations: VecMap<ModuleId, Expectations>,
|
||||
interns: Interns,
|
||||
layout_interner: SingleThreadedInterner<Layout>,
|
||||
) -> io::Result<i32> {
|
||||
match triple.architecture {
|
||||
Architecture::Wasm32 => {
|
||||
|
@ -728,7 +750,15 @@ 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,
|
||||
expectations,
|
||||
interns,
|
||||
layout_interner,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -777,12 +807,13 @@ fn make_argv_envp<'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,
|
||||
layout_interner: SingleThreadedInterner<Layout>,
|
||||
) -> std::io::Result<i32> {
|
||||
use bumpalo::collections::CollectIn;
|
||||
|
||||
|
@ -794,18 +825,24 @@ 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)
|
||||
}
|
||||
OptLevel::Development => roc_run_native_debug(
|
||||
arena,
|
||||
executable,
|
||||
argv,
|
||||
envp,
|
||||
expectations,
|
||||
interns,
|
||||
layout_interner,
|
||||
),
|
||||
OptLevel::Normal | OptLevel::Size | OptLevel::Optimize => {
|
||||
roc_run_native_fast(executable, &argv, &envp);
|
||||
}
|
||||
|
@ -882,14 +919,67 @@ 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,
|
||||
fn roc_run_native_debug(
|
||||
arena: &Bump,
|
||||
executable: ExecutableFile,
|
||||
argv: bumpalo::collections::Vec<*const c_char>,
|
||||
envp: bumpalo::collections::Vec<*const c_char>,
|
||||
mut expectations: VecMap<ModuleId, Expectations>,
|
||||
interns: Interns,
|
||||
layout_interner: SingleThreadedInterner<Layout>,
|
||||
) {
|
||||
todo!()
|
||||
use roc_repl_expect::run::ExpectMemory;
|
||||
use signal_hook::{consts::signal::SIGCHLD, consts::signal::SIGUSR1, iterator::Signals};
|
||||
|
||||
let mut signals = Signals::new(&[SIGCHLD, SIGUSR1]).unwrap();
|
||||
|
||||
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);
|
||||
},
|
||||
-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 => {
|
||||
// done!
|
||||
return;
|
||||
}
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
|
|
|
@ -60,7 +60,7 @@ pub struct ThreadLocalInterner<'a, K> {
|
|||
///
|
||||
/// The only way to construct such an interner is to collapse a shared [GlobalInterner] into
|
||||
/// a [SingleThreadedInterner], via [GlobalInterner::unwrap].
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SingleThreadedInterner<'a, K> {
|
||||
map: BumpMap<&'a K, Interned<K>>,
|
||||
vec: Vec<&'a K>,
|
||||
|
|
|
@ -19,7 +19,7 @@ use roc_reporting::{error::expect::Renderer, report::RenderTarget};
|
|||
use roc_target::TargetInfo;
|
||||
use target_lexicon::Triple;
|
||||
|
||||
pub(crate) struct ExpectMemory<'a> {
|
||||
pub struct ExpectMemory<'a> {
|
||||
ptr: *mut u8,
|
||||
length: usize,
|
||||
shm_name: Option<std::ffi::CString>,
|
||||
|
@ -39,7 +39,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)
|
||||
}
|
||||
|
@ -323,14 +323,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;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue