mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 11:24:16 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			329 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			329 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
    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
 | 
						|
  globtype,cclasses,
 | 
						|
  symtype,
 | 
						|
  wpobase;
 | 
						|
 | 
						|
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: TSymStr): boolean; override;
 | 
						|
    function optimized_name_for_vmt(objdef, procdef: tdef; out name: TSymStr): boolean; override;
 | 
						|
    function symbol_live(const name: shortstring): boolean; override;
 | 
						|
  end;
 | 
						|
 | 
						|
 | 
						|
implementation
 | 
						|
 | 
						|
  uses
 | 
						|
    globals,
 | 
						|
    symdef,
 | 
						|
    verbose,
 | 
						|
    entfile;
 | 
						|
 | 
						|
  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
 | 
						|
        message(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: TSymStr): 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: TSymStr): 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.
 |