Prechádzať zdrojové kódy

* keep track of the number of abstract methods per class via a counter
* use this counter to mark classes containing abstract methods as
"abstract" in the bytecode per the JVM spec
* also use the counter to short-circuit printing of all abstract
methods in a class when creating a new instance (we build the list
of abstract methods every time a new instance is created, which is
a waste of time if there are none in the first place)

git-svn-id: branches/jvmbackend@18635 -

Jonas Maebe 14 rokov pred
rodič
commit
6154f1b0d9

+ 2 - 1
compiler/agjasmin.pas

@@ -570,7 +570,8 @@ implementation
                         AsmWrite('.class ');
                         if oo_is_sealed in tobjectdef(obj).objectoptions then
                           AsmWrite('final ');
-                        if oo_is_abstract in tobjectdef(obj).objectoptions then
+                        if (oo_is_abstract in tobjectdef(obj).objectoptions) or
+                           (tobjectdef(obj).abstractcnt<>0) then
                           AsmWrite('abstract ');
                         if toplevelowner.symtabletype=globalsymtable then
                           AsmWrite('public ');

+ 3 - 0
compiler/ncal.pas

@@ -2456,6 +2456,9 @@ implementation
           end;
         if not assigned(objectdf) then
           exit;
+        { quick exit if nothing to check }
+        if objectdf.abstractcnt = 0 then
+          exit;
 
         parents := tlinkedlist.create;
         AbstractMethodsList := TFPHashList.create;

+ 6 - 0
compiler/nobj.pas

@@ -384,6 +384,12 @@ implementation
                         vmtentryvis:=pd.visibility;
                     end;
 
+                  { in case we are overriding an abstract method,
+                    decrease the number of abstract methods in this class }
+                  if (po_overridingmethod in pd.procoptions) and
+                     (po_abstractmethod in vmtpd.procoptions) then
+                    dec(tobjectdef(pd.owner.defowner).abstractcnt);
+
                   { override old virtual method in VMT }
                   if updatevalues then
                     begin

+ 5 - 1
compiler/pdecsub.pas

@@ -1667,7 +1667,11 @@ begin
     (oo_is_sealed in tprocdef(pd).struct.objectoptions) then
     Message(parser_e_sealed_class_cannot_have_abstract_methods)
   else if (po_virtualmethod in pd.procoptions) then
-    include(pd.procoptions,po_abstractmethod)
+    begin
+      include(pd.procoptions,po_abstractmethod);
+      { one more abstract method }
+      inc(tobjectdef(pd.owner.defowner).abstractcnt);
+    end
   else
     Message(parser_e_only_virtual_methods_abstract);
   { the method is defined }

+ 1 - 1
compiler/ppu.pas

@@ -43,7 +43,7 @@ type
 {$endif Test_Double_checksum}
 
 const
-  CurrentPPUVersion = 136;
+  CurrentPPUVersion = 137;
 
 { buffer sizes }
   maxentrysize = 1024;

+ 9 - 0
compiler/symdef.pas

@@ -284,6 +284,10 @@ interface
           iidstr         : pshortstring;
           { store implemented interfaces defs and name mappings }
           ImplementedInterfaces : TFPObjectList;
+          { number of abstract methods (used by JVM target to determine whether
+            or not the class should be marked as abstract: must be done if 1 or
+            more abstract methods) }
+          abstractcnt    : longint;
           writing_class_record_dbginfo,
           { a class of this type has been created in this module }
           created_in_current_module,
@@ -4902,6 +4906,7 @@ implementation
               ppufile.getguid(iidguid^);
               iidstr:=stringdup(ppufile.getstring);
            end;
+         abstractcnt:=ppufile.getlongint;
 
          if objecttype=odt_helper then
            ppufile.getderef(extendeddefderef);
@@ -5038,6 +5043,7 @@ implementation
           end;
         if assigned(iidstr) then
           tobjectdef(result).iidstr:=stringdup(iidstr^);
+        tobjectdef(result).abstractcnt:=abstractcnt;
         if assigned(ImplementedInterfaces) then
           begin
             for i:=0 to ImplementedInterfaces.count-1 do
@@ -5084,6 +5090,7 @@ implementation
               ppufile.putguid(iidguid^);
               ppufile.putstring(iidstr^);
            end;
+         ppufile.putlongint(abstractcnt);
          if objecttype=odt_helper then
            ppufile.putderef(extendeddefderef);
 
@@ -5313,6 +5320,8 @@ implementation
           exit;
         { inherit options and status }
         objectoptions:=objectoptions+(c.objectoptions*inherited_objectoptions);
+        { initially has the same number of abstract methods as the parent }
+        abstractcnt:=c.abstractcnt;
         { add the data of the anchestor class/object }
         if (objecttype in [odt_class,odt_object,odt_objcclass,odt_javaclass]) then
           begin

+ 2 - 0
compiler/utils/ppudump.pp

@@ -2055,6 +2055,8 @@ begin
                   writeln(space,'       IID String : ',getstring);
                end;
 
+             writeln(space,' Abstract methods : ',getlongint);
+
              if (tobjecttyp(b)=odt_helper) or
                  (oo_is_classhelper in current_objectoptions) then
                begin