瀏覽代碼

* generalized handling of pointers to non-implicit pointer types:
as far as Java is concerned, they're now all arrays of JLObject.
When loading a value from them, we typecast the loaded value
to the appropriate type. This allows typecasting one pointer
type to another without getting verification errors (since an
"array of JLObject" is not compatible with "array of JLString")
- no longer allow dereferencing untyped pointers on the JVM
target, since that always results in invalid bytecode

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

Jonas Maebe 14 年之前
父節點
當前提交
992cc352c6
共有 5 個文件被更改,包括 75 次插入35 次删除
  1. 1 0
      compiler/cgutils.pas
  2. 38 0
      compiler/jvm/hlcgcpu.pas
  3. 12 3
      compiler/jvm/jvmdef.pas
  4. 1 30
      compiler/jvm/njvmcnv.pas
  5. 23 2
      compiler/jvm/njvmmem.pas

+ 1 - 0
compiler/cgutils.pas

@@ -69,6 +69,7 @@ unit cgutils;
          indexbase: tregister;
          indexsymbol: tasmsymbol;
          indexoffset: aint;
+         checkcast: boolean;
 {$endif jvm}
          alignment : byte;
       end;

+ 38 - 0
compiler/jvm/hlcgcpu.pas

@@ -154,6 +154,8 @@ uses
       property maxevalstackheight: longint read fmaxevalstackheight;
 
       procedure gen_initialize_fields_code(list:TAsmList);
+
+      procedure gen_typecheck(list: TAsmList; checkop: tasmop; checkdef: tdef);
      protected
       function get_enum_init_val_ref(def: tdef; out ref: treference): boolean;
 
@@ -1778,6 +1780,8 @@ implementation
       incstack(list,1+ord(size.size>4)-extra_slots);
       if finishandval<>-1 then
         a_op_const_stack(list,OP_AND,size,finishandval);
+      if ref.checkcast then
+        gen_typecheck(list,a_checkcast,size);
     end;
 
   function thlcgjvm.loadstoreopcref(def: tdef; isload: boolean; const ref: treference; out finishandval: aint): tasmop;
@@ -2089,6 +2093,40 @@ implementation
       allocate_implicit_structs_for_st_with_base_ref(list,obj.symtable,ref,fieldvarsym);
     end;
 
+  procedure thlcgjvm.gen_typecheck(list: TAsmList; checkop: tasmop; checkdef: tdef);
+    begin
+      { replace special types with their equivalent class type }
+      if (checkdef.typ=pointerdef) and
+         jvmimplicitpointertype(tpointerdef(checkdef).pointeddef) then
+        checkdef:=tpointerdef(checkdef).pointeddef;
+      if (checkdef=voidpointertype) or
+         (checkdef.typ=formaldef) then
+        checkdef:=java_jlobject
+      else if checkdef.typ=enumdef then
+        checkdef:=tenumdef(checkdef).classdef
+      else if checkdef.typ=setdef then
+        begin
+          if tsetdef(checkdef).elementdef.typ=enumdef then
+            checkdef:=java_juenumset
+          else
+            checkdef:=java_jubitset;
+        end
+      else if checkdef.typ=procvardef then
+        checkdef:=tprocvardef(checkdef).classdef
+      else if is_wide_or_unicode_string(checkdef) then
+        checkdef:=java_jlstring
+      else if is_ansistring(checkdef) then
+        checkdef:=java_ansistring
+      else if is_shortstring(checkdef) then
+        checkdef:=java_shortstring;
+      if checkdef.typ in [objectdef,recorddef] then
+        list.concat(taicpu.op_sym(checkop,current_asmdata.RefAsmSymbol(tabstractrecorddef(checkdef).jvm_full_typename(true))))
+      else if checkdef.typ=classrefdef then
+        list.concat(taicpu.op_sym(checkop,current_asmdata.RefAsmSymbol('java/lang/Class')))
+      else
+        list.concat(taicpu.op_sym(checkop,current_asmdata.RefAsmSymbol(jvmencodetype(checkdef,false))));
+    end;
+
   procedure thlcgjvm.resizestackfpuval(list: TAsmList; fromsize, tosize: tcgsize);
     begin
       if (fromsize=OS_F32) and

+ 12 - 3
compiler/jvm/jvmdef.pas

@@ -253,15 +253,24 @@ implementation
             end;
           pointerdef :
             begin
-              if def=voidpointertype then
+              if is_voidpointer(def) then
                 result:=jvmaddencodedtype(java_jlobject,false,encodedstr,forcesignature,founderror)
+              else if tpointerdef(def).pointeddef.typ in [orddef,floatdef] then
+                begin
+                  encodedstr:=encodedstr+'[';
+                  result:=jvmaddencodedtype(tpointerdef(def).pointeddef,false,encodedstr,forcesignature,founderror);
+                end
               else if jvmimplicitpointertype(tpointerdef(def).pointeddef) then
                 result:=jvmaddencodedtype(tpointerdef(def).pointeddef,false,encodedstr,forcesignature,founderror)
               else
                 begin
-                  { used for internal pointer constructs }
+                  { Semantically, these are pointers to types that are
+                    pointer-based themselves (or typecastable to pointer).
+                    Internally, we represent them all as array of JLObject so that
+                    they are assignment-compatible. We will perform the type
+                    checks when actually loading a value from them }
                   encodedstr:=encodedstr+'[';
-                  result:=jvmaddencodedtype(tpointerdef(def).pointeddef,false,encodedstr,forcesignature,founderror);
+                  result:=jvmaddencodedtype(java_jlobject,false,encodedstr,forcesignature,founderror)
                 end;
             end;
           floatdef :

+ 1 - 30
compiler/jvm/njvmcnv.pas

@@ -1485,36 +1485,7 @@ implementation
         checkdef:=tclassrefdef(node.right.resultdef).pointeddef
       else
         checkdef:=node.right.resultdef;
-      { replace special types with their equivalent class type }
-      if (checkdef.typ=pointerdef) and
-         jvmimplicitpointertype(tpointerdef(checkdef).pointeddef) then
-        checkdef:=tpointerdef(checkdef).pointeddef;
-      if (checkdef=voidpointertype) or
-         (checkdef.typ=formaldef) then
-        checkdef:=java_jlobject
-      else if checkdef.typ=enumdef then
-        checkdef:=tenumdef(checkdef).classdef
-      else if checkdef.typ=setdef then
-        begin
-          if tsetdef(checkdef).elementdef.typ=enumdef then
-            checkdef:=java_juenumset
-          else
-            checkdef:=java_jubitset;
-        end
-      else if checkdef.typ=procvardef then
-        checkdef:=tprocvardef(checkdef).classdef
-      else if is_wide_or_unicode_string(checkdef) then
-        checkdef:=java_jlstring
-      else if is_ansistring(checkdef) then
-        checkdef:=java_ansistring
-      else if is_shortstring(checkdef) then
-        checkdef:=java_shortstring;
-      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))));
+      thlcgjvm(hlcg).gen_typecheck(current_asmdata.CurrAsmList,opcode,checkdef);
       location_reset(node.location,LOC_REGISTER,OS_ADDR);
       node.location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,node.resultdef);
       thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,node.resultdef,node.location.register);

+ 23 - 2
compiler/jvm/njvmmem.pas

@@ -41,6 +41,7 @@ interface
        end;
 
        tjvmderefnode = class(tcgderefnode)
+          function pass_typecheck: tnode; override;
           procedure pass_generate_code; override;
        end;
 
@@ -68,12 +69,25 @@ implementation
                               TJVMDEREFNODE
 *****************************************************************************}
 
+    function tjvmderefnode.pass_typecheck: tnode;
+      begin
+        result:=inherited pass_typecheck;
+        if assigned(result) then
+          exit;
+        { don't allow dereferencing untyped pointers, because how this has to
+          be done depends on whether it's a pointer to an implicit pointer type
+          or not }
+        if is_voidpointer(left.resultdef) then
+          CGMessage(parser_e_illegal_expression);
+      end;
+
+
     procedure tjvmderefnode.pass_generate_code;
       var
         implicitptr: boolean;
       begin
         secondpass(left);
-        implicitptr:=jvmimplicitpointertype(tpointerdef(left.resultdef).pointeddef);
+        implicitptr:=jvmimplicitpointertype(resultdef);
         if implicitptr then
           begin
             { this is basically a typecast: the left node is a regular
@@ -91,11 +105,18 @@ implementation
         else
           begin
             { these are always arrays (used internally for pointers to var
-              parameters stored in nestedfpstructs) }
+              parameters stored in nestedfpstructs, and by programmers for any
+              kind of pointers) }
             hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
             location_reset_ref(location,LOC_REFERENCE,def_cgsize(resultdef),4);
             reference_reset_base(location.reference,left.location.register,0,4);
             location.reference.arrayreftype:=art_indexconst;
+            if (left.nodetype<>addrn) and
+               not(resultdef.typ in [orddef,floatdef]) and
+               not is_voidpointer(resultdef) and
+               ((resultdef.typ<>objectdef) or
+                (find_real_class_definition(tobjectdef(resultdef),false)<>java_jlobject)) then
+              location.reference.checkcast:=true;
           end
       end;