瀏覽代碼

* change non-virtual instance methods to "virtual; final;" methods on the
JVM target, because that's the only way to guarantee their semantics on
that platform (see comments in pdecobj)
* allow starting new inheritance trees (which is the same as adding a new
non-virtual method as of this revision) on the JVM target in case the
parameters of the new routine match the old one, but the complete mangled
name does not (because then the JVM won't consider them to be the same
either -> Pascal semantics are matched)

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

Jonas Maebe 14 年之前
父節點
當前提交
ee75bfaaf4
共有 4 個文件被更改,包括 61 次插入7 次删除
  1. 37 5
      compiler/nobj.pas
  2. 18 0
      compiler/pdecobj.pas
  3. 4 1
      compiler/symconst.pas
  4. 2 1
      compiler/utils/ppudump.pp

+ 37 - 5
compiler/nobj.pas

@@ -240,6 +240,10 @@ implementation
 
       // returns true if we can stop checking, false if we have to continue
       function found_entry(var vmtpd: tprocdef; var vmtentryvis: tvisibility; updatevalues: boolean): boolean;
+{$ifdef jvm}
+        var
+          javanewtreeok: boolean;
+{$endif jvm}
         begin
           result:=false;
 
@@ -269,9 +273,16 @@ implementation
           hasequalpara:=(compare_paras(vmtpd.paras,pd.paras,cp_none,[cpo_ignoreuniv,cpo_ignorehidden])>=te_equal);
 
           { check that we are not trying to override a final method }
+          { in Java, new virtual inheritance trees can never be started ->
+            treat all methods as "overriding" in the context of this check
+            (Java does check whether the mangled names are identical, so if they
+             are not we can stil get away with it) }
           if (po_finalmethod in vmtpd.procoptions) and
-             hasequalpara and (po_overridingmethod in pd.procoptions) and
-             (is_class(_class) or is_objectpascal_helper(_class)) then
+             hasequalpara and
+             ((po_overridingmethod in pd.procoptions) or
+              (is_javaclass(_class) and
+               (pd.mangledname=vmtpd.mangledname))) and
+             (is_class(_class) or is_objectpascal_helper(_class) or is_javaclass(_class)) then
             MessagePos1(pd.fileinfo,parser_e_final_can_no_be_overridden,pd.fullprocname(false))
           else
           { old definition has virtual
@@ -296,9 +307,21 @@ implementation
                   hasequalpara
                  ) then
                 begin
-                  if not(po_reintroduce in pd.procoptions) then
-                    if not(is_objc_class_or_protocol(_class)) and
-                       not(is_java_class_or_interface(_class)) then
+{$ifdef jvm}
+                  { if the mangled names are different, the inheritance trees
+                    are different too in Java }
+                  javanewtreeok:=
+                    is_java_class_or_interface(_class) and
+                    (pd.jvmmangledbasename(false)<>vmtpd.jvmmangledbasename(false));
+{$endif}
+                  if not(po_reintroduce in pd.procoptions) and
+                     not(po_java_nonvirtual in vmtpd.procoptions) then
+                    if not(is_objc_class_or_protocol(_class))
+{$ifdef jvm}
+                       and (not is_java_class_or_interface(_class) or
+                        javanewtreeok)
+{$endif jvm}
+                       then
                       MessagePos1(pd.fileinfo,parser_w_should_use_override,pd.fullprocname(false))
                     else
                       begin
@@ -341,6 +364,15 @@ implementation
                           dec(tobjectdef(pd.owner.defowner).abstractcnt);
                         result:=true;
                         exit;
+{$ifdef jvm}
+                      end
+                  else
+                    if not javanewtreeok and
+                       is_java_class_or_interface(_class) then
+                      begin
+                        { mangled names are the same -> can only override }
+                        MessagePos1(pd.fileinfo,parser_e_must_use_override,FullTypeName(tdef(vmtpd.owner.defowner),nil))
+{$endif jvm}
                       end;
                   { disable/hide old VMT entry }
                   if updatevalues then

+ 18 - 0
compiler/pdecobj.pas

@@ -782,6 +782,24 @@ implementation
         begin
           if is_java_class_or_interface(pd.struct) then
             begin
+              { mark all non-virtual instance methods as "virtual; final;",
+                because
+                 a) that's the only way to guarantee "non-virtual" behaviour
+                    (other than making them class methods with an explicit self
+                     pointer, but that causes problems with interface mappings
+                     and procvars)
+                 b) if we don't mark them virtual, they don't get added to the
+                    vmt and we can't check whether child classes try to override
+                    them
+              }
+              if is_javaclass(pd.struct) and
+                 not(po_virtualmethod in pd.procoptions) and
+                 not(po_classmethod in pd.procoptions) then
+                begin
+                  include(pd.procoptions,po_virtualmethod);
+                  include(pd.procoptions,po_finalmethod);
+                  include(pd.procoptions,po_java_nonvirtual);
+                end;
             end;
         end;
 

+ 4 - 1
compiler/symconst.pas

@@ -315,7 +315,10 @@ type
       (when calling a regular procedure using the above convention, it will
        simply not see the frame pointer parameter, and since the caller cleans
        up the stack will also remain balanced) }
-    po_delphi_nested_cc
+    po_delphi_nested_cc,
+    { Non-virtual method of a Java class that has been transformed into a
+      "virtual; final;" method for JVM-implementation reasons }
+    po_java_nonvirtual
   );
   tprocoptions=set of tprocoption;
 

+ 2 - 1
compiler/utils/ppudump.pp

@@ -1148,7 +1148,8 @@ const
      (mask:po_objc;            str:'ObjC'),
      (mask:po_enumerator_movenext; str:'EnumeratorMoveNext'),
      (mask:po_optional;        str: 'Optional'),
-     (mask:po_delphi_nested_cc;str: 'Delphi-style nested frameptr')
+     (mask:po_delphi_nested_cc;str: 'Delphi-style nested frameptr'),
+     (mask:po_java_nonvirtual; str: 'Java non-virtual method')
   );
 var
   proctypeoption  : tproctypeoption;