@@ -25,34 +25,22 @@ use std::collections::HashMap;
2525/// The SCTable contains a table of SyntaxContext_'s. It
2626/// represents a flattened tree structure, to avoid having
2727/// managed pointers everywhere (that caused an ICE).
28- /// the mark_memo and rename_memo fields are side-tables
28+ /// the `marks` and `renames` fields are side-tables
2929/// that ensure that adding the same mark to the same context
30- /// gives you back the same context as before. This shouldn't
31- /// change the semantics--everything here is immutable--but
32- /// it should cut down on memory use *a lot*; applying a mark
33- /// to a tree containing 50 identifiers would otherwise generate
34- /// 50 new contexts
30+ /// gives you back the same context as before. This should cut
31+ /// down on memory use *a lot*; applying a mark to a tree containing
32+ /// 50 identifiers would otherwise generate 50 new contexts.
3533pub struct SCTable {
3634 table : RefCell < Vec < SyntaxContext_ > > ,
37- mark_memo : RefCell < HashMap < ( SyntaxContext , Mrk ) , SyntaxContext > > ,
38- // The pair (Name,SyntaxContext) is actually one Ident, but it needs to be hashed and
39- // compared as pair (name, ctxt) and not as an Ident
40- rename_memo : RefCell < HashMap < ( SyntaxContext , ( Name , SyntaxContext ) , Name ) , SyntaxContext > > ,
35+ marks : RefCell < HashMap < ( SyntaxContext , Mrk ) , SyntaxContext > > ,
36+ renames : RefCell < HashMap < Name , SyntaxContext > > ,
4137}
4238
4339#[ derive( PartialEq , RustcEncodable , RustcDecodable , Hash , Debug , Copy , Clone ) ]
4440pub enum SyntaxContext_ {
4541 EmptyCtxt ,
4642 Mark ( Mrk , SyntaxContext ) ,
47- /// flattening the name and syntaxcontext into the rename...
48- /// HIDDEN INVARIANTS:
49- /// 1) the first name in a Rename node
50- /// can only be a programmer-supplied name.
51- /// 2) Every Rename node with a given Name in the
52- /// "to" slot must have the same name and context
53- /// in the "from" slot. In essence, they're all
54- /// pointers to a single "rename" event node.
55- Rename ( Ident , Name , SyntaxContext ) ,
43+ Rename ( Name ) ,
5644 /// actually, IllegalCtxt may not be necessary.
5745 IllegalCtxt
5846}
@@ -67,37 +55,39 @@ pub fn apply_mark(m: Mrk, ctxt: SyntaxContext) -> SyntaxContext {
6755
6856/// Extend a syntax context with a given mark and sctable (explicit memoization)
6957fn apply_mark_internal ( m : Mrk , ctxt : SyntaxContext , table : & SCTable ) -> SyntaxContext {
70- let key = ( ctxt, m) ;
71- * table. mark_memo . borrow_mut ( ) . entry ( key) . or_insert_with ( || {
72- SyntaxContext ( idx_push ( & mut * table. table . borrow_mut ( ) , Mark ( m, ctxt) ) )
73- } )
58+ let ctxts = & mut * table. table . borrow_mut ( ) ;
59+ match ctxts[ ctxt. 0 as usize ] {
60+ // Applying the same mark twice is a no-op.
61+ Mark ( outer_mark, prev_ctxt) if outer_mark == m => return prev_ctxt,
62+ _ => * table. marks . borrow_mut ( ) . entry ( ( ctxt, m) ) . or_insert_with ( || {
63+ SyntaxContext ( idx_push ( ctxts, Mark ( m, ctxt) ) )
64+ } ) ,
65+ }
7466}
7567
7668/// Extend a syntax context with a given rename
77- pub fn apply_rename ( id : Ident , to : Name ,
78- ctxt : SyntaxContext ) -> SyntaxContext {
79- with_sctable ( |table| apply_rename_internal ( id, to, ctxt, table) )
69+ pub fn apply_rename ( from : Ident , to : Name , ident : Ident ) -> Ident {
70+ with_sctable ( |table| apply_rename_internal ( from, to, ident, table) )
8071}
8172
8273/// Extend a syntax context with a given rename and sctable (explicit memoization)
83- fn apply_rename_internal ( id : Ident ,
84- to : Name ,
85- ctxt : SyntaxContext ,
86- table : & SCTable ) -> SyntaxContext {
87- let key = ( ctxt, ( id. name , id. ctxt ) , to) ;
88-
89- * table. rename_memo . borrow_mut ( ) . entry ( key) . or_insert_with ( || {
90- SyntaxContext ( idx_push ( & mut * table. table . borrow_mut ( ) , Rename ( id, to, ctxt) ) )
91- } )
74+ fn apply_rename_internal ( from : Ident , to : Name , ident : Ident , table : & SCTable ) -> Ident {
75+ if ( ident. name , ident. ctxt ) != ( from. name , from. ctxt ) {
76+ return ident;
77+ }
78+ let ctxt = * table. renames . borrow_mut ( ) . entry ( to) . or_insert_with ( || {
79+ SyntaxContext ( idx_push ( & mut * table. table . borrow_mut ( ) , Rename ( to) ) )
80+ } ) ;
81+ Ident { ctxt : ctxt, ..ident }
9282}
9383
9484/// Apply a list of renamings to a context
9585// if these rename lists get long, it would make sense
9686// to consider memoizing this fold. This may come up
9787// when we add hygiene to item names.
98- pub fn apply_renames ( renames : & RenameList , ctxt : SyntaxContext ) -> SyntaxContext {
99- renames. iter ( ) . fold ( ctxt , |ctxt , & ( from, to) | {
100- apply_rename ( from, to, ctxt )
88+ pub fn apply_renames ( renames : & RenameList , ident : Ident ) -> Ident {
89+ renames. iter ( ) . fold ( ident , |ident , & ( from, to) | {
90+ apply_rename ( from, to, ident )
10191 } )
10292}
10393
@@ -114,8 +104,8 @@ pub fn with_sctable<T, F>(op: F) -> T where
114104fn new_sctable_internal ( ) -> SCTable {
115105 SCTable {
116106 table : RefCell :: new ( vec ! ( EmptyCtxt , IllegalCtxt ) ) ,
117- mark_memo : RefCell :: new ( HashMap :: new ( ) ) ,
118- rename_memo : RefCell :: new ( HashMap :: new ( ) ) ,
107+ marks : RefCell :: new ( HashMap :: new ( ) ) ,
108+ renames : RefCell :: new ( HashMap :: new ( ) ) ,
119109 }
120110}
121111
@@ -131,20 +121,18 @@ pub fn display_sctable(table: &SCTable) {
131121pub fn clear_tables ( ) {
132122 with_sctable ( |table| {
133123 * table. table . borrow_mut ( ) = Vec :: new ( ) ;
134- * table. mark_memo . borrow_mut ( ) = HashMap :: new ( ) ;
135- * table. rename_memo . borrow_mut ( ) = HashMap :: new ( ) ;
124+ * table. marks . borrow_mut ( ) = HashMap :: new ( ) ;
125+ * table. renames . borrow_mut ( ) = HashMap :: new ( ) ;
136126 } ) ;
137- with_resolve_table_mut ( |table| * table = HashMap :: new ( ) ) ;
138127}
139128
140129/// Reset the tables to their initial state
141130pub fn reset_tables ( ) {
142131 with_sctable ( |table| {
143132 * table. table . borrow_mut ( ) = vec ! ( EmptyCtxt , IllegalCtxt ) ;
144- * table. mark_memo . borrow_mut ( ) = HashMap :: new ( ) ;
145- * table. rename_memo . borrow_mut ( ) = HashMap :: new ( ) ;
133+ * table. marks . borrow_mut ( ) = HashMap :: new ( ) ;
134+ * table. renames . borrow_mut ( ) = HashMap :: new ( ) ;
146135 } ) ;
147- with_resolve_table_mut ( |table| * table = HashMap :: new ( ) ) ;
148136}
149137
150138/// Add a value to the end of a vec, return its index
@@ -156,103 +144,19 @@ fn idx_push<T>(vec: &mut Vec<T>, val: T) -> u32 {
156144/// Resolve a syntax object to a name, per MTWT.
157145pub fn resolve ( id : Ident ) -> Name {
158146 with_sctable ( |sctable| {
159- with_resolve_table_mut ( |resolve_table| {
160- resolve_internal ( id, sctable, resolve_table)
161- } )
147+ resolve_internal ( id, sctable)
162148 } )
163149}
164150
165- type ResolveTable = HashMap < ( Name , SyntaxContext ) , Name > ;
166-
167- // okay, I admit, putting this in TLS is not so nice:
168- // fetch the SCTable from TLS, create one if it doesn't yet exist.
169- fn with_resolve_table_mut < T , F > ( op : F ) -> T where
170- F : FnOnce ( & mut ResolveTable ) -> T ,
171- {
172- thread_local ! ( static RESOLVE_TABLE_KEY : RefCell <ResolveTable > = {
173- RefCell :: new( HashMap :: new( ) )
174- } ) ;
175-
176- RESOLVE_TABLE_KEY . with ( move |slot| op ( & mut * slot. borrow_mut ( ) ) )
177- }
178-
179151/// Resolve a syntax object to a name, per MTWT.
180152/// adding memoization to resolve 500+ seconds in resolve for librustc (!)
181- fn resolve_internal ( id : Ident ,
182- table : & SCTable ,
183- resolve_table : & mut ResolveTable ) -> Name {
184- let key = ( id. name , id. ctxt ) ;
185-
186- match resolve_table. get ( & key) {
187- Some ( & name) => return name,
188- None => { }
189- }
190-
191- let resolved = {
192- let result = ( * table. table . borrow ( ) ) [ id. ctxt . 0 as usize ] ;
193- match result {
194- EmptyCtxt => id. name ,
195- // ignore marks here:
196- Mark ( _, subctxt) =>
197- resolve_internal ( Ident :: new ( id. name , subctxt) ,
198- table, resolve_table) ,
199- // do the rename if necessary:
200- Rename ( Ident { name, ctxt} , toname, subctxt) => {
201- let resolvedfrom =
202- resolve_internal ( Ident :: new ( name, ctxt) ,
203- table, resolve_table) ;
204- let resolvedthis =
205- resolve_internal ( Ident :: new ( id. name , subctxt) ,
206- table, resolve_table) ;
207- if ( resolvedthis == resolvedfrom)
208- && ( marksof_internal ( ctxt, resolvedthis, table)
209- == marksof_internal ( subctxt, resolvedthis, table) ) {
210- toname
211- } else {
212- resolvedthis
213- }
214- }
215- IllegalCtxt => panic ! ( "expected resolvable context, got IllegalCtxt" )
216- }
217- } ;
218- resolve_table. insert ( key, resolved) ;
219- resolved
220- }
221-
222- /// Compute the marks associated with a syntax context.
223- pub fn marksof ( ctxt : SyntaxContext , stopname : Name ) -> Vec < Mrk > {
224- with_sctable ( |table| marksof_internal ( ctxt, stopname, table) )
225- }
226-
227- // the internal function for computing marks
228- // it's not clear to me whether it's better to use a [] mutable
229- // vector or a cons-list for this.
230- fn marksof_internal ( ctxt : SyntaxContext ,
231- stopname : Name ,
232- table : & SCTable ) -> Vec < Mrk > {
233- let mut result = Vec :: new ( ) ;
234- let mut loopvar = ctxt;
235- loop {
236- let table_entry = ( * table. table . borrow ( ) ) [ loopvar. 0 as usize ] ;
237- match table_entry {
238- EmptyCtxt => {
239- return result;
240- } ,
241- Mark ( mark, tl) => {
242- xor_push ( & mut result, mark) ;
243- loopvar = tl;
244- } ,
245- Rename ( _, name, tl) => {
246- // see MTWT for details on the purpose of the stopname.
247- // short version: it prevents duplication of effort.
248- if name == stopname {
249- return result;
250- } else {
251- loopvar = tl;
252- }
253- }
254- IllegalCtxt => panic ! ( "expected resolvable context, got IllegalCtxt" )
255- }
153+ fn resolve_internal ( id : Ident , table : & SCTable ) -> Name {
154+ match table. table . borrow ( ) [ id. ctxt . 0 as usize ] {
155+ EmptyCtxt => id. name ,
156+ // ignore marks here:
157+ Mark ( _, subctxt) => resolve_internal ( Ident :: new ( id. name , subctxt) , table) ,
158+ Rename ( name) => name,
159+ IllegalCtxt => panic ! ( "expected resolvable context, got IllegalCtxt" )
256160 }
257161}
258162
@@ -267,16 +171,6 @@ pub fn outer_mark(ctxt: SyntaxContext) -> Mrk {
267171 } )
268172}
269173
270- /// Push a name... unless it matches the one on top, in which
271- /// case pop and discard (so two of the same marks cancel)
272- fn xor_push ( marks : & mut Vec < Mrk > , mark : Mrk ) {
273- if ( !marks. is_empty ( ) ) && ( * marks. last ( ) . unwrap ( ) == mark) {
274- marks. pop ( ) . unwrap ( ) ;
275- } else {
276- marks. push ( mark) ;
277- }
278- }
279-
280174#[ cfg( test) ]
281175mod tests {
282176 use self :: TestSC :: * ;
0 commit comments