forked from M-Labs/nac3
escape analysis: fixed some bugs regarding imprecise local
This commit is contained in:
parent
fb79b47b38
commit
ea5a8c95dc
@ -37,7 +37,7 @@ pub struct BasicBlockId(usize);
|
|||||||
pub enum LifetimeIR {
|
pub enum LifetimeIR {
|
||||||
VarAssign { var: StrRef, lifetime: LifetimeId },
|
VarAssign { var: StrRef, lifetime: LifetimeId },
|
||||||
VarAccess { var: StrRef },
|
VarAccess { var: StrRef },
|
||||||
FieldAssign { obj: LifetimeId, field: StrRef, new: LifetimeId },
|
FieldAssign { obj: LifetimeId, field: StrRef, new: LifetimeId, is_init: bool },
|
||||||
FieldAccess { obj: LifetimeId, field: StrRef },
|
FieldAccess { obj: LifetimeId, field: StrRef },
|
||||||
CreateLifetime { kind: LifetimeKind },
|
CreateLifetime { kind: LifetimeKind },
|
||||||
PassedToFunc { param_lifetimes: Vec<LifetimeId> },
|
PassedToFunc { param_lifetimes: Vec<LifetimeId> },
|
||||||
@ -123,7 +123,7 @@ impl LifetimeIRBuilder {
|
|||||||
LifetimeIR::Branch { targets } => {
|
LifetimeIR::Branch { targets } => {
|
||||||
destination_mapping.insert(i, targets);
|
destination_mapping.insert(i, targets);
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -339,14 +339,23 @@ impl<'a> LifetimeAnalyzer<'a> {
|
|||||||
self.lifetime_stores.remove(rhs_id);
|
self.lifetime_stores.remove(rhs_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_field_lifetime(&self, obj: LifetimeId, field: StrRef) -> LifetimeId {
|
fn get_field_lifetime(&mut self, obj: LifetimeId, field: StrRef) -> LifetimeId {
|
||||||
use LifetimeKind::*;
|
use LifetimeKind::*;
|
||||||
let id = *self.lifetime_to_id.get(&obj).unwrap();
|
let id = *self.lifetime_to_id.get(&obj).unwrap();
|
||||||
let store = &self.lifetime_stores.get(id).unwrap();
|
let store = self.lifetime_stores.get(id).unwrap();
|
||||||
if let Some(lifetime) = store.fields.get(&field) {
|
if matches!(store.kind, PreciseLocal | ImpreciseLocal) {
|
||||||
*lifetime
|
if let Some(&lifetime) = store.fields.get(&field) {
|
||||||
} else if matches!(store.kind, PreciseLocal | ImpreciseLocal) {
|
let field_lifetime_kind = self.get_lifetime_kind(lifetime);
|
||||||
LifetimeId(0)
|
if field_lifetime_kind == PreciseLocal
|
||||||
|
&& (store.kind == ImpreciseLocal || field == "$elem".into())
|
||||||
|
{
|
||||||
|
let id = *self.lifetime_to_id.get(&lifetime).unwrap();
|
||||||
|
self.lifetime_stores.get_mut(id).unwrap().to_mut().kind = ImpreciseLocal;
|
||||||
|
}
|
||||||
|
lifetime
|
||||||
|
} else {
|
||||||
|
LifetimeId(0)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
obj
|
obj
|
||||||
}
|
}
|
||||||
@ -357,6 +366,7 @@ impl<'a> LifetimeAnalyzer<'a> {
|
|||||||
obj: LifetimeId,
|
obj: LifetimeId,
|
||||||
field: StrRef,
|
field: StrRef,
|
||||||
field_lifetime: LifetimeId,
|
field_lifetime: LifetimeId,
|
||||||
|
is_init: bool,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
use LifetimeKind::*;
|
use LifetimeKind::*;
|
||||||
let obj_id = *self.lifetime_to_id.get(&obj).unwrap();
|
let obj_id = *self.lifetime_to_id.get(&obj).unwrap();
|
||||||
@ -377,15 +387,15 @@ impl<'a> LifetimeAnalyzer<'a> {
|
|||||||
}
|
}
|
||||||
PreciseLocal | ImpreciseLocal => {
|
PreciseLocal | ImpreciseLocal => {
|
||||||
// weak update
|
// weak update
|
||||||
let old_lifetime = obj_store
|
let old_lifetime = obj_store.to_mut().fields.get(&field).copied();
|
||||||
.to_mut()
|
|
||||||
.fields
|
|
||||||
.get(&field)
|
|
||||||
.copied();
|
|
||||||
if let Some(old_lifetime) = old_lifetime {
|
if let Some(old_lifetime) = old_lifetime {
|
||||||
self.unify(old_lifetime, field_lifetime);
|
self.unify(old_lifetime, field_lifetime);
|
||||||
} else {
|
} else {
|
||||||
obj_store.to_mut().fields.insert(field, field_lifetime);
|
obj_store.to_mut().fields.insert(field, field_lifetime);
|
||||||
|
if !is_init {
|
||||||
|
// unify with unknown lifetime
|
||||||
|
self.unify(LifetimeId(0), field_lifetime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
@ -455,8 +465,8 @@ impl<'a> LifetimeAnalyzer<'a> {
|
|||||||
self.add_lifetime(id, LifetimeKind::Static)
|
self.add_lifetime(id, LifetimeKind::Static)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FieldAssign { obj, field, new } => {
|
FieldAssign { obj, field, new, is_init } => {
|
||||||
self.set_field_lifetime(*obj, *field, *new)
|
self.set_field_lifetime(*obj, *field, *new, *is_init)
|
||||||
.map_err(|e| format!("{} in {}", e, loc))?;
|
.map_err(|e| format!("{} in {}", e, loc))?;
|
||||||
}
|
}
|
||||||
FieldAccess { obj, field } => {
|
FieldAccess { obj, field } => {
|
||||||
@ -490,7 +500,7 @@ impl<'a> LifetimeAnalyzer<'a> {
|
|||||||
}
|
}
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
Branch { targets } => return Ok(Some(targets))
|
Branch { targets } => return Ok(Some(targets)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
@ -153,6 +153,7 @@ impl<'a> EscapeAnalyzer<'a> {
|
|||||||
obj: list_lifetime,
|
obj: list_lifetime,
|
||||||
field: "$elem".into(),
|
field: "$elem".into(),
|
||||||
new: elem_lifetime,
|
new: elem_lifetime,
|
||||||
|
is_init: true,
|
||||||
},
|
},
|
||||||
loc,
|
loc,
|
||||||
);
|
);
|
||||||
@ -165,6 +166,7 @@ impl<'a> EscapeAnalyzer<'a> {
|
|||||||
obj: list_lifetime,
|
obj: list_lifetime,
|
||||||
field: "$elem".into(),
|
field: "$elem".into(),
|
||||||
new: elem_lifetime,
|
new: elem_lifetime,
|
||||||
|
is_init: true,
|
||||||
},
|
},
|
||||||
loc,
|
loc,
|
||||||
);
|
);
|
||||||
@ -183,6 +185,7 @@ impl<'a> EscapeAnalyzer<'a> {
|
|||||||
obj: tuple_lifetime,
|
obj: tuple_lifetime,
|
||||||
field: format!("$elem{}", i).into(),
|
field: format!("$elem{}", i).into(),
|
||||||
new: lifetime,
|
new: lifetime,
|
||||||
|
is_init: true,
|
||||||
},
|
},
|
||||||
loc,
|
loc,
|
||||||
);
|
);
|
||||||
@ -208,6 +211,7 @@ impl<'a> EscapeAnalyzer<'a> {
|
|||||||
obj: slice_lifetime,
|
obj: slice_lifetime,
|
||||||
field: "$elem".into(),
|
field: "$elem".into(),
|
||||||
new: slice_elem,
|
new: slice_elem,
|
||||||
|
is_init: true
|
||||||
},
|
},
|
||||||
loc,
|
loc,
|
||||||
);
|
);
|
||||||
@ -249,7 +253,9 @@ impl<'a> EscapeAnalyzer<'a> {
|
|||||||
}
|
}
|
||||||
match &func.node {
|
match &func.node {
|
||||||
ExprKind::Name { id, .. } => {
|
ExprKind::Name { id, .. } => {
|
||||||
self.builder.append_ir(PassedToFunc { param_lifetimes: lifetimes }, loc);
|
if !lifetimes.is_empty() {
|
||||||
|
self.builder.append_ir(PassedToFunc { param_lifetimes: lifetimes }, loc);
|
||||||
|
}
|
||||||
if need_alloca {
|
if need_alloca {
|
||||||
let id = self
|
let id = self
|
||||||
.resolver
|
.resolver
|
||||||
@ -342,6 +348,7 @@ impl<'a> EscapeAnalyzer<'a> {
|
|||||||
obj: list_lifetime,
|
obj: list_lifetime,
|
||||||
field: "$elem".into(),
|
field: "$elem".into(),
|
||||||
new: elem_lifetime,
|
new: elem_lifetime,
|
||||||
|
is_init: true
|
||||||
},
|
},
|
||||||
elt.location,
|
elt.location,
|
||||||
);
|
);
|
||||||
@ -365,7 +372,7 @@ impl<'a> EscapeAnalyzer<'a> {
|
|||||||
let value_lifetime = self.handle_expr(value)?.unwrap();
|
let value_lifetime = self.handle_expr(value)?.unwrap();
|
||||||
if let Some(field_lifetime) = rhs_lifetime {
|
if let Some(field_lifetime) = rhs_lifetime {
|
||||||
self.builder.append_ir(
|
self.builder.append_ir(
|
||||||
FieldAssign { obj: value_lifetime, field: *attr, new: field_lifetime },
|
FieldAssign { obj: value_lifetime, field: *attr, new: field_lifetime, is_init: false },
|
||||||
lhs.location,
|
lhs.location,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -396,6 +403,7 @@ impl<'a> EscapeAnalyzer<'a> {
|
|||||||
obj: value_lifetime,
|
obj: value_lifetime,
|
||||||
field: "$elem".into(),
|
field: "$elem".into(),
|
||||||
new: elem_lifetime,
|
new: elem_lifetime,
|
||||||
|
is_init: false
|
||||||
},
|
},
|
||||||
lhs.location,
|
lhs.location,
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user