mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 19:58:18 +00:00
Specialize erased
This commit is contained in:
parent
d17d8c72ad
commit
2cb2e37fd7
5 changed files with 104 additions and 42 deletions
|
@ -1041,6 +1041,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[Ownership] {
|
|||
|
||||
PtrStore => arena.alloc_slice_copy(&[owned, owned]),
|
||||
PtrLoad => arena.alloc_slice_copy(&[owned]),
|
||||
PtrCast => arena.alloc_slice_copy(&[owned]),
|
||||
Alloca => arena.alloc_slice_copy(&[owned]),
|
||||
|
||||
PtrClearTagId | PtrCast | RefCountIncRcPtr | RefCountDecRcPtr | RefCountIncDataPtr
|
||||
|
|
|
@ -1598,6 +1598,7 @@ fn low_level_no_rc(lowlevel: &LowLevel) -> RC {
|
|||
// only inserted for internal purposes. RC should not touch it
|
||||
PtrStore => RC::NoRc,
|
||||
PtrLoad => RC::NoRc,
|
||||
PtrCast => RC::NoRc,
|
||||
Alloca => RC::NoRc,
|
||||
|
||||
PtrClearTagId | PtrCast | RefCountIncRcPtr | RefCountDecRcPtr | RefCountIncDataPtr
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::{collections::HashMap, hash::BuildHasherDefault};
|
|||
use bumpalo::collections::{CollectIn, Vec};
|
||||
use bumpalo::Bump;
|
||||
use roc_collections::{all::WyHash, MutMap, MutSet};
|
||||
use roc_error_macros::{internal_error, todo_lambda_erasure};
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::low_level::LowLevel;
|
||||
use roc_module::{low_level::LowLevelWrapperType, symbol::Symbol};
|
||||
|
||||
|
@ -946,8 +946,13 @@ fn insert_refcount_operations_binding<'a>(
|
|||
|
||||
inc_owned!(arguments.iter().copied(), new_let)
|
||||
}
|
||||
// A normal Roc function call, but we don't actually know where its target is.
|
||||
// As such, we assume that it takes all parameters as owned, as will the function
|
||||
// itself.
|
||||
CallType::ByPointer { .. } => {
|
||||
todo_lambda_erasure!()
|
||||
let new_let = new_let!(stmt);
|
||||
|
||||
inc_owned!(arguments.iter().copied(), new_let)
|
||||
}
|
||||
CallType::Foreign { .. } => {
|
||||
// Foreign functions should be responsible for their own memory management.
|
||||
|
|
|
@ -4027,7 +4027,17 @@ impl<'a> ProcLayout<'a> {
|
|||
lambda_set.extend_argument_list_for_named(arena, lambda_name, arguments);
|
||||
ProcLayout::new(arena, arguments, lambda_name.niche(), result)
|
||||
}
|
||||
RawFunctionLayout::ErasedFunction(..) => todo_lambda_erasure!(),
|
||||
RawFunctionLayout::ErasedFunction(arguments, result) => {
|
||||
let arguments = if lambda_name.no_captures() {
|
||||
arguments
|
||||
} else {
|
||||
let mut extended_args = Vec::with_capacity_in(arguments.len(), arena);
|
||||
extended_args.extend(arguments.iter().chain(&[Layout::OPAQUE_PTR]).copied());
|
||||
extended_args.into_bump_slice()
|
||||
};
|
||||
|
||||
ProcLayout::new(arena, arguments, lambda_name.niche(), result)
|
||||
}
|
||||
RawFunctionLayout::ZeroArgumentThunk(result) => {
|
||||
ProcLayout::new(arena, &[], Niche::NONE, result)
|
||||
}
|
||||
|
@ -8219,14 +8229,31 @@ fn specialize_symbol<'a>(
|
|||
)
|
||||
}
|
||||
}
|
||||
RawFunctionLayout::ErasedFunction(..) => erased::build_erased_function(
|
||||
env,
|
||||
layout_cache,
|
||||
original,
|
||||
captured,
|
||||
assign_to,
|
||||
result,
|
||||
),
|
||||
RawFunctionLayout::ErasedFunction(..) => {
|
||||
let erased_lambda =
|
||||
erased::ResolvedErasedLambda::new(env, layout_cache, original, captured);
|
||||
let lambda_name = erased_lambda.lambda_name();
|
||||
|
||||
let proc_layout =
|
||||
ProcLayout::from_raw_named(env.arena, lambda_name, res_layout);
|
||||
|
||||
procs.insert_passed_by_name(
|
||||
env,
|
||||
arg_var,
|
||||
lambda_name,
|
||||
proc_layout,
|
||||
layout_cache,
|
||||
);
|
||||
|
||||
erased::build_erased_function(
|
||||
env,
|
||||
layout_cache,
|
||||
erased_lambda,
|
||||
captured,
|
||||
assign_to,
|
||||
result,
|
||||
)
|
||||
}
|
||||
RawFunctionLayout::ZeroArgumentThunk(ret_layout) => {
|
||||
// this is a 0-argument thunk
|
||||
let top_level = ProcLayout::new(env.arena, &[], Niche::NONE, ret_layout);
|
||||
|
|
|
@ -283,7 +283,7 @@ pub fn call_erased_function<'a>(
|
|||
pub fn build_erased_function<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
lambda_symbol: Symbol,
|
||||
resolved_lambda: ResolvedErasedLambda<'a>,
|
||||
captures: CapturedSymbols<'a>,
|
||||
assigned: Symbol,
|
||||
hole: &'a Stmt<'a>,
|
||||
|
@ -310,34 +310,10 @@ pub fn build_erased_function<'a>(
|
|||
env.arena.alloc(result),
|
||||
);
|
||||
|
||||
struct ResolvedCaptures<'a> {
|
||||
layouts: &'a [InLayout<'a>],
|
||||
symbols: &'a [Symbol],
|
||||
}
|
||||
|
||||
let resolved_captures;
|
||||
let lambda_name;
|
||||
match captures {
|
||||
CapturedSymbols::None => {
|
||||
resolved_captures = None;
|
||||
lambda_name = LambdaName::from_captures(lambda_symbol, &[]);
|
||||
}
|
||||
CapturedSymbols::Captured(captures) => {
|
||||
let layouts = {
|
||||
let layouts = captures
|
||||
.iter()
|
||||
.map(|(_, var)| layout_cache.from_var(env.arena, *var, env.subs).unwrap());
|
||||
env.arena.alloc_slice_fill_iter(layouts)
|
||||
};
|
||||
let symbols = {
|
||||
let symbols = captures.iter().map(|(sym, _)| *sym);
|
||||
env.arena.alloc_slice_fill_iter(symbols)
|
||||
};
|
||||
|
||||
resolved_captures = Some(ResolvedCaptures { layouts, symbols });
|
||||
lambda_name = LambdaName::from_captures(lambda_symbol, layouts);
|
||||
}
|
||||
};
|
||||
let ResolvedErasedLambda {
|
||||
captures,
|
||||
lambda_name,
|
||||
} = resolved_lambda;
|
||||
|
||||
// callee = Expr::FunctionPointer(f)
|
||||
let result = Stmt::Let(
|
||||
|
@ -348,7 +324,7 @@ pub fn build_erased_function<'a>(
|
|||
);
|
||||
|
||||
// value = Expr::Box({s})
|
||||
match resolved_captures {
|
||||
match captures {
|
||||
None => {
|
||||
// value = nullptr
|
||||
// <hole>
|
||||
|
@ -359,7 +335,7 @@ pub fn build_erased_function<'a>(
|
|||
env.arena.alloc(result),
|
||||
)
|
||||
}
|
||||
Some(ResolvedCaptures { layouts, symbols }) => {
|
||||
Some(ResolvedErasedCaptures { layouts, symbols }) => {
|
||||
// captures = {...captures}
|
||||
// captures = Box(captures)
|
||||
// value = Cast(captures, void*)
|
||||
|
@ -406,3 +382,55 @@ pub fn build_erased_function<'a>(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ResolvedErasedCaptures<'a> {
|
||||
layouts: &'a [InLayout<'a>],
|
||||
symbols: &'a [Symbol],
|
||||
}
|
||||
|
||||
pub struct ResolvedErasedLambda<'a> {
|
||||
captures: Option<ResolvedErasedCaptures<'a>>,
|
||||
lambda_name: LambdaName<'a>,
|
||||
}
|
||||
|
||||
impl<'a> ResolvedErasedLambda<'a> {
|
||||
pub fn new(
|
||||
env: &Env<'a, '_>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
lambda_symbol: Symbol,
|
||||
captures: CapturedSymbols<'a>,
|
||||
) -> Self {
|
||||
let resolved_captures;
|
||||
let lambda_name;
|
||||
match captures {
|
||||
CapturedSymbols::None => {
|
||||
resolved_captures = None;
|
||||
lambda_name = LambdaName::from_captures(lambda_symbol, &[]);
|
||||
}
|
||||
CapturedSymbols::Captured(captures) => {
|
||||
let layouts = {
|
||||
let layouts = captures
|
||||
.iter()
|
||||
.map(|(_, var)| layout_cache.from_var(env.arena, *var, env.subs).unwrap());
|
||||
env.arena.alloc_slice_fill_iter(layouts)
|
||||
};
|
||||
let symbols = {
|
||||
let symbols = captures.iter().map(|(sym, _)| *sym);
|
||||
env.arena.alloc_slice_fill_iter(symbols)
|
||||
};
|
||||
|
||||
resolved_captures = Some(ResolvedErasedCaptures { layouts, symbols });
|
||||
lambda_name = LambdaName::from_captures(lambda_symbol, layouts);
|
||||
}
|
||||
};
|
||||
|
||||
Self {
|
||||
captures: resolved_captures,
|
||||
lambda_name,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lambda_name(&self) -> LambdaName<'a> {
|
||||
self.lambda_name
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue