hlcgcpu.pas 100 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563
  1. {
  2. Copyright (c) 1998-2010 by Florian Klaempfl and Jonas Maebe
  3. Member of the Free Pascal development team
  4. This unit implements the jvm high level code generator
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit hlcgcpu;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,
  23. aasmbase,aasmdata,
  24. symbase,symconst,symtype,symdef,symsym,
  25. node,
  26. cpubase, hlcgobj, cgbase, cgutils, parabase;
  27. type
  28. { thlcgjvm }
  29. thlcgjvm = class(thlcgobj)
  30. private
  31. fevalstackheight,
  32. fmaxevalstackheight: longint;
  33. public
  34. constructor create;
  35. procedure incstack(list : TAsmList;slots: longint);
  36. procedure decstack(list : TAsmList;slots: longint);
  37. class function def2regtyp(def: tdef): tregistertype; override;
  38. procedure a_load_const_cgpara(list : TAsmList;tosize : tdef;a : tcgint;const cgpara : TCGPara);override;
  39. function a_call_name(list : TAsmList;pd : tprocdef;const s : TSymStr; const paras: array of pcgpara; forceresdef: tdef; weak: boolean): tcgpara;override;
  40. function a_call_name_inherited(list : TAsmList;pd : tprocdef;const s : TSymStr; const paras: array of pcgpara): tcgpara;override;
  41. function a_call_reg(list: TAsmList; pd: tabstractprocdef; reg: tregister; const paras: array of pcgpara): tcgpara; override;
  42. procedure a_load_const_reg(list : TAsmList;tosize : tdef;a : tcgint;register : tregister);override;
  43. procedure a_load_const_ref(list : TAsmList;tosize : tdef;a : tcgint;const ref : treference);override;
  44. procedure a_load_reg_ref(list : TAsmList;fromsize, tosize : tdef;register : tregister;const ref : treference);override;
  45. procedure a_load_reg_reg(list : TAsmList;fromsize, tosize : tdef;reg1,reg2 : tregister);override;
  46. procedure a_load_ref_reg(list : TAsmList;fromsize, tosize : tdef;const ref : treference;register : tregister);override;
  47. procedure a_load_ref_ref(list : TAsmList;fromsize, tosize : tdef;const sref : treference;const dref : treference);override;
  48. procedure a_loadaddr_ref_reg(list : TAsmList;fromsize, tosize : tdef;const ref : treference;r : tregister);override;
  49. procedure a_op_const_reg(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; reg: TRegister); override;
  50. procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister); override;
  51. procedure a_op_const_ref(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; const ref: TReference); override;
  52. procedure a_op_ref_reg(list: TAsmList; Op: TOpCG; size: tdef; const ref: TReference; reg: TRegister); override;
  53. procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister); override;
  54. procedure a_op_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; reg1, reg2: TRegister); override;
  55. procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation); override;
  56. procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation); override;
  57. procedure a_cmp_const_ref_label(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; const ref: treference; l: tasmlabel); override;
  58. procedure a_cmp_const_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel); override;
  59. procedure a_cmp_ref_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; const ref: treference; reg: tregister; l: tasmlabel); override;
  60. procedure a_cmp_reg_ref_label(list: TAsmList; size: tdef; cmp_op: topcmp; reg: tregister; const ref: treference; l: tasmlabel); override;
  61. procedure a_cmp_reg_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel); override;
  62. procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
  63. procedure g_concatcopy(list : TAsmList;size: tdef; const source,dest : treference);override;
  64. procedure g_copyshortstring(list : TAsmList;const source,dest : treference;strdef:tstringdef);override;
  65. procedure a_loadfpu_ref_ref(list: TAsmList; fromsize, tosize: tdef; const ref1, ref2: treference); override;
  66. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister); override;
  67. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference); override;
  68. procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister); override;
  69. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean); override;
  70. procedure g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean); override;
  71. procedure gen_load_return_value(list:TAsmList);override;
  72. procedure record_generated_code_for_procdef(pd: tprocdef; code, data: TAsmList); override;
  73. procedure g_incrrefcount(list : TAsmList;t: tdef; const ref: treference);override;
  74. procedure g_array_rtti_helper(list: TAsmList; t: tdef; const ref: treference; const highloc: tlocation; const name: string); override;
  75. procedure g_initialize(list : TAsmList;t : tdef;const ref : treference);override;
  76. procedure g_finalize(list : TAsmList;t : tdef;const ref : treference);override;
  77. procedure g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef); override;
  78. procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;var ovloc : tlocation); override;
  79. procedure location_get_data_ref(list:TAsmList;def: tdef; const l:tlocation;var ref:treference;loadref:boolean; alignment: longint);override;
  80. procedure maybe_change_load_node_reg(list: TAsmList; var n: tnode; reload: boolean); override;
  81. procedure g_copyvaluepara_openarray(list: TAsmList; const ref: treference; const lenloc: tlocation; arrdef: tarraydef; destreg: tregister); override;
  82. procedure g_releasevaluepara_openarray(list: TAsmList; arrdef: tarraydef; const l: tlocation); override;
  83. procedure gen_initialize_code(list: TAsmList); override;
  84. procedure gen_entry_code(list: TAsmList); override;
  85. procedure gen_exit_code(list: TAsmList); override;
  86. { unimplemented/unnecessary routines }
  87. procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tdef; src, dst: tregister); override;
  88. procedure a_loadmm_loc_reg(list: TAsmList; fromsize, tosize: tdef; const loc: tlocation; const reg: tregister; shuffle: pmmshuffle); override;
  89. procedure a_loadmm_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister; shuffle: pmmshuffle); override;
  90. procedure a_loadmm_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister; shuffle: pmmshuffle); override;
  91. procedure a_loadmm_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference; shuffle: pmmshuffle); override;
  92. procedure a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; src, dst: tregister; shuffle: pmmshuffle); override;
  93. procedure a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize: tdef; intreg, mmreg: tregister; shuffle: pmmshuffle); override;
  94. procedure a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize: tdef; mmreg, intreg: tregister; shuffle: pmmshuffle); override;
  95. procedure g_stackpointer_alloc(list: TAsmList; size: longint); override;
  96. procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint); override;
  97. procedure g_adjust_self_value(list: TAsmList; procdef: tprocdef; ioffset: aint); override;
  98. procedure g_local_unwind(list: TAsmList; l: TAsmLabel); override;
  99. { JVM-specific routines }
  100. procedure a_load_stack_reg(list : TAsmList;size: tdef;reg: tregister);
  101. { extra_slots are the slots that are used by the reference, and that
  102. will be removed by the store operation }
  103. procedure a_load_stack_ref(list : TAsmList;size: tdef;const ref: treference;extra_slots: longint);
  104. procedure a_load_reg_stack(list : TAsmList;size: tdef;reg: tregister);
  105. { extra_slots are the slots that are used by the reference, and that
  106. will be removed by the load operation }
  107. procedure a_load_ref_stack(list : TAsmList;size: tdef;const ref: treference;extra_slots: longint);
  108. procedure a_load_const_stack(list : TAsmList;size: tdef;a :tcgint; typ: TRegisterType);
  109. procedure a_load_stack_loc(list : TAsmList;size: tdef;const loc: tlocation);
  110. procedure a_load_loc_stack(list : TAsmList;size: tdef;const loc: tlocation);
  111. procedure a_loadfpu_const_stack(list : TAsmList;size: tdef;a :double);
  112. procedure a_op_stack(list : TAsmList;op: topcg; size: tdef; trunc32: boolean);
  113. procedure a_op_const_stack(list : TAsmList;op: topcg; size: tdef;a : tcgint);
  114. procedure a_op_reg_stack(list : TAsmList;op: topcg; size: tdef;reg: tregister);
  115. procedure a_op_ref_stack(list : TAsmList;op: topcg; size: tdef;const ref: treference);
  116. procedure a_op_loc_stack(list : TAsmList;op: topcg; size: tdef;const loc: tlocation);
  117. procedure g_reference_loc(list: TAsmList; def: tdef; const fromloc: tlocation; out toloc: tlocation); override;
  118. { assumes that initdim dimensions have already been pushed on the
  119. evaluation stack, and creates a new array of type arrdef with these
  120. dimensions }
  121. procedure g_newarray(list : TAsmList; arrdef: tdef; initdim: longint);
  122. { gets the length of the array whose reference is stored in arrloc,
  123. and puts it on the evaluation stack }
  124. procedure g_getarraylen(list : TAsmList; const arrloc: tlocation);
  125. { this routine expects that all values are already massaged into the
  126. required form (sign bits xor'ed for gt/lt comparisons for OS_32/OS_64,
  127. see http://stackoverflow.com/questions/4068973/c-performing-signed-comparison-in-unsigned-variables-without-casting ) }
  128. procedure a_cmp_stack_label(list : TAsmlist; size: tdef; cmp_op: topcmp; lab: tasmlabel);
  129. { these 2 routines perform the massaging expected by the previous one }
  130. procedure maybe_adjust_cmp_stackval(list : TAsmlist; size: tdef; cmp_op: topcmp);
  131. function maybe_adjust_cmp_constval(size: tdef; cmp_op: topcmp; a: tcgint): tcgint;
  132. { truncate/sign extend after performing operations on values < 32 bit
  133. that may have overflowed outside the range }
  134. procedure maybe_adjust_op_result(list: TAsmList; op: TOpCg; size: tdef);
  135. { performs sign/zero extension as required }
  136. procedure resize_stack_int_val(list: TAsmList;fromsize,tosize: tdef; formemstore: boolean);
  137. { 8/16 bit unsigned parameters and return values must be sign-extended on
  138. the producer side, because the JVM does not support unsigned variants;
  139. then they have to be zero-extended again on the consumer side }
  140. procedure maybe_resize_stack_para_val(list: TAsmList; retdef: tdef; callside: boolean);
  141. { adjust the stack height after a call based on the specified number of
  142. slots used for parameters and the provided resultdef }
  143. procedure g_adjust_stack_after_call(list: TAsmList; pd: tabstractprocdef; paraheight: longint; forceresdef: tdef);
  144. property maxevalstackheight: longint read fmaxevalstackheight;
  145. procedure gen_initialize_fields_code(list:TAsmList);
  146. procedure gen_typecheck(list: TAsmList; checkop: tasmop; checkdef: tdef);
  147. protected
  148. procedure a_load_const_stack_intern(list : TAsmList;size : tdef;a : tcgint; typ: TRegisterType; legalize_const: boolean);
  149. function get_enum_init_val_ref(def: tdef; out ref: treference): boolean;
  150. procedure allocate_implicit_structs_for_st_with_base_ref(list: TAsmList; st: tsymtable; const ref: treference; allocvartyp: tsymtyp);
  151. procedure allocate_enum_with_base_ref(list: TAsmList; vs: tabstractvarsym; const initref: treference; destbaseref: treference);
  152. procedure allocate_implicit_struct_with_base_ref(list: TAsmList; vs: tabstractvarsym; ref: treference);
  153. procedure gen_load_uninitialized_function_result(list: TAsmList; pd: tprocdef; resdef: tdef; const resloc: tcgpara); override;
  154. procedure g_copyvalueparas(p: TObject; arg: pointer); override;
  155. procedure inittempvariables(list:TAsmList);override;
  156. function g_call_system_proc_intern(list: TAsmList; pd: tprocdef; const paras: array of pcgpara; forceresdef: tdef): tcgpara; override;
  157. { in case of an array, the array base address and index have to be
  158. put on the evaluation stack before the stored value; similarly, for
  159. fields the self pointer has to be loaded first. Also checks whether
  160. the reference is valid. If dup is true, the necessary values are stored
  161. twice. Returns how many stack slots have been consumed, disregarding
  162. the "dup". }
  163. function prepare_stack_for_ref(list: TAsmList; const ref: treference; dup: boolean): longint;
  164. { return the load/store opcode to load/store from/to ref; if the result
  165. has to be and'ed after a load to get the final value, that constant
  166. is returned in finishandval (otherwise that value is set to -1) }
  167. function loadstoreopcref(def: tdef; isload: boolean; const ref: treference; out finishandval: tcgint): tasmop;
  168. { return the load/store opcode to load/store from/to reg; if the result
  169. has to be and'ed after a load to get the final value, that constant
  170. is returned in finishandval (otherwise that value is set to -1) }
  171. function loadstoreopc(def: tdef; isload, isarray: boolean; out finishandval: tcgint): tasmop;
  172. procedure resizestackfpuval(list: TAsmList; fromsize, tosize: tcgsize);
  173. { in case of an OS_32 OP_DIV, we have to use an OS_S64 OP_IDIV because the
  174. JVM does not support unsigned divisions }
  175. procedure maybepreparedivu32(list: TAsmList; var op: topcg; size: tdef; out isdivu32: boolean);
  176. { common implementation of a_call_* }
  177. function a_call_name_intern(list : TAsmList;pd : tprocdef;const s : TSymStr; forceresdef: tdef; inheritedcall: boolean): tcgpara;
  178. { concatcopy helpers }
  179. procedure concatcopy_normal_array(list: TAsmList; size: tdef; const source, dest: treference);
  180. procedure concatcopy_record(list: TAsmList; size: tdef; const source, dest: treference);
  181. procedure concatcopy_set(list: TAsmList; size: tdef; const source, dest: treference);
  182. procedure concatcopy_shortstring(list: TAsmList; size: tdef; const source, dest: treference);
  183. end;
  184. procedure create_hlcodegen;
  185. const
  186. opcmp2if: array[topcmp] of tasmop = (A_None,
  187. a_ifeq,a_ifgt,a_iflt,a_ifge,a_ifle,
  188. a_ifne,a_ifle,a_iflt,a_ifge,a_ifgt);
  189. implementation
  190. uses
  191. verbose,cutils,globals,fmodule,constexp,
  192. defutil,
  193. aasmtai,aasmcpu,
  194. symtable,symcpu,jvmdef,
  195. procinfo,cpuinfo,cgcpu,tgobj;
  196. const
  197. TOpCG2IAsmOp : array[topcg] of TAsmOp=( { not = xor -1 }
  198. A_None,A_None,a_iadd,a_iand,A_none,a_idiv,a_imul,a_imul,a_ineg,A_None,a_ior,a_ishr,a_ishl,a_iushr,a_isub,a_ixor,A_None,A_None
  199. );
  200. TOpCG2LAsmOp : array[topcg] of TAsmOp=( { not = xor -1 }
  201. A_None,A_None,a_ladd,a_land,A_none,a_ldiv,a_lmul,a_lmul,a_lneg,A_None,a_lor,a_lshr,a_lshl,a_lushr,a_lsub,a_lxor,A_None,A_None
  202. );
  203. constructor thlcgjvm.create;
  204. begin
  205. fevalstackheight:=0;
  206. fmaxevalstackheight:=0;
  207. end;
  208. procedure thlcgjvm.incstack(list: TasmList;slots: longint);
  209. begin
  210. if slots=0 then
  211. exit;
  212. inc(fevalstackheight,slots);
  213. if (fevalstackheight>fmaxevalstackheight) then
  214. fmaxevalstackheight:=fevalstackheight;
  215. if cs_asm_regalloc in current_settings.globalswitches then
  216. list.concat(tai_comment.Create(strpnew(' allocated '+tostr(slots)+', stack height = '+tostr(fevalstackheight))));
  217. end;
  218. procedure thlcgjvm.decstack(list: TAsmList;slots: longint);
  219. begin
  220. if slots=0 then
  221. exit;
  222. dec(fevalstackheight,slots);
  223. if (fevalstackheight<0) and
  224. not(cs_no_regalloc in current_settings.globalswitches) then
  225. internalerror(2010120501);
  226. if cs_asm_regalloc in current_settings.globalswitches then
  227. list.concat(tai_comment.Create(strpnew(' freed '+tostr(slots)+', stack height = '+tostr(fevalstackheight))));
  228. end;
  229. class function thlcgjvm.def2regtyp(def: tdef): tregistertype;
  230. begin
  231. case def.typ of
  232. { records and enums are implemented via classes }
  233. recorddef,
  234. enumdef,
  235. setdef:
  236. result:=R_ADDRESSREGISTER;
  237. { shortstrings are implemented via classes }
  238. else if is_shortstring(def) or
  239. { voiddef can only be typecasted into (implicit) pointers }
  240. is_void(def) then
  241. result:=R_ADDRESSREGISTER
  242. else
  243. result:=inherited;
  244. end;
  245. end;
  246. procedure thlcgjvm.a_load_const_cgpara(list: TAsmList; tosize: tdef; a: tcgint; const cgpara: TCGPara);
  247. begin
  248. tosize:=get_para_push_size(tosize);
  249. if tosize=s8inttype then
  250. a:=shortint(a)
  251. else if tosize=s16inttype then
  252. a:=smallint(a);
  253. inherited a_load_const_cgpara(list, tosize, a, cgpara);
  254. end;
  255. function thlcgjvm.a_call_name(list: TAsmList; pd: tprocdef; const s: TSymStr; const paras: array of pcgpara; forceresdef: tdef; weak: boolean): tcgpara;
  256. begin
  257. result:=a_call_name_intern(list,pd,s,forceresdef,false);
  258. end;
  259. function thlcgjvm.a_call_name_inherited(list: TAsmList; pd: tprocdef; const s: TSymStr; const paras: array of pcgpara): tcgpara;
  260. begin
  261. result:=a_call_name_intern(list,pd,s,nil,true);
  262. end;
  263. function thlcgjvm.a_call_reg(list: TAsmList; pd: tabstractprocdef; reg: tregister; const paras: array of pcgpara): tcgpara;
  264. begin
  265. internalerror(2012042824);
  266. result.init;
  267. end;
  268. procedure thlcgjvm.a_load_const_stack_intern(list : TAsmList;size : tdef;a : tcgint; typ: TRegisterType; legalize_const: boolean);
  269. begin
  270. if legalize_const and
  271. (typ=R_INTREGISTER) and
  272. (size.typ=orddef) then
  273. begin
  274. { uses specific byte/short array store instructions, and the Dalvik
  275. VM does not like it if we store values outside the range }
  276. case torddef(size).ordtype of
  277. u8bit:
  278. a:=shortint(a);
  279. u16bit:
  280. a:=smallint(a);
  281. end;
  282. end;
  283. a_load_const_stack(list,size,a,typ);
  284. end;
  285. procedure thlcgjvm.a_load_const_stack(list : TAsmList;size : tdef;a : tcgint; typ: TRegisterType);
  286. const
  287. int2opc: array[-1..5] of tasmop = (a_iconst_m1,a_iconst_0,a_iconst_1,
  288. a_iconst_2,a_iconst_3,a_iconst_4,a_iconst_5);
  289. begin
  290. case typ of
  291. R_INTREGISTER:
  292. begin
  293. case def_cgsize(size) of
  294. OS_8,OS_16,OS_32,
  295. OS_S8,OS_S16,OS_S32:
  296. begin
  297. { convert cardinals to longints }
  298. a:=longint(a);
  299. if (a>=-1) and
  300. (a<=5) then
  301. list.concat(taicpu.op_none(int2opc[a]))
  302. else if (a>=low(shortint)) and
  303. (a<=high(shortint)) then
  304. list.concat(taicpu.op_const(a_bipush,a))
  305. else if (a>=low(smallint)) and
  306. (a<=high(smallint)) then
  307. list.concat(taicpu.op_const(a_sipush,a))
  308. else
  309. list.concat(taicpu.op_const(a_ldc,a));
  310. { for android verifier }
  311. if (size.typ=orddef) and
  312. (torddef(size).ordtype=uwidechar) then
  313. list.concat(taicpu.op_none(a_i2c));
  314. end;
  315. OS_64,OS_S64:
  316. begin
  317. case a of
  318. 0:
  319. list.concat(taicpu.op_none(a_lconst_0));
  320. 1:
  321. list.concat(taicpu.op_none(a_lconst_1));
  322. else
  323. list.concat(taicpu.op_const(a_ldc2_w,a));
  324. end;
  325. incstack(list,1);
  326. end;
  327. else
  328. internalerror(2010110702);
  329. end;
  330. end;
  331. R_ADDRESSREGISTER:
  332. begin
  333. if a<>0 then
  334. internalerror(2010110701);
  335. list.concat(taicpu.op_none(a_aconst_null));
  336. end;
  337. else
  338. internalerror(2010110703);
  339. end;
  340. incstack(list,1);
  341. end;
  342. procedure thlcgjvm.a_load_stack_loc(list: TAsmList; size: tdef; const loc: tlocation);
  343. begin
  344. case loc.loc of
  345. LOC_REGISTER,LOC_CREGISTER,
  346. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  347. a_load_stack_reg(list,size,loc.register);
  348. LOC_REFERENCE:
  349. a_load_stack_ref(list,size,loc.reference,prepare_stack_for_ref(list,loc.reference,false));
  350. else
  351. internalerror(2011020501);
  352. end;
  353. end;
  354. procedure thlcgjvm.a_load_loc_stack(list: TAsmList;size: tdef;const loc: tlocation);
  355. begin
  356. case loc.loc of
  357. LOC_REGISTER,LOC_CREGISTER,
  358. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  359. a_load_reg_stack(list,size,loc.register);
  360. LOC_REFERENCE,LOC_CREFERENCE:
  361. a_load_ref_stack(list,size,loc.reference,prepare_stack_for_ref(list,loc.reference,false));
  362. LOC_CONSTANT:
  363. a_load_const_stack(list,size,loc.value,def2regtyp(size));
  364. else
  365. internalerror(2011010401);
  366. end;
  367. end;
  368. procedure thlcgjvm.a_loadfpu_const_stack(list: TAsmList; size: tdef; a: double);
  369. begin
  370. case tfloatdef(size).floattype of
  371. s32real:
  372. begin
  373. if a=0.0 then
  374. list.concat(taicpu.op_none(a_fconst_0))
  375. else if a=1.0 then
  376. list.concat(taicpu.op_none(a_fconst_1))
  377. else if a=2.0 then
  378. list.concat(taicpu.op_none(a_fconst_2))
  379. else
  380. list.concat(taicpu.op_single(a_ldc,a));
  381. incstack(list,1);
  382. end;
  383. s64real:
  384. begin
  385. if a=0.0 then
  386. list.concat(taicpu.op_none(a_dconst_0))
  387. else if a=1.0 then
  388. list.concat(taicpu.op_none(a_dconst_1))
  389. else
  390. list.concat(taicpu.op_double(a_ldc2_w,a));
  391. incstack(list,2);
  392. end
  393. else
  394. internalerror(2011010501);
  395. end;
  396. end;
  397. procedure thlcgjvm.a_op_stack(list: TAsmList; op: topcg; size: tdef; trunc32: boolean);
  398. var
  399. cgsize: tcgsize;
  400. begin
  401. if not trunc32 then
  402. cgsize:=def_cgsize(size)
  403. else
  404. begin
  405. resize_stack_int_val(list,u32inttype,s64inttype,false);
  406. cgsize:=OS_S64;
  407. end;
  408. case cgsize of
  409. OS_8,OS_S8,
  410. OS_16,OS_S16,
  411. OS_32,OS_S32:
  412. begin
  413. { not = xor 1 for boolean, xor -1 for the rest}
  414. if op=OP_NOT then
  415. begin
  416. if not is_pasbool(size) then
  417. a_load_const_stack(list,s32inttype,high(cardinal),R_INTREGISTER)
  418. else
  419. a_load_const_stack(list,size,1,R_INTREGISTER);
  420. op:=OP_XOR;
  421. end;
  422. if TOpCG2IAsmOp[op]=A_None then
  423. internalerror(2010120532);
  424. list.concat(taicpu.op_none(TOpCG2IAsmOp[op]));
  425. maybe_adjust_op_result(list,op,size);
  426. if op<>OP_NEG then
  427. decstack(list,1);
  428. end;
  429. OS_64,OS_S64:
  430. begin
  431. { unsigned 64 bit division must be done via a helper }
  432. if op=OP_DIV then
  433. internalerror(2010120530);
  434. { not = xor 1 for boolean, xor -1 for the rest}
  435. if op=OP_NOT then
  436. begin
  437. if not is_pasbool(size) then
  438. a_load_const_stack(list,s64inttype,-1,R_INTREGISTER)
  439. else
  440. a_load_const_stack(list,s64inttype,1,R_INTREGISTER);
  441. op:=OP_XOR;
  442. end;
  443. if TOpCG2LAsmOp[op]=A_None then
  444. internalerror(2010120533);
  445. list.concat(taicpu.op_none(TOpCG2LAsmOp[op]));
  446. case op of
  447. OP_NOT,
  448. OP_NEG:
  449. ;
  450. { the second argument here is an int rather than a long }
  451. OP_SHL,OP_SHR,OP_SAR:
  452. decstack(list,1);
  453. else
  454. decstack(list,2);
  455. end;
  456. end;
  457. else
  458. internalerror(2010120531);
  459. end;
  460. if trunc32 then
  461. begin
  462. list.concat(taicpu.op_none(a_l2i));
  463. decstack(list,1);
  464. end;
  465. end;
  466. procedure thlcgjvm.a_op_const_stack(list: TAsmList;op: topcg;size: tdef;a: tcgint);
  467. var
  468. trunc32: boolean;
  469. begin
  470. maybepreparedivu32(list,op,size,trunc32);
  471. case op of
  472. OP_NEG,OP_NOT:
  473. internalerror(2011010801);
  474. OP_SHL,OP_SHR,OP_SAR:
  475. { the second argument here is an int rather than a long }
  476. a_load_const_stack(list,s32inttype,a,R_INTREGISTER);
  477. else
  478. a_load_const_stack(list,size,a,R_INTREGISTER);
  479. end;
  480. a_op_stack(list,op,size,trunc32);
  481. end;
  482. procedure thlcgjvm.a_op_reg_stack(list: TAsmList; op: topcg; size: tdef; reg: tregister);
  483. var
  484. trunc32: boolean;
  485. begin
  486. maybepreparedivu32(list,op,size,trunc32);
  487. case op of
  488. OP_SHL,OP_SHR,OP_SAR:
  489. if not is_64bitint(size) then
  490. a_load_reg_stack(list,size,reg)
  491. else
  492. begin
  493. { the second argument here is an int rather than a long }
  494. if getsubreg(reg)=R_SUBQ then
  495. internalerror(2011010802);
  496. a_load_reg_stack(list,s32inttype,reg)
  497. end
  498. else
  499. a_load_reg_stack(list,size,reg);
  500. end;
  501. a_op_stack(list,op,size,trunc32);
  502. end;
  503. procedure thlcgjvm.a_op_ref_stack(list: TAsmList; op: topcg; size: tdef; const ref: treference);
  504. var
  505. trunc32: boolean;
  506. begin
  507. { ref must not be the stack top, because that may indicate an error
  508. (it means that we will perform an operation of the stack top onto
  509. itself, so that means the two values have been loaded manually prior
  510. to calling this routine, instead of letting this routine load one of
  511. them; if something like that is needed, call a_op_stack() directly) }
  512. if ref.base=NR_EVAL_STACK_BASE then
  513. internalerror(2010121102);
  514. maybepreparedivu32(list,op,size,trunc32);
  515. case op of
  516. OP_SHL,OP_SHR,OP_SAR:
  517. begin
  518. if not is_64bitint(size) then
  519. a_load_ref_stack(list,size,ref,prepare_stack_for_ref(list,ref,false))
  520. else
  521. a_load_ref_stack(list,s32inttype,ref,prepare_stack_for_ref(list,ref,false));
  522. end;
  523. else
  524. a_load_ref_stack(list,size,ref,prepare_stack_for_ref(list,ref,false));
  525. end;
  526. a_op_stack(list,op,size,trunc32);
  527. end;
  528. procedure thlcgjvm.a_op_loc_stack(list: TAsmList; op: topcg; size: tdef; const loc: tlocation);
  529. begin
  530. case loc.loc of
  531. LOC_REGISTER,LOC_CREGISTER:
  532. a_op_reg_stack(list,op,size,loc.register);
  533. LOC_REFERENCE,LOC_CREFERENCE:
  534. a_op_ref_stack(list,op,size,loc.reference);
  535. LOC_CONSTANT:
  536. a_op_const_stack(list,op,size,loc.value);
  537. else
  538. internalerror(2011011415)
  539. end;
  540. end;
  541. procedure thlcgjvm.g_reference_loc(list: TAsmList; def: tdef; const fromloc: tlocation; out toloc: tlocation);
  542. begin
  543. case fromloc.loc of
  544. LOC_CREFERENCE,
  545. LOC_REFERENCE:
  546. begin
  547. toloc:=fromloc;
  548. if (fromloc.reference.base<>NR_NO) and
  549. (fromloc.reference.base<>current_procinfo.framepointer) and
  550. (fromloc.reference.base<>NR_STACK_POINTER_REG) then
  551. g_allocload_reg_reg(list,voidpointertype,fromloc.reference.base,toloc.reference.base,R_ADDRESSREGISTER);
  552. case fromloc.reference.arrayreftype of
  553. art_indexreg:
  554. begin
  555. { all array indices in Java are 32 bit ints }
  556. g_allocload_reg_reg(list,s32inttype,fromloc.reference.index,toloc.reference.index,R_INTREGISTER);
  557. end;
  558. art_indexref:
  559. begin
  560. { base register of the address of the index -> pointer }
  561. if (fromloc.reference.indexbase<>NR_NO) and
  562. (fromloc.reference.indexbase<>NR_STACK_POINTER_REG) then
  563. g_allocload_reg_reg(list,voidpointertype,fromloc.reference.indexbase,toloc.reference.indexbase,R_ADDRESSREGISTER);
  564. end;
  565. end;
  566. end;
  567. else
  568. inherited;
  569. end;
  570. end;
  571. procedure thlcgjvm.g_newarray(list: TAsmList; arrdef: tdef; initdim: longint);
  572. var
  573. recref,
  574. enuminitref: treference;
  575. elemdef: tdef;
  576. i: longint;
  577. mangledname: string;
  578. opc: tasmop;
  579. primitivetype: boolean;
  580. begin
  581. elemdef:=arrdef;
  582. if initdim>1 then
  583. begin
  584. { multianewarray typedesc ndim }
  585. list.concat(taicpu.op_sym_const(a_multianewarray,
  586. current_asmdata.RefAsmSymbol(jvmarrtype(elemdef,primitivetype)),initdim));
  587. { has to be a multi-dimensional array type }
  588. if primitivetype then
  589. internalerror(2011012207);
  590. end
  591. else
  592. begin
  593. { for primitive types:
  594. newarray typedesc
  595. for reference types:
  596. anewarray typedesc
  597. }
  598. { get the type of the elements of the array we are creating }
  599. elemdef:=tarraydef(arrdef).elementdef;
  600. mangledname:=jvmarrtype(elemdef,primitivetype);
  601. if primitivetype then
  602. opc:=a_newarray
  603. else
  604. opc:=a_anewarray;
  605. list.concat(taicpu.op_sym(opc,current_asmdata.RefAsmSymbol(mangledname)));
  606. end;
  607. { all dimensions are removed from the stack, an array reference is
  608. added }
  609. decstack(list,initdim-1);
  610. { in case of an array of records, sets or shortstrings, initialise }
  611. elemdef:=tarraydef(arrdef).elementdef;
  612. for i:=1 to pred(initdim) do
  613. elemdef:=tarraydef(elemdef).elementdef;
  614. if (elemdef.typ in [recorddef,setdef]) or
  615. ((elemdef.typ=enumdef) and
  616. get_enum_init_val_ref(elemdef,enuminitref)) or
  617. is_shortstring(elemdef) or
  618. ((elemdef.typ=procvardef) and
  619. not tprocvardef(elemdef).is_addressonly) or
  620. is_ansistring(elemdef) or
  621. is_wide_or_unicode_string(elemdef) or
  622. is_dynamic_array(elemdef) then
  623. begin
  624. { duplicate array instance }
  625. list.concat(taicpu.op_none(a_dup));
  626. incstack(list,1);
  627. a_load_const_stack(list,s32inttype,initdim-1,R_INTREGISTER);
  628. case elemdef.typ of
  629. arraydef:
  630. g_call_system_proc(list,'fpc_initialize_array_dynarr',[],nil);
  631. recorddef,setdef,procvardef:
  632. begin
  633. tg.gethltemp(list,elemdef,elemdef.size,tt_persistent,recref);
  634. a_load_ref_stack(list,elemdef,recref,prepare_stack_for_ref(list,recref,false));
  635. case elemdef.typ of
  636. recorddef:
  637. g_call_system_proc(list,'fpc_initialize_array_record',[],nil);
  638. setdef:
  639. begin
  640. if tsetdef(elemdef).elementdef.typ=enumdef then
  641. g_call_system_proc(list,'fpc_initialize_array_enumset',[],nil)
  642. else
  643. g_call_system_proc(list,'fpc_initialize_array_bitset',[],nil)
  644. end;
  645. procvardef:
  646. g_call_system_proc(list,'fpc_initialize_array_procvar',[],nil);
  647. end;
  648. tg.ungettemp(list,recref);
  649. end;
  650. enumdef:
  651. begin
  652. a_load_ref_stack(list,java_jlobject,enuminitref,prepare_stack_for_ref(list,enuminitref,false));
  653. g_call_system_proc(list,'fpc_initialize_array_object',[],nil);
  654. end;
  655. stringdef:
  656. begin
  657. case tstringdef(elemdef).stringtype of
  658. st_shortstring:
  659. begin
  660. a_load_const_stack_intern(list,u8inttype,tstringdef(elemdef).len,R_INTREGISTER,true);
  661. g_call_system_proc(list,'fpc_initialize_array_shortstring',[],nil);
  662. end;
  663. st_ansistring:
  664. g_call_system_proc(list,'fpc_initialize_array_ansistring',[],nil);
  665. st_unicodestring,
  666. st_widestring:
  667. g_call_system_proc(list,'fpc_initialize_array_unicodestring',[],nil);
  668. else
  669. internalerror(2011081801);
  670. end;
  671. end;
  672. else
  673. internalerror(2011081801);
  674. end;
  675. end;
  676. end;
  677. procedure thlcgjvm.g_getarraylen(list: TAsmList; const arrloc: tlocation);
  678. var
  679. nillab,endlab: tasmlabel;
  680. begin
  681. { inline because we have to use the arraylength opcode, which
  682. cannot be represented directly in Pascal. Even though the JVM
  683. supports allocated arrays with length=0, we still also have to
  684. check for nil pointers because even if FPC always generates
  685. allocated empty arrays under all circumstances, external Java
  686. code could pass in nil pointers.
  687. Note that this means that assigned(arr) can be different from
  688. length(arr)<>0 for dynamic arrays when targeting the JVM.
  689. }
  690. current_asmdata.getjumplabel(nillab);
  691. current_asmdata.getjumplabel(endlab);
  692. { if assigned(arr) ... }
  693. a_load_loc_stack(list,java_jlobject,arrloc);
  694. list.concat(taicpu.op_none(a_dup));
  695. incstack(list,1);
  696. list.concat(taicpu.op_sym(a_ifnull,nillab));
  697. decstack(list,1);
  698. { ... then result:=arraylength(arr) ... }
  699. list.concat(taicpu.op_none(a_arraylength));
  700. a_jmp_always(list,endlab);
  701. { ... else result:=0 }
  702. a_label(list,nillab);
  703. list.concat(taicpu.op_none(a_pop));
  704. decstack(list,1);
  705. list.concat(taicpu.op_none(a_iconst_0));
  706. incstack(list,1);
  707. a_label(list,endlab);
  708. end;
  709. procedure thlcgjvm.a_cmp_stack_label(list: TAsmlist; size: tdef; cmp_op: topcmp; lab: tasmlabel);
  710. const
  711. opcmp2icmp: array[topcmp] of tasmop = (A_None,
  712. a_if_icmpeq,a_if_icmpgt,a_if_icmplt,a_if_icmpge,a_if_icmple,
  713. a_if_icmpne,a_if_icmple,a_if_icmplt,a_if_icmpge,a_if_icmpgt);
  714. var
  715. cgsize: tcgsize;
  716. begin
  717. case def2regtyp(size) of
  718. R_INTREGISTER:
  719. begin
  720. cgsize:=def_cgsize(size);
  721. case cgsize of
  722. OS_S8,OS_8,
  723. OS_16,OS_S16,
  724. OS_S32,OS_32:
  725. begin
  726. list.concat(taicpu.op_sym(opcmp2icmp[cmp_op],lab));
  727. decstack(list,2);
  728. end;
  729. OS_64,OS_S64:
  730. begin
  731. list.concat(taicpu.op_none(a_lcmp));
  732. decstack(list,3);
  733. list.concat(taicpu.op_sym(opcmp2if[cmp_op],lab));
  734. decstack(list,1);
  735. end;
  736. else
  737. internalerror(2010120538);
  738. end;
  739. end;
  740. R_ADDRESSREGISTER:
  741. begin
  742. case cmp_op of
  743. OC_EQ:
  744. list.concat(taicpu.op_sym(a_if_acmpeq,lab));
  745. OC_NE:
  746. list.concat(taicpu.op_sym(a_if_acmpne,lab));
  747. else
  748. internalerror(2010120537);
  749. end;
  750. decstack(list,2);
  751. end;
  752. else
  753. internalerror(2010120538);
  754. end;
  755. end;
  756. procedure thlcgjvm.maybe_adjust_cmp_stackval(list: TAsmlist; size: tdef; cmp_op: topcmp);
  757. begin
  758. { use cmp_op because eventually that's what indicates the
  759. signed/unsigned character of the operation, not the size... }
  760. if (cmp_op in [OC_EQ,OC_NE,OC_LT,OC_LTE,OC_GT,OC_GTE]) or
  761. (def2regtyp(size)<>R_INTREGISTER) then
  762. exit;
  763. { http://stackoverflow.com/questions/4068973/c-performing-signed-comparison-in-unsigned-variables-without-casting }
  764. case def_cgsize(size) of
  765. OS_32,OS_S32:
  766. a_op_const_stack(list,OP_XOR,size,cardinal($80000000));
  767. OS_64,OS_S64:
  768. a_op_const_stack(list,OP_XOR,size,tcgint($8000000000000000));
  769. end;
  770. end;
  771. function thlcgjvm.maybe_adjust_cmp_constval(size: tdef; cmp_op: topcmp; a: tcgint): tcgint;
  772. begin
  773. result:=a;
  774. { use cmp_op because eventually that's what indicates the
  775. signed/unsigned character of the operation, not the size... }
  776. if (cmp_op in [OC_EQ,OC_NE,OC_LT,OC_LTE,OC_GT,OC_GTE]) or
  777. (def2regtyp(size)<>R_INTREGISTER) then
  778. exit;
  779. case def_cgsize(size) of
  780. OS_32,OS_S32:
  781. result:=a xor cardinal($80000000);
  782. OS_64,OS_S64:
  783. result:=a xor tcgint($8000000000000000);
  784. end;
  785. end;
  786. procedure thlcgjvm.maybe_adjust_op_result(list: TAsmList; op: TOpCg; size: tdef);
  787. const
  788. overflowops = [OP_MUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
  789. begin
  790. if ((op in overflowops) or
  791. (current_settings.cputype=cpu_dalvik)) and
  792. (def_cgsize(size) in [OS_8,OS_S8,OS_16,OS_S16]) then
  793. resize_stack_int_val(list,s32inttype,size,false);
  794. end;
  795. procedure thlcgjvm.gen_load_uninitialized_function_result(list: TAsmList; pd: tprocdef; resdef: tdef; const resloc: tcgpara);
  796. begin
  797. { constructors don't return anything in Java }
  798. if pd.proctypeoption=potype_constructor then
  799. exit;
  800. { must return a value of the correct type on the evaluation stack }
  801. case def2regtyp(resdef) of
  802. R_INTREGISTER,
  803. R_ADDRESSREGISTER:
  804. a_load_const_cgpara(list,resdef,0,resloc);
  805. R_FPUREGISTER:
  806. case tfloatdef(resdef).floattype of
  807. s32real:
  808. begin
  809. list.concat(taicpu.op_none(a_fconst_0));
  810. incstack(list,1);
  811. end;
  812. s64real:
  813. begin
  814. list.concat(taicpu.op_none(a_dconst_0));
  815. incstack(list,2);
  816. end;
  817. else
  818. internalerror(2011010302);
  819. end
  820. else
  821. internalerror(2011010301);
  822. end;
  823. end;
  824. procedure thlcgjvm.g_copyvalueparas(p: TObject; arg: pointer);
  825. var
  826. list: tasmlist;
  827. tmpref: treference;
  828. begin
  829. { zero-extend < 32 bit primitive types (FPC can zero-extend when calling,
  830. but that doesn't help when we're called from Java code or indirectly
  831. as a procvar -- exceptions: widechar (Java-specific type) and ordinal
  832. types whose upper bound does not set the sign bit }
  833. if (tsym(p).typ=paravarsym) and
  834. (tparavarsym(p).varspez in [vs_value,vs_const]) and
  835. (tparavarsym(p).vardef.typ=orddef) and
  836. not is_pasbool(tparavarsym(p).vardef) and
  837. not is_widechar(tparavarsym(p).vardef) and
  838. (tparavarsym(p).vardef.size<4) and
  839. not is_signed(tparavarsym(p).vardef) and
  840. (torddef(tparavarsym(p).vardef).high>=(1 shl (tparavarsym(p).vardef.size*8-1))) then
  841. begin
  842. list:=TAsmList(arg);
  843. { store value in new location to keep Android verifier happy }
  844. tg.gethltemp(list,tparavarsym(p).vardef,tparavarsym(p).vardef.size,tt_persistent,tmpref);
  845. a_load_loc_stack(list,tparavarsym(p).vardef,tparavarsym(p).initialloc);
  846. a_op_const_stack(list,OP_AND,tparavarsym(p).vardef,(1 shl (tparavarsym(p).vardef.size*8))-1);
  847. a_load_stack_ref(list,tparavarsym(p).vardef,tmpref,prepare_stack_for_ref(list,tmpref,false));
  848. location_reset_ref(tparavarsym(p).localloc,LOC_REFERENCE,def_cgsize(tparavarsym(p).vardef),4);
  849. tparavarsym(p).localloc.reference:=tmpref;
  850. end;
  851. inherited g_copyvalueparas(p, arg);
  852. end;
  853. procedure thlcgjvm.inittempvariables(list: TAsmList);
  854. begin
  855. { these are automatically initialised when allocated if necessary }
  856. end;
  857. function thlcgjvm.g_call_system_proc_intern(list: TAsmList; pd: tprocdef; const paras: array of pcgpara; forceresdef: tdef): tcgpara;
  858. begin
  859. result:=inherited;
  860. pd.init_paraloc_info(callerside);
  861. g_adjust_stack_after_call(list,pd,pd.callerargareasize,forceresdef);
  862. end;
  863. function thlcgjvm.prepare_stack_for_ref(list: TAsmList; const ref: treference; dup: boolean): longint;
  864. var
  865. href: treference;
  866. begin
  867. result:=0;
  868. { fake location that indicates the value is already on the stack? }
  869. if (ref.base=NR_EVAL_STACK_BASE) then
  870. exit;
  871. if ref.arrayreftype=art_none then
  872. begin
  873. { non-array accesses cannot have an index reg }
  874. if ref.index<>NR_NO then
  875. internalerror(2010120509);
  876. if (ref.base<>NR_NO) then
  877. begin
  878. if (ref.base<>NR_STACK_POINTER_REG) then
  879. begin
  880. { regular field -> load self on the stack }
  881. a_load_reg_stack(list,voidpointertype,ref.base);
  882. if dup then
  883. begin
  884. list.concat(taicpu.op_none(a_dup));
  885. incstack(list,1);
  886. end;
  887. { field name/type encoded in symbol, no index/offset }
  888. if not assigned(ref.symbol) or
  889. (ref.offset<>0) then
  890. internalerror(2010120524);
  891. result:=1;
  892. end
  893. else
  894. begin
  895. { local variable -> offset encoded in opcode and nothing to
  896. do here, except for checking that it's a valid reference }
  897. if assigned(ref.symbol) then
  898. internalerror(2010120523);
  899. end;
  900. end
  901. else
  902. begin
  903. { static field -> nothing to do here, except for validity check }
  904. if not assigned(ref.symbol) or
  905. (ref.offset<>0) then
  906. internalerror(2010120525);
  907. end;
  908. end
  909. else
  910. begin
  911. { arrays have implicit dereference -> pointer to array must have been
  912. loaded into base reg }
  913. if (ref.base=NR_NO) or
  914. (ref.base=NR_STACK_POINTER_REG) then
  915. internalerror(2010120511);
  916. if assigned(ref.symbol) then
  917. internalerror(2010120512);
  918. { stack: ... -> ..., arrayref, index }
  919. { load array base address }
  920. a_load_reg_stack(list,voidpointertype,ref.base);
  921. { index can either be in a register, or located in a simple memory
  922. location (since we have to load it anyway) }
  923. case ref.arrayreftype of
  924. art_indexreg:
  925. begin
  926. if ref.index=NR_NO then
  927. internalerror(2010120513);
  928. { all array indices in Java are 32 bit ints }
  929. a_load_reg_stack(list,s32inttype,ref.index);
  930. end;
  931. art_indexref:
  932. begin
  933. cgutils.reference_reset_base(href,ref.indexbase,ref.indexoffset,4);
  934. href.symbol:=ref.indexsymbol;
  935. a_load_ref_stack(list,s32inttype,href,prepare_stack_for_ref(list,href,false));
  936. end;
  937. art_indexconst:
  938. begin
  939. a_load_const_stack(list,s32inttype,ref.indexoffset,R_INTREGISTER);
  940. end;
  941. else
  942. internalerror(2011012001);
  943. end;
  944. { adjustment of the index }
  945. if ref.offset<>0 then
  946. a_op_const_stack(list,OP_ADD,s32inttype,ref.offset);
  947. if dup then
  948. begin
  949. list.concat(taicpu.op_none(a_dup2));
  950. incstack(list,2);
  951. end;
  952. result:=2;
  953. end;
  954. end;
  955. procedure thlcgjvm.a_load_const_reg(list: TAsmList; tosize: tdef; a: tcgint; register: tregister);
  956. begin
  957. a_load_const_stack(list,tosize,a,def2regtyp(tosize));
  958. a_load_stack_reg(list,tosize,register);
  959. end;
  960. procedure thlcgjvm.a_load_const_ref(list: TAsmList; tosize: tdef; a: tcgint; const ref: treference);
  961. var
  962. extra_slots: longint;
  963. begin
  964. extra_slots:=prepare_stack_for_ref(list,ref,false);
  965. a_load_const_stack_intern(list,tosize,a,def2regtyp(tosize),(ref.arrayreftype<>art_none) or assigned(ref.symbol));
  966. a_load_stack_ref(list,tosize,ref,extra_slots);
  967. end;
  968. procedure thlcgjvm.a_load_reg_ref(list: TAsmList; fromsize, tosize: tdef; register: tregister; const ref: treference);
  969. var
  970. extra_slots: longint;
  971. begin
  972. extra_slots:=prepare_stack_for_ref(list,ref,false);
  973. a_load_reg_stack(list,fromsize,register);
  974. if def2regtyp(fromsize)=R_INTREGISTER then
  975. resize_stack_int_val(list,fromsize,tosize,(ref.arrayreftype<>art_none) or assigned(ref.symbol));
  976. a_load_stack_ref(list,tosize,ref,extra_slots);
  977. end;
  978. procedure thlcgjvm.a_load_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister);
  979. begin
  980. a_load_reg_stack(list,fromsize,reg1);
  981. if def2regtyp(fromsize)=R_INTREGISTER then
  982. resize_stack_int_val(list,fromsize,tosize,false);
  983. a_load_stack_reg(list,tosize,reg2);
  984. end;
  985. procedure thlcgjvm.a_load_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; register: tregister);
  986. var
  987. extra_slots: longint;
  988. begin
  989. extra_slots:=prepare_stack_for_ref(list,ref,false);
  990. a_load_ref_stack(list,fromsize,ref,extra_slots);
  991. if def2regtyp(fromsize)=R_INTREGISTER then
  992. resize_stack_int_val(list,fromsize,tosize,false);
  993. a_load_stack_reg(list,tosize,register);
  994. end;
  995. procedure thlcgjvm.a_load_ref_ref(list: TAsmList; fromsize, tosize: tdef; const sref: treference; const dref: treference);
  996. var
  997. extra_sslots,
  998. extra_dslots: longint;
  999. begin
  1000. { make sure the destination reference is on top, since in the end the
  1001. order has to be "destref, value" -> first create "destref, sourceref" }
  1002. extra_dslots:=prepare_stack_for_ref(list,dref,false);
  1003. extra_sslots:=prepare_stack_for_ref(list,sref,false);
  1004. a_load_ref_stack(list,fromsize,sref,extra_sslots);
  1005. if def2regtyp(fromsize)=R_INTREGISTER then
  1006. resize_stack_int_val(list,fromsize,tosize,(dref.arrayreftype<>art_none) or assigned(dref.symbol));
  1007. a_load_stack_ref(list,tosize,dref,extra_dslots);
  1008. end;
  1009. procedure thlcgjvm.a_loadaddr_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; r: tregister);
  1010. begin
  1011. { only allowed for types that are not implicit pointers in Pascal (in
  1012. that case, ref contains a pointer to the actual data and we simply
  1013. return that pointer) }
  1014. if not jvmimplicitpointertype(fromsize) then
  1015. internalerror(2010120534);
  1016. a_load_ref_reg(list,java_jlobject,java_jlobject,ref,r);
  1017. end;
  1018. procedure thlcgjvm.a_op_const_reg(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; reg: TRegister);
  1019. begin
  1020. a_op_const_reg_reg(list,op,size,a,reg,reg);
  1021. end;
  1022. procedure thlcgjvm.a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister);
  1023. begin
  1024. a_load_reg_stack(list,size,src);
  1025. a_op_const_stack(list,op,size,a);
  1026. a_load_stack_reg(list,size,dst);
  1027. end;
  1028. procedure thlcgjvm.a_op_const_ref(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; const ref: TReference);
  1029. var
  1030. extra_slots: longint;
  1031. begin
  1032. extra_slots:=prepare_stack_for_ref(list,ref,true);
  1033. { TODO, here or in peepholeopt: use iinc when possible }
  1034. a_load_ref_stack(list,size,ref,extra_slots);
  1035. a_op_const_stack(list,op,size,a);
  1036. { for android verifier }
  1037. if (def2regtyp(size)=R_INTREGISTER) and
  1038. ((ref.arrayreftype<>art_none) or
  1039. assigned(ref.symbol)) then
  1040. resize_stack_int_val(list,size,size,true);
  1041. a_load_stack_ref(list,size,ref,extra_slots);
  1042. end;
  1043. procedure thlcgjvm.a_op_ref_reg(list: TAsmList; Op: TOpCG; size: tdef; const ref: TReference; reg: TRegister);
  1044. begin
  1045. if not(op in [OP_NOT,OP_NEG]) then
  1046. a_load_reg_stack(list,size,reg);
  1047. a_op_ref_stack(list,op,size,ref);
  1048. a_load_stack_reg(list,size,reg);
  1049. end;
  1050. procedure thlcgjvm.a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister);
  1051. begin
  1052. if not(op in [OP_NOT,OP_NEG]) then
  1053. a_load_reg_stack(list,size,src2);
  1054. a_op_reg_stack(list,op,size,src1);
  1055. a_load_stack_reg(list,size,dst);
  1056. end;
  1057. procedure thlcgjvm.a_op_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; reg1, reg2: TRegister);
  1058. begin
  1059. a_op_reg_reg_reg(list,op,size,reg1,reg2,reg2);
  1060. end;
  1061. procedure thlcgjvm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation);
  1062. var
  1063. tmpreg: tregister;
  1064. begin
  1065. if not setflags then
  1066. begin
  1067. inherited;
  1068. exit;
  1069. end;
  1070. tmpreg:=getintregister(list,size);
  1071. a_load_const_reg(list,size,a,tmpreg);
  1072. a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,true,ovloc);
  1073. end;
  1074. procedure thlcgjvm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation);
  1075. var
  1076. orgsrc1, orgsrc2: tregister;
  1077. docheck: boolean;
  1078. lab: tasmlabel;
  1079. begin
  1080. if not setflags then
  1081. begin
  1082. inherited;
  1083. exit;
  1084. end;
  1085. { anything else cannot overflow }
  1086. docheck:=size.size in [4,8];
  1087. if docheck then
  1088. begin
  1089. orgsrc1:=src1;
  1090. orgsrc2:=src2;
  1091. if src1=dst then
  1092. begin
  1093. orgsrc1:=getintregister(list,size);
  1094. a_load_reg_reg(list,size,size,src1,orgsrc1);
  1095. end;
  1096. if src2=dst then
  1097. begin
  1098. orgsrc2:=getintregister(list,size);
  1099. a_load_reg_reg(list,size,size,src2,orgsrc2);
  1100. end;
  1101. end;
  1102. a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  1103. if docheck then
  1104. begin
  1105. { * signed overflow for addition iff
  1106. - src1 and src2 are negative and result is positive (excep in case of
  1107. subtraction, then sign of src1 has to be inverted)
  1108. - src1 and src2 are positive and result is negative
  1109. -> Simplified boolean equivalent (in terms of sign bits):
  1110. not(src1 xor src2) and (src1 xor dst)
  1111. for subtraction, multiplication: invert src1 sign bit
  1112. for division: handle separately (div by zero, low(inttype) div -1),
  1113. not supported by this code
  1114. * unsigned overflow iff carry out, aka dst < src1 or dst < src2
  1115. }
  1116. location_reset(ovloc,LOC_REGISTER,OS_S32);
  1117. { not pasbool8, because then we'd still have to convert the integer to
  1118. a boolean via branches for Dalvik}
  1119. ovloc.register:=getintregister(list,s32inttype);
  1120. if not ((size.typ=pointerdef) or
  1121. ((size.typ=orddef) and
  1122. (torddef(size).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  1123. pasbool8,pasbool16,pasbool32,pasbool64]))) then
  1124. begin
  1125. a_load_reg_stack(list,size,src1);
  1126. if op in [OP_SUB,OP_IMUL] then
  1127. a_op_stack(list,OP_NOT,size,false);
  1128. a_op_reg_stack(list,OP_XOR,size,src2);
  1129. a_op_stack(list,OP_NOT,size,false);
  1130. a_load_reg_stack(list,size,src1);
  1131. a_op_reg_stack(list,OP_XOR,size,dst);
  1132. a_op_stack(list,OP_AND,size,false);
  1133. a_op_const_stack(list,OP_SHR,size,(size.size*8)-1);
  1134. if size.size=8 then
  1135. begin
  1136. list.concat(taicpu.op_none(a_l2i));
  1137. decstack(list,1);
  1138. end;
  1139. end
  1140. else
  1141. begin
  1142. a_load_const_stack(list,s32inttype,0,R_INTREGISTER);
  1143. current_asmdata.getjumplabel(lab);
  1144. { can be optimized by removing duplicate xor'ing to convert dst from
  1145. signed to unsigned quadrant }
  1146. a_cmp_reg_reg_label(list,size,OC_B,dst,src1,lab);
  1147. a_cmp_reg_reg_label(list,size,OC_B,dst,src2,lab);
  1148. a_op_const_stack(list,OP_XOR,s32inttype,1);
  1149. a_label(list,lab);
  1150. end;
  1151. a_load_stack_reg(list,s32inttype,ovloc.register);
  1152. end
  1153. else
  1154. ovloc.loc:=LOC_VOID;
  1155. end;
  1156. procedure thlcgjvm.a_cmp_const_ref_label(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; const ref: treference; l: tasmlabel);
  1157. begin
  1158. if ref.base<>NR_EVAL_STACK_BASE then
  1159. a_load_ref_stack(list,size,ref,prepare_stack_for_ref(list,ref,false));
  1160. maybe_adjust_cmp_stackval(list,size,cmp_op);
  1161. a_load_const_stack(list,size,maybe_adjust_cmp_constval(size,cmp_op,a),def2regtyp(size));
  1162. a_cmp_stack_label(list,size,cmp_op,l);
  1163. end;
  1164. procedure thlcgjvm.a_cmp_const_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
  1165. begin
  1166. a_load_reg_stack(list,size,reg);
  1167. maybe_adjust_cmp_stackval(list,size,cmp_op);
  1168. a_load_const_stack(list,size,maybe_adjust_cmp_constval(size,cmp_op,a),def2regtyp(size));
  1169. a_cmp_stack_label(list,size,cmp_op,l);
  1170. end;
  1171. procedure thlcgjvm.a_cmp_ref_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; const ref: treference; reg: tregister; l: tasmlabel);
  1172. begin
  1173. a_load_reg_stack(list,size,reg);
  1174. maybe_adjust_cmp_stackval(list,size,cmp_op);
  1175. if ref.base<>NR_EVAL_STACK_BASE then
  1176. a_load_ref_stack(list,size,ref,prepare_stack_for_ref(list,ref,false))
  1177. else
  1178. list.concat(taicpu.op_none(a_swap));
  1179. maybe_adjust_cmp_stackval(list,size,cmp_op);
  1180. a_cmp_stack_label(list,size,cmp_op,l);
  1181. end;
  1182. procedure thlcgjvm.a_cmp_reg_ref_label(list: TAsmList; size: tdef; cmp_op: topcmp; reg: tregister; const ref: treference; l: tasmlabel);
  1183. begin
  1184. if ref.base<>NR_EVAL_STACK_BASE then
  1185. a_load_ref_stack(list,size,ref,prepare_stack_for_ref(list,ref,false));
  1186. maybe_adjust_cmp_stackval(list,size,cmp_op);
  1187. a_load_reg_stack(list,size,reg);
  1188. maybe_adjust_cmp_stackval(list,size,cmp_op);
  1189. a_cmp_stack_label(list,size,cmp_op,l);
  1190. end;
  1191. procedure thlcgjvm.a_cmp_reg_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel);
  1192. begin
  1193. a_load_reg_stack(list,size,reg2);
  1194. maybe_adjust_cmp_stackval(list,size,cmp_op);
  1195. a_load_reg_stack(list,size,reg1);
  1196. maybe_adjust_cmp_stackval(list,size,cmp_op);
  1197. a_cmp_stack_label(list,size,cmp_op,l);
  1198. end;
  1199. procedure thlcgjvm.a_jmp_always(list: TAsmList; l: tasmlabel);
  1200. begin
  1201. list.concat(taicpu.op_sym(a_goto,current_asmdata.RefAsmSymbol(l.name)));
  1202. end;
  1203. procedure thlcgjvm.concatcopy_normal_array(list: TAsmList; size: tdef; const source, dest: treference);
  1204. var
  1205. procname: string;
  1206. eledef: tdef;
  1207. ndim: longint;
  1208. adddefaultlenparas: boolean;
  1209. begin
  1210. { load copy helper parameters on the stack }
  1211. a_load_ref_stack(list,java_jlobject,source,prepare_stack_for_ref(list,source,false));
  1212. a_load_ref_stack(list,java_jlobject,dest,prepare_stack_for_ref(list,dest,false));
  1213. { call copy helper }
  1214. eledef:=tarraydef(size).elementdef;
  1215. ndim:=1;
  1216. adddefaultlenparas:=true;
  1217. case eledef.typ of
  1218. orddef:
  1219. begin
  1220. case torddef(eledef).ordtype of
  1221. pasbool8,s8bit,u8bit,bool8bit,uchar,
  1222. s16bit,u16bit,bool16bit,pasbool16,
  1223. uwidechar,
  1224. s32bit,u32bit,bool32bit,pasbool32,
  1225. s64bit,u64bit,bool64bit,pasbool64,scurrency:
  1226. procname:='FPC_COPY_SHALLOW_ARRAY'
  1227. else
  1228. internalerror(2011020504);
  1229. end;
  1230. end;
  1231. arraydef:
  1232. begin
  1233. { call fpc_setlength_dynarr_multidim with deepcopy=true, and extra
  1234. parameters }
  1235. while (eledef.typ=arraydef) and
  1236. not is_dynamic_array(eledef) do
  1237. begin
  1238. eledef:=tarraydef(eledef).elementdef;
  1239. inc(ndim)
  1240. end;
  1241. if (ndim=1) then
  1242. procname:='FPC_COPY_SHALLOW_ARRAY'
  1243. else
  1244. begin
  1245. { deepcopy=true }
  1246. a_load_const_stack(list,pasbool8type,1,R_INTREGISTER);
  1247. { ndim }
  1248. a_load_const_stack(list,s32inttype,ndim,R_INTREGISTER);
  1249. { eletype }
  1250. a_load_const_stack(list,cwidechartype,ord(jvmarrtype_setlength(eledef)),R_INTREGISTER);
  1251. adddefaultlenparas:=false;
  1252. procname:='FPC_SETLENGTH_DYNARR_MULTIDIM';
  1253. end;
  1254. end;
  1255. recorddef:
  1256. procname:='FPC_COPY_JRECORD_ARRAY';
  1257. procvardef:
  1258. if tprocvardef(eledef).is_addressonly then
  1259. procname:='FPC_COPY_SHALLOW_ARRAY'
  1260. else
  1261. procname:='FPC_COPY_JPROCVAR_ARRAY';
  1262. setdef:
  1263. if tsetdef(eledef).elementdef.typ=enumdef then
  1264. procname:='FPC_COPY_JENUMSET_ARRAY'
  1265. else
  1266. procname:='FPC_COPY_JBITSET_ARRAY';
  1267. floatdef:
  1268. procname:='FPC_COPY_SHALLOW_ARRAY';
  1269. stringdef:
  1270. if is_shortstring(eledef) then
  1271. procname:='FPC_COPY_JSHORTSTRING_ARRAY'
  1272. else
  1273. procname:='FPC_COPY_SHALLOW_ARRAY';
  1274. variantdef:
  1275. begin
  1276. {$ifndef nounsupported}
  1277. procname:='FPC_COPY_SHALLOW_ARRAY';
  1278. {$else}
  1279. { todo: make a deep copy via clone... }
  1280. internalerror(2011020505);
  1281. {$endif}
  1282. end;
  1283. else
  1284. procname:='FPC_COPY_SHALLOW_ARRAY';
  1285. end;
  1286. if adddefaultlenparas then
  1287. begin
  1288. { -1, -1 means "copy entire array" }
  1289. a_load_const_stack(list,s32inttype,-1,R_INTREGISTER);
  1290. a_load_const_stack(list,s32inttype,-1,R_INTREGISTER);
  1291. end;
  1292. g_call_system_proc(list,procname,[],nil);
  1293. if ndim<>1 then
  1294. begin
  1295. { pop return value, must be the same as dest }
  1296. list.concat(taicpu.op_none(a_pop));
  1297. decstack(list,1);
  1298. end;
  1299. end;
  1300. procedure thlcgjvm.concatcopy_record(list: TAsmList; size: tdef; const source, dest: treference);
  1301. var
  1302. srsym: tsym;
  1303. pd: tprocdef;
  1304. begin
  1305. { self }
  1306. a_load_ref_stack(list,size,source,prepare_stack_for_ref(list,source,false));
  1307. { result }
  1308. a_load_ref_stack(list,size,dest,prepare_stack_for_ref(list,dest,false));
  1309. { call fpcDeepCopy helper }
  1310. srsym:=search_struct_member(tabstractrecorddef(size),'FPCDEEPCOPY');
  1311. if not assigned(srsym) or
  1312. (srsym.typ<>procsym) then
  1313. Message1(cg_f_unknown_compilerproc,size.typename+'.fpcDeepCopy');
  1314. pd:=tprocdef(tprocsym(srsym).procdeflist[0]);
  1315. a_call_name(list,pd,pd.mangledname,[],nil,false);
  1316. { both parameters are removed, no function result }
  1317. decstack(list,2);
  1318. end;
  1319. procedure thlcgjvm.concatcopy_set(list: TAsmList; size: tdef; const source, dest: treference);
  1320. begin
  1321. a_load_ref_stack(list,size,source,prepare_stack_for_ref(list,source,false));
  1322. a_load_ref_stack(list,size,dest,prepare_stack_for_ref(list,dest,false));
  1323. { call set copy helper }
  1324. if tsetdef(size).elementdef.typ=enumdef then
  1325. g_call_system_proc(list,'fpc_enumset_copy',[],nil)
  1326. else
  1327. g_call_system_proc(list,'fpc_bitset_copy',[],nil);
  1328. end;
  1329. procedure thlcgjvm.concatcopy_shortstring(list: TAsmList; size: tdef; const source, dest: treference);
  1330. var
  1331. srsym: tsym;
  1332. pd: tprocdef;
  1333. begin
  1334. { self }
  1335. a_load_ref_stack(list,size,source,prepare_stack_for_ref(list,source,false));
  1336. { result }
  1337. a_load_ref_stack(list,size,dest,prepare_stack_for_ref(list,dest,false));
  1338. { call fpcDeepCopy helper }
  1339. srsym:=search_struct_member(java_shortstring,'FPCDEEPCOPY');
  1340. if not assigned(srsym) or
  1341. (srsym.typ<>procsym) then
  1342. Message1(cg_f_unknown_compilerproc,'ShortstringClass.FpcDeepCopy');
  1343. pd:=tprocdef(tprocsym(srsym).procdeflist[0]);
  1344. a_call_name(list,pd,pd.mangledname,[],nil,false);
  1345. { both parameters are removed, no function result }
  1346. decstack(list,2);
  1347. end;
  1348. procedure thlcgjvm.g_concatcopy(list: TAsmList; size: tdef; const source, dest: treference);
  1349. var
  1350. handled: boolean;
  1351. begin
  1352. handled:=false;
  1353. case size.typ of
  1354. arraydef:
  1355. begin
  1356. if not is_dynamic_array(size) then
  1357. begin
  1358. concatcopy_normal_array(list,size,source,dest);
  1359. handled:=true;
  1360. end;
  1361. end;
  1362. recorddef:
  1363. begin
  1364. concatcopy_record(list,size,source,dest);
  1365. handled:=true;
  1366. end;
  1367. setdef:
  1368. begin
  1369. concatcopy_set(list,size,source,dest);
  1370. handled:=true;
  1371. end;
  1372. stringdef:
  1373. begin
  1374. if is_shortstring(size) then
  1375. begin
  1376. concatcopy_shortstring(list,size,source,dest);
  1377. handled:=true;
  1378. end;
  1379. end;
  1380. procvardef:
  1381. begin
  1382. if not tprocvardef(size).is_addressonly then
  1383. begin
  1384. concatcopy_record(list,tcpuprocvardef(size).classdef,source,dest);
  1385. handled:=true;
  1386. end;
  1387. end;
  1388. end;
  1389. if not handled then
  1390. inherited;
  1391. end;
  1392. procedure thlcgjvm.g_copyshortstring(list: TAsmList; const source, dest: treference; strdef: tstringdef);
  1393. begin
  1394. concatcopy_shortstring(list,strdef,source,dest);
  1395. end;
  1396. procedure thlcgjvm.a_loadfpu_ref_ref(list: TAsmList; fromsize, tosize: tdef; const ref1, ref2: treference);
  1397. var
  1398. dstack_slots: longint;
  1399. begin
  1400. dstack_slots:=prepare_stack_for_ref(list,ref2,false);
  1401. a_load_ref_stack(list,fromsize,ref1,prepare_stack_for_ref(list,ref1,false));
  1402. resizestackfpuval(list,def_cgsize(fromsize),def_cgsize(tosize));
  1403. a_load_stack_ref(list,tosize,ref2,dstack_slots);
  1404. end;
  1405. procedure thlcgjvm.a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister);
  1406. begin
  1407. a_load_ref_stack(list,fromsize,ref,prepare_stack_for_ref(list,ref,false));
  1408. resizestackfpuval(list,def_cgsize(fromsize),def_cgsize(tosize));
  1409. a_load_stack_reg(list,tosize,reg);
  1410. end;
  1411. procedure thlcgjvm.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference);
  1412. var
  1413. dstack_slots: longint;
  1414. begin
  1415. dstack_slots:=prepare_stack_for_ref(list,ref,false);
  1416. a_load_reg_stack(list,fromsize,reg);
  1417. resizestackfpuval(list,def_cgsize(fromsize),def_cgsize(tosize));
  1418. a_load_stack_ref(list,tosize,ref,dstack_slots);
  1419. end;
  1420. procedure thlcgjvm.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister);
  1421. begin
  1422. a_load_reg_stack(list,fromsize,reg1);
  1423. resizestackfpuval(list,def_cgsize(fromsize),def_cgsize(tosize));
  1424. a_load_stack_reg(list,tosize,reg2);
  1425. end;
  1426. procedure thlcgjvm.g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean);
  1427. begin
  1428. { the localsize is based on tg.lasttemp -> already in terms of stack
  1429. slots rather than bytes }
  1430. list.concat(tai_directive.Create(asd_jlimit,'locals '+tostr(localsize)));
  1431. { we insert the unit initialisation code afterwards in the proginit code,
  1432. and it uses one stack slot }
  1433. if (current_procinfo.procdef.proctypeoption=potype_proginit) then
  1434. fmaxevalstackheight:=max(1,fmaxevalstackheight);
  1435. list.concat(tai_directive.Create(asd_jlimit,'stack '+tostr(fmaxevalstackheight)));
  1436. end;
  1437. procedure thlcgjvm.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
  1438. var
  1439. retdef: tdef;
  1440. opc: tasmop;
  1441. begin
  1442. if current_procinfo.procdef.proctypeoption in [potype_constructor,potype_class_constructor] then
  1443. retdef:=voidtype
  1444. else
  1445. retdef:=current_procinfo.procdef.returndef;
  1446. case retdef.typ of
  1447. orddef:
  1448. case torddef(retdef).ordtype of
  1449. uvoid:
  1450. opc:=a_return;
  1451. s64bit,
  1452. u64bit,
  1453. scurrency:
  1454. opc:=a_lreturn;
  1455. else
  1456. opc:=a_ireturn;
  1457. end;
  1458. setdef:
  1459. opc:=a_areturn;
  1460. floatdef:
  1461. case tfloatdef(retdef).floattype of
  1462. s32real:
  1463. opc:=a_freturn;
  1464. s64real:
  1465. opc:=a_dreturn;
  1466. else
  1467. internalerror(2011010213);
  1468. end;
  1469. else
  1470. opc:=a_areturn;
  1471. end;
  1472. list.concat(taicpu.op_none(opc));
  1473. end;
  1474. procedure thlcgjvm.gen_load_return_value(list: TAsmList);
  1475. begin
  1476. { constructors don't return anything in the jvm }
  1477. if current_procinfo.procdef.proctypeoption in [potype_constructor,potype_class_constructor] then
  1478. exit;
  1479. inherited gen_load_return_value(list);
  1480. end;
  1481. procedure thlcgjvm.record_generated_code_for_procdef(pd: tprocdef; code, data: TAsmList);
  1482. begin
  1483. { add something to the al_procedures list as well, because if all al_*
  1484. lists are empty, the assembler writer isn't called }
  1485. if not code.empty and
  1486. current_asmdata.asmlists[al_procedures].empty then
  1487. current_asmdata.asmlists[al_procedures].concat(tai_align.Create(4));
  1488. tcpuprocdef(pd).exprasmlist:=TAsmList.create;
  1489. tcpuprocdef(pd).exprasmlist.concatlist(code);
  1490. if assigned(data) and
  1491. not data.empty then
  1492. internalerror(2010122801);
  1493. end;
  1494. procedure thlcgjvm.g_incrrefcount(list: TAsmList; t: tdef; const ref: treference);
  1495. begin
  1496. // do nothing
  1497. end;
  1498. procedure thlcgjvm.g_array_rtti_helper(list: TAsmList; t: tdef; const ref: treference; const highloc: tlocation; const name: string);
  1499. var
  1500. normaldim: longint;
  1501. eleref: treference;
  1502. begin
  1503. { only in case of initialisation, we have to set all elements to "empty" }
  1504. if name<>'fpc_initialize_array' then
  1505. exit;
  1506. { put array on the stack }
  1507. a_load_ref_stack(list,java_jlobject,ref,prepare_stack_for_ref(list,ref,false));
  1508. { in case it's an open array whose elements are regular arrays, put the
  1509. dimension of the regular arrays on the stack (otherwise pass 0) }
  1510. normaldim:=0;
  1511. while (t.typ=arraydef) and
  1512. not is_dynamic_array(t) do
  1513. begin
  1514. inc(normaldim);
  1515. t:=tarraydef(t).elementdef;
  1516. end;
  1517. a_load_const_stack(list,s32inttype,normaldim,R_INTREGISTER);
  1518. { highloc is invalid, the length is part of the array in Java }
  1519. if is_wide_or_unicode_string(t) then
  1520. g_call_system_proc(list,'fpc_initialize_array_unicodestring',[],nil)
  1521. else if is_ansistring(t) then
  1522. g_call_system_proc(list,'fpc_initialize_array_ansistring',[],nil)
  1523. else if is_dynamic_array(t) then
  1524. g_call_system_proc(list,'fpc_initialize_array_dynarr',[],nil)
  1525. else if is_record(t) or
  1526. (t.typ=setdef) then
  1527. begin
  1528. tg.gethltemp(list,t,t.size,tt_persistent,eleref);
  1529. a_load_ref_stack(list,t,eleref,prepare_stack_for_ref(list,eleref,false));
  1530. if is_record(t) then
  1531. g_call_system_proc(list,'fpc_initialize_array_record',[],nil)
  1532. else if tsetdef(t).elementdef.typ=enumdef then
  1533. g_call_system_proc(list,'fpc_initialize_array_enumset',[],nil)
  1534. else
  1535. g_call_system_proc(list,'fpc_initialize_array_bitset',[],nil);
  1536. tg.ungettemp(list,eleref);
  1537. end
  1538. else if (t.typ=enumdef) then
  1539. begin
  1540. if get_enum_init_val_ref(t,eleref) then
  1541. begin
  1542. a_load_ref_stack(list,java_jlobject,eleref,prepare_stack_for_ref(list,eleref,false));
  1543. g_call_system_proc(list,'fpc_initialize_array_object',[],nil);
  1544. end;
  1545. end
  1546. else
  1547. internalerror(2011031901);
  1548. end;
  1549. procedure thlcgjvm.g_initialize(list: TAsmList; t: tdef; const ref: treference);
  1550. var
  1551. dummyloc: tlocation;
  1552. sym: tsym;
  1553. pd: tprocdef;
  1554. begin
  1555. if (t.typ=arraydef) and
  1556. not is_dynamic_array(t) then
  1557. begin
  1558. dummyloc.loc:=LOC_INVALID;
  1559. g_array_rtti_helper(list,tarraydef(t).elementdef,ref,dummyloc,'fpc_initialize_array')
  1560. end
  1561. else if is_record(t) then
  1562. begin
  1563. { call the fpcInitializeRec method }
  1564. sym:=tsym(trecorddef(t).symtable.find('FPCINITIALIZEREC'));
  1565. if assigned(sym) and
  1566. (sym.typ=procsym) then
  1567. begin
  1568. if tprocsym(sym).procdeflist.Count<>1 then
  1569. internalerror(2011071713);
  1570. pd:=tprocdef(tprocsym(sym).procdeflist[0]);
  1571. end
  1572. else
  1573. internalerror(2013113008);
  1574. a_load_ref_stack(list,java_jlobject,ref,prepare_stack_for_ref(list,ref,false));
  1575. a_call_name(list,pd,pd.mangledname,[],nil,false);
  1576. { parameter removed, no result }
  1577. decstack(list,1);
  1578. end
  1579. else
  1580. a_load_const_ref(list,t,0,ref);
  1581. end;
  1582. procedure thlcgjvm.g_finalize(list: TAsmList; t: tdef; const ref: treference);
  1583. begin
  1584. // do nothing
  1585. end;
  1586. procedure thlcgjvm.g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef);
  1587. begin
  1588. { not possible, need the original operands }
  1589. internalerror(2012102101);
  1590. end;
  1591. procedure thlcgjvm.g_overflowCheck_loc(List: TAsmList; const Loc: TLocation; def: TDef; var ovloc: tlocation);
  1592. var
  1593. hl : tasmlabel;
  1594. begin
  1595. if not(cs_check_overflow in current_settings.localswitches) then
  1596. exit;
  1597. current_asmdata.getjumplabel(hl);
  1598. a_cmp_const_loc_label(list,s32inttype,OC_EQ,0,ovloc,hl);
  1599. g_call_system_proc(list,'fpc_overflow',[],nil);
  1600. a_label(list,hl);
  1601. end;
  1602. procedure thlcgjvm.location_get_data_ref(list: TAsmList; def: tdef; const l: tlocation; var ref: treference; loadref: boolean; alignment: longint);
  1603. var
  1604. tmploc: tlocation;
  1605. begin
  1606. { This routine is a combination of a generalised a_loadaddr_ref_reg()
  1607. that also works for addresses in registers (in case loadref is false)
  1608. and of a_load_ref_reg (in case loadref is true). It is used for
  1609. a) getting the address of managed var/out parameters
  1610. b) getting to the actual data of value types that are passed by
  1611. reference by the compiler (and then get a local copy at the caller
  1612. side). Normally, depending on whether this reference is passed in a
  1613. register or reference, we either need a reference with that register
  1614. as base or load the address in that reference and use that as a new
  1615. base.
  1616. Since the JVM cannot take the address of anything, all
  1617. "pass-by-reference" value parameters (which are always aggregate types)
  1618. are already simply the implicit pointer to the data (since arrays,
  1619. records, etc are already internally implicit pointers). This means
  1620. that if "loadref" is true, we must simply return this implicit pointer.
  1621. If it is false, we are supposed the take the address of this implicit
  1622. pointer, which is not possible.
  1623. However, managed types are also implicit pointers in Pascal, so in that
  1624. case "taking the address" again consists of simply returning the
  1625. implicit pointer/current value (in case of a var/out parameter, this
  1626. value is stored inside an array).
  1627. }
  1628. if not loadref then
  1629. begin
  1630. if not is_managed_type(def) then
  1631. internalerror(2011020601);
  1632. tmploc:=l;
  1633. end
  1634. else
  1635. begin
  1636. if not jvmimplicitpointertype(def) then
  1637. begin
  1638. { passed by reference in array of single element; l contains the
  1639. base address of the array }
  1640. location_reset_ref(tmploc,LOC_REFERENCE,OS_ADDR,4);
  1641. cgutils.reference_reset_base(tmploc.reference,getaddressregister(list,java_jlobject),0,4);
  1642. tmploc.reference.arrayreftype:=art_indexconst;
  1643. tmploc.reference.indexoffset:=0;
  1644. a_load_loc_reg(list,java_jlobject,java_jlobject,l,tmploc.reference.base);
  1645. end
  1646. else
  1647. tmploc:=l;
  1648. end;
  1649. case tmploc.loc of
  1650. LOC_REGISTER,
  1651. LOC_CREGISTER :
  1652. begin
  1653. { the implicit pointer is in a register and has to be in a
  1654. reference -> create a reference and put it there }
  1655. location_force_mem(list,tmploc,java_jlobject);
  1656. ref:=tmploc.reference;
  1657. end;
  1658. LOC_REFERENCE,
  1659. LOC_CREFERENCE :
  1660. begin
  1661. ref:=tmploc.reference;
  1662. end;
  1663. else
  1664. internalerror(2011020603);
  1665. end;
  1666. end;
  1667. procedure thlcgjvm.maybe_change_load_node_reg(list: TAsmList; var n: tnode; reload: boolean);
  1668. begin
  1669. { don't do anything, all registers become stack locations anyway }
  1670. end;
  1671. procedure thlcgjvm.g_copyvaluepara_openarray(list: TAsmList; const ref: treference; const lenloc: tlocation; arrdef: tarraydef; destreg: tregister);
  1672. var
  1673. localref: treference;
  1674. arrloc: tlocation;
  1675. stackslots: longint;
  1676. begin
  1677. { temporary reference for passing to concatcopy }
  1678. tg.gethltemp(list,java_jlobject,java_jlobject.size,tt_persistent,localref);
  1679. stackslots:=prepare_stack_for_ref(list,localref,false);
  1680. { create the local copy of the array (lenloc is invalid, get length
  1681. directly from the array) }
  1682. location_reset_ref(arrloc,LOC_REFERENCE,OS_ADDR,sizeof(pint));
  1683. arrloc.reference:=ref;
  1684. g_getarraylen(list,arrloc);
  1685. g_newarray(list,arrdef,1);
  1686. a_load_stack_ref(list,java_jlobject,localref,stackslots);
  1687. { copy the source array to the destination }
  1688. g_concatcopy(list,arrdef,ref,localref);
  1689. { and put the array pointer in the register as expected by the caller }
  1690. a_load_ref_reg(list,java_jlobject,java_jlobject,localref,destreg);
  1691. end;
  1692. procedure thlcgjvm.g_releasevaluepara_openarray(list: TAsmList; arrdef: tarraydef; const l: tlocation);
  1693. begin
  1694. // do nothing, long live garbage collection!
  1695. end;
  1696. procedure thlcgjvm.gen_initialize_code(list: TAsmList);
  1697. var
  1698. ref: treference;
  1699. begin
  1700. { create globals with wrapped types such as arrays/records }
  1701. case current_procinfo.procdef.proctypeoption of
  1702. potype_unitinit:
  1703. begin
  1704. cgutils.reference_reset_base(ref,NR_NO,0,1);
  1705. if assigned(current_module.globalsymtable) then
  1706. allocate_implicit_structs_for_st_with_base_ref(list,current_module.globalsymtable,ref,staticvarsym);
  1707. allocate_implicit_structs_for_st_with_base_ref(list,current_module.localsymtable,ref,staticvarsym);
  1708. end;
  1709. potype_class_constructor:
  1710. begin
  1711. { also initialise local variables, if any }
  1712. inherited;
  1713. { initialise class fields }
  1714. cgutils.reference_reset_base(ref,NR_NO,0,1);
  1715. allocate_implicit_structs_for_st_with_base_ref(list,tabstractrecorddef(current_procinfo.procdef.owner.defowner).symtable,ref,staticvarsym);
  1716. end
  1717. else
  1718. inherited
  1719. end;
  1720. end;
  1721. procedure thlcgjvm.gen_entry_code(list: TAsmList);
  1722. begin
  1723. list.concat(Tai_force_line.Create);
  1724. end;
  1725. procedure thlcgjvm.gen_exit_code(list: TAsmList);
  1726. begin
  1727. { nothing }
  1728. end;
  1729. procedure thlcgjvm.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tdef; src, dst: tregister);
  1730. begin
  1731. internalerror(2012090201);
  1732. end;
  1733. procedure thlcgjvm.a_loadmm_loc_reg(list: TAsmList; fromsize, tosize: tdef; const loc: tlocation; const reg: tregister; shuffle: pmmshuffle);
  1734. begin
  1735. internalerror(2012090202);
  1736. end;
  1737. procedure thlcgjvm.a_loadmm_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister; shuffle: pmmshuffle);
  1738. begin
  1739. internalerror(2012060130);
  1740. end;
  1741. procedure thlcgjvm.a_loadmm_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister; shuffle: pmmshuffle);
  1742. begin
  1743. internalerror(2012060131);
  1744. end;
  1745. procedure thlcgjvm.a_loadmm_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference; shuffle: pmmshuffle);
  1746. begin
  1747. internalerror(2012060132);
  1748. end;
  1749. procedure thlcgjvm.a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; src, dst: tregister; shuffle: pmmshuffle);
  1750. begin
  1751. internalerror(2012060133);
  1752. end;
  1753. procedure thlcgjvm.a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize: tdef; intreg, mmreg: tregister; shuffle: pmmshuffle);
  1754. begin
  1755. internalerror(2012060134);
  1756. end;
  1757. procedure thlcgjvm.a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize: tdef; mmreg, intreg: tregister; shuffle: pmmshuffle);
  1758. begin
  1759. internalerror(2012060135);
  1760. end;
  1761. procedure thlcgjvm.g_stackpointer_alloc(list: TAsmList; size: longint);
  1762. begin
  1763. internalerror(2012090203);
  1764. end;
  1765. procedure thlcgjvm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  1766. begin
  1767. internalerror(2012090204);
  1768. end;
  1769. procedure thlcgjvm.g_adjust_self_value(list: TAsmList; procdef: tprocdef; ioffset: aint);
  1770. begin
  1771. internalerror(2012090205);
  1772. end;
  1773. procedure thlcgjvm.g_local_unwind(list: TAsmList; l: TAsmLabel);
  1774. begin
  1775. internalerror(2012090206);
  1776. end;
  1777. procedure thlcgjvm.a_load_stack_reg(list: TAsmList; size: tdef; reg: tregister);
  1778. var
  1779. opc: tasmop;
  1780. finishandval: tcgint;
  1781. begin
  1782. opc:=loadstoreopc(size,false,false,finishandval);
  1783. list.concat(taicpu.op_reg(opc,reg));
  1784. { avoid problems with getting the size of an open array etc }
  1785. if jvmimplicitpointertype(size) then
  1786. size:=java_jlobject;
  1787. decstack(list,1+ord(size.size>4));
  1788. end;
  1789. procedure thlcgjvm.a_load_stack_ref(list: TAsmList; size: tdef; const ref: treference; extra_slots: longint);
  1790. var
  1791. opc: tasmop;
  1792. finishandval: tcgint;
  1793. begin
  1794. { fake location that indicates the value has to remain on the stack }
  1795. if ref.base=NR_EVAL_STACK_BASE then
  1796. exit;
  1797. opc:=loadstoreopcref(size,false,ref,finishandval);
  1798. if ref.arrayreftype=art_none then
  1799. list.concat(taicpu.op_ref(opc,ref))
  1800. else
  1801. list.concat(taicpu.op_none(opc));
  1802. { avoid problems with getting the size of an open array etc }
  1803. if jvmimplicitpointertype(size) then
  1804. size:=java_jlobject;
  1805. decstack(list,1+ord(size.size>4)+extra_slots);
  1806. end;
  1807. procedure thlcgjvm.a_load_reg_stack(list: TAsmList; size: tdef; reg: tregister);
  1808. var
  1809. opc: tasmop;
  1810. finishandval: tcgint;
  1811. begin
  1812. opc:=loadstoreopc(size,true,false,finishandval);
  1813. list.concat(taicpu.op_reg(opc,reg));
  1814. { avoid problems with getting the size of an open array etc }
  1815. if jvmimplicitpointertype(size) then
  1816. size:=java_jlobject;
  1817. incstack(list,1+ord(size.size>4));
  1818. if finishandval<>-1 then
  1819. a_op_const_stack(list,OP_AND,size,finishandval);
  1820. end;
  1821. procedure thlcgjvm.a_load_ref_stack(list: TAsmList; size: tdef; const ref: treference; extra_slots: longint);
  1822. var
  1823. opc: tasmop;
  1824. finishandval: tcgint;
  1825. begin
  1826. { fake location that indicates the value is already on the stack? }
  1827. if (ref.base=NR_EVAL_STACK_BASE) then
  1828. exit;
  1829. opc:=loadstoreopcref(size,true,ref,finishandval);
  1830. if ref.arrayreftype=art_none then
  1831. list.concat(taicpu.op_ref(opc,ref))
  1832. else
  1833. list.concat(taicpu.op_none(opc));
  1834. { avoid problems with getting the size of an open array etc }
  1835. if jvmimplicitpointertype(size) then
  1836. size:=java_jlobject;
  1837. incstack(list,1+ord(size.size>4)-extra_slots);
  1838. if finishandval<>-1 then
  1839. a_op_const_stack(list,OP_AND,size,finishandval);
  1840. if ref.checkcast then
  1841. gen_typecheck(list,a_checkcast,size);
  1842. end;
  1843. function thlcgjvm.loadstoreopcref(def: tdef; isload: boolean; const ref: treference; out finishandval: tcgint): tasmop;
  1844. const
  1845. { isload static }
  1846. getputopc: array[boolean,boolean] of tasmop =
  1847. ((a_putfield,a_putstatic),
  1848. (a_getfield,a_getstatic));
  1849. begin
  1850. if assigned(ref.symbol) then
  1851. begin
  1852. { -> either a global (static) field, or a regular field. If a regular
  1853. field, then ref.base contains the self pointer, otherwise
  1854. ref.base=NR_NO. In both cases, the symbol contains all other
  1855. information (combined field name and type descriptor) }
  1856. result:=getputopc[isload,ref.base=NR_NO];
  1857. finishandval:=-1;
  1858. { erase sign extension for byte/smallint loads }
  1859. if (def2regtyp(def)=R_INTREGISTER) and
  1860. not is_signed(def) and
  1861. (def.typ=orddef) and
  1862. not is_widechar(def) then
  1863. case def.size of
  1864. 1: if (torddef(def).high>127) then
  1865. finishandval:=255;
  1866. 2: if (torddef(def).high>32767) then
  1867. finishandval:=65535;
  1868. end;
  1869. end
  1870. else
  1871. result:=loadstoreopc(def,isload,ref.arrayreftype<>art_none,finishandval);
  1872. end;
  1873. function thlcgjvm.loadstoreopc(def: tdef; isload, isarray: boolean; out finishandval: tcgint): tasmop;
  1874. var
  1875. size: longint;
  1876. begin
  1877. finishandval:=-1;
  1878. case def2regtyp(def) of
  1879. R_INTREGISTER:
  1880. begin
  1881. size:=def.size;
  1882. if not isarray then
  1883. begin
  1884. case size of
  1885. 1,2,3,4:
  1886. if isload then
  1887. result:=a_iload
  1888. else
  1889. result:=a_istore;
  1890. 8:
  1891. if isload then
  1892. result:=a_lload
  1893. else
  1894. result:=a_lstore;
  1895. else
  1896. internalerror(2011032814);
  1897. end;
  1898. end
  1899. { array }
  1900. else if isload then
  1901. begin
  1902. case size of
  1903. 1:
  1904. begin
  1905. result:=a_baload;
  1906. if not is_signed(def) and
  1907. (def.typ=orddef) and
  1908. (torddef(def).high>127) then
  1909. finishandval:=255;
  1910. end;
  1911. 2:
  1912. begin
  1913. if is_widechar(def) then
  1914. result:=a_caload
  1915. else
  1916. begin
  1917. result:=a_saload;
  1918. { if we'd treat arrays of word as "array of widechar" we
  1919. could use a_caload, but that would make for even more
  1920. awkward interfacing with external Java code }
  1921. if not is_signed(def) and
  1922. (def.typ=orddef) and
  1923. (torddef(def).high>32767) then
  1924. finishandval:=65535;
  1925. end;
  1926. end;
  1927. 4: result:=a_iaload;
  1928. 8: result:=a_laload;
  1929. else
  1930. internalerror(2010120503);
  1931. end
  1932. end
  1933. else
  1934. begin
  1935. case size of
  1936. 1: result:=a_bastore;
  1937. 2: if not is_widechar(def) then
  1938. result:=a_sastore
  1939. else
  1940. result:=a_castore;
  1941. 4: result:=a_iastore;
  1942. 8: result:=a_lastore;
  1943. else
  1944. internalerror(2010120508);
  1945. end
  1946. end
  1947. end;
  1948. R_ADDRESSREGISTER:
  1949. if not isarray then
  1950. if isload then
  1951. result:=a_aload
  1952. else
  1953. result:=a_astore
  1954. else if isload then
  1955. result:=a_aaload
  1956. else
  1957. result:=a_aastore;
  1958. R_FPUREGISTER:
  1959. begin
  1960. case tfloatdef(def).floattype of
  1961. s32real:
  1962. if not isarray then
  1963. if isload then
  1964. result:=a_fload
  1965. else
  1966. result:=a_fstore
  1967. else if isload then
  1968. result:=a_faload
  1969. else
  1970. result:=a_fastore;
  1971. s64real:
  1972. if not isarray then
  1973. if isload then
  1974. result:=a_dload
  1975. else
  1976. result:=a_dstore
  1977. else if isload then
  1978. result:=a_daload
  1979. else
  1980. result:=a_dastore;
  1981. else
  1982. internalerror(2010120504);
  1983. end
  1984. end
  1985. else
  1986. internalerror(2010120502);
  1987. end;
  1988. end;
  1989. procedure thlcgjvm.resize_stack_int_val(list: TAsmList; fromsize, tosize: tdef; formemstore: boolean);
  1990. var
  1991. fromcgsize, tocgsize: tcgsize;
  1992. begin
  1993. { When storing to an array, field or global variable, make sure the
  1994. static type verification can determine that the stored value fits
  1995. within the boundaries of the declared type (to appease the Dalvik VM).
  1996. Local variables either get their type upgraded in the debug info,
  1997. or have no type information at all }
  1998. if formemstore and
  1999. (tosize.typ=orddef) then
  2000. if (torddef(tosize).ordtype in [u8bit,uchar]) then
  2001. tosize:=s8inttype
  2002. else if torddef(tosize).ordtype=u16bit then
  2003. tosize:=s16inttype;
  2004. fromcgsize:=def_cgsize(fromsize);
  2005. tocgsize:=def_cgsize(tosize);
  2006. if fromcgsize in [OS_S64,OS_64] then
  2007. begin
  2008. if not(tocgsize in [OS_S64,OS_64]) then
  2009. begin
  2010. { truncate }
  2011. list.concat(taicpu.op_none(a_l2i));
  2012. decstack(list,1);
  2013. end;
  2014. end
  2015. else if tocgsize in [OS_S64,OS_64] then
  2016. begin
  2017. { extend }
  2018. list.concat(taicpu.op_none(a_i2l));
  2019. incstack(list,1);
  2020. { if it was an unsigned 32 bit value, remove sign extension }
  2021. if fromcgsize=OS_32 then
  2022. a_op_const_stack(list,OP_AND,s64inttype,cardinal($ffffffff));
  2023. end;
  2024. { Conversions between 32 and 64 bit types have been completely handled
  2025. above. We still may have to truncate or sign extend in case the
  2026. destination type is smaller that the source type, or has a different
  2027. sign. In case the destination is a widechar and the source is not, we
  2028. also have to insert a conversion to widechar.
  2029. In case of Dalvik, we also have to insert conversions for e.g. byte
  2030. -> smallint, because truncating a byte happens via "and 255", and the
  2031. result is a longint in Dalvik's type verification model (so we have
  2032. to "truncate" it back to smallint) }
  2033. if (not(fromcgsize in [OS_S64,OS_64,OS_32,OS_S32]) or
  2034. not(tocgsize in [OS_S64,OS_64,OS_32,OS_S32])) and
  2035. (((current_settings.cputype=cpu_dalvik) and
  2036. not(tocgsize in [OS_32,OS_S32]) and
  2037. not is_signed(fromsize) and
  2038. is_signed(tosize)) or
  2039. (tcgsize2size[fromcgsize]>tcgsize2size[tocgsize]) or
  2040. ((tcgsize2size[fromcgsize]=tcgsize2size[tocgsize]) and
  2041. (fromcgsize<>tocgsize)) or
  2042. { needs to mask out the sign in the top 16 bits }
  2043. ((fromcgsize=OS_S8) and
  2044. (tocgsize=OS_16)) or
  2045. ((tosize=cwidechartype) and
  2046. (fromsize<>cwidechartype))) then
  2047. case tocgsize of
  2048. OS_8:
  2049. a_op_const_stack(list,OP_AND,s32inttype,255);
  2050. OS_S8:
  2051. list.concat(taicpu.op_none(a_i2b));
  2052. OS_16:
  2053. if (tosize.typ=orddef) and
  2054. (torddef(tosize).ordtype=uwidechar) then
  2055. list.concat(taicpu.op_none(a_i2c))
  2056. else
  2057. a_op_const_stack(list,OP_AND,s32inttype,65535);
  2058. OS_S16:
  2059. list.concat(taicpu.op_none(a_i2s));
  2060. end;
  2061. end;
  2062. procedure thlcgjvm.maybe_resize_stack_para_val(list: TAsmList; retdef: tdef; callside: boolean);
  2063. var
  2064. convsize: tdef;
  2065. begin
  2066. if (retdef.typ=orddef) then
  2067. begin
  2068. if (torddef(retdef).ordtype in [u8bit,u16bit,uchar]) and
  2069. (torddef(retdef).high>=(1 shl (retdef.size*8-1))) then
  2070. begin
  2071. convsize:=nil;
  2072. if callside then
  2073. if torddef(retdef).ordtype in [u8bit,uchar] then
  2074. convsize:=s8inttype
  2075. else
  2076. convsize:=s16inttype
  2077. else if torddef(retdef).ordtype in [u8bit,uchar] then
  2078. convsize:=u8inttype
  2079. else
  2080. convsize:=u16inttype;
  2081. if assigned(convsize) then
  2082. resize_stack_int_val(list,s32inttype,convsize,false);
  2083. end;
  2084. end;
  2085. end;
  2086. procedure thlcgjvm.g_adjust_stack_after_call(list: TAsmList; pd: tabstractprocdef; paraheight: longint; forceresdef: tdef);
  2087. var
  2088. totalremovesize: longint;
  2089. realresdef: tdef;
  2090. begin
  2091. if not assigned(forceresdef) then
  2092. realresdef:=pd.returndef
  2093. else
  2094. realresdef:=forceresdef;
  2095. { a constructor doesn't actually return a value in the jvm }
  2096. if (tabstractprocdef(pd).proctypeoption=potype_constructor) then
  2097. totalremovesize:=paraheight
  2098. else
  2099. { even a byte takes up a full stackslot -> align size to multiple of 4 }
  2100. totalremovesize:=paraheight-(align(realresdef.size,4) shr 2);
  2101. { remove parameters from internal evaluation stack counter (in case of
  2102. e.g. no parameters and a result, it can also increase) }
  2103. if totalremovesize>0 then
  2104. decstack(list,totalremovesize)
  2105. else if totalremovesize<0 then
  2106. incstack(list,-totalremovesize);
  2107. end;
  2108. procedure thlcgjvm.allocate_implicit_struct_with_base_ref(list: TAsmList; vs: tabstractvarsym; ref: treference);
  2109. var
  2110. tmpref: treference;
  2111. begin
  2112. ref.symbol:=current_asmdata.RefAsmSymbol(vs.mangledname);
  2113. tg.gethltemp(list,vs.vardef,vs.vardef.size,tt_persistent,tmpref);
  2114. { only copy the reference, not the actual data }
  2115. a_load_ref_ref(list,java_jlobject,java_jlobject,tmpref,ref);
  2116. { remains live since there's still a reference to the created
  2117. entity }
  2118. tg.ungettemp(list,tmpref);
  2119. end;
  2120. procedure thlcgjvm.allocate_enum_with_base_ref(list: TAsmList; vs: tabstractvarsym; const initref: treference; destbaseref: treference);
  2121. begin
  2122. destbaseref.symbol:=current_asmdata.RefAsmSymbol(vs.mangledname);
  2123. { only copy the reference, not the actual data }
  2124. a_load_ref_ref(list,java_jlobject,java_jlobject,initref,destbaseref);
  2125. end;
  2126. function thlcgjvm.get_enum_init_val_ref(def: tdef; out ref: treference): boolean;
  2127. var
  2128. sym: tstaticvarsym;
  2129. begin
  2130. result:=false;
  2131. sym:=tstaticvarsym(tcpuenumdef(tenumdef(def).getbasedef).classdef.symtable.Find('__FPC_ZERO_INITIALIZER'));
  2132. { no enum with ordinal value 0 -> exit }
  2133. if not assigned(sym) then
  2134. exit;
  2135. reference_reset_symbol(ref,current_asmdata.RefAsmSymbol(sym.mangledname),0,4);
  2136. result:=true;
  2137. end;
  2138. procedure thlcgjvm.allocate_implicit_structs_for_st_with_base_ref(list: TAsmList; st: tsymtable; const ref: treference; allocvartyp: tsymtyp);
  2139. var
  2140. vs: tabstractvarsym;
  2141. def: tdef;
  2142. i: longint;
  2143. initref: treference;
  2144. begin
  2145. for i:=0 to st.symlist.count-1 do
  2146. begin
  2147. if (tsym(st.symlist[i]).typ<>allocvartyp) then
  2148. continue;
  2149. vs:=tabstractvarsym(st.symlist[i]);
  2150. if sp_static in vs.symoptions then
  2151. continue;
  2152. { vo_is_external and vo_has_local_copy means a staticvarsym that is
  2153. alias for a constsym, whose sole purpose is for allocating and
  2154. intialising the constant }
  2155. if [vo_is_external,vo_has_local_copy]*vs.varoptions=[vo_is_external] then
  2156. continue;
  2157. { threadvar innitializations are handled at the node tree level }
  2158. if vo_is_thread_var in vs.varoptions then
  2159. begin
  2160. { nothing }
  2161. end
  2162. else if jvmimplicitpointertype(vs.vardef) then
  2163. allocate_implicit_struct_with_base_ref(list,vs,ref)
  2164. { enums are class instances in Java, while they are ordinals in
  2165. Pascal. When they are initialized with enum(0), such as in
  2166. constructors or global variables, initialize them with the
  2167. enum instance for 0 if it exists (if not, it remains nil since
  2168. there is no valid enum value in it) }
  2169. else if (vs.vardef.typ=enumdef) and
  2170. ((vs.typ<>fieldvarsym) or
  2171. (tdef(vs.owner.defowner).typ<>objectdef) or
  2172. (ts_jvm_enum_field_init in current_settings.targetswitches)) and
  2173. get_enum_init_val_ref(vs.vardef,initref) then
  2174. allocate_enum_with_base_ref(list,vs,initref,ref);
  2175. end;
  2176. { process symtables of routines part of this symtable (for local typed
  2177. constants) }
  2178. if allocvartyp=staticvarsym then
  2179. begin
  2180. for i:=0 to st.deflist.count-1 do
  2181. begin
  2182. def:=tdef(st.deflist[i]);
  2183. { the unit symtable also contains the methods of classes defined
  2184. in that unit -> skip them when processing the unit itself.
  2185. Localst is not assigned for the main program code.
  2186. Localst can be the same as st in case of unit init code. }
  2187. if (def.typ<>procdef) or
  2188. (def.owner<>st) or
  2189. not assigned(tprocdef(def).localst) or
  2190. (tprocdef(def).localst=st) then
  2191. continue;
  2192. allocate_implicit_structs_for_st_with_base_ref(list,tprocdef(def).localst,ref,allocvartyp);
  2193. end;
  2194. end;
  2195. end;
  2196. procedure thlcgjvm.gen_initialize_fields_code(list: TAsmList);
  2197. var
  2198. sym: tsym;
  2199. selfpara: tparavarsym;
  2200. selfreg: tregister;
  2201. ref: treference;
  2202. obj: tabstractrecorddef;
  2203. i: longint;
  2204. needinit: boolean;
  2205. begin
  2206. obj:=tabstractrecorddef(current_procinfo.procdef.owner.defowner);
  2207. { check whether there are any fields that need initialisation }
  2208. needinit:=false;
  2209. for i:=0 to obj.symtable.symlist.count-1 do
  2210. begin
  2211. sym:=tsym(obj.symtable.symlist[i]);
  2212. if (sym.typ=fieldvarsym) and
  2213. not(sp_static in sym.symoptions) and
  2214. (jvmimplicitpointertype(tfieldvarsym(sym).vardef) or
  2215. ((tfieldvarsym(sym).vardef.typ=enumdef) and
  2216. get_enum_init_val_ref(tfieldvarsym(sym).vardef,ref))) then
  2217. begin
  2218. needinit:=true;
  2219. break;
  2220. end;
  2221. end;
  2222. if not needinit then
  2223. exit;
  2224. selfpara:=tparavarsym(current_procinfo.procdef.parast.find('self'));
  2225. if not assigned(selfpara) then
  2226. internalerror(2011033001);
  2227. selfreg:=getaddressregister(list,selfpara.vardef);
  2228. a_load_loc_reg(list,obj,obj,selfpara.localloc,selfreg);
  2229. cgutils.reference_reset_base(ref,selfreg,0,1);
  2230. allocate_implicit_structs_for_st_with_base_ref(list,obj.symtable,ref,fieldvarsym);
  2231. end;
  2232. procedure thlcgjvm.gen_typecheck(list: TAsmList; checkop: tasmop; checkdef: tdef);
  2233. begin
  2234. { replace special types with their equivalent class type }
  2235. if (checkdef.typ=pointerdef) and
  2236. jvmimplicitpointertype(tpointerdef(checkdef).pointeddef) then
  2237. checkdef:=tpointerdef(checkdef).pointeddef;
  2238. if (checkdef=voidpointertype) or
  2239. (checkdef.typ=formaldef) then
  2240. checkdef:=java_jlobject
  2241. else if checkdef.typ=enumdef then
  2242. checkdef:=tcpuenumdef(checkdef).classdef
  2243. else if checkdef.typ=setdef then
  2244. begin
  2245. if tsetdef(checkdef).elementdef.typ=enumdef then
  2246. checkdef:=java_juenumset
  2247. else
  2248. checkdef:=java_jubitset;
  2249. end
  2250. else if checkdef.typ=procvardef then
  2251. checkdef:=tcpuprocvardef(checkdef).classdef
  2252. else if is_wide_or_unicode_string(checkdef) then
  2253. checkdef:=java_jlstring
  2254. else if is_ansistring(checkdef) then
  2255. checkdef:=java_ansistring
  2256. else if is_shortstring(checkdef) then
  2257. checkdef:=java_shortstring;
  2258. if checkdef.typ in [objectdef,recorddef] then
  2259. list.concat(taicpu.op_sym(checkop,current_asmdata.RefAsmSymbol(tabstractrecorddef(checkdef).jvm_full_typename(true))))
  2260. else if checkdef.typ=classrefdef then
  2261. list.concat(taicpu.op_sym(checkop,current_asmdata.RefAsmSymbol('java/lang/Class')))
  2262. else
  2263. list.concat(taicpu.op_sym(checkop,current_asmdata.RefAsmSymbol(jvmencodetype(checkdef,false))));
  2264. end;
  2265. procedure thlcgjvm.resizestackfpuval(list: TAsmList; fromsize, tosize: tcgsize);
  2266. begin
  2267. if (fromsize=OS_F32) and
  2268. (tosize=OS_F64) then
  2269. begin
  2270. list.concat(taicpu.op_none(a_f2d));
  2271. incstack(list,1);
  2272. end
  2273. else if (fromsize=OS_F64) and
  2274. (tosize=OS_F32) then
  2275. begin
  2276. list.concat(taicpu.op_none(a_d2f));
  2277. decstack(list,1);
  2278. end;
  2279. end;
  2280. procedure thlcgjvm.maybepreparedivu32(list: TAsmList; var op: topcg; size: tdef; out isdivu32: boolean);
  2281. begin
  2282. if (op=OP_DIV) and
  2283. (def_cgsize(size)=OS_32) then
  2284. begin
  2285. { needs zero-extension to 64 bit, because the JVM only supports
  2286. signed divisions }
  2287. resize_stack_int_val(list,u32inttype,s64inttype,false);
  2288. op:=OP_IDIV;
  2289. isdivu32:=true;
  2290. end
  2291. else
  2292. isdivu32:=false;
  2293. end;
  2294. function thlcgjvm.a_call_name_intern(list: TAsmList; pd: tprocdef; const s: TSymStr; forceresdef: tdef; inheritedcall: boolean): tcgpara;
  2295. var
  2296. opc: tasmop;
  2297. begin
  2298. {
  2299. invoke types:
  2300. * invokeinterface: call method from an interface (must also specify
  2301. number of parameters in terms of stack slot count!)
  2302. * invokespecial: invoke a constructor, method in a superclass,
  2303. or private instance method
  2304. * invokestatic: invoke a class method (private or not)
  2305. * invokevirtual: invoke a regular method
  2306. }
  2307. case pd.owner.symtabletype of
  2308. globalsymtable,
  2309. staticsymtable,
  2310. localsymtable:
  2311. { regular and nested procedures are turned into static methods }
  2312. opc:=a_invokestatic;
  2313. objectsymtable:
  2314. begin
  2315. case tobjectdef(pd.owner.defowner).objecttype of
  2316. odt_javaclass:
  2317. begin
  2318. if (po_classmethod in pd.procoptions) or
  2319. (pd.proctypeoption=potype_operator) then
  2320. opc:=a_invokestatic
  2321. else if (pd.visibility=vis_strictprivate) or
  2322. (pd.proctypeoption=potype_constructor) or
  2323. inheritedcall then
  2324. opc:=a_invokespecial
  2325. else
  2326. opc:=a_invokevirtual;
  2327. end;
  2328. odt_interfacejava:
  2329. { static interface methods are not allowed }
  2330. opc:=a_invokeinterface;
  2331. else
  2332. internalerror(2010122601);
  2333. end;
  2334. end;
  2335. recordsymtable:
  2336. begin
  2337. if (po_staticmethod in pd.procoptions) or
  2338. (pd.proctypeoption=potype_operator) then
  2339. opc:=a_invokestatic
  2340. else if (pd.visibility=vis_strictprivate) or
  2341. (pd.proctypeoption=potype_constructor) or
  2342. inheritedcall then
  2343. opc:=a_invokespecial
  2344. else
  2345. opc:=a_invokevirtual;
  2346. end
  2347. else
  2348. internalerror(2010122602);
  2349. end;
  2350. if (opc<>a_invokeinterface) then
  2351. list.concat(taicpu.op_sym(opc,current_asmdata.RefAsmSymbol(s)))
  2352. else
  2353. begin
  2354. pd.init_paraloc_info(calleeside);
  2355. list.concat(taicpu.op_sym_const(opc,current_asmdata.RefAsmSymbol(s),pd.calleeargareasize));
  2356. end;
  2357. result:=get_call_result_cgpara(pd,forceresdef);
  2358. end;
  2359. procedure create_hlcodegen;
  2360. begin
  2361. hlcg:=thlcgjvm.create;
  2362. create_codegen;
  2363. end;
  2364. begin
  2365. chlcgobj:=thlcgjvm;
  2366. end.