Browse Source

* cache and reuse procvardefs internally created to get the address of a
procdef (halves the amount of memory needed to compile the googlapi
package using a build unit, as done by fpmake)

git-svn-id: trunk@30856 -

Jonas Maebe 10 years ago
parent
commit
bd8079f896

+ 1 - 1
compiler/aasmcnst.pas

@@ -1268,7 +1268,7 @@ implementation
 
 
    procedure ttai_typedconstbuilder.emit_procdef_const(pd: tprocdef);
    procedure ttai_typedconstbuilder.emit_procdef_const(pd: tprocdef);
      begin
      begin
-       emit_tai(Tai_const.Createname(pd.mangledname,AT_FUNCTION,0),pd.getcopyas(procvardef,pc_address_only));
+       emit_tai(Tai_const.Createname(pd.mangledname,AT_FUNCTION,0),getprocaddressprocvar(pd));
      end;
      end;
 
 
 
 

+ 5 - 0
compiler/fmodule.pas

@@ -144,6 +144,7 @@ interface
         symlist       : TFPObjectList;
         symlist       : TFPObjectList;
         ptrdefs       : tPtrDefHashSet; { list of pointerdefs created in this module so we can reuse them (not saved/restored) }
         ptrdefs       : tPtrDefHashSet; { list of pointerdefs created in this module so we can reuse them (not saved/restored) }
         arraydefs     : THashSet; { list of single-element-arraydefs created in this module so we can reuse them (not saved/restored) }
         arraydefs     : THashSet; { list of single-element-arraydefs created in this module so we can reuse them (not saved/restored) }
+        procaddrdefs  : THashSet; { list of procvardefs created when getting the address of a procdef (not saved/restored) }
 {$ifdef llvm}
 {$ifdef llvm}
         llvmdefs      : THashSet; { defs added for llvm-specific reasons (not saved/restored) }
         llvmdefs      : THashSet; { defs added for llvm-specific reasons (not saved/restored) }
 {$endif llvm}
 {$endif llvm}
@@ -572,6 +573,7 @@ implementation
         symlist:=TFPObjectList.Create(false);
         symlist:=TFPObjectList.Create(false);
         ptrdefs:=cPtrDefHashSet.Create;
         ptrdefs:=cPtrDefHashSet.Create;
         arraydefs:=THashSet.Create(64,true,false);
         arraydefs:=THashSet.Create(64,true,false);
+        procaddrdefs:=THashSet.Create(64,true,false);
 {$ifdef llvm}
 {$ifdef llvm}
         llvmdefs:=THashSet.Create(64,true,false);
         llvmdefs:=THashSet.Create(64,true,false);
 {$endif llvm}
 {$endif llvm}
@@ -689,6 +691,7 @@ implementation
         symlist.free;
         symlist.free;
         ptrdefs.free;
         ptrdefs.free;
         arraydefs.free;
         arraydefs.free;
+        procaddrdefs.free;
 {$ifdef llvm}
 {$ifdef llvm}
         llvmdefs.free;
         llvmdefs.free;
 {$endif llvm}
 {$endif llvm}
@@ -756,6 +759,8 @@ implementation
         ptrdefs:=cPtrDefHashSet.Create;
         ptrdefs:=cPtrDefHashSet.Create;
         arraydefs.free;
         arraydefs.free;
         arraydefs:=THashSet.Create(64,true,false);
         arraydefs:=THashSet.Create(64,true,false);
+        procaddrdefs.free;
+        procaddrdefs:=THashSet.Create(64,true,false);
 {$ifdef llvm}
 {$ifdef llvm}
         llvmdefs.free;
         llvmdefs.free;
         llvmdefs:=THashSet.Create(64,true,false);
         llvmdefs:=THashSet.Create(64,true,false);

+ 2 - 2
compiler/llvm/hlcgllvm.pas

@@ -318,7 +318,7 @@ implementation
     begin
     begin
       if (pd.typ=procdef) or
       if (pd.typ=procdef) or
          not pd.is_addressonly then
          not pd.is_addressonly then
-        result:=pd.getcopyas(procvardef,pc_address_only)
+        result:=getprocaddressprocvar(pd)
       else
       else
         result:=pd
         result:=pd
     end;
     end;
@@ -419,7 +419,7 @@ implementation
     { if this is a complex procvar, get the non-tmethod-like equivalent }
     { if this is a complex procvar, get the non-tmethod-like equivalent }
     if (pd.typ=procvardef) and
     if (pd.typ=procvardef) and
        not pd.is_addressonly then
        not pd.is_addressonly then
-      pd:=tprocvardef(pd.getcopyas(procvardef,pc_address_only));
+      pd:=tprocvardef(getprocaddressprocvar(pd));
     { if the function returns a function pointer type or is varargs, we
     { if the function returns a function pointer type or is varargs, we
       must specify the full function signature, otherwise we can only
       must specify the full function signature, otherwise we can only
       specify the return type }
       specify the return type }

+ 2 - 2
compiler/llvm/nllvmtcon.pas

@@ -236,7 +236,7 @@ implementation
   procedure tllvmtai_typedconstbuilder.emit_tai_procvar2procdef(p: tai; pvdef: tprocvardef);
   procedure tllvmtai_typedconstbuilder.emit_tai_procvar2procdef(p: tai; pvdef: tprocvardef);
     begin
     begin
       if not pvdef.is_addressonly then
       if not pvdef.is_addressonly then
-        pvdef:=tprocvardef(pvdef.getcopyas(procvardef,pc_address_only));
+        pvdef:=getprocaddressprocvar(pvdef);
       emit_tai(p,pvdef);
       emit_tai(p,pvdef);
     end;
     end;
 
 
@@ -444,7 +444,7 @@ implementation
         the procdef }
         the procdef }
       if (fromdef.typ=procdef) and
       if (fromdef.typ=procdef) and
          (todef.typ<>procdef) then
          (todef.typ<>procdef) then
-        fromdef:=tprocdef(fromdef).getcopyas(procvardef,pc_address_only);
+        fromdef:=getprocaddressprocvar(tprocdef(fromdef));
       op:=llvmconvop(fromdef,todef);
       op:=llvmconvop(fromdef,todef);
       case op of
       case op of
         la_ptrtoint_to_x,
         la_ptrtoint_to_x,

+ 1 - 1
compiler/ncgcal.pas

@@ -820,7 +820,7 @@ implementation
            of far calls where the procvardef was defined does not matter,
            of far calls where the procvardef was defined does not matter,
            even though the procvardef constructor called by getcopyas looks at
            even though the procvardef constructor called by getcopyas looks at
            it) }
            it) }
-         codeprocdef:=tabstractprocdef(procdefinition.getcopyas(procvardef,pc_address_only));
+         codeprocdef:=getprocaddressprocvar(procdefinition);
          result:=hlcg.getaddressregister(current_asmdata.CurrAsmList,codeprocdef);
          result:=hlcg.getaddressregister(current_asmdata.CurrAsmList,codeprocdef);
          { in case we have a method pointer on a big endian target in registers,
          { in case we have a method pointer on a big endian target in registers,
            the method address is stored in registerhi (it's the first field
            the method address is stored in registerhi (it's the first field

+ 2 - 2
compiler/ncgvmt.pas

@@ -722,7 +722,7 @@ implementation
                 hs:=make_mangledname('WRPR',_class.owner,_class.objname^+'_$_'+AImplIntf.IntfDef.objname^+'_$_'+
                 hs:=make_mangledname('WRPR',_class.owner,_class.objname^+'_$_'+AImplIntf.IntfDef.objname^+'_$_'+
                                      tostr(i)+'_$_'+pd.mangledname);
                                      tostr(i)+'_$_'+pd.mangledname);
                 { create reference }
                 { create reference }
-                datatcb.emit_tai(Tai_const.Createname(hs,AT_FUNCTION,0),pd.getcopyas(procvardef,pc_address_only));
+                datatcb.emit_tai(Tai_const.Createname(hs,AT_FUNCTION,0),getprocaddressprocvar(pd));
               end;
               end;
            end
            end
         else
         else
@@ -1011,7 +1011,7 @@ implementation
              procname:='FPC_EMPTYMETHOD'
              procname:='FPC_EMPTYMETHOD'
            else if not wpoinfomanager.optimized_name_for_vmt(_class,vmtpd,procname) then
            else if not wpoinfomanager.optimized_name_for_vmt(_class,vmtpd,procname) then
              procname:=vmtpd.mangledname;
              procname:=vmtpd.mangledname;
-           tcb.emit_tai(Tai_const.Createname(procname,AT_FUNCTION,0),vmtpd.getcopyas(procvardef,pc_address_only));
+           tcb.emit_tai(Tai_const.Createname(procname,AT_FUNCTION,0),getprocaddressprocvar(vmtpd));
 {$ifdef vtentry}
 {$ifdef vtentry}
            hs:='VTENTRY'+'_'+_class.vmt_mangledname+'$$'+tostr(_class.vmtmethodoffset(i) div sizeof(pint));
            hs:='VTENTRY'+'_'+_class.vmt_mangledname+'$$'+tostr(_class.vmtmethodoffset(i) div sizeof(pint));
            current_asmdata.asmlists[al_globals].concat(tai_symbol.CreateName(hs,AT_DATA,0));
            current_asmdata.asmlists[al_globals].concat(tai_symbol.CreateName(hs,AT_DATA,0));

+ 28 - 0
compiler/symdef.pas

@@ -1128,6 +1128,8 @@ interface
       an existing one in case it exists in the current module }
       an existing one in case it exists in the current module }
     function getsingletonarraydef(def: tdef): tarraydef;
     function getsingletonarraydef(def: tdef): tarraydef;
     function getarraydef(def: tdef; elecount: asizeint): tarraydef;
     function getarraydef(def: tdef; elecount: asizeint): tarraydef;
+    { returns a procvardef that represents the address of a procdef }
+    function getprocaddressprocvar(def: tabstractprocdef): tprocvardef;
 
 
     function getansistringcodepage:tstringencoding; inline;
     function getansistringcodepage:tstringencoding; inline;
     function getansistringdef:tstringdef;
     function getansistringdef:tstringdef;
@@ -7651,4 +7653,30 @@ implementation
       end;
       end;
 
 
 
 
+    function getprocaddressprocvar(def: tabstractprocdef): tprocvardef;
+      var
+        res: PHashSetItem;
+        oldsymtablestack: tsymtablestack;
+      begin
+        if not assigned(current_module) then
+          internalerror(2011081301);
+        res:=current_module.procaddrdefs.FindOrAdd(@def,sizeof(def));
+        if not assigned(res^.Data) then
+          begin
+            { since these pointerdefs can be reused anywhere in the current
+              unit, add them to the global/staticsymtable }
+            oldsymtablestack:=symtablestack;
+            { do not simply push/pop current_module.localsymtable, because
+              that can have side-effects (e.g., it removes helpers) }
+            symtablestack:=nil;
+            res^.Data:=def.getcopyas(procvardef,pc_address_only);
+            if assigned(current_module.localsymtable) then
+              current_module.localsymtable.insertdef(tdef(res^.Data))
+            else
+              current_module.globalsymtable.insertdef(tdef(res^.Data));
+            symtablestack:=oldsymtablestack;
+          end;
+        result:=tprocvardef(res^.Data);
+      end;
+
 end.
 end.