From ea5a8c95dcccfa01d0d3655ad67e893324395c4d Mon Sep 17 00:00:00 2001 From: pca006132 Date: Fri, 8 Apr 2022 20:16:48 +0800 Subject: [PATCH] escape analysis: fixed some bugs regarding imprecise local --- .../src/typecheck/escape_analysis/lifetime.rs | 42 ++++++++++++------- nac3core/src/typecheck/escape_analysis/mod.rs | 12 +++++- 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/nac3core/src/typecheck/escape_analysis/lifetime.rs b/nac3core/src/typecheck/escape_analysis/lifetime.rs index 942527e64..b71bdc95f 100644 --- a/nac3core/src/typecheck/escape_analysis/lifetime.rs +++ b/nac3core/src/typecheck/escape_analysis/lifetime.rs @@ -37,7 +37,7 @@ pub struct BasicBlockId(usize); pub enum LifetimeIR { VarAssign { var: StrRef, lifetime: LifetimeId }, 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 }, CreateLifetime { kind: LifetimeKind }, PassedToFunc { param_lifetimes: Vec }, @@ -123,7 +123,7 @@ impl LifetimeIRBuilder { LifetimeIR::Branch { targets } => { destination_mapping.insert(i, targets); } - _ => () + _ => (), } } } @@ -339,14 +339,23 @@ impl<'a> LifetimeAnalyzer<'a> { 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::*; let id = *self.lifetime_to_id.get(&obj).unwrap(); - let store = &self.lifetime_stores.get(id).unwrap(); - if let Some(lifetime) = store.fields.get(&field) { - *lifetime - } else if matches!(store.kind, PreciseLocal | ImpreciseLocal) { - LifetimeId(0) + let store = self.lifetime_stores.get(id).unwrap(); + if matches!(store.kind, PreciseLocal | ImpreciseLocal) { + if let Some(&lifetime) = store.fields.get(&field) { + let field_lifetime_kind = self.get_lifetime_kind(lifetime); + 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 { obj } @@ -357,6 +366,7 @@ impl<'a> LifetimeAnalyzer<'a> { obj: LifetimeId, field: StrRef, field_lifetime: LifetimeId, + is_init: bool, ) -> Result<(), String> { use LifetimeKind::*; let obj_id = *self.lifetime_to_id.get(&obj).unwrap(); @@ -377,15 +387,15 @@ impl<'a> LifetimeAnalyzer<'a> { } PreciseLocal | ImpreciseLocal => { // weak update - let old_lifetime = obj_store - .to_mut() - .fields - .get(&field) - .copied(); + let old_lifetime = obj_store.to_mut().fields.get(&field).copied(); if let Some(old_lifetime) = old_lifetime { self.unify(old_lifetime, field_lifetime); } else { 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) } } - FieldAssign { obj, field, new } => { - self.set_field_lifetime(*obj, *field, *new) + FieldAssign { obj, field, new, is_init } => { + self.set_field_lifetime(*obj, *field, *new, *is_init) .map_err(|e| format!("{} in {}", e, loc))?; } FieldAccess { obj, field } => { @@ -490,7 +500,7 @@ impl<'a> LifetimeAnalyzer<'a> { } return Ok(None); } - Branch { targets } => return Ok(Some(targets)) + Branch { targets } => return Ok(Some(targets)), } } Ok(None) diff --git a/nac3core/src/typecheck/escape_analysis/mod.rs b/nac3core/src/typecheck/escape_analysis/mod.rs index 9bd255f6d..b848158dd 100644 --- a/nac3core/src/typecheck/escape_analysis/mod.rs +++ b/nac3core/src/typecheck/escape_analysis/mod.rs @@ -153,6 +153,7 @@ impl<'a> EscapeAnalyzer<'a> { obj: list_lifetime, field: "$elem".into(), new: elem_lifetime, + is_init: true, }, loc, ); @@ -165,6 +166,7 @@ impl<'a> EscapeAnalyzer<'a> { obj: list_lifetime, field: "$elem".into(), new: elem_lifetime, + is_init: true, }, loc, ); @@ -183,6 +185,7 @@ impl<'a> EscapeAnalyzer<'a> { obj: tuple_lifetime, field: format!("$elem{}", i).into(), new: lifetime, + is_init: true, }, loc, ); @@ -208,6 +211,7 @@ impl<'a> EscapeAnalyzer<'a> { obj: slice_lifetime, field: "$elem".into(), new: slice_elem, + is_init: true }, loc, ); @@ -249,7 +253,9 @@ impl<'a> EscapeAnalyzer<'a> { } match &func.node { 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 { let id = self .resolver @@ -342,6 +348,7 @@ impl<'a> EscapeAnalyzer<'a> { obj: list_lifetime, field: "$elem".into(), new: elem_lifetime, + is_init: true }, elt.location, ); @@ -365,7 +372,7 @@ impl<'a> EscapeAnalyzer<'a> { let value_lifetime = self.handle_expr(value)?.unwrap(); if let Some(field_lifetime) = rhs_lifetime { 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, ); } @@ -396,6 +403,7 @@ impl<'a> EscapeAnalyzer<'a> { obj: value_lifetime, field: "$elem".into(), new: elem_lifetime, + is_init: false }, lhs.location, );