mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 11:39:40 +01:00 
			
		
		
		
	implicit pointer types into the nestedfpstruct, so that the original
    parameter is properly changed when updated from inside nested routines
git-svn-id: branches/jvmbackend@19645 -
		
	
			
		
			
				
	
	
		
			238 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			238 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
    Copyright (c) 2011 by Jonas Maebe
 | 
						|
 | 
						|
    Support for load nodes on targets that have to group all local variables
 | 
						|
    and parameters accessed by nested routines into structs (and then pass the
 | 
						|
    address of these structs to nested routines rather than the frame pointer,
 | 
						|
    and access the local variables as fields thereof)
 | 
						|
 | 
						|
    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 ncgnstld;
 | 
						|
 | 
						|
{$i fpcdefs.inc}
 | 
						|
 | 
						|
interface
 | 
						|
 | 
						|
    uses
 | 
						|
       node,
 | 
						|
       symtype,
 | 
						|
       nld,
 | 
						|
       ncgld;
 | 
						|
 | 
						|
    type
 | 
						|
       tcgnestloadnode = class(tcgloadnode)
 | 
						|
        protected
 | 
						|
         nestsym: tsym;
 | 
						|
         nestsymderef: tderef;
 | 
						|
         procedure generate_nested_access(vs: tsym);override;
 | 
						|
         function  keep_param_address_in_nested_struct: boolean; virtual;
 | 
						|
        public
 | 
						|
         function  pass_typecheck: tnode; override;
 | 
						|
         function  pass_1:tnode;override;
 | 
						|
         function  dogetcopy: tnode; override;
 | 
						|
         function  docompare(p: tnode): boolean; override;
 | 
						|
         constructor ppuload(t: tnodetype; ppufile: tcompilerppufile); override;
 | 
						|
         procedure ppuwrite(ppufile: tcompilerppufile); override;
 | 
						|
         procedure buildderefimpl; override;
 | 
						|
         procedure derefimpl; override;
 | 
						|
       end;
 | 
						|
 | 
						|
implementation
 | 
						|
 | 
						|
    uses
 | 
						|
      cutils,verbose,globtype,globals,systems,constexp,
 | 
						|
      symnot,
 | 
						|
      defutil,defcmp,
 | 
						|
      htypechk,pass_1,procinfo,paramgr,
 | 
						|
      cpuinfo,
 | 
						|
      symconst,symbase,symsym,symdef,symtable,symcreat,
 | 
						|
      ncon,ninl,ncnv,nmem,ncal,nutils,nbas,
 | 
						|
      pass_2,cgbase
 | 
						|
      ;
 | 
						|
 | 
						|
{*****************************************************************************
 | 
						|
                          TCGNESTLOADNODE
 | 
						|
*****************************************************************************}
 | 
						|
 | 
						|
    procedure tcgnestloadnode.generate_nested_access(vs: tsym);
 | 
						|
      begin
 | 
						|
        { left has been transformed into a string of accesses that result in
 | 
						|
          the location of the original variable's copy in the appropriate
 | 
						|
          parentfpstruct (via tcgnestloadparentfpnode.pass_1). In case it is a
 | 
						|
          var/out/constref parameter, that "copy" will have been a copy of the
 | 
						|
          address so the normal handling of such parameters in ncgld is ok) }
 | 
						|
        secondpass(left);
 | 
						|
        location:=left.location;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function tcgnestloadnode.keep_param_address_in_nested_struct: boolean;
 | 
						|
      begin
 | 
						|
        result:=is_addr_param_load;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function tcgnestloadnode.pass_typecheck: tnode;
 | 
						|
      var
 | 
						|
        nestedvars: tsym;
 | 
						|
      begin
 | 
						|
        result:=inherited pass_typecheck;
 | 
						|
        if assigned(result) then
 | 
						|
          exit;
 | 
						|
        case symtableentry.typ of
 | 
						|
          paravarsym,
 | 
						|
          localvarsym :
 | 
						|
            begin
 | 
						|
              { Nested variable? Then we have to move it to a structure that
 | 
						|
                can be passed by reference to nested routines }
 | 
						|
              if assigned(current_procinfo) and
 | 
						|
                 (symtable.symtabletype in [localsymtable,parasymtable]) and
 | 
						|
                 ((symtable.symtablelevel<>current_procinfo.procdef.parast.symtablelevel) or
 | 
						|
                  { also redirect loads of locals/paras that have been moved to
 | 
						|
                     the parentfpstruct inside the routine in which they were
 | 
						|
                     originally declared, except in the initialisation code for
 | 
						|
                     the parentfpstruct (nf_internal flag) }
 | 
						|
                  (tabstractnormalvarsym(symtableentry).inparentfpstruct and
 | 
						|
                   not(nf_internal in flags))) then
 | 
						|
                begin
 | 
						|
                  { get struct holding all locals accessed by nested routines }
 | 
						|
                  nestedvars:=tprocdef(symtable.defowner).parentfpstruct;
 | 
						|
                  { don't add the parentfpstruct to itself! }
 | 
						|
                  if nestedvars=symtableentry then
 | 
						|
                    exit;
 | 
						|
                  if not assigned(nestedvars) then
 | 
						|
                    begin
 | 
						|
                      { create this struct }
 | 
						|
                      build_parentfpstruct(tprocdef(symtable.defowner));
 | 
						|
                      nestedvars:=tprocdef(symtable.defowner).parentfpstruct;
 | 
						|
                    end;
 | 
						|
                  {  store result for use in pass_1 }
 | 
						|
                  nestsym:=maybe_add_sym_to_parentfpstruct(tprocdef(symtableentry.owner.defowner),symtableentry,resultdef,keep_param_address_in_nested_struct);
 | 
						|
                  { left normally holds the parentfp node. If it's not assigned,
 | 
						|
                    this is an access to a local variable/para from the routine
 | 
						|
                    in which it was actually declared -> redirect to its
 | 
						|
                    equivalent in the parentfp struct }
 | 
						|
                  if not assigned(left) then
 | 
						|
                    begin
 | 
						|
                      left:=caddrnode.create_internal(cloadnode.create(tprocdef(symtableentry.owner.defowner).parentfpstruct,tprocdef(symtableentry.owner.defowner).parentfpstruct.owner));
 | 
						|
                      include(left.flags,nf_typedaddr);
 | 
						|
                    end;
 | 
						|
                  typecheckpass(left);
 | 
						|
                end;
 | 
						|
            end;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function tcgnestloadnode.pass_1:tnode;
 | 
						|
      var
 | 
						|
        thissym,
 | 
						|
        nestedvars: tsym;
 | 
						|
        nestedvarsdef: tdef;
 | 
						|
      begin
 | 
						|
        result:=inherited;
 | 
						|
        if assigned(result) then
 | 
						|
          exit;
 | 
						|
        case symtableentry.typ of
 | 
						|
          paravarsym,
 | 
						|
          localvarsym :
 | 
						|
            begin
 | 
						|
              { Nested variable? Then we have to move it to a structure that
 | 
						|
                can be passed by reference to nested routines }
 | 
						|
              if assigned(current_procinfo) and
 | 
						|
                 (symtable.symtabletype in [localsymtable,parasymtable]) and
 | 
						|
                 ((symtable.symtablelevel<>current_procinfo.procdef.parast.symtablelevel) or
 | 
						|
                  (tabstractnormalvarsym(symtableentry).inparentfpstruct and
 | 
						|
                   not(nf_internal in flags))) then
 | 
						|
                begin
 | 
						|
                  { get struct holding all locals accessed by nested routines }
 | 
						|
                  nestedvars:=tprocdef(symtable.defowner).parentfpstruct;
 | 
						|
                  if not assigned(nestedvars) then
 | 
						|
                    begin
 | 
						|
                      { create this struct }
 | 
						|
                      build_parentfpstruct(tprocdef(symtable.defowner));
 | 
						|
                      nestedvars:=tprocdef(symtable.defowner).parentfpstruct;
 | 
						|
                    end;
 | 
						|
                  nestedvarsdef:=tlocalvarsym(nestedvars).vardef;
 | 
						|
                  if nestedvars<>symtableentry then
 | 
						|
                    thissym:=nestsym
 | 
						|
                  else
 | 
						|
                    thissym:=find_sym_in_parentfpstruct(tprocdef(symtableentry.owner.defowner),symtableentry);
 | 
						|
                  if not assigned(thissym) then
 | 
						|
                    internalerror(2011060406);
 | 
						|
                  { firstpass the parentfpnode. This will transform it into
 | 
						|
                    a load of the appropriate parentfpstruct }
 | 
						|
                  if not assigned(left) then
 | 
						|
                    internalerror(2011060104);
 | 
						|
                  firstpass(left);
 | 
						|
                  { subscript it to get the variable }
 | 
						|
                  left:=csubscriptnode.create(thissym,cderefnode.create(left));
 | 
						|
                  firstpass(left);
 | 
						|
                 end;
 | 
						|
            end;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function tcgnestloadnode.dogetcopy: tnode;
 | 
						|
      begin
 | 
						|
        result:=inherited dogetcopy;
 | 
						|
        tcgnestloadnode(result).nestsym:=nestsym;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function tcgnestloadnode.docompare(p: tnode): boolean;
 | 
						|
      begin
 | 
						|
        result:=
 | 
						|
          inherited docompare(p) and
 | 
						|
          (tcgnestloadnode(p).nestsym=nestsym);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor tcgnestloadnode.ppuload(t: tnodetype; ppufile: tcompilerppufile);
 | 
						|
      begin
 | 
						|
        inherited ppuload(t, ppufile);
 | 
						|
        ppufile.getderef(nestsymderef);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure tcgnestloadnode.ppuwrite(ppufile: tcompilerppufile);
 | 
						|
      begin
 | 
						|
        inherited ppuwrite(ppufile);
 | 
						|
        ppufile.putderef(nestsymderef);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure tcgnestloadnode.buildderefimpl;
 | 
						|
      begin
 | 
						|
        inherited buildderefimpl;
 | 
						|
        nestsymderef.build(nestsym);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure tcgnestloadnode.derefimpl;
 | 
						|
      begin
 | 
						|
        inherited derefimpl;
 | 
						|
        nestsym:=tsym(nestsymderef.resolve);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
begin
 | 
						|
  cloadnode:=tcgnestloadnode;
 | 
						|
end.
 |