njvmmem.pas 17 KB

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