wpoinfo.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. {
  2. Copyright (c) 2008 by Jonas Maebe
  3. Whole program optimisation information collection
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit wpoinfo;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,cclasses,
  22. symtype,
  23. wpobase;
  24. type
  25. tderefarray = array of tderef;
  26. tunitwpoinfo = class(tunitwpoinfobase)
  27. { devirtualisation information -- begin }
  28. private
  29. fcreatedobjtypesderefs: tderefarray;
  30. fcreatedclassrefobjtypesderefs: tderefarray;
  31. fmaybecreatedbyclassrefdeftypesderefs: tderefarray;
  32. fcalledvmtentriestemplist: tfpobjectlist;
  33. { devirtualisation information -- end }
  34. procedure clearderefinfo;
  35. public
  36. destructor destroy; override;
  37. procedure ppuwrite(ppufile:tcompilerppufile);
  38. constructor ppuload(ppufile:tcompilerppufile);
  39. procedure deref;
  40. procedure derefimpl;
  41. procedure buildderef;
  42. procedure buildderefimpl;
  43. end;
  44. { twpoinfomanager }
  45. twpoinfomanager = class(twpoinfomanagerbase)
  46. function can_be_devirtualized(objdef, procdef: tdef; out name: TSymStr): boolean; override;
  47. function optimized_name_for_vmt(objdef, procdef: tdef; out name: TSymStr): boolean; override;
  48. function symbol_live(const name: shortstring): boolean; override;
  49. end;
  50. implementation
  51. uses
  52. globals,
  53. symdef,
  54. verbose,
  55. entfile;
  56. procedure tunitwpoinfo.clearderefinfo;
  57. begin
  58. fcreatedobjtypesderefs:=nil;
  59. fcreatedclassrefobjtypesderefs:=nil;
  60. fmaybecreatedbyclassrefdeftypesderefs:=nil;
  61. fcalledvmtentriestemplist.free;
  62. fcalledvmtentriestemplist:=nil;
  63. end;
  64. destructor tunitwpoinfo.destroy;
  65. begin
  66. clearderefinfo;
  67. inherited destroy;
  68. end;
  69. procedure tunitwpoinfo.ppuwrite(ppufile:tcompilerppufile);
  70. var
  71. i: longint;
  72. begin
  73. { write the number of instantiated object types in this module,
  74. followed by the derefs of those types
  75. }
  76. ppufile.putlongint(fcreatedobjtypes.count);
  77. for i:=0 to fcreatedobjtypes.count-1 do
  78. ppufile.putderef(fcreatedobjtypesderefs[i]);
  79. ppufile.putlongint(fcreatedclassrefobjtypes.count);
  80. for i:=0 to fcreatedclassrefobjtypes.count-1 do
  81. ppufile.putderef(fcreatedclassrefobjtypesderefs[i]);
  82. ppufile.putlongint(fmaybecreatedbyclassrefdeftypes.count);
  83. for i:=0 to fmaybecreatedbyclassrefdeftypes.count-1 do
  84. ppufile.putderef(fmaybecreatedbyclassrefdeftypesderefs[i]);
  85. ppufile.putlongint(fcalledvmtentriestemplist.count);
  86. for i:=0 to fcalledvmtentriestemplist.count-1 do
  87. tcalledvmtentries(fcalledvmtentriestemplist[i]).ppuwrite(ppufile);
  88. ppufile.writeentry(ibcreatedobjtypes);
  89. { don't free deref arrays immediately after use, as the types may need
  90. re-resolving in case a unit needs to be reloaded
  91. }
  92. end;
  93. constructor tunitwpoinfo.ppuload(ppufile:tcompilerppufile);
  94. var
  95. i, len: longint;
  96. begin
  97. { load start of definition section, which holds the amount of defs }
  98. if ppufile.readentry<>ibcreatedobjtypes then
  99. message(unit_f_ppu_read_error);
  100. { don't load the wpo info from the units if we are not generating
  101. a wpo feedback file (that would just take time and memory)
  102. }
  103. if (init_settings.genwpoptimizerswitches=[]) then
  104. ppufile.skipdata(ppufile.entrysize)
  105. else
  106. begin
  107. len:=ppufile.getlongint;
  108. fcreatedobjtypes:=tfpobjectlist.create(false);
  109. fcreatedobjtypes.count:=len;
  110. setlength(fcreatedobjtypesderefs,len);
  111. for i:=0 to len-1 do
  112. ppufile.getderef(fcreatedobjtypesderefs[i]);
  113. len:=ppufile.getlongint;
  114. fcreatedclassrefobjtypes:=tfpobjectlist.create(false);
  115. fcreatedclassrefobjtypes.count:=len;
  116. setlength(fcreatedclassrefobjtypesderefs,len);
  117. for i:=0 to len-1 do
  118. ppufile.getderef(fcreatedclassrefobjtypesderefs[i]);
  119. len:=ppufile.getlongint;
  120. fmaybecreatedbyclassrefdeftypes:=tfpobjectlist.create(false);
  121. fmaybecreatedbyclassrefdeftypes.count:=len;
  122. setlength(fmaybecreatedbyclassrefdeftypesderefs,len);
  123. for i:=0 to len-1 do
  124. ppufile.getderef(fmaybecreatedbyclassrefdeftypesderefs[i]);
  125. len:=ppufile.getlongint;
  126. fcalledvmtentriestemplist:=tfpobjectlist.create(false);
  127. fcalledvmtentriestemplist.count:=len;
  128. fcalledvmtentries:=tfphashlist.create;
  129. for i:=0 to len-1 do
  130. fcalledvmtentriestemplist[i]:=tcalledvmtentries.ppuload(ppufile);
  131. end;
  132. end;
  133. procedure tunitwpoinfo.buildderef;
  134. var
  135. i: longint;
  136. begin
  137. { ppuload may have already been called before -> deref info structures
  138. may already have been allocated }
  139. clearderefinfo;
  140. setlength(fcreatedobjtypesderefs,fcreatedobjtypes.count);
  141. for i:=0 to fcreatedobjtypes.count-1 do
  142. fcreatedobjtypesderefs[i].build(fcreatedobjtypes[i]);
  143. setlength(fcreatedclassrefobjtypesderefs,fcreatedclassrefobjtypes.count);
  144. for i:=0 to fcreatedclassrefobjtypes.count-1 do
  145. fcreatedclassrefobjtypesderefs[i].build(fcreatedclassrefobjtypes[i]);
  146. setlength(fmaybecreatedbyclassrefdeftypesderefs,fmaybecreatedbyclassrefdeftypes.count);
  147. for i:=0 to fmaybecreatedbyclassrefdeftypes.count-1 do
  148. fmaybecreatedbyclassrefdeftypesderefs[i].build(fmaybecreatedbyclassrefdeftypes[i]);
  149. fcalledvmtentriestemplist:=tfpobjectlist.create(false);
  150. fcalledvmtentriestemplist.count:=fcalledvmtentries.count;
  151. for i:=0 to fcalledvmtentries.count-1 do
  152. begin
  153. tcalledvmtentries(fcalledvmtentries[i]).buildderef;
  154. { necessary in case we have unit1 loads unit2, unit2 is recompiled,
  155. then unit1 derefs unit2 -> in this case we have buildderef for unit2
  156. -> ppuwrite for unit2 -> deref for unit2 (without a load) -> ensure
  157. that the fcalledvmtentriestemplist, normally constructed by ppuload,
  158. is created here as well since deref needs it }
  159. fcalledvmtentriestemplist[i]:=tobject(fcalledvmtentries[i]);
  160. end;
  161. end;
  162. procedure tunitwpoinfo.buildderefimpl;
  163. var
  164. i: longint;
  165. begin
  166. for i:=0 to fcalledvmtentriestemplist.count-1 do
  167. begin
  168. tcalledvmtentries(fcalledvmtentriestemplist[i]).buildderefimpl;
  169. end;
  170. end;
  171. procedure tunitwpoinfo.deref;
  172. var
  173. i: longint;
  174. begin
  175. if (init_settings.genwpoptimizerswitches=[]) or
  176. not assigned(fcalledvmtentriestemplist) then
  177. exit;
  178. { don't free deref arrays immediately after use, as the types may need
  179. re-resolving in case a unit needs to be reloaded
  180. }
  181. for i:=0 to fcreatedobjtypes.count-1 do
  182. fcreatedobjtypes[i]:=fcreatedobjtypesderefs[i].resolve;
  183. for i:=0 to fcreatedclassrefobjtypes.count-1 do
  184. fcreatedclassrefobjtypes[i]:=fcreatedclassrefobjtypesderefs[i].resolve;
  185. for i:=0 to fmaybecreatedbyclassrefdeftypes.count-1 do
  186. fmaybecreatedbyclassrefdeftypes[i]:=fmaybecreatedbyclassrefdeftypesderefs[i].resolve;
  187. { in case we are re-resolving, free previous batch }
  188. if (fcalledvmtentries.count<>0) then
  189. fcalledvmtentries.clear;
  190. { allocate enough internal memory in one go }
  191. fcalledvmtentries.capacity:=fcalledvmtentriestemplist.count;
  192. { now resolve all items in the list and add them to the hash table }
  193. for i:=0 to fcalledvmtentriestemplist.count-1 do
  194. begin
  195. with tcalledvmtentries(fcalledvmtentriestemplist[i]) do
  196. begin
  197. deref;
  198. fcalledvmtentries.add(tobjectdef(objdef).vmt_mangledname,
  199. fcalledvmtentriestemplist[i]);
  200. end;
  201. end;
  202. end;
  203. procedure tunitwpoinfo.derefimpl;
  204. var
  205. i: longint;
  206. begin
  207. if (init_settings.genwpoptimizerswitches=[]) or
  208. not assigned(fcalledvmtentriestemplist) then
  209. exit;
  210. for i:=0 to fcalledvmtentriestemplist.count-1 do
  211. begin
  212. tcalledvmtentries(fcalledvmtentriestemplist[i]).derefimpl;
  213. end;
  214. end;
  215. { twpoinfomanager }
  216. { devirtualisation }
  217. function twpoinfomanager.can_be_devirtualized(objdef, procdef: tdef; out name: TSymStr): boolean;
  218. begin
  219. if not assigned(wpoinfouse[wpo_devirtualization_context_insensitive]) or
  220. not(cs_wpo_devirtualize_calls in current_settings.dowpoptimizerswitches) then
  221. begin
  222. result:=false;
  223. exit;
  224. end;
  225. result:=twpodevirtualisationhandler(wpoinfouse[wpo_devirtualization_context_insensitive]).staticnameforcallingvirtualmethod(objdef,procdef,name);
  226. end;
  227. function twpoinfomanager.optimized_name_for_vmt(objdef, procdef: tdef; out name: TSymStr): boolean;
  228. begin
  229. if not assigned(wpoinfouse[wpo_devirtualization_context_insensitive]) or
  230. not(cs_wpo_optimize_vmts in current_settings.dowpoptimizerswitches) then
  231. begin
  232. result:=false;
  233. exit;
  234. end;
  235. result:=twpodevirtualisationhandler(wpoinfouse[wpo_devirtualization_context_insensitive]).staticnameforvmtentry(objdef,procdef,name);
  236. end;
  237. { symbol liveness }
  238. function twpoinfomanager.symbol_live(const name: shortstring): boolean;
  239. begin
  240. if not assigned(wpoinfouse[wpo_live_symbol_information]) or
  241. not(cs_wpo_symbol_liveness in current_settings.dowpoptimizerswitches) then
  242. begin
  243. { if we don't know, say that the symbol is live }
  244. result:=true;
  245. exit;
  246. end;
  247. result:=twpodeadcodehandler(wpoinfouse[wpo_live_symbol_information]).symbolinfinalbinary(name);
  248. end;
  249. end.