2
0

symstack.pas 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Daniel Mantione
  4. member of the Free Pascal development team
  5. Commandline compiler for Free Pascal
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ***************************************************************************}
  18. unit symstack;
  19. interface
  20. uses objects,symtable,globtype;
  21. const cachesize=64; {This should be a power of 2.}
  22. type Tsymtablestack=object(Tobject)
  23. srsym:Psym; {Result of the last search.}
  24. srsymtable:Psymtable;
  25. lastsrsym:Psym; {Last sym found in statement.}
  26. lastsrsymtable:Psymtable;
  27. constructor init;
  28. procedure clearcache;
  29. procedure insert(s:Psym;addtocache:boolean);
  30. function pop:Psymtable;
  31. procedure push(s:Psymtable);
  32. procedure search(const s:stringid;notfounderror:boolean);
  33. function search_a_symtable(const symbol:stringid;symtabletype:pointer):Psym;
  34. function top:Psymtable;
  35. procedure topfree;
  36. destructor done;virtual;
  37. private
  38. cache:array[1..cachesize] of Psym;
  39. cachetables:array[1..cachesize] of Psymtable;
  40. symtablestack:Tcollection; {For speed reasons this is not
  41. a pointer. A Tcollection is not
  42. the perfect data structure for
  43. a stack; it could be a good idea
  44. to write an abstract stack object.}
  45. procedure decache(s:Psymtable);
  46. end;
  47. {$IFDEF STATISTICS}
  48. var hits,misses:longint;
  49. {$ENDIF STATISTICS}
  50. implementation
  51. uses cobjects,symtablt,verbose,symbols,defs;
  52. var oldexit:pointer;
  53. constructor Tsymtablestack.init;
  54. begin
  55. symtablestack.init(16,8);
  56. clearcache;
  57. end;
  58. procedure Tsymtablestack.clearcache;
  59. begin
  60. fillchar(cache,sizeof(cache),0);
  61. fillchar(cachetables,sizeof(cache),0);
  62. end;
  63. procedure Tsymtablestack.decache(s:Psymtable);
  64. var p,endp:^Psymtable;
  65. q:^Psym;
  66. begin
  67. {Must be fast, otherwise the speed advantage is lost!
  68. Therefore, the cache should not be too large...}
  69. p:=@cachetables;
  70. endp:=pointer(longint(@cachetables)+cachesize*sizeof(pointer));
  71. q:=@cache;
  72. repeat
  73. if p^=s then
  74. begin
  75. p^:=nil;
  76. q^:=nil;
  77. end;
  78. inc(p);
  79. inc(q);
  80. until p=endp;
  81. end;
  82. procedure Tsymtablestack.search(const s:stringid;notfounderror:boolean);
  83. var speedvalue,entry:longint;
  84. i:word;
  85. begin
  86. speedvalue:=getspeedvalue(s);
  87. lastsrsym:=nil;
  88. {Check the cache.}
  89. entry:=(speedvalue and cachesize-1)+1;
  90. if (cache[entry]<>nil) and (cache[entry]^.speedvalue=speedvalue) and
  91. (cache[entry]^.name=s) then
  92. begin
  93. {Cache hit!}
  94. srsym:=cache[entry];
  95. srsymtable:=cachetables[entry];
  96. {$IFDEF STATISTICS}
  97. inc(hits);
  98. {$ENDIF STATISTICS}
  99. end
  100. else
  101. begin
  102. {Cache miss. :( }
  103. {$IFDEF STATISTICS}
  104. inc(misses);
  105. {$ENDIF STATISTICS}
  106. for i:=symtablestack.count-1 downto 0 do
  107. begin
  108. srsymtable:=Psymtable(symtablestack.at(i));
  109. srsym:=srsymtable^.speedsearch(s,speedvalue);
  110. if srsym<>nil then
  111. begin
  112. {Found! Place it in the cache.}
  113. cache[entry]:=srsym;
  114. cachetables[entry]:=srsymtable;
  115. exit;
  116. end
  117. end;
  118. {Not found...}
  119. srsym:=nil;
  120. if notfounderror then
  121. begin
  122. message1(sym_e_id_not_found,s);
  123. srsym:=generrorsym;
  124. end;
  125. end;
  126. end;
  127. function Tsymtablestack.pop:Psymtable;
  128. var r:Psymtable;
  129. begin
  130. r:=symtablestack.at(symtablestack.count);
  131. decache(r);
  132. pop:=r;
  133. symtablestack.atdelete(symtablestack.count);
  134. end;
  135. procedure Tsymtablestack.push(s:Psymtable);
  136. begin
  137. symtablestack.insert(s);
  138. end;
  139. procedure Tsymtablestack.insert(s:Psym;addtocache:boolean);
  140. var pretop,sttop:Psymtable;
  141. hsym:Psym;
  142. entry:longint;
  143. begin
  144. sttop:=Psymtable(symtablestack.at(symtablestack.count));
  145. pretop:=Psymtable(symtablestack.at(symtablestack.count-1));
  146. if typeof(sttop^)=typeof(Timplsymtable) then
  147. begin
  148. {There must also be an interface symtable...}
  149. if pretop^.speedsearch(s^.name,s^.speedvalue)<>nil then
  150. duplicatesym(s);
  151. end;
  152. {Check for duplicate field id in inherited classes.}
  153. if sttop^.is_object(typeof(Tobjectsymtable)) and
  154. (Pobjectsymtable(sttop)^.defowner<>nil) then
  155. begin
  156. {Even though the private symtable is disposed and set to nil
  157. after the unit has been compiled, we will still have to check
  158. for a private sym, because of interdependend units.}
  159. hsym:=Pobjectdef(Pobjectsymtable(sttop)^.defowner)^.
  160. speedsearch(s^.name,s^.speedvalue);
  161. if (hsym<>nil) and
  162. (hsym^.is_object(typeof(Tprocsym))
  163. and (sp_private in Pprocsym(hsym)^.objprop)) and
  164. (hsym^.is_object(typeof(Tvarsym))
  165. and (sp_private in Pvarsym(hsym)^.objprop)) then
  166. duplicatesym(hsym);
  167. end;
  168. entry:=(s^.speedvalue and cachesize-1)+1;
  169. if s^.is_object(typeof(Tenumsym)) and
  170. sttop^.is_object(Tabstractrecordsymtable)) then
  171. begin
  172. if pretop^.insert(s) and addtocache then
  173. begin
  174. cache[entry]:=s;
  175. cachetables[entry]:=pretop;
  176. end;
  177. end
  178. else
  179. begin
  180. if sttop^.insert(s) and addtocache then
  181. begin
  182. cache[entry]:=s;
  183. cachetables[entry]:=top;
  184. end;
  185. end;
  186. end;
  187. function Tsymtablestack.top:Psymtable;
  188. begin
  189. top:=symtablestack.at(symtablestack.count);
  190. end;
  191. function Tsymtablestack.search_a_symtable(const symbol:stringid;symtabletype:pointer):Psym;
  192. {Search for a symbol in a specified symbol table. Returns nil if
  193. the symtable is not found, and also if the symbol cannot be found
  194. in the desired symtable.}
  195. var hsymtab:Psymtable;
  196. res:Psym;
  197. i:word;
  198. begin
  199. res:=nil;
  200. for i:=symtablestack.count-1 downto 0 do
  201. if typeof((Psymtable(symtablestack.at(i))^))=symtabletype then
  202. begin
  203. {We found the desired symtable. Now check if the symbol we
  204. search for is defined in it }
  205. res:=hsymtab^.search(symbol);
  206. break;
  207. end;
  208. search_a_symtable:=res;
  209. end;
  210. procedure Tsymtablestack.topfree;
  211. begin
  212. decache(symtablestack.at(symtablestack.count));
  213. symtablestack.atfree(symtablestack.count);
  214. end;
  215. destructor Tsymtablestack.done;
  216. begin
  217. symtablestack.done;
  218. end;
  219. {$IFDEF STATISTICS}
  220. procedure exitprocedure;{$IFDEF TP}far;{$ENDIF}
  221. begin
  222. writeln('Symbol cache statistics:');
  223. writeln('------------------------');
  224. writeln;
  225. writeln('Hits: ',hits);
  226. writeln('Misses: ',misses);
  227. writeln;
  228. writeln('Hit percentage: ',(hits*100) div (hits+misses),'%');
  229. exitproc:=oldexit;
  230. end;
  231. begin
  232. hits:=0;
  233. misses:=0;
  234. oldexit:=exitproc;
  235. exitproc:=@exitprocedure;
  236. {$ENDIF STATISTICS}
  237. end.