Explorar el Código

* 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 hace 14 años
padre
commit
1a7c024ad3

+ 2 - 0
compiler/jvm/cpupara.pas

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

+ 45 - 1
compiler/jvm/hlcgcpu.pas

@@ -48,6 +48,8 @@ uses
 
       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_inherited(list : TAsmList;pd : tprocdef;const s : TSymStr);override;
 
@@ -151,6 +153,12 @@ uses
       { performs sign/zero extension as required }
       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;
 
       procedure gen_initialize_fields_code(list:TAsmList);
@@ -271,6 +279,16 @@ implementation
       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);
     begin
       a_call_name_intern(list,pd,s,false);
@@ -702,7 +720,7 @@ implementation
                   st_shortstring:
                     begin
                       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');
                     end;
                   st_ansistring:
@@ -1429,6 +1447,7 @@ implementation
   procedure thlcgjvm.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
     var
       retdef: tdef;
+      cgsize: tcgsize;
       opc: tasmop;
     begin
       if current_procinfo.procdef.proctypeoption in [potype_constructor,potype_class_constructor] then
@@ -1972,6 +1991,31 @@ implementation
         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);
     var
       tmpref: treference;

+ 18 - 1
compiler/jvm/jvmdef.pas

@@ -81,6 +81,8 @@ interface
 
     function jvmgetcorrespondingclassdef(def: tdef): tdef;
 
+    function get_para_push_size(def: tdef): tdef;
+
     { threadvars are wrapped via descendents of java.lang.ThreadLocal }
     function jvmgetthreadvardef(def: tdef): tdef;
 
@@ -92,7 +94,7 @@ interface
 implementation
 
   uses
-    cutils,cclasses,
+    cutils,cclasses,constexp,
     verbose,systems,
     fmodule,
     symtable,symconst,symsym,symdef,symcreat,
@@ -745,6 +747,21 @@ implementation
       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;
       begin
         if (def.typ=arraydef) and

+ 10 - 2
compiler/jvm/njvmcal.pas

@@ -404,8 +404,16 @@ implementation
         if (tabstractprocdef(procdefinition).proctypeoption=potype_constructor) then
           totalremovesize:=pushedparasize
         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
           e.g. no parameters and a result, it can also increase) }
         if totalremovesize>0 then

+ 3 - 2
compiler/jvm/tgcpu.pas

@@ -191,8 +191,9 @@ unit tgcpu;
               if is_shortstring(def) then
                 begin
                   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 }
                   sym:=tsym(tobjectdef(java_shortstring).symtable.find('CREATEEMPTY'));
                   if assigned(sym) and

+ 1 - 1
compiler/ncgcal.pas

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