Skip to content

Commit

Permalink
Revert "introduce Table and use for interned values"
Browse files Browse the repository at this point in the history
This reverts commit 9a3111c.
  • Loading branch information
nikomatsakis committed Aug 11, 2024
1 parent 9a3111c commit 4657ac3
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 222 deletions.
18 changes: 9 additions & 9 deletions components/salsa-macro-rules/src/setup_interned_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ macro_rules! setup_interned_struct {
$(#[$attr])*
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
$vis struct $Struct<$db_lt>(
salsa::Id,
std::ptr::NonNull<salsa::plumbing::interned::Value < $Struct<'static> >>,
std::marker::PhantomData < & $db_lt salsa::plumbing::interned::Value < $Struct<'static> > >
);

Expand All @@ -66,11 +66,11 @@ macro_rules! setup_interned_struct {
const DEBUG_NAME: &'static str = stringify!($Struct);
type Data<$db_lt> = ($($field_ty,)*);
type Struct<$db_lt> = $Struct<$db_lt>;
fn struct_from_id<'db>(id: salsa::Id) -> Self::Struct<'db> {
$Struct(id, std::marker::PhantomData)
unsafe fn struct_from_raw<'db>(ptr: std::ptr::NonNull<$zalsa_struct::Value<Self>>) -> Self::Struct<'db> {
$Struct(ptr, std::marker::PhantomData)
}
fn deref_struct(s: Self::Struct<'_>) -> salsa::Id {
s.0
fn deref_struct(s: Self::Struct<'_>) -> &$zalsa_struct::Value<Self> {
unsafe { s.0.as_ref() }
}
}

Expand All @@ -89,13 +89,13 @@ macro_rules! setup_interned_struct {

impl $zalsa::AsId for $Struct<'_> {
fn as_id(&self) -> salsa::Id {
self.0
unsafe { self.0.as_ref() }.as_id()
}
}

impl<$db_lt> $zalsa::LookupId<$db_lt> for $Struct<$db_lt> {
fn lookup_id(id: salsa::Id, db: &$db_lt dyn $zalsa::Database) -> Self {
Self(id, std::marker::PhantomData)
$Configuration::ingredient(db).interned_value(id)
}
}

Expand Down Expand Up @@ -144,7 +144,7 @@ macro_rules! setup_interned_struct {
// FIXME(rust-lang/rust#65991): The `db` argument *should* have the type `dyn Database`
$Db: ?Sized + $zalsa::Database,
{
let fields = $Configuration::ingredient(db).fields(db.as_dyn_database(), self);
let fields = $Configuration::ingredient(db).fields(self);
$zalsa::maybe_clone!(
$field_option,
$field_ty,
Expand All @@ -156,7 +156,7 @@ macro_rules! setup_interned_struct {
/// Default debug formatting for this struct (may be useful if you define your own `Debug` impl)
pub fn default_debug_fmt(this: Self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
$zalsa::with_attached_database(|db| {
let fields = $Configuration::ingredient(db).fields(db.as_dyn_database(), this);
let fields = $Configuration::ingredient(db).fields(this);
let mut f = f.debug_struct(stringify!($Struct));
$(
let f = f.field(stringify!($field_id), &fields.$field_index);
Expand Down
14 changes: 7 additions & 7 deletions components/salsa-macro-rules/src/setup_tracked_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ macro_rules! setup_tracked_fn {
if $needs_interner {
#[derive(Copy, Clone)]
struct $InternedData<$db_lt>(
salsa::Id,
std::ptr::NonNull<$zalsa::interned::Value<$Configuration>>,
std::marker::PhantomData<&$db_lt $zalsa::interned::Value<$Configuration>>,
);

Expand All @@ -114,14 +114,14 @@ macro_rules! setup_tracked_fn {

type Struct<$db_lt> = $InternedData<$db_lt>;

fn struct_from_id<$db_lt>(
id: salsa::Id,
unsafe fn struct_from_raw<$db_lt>(
ptr: std::ptr::NonNull<$zalsa::interned::Value<Self>>,
) -> Self::Struct<$db_lt> {
$InternedData(id, std::marker::PhantomData)
$InternedData(ptr, std::marker::PhantomData)
}

fn deref_struct(s: Self::Struct<'_>) -> salsa::Id {
s.0
fn deref_struct(s: Self::Struct<'_>) -> &$zalsa::interned::Value<Self> {
unsafe { s.0.as_ref() }
}
}
} else {
Expand Down Expand Up @@ -191,7 +191,7 @@ macro_rules! setup_tracked_fn {
fn id_to_input<$db_lt>(db: &$db_lt Self::DbView, key: salsa::Id) -> Self::Input<$db_lt> {
$zalsa::macro_if! {
if $needs_interner {
$Configuration::intern_ingredient(db).data(db, key).clone()
$Configuration::intern_ingredient(db).data(key).clone()
} else {
$zalsa::LookupId::lookup_id(key, db.as_dyn_database())
}
Expand Down
77 changes: 57 additions & 20 deletions src/interned.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use crossbeam::atomic::AtomicCell;
use std::fmt;
use std::hash::Hash;
use std::marker::PhantomData;
use std::ptr::NonNull;

use crate::alloc::Alloc;
use crate::durability::Durability;
use crate::id::AsId;
use crate::ingredient::fmt_index;
Expand All @@ -24,16 +27,24 @@ pub trait Configuration: Sized + 'static {
/// The end user struct
type Struct<'db>: Copy;

/// Create an end-user struct from the salsa id
/// Create an end-user struct from the underlying raw pointer.
///
/// This call is an "end-step" to the tracked struct lookup/creation
/// process in a given revision: it occurs only when the struct is newly
/// created or, if a struct is being reused, after we have updated its
/// fields (or confirmed it is green and no updates are required).
fn struct_from_id<'db>(id: Id) -> Self::Struct<'db>;

/// Deref the struct to yield the underlying id.
fn deref_struct(s: Self::Struct<'_>) -> Id;
///
/// # Safety
///
/// Requires that `ptr` represents a "confirmed" value in this revision,
/// which means that it will remain valid and immutable for the remainder of this
/// revision, represented by the lifetime `'db`.
unsafe fn struct_from_raw<'db>(ptr: NonNull<Value<Self>>) -> Self::Struct<'db>;

/// Deref the struct to yield the underlying value struct.
/// Since we are still part of the `'db` lifetime in which the struct was created,
/// this deref is safe, and the value-struct fields are immutable and verified.
fn deref_struct(s: Self::Struct<'_>) -> &Value<Self>;
}

pub trait InternedData: Sized + Eq + Hash + Clone {}
Expand All @@ -55,6 +66,14 @@ pub struct IngredientImpl<C: Configuration> {
/// Deadlock requirement: We access `value_map` while holding lock on `key_map`, but not vice versa.
key_map: FxDashMap<C::Data<'static>, Id>,

/// Maps from an interned id to its data.
///
/// Deadlock requirement: We access `value_map` while holding lock on `key_map`, but not vice versa.
value_map: FxDashMap<Id, Alloc<Value<C>>>,

/// counter for the next id.
counter: AtomicCell<u32>,

/// Stores the revision when this interned ingredient was last cleared.
/// You can clear an interned table at any point, deleting all its entries,
/// but that will make anything dependent on those entries dirty and in need
Expand Down Expand Up @@ -93,6 +112,8 @@ where
Self {
ingredient_index,
key_map: Default::default(),
value_map: Default::default(),
counter: AtomicCell::default(),
reset_at: Revision::start(),
}
}
Expand All @@ -101,10 +122,6 @@ where
unsafe { std::mem::transmute(data) }
}

unsafe fn from_internal_data<'db>(&'db self, data: &C::Data<'static>) -> &C::Data<'db> {
unsafe { std::mem::transmute(data) }
}

pub fn intern_id<'db>(
&'db self,
db: &'db dyn crate::Database,
Expand Down Expand Up @@ -132,46 +149,66 @@ where
if let Some(guard) = self.key_map.get(&internal_data) {
let id = *guard;
drop(guard);
return C::struct_from_id(id);
return self.interned_value(id);
}

match self.key_map.entry(internal_data.clone()) {
// Data has been interned by a racing call, use that ID instead
dashmap::mapref::entry::Entry::Occupied(entry) => {
let id = *entry.get();
drop(entry);
C::struct_from_id(id)
self.interned_value(id)
}

// We won any races so should intern the data
dashmap::mapref::entry::Entry::Vacant(entry) => {
let zalsa = db.zalsa();
let table = zalsa.table();
let next_id = zalsa_local.allocate(table, self.ingredient_index, internal_data);
let next_id = self.counter.fetch_add(1);
let next_id = crate::id::Id::from_u32(next_id);
let value = self.value_map.entry(next_id).or_insert(Alloc::new(Value {
id: next_id,
fields: internal_data,
}));
let value_raw = value.as_raw();
drop(value);
entry.insert(next_id);
C::struct_from_id(next_id)
// SAFETY: Items are only removed from the `value_map` with an `&mut self` reference.
unsafe { C::struct_from_raw(value_raw) }
}
}
}

pub fn interned_value(&self, id: Id) -> C::Struct<'_> {
let r = self.value_map.get(&id).unwrap();

// SAFETY: Items are only removed from the `value_map` with an `&mut self` reference.
unsafe { C::struct_from_raw(r.as_raw()) }
}

/// Lookup the data for an interned value based on its id.
/// Rarely used since end-users generally carry a struct with a pointer directly
/// to the interned item.
pub fn data<'db>(&'db self, db: &'db dyn Database, id: Id) -> &'db C::Data<'db> {
let internal_data = db.zalsa().table().get::<C::Data<'static>>(id);
unsafe { self.from_internal_data(internal_data) }
pub fn data(&self, id: Id) -> &C::Data<'_> {
C::deref_struct(self.interned_value(id)).data()
}

/// Lookup the fields from an interned struct.
/// Note that this is not "leaking" since no dependency edge is required.
pub fn fields<'db>(&'db self, db: &'db dyn Database, s: C::Struct<'db>) -> &'db C::Data<'db> {
self.data(db, C::deref_struct(s))
pub fn fields<'db>(&'db self, s: C::Struct<'db>) -> &'db C::Data<'db> {
C::deref_struct(s).data()
}

/// Variant of `data` that takes a (unnecessary) database argument.
/// This exists because tracked functions sometimes use true interning and sometimes use
/// [`IdentityInterner`][], which requires the database argument.
pub fn data_with_db<'db, DB: ?Sized>(&'db self, id: Id, _db: &'db DB) -> &'db C::Data<'db> {
self.data(id)
}

pub fn reset(&mut self, revision: Revision) {
assert!(revision > self.reset_at);
self.reset_at = revision;
self.key_map.clear();
self.value_map.clear();
}
}

Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ mod revision;
mod runtime;
mod salsa_struct;
mod storage;
mod table;
mod tracked_struct;
mod update;
mod views;
Expand Down
133 changes: 0 additions & 133 deletions src/table.rs

This file was deleted.

Loading

0 comments on commit 4657ac3

Please sign in to comment.