2
0
Эх сурвалжийг харах

* store vmt procdefs in the ppu files so we don't have to use a hack to
regenerate them for whole-program optimisation
* fixed crash when performing devirtualisation optimisation on programs
that do not construct any classes/objects with optimisable vmts

git-svn-id: branches/wpo@11902 -

Jonas Maebe 17 жил өмнө
parent
commit
2d5f97953d

+ 39 - 47
compiler/nobj.pas

@@ -55,9 +55,9 @@ interface
         VMTSymEntryList : TFPHashObjectList;
         VMTSymEntryList : TFPHashObjectList;
         has_constructor,
         has_constructor,
         has_virtual_method : boolean;
         has_virtual_method : boolean;
-        function is_new_vmt_entry(VMTSymEntry:TVMTSymEntry;pd:tprocdef; check_visibility: boolean):boolean;
+        function is_new_vmt_entry(VMTSymEntry:TVMTSymEntry;pd:tprocdef):boolean;
         procedure add_new_vmt_entry(VMTSymEntry:TVMTSymEntry;pd:tprocdef);
         procedure add_new_vmt_entry(VMTSymEntry:TVMTSymEntry;pd:tprocdef);
-        procedure add_vmt_entries(objdef:tobjectdef; check_visibility: boolean);
+        procedure add_vmt_entries(objdef:tobjectdef);
         function  intf_search_procdef_by_name(proc: tprocdef;const name: string): tprocdef;
         function  intf_search_procdef_by_name(proc: tprocdef;const name: string): tprocdef;
         procedure intf_get_procdefs(ImplIntf:TImplementedInterface;IntfDef:TObjectDef);
         procedure intf_get_procdefs(ImplIntf:TImplementedInterface;IntfDef:TObjectDef);
         procedure intf_get_procdefs_recursive(ImplIntf:TImplementedInterface;IntfDef:TObjectDef);
         procedure intf_get_procdefs_recursive(ImplIntf:TImplementedInterface;IntfDef:TObjectDef);
@@ -66,7 +66,7 @@ interface
       public
       public
         constructor create(c:tobjectdef);
         constructor create(c:tobjectdef);
         destructor  destroy;override;
         destructor  destroy;override;
-        procedure generate_vmt(check_visibility: boolean);
+        procedure generate_vmt;
       end;
       end;
 
 
     type
     type
@@ -235,7 +235,7 @@ implementation
       end;
       end;
 
 
 
 
-    function TVMTBuilder.is_new_vmt_entry(VMTSymEntry:TVMTSymEntry;pd:tprocdef; check_visibility: boolean):boolean;
+    function TVMTBuilder.is_new_vmt_entry(VMTSymEntry:TVMTSymEntry;pd:tprocdef):boolean;
       const
       const
         po_comp = [po_classmethod,po_virtualmethod,po_staticmethod,po_interrupt,po_iocheck,po_msgstr,po_msgint,
         po_comp = [po_classmethod,po_virtualmethod,po_staticmethod,po_interrupt,po_iocheck,po_msgstr,po_msgint,
                    po_exports,po_varargs,po_explicitparaloc,po_nostackframe];
                    po_exports,po_varargs,po_explicitparaloc,po_nostackframe];
@@ -283,11 +283,10 @@ implementation
                       begin
                       begin
                         if is_visible then
                         if is_visible then
                           procdefcoll^.hidden:=true;
                           procdefcoll^.hidden:=true;
-                        if check_visibility then
-                          if (pd._class=procdefcoll^.data._class) then
-                             MessagePos(pd.fileinfo,parser_e_overloaded_have_same_parameters)
-                          else if (_class=pd._class) and not(po_reintroduce in pd.procoptions) then
-                            MessagePos1(pd.fileinfo,parser_w_should_use_override,pd.fullprocname(false));
+                        if (pd._class=procdefcoll^.data._class) then
+                           MessagePos(pd.fileinfo,parser_e_overloaded_have_same_parameters)
+                        else if (_class=pd._class) and not(po_reintroduce in pd.procoptions) then
+                          MessagePos1(pd.fileinfo,parser_w_should_use_override,pd.fullprocname(false));
                       end;
                       end;
                   end
                   end
                 { if both are virtual we check the header }
                 { if both are virtual we check the header }
@@ -305,11 +304,10 @@ implementation
                           begin
                           begin
                             if is_visible then
                             if is_visible then
                               procdefcoll^.hidden:=true;
                               procdefcoll^.hidden:=true;
-                            if check_visibility then
-                              if (pd._class=procdefcoll^.data._class) then
-                                MessagePos(pd.fileinfo,parser_e_overloaded_have_same_parameters)
-                              else if (_class=pd._class) and not(po_reintroduce in pd.procoptions) then
-                                MessagePos1(pd.fileinfo,parser_w_should_use_override,pd.fullprocname(false));
+                            if (pd._class=procdefcoll^.data._class) then
+                              MessagePos(pd.fileinfo,parser_e_overloaded_have_same_parameters)
+                            else if (_class=pd._class) and not(po_reintroduce in pd.procoptions) then
+                              MessagePos1(pd.fileinfo,parser_w_should_use_override,pd.fullprocname(false));
                           end;
                           end;
                       end
                       end
                     { same parameter and return types (parameter specifiers will be checked below) }
                     { same parameter and return types (parameter specifiers will be checked below) }
@@ -344,8 +342,7 @@ implementation
                           for the current parsed class. Parent classes are already validated and
                           for the current parsed class. Parent classes are already validated and
                           need to include all virtual methods including the ones not visible in the
                           need to include all virtual methods including the ones not visible in the
                           current class }
                           current class }
-                        if check_visibility and
-                           (_class=pd._class) and
+                        if (_class=pd._class) and
                            (po_overridingmethod in pd.procoptions) and
                            (po_overridingmethod in pd.procoptions) and
                            (not procdefcoll^.visible) then
                            (not procdefcoll^.visible) then
                           MessagePos1(pd.fileinfo,parser_e_nothing_to_be_overridden,pd.fullprocname(false));
                           MessagePos1(pd.fileinfo,parser_e_nothing_to_be_overridden,pd.fullprocname(false));
@@ -373,15 +370,14 @@ implementation
                         begin
                         begin
                           if is_visible then
                           if is_visible then
                             procdefcoll^.hidden:=true;
                             procdefcoll^.hidden:=true;
-                          if check_visibility then
-                            if (pd._class=procdefcoll^.data._class) then
-                              MessagePos(pd.fileinfo,parser_e_overloaded_have_same_parameters)
-                            else if (_class=pd._class) and not(po_reintroduce in pd.procoptions) then
-                              if not is_object(_class) then
-                                MessagePos1(pd.fileinfo,parser_w_should_use_override,pd.fullprocname(false))
-                              else
-                                { objects don't allow starting a new virtual tree }
-                                MessagePos1(pd.fileinfo,parser_e_header_dont_match_forward,procdefcoll^.data.fullprocname(false));
+                          if (pd._class=procdefcoll^.data._class) then
+                            MessagePos(pd.fileinfo,parser_e_overloaded_have_same_parameters)
+                          else if (_class=pd._class) and not(po_reintroduce in pd.procoptions) then
+                            if not is_object(_class) then
+                              MessagePos1(pd.fileinfo,parser_w_should_use_override,pd.fullprocname(false))
+                            else
+                              { objects don't allow starting a new virtual tree }
+                              MessagePos1(pd.fileinfo,parser_e_header_dont_match_forward,procdefcoll^.data.fullprocname(false));
                         end;
                         end;
                      end;
                      end;
                   end
                   end
@@ -414,7 +410,7 @@ implementation
       end;
       end;
 
 
 
 
-    procedure TVMTBuilder.add_vmt_entries(objdef:tobjectdef; check_visibility: boolean);
+    procedure TVMTBuilder.add_vmt_entries(objdef:tobjectdef);
       var
       var
          def : tdef;
          def : tdef;
          pd  : tprocdef;
          pd  : tprocdef;
@@ -423,7 +419,7 @@ implementation
       begin
       begin
         { start with the base class }
         { start with the base class }
         if assigned(objdef.childof) then
         if assigned(objdef.childof) then
-          add_vmt_entries(objdef.childof,check_visibility);
+          add_vmt_entries(objdef.childof);
         { process all procdefs, we must process the defs to
         { process all procdefs, we must process the defs to
           keep the same order as that is written in the source
           keep the same order as that is written in the source
           to be compatible with the indexes in the interface vtable (PFV) }
           to be compatible with the indexes in the interface vtable (PFV) }
@@ -438,7 +434,7 @@ implementation
                 if not assigned(VMTSymEntry) then
                 if not assigned(VMTSymEntry) then
                   VMTSymEntry:=TVMTSymEntry.Create(VMTSymEntryList,pd.procsym.name);
                   VMTSymEntry:=TVMTSymEntry.Create(VMTSymEntryList,pd.procsym.name);
                 { VMT entry }
                 { VMT entry }
-                if is_new_vmt_entry(VMTSymEntry,pd,check_visibility) then
+                if is_new_vmt_entry(VMTSymEntry,pd) then
                   add_new_vmt_entry(VMTSymEntry,pd);
                   add_new_vmt_entry(VMTSymEntry,pd);
               end;
               end;
           end;
           end;
@@ -668,7 +664,7 @@ implementation
       end;
       end;
 
 
 
 
-    procedure TVMTBuilder.generate_vmt(check_visibility: boolean);
+    procedure TVMTBuilder.generate_vmt;
       var
       var
         i : longint;
         i : longint;
         ImplIntf : TImplementedInterface;
         ImplIntf : TImplementedInterface;
@@ -676,27 +672,26 @@ implementation
         { Find VMT entries }
         { Find VMT entries }
         has_constructor:=false;
         has_constructor:=false;
         has_virtual_method:=false;
         has_virtual_method:=false;
-        add_vmt_entries(_class,check_visibility);
+        add_vmt_entries(_class);
         if not(is_interface(_class)) and
         if not(is_interface(_class)) and
            has_virtual_method and
            has_virtual_method and
            not(has_constructor) then
            not(has_constructor) then
           Message1(parser_w_virtual_without_constructor,_class.objrealname^);
           Message1(parser_w_virtual_without_constructor,_class.objrealname^);
 
 
         { Find Procdefs implementing the interfaces }
         { Find Procdefs implementing the interfaces }
-        if check_visibility then
-          if assigned(_class.ImplementedInterfaces) then
-            begin
-              { Collect implementor functions into the tImplementedInterface.procdefs }
-              for i:=0 to _class.ImplementedInterfaces.count-1 do
-                begin
-                  ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]);
-                  intf_get_procdefs_recursive(ImplIntf,ImplIntf.IntfDef);
-                end;
-              { Optimize interface tables to reuse wrappers }
-              intf_optimize_vtbls;
-              { Allocate interface tables }
-              intf_allocate_vtbls;
-            end;
+        if assigned(_class.ImplementedInterfaces) then
+          begin
+            { Collect implementor functions into the tImplementedInterface.procdefs }
+            for i:=0 to _class.ImplementedInterfaces.count-1 do
+              begin
+                ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]);
+                intf_get_procdefs_recursive(ImplIntf,ImplIntf.IntfDef);
+              end;
+            { Optimize interface tables to reuse wrappers }
+            intf_optimize_vtbls;
+            { Allocate interface tables }
+            intf_allocate_vtbls;
+          end;
       end;
       end;
 
 
 
 
@@ -1326,9 +1321,6 @@ implementation
            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));
 {$endif vtentry}
 {$endif vtentry}
          end;
          end;
-        { release VMTEntries, we don't need them anymore }
-        _class.VMTEntries.free;
-        _class.VMTEntries:=nil;
       end;
       end;
 
 
 
 

+ 7 - 20
compiler/optvirt.pas

@@ -372,14 +372,7 @@ unit optvirt;
         {$ENDIF}
         {$ENDIF}
         { todo: also process interfaces (ImplementedInterfaces) }
         { todo: also process interfaces (ImplementedInterfaces) }
         if not assigned(node.def.vmtentries) then
         if not assigned(node.def.vmtentries) then
-          begin
-            vmtbuilder:=tvmtbuilder.create(node.def);
-            vmtbuilder.generate_vmt(false);
-            vmtbuilder.free;
-            { may not have any virtual methods }
-            if not assigned(node.def.vmtentries) then
-              exit;
-          end;
+          exit;
         { process all vmt entries for this class/object }
         { process all vmt entries for this class/object }
         for i:=0 to node.def.vmtentries.count-1 do
         for i:=0 to node.def.vmtentries.count-1 do
           begin
           begin
@@ -403,17 +396,10 @@ unit optvirt;
             }
             }
             makeallvirtual:=false;
             makeallvirtual:=false;
             repeat
             repeat
-              if not assigned(currnode.def.vmtentries) then
-                begin
-                  vmtbuilder:=tvmtbuilder.create(currnode.def);
-                  vmtbuilder.generate_vmt(false);
-                  vmtbuilder.free;
-                  { may not have any vmtentries }
-                  if not assigned(currnode.def.vmtentries) then
-                    break;
-                end;
-              { stop when this method does not exist in a parent }
-              if (currnode.def.vmtentries.count<=i) then
+                 { this parent may not have any virtual methods }
+              if not assigned(currnode.def.vmtentries) or
+                 { stop when this method does not exist in a parent }
+                 (currnode.def.vmtentries.count<=i) then
                 break;
                 break;
               
               
               if not assigned(currnode.def.vmcallstaticinfo) then
               if not assigned(currnode.def.vmcallstaticinfo) then
@@ -928,7 +914,8 @@ unit optvirt;
         unitdevirtinfo: tunitdevirtinfo;
         unitdevirtinfo: tunitdevirtinfo;
         classdevirtinfo: tclassdevirtinfo;
         classdevirtinfo: tclassdevirtinfo;
       begin
       begin
-        if (funits.count=0) then
+        { if there are no optimised virtual methods, we have stored no info }
+        if not assigned(funits) then
           exit;
           exit;
         writer.startsection(DEVIRT_SECTION_NAME);
         writer.startsection(DEVIRT_SECTION_NAME);
         for unitcount:=0 to funits.count-1 do
         for unitcount:=0 to funits.count-1 do

+ 1 - 1
compiler/pdecl.pas

@@ -465,7 +465,7 @@ implementation
                        not(df_generic in hdef.defoptions) then
                        not(df_generic in hdef.defoptions) then
                       begin
                       begin
                         vmtbuilder:=TVMTBuilder.Create(tobjectdef(hdef));
                         vmtbuilder:=TVMTBuilder.Create(tobjectdef(hdef));
-                        vmtbuilder.generate_vmt(true);
+                        vmtbuilder.generate_vmt;
                         vmtbuilder.free;
                         vmtbuilder.free;
                       end;
                       end;
                     try_consume_hintdirective(newtype.symoptions);
                     try_consume_hintdirective(newtype.symoptions);

+ 1 - 1
compiler/ptype.pas

@@ -259,7 +259,7 @@ implementation
                 if (tt.typ=objectdef) then
                 if (tt.typ=objectdef) then
                   begin
                   begin
                     vmtbuilder:=TVMTBuilder.Create(tobjectdef(tt));
                     vmtbuilder:=TVMTBuilder.Create(tobjectdef(tt));
-                    vmtbuilder.generate_vmt(true);
+                    vmtbuilder.generate_vmt;
                     vmtbuilder.free;
                     vmtbuilder.free;
                   end;
                   end;
               end;
               end;

+ 42 - 1
compiler/symdef.pas

@@ -226,7 +226,11 @@ interface
        tvmcallstatic = (vmcs_default, vmcs_yes, vmcs_no);
        tvmcallstatic = (vmcs_default, vmcs_yes, vmcs_no);
        pmvcallstaticinfo = ^tmvcallstaticinfo;
        pmvcallstaticinfo = ^tmvcallstaticinfo;
        tmvcallstaticinfo = array[0..1024*1024-1] of tvmcallstatic;
        tmvcallstaticinfo = array[0..1024*1024-1] of tvmcallstatic;
+       pderefarray = ^tderefarray;
+       tderefarray = array[0..1024*1024-1] of tderef;
        tobjectdef = class(tabstractrecorddef)
        tobjectdef = class(tabstractrecorddef)
+       private
+          vmtentriesderefs: pderefarray;
        public
        public
           dwarf_struct_lab : tasmsymbol;
           dwarf_struct_lab : tasmsymbol;
           childof        : tobjectdef;
           childof        : tobjectdef;
@@ -3718,7 +3722,8 @@ implementation
     constructor tobjectdef.ppuload(ppufile:tcompilerppufile);
     constructor tobjectdef.ppuload(ppufile:tcompilerppufile);
       var
       var
          i,
          i,
-         implintfcount : longint;
+         implintfcount,
+         vmtentrycount  : longint;
          d : tderef;
          d : tderef;
          ImplIntf : TImplementedInterface;
          ImplIntf : TImplementedInterface;
       begin
       begin
@@ -3760,6 +3765,17 @@ implementation
          else
          else
            ImplementedInterfaces:=nil;
            ImplementedInterfaces:=nil;
 
 
+         { load vmt procdefs }
+         vmtentrycount:=ppufile.getlongint;
+         if (vmtentrycount<>0) then
+           begin
+             vmtentries:=tfpobjectlist.create(false);
+             vmtentries.count:=vmtentrycount;
+             getmem(vmtentriesderefs,vmtentrycount*sizeof(tderef));
+             for i:=0 to vmtentrycount-1 do
+               ppufile.getderef(vmtentriesderefs^[i]);
+           end;
+
          if df_copied_def in defoptions then
          if df_copied_def in defoptions then
            ppufile.getderef(cloneddefderef)
            ppufile.getderef(cloneddefderef)
          else
          else
@@ -3880,6 +3896,16 @@ implementation
                end;
                end;
            end;
            end;
 
 
+         { write vmt procdefs }
+         if assigned(vmtentries) then
+           begin
+             ppufile.putlongint(vmtentries.count);
+             for i:=0 to vmtentries.count-1 do
+               ppufile.putderef(vmtentriesderefs^[i]);
+           end
+         else
+           ppufile.putlongint(0);
+
          if df_copied_def in defoptions then
          if df_copied_def in defoptions then
            ppufile.putderef(cloneddefderef);
            ppufile.putderef(cloneddefderef);
 
 
@@ -3919,6 +3945,13 @@ implementation
              for i:=0 to ImplementedInterfaces.count-1 do
              for i:=0 to ImplementedInterfaces.count-1 do
                TImplementedInterface(ImplementedInterfaces[i]).buildderef;
                TImplementedInterface(ImplementedInterfaces[i]).buildderef;
            end;
            end;
+
+         if assigned(vmtentries) then
+           begin
+             getmem(vmtentriesderefs,vmtentries.count*sizeof(tderef));
+             for i:=0 to vmtentries.count-1 do
+               vmtentriesderefs^[i].build(vmtentries[i]);
+           end;
       end;
       end;
 
 
 
 
@@ -3940,6 +3973,14 @@ implementation
              for i:=0 to ImplementedInterfaces.count-1 do
              for i:=0 to ImplementedInterfaces.count-1 do
                TImplementedInterface(ImplementedInterfaces[i]).deref;
                TImplementedInterface(ImplementedInterfaces[i]).deref;
            end;
            end;
+
+         if assigned(vmtentries) then
+           begin
+             for i:=0 to vmtentries.count-1 do
+               vmtentries[i]:=vmtentriesderefs^[i].resolve;
+             freemem(vmtentriesderefs);
+             vmtentriesderefs:=nil;
+           end;
       end;
       end;