浏览代码

* sign extend all byte/ansichar/word parameters before passing them
to and returning them from sub routines, in order to follow the JVM
specs to the letter (not checked by the JVM bytecode verifiers, but
checked by the Android DEX verifier)
* -> also zero-extend them again at the caller side after returning
from such a function

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

Jonas Maebe 14 年之前
父节点
当前提交
1a7c024ad3
共有 6 个文件被更改,包括 79 次插入7 次删除
  1. 2 0
      compiler/jvm/cpupara.pas
  2. 45 1
      compiler/jvm/hlcgcpu.pas
  3. 18 1
      compiler/jvm/jvmdef.pas
  4. 10 2
      compiler/jvm/njvmcal.pas
  5. 3 2
      compiler/jvm/tgcpu.pas
  6. 1 1
      compiler/ncgcal.pas

+ 2 - 0
compiler/jvm/cpupara.pas

@@ -121,6 +121,7 @@ implementation
         paraloc : pcgparalocation;
         paraloc : pcgparalocation;
         retcgsize  : tcgsize;
         retcgsize  : tcgsize;
       begin
       begin
+        def:=get_para_push_size(def);
         result.init;
         result.init;
         result.alignment:=get_para_align(p.proccalloption);
         result.alignment:=get_para_align(p.proccalloption);
         result.def:=def;
         result.def:=def;
@@ -204,6 +205,7 @@ implementation
                   paracgsize:=OS_ADDR;
                   paracgsize:=OS_ADDR;
                 paradef:=hp.vardef;
                 paradef:=hp.vardef;
               end;
               end;
+            paradef:=get_para_push_size(paradef);
             hp.paraloc[side].reset;
             hp.paraloc[side].reset;
             hp.paraloc[side].size:=paracgsize;
             hp.paraloc[side].size:=paracgsize;
             hp.paraloc[side].def:=paradef;
             hp.paraloc[side].def:=paradef;

+ 45 - 1
compiler/jvm/hlcgcpu.pas

@@ -48,6 +48,8 @@ uses
 
 
       function def2regtyp(def: tdef): tregistertype; override;
       function def2regtyp(def: tdef): tregistertype; override;
 
 
+      procedure a_load_const_cgpara(list : TAsmList;tosize : tdef;a : aint;const cgpara : TCGPara);override;
+
       procedure a_call_name(list : TAsmList;pd : tprocdef;const s : TSymStr; weak: boolean);override;
       procedure a_call_name(list : TAsmList;pd : tprocdef;const s : TSymStr; weak: boolean);override;
       procedure a_call_name_inherited(list : TAsmList;pd : tprocdef;const s : TSymStr);override;
       procedure a_call_name_inherited(list : TAsmList;pd : tprocdef;const s : TSymStr);override;
 
 
@@ -151,6 +153,12 @@ uses
       { performs sign/zero extension as required }
       { performs sign/zero extension as required }
       procedure resize_stack_int_val(list: TAsmList;fromsize,tosize: tcgsize; forarraystore: boolean);
       procedure resize_stack_int_val(list: TAsmList;fromsize,tosize: tcgsize; forarraystore: boolean);
 
 
+      { 8/16 bit unsigned parameters and return values must be sign-extended on
+        the producer side, because the JVM does not support unsigned variants;
+        then they have to be zero-extended again on the consumer side }
+      procedure maybe_resize_stack_para_val(list: TAsmList; retdef: tdef; callside: boolean);
+
+
       property maxevalstackheight: longint read fmaxevalstackheight;
       property maxevalstackheight: longint read fmaxevalstackheight;
 
 
       procedure gen_initialize_fields_code(list:TAsmList);
       procedure gen_initialize_fields_code(list:TAsmList);
@@ -271,6 +279,16 @@ implementation
       end;
       end;
     end;
     end;
 
 
+  procedure thlcgjvm.a_load_const_cgpara(list: TAsmList; tosize: tdef; a: aint; const cgpara: TCGPara);
+    begin
+      tosize:=get_para_push_size(tosize);
+      if tosize=s8inttype then
+        a:=shortint(a)
+      else if tosize=s16inttype then
+        a:=smallint(a);
+      inherited a_load_const_cgpara(list, tosize, a, cgpara);
+    end;
+
   procedure thlcgjvm.a_call_name(list: TAsmList; pd: tprocdef; const s: TSymStr; weak: boolean);
   procedure thlcgjvm.a_call_name(list: TAsmList; pd: tprocdef; const s: TSymStr; weak: boolean);
     begin
     begin
       a_call_name_intern(list,pd,s,false);
       a_call_name_intern(list,pd,s,false);
@@ -702,7 +720,7 @@ implementation
                   st_shortstring:
                   st_shortstring:
                     begin
                     begin
                       inc(parasize);
                       inc(parasize);
-                      a_load_const_stack(list,u8inttype,tstringdef(elemdef).len,R_INTREGISTER);
+                      a_load_const_stack(list,s8inttype,shortint(tstringdef(elemdef).len),R_INTREGISTER);
                       g_call_system_proc(list,'fpc_initialize_array_shortstring');
                       g_call_system_proc(list,'fpc_initialize_array_shortstring');
                     end;
                     end;
                   st_ansistring:
                   st_ansistring:
@@ -1429,6 +1447,7 @@ implementation
   procedure thlcgjvm.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
   procedure thlcgjvm.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
     var
     var
       retdef: tdef;
       retdef: tdef;
+      cgsize: tcgsize;
       opc: tasmop;
       opc: tasmop;
     begin
     begin
       if current_procinfo.procdef.proctypeoption in [potype_constructor,potype_class_constructor] then
       if current_procinfo.procdef.proctypeoption in [potype_constructor,potype_class_constructor] then
@@ -1972,6 +1991,31 @@ implementation
         end;
         end;
     end;
     end;
 
 
+    procedure thlcgjvm.maybe_resize_stack_para_val(list: TAsmList; retdef: tdef; callside: boolean);
+      var
+        cgsize: tcgsize;
+      begin
+        if (retdef.typ=orddef) then
+          begin
+            if (torddef(retdef).ordtype in [u8bit,u16bit,uchar]) and
+               (torddef(retdef).high>=(1 shl (retdef.size*8-1))) then
+              begin
+                cgsize:=OS_NO;
+                if callside then
+                  if torddef(retdef).ordtype in [u8bit,uchar] then
+                    cgsize:=OS_S8
+                  else
+                    cgsize:=OS_S16
+                else if torddef(retdef).ordtype in [u8bit,uchar] then
+                    cgsize:=OS_8
+                  else
+                    cgsize:=OS_16;
+                if cgsize<>OS_NO then
+                  resize_stack_int_val(list,OS_S32,cgsize,false);
+              end;
+          end;
+      end;
+
   procedure thlcgjvm.allocate_implicit_struct_with_base_ref(list: TAsmList; vs: tabstractvarsym; ref: treference);
   procedure thlcgjvm.allocate_implicit_struct_with_base_ref(list: TAsmList; vs: tabstractvarsym; ref: treference);
     var
     var
       tmpref: treference;
       tmpref: treference;

+ 18 - 1
compiler/jvm/jvmdef.pas

@@ -81,6 +81,8 @@ interface
 
 
     function jvmgetcorrespondingclassdef(def: tdef): tdef;
     function jvmgetcorrespondingclassdef(def: tdef): tdef;
 
 
+    function get_para_push_size(def: tdef): tdef;
+
     { threadvars are wrapped via descendents of java.lang.ThreadLocal }
     { threadvars are wrapped via descendents of java.lang.ThreadLocal }
     function jvmgetthreadvardef(def: tdef): tdef;
     function jvmgetthreadvardef(def: tdef): tdef;
 
 
@@ -92,7 +94,7 @@ interface
 implementation
 implementation
 
 
   uses
   uses
-    cutils,cclasses,
+    cutils,cclasses,constexp,
     verbose,systems,
     verbose,systems,
     fmodule,
     fmodule,
     symtable,symconst,symsym,symdef,symcreat,
     symtable,symconst,symsym,symdef,symcreat,
@@ -745,6 +747,21 @@ implementation
       end;
       end;
 
 
 
 
+  function get_para_push_size(def: tdef): tdef;
+    begin
+      result:=def;
+      if def.typ=orddef then
+        case torddef(def).ordtype of
+          u8bit,uchar:
+            if torddef(def).high>127 then
+              result:=s8inttype;
+          u16bit:
+            if torddef(def).high>32767 then
+              result:=s16inttype;
+        end;
+    end;
+
+
     function jvmgetthreadvardef(def: tdef): tdef;
     function jvmgetthreadvardef(def: tdef): tdef;
       begin
       begin
         if (def.typ=arraydef) and
         if (def.typ=arraydef) and

+ 10 - 2
compiler/jvm/njvmcal.pas

@@ -404,8 +404,16 @@ implementation
         if (tabstractprocdef(procdefinition).proctypeoption=potype_constructor) then
         if (tabstractprocdef(procdefinition).proctypeoption=potype_constructor) then
           totalremovesize:=pushedparasize
           totalremovesize:=pushedparasize
         else
         else
-          { even a byte takes up a full stackslot -> align size to multiple of 4 }
-          totalremovesize:=pushedparasize-(align(realresdef.size,4) shr 2);
+          begin
+            { zero-extend unsigned 8/16 bit returns (we have to return them
+              sign-extended to keep the Android verifier happy, and even if that
+              one did not exist a plain Java routine could return a
+              sign-extended value) }
+            if cnf_return_value_used in callnodeflags then
+              thlcgjvm(hlcg).maybe_resize_stack_para_val(current_asmdata.CurrAsmList,realresdef,false);
+            { even a byte takes up a full stackslot -> align size to multiple of 4 }
+            totalremovesize:=pushedparasize-(align(realresdef.size,4) shr 2);
+          end;
         { remove parameters from internal evaluation stack counter (in case of
         { remove parameters from internal evaluation stack counter (in case of
           e.g. no parameters and a result, it can also increase) }
           e.g. no parameters and a result, it can also increase) }
         if totalremovesize>0 then
         if totalremovesize>0 then

+ 3 - 2
compiler/jvm/tgcpu.pas

@@ -191,8 +191,9 @@ unit tgcpu;
               if is_shortstring(def) then
               if is_shortstring(def) then
                 begin
                 begin
                   gettemp(list,java_jlobject.size,java_jlobject.alignment,temptype,ref);
                   gettemp(list,java_jlobject.size,java_jlobject.alignment,temptype,ref);
-                  { add the maxlen parameter }
-                  thlcgjvm(hlcg).a_load_const_stack(list,u8inttype,tstringdef(def).len,R_INTREGISTER);
+                  { add the maxlen parameter (s8inttype because parameters must
+                    be sign extended) }
+                  thlcgjvm(hlcg).a_load_const_stack(list,s8inttype,shortint(tstringdef(def).len),R_INTREGISTER);
                   { call the constructor }
                   { call the constructor }
                   sym:=tsym(tobjectdef(java_shortstring).symtable.find('CREATEEMPTY'));
                   sym:=tsym(tobjectdef(java_shortstring).symtable.find('CREATEEMPTY'));
                   if assigned(sym) and
                   if assigned(sym) and

+ 1 - 1
compiler/ncgcal.pas

@@ -36,7 +36,7 @@ interface
        protected
        protected
           tempcgpara : tcgpara;
           tempcgpara : tcgpara;
           procedure push_addr_para;
           procedure push_addr_para;
-          procedure push_value_para;
+          procedure push_value_para;virtual;
           procedure push_formal_para;virtual;
           procedure push_formal_para;virtual;
           procedure push_copyout_para;virtual;abstract;
           procedure push_copyout_para;virtual;abstract;
        public
        public