make the surgical linker aware of custom exported closure names

This commit is contained in:
Folkert 2022-01-25 00:13:22 +01:00
parent eb08c12099
commit 73bc50c952
7 changed files with 124 additions and 79 deletions

View File

@ -105,6 +105,21 @@ pub fn build_file<'a>(
// To do this we will need to preprocess files just for their exported symbols.
// Also, we should no longer need to do this once we have platforms on
// a package repository, as we can then get precompiled hosts from there.
let exposed_values = loaded
.exposed_to_host
.values
.keys()
.map(|x| x.as_str(&loaded.interns).to_string())
.collect();
let exposed_closure_types = loaded
.exposed_to_host
.closure_types
.iter()
.map(|x| x.as_str(&loaded.interns).to_string())
.collect();
let rebuild_thread = spawn_rebuild_thread(
opt_level,
surgically_link,
@ -112,11 +127,8 @@ pub fn build_file<'a>(
host_input_path.clone(),
binary_path.clone(),
target,
loaded
.exposed_to_host
.keys()
.map(|x| x.as_str(&loaded.interns).to_string())
.collect(),
exposed_values,
exposed_closure_types,
target_valgrind,
);
@ -291,6 +303,7 @@ fn spawn_rebuild_thread(
binary_path: PathBuf,
target: &Triple,
exported_symbols: Vec<String>,
exported_closure_types: Vec<String>,
target_valgrind: bool,
) -> std::thread::JoinHandle<u128> {
let thread_local_target = target.clone();
@ -305,6 +318,7 @@ fn spawn_rebuild_thread(
&thread_local_target,
host_input_path.as_path(),
exported_symbols,
exported_closure_types,
target_valgrind,
)
.unwrap();

View File

@ -146,8 +146,8 @@ pub fn gen_and_eval<'a>(
}
}
debug_assert_eq!(exposed_to_host.len(), 1);
let (main_fn_symbol, main_fn_var) = exposed_to_host.iter().next().unwrap();
debug_assert_eq!(exposed_to_host.values.len(), 1);
let (main_fn_symbol, main_fn_var) = exposed_to_host.values.iter().next().unwrap();
let main_fn_symbol = *main_fn_symbol;
let main_fn_var = *main_fn_var;

View File

@ -87,7 +87,7 @@ mod cli_run {
let compile_out = run_roc(&[&["build", file.to_str().unwrap()], &all_flags[..]].concat());
if !compile_out.stderr.is_empty() {
panic!("{}", compile_out.stderr);
panic!("roc build had stderr: {}", compile_out.stderr);
}
assert!(compile_out.status.success(), "bad status {:?}", compile_out);

View File

@ -753,49 +753,52 @@ fn link_linux(
// NOTE: order of arguments to `ld` matters here!
// The `-l` flags should go after the `.o` arguments
Ok((
Command::new("ld")
// Don't allow LD_ env vars to affect this
.env_clear()
.env("PATH", &env_path)
// Keep NIX_ env vars
.envs(
env::vars()
.filter(|&(ref k, _)| k.starts_with("NIX_"))
.collect::<HashMap<String, String>>(),
)
.args(&[
"--gc-sections",
"--eh-frame-hdr",
"-A",
arch_str(target),
"-pie",
libcrt_path.join("crti.o").to_str().unwrap(),
libcrt_path.join("crtn.o").to_str().unwrap(),
])
.args(&base_args)
.args(&["-dynamic-linker", ld_linux])
.args(input_paths)
// ld.lld requires this argument, and does not accept --arch
// .args(&["-L/usr/lib/x86_64-linux-gnu"])
.args(&[
// Libraries - see https://github.com/rtfeldman/roc/pull/554#discussion_r496365925
// for discussion and further references
"-lc",
"-lm",
"-lpthread",
"-ldl",
"-lrt",
"-lutil",
"-lc_nonshared",
libgcc_path.to_str().unwrap(),
// Output
"-o",
output_path.as_path().to_str().unwrap(), // app (or app.so or app.dylib etc.)
])
.spawn()?,
output_path,
))
let mut command = Command::new("ld");
command
// Don't allow LD_ env vars to affect this
.env_clear()
.env("PATH", &env_path)
// Keep NIX_ env vars
.envs(
env::vars()
.filter(|&(ref k, _)| k.starts_with("NIX_"))
.collect::<HashMap<String, String>>(),
)
.args(&[
"--gc-sections",
"--eh-frame-hdr",
"-A",
arch_str(target),
"-pie",
libcrt_path.join("crti.o").to_str().unwrap(),
libcrt_path.join("crtn.o").to_str().unwrap(),
])
.args(&base_args)
.args(&["-dynamic-linker", ld_linux])
.args(input_paths)
// ld.lld requires this argument, and does not accept --arch
// .args(&["-L/usr/lib/x86_64-linux-gnu"])
.args(&[
// Libraries - see https://github.com/rtfeldman/roc/pull/554#discussion_r496365925
// for discussion and further references
"-lc",
"-lm",
"-lpthread",
"-ldl",
"-lrt",
"-lutil",
"-lc_nonshared",
libgcc_path.to_str().unwrap(),
// Output
"-o",
output_path.as_path().to_str().unwrap(), // app (or app.so or app.dylib etc.)
]);
let output = command.spawn()?;
Ok((output, output_path))
}
fn link_macos(

View File

@ -290,7 +290,7 @@ pub fn gen_from_mono_module_llvm(
// in gen_tests, the compiler provides roc_panic
// and sets up the setjump/longjump exception handling
is_gen_test: false,
exposed_to_host: loaded.exposed_to_host.keys().copied().collect(),
exposed_to_host: loaded.exposed_to_host.values.keys().copied().collect(),
};
roc_gen_llvm::llvm::build::build_procedures(
@ -495,6 +495,7 @@ fn gen_from_mono_module_dev_wasm32(
let exposed_to_host = loaded
.exposed_to_host
.values
.keys()
.copied()
.collect::<MutSet<_>>();
@ -544,7 +545,7 @@ fn gen_from_mono_module_dev_assembly(
let env = roc_gen_dev::Env {
arena,
module_id,
exposed_to_host: exposed_to_host.keys().copied().collect(),
exposed_to_host: exposed_to_host.values.keys().copied().collect(),
lazy_literals,
generate_allocators,
};

View File

@ -737,11 +737,19 @@ pub struct MonomorphizedModule<'a> {
pub mono_problems: MutMap<ModuleId, Vec<roc_mono::ir::MonoProblem>>,
pub procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
pub entry_point: EntryPoint<'a>,
pub exposed_to_host: MutMap<Symbol, Variable>,
pub exposed_to_host: ExposedToHost,
pub sources: MutMap<ModuleId, (PathBuf, Box<str>)>,
pub timings: MutMap<ModuleId, ModuleTiming>,
}
#[derive(Clone, Debug, Default)]
pub struct ExposedToHost {
/// usually `mainForHost`
pub values: MutMap<Symbol, Variable>,
/// exposed closure types, typically `Fx`
pub closure_types: Vec<Symbol>,
}
impl<'a> MonomorphizedModule<'a> {
pub fn total_problems(&self) -> usize {
let mut total = 0;
@ -837,7 +845,7 @@ enum Msg<'a> {
/// all modules are now monomorphized, we are done
FinishedAllSpecialization {
subs: Subs,
exposed_to_host: MutMap<Symbol, Variable>,
exposed_to_host: ExposedToHost,
},
FailedToParse(FileError<'a, SyntaxError<'a>>),
@ -875,7 +883,7 @@ struct State<'a> {
pub module_cache: ModuleCache<'a>,
pub dependencies: Dependencies<'a>,
pub procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
pub exposed_to_host: MutMap<Symbol, Variable>,
pub exposed_to_host: ExposedToHost,
/// This is the "final" list of IdentIds, after canonicalization and constraint gen
/// have completed for a given module.
@ -1008,7 +1016,7 @@ enum BuildTask<'a> {
module_id: ModuleId,
ident_ids: IdentIds,
decls: Vec<Declaration>,
exposed_to_host: MutMap<Symbol, Variable>,
exposed_to_host: ExposedToHost,
},
MakeSpecializations {
module_id: ModuleId,
@ -1475,7 +1483,7 @@ where
module_cache: ModuleCache::default(),
dependencies: Dependencies::default(),
procedures: MutMap::default(),
exposed_to_host: MutMap::default(),
exposed_to_host: ExposedToHost::default(),
exposed_types,
arc_modules,
arc_shorthands,
@ -1937,12 +1945,17 @@ fn update<'a>(
};
if is_host_exposed {
state.exposed_to_host.extend(
state.exposed_to_host.values.extend(
solved_module
.exposed_vars_by_symbol
.iter()
.map(|(k, v)| (*k, *v)),
);
state
.exposed_to_host
.closure_types
.extend(solved_module.aliases.keys().copied());
}
if is_host_exposed && state.goal_phase == Phase::SolveTypes {
@ -2177,7 +2190,7 @@ fn update<'a>(
fn finish_specialization(
state: State,
subs: Subs,
exposed_to_host: MutMap<Symbol, Variable>,
exposed_to_host: ExposedToHost,
) -> Result<MonomorphizedModule, LoadingProblem> {
let module_ids = Arc::try_unwrap(state.arc_modules)
.unwrap_or_else(|_| panic!("There were still outstanding Arc references to module_ids"))
@ -2235,8 +2248,8 @@ fn finish_specialization(
let entry_point = {
let symbol = match platform_data {
None => {
debug_assert_eq!(exposed_to_host.len(), 1);
*exposed_to_host.iter().next().unwrap().0
debug_assert_eq!(exposed_to_host.values.len(), 1);
*exposed_to_host.values.iter().next().unwrap().0
}
Some(PlatformData { provides, .. }) => provides,
};
@ -3884,7 +3897,7 @@ fn build_pending_specializations<'a>(
mut layout_cache: LayoutCache<'a>,
ptr_bytes: u32,
// TODO remove
exposed_to_host: MutMap<Symbol, Variable>,
exposed_to_host: ExposedToHost,
) -> Msg<'a> {
let find_specializations_start = SystemTime::now();
@ -3924,7 +3937,7 @@ fn build_pending_specializations<'a>(
&mut module_thunks,
&mut mono_env,
def,
&exposed_to_host,
&exposed_to_host.values,
false,
),
DeclareRec(defs) => {
@ -3935,7 +3948,7 @@ fn build_pending_specializations<'a>(
&mut module_thunks,
&mut mono_env,
def,
&exposed_to_host,
&exposed_to_host.values,
true,
)
}

View File

@ -142,10 +142,11 @@ pub fn build_and_preprocess_host(
target: &Triple,
host_input_path: &Path,
exposed_to_host: Vec<String>,
exported_closure_types: Vec<String>,
target_valgrind: bool,
) -> io::Result<()> {
let dummy_lib = host_input_path.with_file_name("libapp.so");
generate_dynamic_lib(target, exposed_to_host, &dummy_lib)?;
generate_dynamic_lib(target, exposed_to_host, exported_closure_types, &dummy_lib)?;
rebuild_host(
opt_level,
target,
@ -193,6 +194,7 @@ pub fn link_preprocessed_host(
fn generate_dynamic_lib(
_target: &Triple,
exposed_to_host: Vec<String>,
exported_closure_types: Vec<String>,
dummy_lib_path: &Path,
) -> io::Result<()> {
let dummy_obj_file = Builder::new().prefix("roc_lib").suffix(".o").tempfile()?;
@ -203,25 +205,37 @@ fn generate_dynamic_lib(
write::Object::new(BinaryFormat::Elf, Architecture::X86_64, Endianness::Little);
let text_section = out_object.section_id(write::StandardSection::Text);
let mut add_symbol = |name: &String| {
out_object.add_symbol(write::Symbol {
name: name.as_bytes().to_vec(),
value: 0,
size: 0,
kind: SymbolKind::Text,
scope: SymbolScope::Dynamic,
weak: false,
section: write::SymbolSection::Section(text_section),
flags: SymbolFlags::None,
});
};
for sym in exposed_to_host {
for name in &[
format!("roc__{}_1_exposed", sym),
format!("roc__{}_1_exposed_generic", sym),
format!("roc__{}_1_Fx_caller", sym),
format!("roc__{}_1_Fx_size", sym),
format!("roc__{}_1_Fx_result_size", sym),
format!("roc__{}_size", sym),
] {
out_object.add_symbol(write::Symbol {
name: name.as_bytes().to_vec(),
value: 0,
size: 0,
kind: SymbolKind::Text,
scope: SymbolScope::Dynamic,
weak: false,
section: write::SymbolSection::Section(text_section),
flags: SymbolFlags::None,
});
add_symbol(name);
}
for closure_type in &exported_closure_types {
for name in &[
format!("roc__{}_1_{}_caller", sym, closure_type),
format!("roc__{}_1_{}_size", sym, closure_type),
format!("roc__{}_1_{}_result_size", sym, closure_type),
] {
add_symbol(name)
}
}
}
std::fs::write(