njvmmem.pas 18 KB

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