diff --git a/compiler/jvm/cpupara.pas b/compiler/jvm/cpupara.pas index 93d38634e8..ddc0773db1 100644 --- a/compiler/jvm/cpupara.pas +++ b/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; diff --git a/compiler/jvm/hlcgcpu.pas b/compiler/jvm/hlcgcpu.pas index d6d7ea306a..9ac0a09319 100644 --- a/compiler/jvm/hlcgcpu.pas +++ b/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; diff --git a/compiler/jvm/jvmdef.pas b/compiler/jvm/jvmdef.pas index b7d53fb5e8..f2855409e7 100644 --- a/compiler/jvm/jvmdef.pas +++ b/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 diff --git a/compiler/jvm/njvmcal.pas b/compiler/jvm/njvmcal.pas index c77ca166cc..e0f303ee98 100644 --- a/compiler/jvm/njvmcal.pas +++ b/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 diff --git a/compiler/jvm/tgcpu.pas b/compiler/jvm/tgcpu.pas index 4984084a51..484a363cd7 100644 --- a/compiler/jvm/tgcpu.pas +++ b/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 diff --git a/compiler/ncgcal.pas b/compiler/ncgcal.pas index 1a207fd499..1a4fd9bcc3 100644 --- a/compiler/ncgcal.pas +++ b/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