mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-10-29 07:01:44 +01:00 
			
		
		
		
	 daef2efa69
			
		
	
	
		daef2efa69
		
	
	
	
	
		
			
			reset_used_unit_defs()/reset_all_defs() calls:
    o removed resetting tprocdef.procstarttai/procendtai and
      instead check in the debug writers whether the def is
      in the current unit or not to determine whether we should
      write debug info for it
    o use the collected defs in the wpoinfo structure to reset
      the wpo flags in the defs, instead of iterating over all
      defs in the program and resetting them that way
  - removed now unused "is_reset" flag from tmodule
git-svn-id: trunk@15501 -
		
	
			
		
			
				
	
	
		
			830 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			830 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| {
 | ||
|     Copyright (c) 2008 by Jonas Maebe
 | ||
| 
 | ||
|     Whole program optimisation information collection base class
 | ||
| 
 | ||
|     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 wpobase;
 | ||
| 
 | ||
| {$i fpcdefs.inc}
 | ||
| 
 | ||
| interface
 | ||
| 
 | ||
| uses
 | ||
|   globtype,
 | ||
|   cclasses,
 | ||
|   symtype;
 | ||
| 
 | ||
| type
 | ||
|   { the types of available whole program optimization }
 | ||
|   twpotype = (wpo_devirtualization_context_insensitive,wpo_live_symbol_information);
 | ||
| const
 | ||
|   wpo2str: array[twpotype] of string[16] = ('devirtualization','symbol liveness');
 | ||
| 
 | ||
| type
 | ||
|   { ************************************************************************* }
 | ||
|   { ******************** General base classes/interfaces ******************** }
 | ||
|   { ************************************************************************* }
 | ||
| 
 | ||
|   { interface to reading a section from a file with wpo info }
 | ||
|   twposectionreaderintf = interface
 | ||
|     ['{51BE3F89-C9C5-4965-9C83-AE7490C92E3E}']
 | ||
|     function sectiongetnextline(out s: string): boolean;
 | ||
|   end;
 | ||
| 
 | ||
| 
 | ||
|   { interface to writing sections to a file with wpoinfo }
 | ||
|   twposectionwriterintf = interface
 | ||
|     ['{C056F0DD-62B1-4612-86C7-2D39944C4437}']
 | ||
|     procedure startsection(const name: string);
 | ||
|     procedure sectionputline(const s: string);
 | ||
|   end;
 | ||
| 
 | ||
| 
 | ||
|   { base class for wpo information stores }
 | ||
| 
 | ||
|   { twpocomponentbase }
 | ||
| 
 | ||
|   twpocomponentbase = class
 | ||
|    public
 | ||
|     constructor create; reintroduce; virtual;
 | ||
| 
 | ||
|     { type of whole program optimization information collected/provided by
 | ||
|       this class
 | ||
|     }
 | ||
|     class function getwpotype: twpotype; virtual; abstract;
 | ||
| 
 | ||
|     { whole program optimizations for which this class generates information }
 | ||
|     class function generatesinfoforwposwitches: twpoptimizerswitches; virtual; abstract;
 | ||
| 
 | ||
|     { whole program optimizations performed by this class }
 | ||
|     class function performswpoforswitches: twpoptimizerswitches; virtual; abstract;
 | ||
| 
 | ||
|     { returns the name of the section parsed by this class }
 | ||
|     class function sectionname: shortstring; virtual; abstract;
 | ||
| 
 | ||
|     { checks whether the compiler options are compatible with this
 | ||
|       optimization (default: don't check anything)
 | ||
|     }
 | ||
|     class procedure checkoptions; virtual;
 | ||
| 
 | ||
|     { loads the information pertinent to this whole program optimization from
 | ||
|       the current section being processed by reader
 | ||
|     }
 | ||
|     procedure loadfromwpofilesection(reader: twposectionreaderintf); virtual; abstract;
 | ||
| 
 | ||
|     { stores the information of this component to a file in a format that can
 | ||
|       be loaded again using loadfromwpofilesection()
 | ||
|     }
 | ||
|     procedure storewpofilesection(writer: twposectionwriterintf); virtual; abstract;
 | ||
| 
 | ||
|     { extracts the information pertinent to this whole program optimization
 | ||
|       from the current compiler state (loaded units, ...)
 | ||
|     }
 | ||
|     procedure constructfromcompilerstate; virtual; abstract;
 | ||
|   end;
 | ||
| 
 | ||
|   twpocomponentbaseclass = class of twpocomponentbase;
 | ||
| 
 | ||
| 
 | ||
|   { forward declaration of overall wpo info manager class }
 | ||
| 
 | ||
|   twpoinfomanagerbase = class;
 | ||
| 
 | ||
|   { ************************************************************************* }
 | ||
|   { ** Information created per unit for use during subsequent compilation *** }
 | ||
|   { ************************************************************************* }
 | ||
| 
 | ||
|   { information about called vmt entries for a class }
 | ||
|   tcalledvmtentries = class
 | ||
|    protected
 | ||
|     { the class }
 | ||
|     fobjdef: tdef;
 | ||
|     fobjdefderef: tderef;
 | ||
|     { the vmt entries }
 | ||
|     fcalledentries: tbitset;
 | ||
|    public
 | ||
|     constructor create(_objdef: tdef; nentries: longint);
 | ||
|     constructor ppuload(ppufile: tcompilerppufile);
 | ||
|     destructor destroy; override;
 | ||
|     procedure ppuwrite(ppufile: tcompilerppufile);
 | ||
| 
 | ||
|     procedure buildderef;
 | ||
|     procedure buildderefimpl;
 | ||
|     procedure deref;
 | ||
|     procedure derefimpl;
 | ||
| 
 | ||
|     property objdef: tdef read fobjdef write fobjdef;
 | ||
|     property objdefderef: tderef read fobjdefderef write fobjdefderef;
 | ||
|     property calledentries: tbitset read fcalledentries write fcalledentries;
 | ||
|   end;
 | ||
| 
 | ||
| 
 | ||
|   { base class of information collected per unit. Still needs to be
 | ||
|     generalised for different kinds of wpo information, currently specific
 | ||
|     to devirtualization.
 | ||
|   }
 | ||
| 
 | ||
|   tunitwpoinfobase = class
 | ||
|    protected
 | ||
|     { created object types }
 | ||
|     fcreatedobjtypes: tfpobjectlist;
 | ||
|     { objectdefs pointed to by created classrefdefs }
 | ||
|     fcreatedclassrefobjtypes: tfpobjectlist;
 | ||
|     { objtypes potentially instantiated by fcreatedclassrefobjtypes
 | ||
|       (objdectdefs pointed to by classrefdefs that are
 | ||
|        passed as a regular parameter, loaded in a variable, ...
 | ||
|        so they can end up in a classrefdef var and be instantiated)
 | ||
|     }
 | ||
|     fmaybecreatedbyclassrefdeftypes: tfpobjectlist;
 | ||
| 
 | ||
|     { called virtual methods for all classes (hashed by mangled classname,
 | ||
|       entries bitmaps indicating which vmt entries per class are called --
 | ||
|       tcalledvmtentries)
 | ||
|     }
 | ||
|     fcalledvmtentries: tfphashlist;
 | ||
|    public
 | ||
|     constructor create; reintroduce; virtual;
 | ||
|     destructor destroy; override;
 | ||
| 
 | ||
|     property createdobjtypes: tfpobjectlist read fcreatedobjtypes;
 | ||
|     property createdclassrefobjtypes: tfpobjectlist read fcreatedclassrefobjtypes;
 | ||
|     property maybecreatedbyclassrefdeftypes: tfpobjectlist read fmaybecreatedbyclassrefdeftypes;
 | ||
|     property calledvmtentries: tfphashlist read fcalledvmtentries;
 | ||
| 
 | ||
|     procedure addcreatedobjtype(def: tdef);
 | ||
|     procedure addcreatedobjtypeforclassref(def: tdef);
 | ||
|     procedure addmaybecreatedbyclassref(def: tdef);
 | ||
|     procedure addcalledvmtentry(def: tdef; index: longint);
 | ||
| 
 | ||
|     { resets the "I've been registered with wpo" flags for all defs in the
 | ||
|       above lists }
 | ||
|     procedure resetdefs;
 | ||
|   end;
 | ||
| 
 | ||
|   { ************************************************************************* }
 | ||
|   { **** Total information created for use during subsequent compilation **** }
 | ||
|   { ************************************************************************* }
 | ||
| 
 | ||
|   { class to create a file with wpo information }
 | ||
| 
 | ||
|   { tavailablewpofilewriter }
 | ||
| 
 | ||
|   twpofilewriter = class(tobject,twposectionwriterintf)
 | ||
|    private
 | ||
|     { array of class *instances* that wish to be written out to the
 | ||
|       whole program optimization feedback file
 | ||
|     }
 | ||
|     fsectioncontents: tfpobjectlist;
 | ||
| 
 | ||
|     ffilename: tcmdstr;
 | ||
|     foutputfile: text;
 | ||
| 
 | ||
|    public
 | ||
|     constructor create(const fn: tcmdstr);
 | ||
|     destructor destroy; override;
 | ||
| 
 | ||
|     procedure writefile;
 | ||
| 
 | ||
|     { starts a new section with name "name" }
 | ||
|     procedure startsection(const name: string);
 | ||
|     { writes s to the wpo file }
 | ||
|     procedure sectionputline(const s: string);
 | ||
| 
 | ||
|     { register a component instance that needs to be written
 | ||
|       to the wpo feedback file
 | ||
|     }
 | ||
|     procedure registerwpocomponent(component: twpocomponentbase);
 | ||
|   end;
 | ||
| 
 | ||
|   { ************************************************************************* }
 | ||
|   { ************ Information for use during current compilation ************* }
 | ||
|   { ************************************************************************* }
 | ||
| 
 | ||
|   { class to read a file with wpo information }
 | ||
|   twpofilereader = class(tobject,twposectionreaderintf)
 | ||
|    private
 | ||
|     ffilename: tcmdstr;
 | ||
|     flinenr: longint;
 | ||
|     finputfile: text;
 | ||
|     fcurline: string;
 | ||
|     fusecurline: boolean;
 | ||
| 
 | ||
|     { destination for the read information }
 | ||
|     fdest: twpoinfomanagerbase;
 | ||
| 
 | ||
|     function getnextnoncommentline(out s: string): boolean;
 | ||
|    public
 | ||
| 
 | ||
|      constructor create(const fn: tcmdstr; dest: twpoinfomanagerbase);
 | ||
|      destructor destroy; override;
 | ||
| 
 | ||
|      { processes the wpo info in the file }
 | ||
|      procedure processfile;
 | ||
| 
 | ||
|      { returns next line of the current section in s, and false if no more
 | ||
|        lines in the current section
 | ||
|      }
 | ||
|      function sectiongetnextline(out s: string): boolean;
 | ||
|   end;
 | ||
| 
 | ||
| 
 | ||
|   { ************************************************************************* }
 | ||
|   { ******* Specific kinds of whole program optimization components ********* }
 | ||
|   { ************************************************************************* }
 | ||
| 
 | ||
|   { method devirtualisation }
 | ||
|   twpodevirtualisationhandler = class(twpocomponentbase)
 | ||
|     { checks whether procdef (a procdef for a virtual method) can be replaced with
 | ||
|       a static call when it's called as objdef.procdef, and if so returns the
 | ||
|       mangled name in staticname.
 | ||
|     }
 | ||
|     function staticnameforcallingvirtualmethod(objdef, procdef: tdef; out staticname: string): boolean; virtual; abstract;
 | ||
|     { checks whether procdef (a procdef for a virtual method) can be replaced with
 | ||
|       a different procname in the vmt of objdef, and if so returns the new
 | ||
|       mangledname in staticname
 | ||
|     }
 | ||
|     function staticnameforvmtentry(objdef, procdef: tdef; out staticname: string): boolean; virtual; abstract;
 | ||
|   end;
 | ||
| 
 | ||
|   twpodeadcodehandler = class(twpocomponentbase)
 | ||
|     { checks whether a mangledname was removed as dead code from the final
 | ||
|       binary (WARNING: must *not* be called for functions marked as inline,
 | ||
|       since if all call sites are inlined, it won't appear in the final
 | ||
|       binary but nevertheless is still necessary!)
 | ||
|     }
 | ||
|     function symbolinfinalbinary(const s: shortstring): boolean; virtual; abstract;
 | ||
|   end;
 | ||
| 
 | ||
| 
 | ||
|   { ************************************************************************* }
 | ||
|   { ************ Collection of all instances of wpo components ************** }
 | ||
|   { ************************************************************************* }
 | ||
| 
 | ||
|   { class doing all the bookkeeping for everything  }
 | ||
| 
 | ||
|   twpoinfomanagerbase = class
 | ||
|    private
 | ||
|     { array of classrefs of handler classes for the various kinds of whole
 | ||
|       program optimizations that we support
 | ||
|     }
 | ||
|     fwpocomponents: tfphashlist;
 | ||
| 
 | ||
|     freader: twpofilereader;
 | ||
|     fwriter: twpofilewriter;
 | ||
|    public
 | ||
|     { instances of the various optimizers/information collectors (for
 | ||
|       information used during this compilation)
 | ||
|     }
 | ||
|     wpoinfouse: array[twpotype] of twpocomponentbase;
 | ||
| 
 | ||
|     { register a whole program optimization class type }
 | ||
|     procedure registerwpocomponentclass(wpocomponent: twpocomponentbaseclass);
 | ||
| 
 | ||
|     { get the program optimization class type that can parse the contents
 | ||
|       of the section with name "secname" in the wpo feedback file
 | ||
|     }
 | ||
|     function gethandlerforsection(const secname: string): twpocomponentbaseclass;
 | ||
| 
 | ||
|     { tell all instantiated wpo component classes to collect the information
 | ||
|       from the global compiler state that they need (done at the very end of
 | ||
|       the compilation process)
 | ||
|     }
 | ||
|     procedure extractwpoinfofromprogram;
 | ||
| 
 | ||
|     { set the name of the feedback file from which all whole-program information
 | ||
|       to be used during the current compilation will be read
 | ||
|     }
 | ||
|     procedure setwpoinputfile(const fn: tcmdstr);
 | ||
| 
 | ||
|     { set the name of the feedback file to which all whole-program information
 | ||
|       collected during the current compilation will be written
 | ||
|     }
 | ||
|     procedure setwpooutputfile(const fn: tcmdstr);
 | ||
| 
 | ||
|     { check whether the specified wpo options (-FW/-Fw/-OW/-Ow) are complete
 | ||
|       and sensical, and parse the wpo feedback file specified with
 | ||
|       setwpoinputfile
 | ||
|     }
 | ||
|     procedure parseandcheckwpoinfo;
 | ||
| 
 | ||
|     { routines accessing the optimizer information }
 | ||
|     { 1) devirtualization at the symbol name level }
 | ||
|     function can_be_devirtualized(objdef, procdef: tdef; out name: shortstring): boolean; virtual; abstract;
 | ||
|     { 2) optimal replacement method name in vmt }
 | ||
|     function optimized_name_for_vmt(objdef, procdef: tdef; out name: shortstring): boolean; virtual; abstract;
 | ||
|     { 3) does a symbol appear in the final binary (i.e., not removed by dead code stripping/smart linking).
 | ||
|         WARNING: do *not* call for inline functions/procedures/methods/...
 | ||
|     }
 | ||
|     function symbol_live(const name: shortstring): boolean; virtual; abstract;
 | ||
| 
 | ||
|     constructor create; reintroduce;
 | ||
|     destructor destroy; override;
 | ||
|   end;
 | ||
| 
 | ||
| 
 | ||
|   var
 | ||
|     wpoinfomanager: twpoinfomanagerbase;
 | ||
| 
 | ||
| implementation
 | ||
| 
 | ||
|   uses
 | ||
|     globals,
 | ||
|     cutils,
 | ||
|     sysutils,
 | ||
|     symdef,
 | ||
|     verbose;
 | ||
| 
 | ||
| 
 | ||
|   { tcreatedwpoinfobase }
 | ||
| 
 | ||
|   constructor tunitwpoinfobase.create;
 | ||
|     begin
 | ||
|       fcreatedobjtypes:=tfpobjectlist.create(false);
 | ||
|       fcreatedclassrefobjtypes:=tfpobjectlist.create(false);
 | ||
|       fmaybecreatedbyclassrefdeftypes:=tfpobjectlist.create(false);
 | ||
|       fcalledvmtentries:=tfphashlist.create;
 | ||
|     end;
 | ||
| 
 | ||
| 
 | ||
|   destructor tunitwpoinfobase.destroy;
 | ||
|     var
 | ||
|       i: longint;
 | ||
|     begin
 | ||
|       { don't call resetdefs here, because the defs may have been freed
 | ||
|         already }
 | ||
|       fcreatedobjtypes.free;
 | ||
|       fcreatedobjtypes:=nil;
 | ||
|       fcreatedclassrefobjtypes.free;
 | ||
|       fcreatedclassrefobjtypes:=nil;
 | ||
|       fmaybecreatedbyclassrefdeftypes.free;
 | ||
|       fmaybecreatedbyclassrefdeftypes:=nil;
 | ||
| 
 | ||
|       { may not be assigned in case the info was loaded from a ppu and we
 | ||
|         are not generating a wpo feedback file (see tunitwpoinfo.ppuload)
 | ||
|       }
 | ||
|       if assigned(fcalledvmtentries) then
 | ||
|         begin
 | ||
|           for i:=0 to fcalledvmtentries.count-1 do
 | ||
|             tcalledvmtentries(fcalledvmtentries[i]).free;
 | ||
|           fcalledvmtentries.free;
 | ||
|           fcalledvmtentries:=nil;
 | ||
|         end;
 | ||
| 
 | ||
|       inherited destroy;
 | ||
|     end;
 | ||
|     
 | ||
|     
 | ||
|   procedure tunitwpoinfobase.resetdefs;
 | ||
|     var
 | ||
|       i: ptrint;
 | ||
|     begin
 | ||
|       if assigned(fcreatedobjtypes) then
 | ||
|         for i:=0 to fcreatedobjtypes.count-1 do
 | ||
|           tobjectdef(fcreatedobjtypes[i]).created_in_current_module:=false;
 | ||
|       if assigned(fcreatedclassrefobjtypes) then
 | ||
|         for i:=0 to fcreatedclassrefobjtypes.count-1 do
 | ||
|           tobjectdef(fcreatedclassrefobjtypes[i]).classref_created_in_current_module:=false;
 | ||
|       if assigned(fmaybecreatedbyclassrefdeftypes) then
 | ||
|         for i:=0 to fmaybecreatedbyclassrefdeftypes.count-1 do
 | ||
|           tobjectdef(fmaybecreatedbyclassrefdeftypes[i]).maybe_created_in_current_module:=false;
 | ||
|     end;
 | ||
| 
 | ||
| 
 | ||
|   procedure tunitwpoinfobase.addcreatedobjtype(def: tdef);
 | ||
|     begin
 | ||
|       fcreatedobjtypes.add(def);
 | ||
|     end;
 | ||
| 
 | ||
| 
 | ||
|   procedure tunitwpoinfobase.addcreatedobjtypeforclassref(def: tdef);
 | ||
|     begin
 | ||
|       fcreatedclassrefobjtypes.add(def);
 | ||
|     end;
 | ||
| 
 | ||
| 
 | ||
|   procedure tunitwpoinfobase.addmaybecreatedbyclassref(def: tdef);
 | ||
|     begin
 | ||
|       fmaybecreatedbyclassrefdeftypes.add(def);
 | ||
|     end;
 | ||
| 
 | ||
| 
 | ||
|   procedure tunitwpoinfobase.addcalledvmtentry(def: tdef; index: longint);
 | ||
|     var
 | ||
|       entries: tcalledvmtentries;
 | ||
|       key: shortstring;
 | ||
|     begin
 | ||
|       key:=tobjectdef(def).vmt_mangledname;
 | ||
|       entries:=tcalledvmtentries(fcalledvmtentries.find(key));
 | ||
|       if not assigned(entries) then
 | ||
|         begin
 | ||
|           entries:=tcalledvmtentries.create(def,tobjectdef(def).vmtentries.count);
 | ||
|           fcalledvmtentries.add(key,entries);
 | ||
|         end;
 | ||
|       entries.calledentries.include(index);
 | ||
|     end;
 | ||
| 
 | ||
| 
 | ||
|   { twpofilereader }
 | ||
| 
 | ||
|   function twpofilereader.getnextnoncommentline(out s: string):
 | ||
|     boolean;
 | ||
|     begin
 | ||
|       if (fusecurline) then
 | ||
|         begin
 | ||
|           s:=fcurline;
 | ||
|           fusecurline:=false;
 | ||
|           result:=true;
 | ||
|           exit;
 | ||
|         end;
 | ||
|       repeat
 | ||
|         readln(finputfile,s);
 | ||
|         if (s='') and
 | ||
|            eof(finputfile) then
 | ||
|           begin
 | ||
|             result:=false;
 | ||
|             exit;
 | ||
|           end;
 | ||
|         inc(flinenr);
 | ||
|       until (s='') or
 | ||
|             (s[1]<>'#');
 | ||
|       result:=true;
 | ||
|     end;
 | ||
| 
 | ||
|   constructor twpofilereader.create(const fn: tcmdstr; dest: twpoinfomanagerbase);
 | ||
|     begin
 | ||
|       if not FileExists(fn) or
 | ||
|          { FileExists also returns true for directories }
 | ||
|          DirectoryExists(fn) then
 | ||
|         begin
 | ||
|           cgmessage1(wpo_cant_find_file,fn);
 | ||
|           exit;
 | ||
|         end;
 | ||
|       assign(finputfile,fn);
 | ||
|       ffilename:=fn;
 | ||
| 
 | ||
|       fdest:=dest;
 | ||
|     end;
 | ||
| 
 | ||
|   destructor twpofilereader.destroy;
 | ||
|     begin
 | ||
|       inherited destroy;
 | ||
|     end;
 | ||
| 
 | ||
|   procedure twpofilereader.processfile;
 | ||
|     var
 | ||
|       sectionhandler: twpocomponentbaseclass;
 | ||
|       i: longint;
 | ||
|       wpotype: twpotype;
 | ||
|       s,
 | ||
|       sectionname: string;
 | ||
|     begin
 | ||
|       cgmessage1(wpo_begin_processing,ffilename);
 | ||
|       reset(finputfile);
 | ||
|       flinenr:=0;
 | ||
|       while getnextnoncommentline(s) do
 | ||
|         begin
 | ||
|           if (s='') then
 | ||
|             continue;
 | ||
|           { format: "% sectionname" }
 | ||
|           if (s[1]<>'%') then
 | ||
|             begin
 | ||
|               cgmessage2(wpo_expected_section,tostr(flinenr),s);
 | ||
|               break;
 | ||
|             end;
 | ||
|           for i:=2 to length(s) do
 | ||
|             if (s[i]<>' ') then
 | ||
|               break;
 | ||
|           sectionname:=copy(s,i,255);
 | ||
| 
 | ||
|           { find handler for section and process }
 | ||
|           sectionhandler:=fdest.gethandlerforsection(sectionname);
 | ||
|           if assigned(sectionhandler) then
 | ||
|             begin
 | ||
|               wpotype:=sectionhandler.getwpotype;
 | ||
|               cgmessage2(wpo_found_section,sectionname,wpo2str[wpotype]);
 | ||
|               { do we need this information? }
 | ||
|               if ((sectionhandler.performswpoforswitches * init_settings.dowpoptimizerswitches) <> []) then
 | ||
|                 begin
 | ||
|                   { did some other section already generate this type of information? }
 | ||
|                   if assigned(fdest.wpoinfouse[wpotype]) then
 | ||
|                     begin
 | ||
|                       cgmessage2(wpo_duplicate_wpotype,wpo2str[wpotype],sectionname);
 | ||
|                       fdest.wpoinfouse[wpotype].free;
 | ||
|                     end;
 | ||
|                   { process the section }
 | ||
|                   fdest.wpoinfouse[wpotype]:=sectionhandler.create;
 | ||
|                   twpocomponentbase(fdest.wpoinfouse[wpotype]).loadfromwpofilesection(self);
 | ||
|                 end
 | ||
|               else
 | ||
|                 begin
 | ||
|                   cgmessage1(wpo_skipping_unnecessary_section,sectionname);
 | ||
|                   { skip the current section }
 | ||
|                   while sectiongetnextline(s) do
 | ||
|                     ;
 | ||
|                 end;
 | ||
|             end
 | ||
|           else
 | ||
|             begin
 | ||
|               cgmessage1(wpo_no_section_handler,sectionname);
 | ||
|               { skip the current section }
 | ||
|               while sectiongetnextline(s) do
 | ||
|                 ;
 | ||
|             end;
 | ||
|         end;
 | ||
|       close(finputfile);
 | ||
|       cgmessage1(wpo_end_processing,ffilename);
 | ||
|     end;
 | ||
| 
 | ||
|   function twpofilereader.sectiongetnextline(out s: string): boolean;
 | ||
|     begin
 | ||
|       result:=getnextnoncommentline(s);
 | ||
|       if not result then
 | ||
|         exit;
 | ||
|       { start of new section? }
 | ||
|       if (s<>'') and
 | ||
|          (s[1]='%') then
 | ||
|         begin
 | ||
|           { keep read line for next call to getnextnoncommentline() }
 | ||
|           fcurline:=s;
 | ||
|           fusecurline:=true;
 | ||
|           result:=false;
 | ||
|         end;
 | ||
|     end;
 | ||
| 
 | ||
| 
 | ||
|   { twpocomponentbase }
 | ||
| 
 | ||
|   constructor twpocomponentbase.create;
 | ||
|     begin
 | ||
|       { do nothing }
 | ||
|     end;
 | ||
| 
 | ||
| 
 | ||
|   class procedure twpocomponentbase.checkoptions;
 | ||
|     begin
 | ||
|       { do nothing }
 | ||
|     end;
 | ||
| 
 | ||
|   { twpofilewriter }
 | ||
| 
 | ||
|   constructor twpofilewriter.create(const fn: tcmdstr);
 | ||
|     begin
 | ||
|       assign(foutputfile,fn);
 | ||
|       ffilename:=fn;
 | ||
|       fsectioncontents:=tfpobjectlist.create(true);
 | ||
|     end;
 | ||
| 
 | ||
|   destructor twpofilewriter.destroy;
 | ||
|     begin
 | ||
|       fsectioncontents.free;
 | ||
|       inherited destroy;
 | ||
|     end;
 | ||
| 
 | ||
|   procedure twpofilewriter.writefile;
 | ||
|     var
 | ||
|       i: longint;
 | ||
|     begin
 | ||
| {$i-}
 | ||
|       rewrite(foutputfile);
 | ||
| {$i+}
 | ||
|       if (ioresult <> 0) then
 | ||
|         begin
 | ||
|           cgmessage1(wpo_cant_create_feedback_file,ffilename);
 | ||
|           exit;
 | ||
|         end;
 | ||
|       for i:=0 to fsectioncontents.count-1 do
 | ||
|         twpocomponentbase(fsectioncontents[i]).storewpofilesection(self);
 | ||
|       close(foutputfile);
 | ||
|     end;
 | ||
| 
 | ||
|   procedure twpofilewriter.startsection(const name: string);
 | ||
|     begin
 | ||
|       writeln(foutputfile,'% ',name);
 | ||
|     end;
 | ||
| 
 | ||
|   procedure twpofilewriter.sectionputline(const s: string);
 | ||
|     begin
 | ||
|       writeln(foutputfile,s);
 | ||
|     end;
 | ||
| 
 | ||
|   procedure twpofilewriter.registerwpocomponent(
 | ||
|     component: twpocomponentbase);
 | ||
|     begin
 | ||
|       fsectioncontents.add(component);
 | ||
|     end;
 | ||
| 
 | ||
| { twpoinfomanagerbase }
 | ||
| 
 | ||
|   procedure twpoinfomanagerbase.registerwpocomponentclass(wpocomponent: twpocomponentbaseclass);
 | ||
|     begin
 | ||
|       fwpocomponents.add(wpocomponent.sectionname,wpocomponent);
 | ||
|     end;
 | ||
| 
 | ||
| 
 | ||
|   function twpoinfomanagerbase.gethandlerforsection(const secname: string
 | ||
|       ): twpocomponentbaseclass;
 | ||
|     begin
 | ||
|       result:=twpocomponentbaseclass(fwpocomponents.find(secname));
 | ||
|     end;
 | ||
| 
 | ||
|   procedure twpoinfomanagerbase.setwpoinputfile(const fn: tcmdstr);
 | ||
|     begin
 | ||
|       freader:=twpofilereader.create(fn,self);
 | ||
|     end;
 | ||
| 
 | ||
|   procedure twpoinfomanagerbase.setwpooutputfile(const fn: tcmdstr);
 | ||
|     begin
 | ||
|       fwriter:=twpofilewriter.create(fn);
 | ||
|     end;
 | ||
| 
 | ||
|   procedure twpoinfomanagerbase.parseandcheckwpoinfo;
 | ||
|     var
 | ||
|       i: longint;
 | ||
|     begin
 | ||
|       { error if we don't have to optimize yet have an input feedback file }
 | ||
|       if (init_settings.dowpoptimizerswitches=[]) and
 | ||
|          assigned(freader) then
 | ||
|         begin
 | ||
|           cgmessage(wpo_input_without_info_use);
 | ||
|           exit;
 | ||
|         end;
 | ||
| 
 | ||
|       { error if we have to optimize yet don't have an input feedback file }
 | ||
|       if (init_settings.dowpoptimizerswitches<>[]) and
 | ||
|          not assigned(freader) then
 | ||
|         begin
 | ||
|           cgmessage(wpo_no_input_specified);
 | ||
|           exit;
 | ||
|         end;
 | ||
| 
 | ||
|       { if we have to generate wpo information, check that a file has been
 | ||
|         specified and that we have something to write to it
 | ||
|       }
 | ||
|       if (init_settings.genwpoptimizerswitches<>[]) and
 | ||
|          not assigned(fwriter) then
 | ||
|         begin
 | ||
|           cgmessage(wpo_no_output_specified);
 | ||
|           exit;
 | ||
|         end;
 | ||
| 
 | ||
|       if (init_settings.genwpoptimizerswitches=[]) and
 | ||
|          assigned(fwriter) then
 | ||
|         begin
 | ||
|           cgmessage(wpo_output_without_info_gen);
 | ||
|           exit;
 | ||
|         end;
 | ||
| 
 | ||
|       { now read the input feedback file }
 | ||
|       if assigned(freader) then
 | ||
|         begin
 | ||
|           freader.processfile;
 | ||
|           freader.free;
 | ||
|           freader:=nil;
 | ||
|         end;
 | ||
| 
 | ||
|       { and for each specified optimization check whether the input feedback
 | ||
|         file contained the necessary information
 | ||
|       }
 | ||
|       if (([cs_wpo_devirtualize_calls,cs_wpo_optimize_vmts] * init_settings.dowpoptimizerswitches) <> []) and
 | ||
|          not assigned(wpoinfouse[wpo_devirtualization_context_insensitive]) then
 | ||
|         begin
 | ||
|           cgmessage1(wpo_not_enough_info,wpo2str[wpo_devirtualization_context_insensitive]);
 | ||
|           exit;
 | ||
|         end;
 | ||
| 
 | ||
|       if (cs_wpo_symbol_liveness in init_settings.dowpoptimizerswitches) and
 | ||
|          not assigned(wpoinfouse[wpo_live_symbol_information]) then
 | ||
|         begin
 | ||
|           cgmessage1(wpo_not_enough_info,wpo2str[wpo_live_symbol_information]);
 | ||
|           exit;
 | ||
|         end;
 | ||
| 
 | ||
|       { perform pre-checking to ensure there are no known incompatibilities between
 | ||
|         the selected optimizations and other switches
 | ||
|       }
 | ||
|       for i:=0 to fwpocomponents.count-1 do
 | ||
|         if (twpocomponentbaseclass(fwpocomponents[i]).generatesinfoforwposwitches*init_settings.genwpoptimizerswitches)<>[] then
 | ||
|           twpocomponentbaseclass(fwpocomponents[i]).checkoptions
 | ||
|     end;
 | ||
| 
 | ||
|   procedure twpoinfomanagerbase.extractwpoinfofromprogram;
 | ||
|     var
 | ||
|       i: longint;
 | ||
|       info: twpocomponentbase;
 | ||
|     begin
 | ||
|       { if don't have to write anything, fwriter has not been created }
 | ||
|       if not assigned(fwriter) then
 | ||
|         exit;
 | ||
| 
 | ||
|       { let all wpo components gather the necessary info from the compiler state }
 | ||
|       for i:=0 to fwpocomponents.count-1 do
 | ||
|         if (twpocomponentbaseclass(fwpocomponents[i]).generatesinfoforwposwitches*current_settings.genwpoptimizerswitches)<>[] then
 | ||
|           begin
 | ||
|             info:=twpocomponentbaseclass(fwpocomponents[i]).create;
 | ||
|             info.constructfromcompilerstate;
 | ||
|             fwriter.registerwpocomponent(info);
 | ||
|           end;
 | ||
|       { and write their info to disk }
 | ||
|       fwriter.writefile;
 | ||
|       fwriter.free;
 | ||
|       fwriter:=nil;
 | ||
|     end;
 | ||
| 
 | ||
|   constructor twpoinfomanagerbase.create;
 | ||
|     begin
 | ||
|       inherited create;
 | ||
|       fwpocomponents:=tfphashlist.create;
 | ||
|     end;
 | ||
| 
 | ||
|   destructor twpoinfomanagerbase.destroy;
 | ||
|     var
 | ||
|       i: twpotype;
 | ||
|     begin
 | ||
|       freader.free;
 | ||
|       freader:=nil;
 | ||
|       fwriter.free;
 | ||
|       fwriter:=nil;
 | ||
|       fwpocomponents.free;
 | ||
|       fwpocomponents:=nil;
 | ||
|       for i:=low(wpoinfouse) to high(wpoinfouse) do
 | ||
|         if assigned(wpoinfouse[i]) then
 | ||
|           wpoinfouse[i].free;
 | ||
|       inherited destroy;
 | ||
|     end;
 | ||
| 
 | ||
|   { tcalledvmtentries }
 | ||
| 
 | ||
|   constructor tcalledvmtentries.create(_objdef: tdef; nentries: longint);
 | ||
|     begin
 | ||
|       objdef:=_objdef;
 | ||
|       calledentries:=tbitset.create(nentries);
 | ||
|     end;
 | ||
| 
 | ||
| 
 | ||
|   constructor tcalledvmtentries.ppuload(ppufile: tcompilerppufile);
 | ||
|     var
 | ||
|       len: longint;
 | ||
|     begin
 | ||
|       ppufile.getderef(fobjdefderef);
 | ||
|       len:=ppufile.getlongint;
 | ||
|       calledentries:=tbitset.create_bytesize(len);
 | ||
|       if (len <> calledentries.datasize) then
 | ||
|         internalerror(2009060301);
 | ||
|       ppufile.readdata(calledentries.data^,len);
 | ||
|     end;
 | ||
| 
 | ||
| 
 | ||
|   destructor tcalledvmtentries.destroy;
 | ||
|     begin
 | ||
|       fcalledentries.free;
 | ||
|       inherited destroy;
 | ||
|     end;
 | ||
| 
 | ||
| 
 | ||
|   procedure tcalledvmtentries.ppuwrite(ppufile: tcompilerppufile);
 | ||
|     begin
 | ||
|       ppufile.putderef(objdefderef);
 | ||
|       ppufile.putlongint(calledentries.datasize);
 | ||
|       ppufile.putdata(calledentries.data^,calledentries.datasize);
 | ||
|     end;
 | ||
| 
 | ||
| 
 | ||
|   procedure tcalledvmtentries.buildderef;
 | ||
|     begin
 | ||
|       objdefderef.build(objdef);
 | ||
|     end;
 | ||
| 
 | ||
| 
 | ||
|   procedure tcalledvmtentries.buildderefimpl;
 | ||
|     begin
 | ||
|     end;
 | ||
| 
 | ||
| 
 | ||
|   procedure tcalledvmtentries.deref;
 | ||
|     begin
 | ||
|       objdef:=tdef(objdefderef.resolve);
 | ||
|     end;
 | ||
| 
 | ||
| 
 | ||
|   procedure tcalledvmtentries.derefimpl;
 | ||
|     begin
 | ||
|     end;
 | ||
| 
 | ||
| end.
 |