Browse Source

* set the vmt entries of non-class virtual methods of not instantiated
objects/classes to FPC_ABSTRACTERROR so the code they refer to can
be thrown away if it is not referred to in any other way either

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

Jonas Maebe 17 years ago
parent
commit
7c16682011
3 changed files with 128 additions and 46 deletions
  1. 116 43
      compiler/optvirt.pas
  2. 6 1
      compiler/wpobase.pas
  3. 6 2
      compiler/wpoinfo.pas

+ 116 - 43
compiler/optvirt.pas

@@ -95,11 +95,15 @@ unit optvirt;
        private
        private
         { array (indexed by vmt entry nr) of replacement statically callable method names }
         { array (indexed by vmt entry nr) of replacement statically callable method names }
         fstaticmethodnames: tfplist;
         fstaticmethodnames: tfplist;
+        { is this class instantiated by the program? }
+        finstantiated: boolean;
         function isstaticvmtentry(vmtindex: longint; out replacementname: pshortstring): boolean;
         function isstaticvmtentry(vmtindex: longint; out replacementname: pshortstring): boolean;
        public
        public
-        constructor create(hashobjectlist:tfphashobjectlist;const n: shortstring);reintroduce;
+        constructor create(hashobjectlist:tfphashobjectlist;const n: shortstring; instantiated: boolean);
         destructor destroy; override;
         destructor destroy; override;
 
 
+        property instantiated: boolean read finstantiated;
+
         procedure addstaticmethod(vmtindex: longint; const replacementname: shortstring);
         procedure addstaticmethod(vmtindex: longint; const replacementname: shortstring);
       end;
       end;
 
 
@@ -114,7 +118,7 @@ unit optvirt;
         constructor create(hashobjectlist:tfphashobjectlist;const n: shortstring);reintroduce;
         constructor create(hashobjectlist:tfphashobjectlist;const n: shortstring);reintroduce;
         destructor destroy; override;
         destructor destroy; override;
 
 
-        function addclass(const n: shortstring): tclassdevirtinfo;
+        function addclass(const n: shortstring; instantiated: boolean): tclassdevirtinfo;
         function findclass(const n: shortstring): tclassdevirtinfo;
         function findclass(const n: shortstring): tclassdevirtinfo;
       end;
       end;
 
 
@@ -130,6 +134,7 @@ unit optvirt;
         procedure converttreenode(node: tinheritancetreenode; arg: pointer);
         procedure converttreenode(node: tinheritancetreenode; arg: pointer);
         function addunitifnew(const n: shortstring): tunitdevirtinfo;
         function addunitifnew(const n: shortstring): tunitdevirtinfo;
         function findunit(const n: shortstring): tunitdevirtinfo;
         function findunit(const n: shortstring): tunitdevirtinfo;
+        function getstaticname(forvmtentry: boolean; objdef, procdef: tdef; out staticname: string): boolean;
        public
        public
         constructor create; override;
         constructor create; override;
         destructor destroy; override;
         destructor destroy; override;
@@ -145,7 +150,8 @@ unit optvirt;
 
 
         { information providing }
         { information providing }
         procedure loadfromwpofilesection(reader: twposectionreaderintf); override;
         procedure loadfromwpofilesection(reader: twposectionreaderintf); override;
-        function staticnameforvirtualmethod(objdef, procdef: tdef; out staticname: string): boolean; override;
+        function staticnameforcallingvirtualmethod(objdef, procdef: tdef; out staticname: string): boolean; override;
+        function staticnameforvmtentry(objdef, procdef: tdef; out staticname: string): boolean; override;
 
 
       end;
       end;
 
 
@@ -362,7 +368,6 @@ unit optvirt;
     procedure tinheritancetree.markvmethods(node: tinheritancetreenode; p: pointer);
     procedure tinheritancetree.markvmethods(node: tinheritancetreenode; p: pointer);
       var
       var
         currnode: tinheritancetreenode;
         currnode: tinheritancetreenode;
-        vmtbuilder: tvmtbuilder;
         pd: tobject;
         pd: tobject;
         i: longint;
         i: longint;
         makeallvirtual: boolean;
         makeallvirtual: boolean;
@@ -490,17 +495,18 @@ unit optvirt;
       end;
       end;
 
 
 
 
-    { helper routine: decompose an object & procdef combo into a unitname, class name and vmtentry number
+    { helper routines: decompose an object & procdef combo into a unitname, class name and vmtentry number
       (unit name where the objectdef is declared, class name of the objectdef, vmtentry number of the
       (unit name where the objectdef is declared, class name of the objectdef, vmtentry number of the
        procdef -- procdef does not necessarily belong to objectdef, it may also belong to a descendant
        procdef -- procdef does not necessarily belong to objectdef, it may also belong to a descendant
-       or parent) }
+       or parent)
+    }
 
 
-    procedure defsdecompose(objdef: tobjectdef; procdef: tprocdef; out unitname, classname: pshortstring; out vmtentry: longint);
+    procedure defunitclassname(objdef: tobjectdef; out unitname, classname: pshortstring);
       const
       const
         mainprogname: string[2] = 'P$';
         mainprogname: string[2] = 'P$';
       var
       var
         mainsymtab,
         mainsymtab,
-        objparentsymtab: tsymtable;
+        objparentsymtab : tsymtable;
       begin
       begin
         objparentsymtab:=objdef.symtable;
         objparentsymtab:=objdef.symtable;
         mainsymtab:=objparentsymtab.defowner.owner;
         mainsymtab:=objparentsymtab.defowner.owner;
@@ -514,6 +520,12 @@ unit optvirt;
         else
         else
           unitname:=mainsymtab.name;
           unitname:=mainsymtab.name;
         classname:=tobjectdef(objparentsymtab.defowner).objname;
         classname:=tobjectdef(objparentsymtab.defowner).objname;
+      end;
+
+
+    procedure defsdecompose(objdef: tobjectdef; procdef: tprocdef; out unitname, classname: pshortstring; out vmtentry: longint);
+      begin
+        defunitclassname(objdef,unitname,classname);
         vmtentry:=procdef.extnumber;
         vmtentry:=procdef.extnumber;
         { if it's $ffff, this is not a valid virtual method }
         { if it's $ffff, this is not a valid virtual method }
         if (vmtentry=$ffff) then
         if (vmtentry=$ffff) then
@@ -523,9 +535,10 @@ unit optvirt;
 
 
    { tclassdevirtinfo }
    { tclassdevirtinfo }
 
 
-    constructor tclassdevirtinfo.create(hashobjectlist:tfphashobjectlist;const n: shortstring);
+    constructor tclassdevirtinfo.create(hashobjectlist:tfphashobjectlist;const n: shortstring; instantiated: boolean);
       begin
       begin
         inherited create(hashobjectlist,n);
         inherited create(hashobjectlist,n);
+        finstantiated:=instantiated;
         fstaticmethodnames:=tfplist.create;
         fstaticmethodnames:=tfplist.create;
       end;
       end;
 
 
@@ -573,13 +586,13 @@ unit optvirt;
         inherited destroy;
         inherited destroy;
       end;
       end;
 
 
-    function tunitdevirtinfo.addclass(const n: shortstring): tclassdevirtinfo;
+    function tunitdevirtinfo.addclass(const n: shortstring; instantiated: boolean): tclassdevirtinfo;
       begin
       begin
         result:=findclass(n);
         result:=findclass(n);
         { can't have two classes with the same name in a single unit }
         { can't have two classes with the same name in a single unit }
         if assigned(result) then
         if assigned(result) then
           internalerror(2008100501);
           internalerror(2008100501);
-        result:=tclassdevirtinfo.create(fclasses,n);
+        result:=tclassdevirtinfo.create(fclasses,n,instantiated);
       end;
       end;
 
 
     function tunitdevirtinfo.findclass(const n: shortstring): tclassdevirtinfo;
     function tunitdevirtinfo.findclass(const n: shortstring): tclassdevirtinfo;
@@ -592,28 +605,27 @@ unit optvirt;
 
 
     procedure tprogdevirtinfo.converttreenode(node: tinheritancetreenode; arg: pointer);
     procedure tprogdevirtinfo.converttreenode(node: tinheritancetreenode; arg: pointer);
       var
       var
-        i,
-        vmtentry: longint;
+        i: longint;
         unitid, classid: pshortstring;
         unitid, classid: pshortstring;
         unitdevirtinfo: tunitdevirtinfo;
         unitdevirtinfo: tunitdevirtinfo;
         classdevirtinfo: tclassdevirtinfo;
         classdevirtinfo: tclassdevirtinfo;
-        first : boolean;
       begin
       begin
+        if (not node.instantiated) and
+           not assigned(node.def.vmtentries) then
+          exit;
+        { always add a class entry for an instantiated class, so we can
+          fill the vmt's of non-instantiated classes with calls to
+          FPC_ABSTRACTERROR during the optimisation phase
+        }
+        defunitclassname(node.def,unitid,classid);
+        unitdevirtinfo:=addunitifnew(unitid^);
+        classdevirtinfo:=unitdevirtinfo.addclass(classid^,node.instantiated);
         if not assigned(node.def.vmtentries) then
         if not assigned(node.def.vmtentries) then
           exit;
           exit;
-        first:=true;
         for i:=0 to node.def.vmtentries.count-1 do
         for i:=0 to node.def.vmtentries.count-1 do
           if (po_virtualmethod in tabstractprocdef(node.def.vmtentries[i]).procoptions) and
           if (po_virtualmethod in tabstractprocdef(node.def.vmtentries[i]).procoptions) and
              (node.def.vmcallstaticinfo^[i]=vmcs_yes) then
              (node.def.vmcallstaticinfo^[i]=vmcs_yes) then
             begin
             begin
-              if first then
-                begin
-                  { add necessary entries for the unit and the class }
-                  defsdecompose(node.def,tprocdef(node.def.vmtentries[i]),unitid,classid,vmtentry);
-                  unitdevirtinfo:=addunitifnew(unitid^);
-                  classdevirtinfo:=unitdevirtinfo.addclass(classid^);
-                  first:=false;
-                end;
               { add info about devirtualised vmt entry }
               { add info about devirtualised vmt entry }
               classdevirtinfo.addstaticmethod(i,tprocdef(node.def.vmtentries[i]).mangledname);
               classdevirtinfo.addstaticmethod(i,tprocdef(node.def.vmtentries[i]).mangledname);
             end;
             end;
@@ -831,15 +843,24 @@ unit optvirt;
         vmtentryname: string;
         vmtentryname: string;
         vmttype: string[15];
         vmttype: string[15];
         vmtentrynrstr: string[7];
         vmtentrynrstr: string[7];
+        classinstantiated: string[1];
         vmtentry, error: longint;
         vmtentry, error: longint;
         unitdevirtinfo: tunitdevirtinfo;
         unitdevirtinfo: tunitdevirtinfo;
         classdevirtinfo: tclassdevirtinfo;
         classdevirtinfo: tclassdevirtinfo;
+        instantiated: boolean;
       begin
       begin
         { format:
         { format:
+            # unitname^
             unit1^
             unit1^
+            # classname&
             class1&
             class1&
+            # instantiated?
+            1
+            # vmt type (base or some interface)
             basevmt
             basevmt
+            # vmt entry nr
             0
             0
+            # name of routine to call instead
             staticvmtentryforslot0
             staticvmtentryforslot0
             5
             5
             staticvmtentryforslot5
             staticvmtentryforslot5
@@ -847,12 +868,20 @@ unit optvirt;
             0
             0
             staticvmtentryforslot0
             staticvmtentryforslot0
 
 
+            # non-instantiated class (but if we encounter a variable of this
+            # type, we can optimise class to vmtentry 1)
             class2&
             class2&
+            0
             basevmt
             basevmt
             1
             1
             staticvmtentryforslot1
             staticvmtentryforslot1
 
 
+            # instantiated class without optimisable virtual methods
+            class3&
+            1
+
             unit2^
             unit2^
+            1
             class3&
             class3&
             ...
             ...
 
 
@@ -875,25 +904,33 @@ unit optvirt;
             if (classid='') or
             if (classid='') or
                (classid[length(classid)]<>'&') then
                (classid[length(classid)]<>'&') then
               internalerror(2008100503);
               internalerror(2008100503);
+            { instantiated? }
+            if not reader.sectiongetnextline(classinstantiated) then
+              internalerror(2008101901);
+            instantiated:=classinstantiated='1';
             { cut off the trailing & }
             { cut off the trailing & }
             setlength(classid,length(classid)-1);
             setlength(classid,length(classid)-1);
-            classdevirtinfo:=unitdevirtinfo.addclass(classid);
+            classdevirtinfo:=unitdevirtinfo.addclass(classid,instantiated);
             if not reader.sectiongetnextline(vmttype) then
             if not reader.sectiongetnextline(vmttype) then
               internalerror(2008100506);
               internalerror(2008100506);
-            { interface info is not yet supported }
-            if (vmttype<>'basevmt') then
-              internalerror(2008100507);
-            { read all vmt entries for this class }
-            while reader.sectiongetnextline(vmtentrynrstr) and
-                  (vmtentrynrstr<>'') do
+            { any optimisable virtual methods? }
+            if (vmttype<>'') then
               begin
               begin
-                val(vmtentrynrstr,vmtentry,error);
-                if (error<>0) then
-                  internalerror(2008100504);
-                if not reader.sectiongetnextline(vmtentryname) or
-                   (vmtentryname='') then
-                  internalerror(2008100508);
-                classdevirtinfo.addstaticmethod(vmtentry,vmtentryname);
+                { interface info is not yet supported }
+                if (vmttype<>'basevmt') then
+                  internalerror(2008100507);
+                { read all vmt entries for this class }
+                while reader.sectiongetnextline(vmtentrynrstr) and
+                      (vmtentrynrstr<>'') do
+                  begin
+                    val(vmtentrynrstr,vmtentry,error);
+                    if (error<>0) then
+                      internalerror(2008100504);
+                    if not reader.sectiongetnextline(vmtentryname) or
+                       (vmtentryname='') then
+                      internalerror(2008100508);
+                    classdevirtinfo.addstaticmethod(vmtentry,vmtentryname);
+                  end;
               end;
               end;
             { end of section -> exit }
             { end of section -> exit }
             if not(reader.sectiongetnextline(classid)) then
             if not(reader.sectiongetnextline(classid)) then
@@ -913,6 +950,7 @@ unit optvirt;
         vmtentrycount: longint;
         vmtentrycount: longint;
         unitdevirtinfo: tunitdevirtinfo;
         unitdevirtinfo: tunitdevirtinfo;
         classdevirtinfo: tclassdevirtinfo;
         classdevirtinfo: tclassdevirtinfo;
+        first: boolean;
       begin
       begin
         { if there are no optimised virtual methods, we have stored no info }
         { if there are no optimised virtual methods, we have stored no info }
         if not assigned(funits) then
         if not assigned(funits) then
@@ -926,10 +964,16 @@ unit optvirt;
               begin
               begin
                 classdevirtinfo:=tclassdevirtinfo(tunitdevirtinfo(funits[unitcount]).fclasses[classcount]);
                 classdevirtinfo:=tclassdevirtinfo(tunitdevirtinfo(funits[unitcount]).fclasses[classcount]);
                 writer.sectionputline(classdevirtinfo.name+'&');
                 writer.sectionputline(classdevirtinfo.name+'&');
-                writer.sectionputline('basevmt');
+                writer.sectionputline(tostr(ord(classdevirtinfo.instantiated)));
+                first:=true;
                 for vmtentrycount:=0 to classdevirtinfo.fstaticmethodnames.count-1 do
                 for vmtentrycount:=0 to classdevirtinfo.fstaticmethodnames.count-1 do
                   if assigned(classdevirtinfo.fstaticmethodnames[vmtentrycount]) then
                   if assigned(classdevirtinfo.fstaticmethodnames[vmtentrycount]) then
                     begin
                     begin
+                      if first then
+                        begin
+                          writer.sectionputline('basevmt');
+                          first:=false;
+                        end;
                       writer.sectionputline(tostr(vmtentrycount));
                       writer.sectionputline(tostr(vmtentrycount));
                       writer.sectionputline(pshortstring(classdevirtinfo.fstaticmethodnames[vmtentrycount])^);
                       writer.sectionputline(pshortstring(classdevirtinfo.fstaticmethodnames[vmtentrycount])^);
                     end;
                     end;
@@ -939,7 +983,7 @@ unit optvirt;
       end;
       end;
 
 
 
 
-    function tprogdevirtinfo.staticnameforvirtualmethod(objdef, procdef: tdef; out staticname: string): boolean;
+    function tprogdevirtinfo.getstaticname(forvmtentry: boolean; objdef, procdef: tdef; out staticname: string): boolean;
       var
       var
         unitid,
         unitid,
         classid,
         classid,
@@ -976,10 +1020,39 @@ unit optvirt;
          classdevirtinfo:=unitdevirtinfo.findclass(classid^);
          classdevirtinfo:=unitdevirtinfo.findclass(classid^);
          if not assigned(classdevirtinfo) then
          if not assigned(classdevirtinfo) then
            exit;
            exit;
-         { now check whether it can be devirtualised, and if so to what }
-         result:=classdevirtinfo.isstaticvmtentry(vmtentry,newname);
-         if result then
-           staticname:=newname^;
+         { if it's for a vmtentry of an objdef and the objdef is
+           not instantiated, then we can fill the vmt with pointers
+           to FPC_ABSTRACTERROR
+         }
+         if forvmtentry and
+            (objdef.typ=objectdef) and
+            not classdevirtinfo.instantiated and
+            { virtual class methods can be called even if the class is not instantiated }
+            not(po_classmethod in tprocdef(procdef).procoptions) then
+           begin
+             staticname:='FPC_ABSTRACTERROR';
+             result:=true;
+           end
+         else
+           begin
+             { now check whether it can be devirtualised, and if so to what }
+             result:=classdevirtinfo.isstaticvmtentry(vmtentry,newname);
+             if result then
+               staticname:=newname^;
+           end;
+      end;
+
+
+
+    function tprogdevirtinfo.staticnameforcallingvirtualmethod(objdef, procdef: tdef; out staticname: string): boolean;
+      begin
+        result:=getstaticname(false,objdef,procdef,staticname);
+      end;
+
+
+    function tprogdevirtinfo.staticnameforvmtentry(objdef, procdef: tdef; out staticname: string): boolean;
+      begin
+        result:=getstaticname(true,objdef,procdef,staticname);
       end;
       end;
 
 
 end.
 end.

+ 6 - 1
compiler/wpobase.pas

@@ -209,7 +209,12 @@ type
       a static call when it's called as objdef.procdef, and if so returns the
       a static call when it's called as objdef.procdef, and if so returns the
       mangled name in staticname.
       mangled name in staticname.
     }
     }
-    function staticnameforvirtualmethod(objdef, procdef: tdef; out staticname: string): boolean; virtual; abstract;
+    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;
   end;
 
 
   twpodeadcodehandler = class(twpocomponentbase)
   twpodeadcodehandler = class(twpocomponentbase)

+ 6 - 2
compiler/wpoinfo.pas

@@ -177,6 +177,8 @@ implementation
 
 
   { twpoinfomanager }
   { twpoinfomanager }
 
 
+  { devirtualisation }
+
   function twpoinfomanager.can_be_devirtualized(objdef, procdef: tdef; out name: shortstring): boolean;
   function twpoinfomanager.can_be_devirtualized(objdef, procdef: tdef; out name: shortstring): boolean;
     begin
     begin
       if not assigned(wpoinfouse[wpo_devirtualization_context_insensitive]) or
       if not assigned(wpoinfouse[wpo_devirtualization_context_insensitive]) or
@@ -185,7 +187,7 @@ implementation
           result:=false;
           result:=false;
           exit;
           exit;
         end;
         end;
-      result:=twpodevirtualisationhandler(wpoinfouse[wpo_devirtualization_context_insensitive]).staticnameforvirtualmethod(objdef,procdef,name);
+      result:=twpodevirtualisationhandler(wpoinfouse[wpo_devirtualization_context_insensitive]).staticnameforcallingvirtualmethod(objdef,procdef,name);
     end;
     end;
 
 
 
 
@@ -197,10 +199,12 @@ implementation
           result:=false;
           result:=false;
           exit;
           exit;
         end;
         end;
-      result:=twpodevirtualisationhandler(wpoinfouse[wpo_devirtualization_context_insensitive]).staticnameforvirtualmethod(objdef,procdef,name);
+      result:=twpodevirtualisationhandler(wpoinfouse[wpo_devirtualization_context_insensitive]).staticnameforvmtentry(objdef,procdef,name);
     end;
     end;
 
 
 
 
+  { symbol liveness }
+
   function twpoinfomanager.symbol_live(const name: shortstring): boolean;
   function twpoinfomanager.symbol_live(const name: shortstring): boolean;
     begin
     begin
       if not assigned(wpoinfouse[wpo_live_symbol_information]) or
       if not assigned(wpoinfouse[wpo_live_symbol_information]) or