{ Copyright (c) 2008 by Jonas Maebe Whole program optimisation information collection 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 wpoinfo; {$i fpcdefs.inc} interface uses cclasses, symtype, wpobase, ppu; type pderefarray = ^tderefarray; tderefarray = array[0..1024*1024-1] of tderef; tunitwpoinfo = class(tunitwpoinfobase) { devirtualisation information -- begin } private fcreatedobjtypesderefs: pderefarray; fcreatedclassrefobjtypesderefs: pderefarray; fmaybecreatedbyclassrefdeftypesderefs: pderefarray; fcalledvmtentriestemplist: tfpobjectlist; { devirtualisation information -- end } procedure clearderefinfo; public destructor destroy; override; procedure ppuwrite(ppufile:tcompilerppufile); constructor ppuload(ppufile:tcompilerppufile); procedure deref; procedure derefimpl; procedure buildderef; procedure buildderefimpl; end; { twpoinfomanager } twpoinfomanager = class(twpoinfomanagerbase) function can_be_devirtualized(objdef, procdef: tdef; out name: shortstring): boolean; override; function optimized_name_for_vmt(objdef, procdef: tdef; out name: shortstring): boolean; override; function symbol_live(const name: shortstring): boolean; override; end; implementation uses globtype, globals, symdef, verbose; procedure tunitwpoinfo.clearderefinfo; begin if assigned(fcreatedobjtypesderefs) then begin freemem(fcreatedobjtypesderefs); fcreatedobjtypesderefs:=nil; end; if assigned(fcreatedclassrefobjtypesderefs) then begin freemem(fcreatedclassrefobjtypesderefs); fcreatedclassrefobjtypesderefs:=nil; end; if assigned(fmaybecreatedbyclassrefdeftypesderefs) then begin freemem(fmaybecreatedbyclassrefdeftypesderefs); fmaybecreatedbyclassrefdeftypesderefs:=nil; end; if assigned(fcalledvmtentriestemplist) then begin fcalledvmtentriestemplist.free; fcalledvmtentriestemplist:=nil; end; end; destructor tunitwpoinfo.destroy; begin clearderefinfo; inherited destroy; end; procedure tunitwpoinfo.ppuwrite(ppufile:tcompilerppufile); var i: longint; begin { write the number of instantiated object types in this module, followed by the derefs of those types } ppufile.putlongint(fcreatedobjtypes.count); for i:=0 to fcreatedobjtypes.count-1 do ppufile.putderef(fcreatedobjtypesderefs^[i]); ppufile.putlongint(fcreatedclassrefobjtypes.count); for i:=0 to fcreatedclassrefobjtypes.count-1 do ppufile.putderef(fcreatedclassrefobjtypesderefs^[i]); ppufile.putlongint(fmaybecreatedbyclassrefdeftypes.count); for i:=0 to fmaybecreatedbyclassrefdeftypes.count-1 do ppufile.putderef(fmaybecreatedbyclassrefdeftypesderefs^[i]); ppufile.putlongint(fcalledvmtentriestemplist.count); for i:=0 to fcalledvmtentriestemplist.count-1 do tcalledvmtentries(fcalledvmtentriestemplist[i]).ppuwrite(ppufile); ppufile.writeentry(ibcreatedobjtypes); { don't free deref arrays immediately after use, as the types may need re-resolving in case a unit needs to be reloaded } end; constructor tunitwpoinfo.ppuload(ppufile:tcompilerppufile); var i, len: longint; begin { load start of definition section, which holds the amount of defs } if ppufile.readentry<>ibcreatedobjtypes then cgmessage(unit_f_ppu_read_error); { don't load the wpo info from the units if we are not generating a wpo feedback file (that would just take time and memory) } if (init_settings.genwpoptimizerswitches=[]) then ppufile.skipdata(ppufile.entrysize) else begin len:=ppufile.getlongint; fcreatedobjtypes:=tfpobjectlist.create(false); fcreatedobjtypes.count:=len; getmem(fcreatedobjtypesderefs,len*sizeof(tderef)); for i:=0 to len-1 do ppufile.getderef(fcreatedobjtypesderefs^[i]); len:=ppufile.getlongint; fcreatedclassrefobjtypes:=tfpobjectlist.create(false); fcreatedclassrefobjtypes.count:=len; getmem(fcreatedclassrefobjtypesderefs,len*sizeof(tderef)); for i:=0 to len-1 do ppufile.getderef(fcreatedclassrefobjtypesderefs^[i]); len:=ppufile.getlongint; fmaybecreatedbyclassrefdeftypes:=tfpobjectlist.create(false); fmaybecreatedbyclassrefdeftypes.count:=len; getmem(fmaybecreatedbyclassrefdeftypesderefs,len*sizeof(tderef)); for i:=0 to len-1 do ppufile.getderef(fmaybecreatedbyclassrefdeftypesderefs^[i]); len:=ppufile.getlongint; fcalledvmtentriestemplist:=tfpobjectlist.create(false); fcalledvmtentriestemplist.count:=len; fcalledvmtentries:=tfphashlist.create; for i:=0 to len-1 do fcalledvmtentriestemplist[i]:=tcalledvmtentries.ppuload(ppufile); end; end; procedure tunitwpoinfo.buildderef; var i: longint; begin { ppuload may have already been called before -> deref info structures may already have been allocated } clearderefinfo; getmem(fcreatedobjtypesderefs,fcreatedobjtypes.count*sizeof(tderef)); for i:=0 to fcreatedobjtypes.count-1 do fcreatedobjtypesderefs^[i].build(fcreatedobjtypes[i]); getmem(fcreatedclassrefobjtypesderefs,fcreatedclassrefobjtypes.count*sizeof(tderef)); for i:=0 to fcreatedclassrefobjtypes.count-1 do fcreatedclassrefobjtypesderefs^[i].build(fcreatedclassrefobjtypes[i]); getmem(fmaybecreatedbyclassrefdeftypesderefs,fmaybecreatedbyclassrefdeftypes.count*sizeof(tderef)); for i:=0 to fmaybecreatedbyclassrefdeftypes.count-1 do fmaybecreatedbyclassrefdeftypesderefs^[i].build(fmaybecreatedbyclassrefdeftypes[i]); fcalledvmtentriestemplist:=tfpobjectlist.create(false); fcalledvmtentriestemplist.count:=fcalledvmtentries.count; for i:=0 to fcalledvmtentries.count-1 do begin tcalledvmtentries(fcalledvmtentries[i]).buildderef; { necessary in case we have unit1 loads unit2, unit2 is recompiled, then unit1 derefs unit2 -> in this case we have buildderef for unit2 -> ppuwrite for unit2 -> deref for unit2 (without a load) -> ensure that the fcalledvmtentriestemplist, normally constructed by ppuload, is created here as well since deref needs it } fcalledvmtentriestemplist[i]:=tobject(fcalledvmtentries[i]); end; end; procedure tunitwpoinfo.buildderefimpl; var i: longint; begin for i:=0 to fcalledvmtentriestemplist.count-1 do begin tcalledvmtentries(fcalledvmtentriestemplist[i]).buildderefimpl; end; end; procedure tunitwpoinfo.deref; var i: longint; begin if (init_settings.genwpoptimizerswitches=[]) or not assigned(fcalledvmtentriestemplist) then exit; { don't free deref arrays immediately after use, as the types may need re-resolving in case a unit needs to be reloaded } for i:=0 to fcreatedobjtypes.count-1 do fcreatedobjtypes[i]:=fcreatedobjtypesderefs^[i].resolve; for i:=0 to fcreatedclassrefobjtypes.count-1 do fcreatedclassrefobjtypes[i]:=fcreatedclassrefobjtypesderefs^[i].resolve; for i:=0 to fmaybecreatedbyclassrefdeftypes.count-1 do fmaybecreatedbyclassrefdeftypes[i]:=fmaybecreatedbyclassrefdeftypesderefs^[i].resolve; { in case we are re-resolving, free previous batch } if (fcalledvmtentries.count<>0) then fcalledvmtentries.clear; { allocate enough internal memory in one go } fcalledvmtentries.capacity:=fcalledvmtentriestemplist.count; { now resolve all items in the list and add them to the hash table } for i:=0 to fcalledvmtentriestemplist.count-1 do begin with tcalledvmtentries(fcalledvmtentriestemplist[i]) do begin deref; fcalledvmtentries.add(tobjectdef(objdef).vmt_mangledname, fcalledvmtentriestemplist[i]); end; end; end; procedure tunitwpoinfo.derefimpl; var i: longint; begin if (init_settings.genwpoptimizerswitches=[]) or not assigned(fcalledvmtentriestemplist) then exit; for i:=0 to fcalledvmtentriestemplist.count-1 do begin tcalledvmtentries(fcalledvmtentriestemplist[i]).derefimpl; end; end; { twpoinfomanager } { devirtualisation } function twpoinfomanager.can_be_devirtualized(objdef, procdef: tdef; out name: shortstring): boolean; begin if not assigned(wpoinfouse[wpo_devirtualization_context_insensitive]) or not(cs_wpo_devirtualize_calls in current_settings.dowpoptimizerswitches) then begin result:=false; exit; end; result:=twpodevirtualisationhandler(wpoinfouse[wpo_devirtualization_context_insensitive]).staticnameforcallingvirtualmethod(objdef,procdef,name); end; function twpoinfomanager.optimized_name_for_vmt(objdef, procdef: tdef; out name: shortstring): boolean; begin if not assigned(wpoinfouse[wpo_devirtualization_context_insensitive]) or not(cs_wpo_optimize_vmts in current_settings.dowpoptimizerswitches) then begin result:=false; exit; end; result:=twpodevirtualisationhandler(wpoinfouse[wpo_devirtualization_context_insensitive]).staticnameforvmtentry(objdef,procdef,name); end; { symbol liveness } function twpoinfomanager.symbol_live(const name: shortstring): boolean; begin if not assigned(wpoinfouse[wpo_live_symbol_information]) or not(cs_wpo_symbol_liveness in current_settings.dowpoptimizerswitches) then begin { if we don't know, say that the symbol is live } result:=true; exit; end; result:=twpodeadcodehandler(wpoinfouse[wpo_live_symbol_information]).symbolinfinalbinary(name); end; end.