Merge branch 'glue-getters-rtfeldman' into pluggable-glue

This commit is contained in:
Brendan Hansknecht 2023-03-05 15:50:33 -08:00
commit 5573ab2275
No known key found for this signature in database
GPG key ID: 0EA784685083E75B
42 changed files with 4821 additions and 1011 deletions

View file

@ -1,5 +1,5 @@
use crate::roc_type;
use crate::types::{Env, Types};
use crate::types::Types;
use bumpalo::Bump;
use libloading::Library;
use roc_build::{
@ -9,12 +9,14 @@ use roc_build::{
BuildFileError, BuildOrdering, BuiltFile, CodeGenBackend, CodeGenOptions,
},
};
use roc_collections::MutMap;
use roc_load::{ExecutionMode, LoadConfig, LoadedModule, LoadingProblem, Threading};
use roc_mono::ir::OptLevel;
use roc_mono::layout::GlobalLayoutInterner;
use roc_mono::ir::{generate_glue_procs, GlueProc, OptLevel};
use roc_mono::layout::{GlobalLayoutInterner, LayoutCache, LayoutInterner};
use roc_packaging::cache::{self, RocCacheDir};
use roc_reporting::report::{RenderTarget, DEFAULT_PALETTE};
use roc_target::{Architecture, OperatingSystem, TargetInfo};
use roc_target::{Architecture, TargetInfo};
use roc_types::subs::{Subs, Variable};
use std::fs::File;
use std::io::{self, ErrorKind, Write};
use std::mem::ManuallyDrop;
@ -209,6 +211,120 @@ pub fn generate(input_path: &Path, output_path: &Path, spec_path: &Path) -> io::
}
}
fn number_lambda_sets(subs: &Subs, initial: Variable) -> Vec<Variable> {
let mut lambda_sets = vec![];
let mut stack = vec![initial];
macro_rules! var_slice {
($variable_subs_slice:expr) => {{
let slice = $variable_subs_slice;
subs.variables[slice.indices()].iter().rev()
}};
}
while let Some(var) = stack.pop() {
use roc_types::subs::Content::*;
use roc_types::subs::FlatType::*;
use roc_types::subs::GetSubsSlice;
use roc_types::types::Uls;
match subs.get_content_without_compacting(var) {
RigidVar(_) | RigidAbleVar(_, _) | FlexVar(_) | FlexAbleVar(_, _) | Error => (),
RecursionVar { .. } => {
// we got here, so we've treated this type already
}
Structure(flat_type) => match flat_type {
Apply(_, args) => {
stack.extend(var_slice!(*args));
}
Func(arg_vars, closure_var, ret_var) => {
lambda_sets.push(subs.get_root_key_without_compacting(*closure_var));
stack.push(*ret_var);
stack.push(*closure_var);
stack.extend(var_slice!(arg_vars));
}
EmptyRecord => (),
EmptyTagUnion => (),
EmptyTuple => (),
Record(fields, ext) => {
let fields = *fields;
let ext = *ext;
stack.push(ext);
stack.extend(var_slice!(fields.variables()));
}
Tuple(_, _) => todo!(),
TagUnion(tags, ext) => {
let tags = *tags;
let ext = *ext;
stack.push(ext.var());
for slice_index in tags.variables() {
let slice = subs.variable_slices[slice_index.index as usize];
stack.extend(var_slice!(slice));
}
}
FunctionOrTagUnion(_, _, ext) => {
stack.push(ext.var());
}
RecursiveTagUnion(rec_var, tags, ext) => {
let tags = *tags;
let ext = *ext;
let rec_var = *rec_var;
stack.push(ext.var());
for slice_index in tags.variables() {
let slice = subs.variable_slices[slice_index.index as usize];
stack.extend(var_slice!(slice));
}
stack.push(rec_var);
}
},
Alias(_, args, var, _) => {
let var = *var;
let args = *args;
stack.extend(var_slice!(args.all_variables()));
stack.push(var);
}
LambdaSet(roc_types::subs::LambdaSet {
solved,
recursion_var,
unspecialized,
ambient_function: _,
}) => {
for slice_index in solved.variables() {
let slice = subs.variable_slices[slice_index.index as usize];
stack.extend(var_slice!(slice));
}
if let Some(rec_var) = recursion_var.into_variable() {
stack.push(rec_var);
}
for Uls(var, _, _) in subs.get_subs_slice(*unspecialized) {
stack.push(*var);
}
}
&RangedNumber(_) => {}
}
}
lambda_sets
}
pub fn load_types(
full_file_path: PathBuf,
threading: Threading,
@ -223,6 +339,7 @@ pub fn load_types(
mut declarations_by_id,
mut solved,
interns,
exposed_to_host,
..
} = roc_load::load_and_typecheck(
arena,
@ -261,42 +378,90 @@ pub fn load_types(
);
}
// Get the variables for all the exposed_to_host symbols
let variables = (0..decls.len()).filter_map(|index| {
use roc_can::expr::DeclarationTag::*;
match decls.declarations[index] {
Value | Function(_) | Recursive(_) | TailRecursive(_) => Some(decls.variables[index]),
Destructure(_) => {
// figure out if we need to export non-identifier defs - when would that
// happen?
None
}
MutualRecursion { .. } => {
// handled by future iterations
None
}
Expectation | ExpectationFx => {
// not publicly visible
None
}
if exposed_to_host.contains_key(&decls.symbols[index].value) {
Some(decls.variables[index])
} else {
None
}
});
let layout_interner = GlobalLayoutInterner::with_capacity(128, target_info);
let operating_system = target_info.operating_system;
let architectures = Architecture::iter();
let mut arch_types = Vec::with_capacity(architectures.len());
for arch in architectures {
let layout_interner = GlobalLayoutInterner::with_capacity(128, target_info);
for architecture in architectures {
let mut interns = interns.clone(); // TODO there may be a way to avoid this.
let target_info = TargetInfo {
architecture: arch,
operating_system: OperatingSystem::Unix,
architecture,
operating_system,
};
let mut layout_cache = LayoutCache::new(layout_interner.fork(), target_info);
let mut glue_procs_by_layout = MutMap::default();
let types = {
let mut env = Env::new(arena, subs, &interns, layout_interner.fork(), target_info);
let mut extern_names = MutMap::default();
env.vars_to_types(variables.clone())
};
// Populate glue getters/setters for all relevant variables
for var in variables.clone() {
for (i, v) in number_lambda_sets(subs, var).iter().enumerate() {
extern_names.insert(*v, i.to_string());
}
let in_layout = layout_cache
.from_var(arena, var, subs)
.expect("Something weird ended up in the content");
let layout = layout_cache.interner.get(in_layout);
// dbg!(layout);
if layout.has_varying_stack_size(&layout_cache.interner, arena) {
let ident_ids = interns.all_ident_ids.get_mut(&home).unwrap();
let answer = generate_glue_procs(
home,
ident_ids,
arena,
&mut layout_interner.fork(),
arena.alloc(layout),
);
// Even though generate_glue_procs does more work than we need it to,
// it's important that we use it in order to make sure we get exactly
// the same names that mono::ir did for code gen!
for (layout, glue_procs) in answer.getters {
let mut names =
bumpalo::collections::Vec::with_capacity_in(glue_procs.len(), arena);
// Record all the getter/setter names associated with this layout
for GlueProc { name, .. } in glue_procs {
// Given a struct layout (including lambda sets!) the offsets - and therefore
// getters/setters - are deterministic, so we can use layout as the hash key
// for these getters/setters. We also only need to store the name because
// since they are getters and setters, we can know their types (from a
// TypeId perspective) deterministically based on knowing the types of
// the structs and fields.
//
// Store them as strings, because symbols won't be useful to glue generators!
names.push(name.as_str(&interns).to_string());
}
glue_procs_by_layout.insert(layout, names.into_bump_slice());
}
}
}
let types = Types::new(
arena,
subs,
variables.clone(),
arena.alloc(interns),
glue_procs_by_layout,
layout_cache,
target_info,
);
arch_types.push(types);
}