njvmutil.pas 18 KB

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