njvmutil.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. {
  2. Copyright (c) 20011 by Jonas Maebe
  3. JVM version of some node tree helper routines
  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 njvmutil;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node,
  22. ngenutil,
  23. symtype,symconst,symsym;
  24. type
  25. tjvmnodeutils = class(tnodeutils)
  26. class function initialize_data_node(p:tnode; force: boolean):tnode; override;
  27. class function finalize_data_node(p:tnode):tnode; override;
  28. class function force_init: boolean; override;
  29. class procedure insertbssdata(sym: tstaticvarsym); override;
  30. class function create_main_procdef(const name: string; potype: tproctypeoption; ps: tprocsym): tdef; override;
  31. class procedure InsertInitFinalTable; override;
  32. class procedure InsertThreadvarTablesTable; override;
  33. class procedure InsertThreadvars; override;
  34. class procedure InsertWideInitsTablesTable; override;
  35. class procedure InsertWideInits; override;
  36. class procedure InsertResourceTablesTable; override;
  37. class procedure InsertResourceInfo(ResourcesUsed : boolean); override;
  38. class procedure InsertMemorySizes; override;
  39. strict protected
  40. class procedure add_main_procdef_paras(pd: tdef); override;
  41. end;
  42. implementation
  43. uses
  44. verbose,cutils,globtype,globals,constexp,fmodule,
  45. aasmdata,aasmtai,cpubase,aasmcpu,
  46. symdef,symbase,symtable,defutil,jvmdef,
  47. nbas,ncnv,ncon,ninl,ncal,nld,nmem,
  48. ppu,
  49. pass_1;
  50. class function tjvmnodeutils.initialize_data_node(p:tnode; force: boolean):tnode;
  51. var
  52. normaldim: longint;
  53. temp: ttempcreatenode;
  54. stat: tstatementnode;
  55. def: tdef;
  56. paras: tcallparanode;
  57. proc: string;
  58. begin
  59. if not assigned(p.resultdef) then
  60. typecheckpass(p);
  61. if ((p.resultdef.typ=stringdef) and
  62. not is_shortstring(p.resultdef) and
  63. not is_longstring(p.resultdef)) or
  64. is_dynamic_array(p.resultdef) then
  65. begin
  66. { Always initialise with empty string/array rather than nil. Java
  67. makes a distinction between an empty string/array and a null
  68. string/array, but we don't. We therefore have to pick which one we
  69. use to represent empty strings/arrays. I've chosen empty rather than
  70. null structures, because otherwise it becomes impossible to return
  71. an empty string to Java code (it would return null).
  72. On the consumer side, we do interpret both null and empty as the same
  73. thing, so Java code can pass in null strings/arrays and we'll
  74. interpret them correctly.
  75. }
  76. result:=cinlinenode.create(in_setlength_x,false,
  77. ccallparanode.create(genintconstnode(0),
  78. ccallparanode.create(p,nil)));
  79. end
  80. else if force then
  81. begin
  82. { an explicit call to initialize() }
  83. if p.resultdef.typ=recorddef then
  84. result:=ccallnode.createinternmethod(p,'FPCINITIALIZEREC',nil)
  85. else if p.resultdef.typ=arraydef then
  86. begin
  87. stat:=nil;
  88. { in case it's an open array whose elements are regular arrays, put the
  89. dimension of the regular arrays on the stack (otherwise pass 0) }
  90. normaldim:=0;
  91. def:=tarraydef(p.resultdef).elementdef;
  92. while (def.typ=arraydef) and
  93. not is_dynamic_array(def) do
  94. begin
  95. inc(normaldim);
  96. def:=tarraydef(def).elementdef;
  97. end;
  98. if jvmimplicitpointertype(p.resultdef) then
  99. begin
  100. p:=caddrnode.create(p);
  101. include(p.flags,nf_typedaddr);
  102. end;
  103. paras:=ccallparanode.create(ctypeconvnode.create_explicit(p,
  104. search_system_type('TJOBJECTARRAY').typedef),nil);
  105. paras:=ccallparanode.create(genintconstnode(normaldim),paras);
  106. if is_wide_or_unicode_string(def) then
  107. proc:='fpc_initialize_array_unicodestring'
  108. else if is_ansistring(def) then
  109. proc:='fpc_initialize_array_ansistring'
  110. else if is_dynamic_array(def) then
  111. proc:='fpc_initialize_array_dynarr'
  112. else if is_record(def) then
  113. begin
  114. result:=internalstatements(stat);
  115. temp:=ctempcreatenode.create(def,def.size,tt_persistent,true);
  116. addstatement(stat,temp);
  117. paras:=ccallparanode.create(ctemprefnode.create(temp),paras);
  118. proc:='fpc_initialize_array_record'
  119. end;
  120. if assigned(stat) then
  121. begin
  122. addstatement(stat,ccallnode.createintern(proc,paras));
  123. addstatement(stat,ctempdeletenode.create(temp));
  124. end
  125. else
  126. result:=ccallnode.createintern(proc,paras);
  127. end
  128. else
  129. result:=cassignmentnode.create(p,cnilnode.create);
  130. end
  131. else
  132. begin
  133. p.free;
  134. { records/arrays/... are automatically initialised }
  135. result:=cnothingnode.create;
  136. end;
  137. end;
  138. class function tjvmnodeutils.finalize_data_node(p:tnode):tnode;
  139. begin
  140. // do nothing
  141. p.free;
  142. result:=cnothingnode.create;
  143. end;
  144. class function tjvmnodeutils.force_init: boolean;
  145. begin
  146. { we need an initialisation in case the al_globals list is not empty
  147. (that's where the initialisation for global records etc is added) }
  148. { problem: some bss symbols are only registered while processing the main
  149. program (e.g. constant sets) -> cannot predict whether or not we'll
  150. need it in advance }
  151. result:=true;
  152. end;
  153. class procedure tjvmnodeutils.insertbssdata(sym: tstaticvarsym);
  154. var
  155. enuminitsym,
  156. vs: tstaticvarsym;
  157. block: tblocknode;
  158. stat: tstatementnode;
  159. temp: ttempcreatenode;
  160. initnode: tnode;
  161. eledef: tdef;
  162. ndim: longint;
  163. initnodefinished: boolean;
  164. begin
  165. { handled while generating the unit/program init code, or class
  166. constructor; add something to al_globals to indicate that we need to
  167. insert an init section though }
  168. if current_asmdata.asmlists[al_globals].empty and
  169. jvmimplicitpointertype(sym.vardef) then
  170. current_asmdata.asmlists[al_globals].concat(cai_align.Create(1));
  171. { in case of a threadvar, allocate a separate sym that's a subtype of the
  172. java.lang.ThreadLocal class which will wrap the actual variable value }
  173. if vo_is_thread_var in sym.varoptions then
  174. begin
  175. vs:=tstaticvarsym.create(sym.realname+'$threadvar',sym.varspez,
  176. jvmgetthreadvardef(sym.vardef),
  177. sym.varoptions - [vo_is_thread_var]);
  178. sym.owner.insert(vs);
  179. { make sure that the new sym does not get allocated (we will allocate
  180. it when encountering the original sym, because only then we know
  181. that it's a threadvar) }
  182. include(vs.symoptions,sp_static);
  183. { switch around the mangled names of sym and vs, since the wrapper
  184. should map to the declared name }
  185. sym.set_mangledbasename(vs.realname);
  186. vs.set_mangledbasename(sym.realname);
  187. { add initialization code for the wrapper }
  188. block:=internalstatements(stat);
  189. if assigned(current_module.tcinitcode) then
  190. addstatement(stat,tnode(current_module.tcinitcode));
  191. current_module.tcinitcode:=block;
  192. { create initialization value if necessary }
  193. initnode:=nil;
  194. initnodefinished:=false;
  195. temp:=nil;
  196. { in case of enum type, initialize with enum(0) if it exists }
  197. if sym.vardef.typ=enumdef then
  198. begin
  199. enuminitsym:=tstaticvarsym(tenumdef(sym.vardef).getbasedef.classdef.symtable.Find('__FPC_ZERO_INITIALIZER'));
  200. if assigned(enuminitsym) then
  201. initnode:=cloadnode.create(enuminitsym,enuminitsym.owner);
  202. end
  203. { normal array -> include dimensions and element type so we can
  204. create a deep copy }
  205. else if (sym.vardef.typ=arraydef) and
  206. not is_dynamic_array(sym.vardef) then
  207. begin
  208. temp:=ctempcreatenode.create(sym.vardef,sym.vardef.size,tt_persistent,true);
  209. addstatement(stat,temp);
  210. initnode:=ccallparanode.create(
  211. ctypeconvnode.create_explicit(
  212. caddrnode.create_internal(ctemprefnode.create(temp)),
  213. java_jlobject),
  214. nil);
  215. jvmgetarraydimdef(sym.vardef,eledef,ndim);
  216. initnode:=ccallparanode.create(genintconstnode(ndim),initnode);
  217. initnode:=ccallparanode.create(
  218. cordconstnode.create(ord(jvmarrtype_setlength(eledef)),
  219. cwidechartype,false),
  220. initnode);
  221. initnodefinished:=true;
  222. end
  223. { implicitpointertype -> allocate (get temp and assign address) }
  224. else if jvmimplicitpointertype(sym.vardef) then
  225. begin
  226. temp:=ctempcreatenode.create(sym.vardef,sym.vardef.size,tt_persistent,true);
  227. addstatement(stat,temp);
  228. initnode:=caddrnode.create_internal(ctemprefnode.create(temp));
  229. end
  230. { unicodestring/ansistring -> empty string }
  231. else if is_wide_or_unicode_string(sym.vardef) or
  232. is_ansistring(sym.vardef) then
  233. begin
  234. temp:=ctempcreatenode.create(sym.vardef,sym.vardef.size,tt_persistent,true);
  235. addstatement(stat,temp);
  236. addstatement(stat,cassignmentnode.create(
  237. ctemprefnode.create(temp),
  238. cstringconstnode.createstr('')));
  239. initnode:=ctemprefnode.create(temp);
  240. end
  241. { dynamic array -> empty array }
  242. else if is_dynamic_array(sym.vardef) then
  243. begin
  244. temp:=ctempcreatenode.create(sym.vardef,sym.vardef.size,tt_persistent,true);
  245. addstatement(stat,temp);
  246. addstatement(stat,cinlinenode.create(in_setlength_x,false,
  247. ccallparanode.create(genintconstnode(0),
  248. ccallparanode.create(ctemprefnode.create(temp),nil))
  249. )
  250. );
  251. initnode:=ctemprefnode.create(temp);
  252. end;
  253. if assigned(initnode) and
  254. not initnodefinished then
  255. initnode:=ccallparanode.create(ctypeconvnode.create_explicit(initnode,java_jlobject),nil);
  256. addstatement(stat,cassignmentnode.create(
  257. cloadnode.create(vs,vs.owner),
  258. ccallnode.createinternmethod(
  259. cloadvmtaddrnode.create(ctypenode.create(vs.vardef)),
  260. 'CREATE',initnode)));
  261. { deallocate the temp if we allocated one }
  262. if assigned(temp) then
  263. addstatement(stat,ctempdeletenode.create(temp));
  264. end;
  265. end;
  266. class function tjvmnodeutils.create_main_procdef(const name: string; potype: tproctypeoption; ps: tprocsym): tdef;
  267. begin
  268. if (potype=potype_proginit) then
  269. begin
  270. result:=inherited create_main_procdef('main', potype, ps);
  271. include(tprocdef(result).procoptions,po_global);
  272. tprocdef(result).visibility:=vis_public;
  273. end
  274. else
  275. result:=inherited create_main_procdef(name, potype, ps);
  276. end;
  277. class procedure tjvmnodeutils.InsertInitFinalTable;
  278. var
  279. hp : tused_unit;
  280. unitinits : TAsmList;
  281. unitclassname: string;
  282. mainpsym: tsym;
  283. mainpd: tprocdef;
  284. begin
  285. unitinits:=TAsmList.Create;
  286. hp:=tused_unit(usedunits.first);
  287. while assigned(hp) do
  288. begin
  289. { class constructors are automatically handled by the JVM }
  290. { call the unit init code and make it external }
  291. if (hp.u.flags and (uf_init or uf_finalize))<>0 then
  292. begin
  293. { trigger init code by referencing the class representing the
  294. unit; if necessary, it will register the fini code to run on
  295. exit}
  296. unitclassname:='';
  297. if assigned(hp.u.namespace) then
  298. begin
  299. unitclassname:=hp.u.namespace^+'/';
  300. replace(unitclassname,'.','/');
  301. end;
  302. unitclassname:=unitclassname+hp.u.realmodulename^;
  303. unitinits.concat(taicpu.op_sym(a_new,current_asmdata.RefAsmSymbol(unitclassname)));
  304. unitinits.concat(taicpu.op_none(a_pop));
  305. end;
  306. hp:=tused_unit(hp.next);
  307. end;
  308. { insert in main program routine }
  309. mainpsym:=tsym(current_module.localsymtable.find(mainaliasname));
  310. if not assigned(mainpsym) or
  311. (mainpsym.typ<>procsym) then
  312. internalerror(2011041901);
  313. mainpd:=tprocsym(mainpsym).find_procdef_bytype(potype_proginit);
  314. if not assigned(mainpd) then
  315. internalerror(2011041902);
  316. mainpd.exprasmlist.insertList(unitinits);
  317. unitinits.free;
  318. end;
  319. class procedure tjvmnodeutils.InsertThreadvarTablesTable;
  320. begin
  321. { not yet supported }
  322. end;
  323. class procedure tjvmnodeutils.InsertThreadvars;
  324. begin
  325. { not yet supported }
  326. end;
  327. class procedure tjvmnodeutils.InsertWideInitsTablesTable;
  328. begin
  329. { not required }
  330. end;
  331. class procedure tjvmnodeutils.InsertWideInits;
  332. begin
  333. { not required }
  334. end;
  335. class procedure tjvmnodeutils.InsertResourceTablesTable;
  336. begin
  337. { not supported }
  338. end;
  339. class procedure tjvmnodeutils.InsertResourceInfo(ResourcesUsed: boolean);
  340. begin
  341. { not supported }
  342. end;
  343. class procedure tjvmnodeutils.InsertMemorySizes;
  344. begin
  345. { not required }
  346. end;
  347. class procedure tjvmnodeutils.add_main_procdef_paras(pd: tdef);
  348. var
  349. pvs: tparavarsym;
  350. begin
  351. if (tprocdef(pd).proctypeoption=potype_proginit) then
  352. begin
  353. { add the args parameter }
  354. pvs:=tparavarsym.create('$args',1,vs_const,search_system_type('TJSTRINGARRAY').typedef,[]);
  355. tprocdef(pd).parast.insert(pvs);
  356. tprocdef(pd).calcparas;
  357. end;
  358. end;
  359. begin
  360. cnodeutils:=tjvmnodeutils;
  361. end.