Browse Source

* fixed typecasting to/from classrefdef

git-svn-id: branches/jvmbackend@18558 -
Jonas Maebe 14 years ago
parent
commit
b370314194
1 changed files with 99 additions and 44 deletions
  1. 99 44
      compiler/jvm/njvmcnv.pas

+ 99 - 44
compiler/jvm/njvmcnv.pas

@@ -62,10 +62,16 @@ interface
 
        tjvmasnode = class(tcgasnode)
         protected
+         { to discern beween "obj as tclassref" and "tclassref(obj)" }
+         classreftypecast: boolean;
          function target_specific_typecheck: boolean;override;
         public
          function pass_1 : tnode;override;
          procedure pass_generate_code; override;
+         function dogetcopy: tnode; override;
+         function docompare(p: tnode): boolean; override;
+         constructor ppuload(t: tnodetype; ppufile: tcompilerppufile); override;
+         procedure ppuwrite(ppufile: tcompilerppufile); override;
        end;
 
        tjvmisnode = class(tisnode)
@@ -445,6 +451,8 @@ implementation
            fromdef:=tarraydef(fromdef).elementdef;
            todef:=tarraydef(todef).elementdef;
          end;
+       fromdef:=maybe_find_real_class_definition(fromdef,false);
+       todef:=maybe_find_real_class_definition(todef,false);
       end;
 
 
@@ -486,8 +494,7 @@ implementation
         toclasscompatible,
         procvarconv: boolean;
         fromdef,
-        todef,
-        jlclass: tdef;
+        todef: tdef;
         fromarrtype,
         toarrtype: char;
       begin
@@ -503,13 +510,13 @@ implementation
         fromclasscompatible:=
           (left.resultdef.typ=objectdef) or
           is_dynamic_array(left.resultdef) or
-          ((left.resultdef.typ in [recorddef,stringdef]) and
+          ((left.resultdef.typ in [recorddef,stringdef,classrefdef]) and
            (resultdef.typ=objectdef)) or
           procvarconv;
         toclasscompatible:=
           (resultdef.typ=objectdef) or
           is_dynamic_array(resultdef) or
-          ((resultdef.typ in [recorddef,stringdef]) and
+          ((resultdef.typ in [recorddef,stringdef,classrefdef]) and
            (left.resultdef.typ=objectdef)) or
           procvarconv;
         if fromclasscompatible and toclasscompatible then
@@ -523,6 +530,8 @@ implementation
                 * related to source
                 * a primitive that are represented by the same type in Java
                   (e.g., byte and shortint) }
+
+            { in case of arrays, check the compatibility of the innermost types }
             fromdef:=left.resultdef;
             todef:=resultdef;
             get_most_nested_types(fromdef,todef);
@@ -532,7 +541,10 @@ implementation
                not fromdef.is_related(todef) and
                (todef<>java_jlobject) and
                ((fromarrtype in ['A','R']) or
-                (fromarrtype<>toarrtype)) then
+                (fromarrtype<>toarrtype)) and
+               ((fromdef.typ<>classrefdef) or
+                (todef.typ<>classrefdef) or
+                not tclassrefdef(fromdef).pointeddef.is_related(tclassrefdef(todef).pointeddef)) then
               begin
                 if not check_only and
                    not assignment_side then
@@ -541,6 +553,8 @@ implementation
                     if resultdef.typ=objectdef then
                       resnode:=cloadvmtaddrnode.create(resnode);
                     resnode:=casnode.create(left,resnode);
+                    if resultdef.typ=classrefdef then
+                      tjvmasnode(resnode).classreftypecast:=true;
                     left:=nil;
                   end
               end
@@ -553,31 +567,6 @@ implementation
             exit;
           end;
 
-        { from classrefdef to JLClass and JLObject and back }
-        if (left.resultdef.typ=classrefdef) or
-           (resultdef.typ=classrefdef) then
-          begin
-            if (left.resultdef.typ=classrefdef) and
-               (resultdef.typ=classrefdef) then
-              begin
-                if not tclassrefdef(left.resultdef).pointeddef.is_related(resultdef) and
-                   not tclassrefdef(resultdef).pointeddef.is_related(left.resultdef) then
-                 CGMessage2(type_e_illegal_type_conversion,left.resultdef.typename,resultdef.typename);
-              end
-            else
-              begin
-                jlclass:=search_system_type('JLCLASS').typedef;
-                if (left.resultdef<>jlclass) and
-                   (left.resultdef<>java_jlobject) and
-                   (resultdef<>jlclass) and
-                   (resultdef<>java_jlobject) then
-                  CGMessage2(type_e_illegal_type_conversion,left.resultdef.typename,resultdef.typename);
-              end;
-            result:=true;
-            exit;
-          end;
-
-
         { don't allow conversions between different classes of primitive types,
           except for a few special cases }
 
@@ -748,20 +737,67 @@ implementation
           result:=false;
       end;
 
+    function isclassrefconv(fromdef, todef: tdef): boolean;
+      var
+        jlclass: tdef;
+      begin
+        jlclass:=nil;
+        if fromdef.typ=classrefdef then
+          begin
+            result:=todef=java_jlobject;
+            if not result and
+               (todef.typ=classrefdef) then
+              { the fromdef.is_related(todef) case should not become an as-node,
+                handled in typeconversion itself and ignored since always ok
+                -- this one is not very useful either since everything is plain
+                JLClass anyway, but maybe in the future it will be different }
+              result:=tclassrefdef(todef).pointeddef.is_related(tclassrefdef(fromdef).pointeddef);
+            if not result then
+              begin
+                jlclass:=search_system_type('JLCLASS').typedef;
+                result:=todef=jlclass;
+              end;
+          end
+        else if todef.typ=classrefdef then
+          begin
+            result:=fromdef=java_jlobject;
+            if not result then
+              begin
+                jlclass:=search_system_type('JLCLASS').typedef;
+                result:=fromdef=jlclass;
+              end;
+          end
+        else
+          result:=false;
+      end;
+
 
     var
       fromelt, toelt: tdef;
       realfromdef,
       realtodef: tdef;
     begin
+      if is_java_class_or_interface(node.left.resultdef) and
+         (node.right.resultdef.typ=classrefdef) and
+         ((node.nodetype<>asn) or
+          not tjvmasnode(node).classreftypecast) then
+        begin
+          { handle using normal code }
+          result:=false;
+          exit;
+        end;
       realfromdef:=maybe_find_real_class_definition(node.left.resultdef,false);
       realtodef:=node.right.resultdef;
-      if realtodef.typ=classrefdef then
+      if (realtodef.typ=classrefdef) and
+         ((node.nodetype<>asn) or
+          not tjvmasnode(node).classreftypecast) then
         realtodef:=tclassrefdef(realtodef).pointeddef;
       realtodef:=maybe_find_real_class_definition(realtodef,false);
       result:=isrecordconv(realfromdef,realtodef);
       if not result then
         result:=isstringconv(realfromdef,realtodef);
+      if not result then
+        result:=isclassrefconv(realfromdef,realtodef);
       if not result then
         { dynamic arrays can be converted to java.lang.Object and vice versa }
         if realtodef=java_jlobject then
@@ -786,22 +822,10 @@ implementation
                (fromelt.typ=arraydef)) and
               ((toelt.typ=objectdef) or
                (toelt.typ=arraydef)));
-          end
-        else
-          begin
-            if (node.right.resultdef.typ<>classrefdef) then
-              result:=false
-            else
-              result:=true;
           end;
       if result then
         if node.nodetype=asn then
-          begin
-            if realtodef.typ<>classrefdef then
-              node.resultdef:=realtodef
-            else
-              node.resultdef:=tclassrefdef(realtodef).pointeddef
-          end
+          node.resultdef:=realtodef
         else
           node.resultdef:=pasbool8type;
     end;
@@ -885,6 +909,8 @@ implementation
         checkdef:=java_jlstring;
       if checkdef.typ in [objectdef,recorddef] then
         current_asmdata.CurrAsmList.concat(taicpu.op_sym(opcode,current_asmdata.RefAsmSymbol(tabstractrecorddef(checkdef).jvm_full_typename(true))))
+      else if checkdef.typ=classrefdef then
+        current_asmdata.CurrAsmList.concat(taicpu.op_sym(opcode,current_asmdata.RefAsmSymbol('java/lang/Class')))
       else
         current_asmdata.CurrAsmList.concat(taicpu.op_sym(opcode,current_asmdata.RefAsmSymbol(jvmencodetype(checkdef,false))));
       location_reset(node.location,LOC_REGISTER,OS_ADDR);
@@ -915,6 +941,35 @@ implementation
     end;
 
 
+  function tjvmasnode.dogetcopy: tnode;
+    begin
+      result:=inherited dogetcopy;
+      tjvmasnode(result).classreftypecast:=classreftypecast;
+    end;
+
+
+  function tjvmasnode.docompare(p: tnode): boolean;
+    begin
+      result:=
+        inherited docompare(p) and
+        (tjvmasnode(p).classreftypecast=classreftypecast);
+    end;
+
+
+  constructor tjvmasnode.ppuload(t: tnodetype; ppufile: tcompilerppufile);
+    begin
+      inherited;
+      classreftypecast:=boolean(ppufile.getbyte);
+    end;
+
+
+  procedure tjvmasnode.ppuwrite(ppufile: tcompilerppufile);
+    begin
+      inherited ppuwrite(ppufile);
+      ppufile.putbyte(byte(classreftypecast));
+    end;
+
+
   {*****************************************************************************
                                TJVMIsNode
   *****************************************************************************}