njvmcnv.pas 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. {
  2. Copyright (c) 1998-2011 by Florian Klaempfl and Jonas Maebe
  3. Generate JVM code for type converting nodes
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************}
  16. unit njvmcnv;
  17. {$i fpcdefs.inc}
  18. interface
  19. uses
  20. node,ncnv,ncgcnv,
  21. symtype;
  22. type
  23. tjvmtypeconvnode = class(tcgtypeconvnode)
  24. function typecheck_dynarray_to_openarray: tnode; override;
  25. function typecheck_string_to_chararray: tnode; override;
  26. function pass_1: tnode; override;
  27. function simplify(forinline: boolean): tnode; override;
  28. procedure second_int_to_int;override;
  29. { procedure second_string_to_string;override; }
  30. { procedure second_cstring_to_pchar;override; }
  31. { procedure second_string_to_chararray;override; }
  32. { procedure second_array_to_pointer;override; }
  33. function first_int_to_real: tnode; override;
  34. { procedure second_pointer_to_array;override; }
  35. { procedure second_chararray_to_string;override; }
  36. { procedure second_char_to_string;override; }
  37. procedure second_int_to_real;override;
  38. { procedure second_real_to_real;override; }
  39. { procedure second_cord_to_pointer;override; }
  40. { procedure second_proc_to_procvar;override; }
  41. procedure second_bool_to_int;override;
  42. procedure second_int_to_bool;override;
  43. { procedure second_load_smallset;override; }
  44. { procedure second_ansistring_to_pchar;override; }
  45. { procedure second_pchar_to_string;override; }
  46. { procedure second_class_to_intf;override; }
  47. { procedure second_char_to_char;override; }
  48. procedure second_elem_to_openarray; override;
  49. function target_specific_explicit_typeconv: boolean; override;
  50. function target_specific_general_typeconv: boolean; override;
  51. protected
  52. function do_target_specific_explicit_typeconv(check_only: boolean; out resnode: tnode): boolean;
  53. end;
  54. tjvmasnode = class(tcgasnode)
  55. protected
  56. { to discern beween "obj as tclassref" and "tclassref(obj)" }
  57. classreftypecast: boolean;
  58. function target_specific_typecheck: boolean;override;
  59. public
  60. function pass_1 : tnode;override;
  61. procedure pass_generate_code; override;
  62. function dogetcopy: tnode; override;
  63. function docompare(p: tnode): boolean; override;
  64. constructor ppuload(t: tnodetype; ppufile: tcompilerppufile); override;
  65. procedure ppuwrite(ppufile: tcompilerppufile); override;
  66. end;
  67. tjvmisnode = class(tisnode)
  68. protected
  69. function target_specific_typecheck: boolean;override;
  70. public
  71. function pass_1 : tnode;override;
  72. procedure pass_generate_code; override;
  73. end;
  74. implementation
  75. uses
  76. verbose,globals,globtype,
  77. symconst,symdef,symsym,symtable,aasmbase,aasmdata,
  78. defutil,defcmp,jvmdef,
  79. cgbase,cgutils,pass_1,pass_2,
  80. nbas,ncon,ncal,nld,nmem,procinfo,
  81. nutils,
  82. cpubase,aasmcpu,
  83. tgobj,hlcgobj,hlcgcpu;
  84. {*****************************************************************************
  85. TypeCheckTypeConv
  86. *****************************************************************************}
  87. function isvalidprocvartypeconv(fromdef, todef: tdef): boolean;
  88. var
  89. tmethoddef: tdef;
  90. function docheck(def1,def2: tdef): boolean;
  91. begin
  92. result:=false;
  93. if def1.typ<>procvardef then
  94. exit;
  95. if tprocvardef(def1).is_addressonly then
  96. result:=
  97. (def2=java_jlobject) or
  98. (def2=voidpointertype)
  99. else
  100. begin
  101. if not assigned(tmethoddef) then
  102. tmethoddef:=search_system_type('TMETHOD').typedef;
  103. result:=
  104. (def2=methodpointertype) or
  105. (def2=tmethoddef);
  106. end;
  107. end;
  108. begin
  109. tmethoddef:=nil;
  110. result:=
  111. docheck(fromdef,todef) or
  112. docheck(todef,fromdef);
  113. end;
  114. function tjvmtypeconvnode.typecheck_dynarray_to_openarray: tnode;
  115. begin
  116. { all arrays are equal in Java }
  117. left.resultdef:=resultdef;
  118. result:=left;
  119. left:=nil;
  120. end;
  121. function tjvmtypeconvnode.typecheck_string_to_chararray: tnode;
  122. var
  123. newblock: tblocknode;
  124. newstat: tstatementnode;
  125. restemp: ttempcreatenode;
  126. chartype: string;
  127. begin
  128. if (left.nodetype = stringconstn) and
  129. (tstringconstnode(left).cst_type=cst_conststring) then
  130. inserttypeconv(left,cunicodestringtype);
  131. { even constant strings have to be handled via a helper }
  132. if is_widechar(tarraydef(resultdef).elementdef) then
  133. chartype:='widechar'
  134. else
  135. chartype:='char';
  136. newblock:=internalstatements(newstat);
  137. restemp:=ctempcreatenode.create(resultdef,resultdef.size,tt_persistent,false);
  138. addstatement(newstat,restemp);
  139. addstatement(newstat,ccallnode.createintern('fpc_'+tstringdef(left.resultdef).stringtypname+
  140. '_to_'+chartype+'array',ccallparanode.create(left,ccallparanode.create(
  141. ctemprefnode.create(restemp),nil))));
  142. addstatement(newstat,ctempdeletenode.create_normal_temp(restemp));
  143. addstatement(newstat,ctemprefnode.create(restemp));
  144. result:=newblock;
  145. left:=nil;
  146. end;
  147. {*****************************************************************************
  148. FirstTypeConv
  149. *****************************************************************************}
  150. function tjvmtypeconvnode.first_int_to_real: tnode;
  151. begin
  152. if not is_64bitint(left.resultdef) then
  153. if is_signed(left.resultdef) or
  154. (left.resultdef.size<4) then
  155. inserttypeconv(left,s32inttype)
  156. else
  157. inserttypeconv(left,u32inttype);
  158. firstpass(left);
  159. result := nil;
  160. expectloc:=LOC_FPUREGISTER;
  161. end;
  162. function tjvmtypeconvnode.pass_1: tnode;
  163. begin
  164. if (nf_explicit in flags) then
  165. begin
  166. do_target_specific_explicit_typeconv(false,result);
  167. if assigned(result) then
  168. exit;
  169. end;
  170. result:=inherited pass_1;
  171. end;
  172. function tjvmtypeconvnode.simplify(forinline: boolean): tnode;
  173. begin
  174. result:=inherited simplify(forinline);
  175. if assigned(result) then
  176. exit;
  177. { string constants passed to java.lang.String must be converted to
  178. widestring }
  179. if (left.nodetype=stringconstn) and
  180. not(tstringconstnode(left).cst_type in [cst_unicodestring,cst_widestring]) and
  181. (maybe_find_real_class_definition(resultdef,false)=java_jlstring) then
  182. inserttypeconv(left,cunicodestringtype);
  183. end;
  184. {*****************************************************************************
  185. SecondTypeConv
  186. *****************************************************************************}
  187. procedure tjvmtypeconvnode.second_int_to_int;
  188. var
  189. ressize,
  190. leftsize : longint;
  191. begin
  192. { insert range check if not explicit conversion }
  193. if not(nf_explicit in flags) then
  194. hlcg.g_rangecheck(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef);
  195. { is the result size smaller? when typecasting from void
  196. we always reuse the current location, because there is
  197. nothing that we can load in a register }
  198. ressize:=resultdef.size;
  199. leftsize :=left.resultdef.size;
  200. if ((ressize<>leftsize) or
  201. ((location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and
  202. (location.reference.arrayreftype<>art_none) and
  203. (is_widechar(left.resultdef)<>is_widechar(resultdef))) or
  204. is_bitpacked_access(left)) and
  205. not is_void(left.resultdef) then
  206. begin
  207. location_copy(location,left.location);
  208. { reuse a loc_reference when the newsize is smaller than
  209. than the original, except
  210. a) for arrays (they use different load instructions for
  211. differently sized data types)
  212. b) when going from 8 to 4 bytes, because these are different
  213. data types
  214. -- note that this is different from other targets, and will
  215. break stuff like passing byte(shortintvar) to a var-parameter;
  216. although that may be "fixed" again because we have to use
  217. copy-in/copy-out to emulate var-parameters anyway... }
  218. if (location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and
  219. (location.reference.arrayreftype=art_none) and
  220. (ressize<leftsize) and
  221. (leftsize<=4) then
  222. begin
  223. location.size:=def_cgsize(resultdef);
  224. { no adjustment of the ffset even though Java is big endian,
  225. because the load instruction will remain the same }
  226. end
  227. else
  228. hlcg.location_force_reg(current_asmdata.CurrAsmList,location,left.resultdef,resultdef,false);
  229. end
  230. else
  231. begin
  232. location_copy(location,left.location);
  233. location.size:=def_cgsize(resultdef);
  234. if (ressize < sizeof(aint)) and
  235. (location.loc in [LOC_REGISTER,LOC_CREGISTER]) and
  236. (def_cgsize(left.resultdef)<>def_cgsize(resultdef)) then
  237. begin
  238. location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
  239. location.loc:=LOC_REGISTER;
  240. hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,left.resultdef,resultdef,left.location.register,location.register);
  241. end;
  242. end;
  243. end;
  244. procedure tjvmtypeconvnode.second_int_to_real;
  245. var
  246. srcsize, ressize: longint;
  247. procedure convertsignedstackloc;
  248. begin
  249. case srcsize of
  250. 4:
  251. case ressize of
  252. 4:
  253. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_i2f));
  254. 8:
  255. begin
  256. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_i2d));
  257. thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,1);
  258. end;
  259. else
  260. internalerror(2011010601);
  261. end;
  262. 8:
  263. case ressize of
  264. 4:
  265. begin
  266. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_l2f));
  267. thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  268. end;
  269. 8:
  270. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_l2d));
  271. else
  272. internalerror(2011010602);
  273. end;
  274. else
  275. internalerror(2011010603);
  276. end;
  277. end;
  278. var
  279. signeddef : tdef;
  280. l1 : tasmlabel;
  281. begin
  282. srcsize:=left.resultdef.size;
  283. ressize:=resultdef.size;
  284. location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
  285. location.register:=hlcg.getfpuregister(current_asmdata.CurrAsmList,resultdef);
  286. { first always convert as if it's a signed number }
  287. thlcgjvm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
  288. convertsignedstackloc;
  289. if not is_signed(left.resultdef) then
  290. begin
  291. { if it was unsigned, add high(cardinal)+1/high(qword)+1 in case
  292. the signed interpretation is < 0 }
  293. current_asmdata.getjumplabel(l1);
  294. if srcsize=4 then
  295. signeddef:=s32inttype
  296. else
  297. signeddef:=s64inttype;
  298. hlcg.a_cmp_const_loc_label(current_asmdata.CurrAsmList,signeddef,OC_GTE,0,left.location,l1);
  299. if srcsize=4 then
  300. thlcgjvm(hlcg).a_loadfpu_const_stack(current_asmdata.CurrAsmList,resultdef,4294967296.0)
  301. else
  302. thlcgjvm(hlcg).a_loadfpu_const_stack(current_asmdata.CurrAsmList,resultdef,18446744073709551616.0);
  303. if ressize=4 then
  304. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_fadd))
  305. else
  306. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_dadd));
  307. hlcg.a_label(current_asmdata.CurrAsmList,l1);
  308. end;
  309. thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
  310. end;
  311. procedure tjvmtypeconvnode.second_bool_to_int;
  312. var
  313. newsize: tcgsize;
  314. oldTrueLabel,oldFalseLabel : tasmlabel;
  315. begin
  316. oldTrueLabel:=current_procinfo.CurrTrueLabel;
  317. oldFalseLabel:=current_procinfo.CurrFalseLabel;
  318. current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
  319. current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
  320. secondpass(left);
  321. location_copy(location,left.location);
  322. newsize:=def_cgsize(resultdef);
  323. { byte(bytebool) or word(wordbool) or longint(longbool) must be }
  324. { accepted for var parameters and assignments, and must not }
  325. { change the ordinal value or value location. }
  326. { htypechk.valid_for_assign ensures that such locations with a }
  327. { size<sizeof(register) cannot be LOC_CREGISTER (they otherwise }
  328. { could be in case of a plain assignment), and LOC_REGISTER can }
  329. { never be an assignment target. The remaining LOC_REGISTER/ }
  330. { LOC_CREGISTER locations do have to be sign/zero-extended. }
  331. { -- Note: this does not work for Java and 2/4 byte sized
  332. values, because bytebool/wordbool are signed and
  333. are stored in 4 byte locations -> will result in
  334. "byte" with the value high(cardinal); see remark
  335. in second_int_to_int above regarding consequences }
  336. if not(nf_explicit in flags) or
  337. (location.loc in [LOC_FLAGS,LOC_JUMP]) or
  338. ((newsize<>left.location.size) and
  339. ((left.resultdef.size<>resultdef.size) or
  340. not(left.resultdef.size in [4,8]))
  341. ) then
  342. hlcg.location_force_reg(current_asmdata.CurrAsmList,location,left.resultdef,resultdef,true)
  343. else
  344. { may differ in sign, e.g. bytebool -> byte }
  345. location.size:=newsize;
  346. current_procinfo.CurrTrueLabel:=oldTrueLabel;
  347. current_procinfo.CurrFalseLabel:=oldFalseLabel;
  348. end;
  349. procedure tjvmtypeconvnode.second_int_to_bool;
  350. var
  351. hlabel1,hlabel2,oldTrueLabel,oldFalseLabel : tasmlabel;
  352. newsize : tcgsize;
  353. begin
  354. oldTrueLabel:=current_procinfo.CurrTrueLabel;
  355. oldFalseLabel:=current_procinfo.CurrFalseLabel;
  356. current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
  357. current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
  358. secondpass(left);
  359. if codegenerror then
  360. exit;
  361. { Explicit typecasts from any ordinal type to a boolean type }
  362. { must not change the ordinal value }
  363. if (nf_explicit in flags) and
  364. not(left.location.loc in [LOC_FLAGS,LOC_JUMP]) then
  365. begin
  366. location_copy(location,left.location);
  367. newsize:=def_cgsize(resultdef);
  368. { change of size? change sign only if location is LOC_(C)REGISTER? Then we have to sign/zero-extend }
  369. if (tcgsize2size[newsize]<>tcgsize2size[left.location.size]) or
  370. ((newsize<>left.location.size) and (location.loc in [LOC_REGISTER,LOC_CREGISTER])) then
  371. hlcg.location_force_reg(current_asmdata.CurrAsmList,location,left.resultdef,resultdef,true)
  372. else
  373. location.size:=newsize;
  374. current_procinfo.CurrTrueLabel:=oldTrueLabel;
  375. current_procinfo.CurrFalseLabel:=oldFalseLabel;
  376. exit;
  377. end;
  378. location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
  379. location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
  380. current_asmdata.getjumplabel(hlabel2);
  381. case left.location.loc of
  382. LOC_CREFERENCE,LOC_REFERENCE,LOC_REGISTER,LOC_CREGISTER:
  383. begin
  384. current_asmdata.getjumplabel(hlabel1);
  385. hlcg.a_cmp_const_loc_label(current_asmdata.CurrAsmList,left.resultdef,OC_EQ,0,left.location,hlabel1);
  386. end;
  387. LOC_JUMP :
  388. begin
  389. hlabel1:=current_procinfo.CurrFalseLabel;
  390. hlcg.a_label(current_asmdata.CurrAsmList,current_procinfo.CurrTrueLabel);
  391. end;
  392. else
  393. internalerror(10062);
  394. end;
  395. if not(is_cbool(resultdef)) then
  396. thlcgjvm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,resultdef,1,R_INTREGISTER)
  397. else
  398. thlcgjvm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,resultdef,-1,R_INTREGISTER);
  399. { we jump over the next constant load -> they don't appear on the
  400. stack simulataneously }
  401. thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  402. hlcg.a_jmp_always(current_asmdata.CurrAsmList,hlabel2);
  403. hlcg.a_label(current_asmdata.CurrAsmList,hlabel1);
  404. thlcgjvm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,resultdef,0,R_INTREGISTER);
  405. hlcg.a_label(current_asmdata.CurrAsmList,hlabel2);
  406. thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
  407. current_procinfo.CurrTrueLabel:=oldTrueLabel;
  408. current_procinfo.CurrFalseLabel:=oldFalseLabel;
  409. end;
  410. procedure tjvmtypeconvnode.second_elem_to_openarray;
  411. var
  412. primitivetype: boolean;
  413. opc: tasmop;
  414. mangledname: string;
  415. basereg: tregister;
  416. arrayref: treference;
  417. begin
  418. { create an array with one element of the required type }
  419. thlcgjvm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,s32inttype,1,R_INTREGISTER);
  420. mangledname:=jvmarrtype(left.resultdef,primitivetype);
  421. if primitivetype then
  422. opc:=a_newarray
  423. else
  424. opc:=a_anewarray;
  425. { doesn't change stack height: one int replaced by one reference }
  426. current_asmdata.CurrAsmList.concat(taicpu.op_sym(opc,current_asmdata.RefAsmSymbol(mangledname)));
  427. { store the data in the newly created array }
  428. basereg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,java_jlobject);
  429. thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,java_jlobject,basereg);
  430. reference_reset_base(arrayref,basereg,0,4);
  431. arrayref.arrayreftype:=art_indexconst;
  432. arrayref.indexoffset:=0;
  433. hlcg.a_load_loc_ref(current_asmdata.CurrAsmList,left.resultdef,left.resultdef,left.location,arrayref);
  434. location_reset_ref(location,LOC_REFERENCE,OS_ADDR,4);
  435. tg.gethltemp(current_asmdata.CurrAsmList,java_jlobject,4,tt_normal,location.reference);
  436. hlcg.a_load_reg_ref(current_asmdata.CurrAsmList,java_jlobject,java_jlobject,basereg,location.reference);
  437. end;
  438. procedure get_most_nested_types(var fromdef, todef: tdef);
  439. begin
  440. while is_dynamic_array(fromdef) and
  441. is_dynamic_array(todef) do
  442. begin
  443. fromdef:=tarraydef(fromdef).elementdef;
  444. todef:=tarraydef(todef).elementdef;
  445. end;
  446. fromdef:=maybe_find_real_class_definition(fromdef,false);
  447. todef:=maybe_find_real_class_definition(todef,false);
  448. end;
  449. function tjvmtypeconvnode.do_target_specific_explicit_typeconv(check_only: boolean; out resnode: tnode): boolean;
  450. { handle explicit typecast from int to to real or vice versa }
  451. function int_real_explicit_typecast(fdef: tfloatdef; const singlemethod, doublemethod: string): tnode;
  452. var
  453. csym: ttypesym;
  454. psym: tsym;
  455. begin
  456. { use the float/double to raw bits methods to get the bit pattern }
  457. if fdef.floattype=s32real then
  458. begin
  459. csym:=search_system_type('JLFLOAT');
  460. psym:=search_struct_member(tobjectdef(csym.typedef),singlemethod);
  461. end
  462. else
  463. begin
  464. csym:=search_system_type('JLDOUBLE');
  465. psym:=search_struct_member(tobjectdef(csym.typedef),doublemethod);
  466. end;
  467. if not assigned(psym) or
  468. (psym.typ<>procsym) then
  469. internalerror(2011012901);
  470. { call the (static class) method to get the raw bits }
  471. result:=ccallnode.create(ccallparanode.create(left,nil),
  472. tprocsym(psym),psym.owner,
  473. cloadvmtaddrnode.create(ctypenode.create(csym.typedef)),[]);
  474. { convert the result to the result type of this type conversion node }
  475. inserttypeconv_explicit(result,resultdef);
  476. { left is reused }
  477. left:=nil;
  478. end;
  479. function ptr_no_typecheck_required(fromdef, todef: tdef): boolean;
  480. function check_type_equality(def1,def2: tdef): boolean;
  481. begin
  482. result:=true;
  483. if is_ansistring(def1) and
  484. (def2=java_ansistring) then
  485. exit;
  486. if is_wide_or_unicode_string(def1) and
  487. (def2=java_jlstring) then
  488. exit;
  489. if def1.typ=pointerdef then
  490. begin
  491. if is_shortstring(tpointerdef(def1).pointeddef) and
  492. (def2=java_shortstring) then
  493. exit;
  494. end;
  495. result:=false;
  496. end;
  497. function check_array_type_equality(def1,def2: tdef): boolean;
  498. begin
  499. result:=true;
  500. if is_shortstring(def1) and
  501. (def2=java_shortstring) then
  502. exit;
  503. result:=false;
  504. end;
  505. begin
  506. result:=true;
  507. if (todef=java_jlobject) or
  508. (todef=voidpointertype) then
  509. exit;
  510. if compare_defs(fromdef,todef,nothingn)>=te_equal then
  511. exit;
  512. { trecorddef.is_related() must work for inheritance/method checking,
  513. but do not allow records to be directly typecasted into class/
  514. pointer types (you have to use FpcBaseRecordType(@rec) instead) }
  515. if not is_record(fromdef) and
  516. fromdef.is_related(todef) then
  517. exit;
  518. if check_type_equality(fromdef,todef) then
  519. exit;
  520. if check_type_equality(todef,fromdef) then
  521. exit;
  522. if (fromdef.typ=pointerdef) and
  523. (tpointerdef(fromdef).pointeddef.typ=recorddef) and
  524. (todef=java_fpcbaserecordtype) then
  525. exit;
  526. { all classrefs are currently java.lang.Class at the bytecode level }
  527. if (fromdef.typ=classrefdef) and
  528. (todef.typ=objectdef) and
  529. (todef=search_system_type('JLCLASS').typedef) then
  530. exit;
  531. if (fromdef.typ=classrefdef) and
  532. (todef.typ=classrefdef) and
  533. tclassrefdef(fromdef).pointeddef.is_related(tclassrefdef(todef).pointeddef) then
  534. exit;
  535. { special case: "array of shortstring" to "array of ShortstringClass"
  536. and "array of <record>" to "array of FpcRecordBaseType" (normally
  537. you have to use ShortstringClass(@shortstrvar) etc, but that's not
  538. possible in case of passing arrays to e.g. setlength) }
  539. if is_dynamic_array(left.resultdef) and
  540. is_dynamic_array(resultdef) then
  541. begin
  542. if check_array_type_equality(fromdef,todef) or
  543. check_array_type_equality(todef,fromdef) then
  544. exit;
  545. if is_record(fromdef) and
  546. (todef=java_fpcbaserecordtype) then
  547. exit;
  548. end;
  549. result:=false;
  550. end;
  551. var
  552. fromclasscompatible,
  553. toclasscompatible,
  554. procvarconv: boolean;
  555. fromdef,
  556. todef: tdef;
  557. fromarrtype,
  558. toarrtype: char;
  559. begin
  560. resnode:=nil;
  561. { This routine is only called for explicit typeconversions of same-sized
  562. entities that aren't handled by normal type conversions -> bit pattern
  563. reinterpretations. In the JVM, many of these also need special
  564. handling because of the type safety. }
  565. { don't allow conversions between object-based and non-object-based
  566. types }
  567. procvarconv:=isvalidprocvartypeconv(left.resultdef,resultdef);
  568. fromclasscompatible:=
  569. (left.resultdef.typ=formaldef) or
  570. (left.resultdef.typ=pointerdef) or
  571. (left.resultdef.typ=objectdef) or
  572. is_dynamic_array(left.resultdef) or
  573. ((left.resultdef.typ in [stringdef,classrefdef]) and
  574. not is_shortstring(left.resultdef)) or
  575. procvarconv;
  576. toclasscompatible:=
  577. (resultdef.typ=pointerdef) or
  578. (resultdef.typ=objectdef) or
  579. is_dynamic_array(resultdef) or
  580. ((resultdef.typ in [stringdef,classrefdef]) and
  581. not is_shortstring(resultdef)) or
  582. procvarconv;
  583. { typescasts from void (the result of untyped_ptr^) to an implicit
  584. pointertype (record, array, ...) also needs a typecheck }
  585. if is_void(left.resultdef) and
  586. jvmimplicitpointertype(resultdef) then
  587. begin
  588. fromclasscompatible:=true;
  589. toclasscompatible:=true;
  590. end;
  591. if fromclasscompatible and toclasscompatible then
  592. begin
  593. { we need an as-node to check the validity of the conversion (since
  594. it wasn't handled by another type conversion, we know it can't
  595. have been valid normally)
  596. Exceptions: (most nested) destination is
  597. * java.lang.Object, since everything is compatible with that type
  598. * related to source
  599. * a primitive that are represented by the same type in Java
  600. (e.g., byte and shortint) }
  601. { in case of arrays, check the compatibility of the innermost types }
  602. fromdef:=left.resultdef;
  603. todef:=resultdef;
  604. get_most_nested_types(fromdef,todef);
  605. fromarrtype:=jvmarrtype_setlength(fromdef);
  606. toarrtype:=jvmarrtype_setlength(todef);
  607. if not ptr_no_typecheck_required(fromdef,todef) then
  608. begin
  609. if (fromarrtype in ['A','R','T']) or
  610. (fromarrtype<>toarrtype) then
  611. begin
  612. if not check_only and
  613. not assignment_side then
  614. begin
  615. resnode:=ctypenode.create(resultdef);
  616. if resultdef.typ=objectdef then
  617. resnode:=cloadvmtaddrnode.create(resnode);
  618. resnode:=casnode.create_internal(left,resnode);
  619. if resultdef.typ=classrefdef then
  620. tjvmasnode(resnode).classreftypecast:=true;
  621. left:=nil;
  622. end
  623. end
  624. { typecasting from a child to a parent type on the assignment side
  625. will (rightly) mess up the type safety verification of the JVM }
  626. else if assignment_side then
  627. CGMessage(type_e_no_managed_assign_generic_typecast);
  628. end;
  629. result:=true;
  630. exit;
  631. end;
  632. { a formaldef can be converted to anything, but not on the assignment
  633. side }
  634. if (left.resultdef.typ=formaldef) and
  635. not assignment_side then
  636. exit;
  637. { don't allow conversions between different classes of primitive types,
  638. except for a few special cases }
  639. { float to int/enum explicit type conversion: get the bits }
  640. if (convtype<>tc_int_2_real) and
  641. (left.resultdef.typ=floatdef) and
  642. (is_integer(resultdef) or
  643. (resultdef.typ=enumdef)) then
  644. begin
  645. if not check_only then
  646. resnode:=int_real_explicit_typecast(tfloatdef(left.resultdef),'FLOATTORAWINTBITS','DOUBLETORAWLONGBITS');
  647. result:=true;
  648. exit;
  649. end;
  650. { int to float explicit type conversion: also use the bits }
  651. if (is_integer(left.resultdef) or
  652. (left.resultdef.typ=enumdef)) and
  653. (resultdef.typ=floatdef) then
  654. begin
  655. if (convtype<>tc_int_2_real) then
  656. begin
  657. if not check_only then
  658. resnode:=int_real_explicit_typecast(tfloatdef(resultdef),'INTBITSTOFLOAT','LONGBITSTODOUBLE');
  659. result:=true;
  660. end
  661. else
  662. result:=false;
  663. exit;
  664. end;
  665. { nothing special required when going between ordinals and enums }
  666. if (left.resultdef.typ in [orddef,enumdef]) and
  667. (resultdef.typ in [orddef,enumdef]) then
  668. begin
  669. result:=false;
  670. exit;
  671. end;
  672. {$ifndef nounsupported}
  673. if (left.resultdef.typ in [orddef,enumdef,setdef]) and
  674. (resultdef.typ in [orddef,enumdef,setdef]) then
  675. begin
  676. result:=false;
  677. exit;
  678. end;
  679. { non-literal type conversions }
  680. if convtype in
  681. [tc_char_2_string,
  682. tc_char_2_chararray,
  683. tc_string_2_string,
  684. tc_string_2_chararray,
  685. tc_real_2_real,
  686. tc_proc_2_procvar,
  687. tc_arrayconstructor_2_set,
  688. tc_set_to_set,
  689. tc_class_2_intf,
  690. tc_array_2_dynarray] then
  691. begin
  692. result:=false;
  693. exit;
  694. end;
  695. {$endif}
  696. { Todo:
  697. * int to set and vice versa
  698. * set to float and vice versa (via int) (maybe)
  699. * regular array of primitive to primitive and vice versa (maybe)
  700. * packed record to primitive and vice versa (maybe)
  701. Definitely not:
  702. * unpacked record to anything and vice versa (no alignment rules
  703. for Java)
  704. }
  705. { anything not explicitly handled is a problem }
  706. result:=true;
  707. CGMessage2(type_e_illegal_type_conversion,left.resultdef.typename,resultdef.typename);
  708. end;
  709. function tjvmtypeconvnode.target_specific_explicit_typeconv: boolean;
  710. var
  711. dummyres: tnode;
  712. begin
  713. result:=do_target_specific_explicit_typeconv(true,dummyres);
  714. end;
  715. function tjvmtypeconvnode.target_specific_general_typeconv: boolean;
  716. begin
  717. result:=false;
  718. {$ifndef nounsupported}
  719. { generated in nmem; replace voidpointertype with java_jlobject }
  720. if nf_load_procvar in flags then
  721. begin
  722. self.totypedef:=java_jlobject;
  723. resultdef:=java_jlobject;
  724. end;
  725. if isvalidprocvartypeconv(left.resultdef,resultdef) then
  726. begin
  727. convtype:=tc_equal;
  728. result:=true;
  729. exit;
  730. end;
  731. {$endif}
  732. end;
  733. {*****************************************************************************
  734. AsNode and IsNode common helpers
  735. *****************************************************************************}
  736. function asis_target_specific_typecheck(node: tasisnode): boolean;
  737. var
  738. realtodef: tdef;
  739. begin
  740. if not(nf_internal in node.flags) then
  741. begin
  742. { handle using normal code }
  743. result:=false;
  744. exit;
  745. end;
  746. result:=true;
  747. { these are converted type conversion nodes, to insert the checkcast
  748. operations }
  749. realtodef:=node.right.resultdef;
  750. if (realtodef.typ=classrefdef) and
  751. ((node.nodetype<>asn) or
  752. not tjvmasnode(node).classreftypecast) then
  753. realtodef:=tclassrefdef(realtodef).pointeddef;
  754. realtodef:=maybe_find_real_class_definition(realtodef,false);
  755. if result then
  756. if node.nodetype=asn then
  757. node.resultdef:=realtodef
  758. else
  759. node.resultdef:=pasbool8type;
  760. end;
  761. function asis_pass_1(node: tasisnode; const methodname: string): tnode;
  762. var
  763. ps: tsym;
  764. call: tnode;
  765. jlclass: tobjectdef;
  766. begin
  767. result:=nil;
  768. firstpass(node.left);
  769. if not(node.right.nodetype in [typen,loadvmtaddrn]) then
  770. begin
  771. if (node.nodetype=isn) or
  772. not assigned(tasnode(node).call) then
  773. begin
  774. if not is_javaclassref(node.right.resultdef) then
  775. internalerror(2011041920);
  776. firstpass(node.right);
  777. jlclass:=tobjectdef(search_system_type('JLCLASS').typedef);
  778. ps:=search_struct_member(jlclass,methodname);
  779. if not assigned(ps) or
  780. (ps.typ<>procsym) then
  781. internalerror(2011041910);
  782. call:=ccallnode.create(ccallparanode.create(node.left,nil),tprocsym(ps),ps.owner,ctypeconvnode.create_explicit(node.right,jlclass),[]);
  783. node.left:=nil;
  784. node.right:=nil;
  785. firstpass(call);
  786. if codegenerror then
  787. exit;
  788. if node.nodetype=isn then
  789. result:=call
  790. else
  791. begin
  792. tasnode(node).call:=call;
  793. node.expectloc:=call.expectloc;
  794. end;
  795. end;
  796. end
  797. else
  798. begin
  799. node.expectloc:=LOC_REGISTER;
  800. result:=nil;
  801. end;
  802. end;
  803. function asis_generate_code(node: tasisnode; opcode: tasmop): boolean;
  804. var
  805. checkdef: tdef;
  806. begin
  807. if (node.nodetype=asn) and
  808. assigned(tasnode(node).call) then
  809. begin
  810. result:=false;
  811. exit;
  812. end;
  813. result:=true;
  814. secondpass(node.left);
  815. thlcgjvm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,node.left.resultdef,node.left.location);
  816. location_freetemp(current_asmdata.CurrAsmList,node.left.location);
  817. { Perform a checkcast instruction, which will raise an exception in case
  818. the actual type does not match/inherit from the expected type.
  819. Object types need the full type name (package+class name), arrays only
  820. the array definition }
  821. if node.nodetype=asn then
  822. checkdef:=node.resultdef
  823. else if node.right.resultdef.typ=classrefdef then
  824. checkdef:=tclassrefdef(node.right.resultdef).pointeddef
  825. else
  826. checkdef:=node.right.resultdef;
  827. { replace special types with their equivalent class type }
  828. if checkdef=voidpointertype then
  829. checkdef:=java_jlobject
  830. else if checkdef.typ=pointerdef then
  831. checkdef:=tpointerdef(checkdef).pointeddef;
  832. {$ifndef nounsupported}
  833. if checkdef.typ=procvardef then
  834. checkdef:=java_jlobject
  835. {$endif}
  836. else if is_wide_or_unicode_string(checkdef) then
  837. checkdef:=java_jlstring
  838. else if is_ansistring(checkdef) then
  839. checkdef:=java_ansistring
  840. else if is_shortstring(checkdef) then
  841. checkdef:=java_shortstring;
  842. if checkdef.typ in [objectdef,recorddef] then
  843. current_asmdata.CurrAsmList.concat(taicpu.op_sym(opcode,current_asmdata.RefAsmSymbol(tabstractrecorddef(checkdef).jvm_full_typename(true))))
  844. else if checkdef.typ=classrefdef then
  845. current_asmdata.CurrAsmList.concat(taicpu.op_sym(opcode,current_asmdata.RefAsmSymbol('java/lang/Class')))
  846. else
  847. current_asmdata.CurrAsmList.concat(taicpu.op_sym(opcode,current_asmdata.RefAsmSymbol(jvmencodetype(checkdef,false))));
  848. location_reset(node.location,LOC_REGISTER,OS_ADDR);
  849. node.location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,node.resultdef);
  850. thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,node.resultdef,node.location.register);
  851. end;
  852. {*****************************************************************************
  853. TJVMAsNode
  854. *****************************************************************************}
  855. function tjvmasnode.target_specific_typecheck: boolean;
  856. begin
  857. result:=asis_target_specific_typecheck(self);
  858. end;
  859. function tjvmasnode.pass_1: tnode;
  860. begin
  861. result:=asis_pass_1(self,'CAST');
  862. end;
  863. procedure tjvmasnode.pass_generate_code;
  864. begin
  865. if not asis_generate_code(self,a_checkcast) then
  866. inherited;
  867. end;
  868. function tjvmasnode.dogetcopy: tnode;
  869. begin
  870. result:=inherited dogetcopy;
  871. tjvmasnode(result).classreftypecast:=classreftypecast;
  872. end;
  873. function tjvmasnode.docompare(p: tnode): boolean;
  874. begin
  875. result:=
  876. inherited docompare(p) and
  877. (tjvmasnode(p).classreftypecast=classreftypecast);
  878. end;
  879. constructor tjvmasnode.ppuload(t: tnodetype; ppufile: tcompilerppufile);
  880. begin
  881. inherited;
  882. classreftypecast:=boolean(ppufile.getbyte);
  883. end;
  884. procedure tjvmasnode.ppuwrite(ppufile: tcompilerppufile);
  885. begin
  886. inherited ppuwrite(ppufile);
  887. ppufile.putbyte(byte(classreftypecast));
  888. end;
  889. {*****************************************************************************
  890. TJVMIsNode
  891. *****************************************************************************}
  892. function tjvmisnode.target_specific_typecheck: boolean;
  893. begin
  894. result:=asis_target_specific_typecheck(self);
  895. end;
  896. function tjvmisnode.pass_1: tnode;
  897. begin
  898. result:=asis_pass_1(self,'ISINSTANCE');
  899. end;
  900. procedure tjvmisnode.pass_generate_code;
  901. begin
  902. if not asis_generate_code(self,a_instanceof) then
  903. inherited;
  904. end;
  905. begin
  906. ctypeconvnode:=tjvmtypeconvnode;
  907. casnode:=tjvmasnode;
  908. cisnode:=tjvmisnode;
  909. end.