2
0

njvmutil.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  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. cclasses,
  22. node,nbas,
  23. fmodule,ngenutil,
  24. symtype,symconst,symsym,symdef;
  25. type
  26. tjvmnodeutils = class(tnodeutils)
  27. class function initialize_data_node(p:tnode; force: boolean):tnode; override;
  28. class function finalize_data_node(p:tnode):tnode; override;
  29. class procedure append_struct_initfinis(u: tmodule; initfini: tstructinifinipotype; var stat: tstatementnode); override;
  30. class function force_init: boolean; override;
  31. class procedure insertbssdata(sym: tstaticvarsym); override;
  32. class function create_main_procdef(const name: string; potype: tproctypeoption; ps: tprocsym): tdef; override;
  33. class function check_insert_trashing(pd: tprocdef): boolean; override;
  34. class function trashable_sym(p: tsym): boolean; override;
  35. class procedure maybe_trash_variable(var stat: tstatementnode; p: tabstractnormalvarsym; trashn: tnode); override;
  36. class procedure InsertThreadvarTablesTable; override;
  37. class procedure InsertThreadvars; override;
  38. class procedure InsertWideInitsTablesTable; override;
  39. class procedure InsertWideInits; override;
  40. class procedure InsertResourceTablesTable; override;
  41. class procedure InsertResourceInfo(ResourcesUsed : boolean); override;
  42. class procedure InsertResStrTablesTable; override;
  43. class procedure InsertResStrInits; override;
  44. class procedure InsertMemorySizes; override;
  45. protected
  46. class procedure insert_init_final_table(entries:tfplist); override;
  47. strict protected
  48. class procedure add_main_procdef_paras(pd: tdef); override;
  49. end;
  50. implementation
  51. uses
  52. verbose,cutils,globtype,globals,constexp,compinnr,
  53. aasmdata,aasmtai,cpubase,aasmbase,aasmcpu,
  54. symbase,symcpu,symtable,defutil,jvmdef,
  55. ncnv,ncon,ninl,ncal,nld,nmem,
  56. ppu,
  57. pass_1;
  58. class function tjvmnodeutils.initialize_data_node(p:tnode; force: boolean):tnode;
  59. var
  60. normaldim: longint;
  61. temp: ttempcreatenode;
  62. stat: tstatementnode;
  63. def: tdef;
  64. paras: tcallparanode;
  65. proc: string;
  66. begin
  67. result:=nil;
  68. proc:='';
  69. temp:=nil;
  70. if not assigned(p.resultdef) then
  71. typecheckpass(p);
  72. if ((p.resultdef.typ=stringdef) and
  73. not is_shortstring(p.resultdef) and
  74. not is_longstring(p.resultdef)) or
  75. is_dynamic_array(p.resultdef) then
  76. begin
  77. { Always initialise with empty string/array rather than nil. Java
  78. makes a distinction between an empty string/array and a null
  79. string/array, but we don't. We therefore have to pick which one we
  80. use to represent empty strings/arrays. I've chosen empty rather than
  81. null structures, because otherwise it becomes impossible to return
  82. an empty string to Java code (it would return null).
  83. On the consumer side, we do interpret both null and empty as the same
  84. thing, so Java code can pass in null strings/arrays and we'll
  85. interpret them correctly.
  86. }
  87. result:=cinlinenode.create(in_setlength_x,false,
  88. ccallparanode.create(genintconstnode(0),
  89. ccallparanode.create(p,nil)));
  90. end
  91. else if force then
  92. begin
  93. { an explicit call to initialize() }
  94. if p.resultdef.typ=recorddef then
  95. result:=ccallnode.createinternmethod(p,'FPCINITIALIZEREC',nil)
  96. else if p.resultdef.typ=arraydef then
  97. begin
  98. stat:=nil;
  99. { in case it's an open array whose elements are regular arrays, put the
  100. dimension of the regular arrays on the stack (otherwise pass 0) }
  101. normaldim:=0;
  102. def:=tarraydef(p.resultdef).elementdef;
  103. while (def.typ=arraydef) and
  104. not is_dynamic_array(def) do
  105. begin
  106. inc(normaldim);
  107. def:=tarraydef(def).elementdef;
  108. end;
  109. if jvmimplicitpointertype(p.resultdef) then
  110. begin
  111. p:=caddrnode.create(p);
  112. include(taddrnode(p).addrnodeflags,anf_typedaddr);
  113. end;
  114. paras:=ccallparanode.create(ctypeconvnode.create_explicit(p,
  115. search_system_type('TJOBJECTARRAY').typedef),nil);
  116. paras:=ccallparanode.create(genintconstnode(normaldim),paras);
  117. if is_wide_or_unicode_string(def) then
  118. proc:='fpc_initialize_array_unicodestring'
  119. else if is_ansistring(def) then
  120. proc:='fpc_initialize_array_ansistring'
  121. else if is_dynamic_array(def) then
  122. proc:='fpc_initialize_array_dynarr'
  123. else if is_record(def) then
  124. begin
  125. result:=internalstatements(stat);
  126. temp:=ctempcreatenode.create(def,def.size,tt_persistent,true);
  127. addstatement(stat,temp);
  128. paras:=ccallparanode.create(ctemprefnode.create(temp),paras);
  129. proc:='fpc_initialize_array_record'
  130. end;
  131. if assigned(stat) then
  132. begin
  133. addstatement(stat,ccallnode.createintern(proc,paras));
  134. addstatement(stat,ctempdeletenode.create(temp));
  135. end
  136. else
  137. result:=ccallnode.createintern(proc,paras);
  138. end
  139. else
  140. result:=cassignmentnode.create(p,cnilnode.create);
  141. end
  142. else
  143. begin
  144. p.free;
  145. { records/arrays/... are automatically initialised }
  146. result:=cnothingnode.create;
  147. end;
  148. end;
  149. class function tjvmnodeutils.finalize_data_node(p:tnode):tnode;
  150. begin
  151. // do nothing
  152. p.free;
  153. result:=cnothingnode.create;
  154. end;
  155. class procedure tjvmnodeutils.append_struct_initfinis(u: tmodule; initfini: tstructinifinipotype; var stat: tstatementnode);
  156. begin
  157. { class constructors are implicitly called by the JVM runtime and cannot be called explicitly }
  158. end;
  159. class function tjvmnodeutils.force_init: boolean;
  160. begin
  161. { we need an initialisation in case the al_globals list is not empty
  162. (that's where the initialisation for global records etc is added) }
  163. { problem: some bss symbols are only registered while processing the main
  164. program (e.g. constant sets) -> cannot predict whether or not we'll
  165. need it in advance }
  166. result:=true;
  167. end;
  168. class procedure tjvmnodeutils.insertbssdata(sym: tstaticvarsym);
  169. var
  170. enuminitsym,
  171. vs: tstaticvarsym;
  172. block: tblocknode;
  173. stat: tstatementnode;
  174. temp: ttempcreatenode;
  175. initnode: tnode;
  176. eledef: tdef;
  177. ndim: longint;
  178. initnodefinished: boolean;
  179. begin
  180. { handled while generating the unit/program init code, or class
  181. constructor; add something to al_globals to indicate that we need to
  182. insert an init section though }
  183. if current_asmdata.asmlists[al_globals].empty and
  184. jvmimplicitpointertype(sym.vardef) then
  185. current_asmdata.asmlists[al_globals].concat(cai_align.Create(1));
  186. { in case of a threadvar, allocate a separate sym that's a subtype of the
  187. java.lang.ThreadLocal class which will wrap the actual variable value }
  188. if vo_is_thread_var in sym.varoptions then
  189. begin
  190. vs:=cstaticvarsym.create(sym.realname+'$threadvar',sym.varspez,
  191. jvmgetthreadvardef(sym.vardef),
  192. sym.varoptions - [vo_is_thread_var]);
  193. sym.owner.insert(vs);
  194. { make sure that the new sym does not get allocated (we will allocate
  195. it when encountering the original sym, because only then we know
  196. that it's a threadvar) }
  197. include(vs.symoptions,sp_static);
  198. { switch around the mangled names of sym and vs, since the wrapper
  199. should map to the declared name }
  200. sym.set_mangledbasename(vs.realname);
  201. vs.set_mangledbasename(sym.realname);
  202. { add initialization code for the wrapper }
  203. block:=internalstatements(stat);
  204. if assigned(current_module.tcinitcode) then
  205. addstatement(stat,tnode(current_module.tcinitcode));
  206. current_module.tcinitcode:=block;
  207. { create initialization value if necessary }
  208. initnode:=nil;
  209. initnodefinished:=false;
  210. temp:=nil;
  211. { in case of enum type, initialize with enum(0) if it exists }
  212. if sym.vardef.typ=enumdef then
  213. begin
  214. enuminitsym:=tstaticvarsym(tcpuenumdef(tenumdef(sym.vardef).getbasedef).classdef.symtable.Find('__FPC_ZERO_INITIALIZER'));
  215. if assigned(enuminitsym) then
  216. initnode:=cloadnode.create(enuminitsym,enuminitsym.owner);
  217. end
  218. { normal array -> include dimensions and element type so we can
  219. create a deep copy }
  220. else if (sym.vardef.typ=arraydef) and
  221. not is_dynamic_array(sym.vardef) then
  222. begin
  223. temp:=ctempcreatenode.create(sym.vardef,sym.vardef.size,tt_persistent,true);
  224. addstatement(stat,temp);
  225. initnode:=ccallparanode.create(
  226. ctypeconvnode.create_explicit(
  227. caddrnode.create_internal(ctemprefnode.create(temp)),
  228. java_jlobject),
  229. nil);
  230. jvmgetarraydimdef(sym.vardef,eledef,ndim);
  231. initnode:=ccallparanode.create(genintconstnode(ndim),initnode);
  232. initnode:=ccallparanode.create(
  233. cordconstnode.create(ord(jvmarrtype_setlength(eledef)),
  234. cwidechartype,false),
  235. initnode);
  236. initnodefinished:=true;
  237. end
  238. { implicitpointertype -> allocate (get temp and assign address) }
  239. else if jvmimplicitpointertype(sym.vardef) then
  240. begin
  241. temp:=ctempcreatenode.create(sym.vardef,sym.vardef.size,tt_persistent,true);
  242. addstatement(stat,temp);
  243. initnode:=caddrnode.create_internal(ctemprefnode.create(temp));
  244. end
  245. { unicodestring/ansistring -> empty string }
  246. else if is_wide_or_unicode_string(sym.vardef) or
  247. is_ansistring(sym.vardef) then
  248. begin
  249. temp:=ctempcreatenode.create(sym.vardef,sym.vardef.size,tt_persistent,true);
  250. addstatement(stat,temp);
  251. addstatement(stat,cassignmentnode.create(
  252. ctemprefnode.create(temp),
  253. cstringconstnode.createstr('')));
  254. initnode:=ctemprefnode.create(temp);
  255. end
  256. { dynamic array -> empty array }
  257. else if is_dynamic_array(sym.vardef) then
  258. begin
  259. temp:=ctempcreatenode.create(sym.vardef,sym.vardef.size,tt_persistent,true);
  260. addstatement(stat,temp);
  261. addstatement(stat,cinlinenode.create(in_setlength_x,false,
  262. ccallparanode.create(genintconstnode(0),
  263. ccallparanode.create(ctemprefnode.create(temp),nil))
  264. )
  265. );
  266. initnode:=ctemprefnode.create(temp);
  267. end;
  268. if assigned(initnode) and
  269. not initnodefinished then
  270. initnode:=ccallparanode.create(ctypeconvnode.create_explicit(initnode,java_jlobject),nil);
  271. addstatement(stat,cassignmentnode.create(
  272. cloadnode.create(vs,vs.owner),
  273. ccallnode.createinternmethod(
  274. cloadvmtaddrnode.create(ctypenode.create(vs.vardef)),
  275. 'CREATE',initnode)));
  276. { deallocate the temp if we allocated one }
  277. if assigned(temp) then
  278. addstatement(stat,ctempdeletenode.create(temp));
  279. end;
  280. end;
  281. class function tjvmnodeutils.create_main_procdef(const name: string; potype: tproctypeoption; ps: tprocsym): tdef;
  282. begin
  283. if (potype=potype_proginit) then
  284. begin
  285. result:=inherited create_main_procdef('main', potype, ps);
  286. include(tprocdef(result).procoptions,po_global);
  287. tprocdef(result).visibility:=vis_public;
  288. end
  289. else
  290. result:=inherited create_main_procdef(name, potype, ps);
  291. end;
  292. class function tjvmnodeutils.check_insert_trashing(pd: tprocdef): boolean;
  293. begin
  294. { initialise locals with 0 }
  295. if ts_init_locals in current_settings.targetswitches then
  296. localvartrashing:=high(trashintvalues);
  297. result:=inherited;
  298. end;
  299. class function tjvmnodeutils.trashable_sym(p: tsym): boolean;
  300. begin
  301. result:=
  302. inherited and
  303. not jvmimplicitpointertype(tabstractnormalvarsym(p).vardef);
  304. end;
  305. class procedure tjvmnodeutils.maybe_trash_variable(var stat: tstatementnode; p: tabstractnormalvarsym; trashn: tnode);
  306. var
  307. enumdef: tenumdef;
  308. trashintval: int64;
  309. trashenumval: longint;
  310. trashable: boolean;
  311. begin
  312. trashable:=trashable_sym(p);
  313. trashintval:=trashintvalues[localvartrashing];
  314. { widechar is a separate type in the JVM, can't cast left hand to integer
  315. like in common code }
  316. if trashable and
  317. is_widechar(tabstractvarsym(p).vardef) then
  318. trash_small(stat,trashn,
  319. cordconstnode.create(word(trashintval),tabstractvarsym(p).vardef,false))
  320. { enums are class instances in the JVM -> create a valid instance }
  321. else if trashable and
  322. is_enum(tabstractvarsym(p).vardef) then
  323. begin
  324. enumdef:=tenumdef(tabstractvarsym(p).vardef);
  325. trashenumval:=longint(trashintval);
  326. if not assigned(enumdef.int2enumsym(trashenumval)) then
  327. trashintval:=longint(enumdef.min);
  328. trash_small(stat,trashn,
  329. cordconstnode.create(trashintval,enumdef,false))
  330. end
  331. { can't init pointers with arbitrary values; procvardef and objectdef are
  332. always pointer-sized here because tjvmnodeutils.trashablesym returns
  333. false for jvm implicit pointer types }
  334. else if trashable and
  335. (tabstractvarsym(p).vardef.typ in [pointerdef,classrefdef,objectdef,procvardef]) then
  336. trash_small(stat,trashn,cnilnode.create)
  337. else if trashable and
  338. is_real(tabstractvarsym(p).vardef) then
  339. trash_small(stat,trashn,crealconstnode.create(trashintval,tabstractvarsym(p).vardef))
  340. { don't use inherited routines because it typecasts left to the target
  341. type, and that doesn't always work in the JVM }
  342. else if trashable and
  343. (is_integer(tabstractvarsym(p).vardef) or
  344. is_cbool(tabstractvarsym(p).vardef) or
  345. is_anychar(tabstractvarsym(p).vardef) or
  346. is_currency(tabstractvarsym(p).vardef)) then
  347. trash_small(stat,trashn,cordconstnode.create(trashintval,tabstractvarsym(p).vardef,false))
  348. else if trashable and
  349. is_pasbool(tabstractvarsym(p).vardef) then
  350. trash_small(stat,trashn,cordconstnode.create(trashintval and 1,tabstractvarsym(p).vardef,false))
  351. else
  352. inherited;
  353. end;
  354. class procedure tjvmnodeutils.insert_init_final_table(entries:tfplist);
  355. var
  356. hp : tused_unit;
  357. unitinits : TAsmList;
  358. unitclassname: string;
  359. mainpsym: tsym;
  360. mainpd: tprocdef;
  361. begin
  362. { JVM does not use the entries list }
  363. unitinits:=TAsmList.Create;
  364. hp:=tused_unit(usedunits.first);
  365. while assigned(hp) do
  366. begin
  367. { class constructors are automatically handled by the JVM }
  368. { call the unit init code and make it external }
  369. if (hp.u.moduleflags*[mf_init,mf_finalize])<>[] then
  370. begin
  371. { trigger init code by referencing the class representing the
  372. unit; if necessary, it will register the fini code to run on
  373. exit}
  374. unitclassname:='';
  375. if assigned(hp.u.namespace) then
  376. begin
  377. unitclassname:=hp.u.namespace^+'/';
  378. replace(unitclassname,'.','/');
  379. end;
  380. unitclassname:=unitclassname+hp.u.realmodulename^;
  381. unitinits.concat(taicpu.op_sym(a_new,current_asmdata.RefAsmSymbol(unitclassname,AT_METADATA)));
  382. unitinits.concat(taicpu.op_none(a_pop));
  383. end;
  384. hp:=tused_unit(hp.next);
  385. end;
  386. { insert in main program routine }
  387. mainpsym:=tsym(current_module.localsymtable.find(mainaliasname));
  388. if not assigned(mainpsym) or
  389. (mainpsym.typ<>procsym) then
  390. internalerror(2011041901);
  391. mainpd:=tprocsym(mainpsym).find_procdef_bytype(potype_proginit);
  392. if not assigned(mainpd) then
  393. internalerror(2011041902);
  394. tcpuprocdef(mainpd).exprasmlist.insertList(unitinits);
  395. unitinits.free;
  396. end;
  397. class procedure tjvmnodeutils.InsertThreadvarTablesTable;
  398. begin
  399. { not yet supported }
  400. end;
  401. class procedure tjvmnodeutils.InsertThreadvars;
  402. begin
  403. { not yet supported }
  404. end;
  405. class procedure tjvmnodeutils.InsertWideInitsTablesTable;
  406. begin
  407. { not required }
  408. end;
  409. class procedure tjvmnodeutils.InsertWideInits;
  410. begin
  411. { not required }
  412. end;
  413. class procedure tjvmnodeutils.InsertResourceTablesTable;
  414. begin
  415. { not supported }
  416. end;
  417. class procedure tjvmnodeutils.InsertResourceInfo(ResourcesUsed: boolean);
  418. begin
  419. { not supported }
  420. end;
  421. class procedure tjvmnodeutils.InsertResStrTablesTable;
  422. begin
  423. { not supported }
  424. end;
  425. class procedure tjvmnodeutils.InsertResStrInits;
  426. begin
  427. { not supported }
  428. end;
  429. class procedure tjvmnodeutils.InsertMemorySizes;
  430. begin
  431. { not required }
  432. end;
  433. class procedure tjvmnodeutils.add_main_procdef_paras(pd: tdef);
  434. var
  435. pvs: tparavarsym;
  436. begin
  437. if (tprocdef(pd).proctypeoption=potype_proginit) then
  438. begin
  439. { add the args parameter }
  440. pvs:=cparavarsym.create('$args',1,vs_const,search_system_type('TJSTRINGARRAY').typedef,[]);
  441. tprocdef(pd).parast.insert(pvs);
  442. tprocdef(pd).calcparas;
  443. end;
  444. end;
  445. begin
  446. cnodeutils:=tjvmnodeutils;
  447. end.