Revert "tamer: asg::graph::index: Use FxHashMap in place of Vec"
This reverts commit 1b7eac337cd5909c01ede3a5b3fba577898d5961. I don't actually think this ends up being worth it in the end. Sure, the implementation is simpler at a glance, but it is more complex at runtime, adding more cycles for little benefit. There are ~220 pre-interned symbols at the time of writing, so ~880 bytes (4 bytes per symbol) are potentially wasted if _none_ of the pre-interned symbols end up serving as identifiers in the graph. The reality is that some of them _will_ but, but using HashMap also introduces overhead, so in practice, the savings is much less. On a fairly small package, it was <100 bytes memory saving in `tamec`. For `tameld`, it actually uses _more_ memory, especially on larger packages, because there are 10s of thousands of symbols involved. And we're incurring a rehashing cost on resize, unlike this original plain `Vec` implementation. So, I'm leaving this in the history to reference in the future or return to it if others ask; maybe it'll be worth it in the future.main
parent
417df548cf
commit
d066bb370f
|
@ -33,7 +33,6 @@ use crate::{
|
|||
parse::{util::SPair, Token},
|
||||
sym::SymbolId,
|
||||
};
|
||||
use fxhash::FxHashMap;
|
||||
use petgraph::{
|
||||
graph::{DiGraph, Graph, NodeIndex},
|
||||
visit::EdgeRef,
|
||||
|
@ -93,7 +92,10 @@ pub struct Asg {
|
|||
/// Note that,
|
||||
/// while we store [`NodeIndex`] internally,
|
||||
/// the public API encapsulates it within an [`ObjectIndex`].
|
||||
index: FxHashMap<SymbolId, NodeIndex<Ix>>,
|
||||
index: Vec<NodeIndex<Ix>>,
|
||||
|
||||
/// Empty node indicating that no object exists for a given index.
|
||||
empty_node: NodeIndex<Ix>,
|
||||
|
||||
/// The root node used for reachability analysis and topological
|
||||
/// sorting.
|
||||
|
@ -127,8 +129,12 @@ impl Asg {
|
|||
/// edge to another object.
|
||||
pub fn with_capacity(objects: usize, edges: usize) -> Self {
|
||||
let mut graph = Graph::with_capacity(objects, edges);
|
||||
let index =
|
||||
FxHashMap::with_capacity_and_hasher(objects, Default::default());
|
||||
let mut index = Vec::with_capacity(objects);
|
||||
|
||||
// Exhaust the first index to be used as a placeholder
|
||||
// (its value does not matter).
|
||||
let empty_node = graph.add_node(Object::Root.into());
|
||||
index.push(empty_node);
|
||||
|
||||
// Automatically add the root which will be used to determine what
|
||||
// identifiers ought to be retained by the final program.
|
||||
|
@ -138,6 +144,7 @@ impl Asg {
|
|||
Self {
|
||||
graph,
|
||||
index,
|
||||
empty_node,
|
||||
root_node,
|
||||
}
|
||||
}
|
||||
|
@ -154,11 +161,27 @@ impl Asg {
|
|||
/// After an identifier is indexed it is not expected to be reassigned
|
||||
/// to another node.
|
||||
/// Debug builds contain an assertion that will panic in this instance.
|
||||
///
|
||||
/// Panics
|
||||
/// ======
|
||||
/// Will panic if unable to allocate more space for the index.
|
||||
fn index_identifier(&mut self, name: SymbolId, node: NodeIndex<Ix>) {
|
||||
let prev = self.index.insert(name, node);
|
||||
let i = name.as_usize();
|
||||
|
||||
if i >= self.index.len() {
|
||||
// If this is ever a problem we can fall back to usize max and
|
||||
// re-compare before panicing
|
||||
let new_size = (i + 1)
|
||||
.checked_next_power_of_two()
|
||||
.expect("internal error: cannot allocate space for ASG index");
|
||||
|
||||
self.index.resize(new_size, self.empty_node);
|
||||
}
|
||||
|
||||
// We should never overwrite indexes
|
||||
debug_assert!(prev == None);
|
||||
debug_assert!(self.index[i] == self.empty_node);
|
||||
|
||||
self.index[i] = node;
|
||||
}
|
||||
|
||||
/// Lookup `ident` or add a missing identifier to the graph and return a
|
||||
|
@ -594,9 +617,12 @@ impl Asg {
|
|||
/// that, see [`Asg::get`].
|
||||
#[inline]
|
||||
pub fn lookup(&self, id: SPair) -> Option<ObjectIndex<Ident>> {
|
||||
let i = id.symbol().as_usize();
|
||||
|
||||
self.index
|
||||
.get(&id.symbol())
|
||||
.map(|&ni| ObjectIndex::new(ni, id.span()))
|
||||
.get(i)
|
||||
.filter(|ni| ni.index() > 0)
|
||||
.map(|ni| ObjectIndex::new(*ni, id.span()))
|
||||
}
|
||||
|
||||
/// Declare that `dep` is a dependency of `ident`.
|
||||
|
|
Loading…
Reference in New Issue