Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move InstanceHistory to thread local storage #1265

Merged
merged 1 commit into from
Feb 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Move InstanceHistory to thread local storage
  • Loading branch information
dalance committed Feb 23, 2025
commit 616628e9c15ed4f05226ad8357dbda67b8f4843a
29 changes: 10 additions & 19 deletions crates/analyzer/src/analyzer.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::analyzer::resource_table::PathId;
use crate::analyzer_error::AnalyzerError;
use crate::attribute_table;
use crate::handlers::check_expression::{CheckExpression, InstanceHistory};
use crate::handlers::check_expression::CheckExpression;
use crate::handlers::*;
use crate::instance_history;
use crate::msb_table;
use crate::namespace::Namespace;
use crate::namespace_table;
Expand Down Expand Up @@ -48,14 +49,9 @@ pub struct AnalyzerPass2<'a> {
}

impl<'a> AnalyzerPass2<'a> {
pub fn new(
text: &'a str,
build_opt: &'a Build,
lint_opt: &'a Lint,
inst_history: &'a mut InstanceHistory,
) -> Self {
pub fn new(text: &'a str, build_opt: &'a Build, lint_opt: &'a Lint) -> Self {
AnalyzerPass2 {
handlers: Pass2Handlers::new(text, build_opt, lint_opt, inst_history),
handlers: Pass2Handlers::new(text, build_opt, lint_opt),
}
}
}
Expand All @@ -71,13 +67,9 @@ pub struct AnalyzerPass2Expression<'a> {
}

impl<'a> AnalyzerPass2Expression<'a> {
pub fn new(
text: &'a str,
inst_context: Vec<TokenRange>,
inst_history: &'a mut InstanceHistory,
) -> Self {
pub fn new(text: &'a str, inst_context: Vec<TokenRange>) -> Self {
AnalyzerPass2Expression {
check_expression: CheckExpression::new(text, inst_context, inst_history),
check_expression: CheckExpression::new(text, inst_context),
}
}

Expand Down Expand Up @@ -333,11 +325,10 @@ impl Analyzer {
let mut ret = Vec::new();

namespace_table::set_default(&[project_name.into()]);
let mut inst_history = InstanceHistory::default();
inst_history.depth_limit = self.build_opt.instance_depth_limit;
inst_history.total_limit = self.build_opt.instance_total_limit;
let mut pass2 =
AnalyzerPass2::new(text, &self.build_opt, &self.lint_opt, &mut inst_history);
instance_history::clear();
instance_history::set_depth_limit(self.build_opt.instance_depth_limit);
instance_history::set_total_limit(self.build_opt.instance_total_limit);
let mut pass2 = AnalyzerPass2::new(text, &self.build_opt, &self.lint_opt);
pass2.veryl(input);
ret.append(&mut pass2.handlers.get_errors());

Expand Down
9 changes: 2 additions & 7 deletions crates/analyzer/src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,7 @@ pub struct Pass2Handlers<'a> {
}

impl<'a> Pass2Handlers<'a> {
pub fn new(
text: &'a str,
_build_opt: &'a Build,
_lint_opt: &'a Lint,
inst_history: &'a mut InstanceHistory,
) -> Self {
pub fn new(text: &'a str, _build_opt: &'a Build, _lint_opt: &'a Lint) -> Self {
Self {
check_separator: CheckSeparator::new(text),
check_enum: CheckEnum::new(text),
Expand All @@ -126,7 +121,7 @@ impl<'a> Pass2Handlers<'a> {
check_var_ref: CheckVarRef::new(text),
check_clock_reset: CheckClockReset::new(text),
create_type_dag: CreateTypeDag::new(text),
check_expression: CheckExpression::new(text, vec![], inst_history),
check_expression: CheckExpression::new(text, vec![]),
check_clock_domain: CheckClockDomain::new(text),
check_proto: CheckProto::new(text),
check_type: CheckType::new(text),
Expand Down
97 changes: 9 additions & 88 deletions crates/analyzer/src/handlers/check_expression.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::analyzer::AnalyzerPass2Expression;
use crate::analyzer_error::AnalyzerError;
use crate::definition_table::{self, Definition};
use crate::evaluator::{Evaluated, EvaluatedError, EvaluatedType, EvaluatedValue, Evaluator};
use crate::evaluator::{Evaluated, EvaluatedError, EvaluatedType, Evaluator};
use crate::instance_history::{self, InstanceHistoryError, InstanceSignature};
use crate::symbol::{Direction, GenericBoundKind, ModuleProperty, Symbol, SymbolId, SymbolKind};
use crate::symbol_table;
use std::collections::{HashMap, HashSet};
Expand All @@ -12,74 +13,6 @@ use veryl_parser::veryl_token::TokenRange;
use veryl_parser::veryl_walker::{Handler, HandlerPoint, VerylWalker};
use veryl_parser::ParolError;

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct InstanceSignature {
symbol: SymbolId,
params: Vec<(StrId, EvaluatedValue)>,
}

impl InstanceSignature {
fn new(symbol: SymbolId) -> Self {
Self {
symbol,
params: Vec::new(),
}
}

fn add_param(&mut self, id: StrId, value: EvaluatedValue) {
self.params.push((id, value));
}

fn normalize(&mut self) {
self.params.sort();
}
}

#[derive(Default)]
pub struct InstanceHistory {
pub depth_limit: usize,
pub total_limit: usize,
pub hierarchy: Vec<InstanceSignature>,
full: HashSet<InstanceSignature>,
}

impl InstanceHistory {
fn push(&mut self, mut sig: InstanceSignature) -> Result<bool, InstanceHistoryError> {
sig.normalize();
if self.hierarchy.len() > self.depth_limit {
return Err(InstanceHistoryError::ExceedDepthLimit);
}
if self.full.len() > self.total_limit {
return Err(InstanceHistoryError::ExceedTotalLimit);
}
if self.hierarchy.iter().any(|x| *x == sig)
&& sig.params.iter().all(|x| x.1.get_value().is_some())
{
return Err(InstanceHistoryError::InfiniteRecursion);
}
if self.full.contains(&sig) {
Ok(false)
} else {
self.hierarchy.push(sig.clone());
self.full.insert(sig);
Ok(true)
}
}

fn pop(&mut self) {
self.hierarchy.pop();
}
}

#[derive(Debug)]
pub enum InstanceHistoryError {
ExceedDepthLimit,
ExceedTotalLimit,
InfiniteRecursion,
}

impl InstanceHistoryError {}

pub struct CheckExpression<'a> {
pub errors: Vec<AnalyzerError>,
text: &'a str,
Expand All @@ -92,15 +25,10 @@ pub struct CheckExpression<'a> {
disable_block_beg: HashSet<TokenId>,
disable_block_end: HashSet<TokenId>,
inst_context: Vec<TokenRange>,
inst_history: &'a mut InstanceHistory,
}

impl<'a> CheckExpression<'a> {
pub fn new(
text: &'a str,
inst_context: Vec<TokenRange>,
inst_history: &'a mut InstanceHistory,
) -> Self {
pub fn new(text: &'a str, inst_context: Vec<TokenRange>) -> Self {
Self {
errors: Vec::new(),
text,
Expand All @@ -113,7 +41,6 @@ impl<'a> CheckExpression<'a> {
disable_block_beg: HashSet::new(),
disable_block_end: HashSet::new(),
inst_context,
inst_history,
}
}

Expand Down Expand Up @@ -578,35 +505,29 @@ impl VerylGrammarTrait for CheckExpression<'_> {
self.check_port_connection(arg, x);
}

match self.inst_history.push(sig) {
match instance_history::push(sig) {
Ok(true) => {
// Check expression with overridden parameters
let def = definition_table::get(definition).unwrap();
match def {
Definition::Module { text, decl } => {
let mut inst_context = self.inst_context.clone();
inst_context.push(arg.identifier.as_ref().into());
let mut analyzer = AnalyzerPass2Expression::new(
&text,
inst_context,
self.inst_history,
);
let mut analyzer =
AnalyzerPass2Expression::new(&text, inst_context);
analyzer.module_declaration(&decl);
self.errors.append(&mut analyzer.get_errors());
}
Definition::Interface { text, decl } => {
let mut inst_context = self.inst_context.clone();
inst_context.push(arg.identifier.as_ref().into());
let mut analyzer = AnalyzerPass2Expression::new(
&text,
inst_context,
self.inst_history,
);
let mut analyzer =
AnalyzerPass2Expression::new(&text, inst_context);
analyzer.interface_declaration(&decl);
self.errors.append(&mut analyzer.get_errors());
}
}
self.inst_history.pop();
instance_history::pop();
}
// Skip duplicated signature
Ok(false) => (),
Expand Down
108 changes: 108 additions & 0 deletions crates/analyzer/src/instance_history.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use crate::evaluator::EvaluatedValue;
use crate::symbol::SymbolId;
use std::cell::RefCell;
use std::collections::HashSet;
use veryl_parser::resource_table::StrId;

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct InstanceSignature {
symbol: SymbolId,
params: Vec<(StrId, EvaluatedValue)>,
}

impl InstanceSignature {
pub fn new(symbol: SymbolId) -> Self {
Self {
symbol,
params: Vec::new(),
}
}

pub fn add_param(&mut self, id: StrId, value: EvaluatedValue) {
self.params.push((id, value));
}

fn normalize(&mut self) {
self.params.sort();
}
}

#[derive(Default)]
pub struct InstanceHistory {
pub depth_limit: usize,
pub total_limit: usize,
pub hierarchy: Vec<InstanceSignature>,
full: HashSet<InstanceSignature>,
}

impl InstanceHistory {
fn set_depth_limit(&mut self, value: usize) {
self.depth_limit = value;
}

fn set_total_limit(&mut self, value: usize) {
self.total_limit = value;
}

fn push(&mut self, mut sig: InstanceSignature) -> Result<bool, InstanceHistoryError> {
sig.normalize();
if self.hierarchy.len() > self.depth_limit {
return Err(InstanceHistoryError::ExceedDepthLimit);
}
if self.full.len() > self.total_limit {
return Err(InstanceHistoryError::ExceedTotalLimit);
}
if self.hierarchy.iter().any(|x| *x == sig)
&& sig.params.iter().all(|x| x.1.get_value().is_some())
{
return Err(InstanceHistoryError::InfiniteRecursion);
}
if self.full.contains(&sig) {
Ok(false)
} else {
self.hierarchy.push(sig.clone());
self.full.insert(sig);
Ok(true)
}
}

fn pop(&mut self) {
self.hierarchy.pop();
}

fn clear(&mut self) {
self.hierarchy.clear();
self.full.clear();
}
}

#[derive(Debug)]
pub enum InstanceHistoryError {
ExceedDepthLimit,
ExceedTotalLimit,
InfiniteRecursion,
}

impl InstanceHistoryError {}

thread_local!(static INSTANCE_HISTORY: RefCell<InstanceHistory> = RefCell::new(InstanceHistory::default()));

pub fn set_depth_limit(value: usize) {
INSTANCE_HISTORY.with(|f| f.borrow_mut().set_depth_limit(value))
}

pub fn set_total_limit(value: usize) {
INSTANCE_HISTORY.with(|f| f.borrow_mut().set_total_limit(value))
}

pub fn push(sig: InstanceSignature) -> Result<bool, InstanceHistoryError> {
INSTANCE_HISTORY.with(|f| f.borrow_mut().push(sig))
}

pub fn pop() {
INSTANCE_HISTORY.with(|f| f.borrow_mut().pop())
}

pub fn clear() {
INSTANCE_HISTORY.with(|f| f.borrow_mut().clear())
}
1 change: 1 addition & 0 deletions crates/analyzer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod attribute_table;
pub mod definition_table;
pub mod evaluator;
pub mod handlers;
pub mod instance_history;
pub mod msb_table;
pub mod namespace;
pub mod namespace_table;
Expand Down