Use a thread-local for the symbol interner (1/2)

This commit is contained in:
Amos Wenger 2022-07-21 14:57:09 +02:00
parent 30769598a4
commit 05d8f5fee7
4 changed files with 33 additions and 17 deletions

1
Cargo.lock generated
View file

@ -1167,7 +1167,6 @@ dependencies = [
"mbe", "mbe",
"memmap2", "memmap2",
"object 0.29.0", "object 0.29.0",
"once_cell",
"paths", "paths",
"proc-macro-api", "proc-macro-api",
"proc-macro-test", "proc-macro-test",

View file

@ -24,7 +24,6 @@ tt = { path = "../tt", version = "0.0.0" }
mbe = { path = "../mbe", version = "0.0.0" } mbe = { path = "../mbe", version = "0.0.0" }
paths = { path = "../paths", version = "0.0.0" } paths = { path = "../paths", version = "0.0.0" }
proc-macro-api = { path = "../proc-macro-api", version = "0.0.0" } proc-macro-api = { path = "../proc-macro-api", version = "0.0.0" }
once_cell = "1.13.0"
[dev-dependencies] [dev-dependencies]
expect-test = "1.4.0" expect-test = "1.4.0"

View file

@ -83,7 +83,7 @@ impl server::FreeFunctions for RustAnalyzer {
s: &str, s: &str,
) -> Result<bridge::Literal<Self::Span, Self::Symbol>, ()> { ) -> Result<bridge::Literal<Self::Span, Self::Symbol>, ()> {
// FIXME: keep track of LitKind and Suffix // FIXME: keep track of LitKind and Suffix
let symbol = SYMBOL_INTERNER.lock().unwrap().intern(s); let symbol = ThreadLocalSymbolInterner::intern(s);
Ok(bridge::Literal { Ok(bridge::Literal {
kind: bridge::LitKind::Err, kind: bridge::LitKind::Err,
symbol, symbol,
@ -124,7 +124,7 @@ impl server::TokenStream for RustAnalyzer {
bridge::TokenTree::Ident(ident) => { bridge::TokenTree::Ident(ident) => {
// FIXME: handle raw idents // FIXME: handle raw idents
let text = SYMBOL_INTERNER.lock().unwrap().get(&ident.sym).clone(); let text = ThreadLocalSymbolInterner::get_cloned(&ident.sym);
let ident: tt::Ident = tt::Ident { text, id: ident.span }; let ident: tt::Ident = tt::Ident { text, id: ident.span };
let leaf = tt::Leaf::from(ident); let leaf = tt::Leaf::from(ident);
let tree = TokenTree::from(leaf); let tree = TokenTree::from(leaf);
@ -132,10 +132,11 @@ impl server::TokenStream for RustAnalyzer {
} }
bridge::TokenTree::Literal(literal) => { bridge::TokenTree::Literal(literal) => {
let symbol = SYMBOL_INTERNER.lock().unwrap().get(&literal.symbol).clone(); // FIXME: remove unnecessary clones here
let symbol = ThreadLocalSymbolInterner::get_cloned(&literal.symbol);
let text: tt::SmolStr = if let Some(suffix) = literal.suffix { let text: tt::SmolStr = if let Some(suffix) = literal.suffix {
let suffix = SYMBOL_INTERNER.lock().unwrap().get(&suffix).clone(); let suffix = ThreadLocalSymbolInterner::get_cloned(&suffix);
format!("{symbol}{suffix}").into() format!("{symbol}{suffix}").into()
} else { } else {
symbol symbol
@ -203,7 +204,7 @@ impl server::TokenStream for RustAnalyzer {
.map(|tree| match tree { .map(|tree| match tree {
tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
bridge::TokenTree::Ident(bridge::Ident { bridge::TokenTree::Ident(bridge::Ident {
sym: SYMBOL_INTERNER.lock().unwrap().intern(&ident.text), sym: ThreadLocalSymbolInterner::intern(&ident.text),
// FIXME: handle raw idents // FIXME: handle raw idents
is_raw: false, is_raw: false,
span: ident.id, span: ident.id,
@ -213,7 +214,7 @@ impl server::TokenStream for RustAnalyzer {
bridge::TokenTree::Literal(bridge::Literal { bridge::TokenTree::Literal(bridge::Literal {
// FIXME: handle literal kinds // FIXME: handle literal kinds
kind: bridge::LitKind::Err, kind: bridge::LitKind::Err,
symbol: SYMBOL_INTERNER.lock().unwrap().intern(&lit.text), symbol: ThreadLocalSymbolInterner::intern(&lit.text),
// FIXME: handle suffixes // FIXME: handle suffixes
suffix: None, suffix: None,
span: lit.id, span: lit.id,
@ -407,11 +408,11 @@ impl server::Server for RustAnalyzer {
} }
fn intern_symbol(ident: &str) -> Self::Symbol { fn intern_symbol(ident: &str) -> Self::Symbol {
SYMBOL_INTERNER.lock().unwrap().intern(&tt::SmolStr::from(ident)) ThreadLocalSymbolInterner::intern(&tt::SmolStr::from(ident))
} }
fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) { fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) {
f(SYMBOL_INTERNER.lock().unwrap().get(symbol).as_str()) ThreadLocalSymbolInterner::with(symbol, |s| f(s.as_str()))
} }
} }

View file

@ -1,23 +1,24 @@
//! Symbol interner for proc-macro-srv //! Symbol interner for proc-macro-srv
use once_cell::sync::Lazy; use std::{cell::RefCell, collections::HashMap};
use std::{collections::HashMap, sync::Mutex};
use tt::SmolStr; use tt::SmolStr;
pub(super) static SYMBOL_INTERNER: Lazy<Mutex<SymbolInterner>> = Lazy::new(|| Default::default()); thread_local! {
static SYMBOL_INTERNER: RefCell<SymbolInterner> = Default::default();
}
// ID for an interned symbol. // ID for an interned symbol.
#[derive(Hash, Eq, PartialEq, Copy, Clone)] #[derive(Hash, Eq, PartialEq, Copy, Clone)]
pub struct Symbol(u32); pub struct Symbol(u32);
#[derive(Default)] #[derive(Default)]
pub(super) struct SymbolInterner { struct SymbolInterner {
idents: HashMap<SmolStr, u32>, idents: HashMap<SmolStr, u32>,
ident_data: Vec<SmolStr>, ident_data: Vec<SmolStr>,
} }
impl SymbolInterner { impl SymbolInterner {
pub(super) fn intern(&mut self, data: &str) -> Symbol { fn intern(&mut self, data: &str) -> Symbol {
if let Some(index) = self.idents.get(data) { if let Some(index) = self.idents.get(data) {
return Symbol(*index); return Symbol(*index);
} }
@ -29,7 +30,23 @@ impl SymbolInterner {
Symbol(index) Symbol(index)
} }
pub(super) fn get(&self, index: &Symbol) -> &SmolStr { fn get(&self, sym: &Symbol) -> &SmolStr {
&self.ident_data[index.0 as usize] &self.ident_data[sym.0 as usize]
}
}
pub(super) struct ThreadLocalSymbolInterner;
impl ThreadLocalSymbolInterner {
pub(super) fn intern(data: &str) -> Symbol {
SYMBOL_INTERNER.with(|i| i.borrow_mut().intern(data))
}
pub(super) fn with<T>(sym: &Symbol, f: impl FnOnce(&SmolStr) -> T) -> T {
SYMBOL_INTERNER.with(|i| f(i.borrow().get(sym)))
}
pub(super) fn get_cloned(sym: &Symbol) -> SmolStr {
Self::with(sym, |s| s.clone())
} }
} }