Skip to content

Commit ec0a64d

Browse files
committed
memoization for resolve
1 parent 0954e66 commit ec0a64d

File tree

2 files changed

+93
-40
lines changed

2 files changed

+93
-40
lines changed

src/libsyntax/ast_util.rs

Lines changed: 91 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -915,30 +915,63 @@ fn idx_push<T>(vec: &mut ~[T], val: T) -> uint {
915915
916916
/// Resolve a syntax object to a name, per MTWT.
917917
pub fn mtwt_resolve(id : Ident) -> Name {
918-
resolve_internal(id, get_sctable())
918+
resolve_internal(id, get_sctable(), get_resolve_table())
919+
}
920+
921+
// FIXME #4536: must be pub for testing
922+
pub type ResolveTable = HashMap<(Name,SyntaxContext),Name>;
923+
924+
// okay, I admit, putting this in TLS is not so nice:
925+
// fetch the SCTable from TLS, create one if it doesn't yet exist.
926+
pub fn get_resolve_table() -> @mut ResolveTable {
927+
static resolve_table_key: local_data::Key<@@mut ResolveTable> = &local_data::Key;
928+
match local_data::get(resolve_table_key, |k| k.map(|&k| *k)) {
929+
None => {
930+
let new_table = @@mut HashMap::new();
931+
local_data::set(resolve_table_key,new_table);
932+
*new_table
933+
},
934+
Some(intr) => *intr
935+
}
919936
}
920937
921938
// Resolve a syntax object to a name, per MTWT.
939+
// adding memoization to possibly resolve 500+ seconds in resolve for librustc (!)
922940
// FIXME #4536 : currently pub to allow testing
923-
pub fn resolve_internal(id : Ident, table : &mut SCTable) -> Name {
924-
match table.table[id.ctxt] {
925-
EmptyCtxt => id.name,
926-
// ignore marks here:
927-
Mark(_,subctxt) => resolve_internal(Ident{name:id.name, ctxt: subctxt},table),
928-
// do the rename if necessary:
929-
Rename(Ident{name,ctxt},toname,subctxt) => {
930-
// this could be cached or computed eagerly:
931-
let resolvedfrom = resolve_internal(Ident{name:name,ctxt:ctxt},table);
932-
let resolvedthis = resolve_internal(Ident{name:id.name,ctxt:subctxt},table);
933-
if ((resolvedthis == resolvedfrom)
934-
&& (marksof(ctxt,resolvedthis,table)
935-
== marksof(subctxt,resolvedthis,table))) {
936-
toname
937-
} else {
938-
resolvedthis
939-
}
941+
pub fn resolve_internal(id : Ident,
942+
table : &mut SCTable,
943+
resolve_table : &mut ResolveTable) -> Name {
944+
let key = (id.name,id.ctxt);
945+
match resolve_table.contains_key(&key) {
946+
false => {
947+
let resolved = {
948+
match table.table[id.ctxt] {
949+
EmptyCtxt => id.name,
950+
// ignore marks here:
951+
Mark(_,subctxt) => resolve_internal(Ident{name:id.name, ctxt: subctxt},table,resolve_table),
952+
// do the rename if necessary:
953+
Rename(Ident{name,ctxt},toname,subctxt) => {
954+
let resolvedfrom = resolve_internal(Ident{name:name,ctxt:ctxt},table,resolve_table);
955+
let resolvedthis = resolve_internal(Ident{name:id.name,ctxt:subctxt},table,resolve_table);
956+
if ((resolvedthis == resolvedfrom)
957+
&& (marksof(ctxt,resolvedthis,table)
958+
== marksof(subctxt,resolvedthis,table))) {
959+
toname
960+
} else {
961+
resolvedthis
962+
}
963+
}
964+
IllegalCtxt() => fail!(~"expected resolvable context, got IllegalCtxt")
965+
}
966+
};
967+
resolve_table.insert(key,resolved);
968+
resolved
969+
}
970+
true => {
971+
// it's guaranteed to be there, because we just checked that it was
972+
// there and we never remove anything from the table:
973+
*(resolve_table.find(&key).unwrap())
940974
}
941-
IllegalCtxt() => fail!(~"expected resolvable context, got IllegalCtxt")
942975
}
943976
}
944977
@@ -1017,20 +1050,21 @@ mod test {
10171050
use super::*;
10181051
use std::io;
10191052
use opt_vec;
1053+
use std::hash::HashMap;
10201054
1021-
fn ident_to_segment(id : &ident) -> PathSegment {
1055+
fn ident_to_segment(id : &Ident) -> PathSegment {
10221056
PathSegment{identifier:id.clone(), lifetime: None, types: opt_vec::Empty}
10231057
}
10241058
10251059
#[test] fn idents_name_eq_test() {
1026-
assert!(segments_name_eq([ident{name:3,ctxt:4},
1027-
ident{name:78,ctxt:82}].map(ident_to_segment),
1028-
[ident{name:3,ctxt:104},
1029-
ident{name:78,ctxt:182}].map(ident_to_segment)));
1030-
assert!(!segments_name_eq([ident{name:3,ctxt:4},
1031-
ident{name:78,ctxt:82}].map(ident_to_segment),
1032-
[ident{name:3,ctxt:104},
1033-
ident{name:77,ctxt:182}].map(ident_to_segment)));
1060+
assert!(segments_name_eq([Ident{name:3,ctxt:4},
1061+
Ident{name:78,ctxt:82}].map(ident_to_segment),
1062+
[Ident{name:3,ctxt:104},
1063+
Ident{name:78,ctxt:182}].map(ident_to_segment)));
1064+
assert!(!segments_name_eq([Ident{name:3,ctxt:4},
1065+
Ident{name:78,ctxt:82}].map(ident_to_segment),
1066+
[Ident{name:3,ctxt:104},
1067+
Ident{name:77,ctxt:182}].map(ident_to_segment)));
10341068
}
10351069
10361070
#[test] fn xorpush_test () {
@@ -1162,52 +1196,59 @@ mod test {
11621196
#[test] fn resolve_tests () {
11631197
let a = 40;
11641198
let mut t = new_sctable_internal();
1199+
let mut rt = HashMap::new();
11651200
// - ctxt is MT
1166-
assert_eq!(resolve_internal(id(a,EMPTY_CTXT),&mut t),a);
1201+
assert_eq!(resolve_internal(id(a,EMPTY_CTXT),&mut t, &mut rt),a);
11671202
// - simple ignored marks
11681203
{ let sc = unfold_marks(~[1,2,3],EMPTY_CTXT,&mut t);
1169-
assert_eq!(resolve_internal(id(a,sc),&mut t),a);}
1204+
assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt),a);}
11701205
// - orthogonal rename where names don't match
11711206
{ let sc = unfold_test_sc(~[R(id(50,EMPTY_CTXT),51),M(12)],EMPTY_CTXT,&mut t);
1172-
assert_eq!(resolve_internal(id(a,sc),&mut t),a);}
1207+
assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt),a);}
11731208
// - rename where names do match, but marks don't
11741209
{ let sc1 = new_mark_internal(1,EMPTY_CTXT,&mut t);
11751210
let sc = unfold_test_sc(~[R(id(a,sc1),50),
11761211
M(1),
11771212
M(2)],
11781213
EMPTY_CTXT,&mut t);
1179-
assert_eq!(resolve_internal(id(a,sc),&mut t), a);}
1214+
assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), a);}
11801215
// - rename where names and marks match
11811216
{ let sc1 = unfold_test_sc(~[M(1),M(2)],EMPTY_CTXT,&mut t);
11821217
let sc = unfold_test_sc(~[R(id(a,sc1),50),M(1),M(2)],EMPTY_CTXT,&mut t);
1183-
assert_eq!(resolve_internal(id(a,sc),&mut t), 50); }
1218+
assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), 50); }
11841219
// - rename where names and marks match by literal sharing
11851220
{ let sc1 = unfold_test_sc(~[M(1),M(2)],EMPTY_CTXT,&mut t);
11861221
let sc = unfold_test_sc(~[R(id(a,sc1),50)],sc1,&mut t);
1187-
assert_eq!(resolve_internal(id(a,sc),&mut t), 50); }
1222+
assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), 50); }
11881223
// - two renames of the same var.. can only happen if you use
11891224
// local-expand to prevent the inner binding from being renamed
11901225
// during the rename-pass caused by the first:
11911226
io::println("about to run bad test");
11921227
{ let sc = unfold_test_sc(~[R(id(a,EMPTY_CTXT),50),
11931228
R(id(a,EMPTY_CTXT),51)],
11941229
EMPTY_CTXT,&mut t);
1195-
assert_eq!(resolve_internal(id(a,sc),&mut t), 51); }
1230+
assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), 51); }
11961231
// the simplest double-rename:
11971232
{ let a_to_a50 = new_rename_internal(id(a,EMPTY_CTXT),50,EMPTY_CTXT,&mut t);
11981233
let a50_to_a51 = new_rename_internal(id(a,a_to_a50),51,a_to_a50,&mut t);
1199-
assert_eq!(resolve_internal(id(a,a50_to_a51),&mut t),51);
1234+
assert_eq!(resolve_internal(id(a,a50_to_a51),&mut t, &mut rt),51);
12001235
// mark on the outside doesn't stop rename:
12011236
let sc = new_mark_internal(9,a50_to_a51,&mut t);
1202-
assert_eq!(resolve_internal(id(a,sc),&mut t),51);
1237+
assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt),51);
12031238
// but mark on the inside does:
12041239
let a50_to_a51_b = unfold_test_sc(~[R(id(a,a_to_a50),51),
12051240
M(9)],
12061241
a_to_a50,
12071242
&mut t);
1208-
assert_eq!(resolve_internal(id(a,a50_to_a51_b),&mut t),50);}
1243+
assert_eq!(resolve_internal(id(a,a50_to_a51_b),&mut t, &mut rt),50);}
1244+
}
1245+
1246+
#[test] fn mtwt_resolve_test(){
1247+
let a = 40;
1248+
assert_eq!(mtwt_resolve(id(a,EMPTY_CTXT)),a);
12091249
}
12101250

1251+
12111252
#[test] fn hashing_tests () {
12121253
let mut t = new_sctable_internal();
12131254
assert_eq!(new_mark_internal(12,EMPTY_CTXT,&mut t),2);
@@ -1217,4 +1258,16 @@ mod test {
12171258
// I'm assuming that the rename table will behave the same....
12181259
}
12191260

1261+
#[test] fn resolve_table_hashing_tests() {
1262+
let mut t = new_sctable_internal();
1263+
let mut rt = HashMap::new();
1264+
assert_eq!(rt.len(),0);
1265+
resolve_internal(id(30,EMPTY_CTXT),&mut t, &mut rt);
1266+
assert_eq!(rt.len(),1);
1267+
resolve_internal(id(39,EMPTY_CTXT),&mut t, &mut rt);
1268+
assert_eq!(rt.len(),2);
1269+
resolve_internal(id(30,EMPTY_CTXT),&mut t, &mut rt);
1270+
assert_eq!(rt.len(),2);
1271+
}
1272+
12201273
}

src/libsyntax/parse/token.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -737,8 +737,8 @@ mod test {
737737
use ast;
738738
use ast_util;
739739

740-
fn mark_ident(id : ast::ident, m : ast::Mrk) -> ast::ident {
741-
ast::ident{name:id.name,ctxt:ast_util::new_mark(m,id.ctxt)}
740+
fn mark_ident(id : ast::Ident, m : ast::Mrk) -> ast::Ident {
741+
ast::Ident{name:id.name,ctxt:ast_util::new_mark(m,id.ctxt)}
742742
}
743743

744744
#[test] fn mtwt_token_eq_test() {

0 commit comments

Comments
 (0)