mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 05:49:08 +00:00
added layout
This commit is contained in:
parent
d82f3ee09d
commit
c991451265
1 changed files with 215 additions and 192 deletions
|
@ -143,30 +143,55 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
|
|||
// The tag is reusable.
|
||||
Reuse::Reusable(union_layout) => {
|
||||
// See if we have a token.
|
||||
match environment.pop_reuse_token(&ReuseLayout {
|
||||
layout_info: get_reuse_layout_info(
|
||||
layout_interner,
|
||||
target_info,
|
||||
union_layout,
|
||||
),
|
||||
// placeholder layout
|
||||
layout,
|
||||
}) {
|
||||
match environment.pop_reuse_token(&get_reuse_layout_info(
|
||||
layout_interner,
|
||||
target_info,
|
||||
union_layout,
|
||||
)) {
|
||||
// We have a reuse token for this layout, use it.
|
||||
Some(reuse_token) => {
|
||||
let new_symbol = Symbol::new(home, ident_ids.gen_unique());
|
||||
(
|
||||
Some((reuse_token.symbol, new_symbol, layout)),
|
||||
Expr::Reuse {
|
||||
symbol: new_symbol,
|
||||
update_mode: reuse_token.update_mode_id,
|
||||
// for now, always overwrite the tag ID just to be sure
|
||||
update_tag_id: true,
|
||||
tag_layout: *tag_layout,
|
||||
tag_id: *tag_id,
|
||||
arguments,
|
||||
},
|
||||
)
|
||||
Some(TokenWithInLayout {
|
||||
token: reuse_token,
|
||||
inlayout: layout_info,
|
||||
}) => {
|
||||
// The reuse token layout is the same, we can use it without casting.
|
||||
if layout_info == layout {
|
||||
(
|
||||
None,
|
||||
Expr::Reuse {
|
||||
symbol: reuse_token.symbol,
|
||||
update_mode: reuse_token.update_mode_id,
|
||||
// for now, always overwrite the tag ID just to be sure
|
||||
update_tag_id: true,
|
||||
tag_layout: *tag_layout,
|
||||
tag_id: *tag_id,
|
||||
arguments,
|
||||
},
|
||||
)
|
||||
}
|
||||
// The reuse token has a different layout from the tag, we need to pointercast it before.
|
||||
else {
|
||||
let new_symbol =
|
||||
Symbol::new(home, ident_ids.gen_unique());
|
||||
(
|
||||
Some(move |new_let| {
|
||||
arena.alloc(Stmt::Let(
|
||||
new_symbol,
|
||||
create_ptr_cast(arena, reuse_token.symbol),
|
||||
*layout,
|
||||
new_let,
|
||||
))
|
||||
}),
|
||||
Expr::Reuse {
|
||||
symbol: new_symbol,
|
||||
update_mode: reuse_token.update_mode_id,
|
||||
// for now, always overwrite the tag ID just to be sure
|
||||
update_tag_id: true,
|
||||
tag_layout: *tag_layout,
|
||||
tag_id: *tag_id,
|
||||
arguments,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// We have no reuse token available, keep the old expression with a fresh allocation.
|
||||
|
@ -202,18 +227,7 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
|
|||
arena.alloc(Stmt::Let(*binding, new_expr, *layout, new_continuation));
|
||||
match reused {
|
||||
// The layout for the reuse does not match that of the reset, use PtrCast to convert the layout.
|
||||
Some((old_symbol, new_symbol, layout)) => arena.alloc(Stmt::Let(
|
||||
new_symbol,
|
||||
Expr::Call(crate::ir::Call {
|
||||
call_type: crate::ir::CallType::LowLevel {
|
||||
op: roc_module::low_level::LowLevel::PtrCast,
|
||||
update_mode: UpdateModeId::BACKEND_DUMMY,
|
||||
},
|
||||
arguments: Vec::from_iter_in([old_symbol], arena).into_bump_slice(),
|
||||
}),
|
||||
*layout,
|
||||
new_let,
|
||||
)),
|
||||
Some(wrap) => wrap(new_let),
|
||||
None => new_let,
|
||||
}
|
||||
},
|
||||
|
@ -317,37 +331,37 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
|
|||
// Then we drop any unused reuse tokens in branches where the minimum is not reached.
|
||||
let msg =
|
||||
"All layouts in the environment should be in the layout_min_reuse_tokens map.";
|
||||
let newer_branches =
|
||||
Vec::from_iter_in(
|
||||
new_branches
|
||||
.iter()
|
||||
.map(|(label, info, branch, branch_env)| {
|
||||
let unused_tokens = branch_env.reuse_tokens.iter().flat_map(
|
||||
|(layout, reuse_tokens)| {
|
||||
let min_reuse_tokens =
|
||||
layout_min_reuse_tokens.get(layout).expect(msg);
|
||||
&reuse_tokens[*min_reuse_tokens..]
|
||||
},
|
||||
);
|
||||
let newer_branches = Vec::from_iter_in(
|
||||
new_branches
|
||||
.iter()
|
||||
.map(|(label, info, branch, branch_env)| {
|
||||
let unused_tokens = branch_env
|
||||
.reuse_tokens
|
||||
.iter()
|
||||
.flat_map(|(layout, reuse_tokens)| {
|
||||
let min_reuse_tokens =
|
||||
layout_min_reuse_tokens.get(layout).expect(msg);
|
||||
&reuse_tokens[*min_reuse_tokens..]
|
||||
})
|
||||
.map(|token_with_layout| token_with_layout.token);
|
||||
|
||||
let newer_branch =
|
||||
drop_unused_reuse_tokens(arena, unused_tokens.copied(), branch);
|
||||
let newer_branch = drop_unused_reuse_tokens(arena, unused_tokens, branch);
|
||||
|
||||
(*label, info.clone(), newer_branch.clone())
|
||||
}),
|
||||
arena,
|
||||
)
|
||||
.into_bump_slice();
|
||||
(*label, info.clone(), newer_branch.clone())
|
||||
}),
|
||||
arena,
|
||||
)
|
||||
.into_bump_slice();
|
||||
|
||||
let newer_default_branch = {
|
||||
// let (info, branch, branch_env) = new_default_branch;
|
||||
let unused_tokens= new_default_branch.2.reuse_tokens.iter().flat_map(|(layout, reuse_tokens) |{
|
||||
let min_reuse_tokens = layout_min_reuse_tokens.get(layout).expect("All layouts in the environment should be in the layout_min_reuse_tokens map.");
|
||||
&reuse_tokens[*min_reuse_tokens..]
|
||||
});
|
||||
}).map(|token_with_layout|{token_with_layout.token});
|
||||
|
||||
let newer_branch =
|
||||
drop_unused_reuse_tokens(arena, unused_tokens.copied(), new_default_branch.1);
|
||||
drop_unused_reuse_tokens(arena, unused_tokens, new_default_branch.1);
|
||||
|
||||
(new_default_branch.0, newer_branch)
|
||||
};
|
||||
|
@ -414,15 +428,13 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
|
|||
|
||||
environment.push_reuse_token(
|
||||
arena,
|
||||
ReuseLayout {
|
||||
layout_info: get_reuse_layout_info(
|
||||
layout_interner,
|
||||
target_info,
|
||||
union_layout,
|
||||
),
|
||||
layout,
|
||||
},
|
||||
get_reuse_layout_info(
|
||||
layout_interner,
|
||||
target_info,
|
||||
union_layout,
|
||||
),
|
||||
reuse_token,
|
||||
layout,
|
||||
);
|
||||
Some((layout, union_layout, *symbol, reuse_token, dec_ref))
|
||||
}
|
||||
|
@ -447,25 +459,21 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
|
|||
|
||||
// If we inserted a reuse token, we need to insert a reset reuse operation if the reuse token is consumed.
|
||||
if let Some((layout, union_layout, symbol, reuse_token, dec_ref)) = reuse_pair {
|
||||
let stack_reuse_token = environment.peek_reuse_token(&ReuseLayout {
|
||||
layout_info: get_reuse_layout_info(layout_interner, target_info, union_layout),
|
||||
// placeholder
|
||||
layout,
|
||||
});
|
||||
let stack_reuse_token = environment.peek_reuse_token(&get_reuse_layout_info(
|
||||
layout_interner,
|
||||
target_info,
|
||||
union_layout,
|
||||
));
|
||||
|
||||
match stack_reuse_token {
|
||||
Some(reuse_symbol) if reuse_symbol == reuse_token => {
|
||||
Some(token_with_layout) if token_with_layout.token == reuse_token => {
|
||||
// The token we inserted is still on the stack, so we don't need to insert a reset operation.
|
||||
// We do need to remove the token from the environment. To prevent errors higher in the tree.
|
||||
let _ = environment.pop_reuse_token(&ReuseLayout {
|
||||
layout_info: get_reuse_layout_info(
|
||||
layout_interner,
|
||||
target_info,
|
||||
union_layout,
|
||||
),
|
||||
// placeholder
|
||||
layout,
|
||||
});
|
||||
let _ = environment.pop_reuse_token(&get_reuse_layout_info(
|
||||
layout_interner,
|
||||
target_info,
|
||||
union_layout,
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
// The token we inserted is no longer on the stack, it must have been consumed.
|
||||
|
@ -617,24 +625,21 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
|
|||
let max_reuse_tokens =
|
||||
match first_pass_remainder_environment.get_jump_reuse_tokens(*joinpoint_id) {
|
||||
Some(all_reuse_maps) => {
|
||||
let all_reuse_layouts = all_reuse_maps
|
||||
let all_token_layouts = all_reuse_maps
|
||||
.iter()
|
||||
.flat_map(|reuse_map| reuse_map.keys())
|
||||
// PERF: replace this collect with an unique iterator. To make sure every layout is only used once.
|
||||
.collect::<MutSet<_>>()
|
||||
.into_iter();
|
||||
let reuse_layouts_max_tokens = all_reuse_layouts.map(|reuse_layout| {
|
||||
let max_token = all_reuse_maps
|
||||
let reuse_layouts_max_tokens = all_token_layouts.map(|token_layout| {
|
||||
// We get the tokens from the jump with the most tokens for this token layout.
|
||||
// So we have an inlayout for each token. And can cast when needed.
|
||||
let max_token_inlayouts = all_reuse_maps
|
||||
.iter()
|
||||
.map(|reuse_map| {
|
||||
reuse_map
|
||||
.get(reuse_layout)
|
||||
.map(|tokens| tokens.len())
|
||||
.unwrap_or(0)
|
||||
})
|
||||
.max()
|
||||
.filter_map(|reuse_map| reuse_map.get(token_layout))
|
||||
.max_by_key(|tokens| tokens.len())
|
||||
.expect("all layouts should be in at least one of the reuse maps");
|
||||
(reuse_layout, max_token)
|
||||
(token_layout, max_token_inlayouts)
|
||||
});
|
||||
Vec::from_iter_in(reuse_layouts_max_tokens, arena)
|
||||
}
|
||||
|
@ -647,13 +652,17 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
|
|||
// For each possibly available reuse token, create a reuse token to add to the join point environment.
|
||||
let max_reuse_token_symbols = max_reuse_tokens
|
||||
.iter()
|
||||
.map(|(layout, size)| {
|
||||
.copied()
|
||||
.map(|(token_layout, tokens)| {
|
||||
(
|
||||
**layout,
|
||||
*token_layout,
|
||||
Vec::from_iter_in(
|
||||
(0..*size).map(|_| ReuseToken {
|
||||
symbol: Symbol::new(home, ident_ids.gen_unique()),
|
||||
update_mode_id: update_mode_ids.next_id(),
|
||||
tokens.iter().map(|token| TokenWithInLayout {
|
||||
token: ReuseToken {
|
||||
symbol: Symbol::new(home, ident_ids.gen_unique()),
|
||||
update_mode_id: update_mode_ids.next_id(),
|
||||
},
|
||||
inlayout: token.inlayout,
|
||||
}),
|
||||
arena,
|
||||
),
|
||||
|
@ -753,9 +762,9 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
|
|||
|
||||
let layouts_for_reuse = {
|
||||
let mut layouts = Vec::from_iter_in(
|
||||
used_reuse_tokens
|
||||
.iter()
|
||||
.flat_map(|(layout, tokens)| tokens.iter().map(|_| *layout)),
|
||||
used_reuse_tokens.iter().flat_map(|(layout, tokens)| {
|
||||
tokens.iter().map(|token| (token.inlayout, *layout))
|
||||
}),
|
||||
arena,
|
||||
);
|
||||
// Make sure the layouts are sorted, so that we can provide them from the jump.
|
||||
|
@ -803,10 +812,10 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
|
|||
let token_params =
|
||||
layouts_for_reuse_with_token
|
||||
.into_iter()
|
||||
.map(|(reuse_layout, token)| Param {
|
||||
symbol: token.symbol,
|
||||
.map(|(_reuse_layout, token)| Param {
|
||||
symbol: token.token.symbol,
|
||||
ownership: Ownership::Owned,
|
||||
layout: *reuse_layout.layout,
|
||||
layout: *token.inlayout,
|
||||
});
|
||||
|
||||
// Add the void tokens to the jump arguments to match the expected arguments of the join point.
|
||||
|
@ -900,36 +909,64 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
|
|||
|
||||
let token_layouts_clone = token_layouts.clone();
|
||||
|
||||
let mut reuse_tokens_to_cast = Vec::new_in(arena);
|
||||
let mut void_pointer_layout_symbols = Vec::new_in(arena);
|
||||
|
||||
// See what tokens we can get from the env, if none are available, use a void pointer.
|
||||
let tokens = token_layouts_clone.iter().map(|token_layout| {
|
||||
environment.pop_reuse_token(token_layout).map_or_else(
|
||||
|| match void_pointer_layout_symbols
|
||||
.iter()
|
||||
.find(|(layout, _)| layout == token_layout)
|
||||
{
|
||||
Some(existing_symbol) => existing_symbol.1,
|
||||
None => {
|
||||
let new_symbol = Symbol::new(home, ident_ids.gen_unique());
|
||||
void_pointer_layout_symbols.push((*token_layout, new_symbol));
|
||||
new_symbol
|
||||
let tokens = token_layouts_clone
|
||||
.iter()
|
||||
.map(|(param_layout, token_layout)| {
|
||||
match environment.pop_reuse_token(token_layout) {
|
||||
Some(reuse_token) => {
|
||||
if reuse_token.inlayout != *param_layout {
|
||||
let new_symbol = Symbol::new(home, ident_ids.gen_unique());
|
||||
reuse_tokens_to_cast.push((
|
||||
*param_layout,
|
||||
reuse_token.token.symbol,
|
||||
new_symbol,
|
||||
));
|
||||
new_symbol
|
||||
} else {
|
||||
reuse_token.token.symbol
|
||||
}
|
||||
}
|
||||
},
|
||||
|reuse_token| reuse_token.symbol,
|
||||
)
|
||||
});
|
||||
None => match void_pointer_layout_symbols
|
||||
.iter()
|
||||
.find(|(layout, _)| layout == layout)
|
||||
{
|
||||
Some(existing_symbol) => existing_symbol.1,
|
||||
None => {
|
||||
let new_symbol = Symbol::new(home, ident_ids.gen_unique());
|
||||
void_pointer_layout_symbols
|
||||
.push((*param_layout, new_symbol));
|
||||
new_symbol
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
// Add the void tokens to the jump arguments to match the expected arguments of the join point.
|
||||
let extended_arguments =
|
||||
Vec::from_iter_in(arguments.iter().copied().chain(tokens), arena)
|
||||
.into_bump_slice();
|
||||
|
||||
let casted_tokens = reuse_tokens_to_cast.into_iter().fold(
|
||||
arena.alloc(Stmt::Jump(*id, extended_arguments)),
|
||||
|child, (layout, old_symbol, new_symbol)| {
|
||||
arena.alloc(Stmt::Let(
|
||||
new_symbol,
|
||||
create_ptr_cast(arena, old_symbol),
|
||||
*layout,
|
||||
child,
|
||||
))
|
||||
},
|
||||
);
|
||||
|
||||
// Wrap the jump in a let statement for each void pointer token layout.
|
||||
void_pointer_layout_symbols.into_iter().fold(
|
||||
arena.alloc(Stmt::Jump(*id, extended_arguments)),
|
||||
|child, (layout, symbol)| {
|
||||
arena.alloc(Stmt::Let(symbol, Expr::NullPointer, *layout.layout, child))
|
||||
casted_tokens,
|
||||
|child, (param_layout, symbol)| {
|
||||
arena.alloc(Stmt::Let(symbol, Expr::NullPointer, *param_layout, child))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -941,26 +978,22 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
|
|||
|
||||
// We currently don't pass any reuse tokens to recursive jumps.
|
||||
// This is to avoid keeping reuse tokens alive for too long. But it could be changed.
|
||||
let mut void_pointer_layout_symbols: std::vec::Vec<(ReuseLayout, Symbol)> =
|
||||
let mut void_pointer_layout_symbols: std::vec::Vec<(&'a InLayout<'a>, Symbol)> =
|
||||
vec![];
|
||||
|
||||
let void_tokens =
|
||||
token_layouts
|
||||
let void_tokens = token_layouts.iter().map(|(param_layout, _token_layout)| {
|
||||
match void_pointer_layout_symbols
|
||||
.iter()
|
||||
.map(|token_layout| {
|
||||
match void_pointer_layout_symbols
|
||||
.iter()
|
||||
.find(|(layout, _)| layout == token_layout)
|
||||
{
|
||||
Some(existing_symbol) => existing_symbol.1,
|
||||
None => {
|
||||
let new_symbol = Symbol::new(home, ident_ids.gen_unique());
|
||||
void_pointer_layout_symbols
|
||||
.push((*token_layout, new_symbol));
|
||||
new_symbol
|
||||
}
|
||||
}
|
||||
});
|
||||
.find(|(void_layout, _)| void_layout == param_layout)
|
||||
{
|
||||
Some(existing_symbol) => existing_symbol.1,
|
||||
None => {
|
||||
let new_symbol = Symbol::new(home, ident_ids.gen_unique());
|
||||
void_pointer_layout_symbols.push((*param_layout, new_symbol));
|
||||
new_symbol
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Add the void tokens to the jump arguments to match the expected arguments of the join point.
|
||||
let extended_arguments =
|
||||
|
@ -970,13 +1003,8 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
|
|||
// Wrap the jump in a let statement for each void pointer token layout.
|
||||
void_pointer_layout_symbols.into_iter().fold(
|
||||
arena.alloc(Stmt::Jump(*id, extended_arguments)),
|
||||
|child, (reuse_layout, symbol)| {
|
||||
arena.alloc(Stmt::Let(
|
||||
symbol,
|
||||
Expr::NullPointer,
|
||||
*reuse_layout.layout,
|
||||
child,
|
||||
))
|
||||
|child, (layout, symbol)| {
|
||||
arena.alloc(Stmt::Let(symbol, Expr::NullPointer, *layout, child))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -986,6 +1014,16 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
|
|||
}
|
||||
}
|
||||
|
||||
fn create_ptr_cast(arena: &Bump, symbol: Symbol) -> Expr {
|
||||
Expr::Call(crate::ir::Call {
|
||||
call_type: crate::ir::CallType::LowLevel {
|
||||
op: roc_module::low_level::LowLevel::PtrCast,
|
||||
update_mode: UpdateModeId::BACKEND_DUMMY,
|
||||
},
|
||||
arguments: Vec::from_iter_in([symbol], arena).into_bump_slice(),
|
||||
})
|
||||
}
|
||||
|
||||
// TODO make sure all dup/drop operations are already inserted statically.
|
||||
// (e.g. not as a side effect of another operation) To make sure we can actually reuse.
|
||||
|
||||
|
@ -999,52 +1037,18 @@ enum Reuse<'a> {
|
|||
Map containing the reuse tokens of a layout.
|
||||
A vec is used as a stack as we want to use the latest reuse token available.
|
||||
*/
|
||||
type ReuseTokens<'a> = MutMap<ReuseLayout<'a>, Vec<'a, ReuseToken>>;
|
||||
type ReuseTokens<'a> = MutMap<TokenLayout, Vec<'a, TokenWithInLayout<'a>>>;
|
||||
|
||||
/**
|
||||
Struct to to check whether two reuse layouts are interchangeable.
|
||||
*/
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
struct ReuseLayoutInfo {
|
||||
struct TokenLayout {
|
||||
has_tag: bool,
|
||||
size: u32,
|
||||
alignment: u32,
|
||||
}
|
||||
|
||||
/**
|
||||
Struct containing the layout of a reuse token, and the layout of the contained union.
|
||||
Hashing/Equality is only done on the union layout. And the normal layout is kept for bookkeeping.
|
||||
*/
|
||||
#[derive(Clone, Copy, Eq)]
|
||||
struct ReuseLayout<'a> {
|
||||
layout_info: ReuseLayoutInfo,
|
||||
layout: &'a InLayout<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Hash for ReuseLayout<'a> {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.layout_info.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq for ReuseLayout<'a> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.layout_info == other.layout_info
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialOrd for ReuseLayout<'a> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
self.layout_info.partial_cmp(&other.layout_info)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Ord for ReuseLayout<'a> {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.layout_info.cmp(&other.layout_info)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
A reuse token is a symbol that is used to reset a layout.
|
||||
Matches symbols that are pointers.
|
||||
|
@ -1058,6 +1062,15 @@ struct ReuseToken {
|
|||
update_mode_id: UpdateModeId,
|
||||
}
|
||||
|
||||
/**
|
||||
Combines a reuse token with it's possible layout info.
|
||||
*/
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
struct TokenWithInLayout<'a> {
|
||||
token: ReuseToken,
|
||||
inlayout: &'a InLayout<'a>,
|
||||
}
|
||||
|
||||
type Tag = u16;
|
||||
|
||||
/**
|
||||
|
@ -1083,7 +1096,7 @@ enum JoinPointReuseTokens<'a> {
|
|||
BodyFirst,
|
||||
|
||||
// Second body pass, to update any jump calls to pass void pointer parameters instead of no parameters.
|
||||
BodySecond(Vec<'a, ReuseLayout<'a>>),
|
||||
BodySecond(Vec<'a, (&'a InLayout<'a>, TokenLayout)>),
|
||||
|
||||
// The first pass is used to determine the amount of reuse tokens a join point can expect.
|
||||
// Therefore, we don't know the amount of reuse tokens yet.
|
||||
|
@ -1091,7 +1104,7 @@ enum JoinPointReuseTokens<'a> {
|
|||
|
||||
// In the second pass, we determined the amount of reuse tokens a join point can expect.
|
||||
// Therefore, we know the amount of reuse tokens and can use.
|
||||
RemainderSecond(Vec<'a, ReuseLayout<'a>>),
|
||||
RemainderSecond(Vec<'a, (&'a InLayout<'a>, TokenLayout)>),
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
|
@ -1124,13 +1137,13 @@ impl<'a> ReuseEnvironment<'a> {
|
|||
/**
|
||||
Retrieve a reuse token for a layout from the stack for said layout.
|
||||
*/
|
||||
fn pop_reuse_token(&mut self, layout: &ReuseLayout<'a>) -> Option<ReuseToken> {
|
||||
let reuse_tokens = self.reuse_tokens.get_mut(layout)?;
|
||||
fn pop_reuse_token(&mut self, token_layout: &TokenLayout) -> Option<TokenWithInLayout> {
|
||||
let reuse_tokens = self.reuse_tokens.get_mut(token_layout)?;
|
||||
// If the layout is in the map, pop the token from the stack.
|
||||
let reuse_token = reuse_tokens.pop();
|
||||
// If the stack is empty, remove the layout from the map.
|
||||
if reuse_tokens.is_empty() {
|
||||
self.reuse_tokens.remove(layout);
|
||||
self.reuse_tokens.remove(token_layout);
|
||||
}
|
||||
reuse_token
|
||||
}
|
||||
|
@ -1139,8 +1152,8 @@ impl<'a> ReuseEnvironment<'a> {
|
|||
Retrieve a reuse token for a layout from the stack for said layout.
|
||||
Without consuming the token.
|
||||
*/
|
||||
fn peek_reuse_token(&mut self, layout: &ReuseLayout<'a>) -> Option<ReuseToken> {
|
||||
let reuse_tokens = self.reuse_tokens.get(layout)?;
|
||||
fn peek_reuse_token(&mut self, token_layout: &TokenLayout) -> Option<TokenWithInLayout> {
|
||||
let reuse_tokens = self.reuse_tokens.get(token_layout)?;
|
||||
// If the layout is in the map, peek at the last element.
|
||||
let reuse_token = reuse_tokens.last();
|
||||
reuse_token.copied()
|
||||
|
@ -1149,16 +1162,26 @@ impl<'a> ReuseEnvironment<'a> {
|
|||
/**
|
||||
Push a reuse token for a layout on the stack for said layout.
|
||||
*/
|
||||
fn push_reuse_token(&mut self, arena: &'a Bump, layout: ReuseLayout<'a>, token: ReuseToken) {
|
||||
match self.reuse_tokens.get_mut(&layout) {
|
||||
fn push_reuse_token(
|
||||
&mut self,
|
||||
arena: &'a Bump,
|
||||
token_layout: TokenLayout,
|
||||
reuse_token: ReuseToken,
|
||||
layout: &'a InLayout<'a>,
|
||||
) {
|
||||
let with_info = TokenWithInLayout {
|
||||
token: reuse_token,
|
||||
inlayout: layout,
|
||||
};
|
||||
match self.reuse_tokens.get_mut(&token_layout) {
|
||||
Some(reuse_tokens) => {
|
||||
// If the layout is already in the map, push the token on the stack.
|
||||
reuse_tokens.push(token);
|
||||
reuse_tokens.push(with_info);
|
||||
}
|
||||
None => {
|
||||
// If the layout is not in the map, create a new stack with the token.
|
||||
self.reuse_tokens
|
||||
.insert(layout, Vec::from_iter_in([token], arena));
|
||||
.insert(token_layout, Vec::from_iter_in([with_info], arena));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1322,7 +1345,7 @@ fn get_reuse_layout_info<'a, 'i>(
|
|||
layout_interner: &'i STLayoutInterner<'a>,
|
||||
target_info: TargetInfo,
|
||||
union_layout: UnionLayout<'a>,
|
||||
) -> ReuseLayoutInfo {
|
||||
) -> TokenLayout {
|
||||
let (size, alignment) = union_layout.data_size_and_alignment(layout_interner, target_info);
|
||||
let has_tag = match union_layout {
|
||||
UnionLayout::NonRecursive(_) => unreachable!("Non recursive unions should not be reused."),
|
||||
|
@ -1331,7 +1354,7 @@ fn get_reuse_layout_info<'a, 'i>(
|
|||
// The memory for union layouts that have no tag_id can be reused for new allocations without tag_id
|
||||
UnionLayout::NonNullableUnwrapped(_) | UnionLayout::NullableUnwrapped { .. } => false,
|
||||
};
|
||||
ReuseLayoutInfo {
|
||||
TokenLayout {
|
||||
has_tag,
|
||||
size,
|
||||
alignment,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue