njvmmem.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. {
  2. Copyright (c) 2011 by Jonas Maebe
  3. Generate JVM byetcode for in memory related 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. }
  17. unit njvmmem;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. cgbase,cpubase,
  23. node,nmem,ncgmem,ncgnstmm;
  24. type
  25. tjvmaddrnode = class(tcgaddrnode)
  26. protected
  27. function isrefparaload: boolean;
  28. function isarrayele0load: boolean;
  29. function isdererence: boolean;
  30. public
  31. function pass_typecheck: tnode; override;
  32. procedure pass_generate_code; override;
  33. end;
  34. tjvmderefnode = class(tcgderefnode)
  35. function pass_typecheck: tnode; override;
  36. procedure pass_generate_code; override;
  37. end;
  38. tjvmsubscriptnode = class(tcgsubscriptnode)
  39. protected
  40. function handle_platform_subscript: boolean; override;
  41. end;
  42. tjvmloadvmtaddrnode = class(tcgloadvmtaddrnode)
  43. procedure pass_generate_code; override;
  44. end;
  45. tjvmvecnode = class(tcgvecnode)
  46. function pass_1: tnode; override;
  47. procedure pass_generate_code;override;
  48. end;
  49. implementation
  50. uses
  51. systems,globals,procinfo,
  52. cutils,verbose,constexp,
  53. aasmbase,
  54. symconst,symtype,symtable,symsym,symdef,defutil,jvmdef,
  55. htypechk,paramgr,
  56. nadd,ncal,ncnv,ncon,nld,nutils,
  57. pass_1,njvmcon,
  58. aasmdata,aasmcpu,pass_2,
  59. cgutils,hlcgobj,hlcgcpu;
  60. {*****************************************************************************
  61. TJVMDEREFNODE
  62. *****************************************************************************}
  63. function tjvmderefnode.pass_typecheck: tnode;
  64. begin
  65. result:=inherited pass_typecheck;
  66. if assigned(result) then
  67. exit;
  68. { don't allow dereferencing untyped pointers, because how this has to
  69. be done depends on whether it's a pointer to an implicit pointer type
  70. or not }
  71. if is_voidpointer(left.resultdef) then
  72. CGMessage(parser_e_illegal_expression);
  73. end;
  74. procedure tjvmderefnode.pass_generate_code;
  75. var
  76. implicitptr: boolean;
  77. begin
  78. secondpass(left);
  79. implicitptr:=jvmimplicitpointertype(resultdef);
  80. if implicitptr then
  81. begin
  82. { this is basically a typecast: the left node is a regular
  83. 'pointer', and we typecast it to an implicit pointer }
  84. location_copy(location,left.location);
  85. { these implicit pointer types (records, sets, shortstrings, ...)
  86. cannot be located in registers on native targets (since
  87. they're not pointers there) -> force into memory to avoid
  88. confusing the compiler; this can happen when typecasting a
  89. Java class type into a pshortstring and then dereferencing etc
  90. }
  91. if location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  92. hlcg.location_force_mem(current_asmdata.CurrAsmList,location,left.resultdef);
  93. end
  94. else
  95. begin
  96. { these are always arrays (used internally for pointers to var
  97. parameters stored in nestedfpstructs, and by programmers for any
  98. kind of pointers) }
  99. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
  100. location_reset_ref(location,LOC_REFERENCE,def_cgsize(resultdef),4);
  101. reference_reset_base(location.reference,left.location.register,0,4);
  102. location.reference.arrayreftype:=art_indexconst;
  103. if (left.nodetype<>addrn) and
  104. not(resultdef.typ in [orddef,floatdef]) and
  105. not is_voidpointer(resultdef) and
  106. ((resultdef.typ<>objectdef) or
  107. (find_real_class_definition(tobjectdef(resultdef),false)<>java_jlobject)) then
  108. location.reference.checkcast:=true;
  109. end
  110. end;
  111. {*****************************************************************************
  112. TJVMSUBSCRIPTNODE
  113. *****************************************************************************}
  114. function tjvmsubscriptnode.handle_platform_subscript: boolean;
  115. begin
  116. result:=false;
  117. if is_java_class_or_interface(left.resultdef) or
  118. (left.resultdef.typ=recorddef) then
  119. begin
  120. if (location.loc<>LOC_REFERENCE) or
  121. (location.reference.index<>NR_NO) or
  122. assigned(location.reference.symbol) then
  123. internalerror(2011011301);
  124. location.reference.symbol:=current_asmdata.RefAsmSymbol(vs.mangledname);
  125. result:=true;
  126. end
  127. end;
  128. {*****************************************************************************
  129. TJVMADDRNODE
  130. *****************************************************************************}
  131. function tjvmaddrnode.isrefparaload: boolean;
  132. begin
  133. result:=
  134. (left.nodetype=loadn) and
  135. (tloadnode(left).symtableentry.typ=paravarsym) and
  136. paramanager.push_copyout_param(tparavarsym(tloadnode(left).symtableentry).varspez,
  137. left.resultdef,
  138. tabstractprocdef(tloadnode(left).symtableentry.owner.defowner).proccalloption);
  139. end;
  140. function tjvmaddrnode.isarrayele0load: boolean;
  141. begin
  142. result:=
  143. (left.nodetype=vecn) and
  144. (tvecnode(left).left.resultdef.typ=arraydef) and
  145. (tvecnode(left).right.nodetype=ordconstn) and
  146. (tordconstnode(tvecnode(left).right).value=tarraydef(tvecnode(left).left.resultdef).lowrange);
  147. end;
  148. function tjvmaddrnode.isdererence: boolean;
  149. var
  150. target: tnode;
  151. begin
  152. target:=actualtargetnode(@left)^;
  153. result:=
  154. (left.nodetype=derefn);
  155. end;
  156. function tjvmaddrnode.pass_typecheck: tnode;
  157. var
  158. fsym: tsym;
  159. begin
  160. result:=nil;
  161. typecheckpass(left);
  162. if codegenerror then
  163. exit;
  164. make_not_regable(left,[ra_addr_regable,ra_addr_taken]);
  165. { in TP/Delphi, @procvar = contents of procvar and @@procvar =
  166. address of procvar. In case of a procedure of object, this works
  167. by letting the first addrnode typecast the procvar into a tmethod
  168. record followed by subscripting its "code" field (= first field),
  169. and if there's a second addrnode then it takes the address of
  170. this code field (which is hence also the address of the procvar).
  171. In Java, such ugly hacks don't work -> replace first addrnode
  172. with getting procvar.method.code, and second addrnode with
  173. the class for procedure of object}
  174. if not(nf_internal in flags) and
  175. ((m_tp_procvar in current_settings.modeswitches) or
  176. (m_mac_procvar in current_settings.modeswitches)) and
  177. (((left.nodetype=addrn) and
  178. (taddrnode(left).left.resultdef.typ=procvardef)) or
  179. (left.resultdef.typ=procvardef)) then
  180. begin
  181. if (left.nodetype=addrn) and
  182. (taddrnode(left).left.resultdef.typ=procvardef) then
  183. begin
  184. { double address -> pointer that is the address of the
  185. procvardef (don't allow for non-object procvars, as they
  186. aren't implicitpointerdefs) }
  187. if not jvmimplicitpointertype(taddrnode(left).left.resultdef) then
  188. CGMessage(parser_e_illegal_expression)
  189. else
  190. begin
  191. { an internal address node will observe "normal" address
  192. operator semantics (= take the actual address!) }
  193. result:=caddrnode.create_internal(taddrnode(left).left);
  194. result:=ctypeconvnode.create_explicit(result,tprocvardef(taddrnode(left).left.resultdef).classdef);
  195. taddrnode(left).left:=nil;
  196. end;
  197. end
  198. else if left.resultdef.typ=procvardef then
  199. begin
  200. if not tprocvardef(left.resultdef).is_addressonly then
  201. begin
  202. { the "code" field from the procvar }
  203. result:=caddrnode.create_internal(left);
  204. result:=ctypeconvnode.create_explicit(result,tprocvardef(left.resultdef).classdef);
  205. { procvarclass.method }
  206. fsym:=search_struct_member(tprocvardef(left.resultdef).classdef,'METHOD');
  207. if not assigned(fsym) or
  208. (fsym.typ<>fieldvarsym) then
  209. internalerror(2011072501);
  210. result:=csubscriptnode.create(fsym,result);
  211. { procvarclass.method.code }
  212. fsym:=search_struct_member(trecorddef(tfieldvarsym(fsym).vardef),'CODE');
  213. if not assigned(fsym) or
  214. (fsym.typ<>fieldvarsym) then
  215. internalerror(2011072502);
  216. result:=csubscriptnode.create(fsym,result);
  217. left:=nil
  218. end
  219. else
  220. { convert contents to plain pointer }
  221. begin
  222. result:=ctypeconvnode.create_explicit(left,java_jlobject);
  223. include(result.flags,nf_load_procvar);
  224. left:=nil;
  225. end;
  226. end
  227. else
  228. internalerror(2011072506);
  229. end
  230. else if (left.resultdef.typ=procdef) then
  231. begin
  232. result:=inherited;
  233. exit;
  234. end
  235. else
  236. begin
  237. if not jvmimplicitpointertype(left.resultdef) then
  238. begin
  239. { allow taking the address of a copy-out parameter (it's an
  240. array reference), of the first element of an array and of a
  241. pointer derefence }
  242. if not isrefparaload and
  243. not isarrayele0load and
  244. not isdererence then
  245. begin
  246. CGMessage(parser_e_illegal_expression);
  247. exit
  248. end;
  249. end;
  250. result:=inherited;
  251. end;
  252. end;
  253. procedure tjvmaddrnode.pass_generate_code;
  254. var
  255. implicitptr: boolean;
  256. begin
  257. secondpass(left);
  258. implicitptr:=jvmimplicitpointertype(left.resultdef);
  259. if implicitptr then
  260. { this is basically a typecast: the left node is an implicit
  261. pointer, and we typecast it to a regular 'pointer'
  262. (java.lang.Object) }
  263. location_copy(location,left.location)
  264. else
  265. begin
  266. { these are always arrays (used internally for pointers to var
  267. parameters stored in nestedfpstructs) -> get base pointer to
  268. array }
  269. if (left.location.loc<>LOC_REFERENCE) or
  270. (left.location.reference.arrayreftype<>art_indexconst) or
  271. (left.location.reference.base=NR_NO) or
  272. (left.location.reference.indexoffset<>0) or
  273. assigned(left.location.reference.symbol) then
  274. internalerror(2011060701);
  275. location_reset(location,LOC_REGISTER,OS_ADDR);
  276. location.register:=left.location.reference.base;
  277. end;
  278. end;
  279. {*****************************************************************************
  280. TJVMLOADVMTADDRNODE
  281. *****************************************************************************}
  282. procedure tjvmloadvmtaddrnode.pass_generate_code;
  283. begin
  284. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_ldc,current_asmdata.RefAsmSymbol(
  285. tabstractrecorddef(tclassrefdef(resultdef).pointeddef).jvm_full_typename(true))));
  286. thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,1);
  287. location_reset(location,LOC_REGISTER,OS_ADDR);
  288. location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resultdef);
  289. thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
  290. end;
  291. {*****************************************************************************
  292. TJVMVECNODE
  293. *****************************************************************************}
  294. function tjvmvecnode.pass_1: tnode;
  295. var
  296. psym: tsym;
  297. stringclass: tdef;
  298. begin
  299. if (left.resultdef.typ=stringdef) then
  300. begin
  301. case tstringdef(left.resultdef).stringtype of
  302. st_ansistring:
  303. stringclass:=java_ansistring;
  304. st_unicodestring,
  305. st_widestring:
  306. stringclass:=java_jlstring;
  307. st_shortstring:
  308. begin
  309. stringclass:=java_shortstring;
  310. left:=caddrnode.create_internal(left);
  311. { avoid useless typecheck when casting to shortstringclass }
  312. include(left.flags,nf_typedaddr);
  313. end
  314. else
  315. internalerror(2011052407);
  316. end;
  317. psym:=search_struct_member(tabstractrecorddef(stringclass),'CHARAT');
  318. if not assigned(psym) or
  319. (psym.typ<>procsym) then
  320. internalerror(2011031501);
  321. { Pascal strings are 1-based, Java strings 0-based }
  322. result:=ccallnode.create(ccallparanode.create(
  323. caddnode.create(subn,right,genintconstnode(1)),nil),tprocsym(psym),
  324. psym.owner,ctypeconvnode.create_explicit(left,stringclass),[]);
  325. left:=nil;
  326. right:=nil;
  327. exit;
  328. end
  329. else
  330. begin
  331. { keep indices that are enum constants that way, rather than
  332. transforming them into a load of the class instance that
  333. represents this constant (since we then would have to extract
  334. the int constant value again at run time anyway) }
  335. if right.nodetype=ordconstn then
  336. tjvmordconstnode(right).enumconstok:=true;
  337. result:=inherited;
  338. end;
  339. end;
  340. procedure tjvmvecnode.pass_generate_code;
  341. var
  342. otl,ofl: tasmlabel;
  343. psym: tsym;
  344. newsize: tcgsize;
  345. isjump: boolean;
  346. begin
  347. if left.resultdef.typ=stringdef then
  348. internalerror(2011052702);
  349. { This routine is not used for Strings, as they are a class type and
  350. you have to use charAt() there to load a character (and you cannot
  351. change characters; you have to create a new string in that case)
  352. As far as arrays are concerned: we have to create a trefererence
  353. with arrayreftype in [art_indexreg,art_indexref], and ref.base =
  354. pointer to the array (i.e., left.location.register) }
  355. secondpass(left);
  356. newsize:=def_cgsize(resultdef);
  357. if left.location.loc=LOC_CREFERENCE then
  358. location_reset_ref(location,LOC_CREFERENCE,newsize,left.location.reference.alignment)
  359. else
  360. location_reset_ref(location,LOC_REFERENCE,newsize,left.location.reference.alignment);
  361. { don't use left.resultdef, because it may be an open or regular array,
  362. and then asking for the size doesn't make any sense }
  363. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,java_jlobject,java_jlobject,true);
  364. location.reference.base:=left.location.register;
  365. isjump:=(right.expectloc=LOC_JUMP);
  366. if isjump then
  367. begin
  368. otl:=current_procinfo.CurrTrueLabel;
  369. current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
  370. ofl:=current_procinfo.CurrFalseLabel;
  371. current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
  372. end;
  373. secondpass(right);
  374. { simplify index location if necessary, since array references support
  375. an index in memory, but not an another array index }
  376. if isjump or
  377. ((right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and
  378. (right.location.reference.arrayreftype<>art_none)) then
  379. hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,true);
  380. if isjump then
  381. begin
  382. current_procinfo.CurrTrueLabel:=otl;
  383. current_procinfo.CurrFalseLabel:=ofl;
  384. end
  385. else if (right.location.loc = LOC_JUMP) then
  386. internalerror(2011090501);
  387. { replace enum class instance with the corresponding integer value }
  388. if (right.resultdef.typ=enumdef) then
  389. begin
  390. if (right.location.loc<>LOC_CONSTANT) then
  391. begin
  392. psym:=search_struct_member(tenumdef(right.resultdef).getbasedef.classdef,'FPCORDINAL');
  393. if not assigned(psym) or
  394. (psym.typ<>procsym) or
  395. (tprocsym(psym).ProcdefList.count<>1) then
  396. internalerror(2011062607);
  397. thlcgjvm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,right.resultdef,right.location);
  398. hlcg.a_call_name(current_asmdata.CurrAsmList,tprocdef(tprocsym(psym).procdeflist[0]),tprocdef(tprocsym(psym).procdeflist[0]).mangledname,nil,false);
  399. { call replaces self parameter with longint result -> no stack
  400. height change }
  401. location_reset(right.location,LOC_REGISTER,OS_S32);
  402. right.location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,s32inttype);
  403. thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,s32inttype,right.location.register);
  404. end;
  405. { always force to integer location, because enums are handled as
  406. object instances (since that's what they are in Java) }
  407. right.resultdef:=s32inttype;
  408. right.location.size:=OS_S32;
  409. end;
  410. { adjust index if necessary }
  411. if not is_special_array(left.resultdef) and
  412. (tarraydef(left.resultdef).lowrange<>0) and
  413. (right.location.loc<>LOC_CONSTANT) then
  414. begin
  415. thlcgjvm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,right.resultdef,right.location);
  416. thlcgjvm(hlcg).a_op_const_stack(current_asmdata.CurrAsmList,OP_SUB,right.resultdef,tarraydef(left.resultdef).lowrange);
  417. if right.location.loc<>LOC_REGISTER then
  418. begin
  419. location_reset(right.location,LOC_REGISTER,def_cgsize(right.resultdef));
  420. right.location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,right.resultdef);
  421. end;
  422. thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,right.resultdef,right.location.register);
  423. end;
  424. { create array reference }
  425. case right.location.loc of
  426. LOC_REGISTER,LOC_CREGISTER:
  427. begin
  428. location.reference.arrayreftype:=art_indexreg;
  429. location.reference.index:=right.location.register;
  430. end;
  431. LOC_REFERENCE,LOC_CREFERENCE:
  432. begin
  433. location.reference.arrayreftype:=art_indexref;
  434. location.reference.indexbase:=right.location.reference.base;
  435. location.reference.indexsymbol:=right.location.reference.symbol;
  436. location.reference.indexoffset:=right.location.reference.offset;
  437. end;
  438. LOC_CONSTANT:
  439. begin
  440. location.reference.arrayreftype:=art_indexconst;
  441. location.reference.indexoffset:=right.location.value-tarraydef(left.resultdef).lowrange;
  442. end
  443. else
  444. internalerror(2011012002);
  445. end;
  446. end;
  447. begin
  448. cderefnode:=tjvmderefnode;
  449. csubscriptnode:=tjvmsubscriptnode;
  450. caddrnode:=tjvmaddrnode;
  451. cvecnode:=tjvmvecnode;
  452. cloadvmtaddrnode:=tjvmloadvmtaddrnode;
  453. end.