123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- {
- $Id$
- Copyright (c) 1998-2000 by Daniel Mantione
- member of the Free Pascal development team
- Commandline compiler for Free Pascal
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ***************************************************************************}
- unit symstack;
- interface
- uses objects,symtable,globtype;
- const cachesize=64; {This should be a power of 2.}
- type Tsymtablestack=object(Tobject)
- srsym:Psym; {Result of the last search.}
- srsymtable:Psymtable;
- lastsrsym:Psym; {Last sym found in statement.}
- lastsrsymtable:Psymtable;
- constructor init;
- procedure clearcache;
- procedure insert(s:Psym;addtocache:boolean);
- function pop:Psymtable;
- procedure push(s:Psymtable);
- procedure search(const s:stringid;notfounderror:boolean);
- function search_a_symtable(const symbol:stringid;symtabletype:pointer):Psym;
- function top:Psymtable;
- procedure topfree;
- destructor done;virtual;
- private
- cache:array[1..cachesize] of Psym;
- cachetables:array[1..cachesize] of Psymtable;
- symtablestack:Tcollection; {For speed reasons this is not
- a pointer. A Tcollection is not
- the perfect data structure for
- a stack; it could be a good idea
- to write an abstract stack object.}
- procedure decache(s:Psymtable);
- end;
- {$IFDEF STATISTICS}
- var hits,misses:longint;
- {$ENDIF STATISTICS}
- implementation
- uses cobjects,symtablt,verbose,symbols,defs;
- var oldexit:pointer;
- constructor Tsymtablestack.init;
- begin
- symtablestack.init(16,8);
- clearcache;
- end;
- procedure Tsymtablestack.clearcache;
- begin
- fillchar(cache,sizeof(cache),0);
- fillchar(cachetables,sizeof(cache),0);
- end;
- procedure Tsymtablestack.decache(s:Psymtable);
- var p,endp:^Psymtable;
- q:^Psym;
- begin
- {Must be fast, otherwise the speed advantage is lost!
- Therefore, the cache should not be too large...}
- p:=@cachetables;
- endp:=pointer(longint(@cachetables)+cachesize*sizeof(pointer));
- q:=@cache;
- repeat
- if p^=s then
- begin
- p^:=nil;
- q^:=nil;
- end;
- inc(p);
- inc(q);
- until p=endp;
- end;
- procedure Tsymtablestack.search(const s:stringid;notfounderror:boolean);
- var speedvalue,entry:longint;
- i:word;
- begin
- speedvalue:=getspeedvalue(s);
- lastsrsym:=nil;
- {Check the cache.}
- entry:=(speedvalue and cachesize-1)+1;
- if (cache[entry]<>nil) and (cache[entry]^.speedvalue=speedvalue) and
- (cache[entry]^.name=s) then
- begin
- {Cache hit!}
- srsym:=cache[entry];
- srsymtable:=cachetables[entry];
- {$IFDEF STATISTICS}
- inc(hits);
- {$ENDIF STATISTICS}
- end
- else
- begin
- {Cache miss. :( }
- {$IFDEF STATISTICS}
- inc(misses);
- {$ENDIF STATISTICS}
- for i:=symtablestack.count-1 downto 0 do
- begin
- srsymtable:=Psymtable(symtablestack.at(i));
- srsym:=srsymtable^.speedsearch(s,speedvalue);
- if srsym<>nil then
- begin
- {Found! Place it in the cache.}
- cache[entry]:=srsym;
- cachetables[entry]:=srsymtable;
- exit;
- end
- end;
- {Not found...}
- srsym:=nil;
- if notfounderror then
- begin
- message1(sym_e_id_not_found,s);
- srsym:=generrorsym;
- end;
- end;
- end;
- function Tsymtablestack.pop:Psymtable;
- var r:Psymtable;
- begin
- r:=symtablestack.at(symtablestack.count);
- decache(r);
- pop:=r;
- symtablestack.atdelete(symtablestack.count);
- end;
- procedure Tsymtablestack.push(s:Psymtable);
- begin
- symtablestack.insert(s);
- end;
- procedure Tsymtablestack.insert(s:Psym;addtocache:boolean);
- var pretop,sttop:Psymtable;
- hsym:Psym;
- entry:longint;
- begin
- sttop:=Psymtable(symtablestack.at(symtablestack.count));
- pretop:=Psymtable(symtablestack.at(symtablestack.count-1));
- if typeof(sttop^)=typeof(Timplsymtable) then
- begin
- {There must also be an interface symtable...}
- if pretop^.speedsearch(s^.name,s^.speedvalue)<>nil then
- duplicatesym(s);
- end;
- {Check for duplicate field id in inherited classes.}
- if sttop^.is_object(typeof(Tobjectsymtable)) and
- (Pobjectsymtable(sttop)^.defowner<>nil) then
- begin
- {Even though the private symtable is disposed and set to nil
- after the unit has been compiled, we will still have to check
- for a private sym, because of interdependend units.}
- hsym:=Pobjectdef(Pobjectsymtable(sttop)^.defowner)^.
- speedsearch(s^.name,s^.speedvalue);
- if (hsym<>nil) and
- (hsym^.is_object(typeof(Tprocsym))
- and (sp_private in Pprocsym(hsym)^.objprop)) and
- (hsym^.is_object(typeof(Tvarsym))
- and (sp_private in Pvarsym(hsym)^.objprop)) then
- duplicatesym(hsym);
- end;
- entry:=(s^.speedvalue and cachesize-1)+1;
- if s^.is_object(typeof(Tenumsym)) and
- sttop^.is_object(Tabstractrecordsymtable)) then
- begin
- if pretop^.insert(s) and addtocache then
- begin
- cache[entry]:=s;
- cachetables[entry]:=pretop;
- end;
- end
- else
- begin
- if sttop^.insert(s) and addtocache then
- begin
- cache[entry]:=s;
- cachetables[entry]:=top;
- end;
- end;
- end;
- function Tsymtablestack.top:Psymtable;
- begin
- top:=symtablestack.at(symtablestack.count);
- end;
- function Tsymtablestack.search_a_symtable(const symbol:stringid;symtabletype:pointer):Psym;
- {Search for a symbol in a specified symbol table. Returns nil if
- the symtable is not found, and also if the symbol cannot be found
- in the desired symtable.}
- var hsymtab:Psymtable;
- res:Psym;
- i:word;
- begin
- res:=nil;
- for i:=symtablestack.count-1 downto 0 do
- if typeof((Psymtable(symtablestack.at(i))^))=symtabletype then
- begin
- {We found the desired symtable. Now check if the symbol we
- search for is defined in it }
- res:=hsymtab^.search(symbol);
- break;
- end;
- search_a_symtable:=res;
- end;
- procedure Tsymtablestack.topfree;
- begin
- decache(symtablestack.at(symtablestack.count));
- symtablestack.atfree(symtablestack.count);
- end;
- destructor Tsymtablestack.done;
- begin
- symtablestack.done;
- end;
- {$IFDEF STATISTICS}
- procedure exitprocedure;{$IFDEF TP}far;{$ENDIF}
- begin
- writeln('Symbol cache statistics:');
- writeln('------------------------');
- writeln;
- writeln('Hits: ',hits);
- writeln('Misses: ',misses);
- writeln;
- writeln('Hit percentage: ',(hits*100) div (hits+misses),'%');
- exitproc:=oldexit;
- end;
- begin
- hits:=0;
- misses:=0;
- oldexit:=exitproc;
- exitproc:=@exitprocedure;
- {$ENDIF STATISTICS}
- end.
|