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