njvmcnv.pas 38 KB

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