ngenutil.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. {
  2. Copyright (c) 1998-20011 by Florian Klaempfl
  3. Generic version of some node tree helper routines that can be overridden
  4. by cpu-specific versions
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit ngenutil;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. node,symsym,symdef;
  23. type
  24. tnodeutils = class
  25. class function call_fail_node:tnode; virtual;
  26. class function initialize_data_node(p:tnode):tnode; virtual;
  27. class function finalize_data_node(p:tnode):tnode; virtual;
  28. { returns true if the unit requires an initialisation section (e.g.,
  29. to force class constructors for the JVM target to initialise global
  30. records/arrays) }
  31. class function force_init: boolean; virtual;
  32. { idem for finalization }
  33. class function force_final: boolean; virtual;
  34. { called after parsing a routine with the code of the entire routine
  35. as argument; can be used to modify the node tree. By default handles
  36. insertion of code for systems that perform the typed constant
  37. initialisation via the node tree }
  38. class function wrap_proc_body(pd: tprocdef; n: tnode): tnode; virtual;
  39. class procedure insertbssdata(sym : tstaticvarsym); virtual;
  40. end;
  41. tnodeutilsclass = class of tnodeutils;
  42. const
  43. cnodeutils: tnodeutilsclass = tnodeutils;
  44. implementation
  45. uses
  46. verbose,globtype,globals,cutils,constexp,
  47. scanner,systems,procinfo,fmodule,
  48. aasmbase,aasmdata,aasmtai,
  49. symconst,symtype,symbase,symtable,defutil,
  50. nadd,nbas,ncal,ncnv,ncon,nflw,nld,nmem,nobj,nutils,
  51. pass_1;
  52. class function tnodeutils.call_fail_node:tnode;
  53. var
  54. para : tcallparanode;
  55. newstatement : tstatementnode;
  56. srsym : tsym;
  57. begin
  58. result:=internalstatements(newstatement);
  59. { call fail helper and exit normal }
  60. if is_class(current_structdef) then
  61. begin
  62. srsym:=search_struct_member(current_structdef,'FREEINSTANCE');
  63. if assigned(srsym) and
  64. (srsym.typ=procsym) then
  65. begin
  66. { if self<>0 and vmt<>0 then freeinstance }
  67. addstatement(newstatement,cifnode.create(
  68. caddnode.create(andn,
  69. caddnode.create(unequaln,
  70. load_self_pointer_node,
  71. cnilnode.create),
  72. caddnode.create(unequaln,
  73. load_vmt_pointer_node,
  74. cnilnode.create)),
  75. ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[]),
  76. nil));
  77. end
  78. else
  79. internalerror(200305108);
  80. end
  81. else
  82. if is_object(current_structdef) then
  83. begin
  84. { parameter 3 : vmt_offset }
  85. { parameter 2 : pointer to vmt }
  86. { parameter 1 : self pointer }
  87. para:=ccallparanode.create(
  88. cordconstnode.create(tobjectdef(current_structdef).vmt_offset,s32inttype,false),
  89. ccallparanode.create(
  90. ctypeconvnode.create_internal(
  91. load_vmt_pointer_node,
  92. voidpointertype),
  93. ccallparanode.create(
  94. ctypeconvnode.create_internal(
  95. load_self_pointer_node,
  96. voidpointertype),
  97. nil)));
  98. addstatement(newstatement,
  99. ccallnode.createintern('fpc_help_fail',para));
  100. end
  101. else
  102. internalerror(200305132);
  103. { self:=nil }
  104. addstatement(newstatement,cassignmentnode.create(
  105. load_self_pointer_node,
  106. cnilnode.create));
  107. { exit }
  108. addstatement(newstatement,cexitnode.create(nil));
  109. end;
  110. class function tnodeutils.initialize_data_node(p:tnode):tnode;
  111. begin
  112. if not assigned(p.resultdef) then
  113. typecheckpass(p);
  114. if is_ansistring(p.resultdef) or
  115. is_wide_or_unicode_string(p.resultdef) or
  116. is_interfacecom_or_dispinterface(p.resultdef) or
  117. is_dynamic_array(p.resultdef) then
  118. begin
  119. result:=cassignmentnode.create(
  120. ctypeconvnode.create_internal(p,voidpointertype),
  121. cnilnode.create
  122. );
  123. end
  124. else
  125. begin
  126. result:=ccallnode.createintern('fpc_initialize',
  127. ccallparanode.create(
  128. caddrnode.create_internal(
  129. crttinode.create(
  130. tstoreddef(p.resultdef),initrtti,rdt_normal)),
  131. ccallparanode.create(
  132. caddrnode.create_internal(p),
  133. nil)));
  134. end;
  135. end;
  136. class function tnodeutils.finalize_data_node(p:tnode):tnode;
  137. var
  138. newstatement : tstatementnode;
  139. begin
  140. if not assigned(p.resultdef) then
  141. typecheckpass(p);
  142. if is_ansistring(p.resultdef) then
  143. begin
  144. result:=internalstatements(newstatement);
  145. addstatement(newstatement,ccallnode.createintern('fpc_ansistr_decr_ref',
  146. ccallparanode.create(
  147. ctypeconvnode.create_internal(p,voidpointertype),
  148. nil)));
  149. addstatement(newstatement,cassignmentnode.create(
  150. ctypeconvnode.create_internal(p.getcopy,voidpointertype),
  151. cnilnode.create
  152. ));
  153. end
  154. else if is_widestring(p.resultdef) then
  155. begin
  156. result:=internalstatements(newstatement);
  157. addstatement(newstatement,ccallnode.createintern('fpc_widestr_decr_ref',
  158. ccallparanode.create(
  159. ctypeconvnode.create_internal(p,voidpointertype),
  160. nil)));
  161. addstatement(newstatement,cassignmentnode.create(
  162. ctypeconvnode.create_internal(p.getcopy,voidpointertype),
  163. cnilnode.create
  164. ));
  165. end
  166. else if is_unicodestring(p.resultdef) then
  167. begin
  168. result:=internalstatements(newstatement);
  169. addstatement(newstatement,ccallnode.createintern('fpc_unicodestr_decr_ref',
  170. ccallparanode.create(
  171. ctypeconvnode.create_internal(p,voidpointertype),
  172. nil)));
  173. addstatement(newstatement,cassignmentnode.create(
  174. ctypeconvnode.create_internal(p.getcopy,voidpointertype),
  175. cnilnode.create
  176. ));
  177. end
  178. else if is_interfacecom_or_dispinterface(p.resultdef) then
  179. begin
  180. result:=internalstatements(newstatement);
  181. addstatement(newstatement,ccallnode.createintern('fpc_intf_decr_ref',
  182. ccallparanode.create(
  183. ctypeconvnode.create_internal(p,voidpointertype),
  184. nil)));
  185. addstatement(newstatement,cassignmentnode.create(
  186. ctypeconvnode.create_internal(p.getcopy,voidpointertype),
  187. cnilnode.create
  188. ));
  189. end
  190. else
  191. result:=ccallnode.createintern('fpc_finalize',
  192. ccallparanode.create(
  193. caddrnode.create_internal(
  194. crttinode.create(
  195. tstoreddef(p.resultdef),initrtti,rdt_normal)),
  196. ccallparanode.create(
  197. caddrnode.create_internal(p),
  198. nil)));
  199. end;
  200. class function tnodeutils.force_init: boolean;
  201. begin
  202. result:=
  203. (target_info.system in systems_typed_constants_node_init) and
  204. assigned(current_module.tcinitcode);
  205. end;
  206. class function tnodeutils.force_final: boolean;
  207. begin
  208. result:=false;
  209. end;
  210. class function tnodeutils.wrap_proc_body(pd: tprocdef; n: tnode): tnode;
  211. var
  212. stat: tstatementnode;
  213. block: tnode;
  214. psym: tsym;
  215. tcinitproc: tprocdef;
  216. begin
  217. result:=n;
  218. if target_info.system in systems_typed_constants_node_init then
  219. begin
  220. case pd.proctypeoption of
  221. potype_class_constructor:
  222. begin
  223. { even though the initialisation code for typed constants may
  224. not yet be complete at this point (there may be more inside
  225. method definitions coming after this class constructor), the
  226. ones from inside the class definition have already been parsed.
  227. in case of {$j-}, these are marked "final" in Java and such
  228. static fields must be initialsed in the class constructor
  229. itself -> add them here }
  230. block:=internalstatements(stat);
  231. if assigned(pd.struct.tcinitcode) then
  232. begin
  233. addstatement(stat,pd.struct.tcinitcode);
  234. pd.struct.tcinitcode:=nil;
  235. end;
  236. psym:=tsym(pd.struct.symtable.find('FPC_INIT_TYPED_CONSTS_HELPER'));
  237. if not assigned(psym) or
  238. (psym.typ<>procsym) or
  239. (tprocsym(psym).procdeflist.count<>1) then
  240. internalerror(2011040301);
  241. tcinitproc:=tprocdef(tprocsym(psym).procdeflist[0]);
  242. addstatement(stat,ccallnode.create(nil,tprocsym(psym),
  243. pd.struct.symtable,nil,[]));
  244. addstatement(stat,result);
  245. result:=block
  246. end;
  247. potype_unitinit:
  248. begin
  249. if assigned(current_module.tcinitcode) then
  250. begin
  251. block:=internalstatements(stat);
  252. addstatement(stat,tnode(current_module.tcinitcode));
  253. current_module.tcinitcode:=nil;
  254. addstatement(stat,result);
  255. result:=block;
  256. end;
  257. end;
  258. else case pd.synthetickind of
  259. tsk_tcinit:
  260. begin
  261. if assigned(pd.struct.tcinitcode) then
  262. begin
  263. block:=internalstatements(stat);
  264. addstatement(stat,pd.struct.tcinitcode);
  265. pd.struct.tcinitcode:=nil;
  266. addstatement(stat,result);
  267. result:=block
  268. end
  269. end;
  270. end;
  271. end;
  272. end;
  273. end;
  274. class procedure tnodeutils.insertbssdata(sym: tstaticvarsym);
  275. var
  276. l : asizeint;
  277. varalign : shortint;
  278. storefilepos : tfileposinfo;
  279. list : TAsmList;
  280. sectype : TAsmSectiontype;
  281. begin
  282. storefilepos:=current_filepos;
  283. current_filepos:=sym.fileinfo;
  284. l:=sym.getsize;
  285. varalign:=sym.vardef.alignment;
  286. if (varalign=0) then
  287. varalign:=var_align_size(l)
  288. else
  289. varalign:=var_align(varalign);
  290. if tf_section_threadvars in target_info.flags then
  291. begin
  292. if (vo_is_thread_var in sym.varoptions) then
  293. begin
  294. list:=current_asmdata.asmlists[al_threadvars];
  295. sectype:=sec_threadvar;
  296. end
  297. else
  298. begin
  299. list:=current_asmdata.asmlists[al_globals];
  300. sectype:=sec_bss;
  301. end;
  302. end
  303. else
  304. begin
  305. if (vo_is_thread_var in sym.varoptions) then
  306. begin
  307. inc(l,sizeof(pint));
  308. { it doesn't help to set a higher alignment, as }
  309. { the first sizeof(pint) bytes field will offset }
  310. { everything anyway }
  311. varalign:=sizeof(pint);
  312. end;
  313. list:=current_asmdata.asmlists[al_globals];
  314. sectype:=sec_bss;
  315. end;
  316. maybe_new_object_file(list);
  317. if vo_has_section in sym.varoptions then
  318. new_section(list,sec_user,sym.section,varalign)
  319. else
  320. new_section(list,sectype,lower(sym.mangledname),varalign);
  321. if (sym.owner.symtabletype=globalsymtable) or
  322. create_smartlink or
  323. DLLSource or
  324. (assigned(current_procinfo) and
  325. (po_inline in current_procinfo.procdef.procoptions)) or
  326. (vo_is_public in sym.varoptions) then
  327. list.concat(Tai_datablock.create_global(sym.mangledname,l))
  328. else
  329. list.concat(Tai_datablock.create(sym.mangledname,l));
  330. current_filepos:=storefilepos;
  331. end;
  332. end.