ngenutil.pas 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437
  1. {
  2. Copyright (c) 1998-2011 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. cclasses,globtype,
  23. aasmdata,
  24. node,nbas,symtype,symsym,symconst,symdef;
  25. type
  26. tnodeutils = class
  27. class function call_fail_node:tnode; virtual;
  28. class function initialize_data_node(p:tnode; force: boolean):tnode; virtual;
  29. class function finalize_data_node(p:tnode):tnode; virtual;
  30. strict protected
  31. class procedure sym_maybe_initialize(p: TObject; arg: pointer);
  32. { generates the code for finalisation of local variables }
  33. class procedure local_varsyms_finalize(p:TObject;arg:pointer);
  34. { generates the code for finalization of static symtable and
  35. all local (static) typed consts }
  36. class procedure static_syms_finalize(p: TObject; arg: pointer);
  37. class procedure sym_maybe_finalize(var stat: tstatementnode; sym: tsym);
  38. public
  39. class procedure procdef_block_add_implicit_initialize_nodes(pd: tprocdef; var stat: tstatementnode);
  40. class procedure procdef_block_add_implicit_finalize_nodes(pd: tprocdef; var stat: tstatementnode);
  41. { returns true if the unit requires an initialisation section (e.g.,
  42. to force class constructors for the JVM target to initialise global
  43. records/arrays) }
  44. class function force_init: boolean; virtual;
  45. { idem for finalization }
  46. class function force_final: boolean; virtual;
  47. { called after parsing a routine with the code of the entire routine
  48. as argument; can be used to modify the node tree. By default handles
  49. insertion of code for systems that perform the typed constant
  50. initialisation via the node tree }
  51. class function wrap_proc_body(pd: tprocdef; n: tnode): tnode; virtual;
  52. { trashes a paravarsym or localvarsym if possible (not a managed type,
  53. "out" in case of parameter, ...) }
  54. class procedure maybe_trash_variable(var stat: tstatementnode; p: tabstractnormalvarsym; trashn: tnode); virtual;
  55. strict protected
  56. { called from wrap_proc_body to insert the trashing for the wrapped
  57. routine's local variables and parameters }
  58. class function maybe_insert_trashing(pd: tprocdef; n: tnode): tnode;
  59. class function check_insert_trashing(pd: tprocdef): boolean; virtual;
  60. { callback called for every local variable and parameter by
  61. maybe_insert_trashing(), calls through to maybe_trash_variable() }
  62. class procedure maybe_trash_variable_callback(p: TObject; statn: pointer);
  63. { returns whether a particular sym can be trashed. If not,
  64. maybe_trash_variable won't do anything }
  65. class function trashable_sym(p: tsym): boolean; virtual;
  66. { trashing for 1/2/3/4/8-byte sized variables }
  67. class procedure trash_small(var stat: tstatementnode; trashn: tnode; trashvaln: tnode); virtual;
  68. { trashing for differently sized variables that those handled by
  69. trash_small() }
  70. class procedure trash_large(var stat: tstatementnode; trashn, sizen: tnode; trashintval: int64); virtual;
  71. { insert a single bss sym, called by insert bssdata (factored out
  72. non-common part for llvm) }
  73. class procedure insertbsssym(list: tasmlist; sym: tstaticvarsym; size: asizeint; varalign: shortint); virtual;
  74. { initialization of iso styled program parameters }
  75. class procedure initialize_textrec(p : TObject; statn : pointer);
  76. { finalization of iso styled program parameters }
  77. class procedure finalize_textrec(p : TObject; statn : pointer);
  78. public
  79. class procedure insertbssdata(sym : tstaticvarsym); virtual;
  80. class function create_main_procdef(const name: string; potype:tproctypeoption; ps: tprocsym):tdef; virtual;
  81. class procedure InsertInitFinalTable; virtual;
  82. protected
  83. class procedure InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:cardinal); virtual;
  84. class procedure InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:cardinal); virtual;
  85. public
  86. class procedure InsertThreadvarTablesTable; virtual;
  87. class procedure InsertThreadvars; virtual;
  88. class procedure InsertWideInitsTablesTable; virtual;
  89. class procedure InsertWideInits; virtual;
  90. class procedure InsertResStrInits; virtual;
  91. class procedure InsertResStrTablesTable; virtual;
  92. class procedure InsertResourceTablesTable; virtual;
  93. class procedure InsertResourceInfo(ResourcesUsed : boolean); virtual;
  94. class procedure InsertMemorySizes; virtual;
  95. { called right before an object is assembled, can be used to insert
  96. global information into the assembler list (used by LLVM to insert type
  97. info) }
  98. class procedure InsertObjectInfo; virtual;
  99. strict protected
  100. class procedure add_main_procdef_paras(pd: tdef); virtual;
  101. end;
  102. tnodeutilsclass = class of tnodeutils;
  103. const
  104. cnodeutils: tnodeutilsclass = tnodeutils;
  105. implementation
  106. uses
  107. verbose,version,globals,cutils,constexp,
  108. scanner,systems,procinfo,fmodule,
  109. aasmbase,aasmtai,aasmcnst,
  110. symbase,symtable,defutil,symcreat,
  111. nadd,ncal,ncnv,ncon,nflw,ninl,nld,nmem,nobj,nutils,ncgutil,
  112. ppu,
  113. pass_1;
  114. class function tnodeutils.call_fail_node:tnode;
  115. var
  116. para : tcallparanode;
  117. newstatement : tstatementnode;
  118. srsym : tsym;
  119. begin
  120. result:=internalstatements(newstatement);
  121. { call fail helper and exit normal }
  122. if is_class(current_structdef) then
  123. begin
  124. srsym:=search_struct_member(current_structdef,'FREEINSTANCE');
  125. if assigned(srsym) and
  126. (srsym.typ=procsym) then
  127. begin
  128. { if self<>0 and vmt<>0 then freeinstance }
  129. addstatement(newstatement,cifnode.create(
  130. caddnode.create(andn,
  131. caddnode.create(unequaln,
  132. load_self_pointer_node,
  133. cnilnode.create),
  134. caddnode.create(unequaln,
  135. load_vmt_pointer_node,
  136. cnilnode.create)),
  137. ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[],nil),
  138. nil));
  139. end
  140. else
  141. internalerror(200305108);
  142. end
  143. else
  144. if is_object(current_structdef) then
  145. begin
  146. { parameter 3 : vmt_offset }
  147. { parameter 2 : pointer to vmt }
  148. { parameter 1 : self pointer }
  149. para:=ccallparanode.create(
  150. cordconstnode.create(tobjectdef(current_structdef).vmt_offset,s32inttype,false),
  151. ccallparanode.create(
  152. ctypeconvnode.create_internal(
  153. load_vmt_pointer_node,
  154. voidpointertype),
  155. ccallparanode.create(
  156. ctypeconvnode.create_internal(
  157. load_self_pointer_node,
  158. voidpointertype),
  159. nil)));
  160. addstatement(newstatement,
  161. ccallnode.createintern('fpc_help_fail',para));
  162. end
  163. else
  164. internalerror(200305132);
  165. { self:=nil }
  166. addstatement(newstatement,cassignmentnode.create(
  167. load_self_pointer_node,
  168. cnilnode.create));
  169. { exit }
  170. addstatement(newstatement,cexitnode.create(nil));
  171. end;
  172. class function tnodeutils.initialize_data_node(p:tnode; force: boolean):tnode;
  173. begin
  174. if not assigned(p.resultdef) then
  175. typecheckpass(p);
  176. if is_ansistring(p.resultdef) or
  177. is_wide_or_unicode_string(p.resultdef) or
  178. is_interfacecom_or_dispinterface(p.resultdef) or
  179. is_dynamic_array(p.resultdef) then
  180. begin
  181. result:=cassignmentnode.create(
  182. ctypeconvnode.create_internal(p,voidpointertype),
  183. cnilnode.create
  184. );
  185. end
  186. else if (p.resultdef.typ=variantdef) then
  187. begin
  188. result:=ccallnode.createintern('fpc_variant_init',
  189. ccallparanode.create(
  190. ctypeconvnode.create_internal(p,search_system_type('TVARDATA').typedef),
  191. nil));
  192. end
  193. else
  194. begin
  195. result:=ccallnode.createintern('fpc_initialize',
  196. ccallparanode.create(
  197. caddrnode.create_internal(
  198. crttinode.create(
  199. tstoreddef(p.resultdef),initrtti,rdt_normal)),
  200. ccallparanode.create(
  201. caddrnode.create_internal(p),
  202. nil)));
  203. end;
  204. end;
  205. class function tnodeutils.finalize_data_node(p:tnode):tnode;
  206. var
  207. hs : string;
  208. begin
  209. if not assigned(p.resultdef) then
  210. typecheckpass(p);
  211. { 'decr_ref' suffix is somewhat misleading, all these helpers
  212. set the passed pointer to nil now }
  213. if is_ansistring(p.resultdef) then
  214. hs:='fpc_ansistr_decr_ref'
  215. else if is_widestring(p.resultdef) then
  216. hs:='fpc_widestr_decr_ref'
  217. else if is_unicodestring(p.resultdef) then
  218. hs:='fpc_unicodestr_decr_ref'
  219. else if is_interfacecom_or_dispinterface(p.resultdef) then
  220. hs:='fpc_intf_decr_ref'
  221. else
  222. hs:='';
  223. if hs<>'' then
  224. result:=ccallnode.createintern(hs,
  225. ccallparanode.create(
  226. ctypeconvnode.create_internal(p,voidpointertype),
  227. nil))
  228. else if p.resultdef.typ=variantdef then
  229. begin
  230. result:=ccallnode.createintern('fpc_variant_clear',
  231. ccallparanode.create(
  232. ctypeconvnode.create_internal(p,search_system_type('TVARDATA').typedef),
  233. nil));
  234. end
  235. else
  236. result:=ccallnode.createintern('fpc_finalize',
  237. ccallparanode.create(
  238. caddrnode.create_internal(
  239. crttinode.create(
  240. tstoreddef(p.resultdef),initrtti,rdt_normal)),
  241. ccallparanode.create(
  242. caddrnode.create_internal(p),
  243. nil)));
  244. end;
  245. class procedure tnodeutils.sym_maybe_initialize(p: TObject; arg: pointer);
  246. begin
  247. if (tsym(p).typ = localvarsym) and
  248. { local (procedure or unit) variables only need initialization if
  249. they are used }
  250. ((tabstractvarsym(p).refs>0) or
  251. { managed return symbols must be inited }
  252. ((tsym(p).typ=localvarsym) and (vo_is_funcret in tlocalvarsym(p).varoptions))
  253. ) and
  254. not(vo_is_typed_const in tabstractvarsym(p).varoptions) and
  255. not(vo_is_external in tabstractvarsym(p).varoptions) and
  256. not(vo_is_default_var in tabstractvarsym(p).varoptions) and
  257. (is_managed_type(tabstractvarsym(p).vardef) or
  258. ((m_iso in current_settings.modeswitches) and (tabstractvarsym(p).vardef.typ=filedef))
  259. ) then
  260. begin
  261. addstatement(tstatementnode(arg^),initialize_data_node(cloadnode.create(tsym(p),tsym(p).owner),false));
  262. end;
  263. end;
  264. class procedure tnodeutils.local_varsyms_finalize(p: TObject; arg: pointer);
  265. begin
  266. if (tsym(p).typ=localvarsym) and
  267. (tlocalvarsym(p).refs>0) and
  268. not(vo_is_external in tlocalvarsym(p).varoptions) and
  269. not(vo_is_funcret in tlocalvarsym(p).varoptions) and
  270. not(vo_is_default_var in tabstractvarsym(p).varoptions) and
  271. is_managed_type(tlocalvarsym(p).vardef) then
  272. sym_maybe_finalize(tstatementnode(arg^),tsym(p));
  273. end;
  274. class procedure tnodeutils.static_syms_finalize(p: TObject; arg: pointer);
  275. var
  276. i : longint;
  277. pd : tprocdef;
  278. begin
  279. case tsym(p).typ of
  280. staticvarsym :
  281. begin
  282. { local (procedure or unit) variables only need finalization
  283. if they are used
  284. }
  285. if ((tstaticvarsym(p).refs>0) or
  286. { global (unit) variables always need finalization, since
  287. they may also be used in another unit
  288. }
  289. (tstaticvarsym(p).owner.symtabletype=globalsymtable)) and
  290. (
  291. (tstaticvarsym(p).varspez<>vs_const) or
  292. (vo_force_finalize in tstaticvarsym(p).varoptions)
  293. ) and
  294. not(vo_is_funcret in tstaticvarsym(p).varoptions) and
  295. not(vo_is_external in tstaticvarsym(p).varoptions) and
  296. is_managed_type(tstaticvarsym(p).vardef) and
  297. not (
  298. assigned(tstaticvarsym(p).fieldvarsym) and
  299. assigned(tstaticvarsym(p).fieldvarsym.owner.defowner) and
  300. (df_generic in tdef(tstaticvarsym(p).fieldvarsym.owner.defowner).defoptions)
  301. )
  302. then
  303. sym_maybe_finalize(tstatementnode(arg^),tsym(p));
  304. end;
  305. procsym :
  306. begin
  307. for i:=0 to tprocsym(p).ProcdefList.Count-1 do
  308. begin
  309. pd:=tprocdef(tprocsym(p).ProcdefList[i]);
  310. if assigned(pd.localst) and
  311. (pd.procsym=tprocsym(p)) and
  312. (pd.localst.symtabletype<>staticsymtable) then
  313. pd.localst.SymList.ForEachCall(@static_syms_finalize,arg);
  314. end;
  315. end;
  316. end;
  317. end;
  318. class procedure tnodeutils.sym_maybe_finalize(var stat: tstatementnode; sym: tsym);
  319. var
  320. hp: tnode;
  321. begin
  322. include(current_procinfo.flags,pi_needs_implicit_finally);
  323. hp:=cloadnode.create(sym,sym.owner);
  324. if (sym.typ=staticvarsym) and (vo_force_finalize in tstaticvarsym(sym).varoptions) then
  325. include(tloadnode(hp).loadnodeflags,loadnf_isinternal_ignoreconst);
  326. addstatement(stat,finalize_data_node(hp));
  327. end;
  328. class procedure tnodeutils.procdef_block_add_implicit_initialize_nodes(pd: tprocdef; var stat: tstatementnode);
  329. begin
  330. { initialize local data like ansistrings }
  331. case pd.proctypeoption of
  332. potype_unitinit:
  333. begin
  334. { this is also used for initialization of variables in a
  335. program which does not have a globalsymtable }
  336. if assigned(current_module.globalsymtable) then
  337. TSymtable(current_module.globalsymtable).SymList.ForEachCall(@sym_maybe_initialize,@stat);
  338. TSymtable(current_module.localsymtable).SymList.ForEachCall(@sym_maybe_initialize,@stat);
  339. TSymtable(current_module.localsymtable).SymList.ForEachCall(@sym_maybe_initialize,@stat);
  340. end;
  341. { units have seperate code for initilization and finalization }
  342. potype_unitfinalize: ;
  343. { program init/final is generated in separate procedure }
  344. potype_proginit:
  345. begin
  346. TSymtable(current_module.localsymtable).SymList.ForEachCall(@sym_maybe_initialize,@stat);
  347. end;
  348. else
  349. current_procinfo.procdef.localst.SymList.ForEachCall(@sym_maybe_initialize,@stat);
  350. end;
  351. end;
  352. class procedure tnodeutils.procdef_block_add_implicit_finalize_nodes(pd: tprocdef; var stat: tstatementnode);
  353. begin
  354. { no finalization in exceptfilters, they /are/ the finalization code }
  355. if current_procinfo.procdef.proctypeoption=potype_exceptfilter then
  356. exit;
  357. { finalize local data like ansistrings}
  358. case current_procinfo.procdef.proctypeoption of
  359. potype_unitfinalize:
  360. begin
  361. { this is also used for initialization of variables in a
  362. program which does not have a globalsymtable }
  363. if assigned(current_module.globalsymtable) then
  364. TSymtable(current_module.globalsymtable).SymList.ForEachCall(@static_syms_finalize,@stat);
  365. TSymtable(current_module.localsymtable).SymList.ForEachCall(@static_syms_finalize,@stat);
  366. end;
  367. { units/progs have separate code for initialization and finalization }
  368. potype_unitinit: ;
  369. { program init/final is generated in separate procedure }
  370. potype_proginit: ;
  371. else
  372. current_procinfo.procdef.localst.SymList.ForEachCall(@local_varsyms_finalize,@stat);
  373. end;
  374. end;
  375. class function tnodeutils.force_init: boolean;
  376. begin
  377. result:=
  378. (target_info.system in systems_typed_constants_node_init) and
  379. assigned(current_module.tcinitcode);
  380. end;
  381. class function tnodeutils.force_final: boolean;
  382. begin
  383. result:=false;
  384. end;
  385. class procedure tnodeutils.initialize_textrec(p:TObject;statn:pointer);
  386. var
  387. stat: ^tstatementnode absolute statn;
  388. begin
  389. if (tsym(p).typ=staticvarsym) and
  390. (tstaticvarsym(p).vardef.typ=filedef) and
  391. (tfiledef(tstaticvarsym(p).vardef).filetyp=ft_text) and
  392. (tstaticvarsym(p).isoindex<>0) then
  393. begin
  394. addstatement(stat^,ccallnode.createintern('fpc_textinit_iso',
  395. ccallparanode.create(
  396. cordconstnode.create(tstaticvarsym(p).isoindex,uinttype,false),
  397. ccallparanode.create(
  398. cloadnode.create(tstaticvarsym(p),tstaticvarsym(p).Owner),
  399. nil))));
  400. end;
  401. end;
  402. class procedure tnodeutils.finalize_textrec(p:TObject;statn:pointer);
  403. var
  404. stat: ^tstatementnode absolute statn;
  405. begin
  406. if (tsym(p).typ=staticvarsym) and
  407. (tstaticvarsym(p).vardef.typ=filedef) and
  408. (tfiledef(tstaticvarsym(p).vardef).filetyp=ft_text) and
  409. (tstaticvarsym(p).isoindex<>0) then
  410. begin
  411. addstatement(stat^,ccallnode.createintern('fpc_textclose_iso',
  412. ccallparanode.create(
  413. cloadnode.create(tstaticvarsym(p),tstaticvarsym(p).Owner),
  414. nil)));
  415. end;
  416. end;
  417. class function tnodeutils.wrap_proc_body(pd: tprocdef; n: tnode): tnode;
  418. var
  419. stat: tstatementnode;
  420. block,
  421. target: tnode;
  422. psym: tsym;
  423. begin
  424. result:=maybe_insert_trashing(pd,n);
  425. if (m_isolike_program_para in current_settings.modeswitches) and
  426. (pd.proctypeoption=potype_proginit) then
  427. begin
  428. block:=internalstatements(stat);
  429. pd.localst.SymList.ForEachCall(@initialize_textrec,@stat);
  430. addstatement(stat,result);
  431. pd.localst.SymList.ForEachCall(@finalize_textrec,@stat);
  432. result:=block;
  433. end;
  434. if target_info.system in systems_typed_constants_node_init then
  435. begin
  436. case pd.proctypeoption of
  437. potype_class_constructor:
  438. begin
  439. { even though the initialisation code for typed constants may
  440. not yet be complete at this point (there may be more inside
  441. method definitions coming after this class constructor), the
  442. ones from inside the class definition have already been parsed.
  443. in case of $j-, these are marked "final" in Java and such
  444. static fields must be initialsed in the class constructor
  445. itself -> add them here }
  446. block:=internalstatements(stat);
  447. if assigned(pd.struct.tcinitcode) then
  448. begin
  449. addstatement(stat,pd.struct.tcinitcode);
  450. pd.struct.tcinitcode:=nil;
  451. end;
  452. psym:=tsym(pd.struct.symtable.find('FPC_INIT_TYPED_CONSTS_HELPER'));
  453. if assigned(psym) then
  454. begin
  455. if (psym.typ<>procsym) or
  456. (tprocsym(psym).procdeflist.count<>1) then
  457. internalerror(2011040301);
  458. addstatement(stat,ccallnode.create(nil,tprocsym(psym),
  459. pd.struct.symtable,nil,[],nil));
  460. end;
  461. addstatement(stat,result);
  462. result:=block
  463. end;
  464. potype_unitinit:
  465. begin
  466. if assigned(current_module.tcinitcode) then
  467. begin
  468. block:=internalstatements(stat);
  469. addstatement(stat,tnode(current_module.tcinitcode));
  470. current_module.tcinitcode:=nil;
  471. addstatement(stat,result);
  472. result:=block;
  473. end;
  474. end;
  475. else case pd.synthetickind of
  476. tsk_tcinit:
  477. begin
  478. if assigned(pd.struct.tcinitcode) then
  479. begin
  480. block:=internalstatements(stat);
  481. addstatement(stat,pd.struct.tcinitcode);
  482. pd.struct.tcinitcode:=nil;
  483. addstatement(stat,result);
  484. result:=block
  485. end
  486. end;
  487. end;
  488. end;
  489. end;
  490. if target_info.system in systems_fpnestedstruct then
  491. begin
  492. { if the funcretsym was moved to the parentfpstruct, move its value
  493. back into the funcretsym now, as the code generator is hardcoded
  494. to use the funcretsym when loading the value to be returned;
  495. replacing it with an absolutevarsym that redirects to the field in
  496. the parentfpstruct doesn't work, as the code generator cannot deal
  497. with such symbols }
  498. if assigned(pd.funcretsym) and
  499. tabstractnormalvarsym(pd.funcretsym).inparentfpstruct then
  500. begin
  501. block:=internalstatements(stat);
  502. addstatement(stat,result);
  503. target:=cloadnode.create(pd.funcretsym,pd.funcretsym.owner);
  504. { ensure the target of this assignment doesn't translate the
  505. funcretsym also to its alias in the parentfpstruct }
  506. include(target.flags,nf_internal);
  507. addstatement(stat,
  508. cassignmentnode.create(
  509. target,cloadnode.create(pd.funcretsym,pd.funcretsym.owner)
  510. )
  511. );
  512. result:=block;
  513. end;
  514. end;
  515. end;
  516. class function tnodeutils.maybe_insert_trashing(pd: tprocdef; n: tnode): tnode;
  517. var
  518. stat: tstatementnode;
  519. begin
  520. result:=n;
  521. if check_insert_trashing(pd) then
  522. begin
  523. result:=internalstatements(stat);
  524. pd.parast.SymList.ForEachCall(@maybe_trash_variable_callback,@stat);
  525. pd.localst.SymList.ForEachCall(@maybe_trash_variable_callback,@stat);
  526. addstatement(stat,n);
  527. end;
  528. end;
  529. class function tnodeutils.check_insert_trashing(pd: tprocdef): boolean;
  530. begin
  531. result:=
  532. (localvartrashing<>-1) and
  533. not(po_assembler in pd.procoptions);
  534. end;
  535. class function tnodeutils.trashable_sym(p: tsym): boolean;
  536. begin
  537. result:=
  538. ((p.typ=localvarsym) or
  539. ((p.typ=paravarsym) and
  540. ((vo_is_funcret in tabstractnormalvarsym(p).varoptions) or
  541. (tabstractnormalvarsym(p).varspez=vs_out)))) and
  542. not (vo_is_default_var in tabstractnormalvarsym(p).varoptions) and
  543. (not is_managed_type(tabstractnormalvarsym(p).vardef) or
  544. (is_string(tabstractnormalvarsym(p).vardef) and
  545. (vo_is_funcret in tabstractnormalvarsym(p).varoptions)
  546. )
  547. ) and
  548. not assigned(tabstractnormalvarsym(p).defaultconstsym);
  549. end;
  550. class procedure tnodeutils.maybe_trash_variable(var stat: tstatementnode; p: tabstractnormalvarsym; trashn: tnode);
  551. var
  552. size: asizeint;
  553. trashintval: int64;
  554. begin
  555. if trashable_sym(p) then
  556. begin
  557. trashintval:=trashintvalues[localvartrashing];
  558. if (p.vardef.typ=procvardef) and
  559. ([m_tp_procvar,m_mac_procvar]*current_settings.modeswitches<>[]) then
  560. begin
  561. if tprocvardef(p.vardef).is_addressonly then
  562. { in tp/delphi mode, you need @procvar to get at the contents of
  563. a procvar ... }
  564. trashn:=caddrnode.create(trashn)
  565. else
  566. { ... but if it's a procedure of object, that will only return
  567. the procedure address -> cast to tmethod instead }
  568. trashn:=ctypeconvnode.create_explicit(trashn,methodpointertype);
  569. end;
  570. if is_managed_type(p.vardef) then
  571. begin
  572. if is_string(p.vardef) then
  573. trash_small(stat,trashn,
  574. cstringconstnode.createstr(
  575. 'uninitialized function result in '+
  576. tprocdef(p.owner.defowner).customprocname([pno_proctypeoption, pno_paranames,pno_ownername, pno_noclassmarker])
  577. )
  578. )
  579. else
  580. internalerror(2016030601);
  581. end
  582. else if ((p.typ=localvarsym) and
  583. (not(vo_is_funcret in p.varoptions) or
  584. not is_shortstring(p.vardef))) or
  585. ((p.typ=paravarsym) and
  586. not is_shortstring(p.vardef)) then
  587. begin
  588. size:=p.getsize;
  589. case size of
  590. 0:
  591. begin
  592. { open array -> at least size 1. Can also be zero-sized
  593. record, so check it's actually an array }
  594. if p.vardef.typ=arraydef then
  595. trash_large(stat,trashn,caddnode.create(addn,cinlinenode.create(in_high_x,false,trashn.getcopy),genintconstnode(1)),trashintval)
  596. else
  597. trashn.free;
  598. end;
  599. 1: trash_small(stat,
  600. ctypeconvnode.create_internal(trashn,s8inttype),
  601. genintconstnode(shortint(trashintval)));
  602. 2: trash_small(stat,
  603. ctypeconvnode.create_internal(trashn,s16inttype),
  604. genintconstnode(smallint(trashintval)));
  605. 4: trash_small(stat,
  606. ctypeconvnode.create_internal(trashn,s32inttype),
  607. genintconstnode(longint(trashintval)));
  608. 8: trash_small(stat,
  609. ctypeconvnode.create_internal(trashn,s64inttype),
  610. genintconstnode(int64(trashintval)));
  611. else
  612. trash_large(stat,trashn,genintconstnode(size),trashintval);
  613. end;
  614. end
  615. else
  616. begin
  617. { may be an open string, even if is_open_string() returns false
  618. (for some helpers in the system unit) }
  619. { an open string has at least size 2 }
  620. trash_small(stat,
  621. cvecnode.create(trashn.getcopy,genintconstnode(0)),
  622. cordconstnode.create(tconstexprint(byte(trashintval)),cansichartype,false));
  623. trash_small(stat,
  624. cvecnode.create(trashn,genintconstnode(1)),
  625. cordconstnode.create(tconstexprint(byte(trashintval)),cansichartype,false));
  626. end;
  627. end
  628. else
  629. trashn.free;
  630. end;
  631. class procedure tnodeutils.maybe_trash_variable_callback(p:TObject;statn:pointer);
  632. var
  633. stat: ^tstatementnode absolute statn;
  634. begin
  635. if not(tsym(p).typ in [localvarsym,paravarsym]) then
  636. exit;
  637. maybe_trash_variable(stat^,tabstractnormalvarsym(p),cloadnode.create(tsym(p),tsym(p).owner));
  638. end;
  639. class procedure tnodeutils.trash_small(var stat: tstatementnode; trashn: tnode; trashvaln: tnode);
  640. begin
  641. addstatement(stat,cassignmentnode.create(trashn,trashvaln));
  642. end;
  643. class procedure tnodeutils.trash_large(var stat: tstatementnode; trashn, sizen: tnode; trashintval: int64);
  644. begin
  645. addstatement(stat,ccallnode.createintern('fpc_fillmem',
  646. ccallparanode.Create(cordconstnode.create(tconstexprint(byte(trashintval)),u8inttype,false),
  647. ccallparanode.Create(sizen,
  648. ccallparanode.Create(trashn,nil)))
  649. ));
  650. end;
  651. class procedure tnodeutils.insertbsssym(list: tasmlist; sym: tstaticvarsym; size: asizeint; varalign: shortint);
  652. var
  653. symind : tasmsymbol;
  654. begin
  655. if sym.globalasmsym then
  656. begin
  657. { on AIX/stabx, we cannot generate debug information that encodes
  658. the address of a global symbol, you need a symbol with the same
  659. name as the identifier -> create an extra *local* symbol.
  660. Moreover, such a local symbol will be removed if it's not
  661. referenced anywhere, so also create a reference }
  662. if (target_dbg.id=dbg_stabx) and
  663. (cs_debuginfo in current_settings.moduleswitches) and
  664. not assigned(current_asmdata.GetAsmSymbol(sym.name)) then
  665. begin
  666. list.concat(tai_symbol.Create(current_asmdata.DefineAsmSymbol(sym.name,AB_LOCAL,AT_DATA,sym.vardef),0));
  667. list.concat(tai_directive.Create(asd_reference,sym.name));
  668. end;
  669. list.concat(Tai_datablock.create_global(sym.mangledname,size,sym.vardef));
  670. end
  671. else
  672. list.concat(Tai_datablock.create(sym.mangledname,size,sym.vardef));
  673. if (tf_supports_packages in target_info.flags) then
  674. begin
  675. { add the indirect symbol if needed }
  676. new_section(list,sec_rodata,lower(sym.mangledname),const_align(sym.vardef.alignment));
  677. symind:=current_asmdata.DefineAsmSymbol(sym.mangledname,AB_INDIRECT,AT_DATA,cpointerdef.getreusable(sym.vardef));
  678. list.concat(Tai_symbol.Create_Global(symind,0));
  679. list.concat(Tai_const.Createname(sym.mangledname,AT_DATA,0));
  680. list.concat(tai_symbol_end.Create(symind));
  681. end;
  682. end;
  683. class procedure tnodeutils.insertbssdata(sym: tstaticvarsym);
  684. var
  685. l : asizeint;
  686. varalign : shortint;
  687. storefilepos : tfileposinfo;
  688. list : TAsmList;
  689. sectype : TAsmSectiontype;
  690. begin
  691. storefilepos:=current_filepos;
  692. current_filepos:=sym.fileinfo;
  693. l:=sym.getsize;
  694. varalign:=sym.vardef.alignment;
  695. if (varalign=0) then
  696. varalign:=var_align_size(l)
  697. else
  698. varalign:=var_align(varalign);
  699. if tf_section_threadvars in target_info.flags then
  700. begin
  701. if (vo_is_thread_var in sym.varoptions) then
  702. begin
  703. list:=current_asmdata.asmlists[al_threadvars];
  704. sectype:=sec_threadvar;
  705. end
  706. else
  707. begin
  708. list:=current_asmdata.asmlists[al_globals];
  709. sectype:=sec_bss;
  710. end;
  711. end
  712. else
  713. begin
  714. if (vo_is_thread_var in sym.varoptions) then
  715. begin
  716. inc(l,sizeof(pint));
  717. { it doesn't help to set a higher alignment, as }
  718. { the first sizeof(pint) bytes field will offset }
  719. { everything anyway }
  720. varalign:=sizeof(pint);
  721. end;
  722. list:=current_asmdata.asmlists[al_globals];
  723. sectype:=sec_bss;
  724. end;
  725. maybe_new_object_file(list);
  726. if vo_has_section in sym.varoptions then
  727. new_section(list,sec_user,sym.section,varalign)
  728. else
  729. new_section(list,sectype,lower(sym.mangledname),varalign);
  730. insertbsssym(list,sym,l,varalign);
  731. current_filepos:=storefilepos;
  732. end;
  733. class function tnodeutils.create_main_procdef(const name: string; potype: tproctypeoption; ps: tprocsym): tdef;
  734. var
  735. pd: tprocdef;
  736. begin
  737. if potype<>potype_mainstub then
  738. pd:=cprocdef.create(main_program_level,true)
  739. else
  740. pd:=cprocdef.create(normal_function_level,true);
  741. { always register the def }
  742. pd.register_def;
  743. pd.procsym:=ps;
  744. ps.ProcdefList.Add(pd);
  745. include(pd.procoptions,po_global);
  746. { set procdef options }
  747. pd.proctypeoption:=potype;
  748. pd.proccalloption:=pocall_default;
  749. include(pd.procoptions,po_hascallingconvention);
  750. pd.forwarddef:=false;
  751. { may be required to calculate the mangled name }
  752. add_main_procdef_paras(pd);
  753. pd.setmangledname(name);
  754. { the mainstub is generated via a synthetic proc -> parsed via
  755. psub.read_proc_body() -> that one will insert the mangled name in the
  756. alias names already }
  757. if potype<>potype_mainstub then
  758. pd.aliasnames.insert(pd.mangledname);
  759. result:=pd;
  760. end;
  761. procedure AddToStructInits(p:TObject;arg:pointer);
  762. var
  763. StructList: TFPList absolute arg;
  764. begin
  765. if (tdef(p).typ in [objectdef,recorddef]) and
  766. not (df_generic in tdef(p).defoptions) then
  767. begin
  768. { first add the class... }
  769. if ([oo_has_class_constructor,oo_has_class_destructor] * tabstractrecorddef(p).objectoptions <> []) then
  770. StructList.Add(p);
  771. { ... and then also add all subclasses }
  772. tabstractrecorddef(p).symtable.deflist.foreachcall(@AddToStructInits,arg);
  773. end;
  774. end;
  775. class procedure tnodeutils.InsertInitFinalTable;
  776. var
  777. hp : tused_unit;
  778. unitinits : ttai_typedconstbuilder;
  779. count : aint;
  780. tablecountplaceholder: ttypedconstplaceholder;
  781. nameinit,namefini : TSymStr;
  782. tabledef: tdef;
  783. procedure write_struct_inits(u: tmodule);
  784. var
  785. i: integer;
  786. structlist: TFPList;
  787. pd: tprocdef;
  788. begin
  789. structlist := TFPList.Create;
  790. if assigned(u.globalsymtable) then
  791. u.globalsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  792. u.localsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  793. { write structures }
  794. for i:=0 to structlist.Count-1 do
  795. begin
  796. pd:=tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_constructor);
  797. if assigned(pd) then
  798. begin
  799. unitinits.emit_procdef_const(pd);
  800. if u<>current_module then
  801. u.addimportedsym(pd.procsym);
  802. end
  803. else
  804. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  805. pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_destructor);
  806. if assigned(pd) then
  807. begin
  808. unitinits.emit_procdef_const(pd);
  809. if u<>current_module then
  810. u.addimportedsym(pd.procsym);
  811. end
  812. else
  813. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  814. inc(count);
  815. end;
  816. structlist.free;
  817. end;
  818. procedure add_initfinal_import(symtable:tsymtable);
  819. var
  820. i,j : longint;
  821. foundinit,foundfini : boolean;
  822. sym : TSymEntry;
  823. pd : tprocdef;
  824. begin
  825. if (nameinit='') and (namefini='') then
  826. exit;
  827. foundinit:=nameinit='';
  828. foundfini:=namefini='';
  829. for i:=0 to symtable.SymList.Count-1 do
  830. begin
  831. sym:=tsymentry(symtable.SymList[i]);
  832. if sym.typ<>procsym then
  833. continue;
  834. for j:=0 to tprocsym(sym).procdeflist.count-1 do
  835. begin
  836. pd:=tprocdef(tprocsym(sym).procdeflist[j]);
  837. if (nameinit<>'') and not foundinit and has_alias_name(pd,nameinit) then
  838. begin
  839. current_module.addimportedsym(sym);
  840. foundinit:=true;
  841. end;
  842. if (namefini<>'') and not foundfini and has_alias_name(pd,namefini) then
  843. begin
  844. current_module.addimportedsym(sym);
  845. foundfini:=true;
  846. end;
  847. if foundinit and foundfini then
  848. break;
  849. end;
  850. if foundinit and foundfini then
  851. break;
  852. end;
  853. if not foundinit or not foundfini then
  854. internalerror(2016041401);
  855. end;
  856. begin
  857. unitinits:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  858. unitinits.begin_anonymous_record('',default_settings.packrecords,sizeof(pint),
  859. targetinfos[target_info.system]^.alignment.recordalignmin,
  860. targetinfos[target_info.system]^.alignment.maxCrecordalign);
  861. { placeholder for tablecount }
  862. tablecountplaceholder:=unitinits.emit_placeholder(sinttype);
  863. { initcount (initialised at run time }
  864. unitinits.emit_ord_const(0,sinttype);
  865. count:=0;
  866. hp:=tused_unit(usedunits.first);
  867. while assigned(hp) do
  868. begin
  869. { insert class constructors/destructors of the unit }
  870. if (hp.u.flags and uf_classinits) <> 0 then
  871. write_struct_inits(hp.u);
  872. { call the unit init code and make it external }
  873. if (hp.u.flags and (uf_init or uf_finalize))<>0 then
  874. begin
  875. if count=high(aint) then
  876. Message1(cg_f_max_units_reached,tostr(count));
  877. nameinit:='';
  878. namefini:='';
  879. if (hp.u.flags and uf_init)<>0 then
  880. begin
  881. nameinit:=make_mangledname('INIT$',hp.u.globalsymtable,'');
  882. unitinits.emit_tai(
  883. Tai_const.Createname(nameinit,AT_FUNCTION,0),
  884. voidcodepointertype);
  885. end
  886. else
  887. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  888. if (hp.u.flags and uf_finalize)<>0 then
  889. begin
  890. namefini:=make_mangledname('FINALIZE$',hp.u.globalsymtable,'');
  891. unitinits.emit_tai(
  892. Tai_const.Createname(namefini,AT_FUNCTION,0),
  893. voidcodepointertype)
  894. end
  895. else
  896. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  897. add_initfinal_import(hp.u.localsymtable);
  898. inc(count);
  899. end;
  900. hp:=tused_unit(hp.next);
  901. end;
  902. { insert class constructors/destructor of the program }
  903. if (current_module.flags and uf_classinits) <> 0 then
  904. write_struct_inits(current_module);
  905. { Insert initialization/finalization of the program }
  906. if (current_module.flags and (uf_init or uf_finalize))<>0 then
  907. begin
  908. if (current_module.flags and uf_init)<>0 then
  909. unitinits.emit_tai(
  910. Tai_const.Createname(make_mangledname('INIT$',current_module.localsymtable,''),AT_FUNCTION,0),
  911. voidcodepointertype)
  912. else
  913. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  914. if (current_module.flags and uf_finalize)<>0 then
  915. unitinits.emit_tai(
  916. Tai_const.Createname(make_mangledname('FINALIZE$',current_module.localsymtable,''),AT_FUNCTION,0),
  917. voidcodepointertype)
  918. else
  919. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  920. inc(count);
  921. end;
  922. { fill in tablecount }
  923. tablecountplaceholder.replace(tai_const.Create_aint(count),sinttype);
  924. tablecountplaceholder.free;
  925. { Add to data segment }
  926. tabledef:=unitinits.end_anonymous_record;
  927. current_asmdata.asmlists[al_globals].concatlist(
  928. unitinits.get_final_asmlist(
  929. current_asmdata.DefineAsmSymbol('INITFINAL',AB_GLOBAL,AT_DATA,tabledef),
  930. tabledef,
  931. sec_data,'INITFINAL',sizeof(pint)
  932. )
  933. );
  934. unitinits.free;
  935. end;
  936. class procedure tnodeutils.InsertThreadvarTablesTable;
  937. var
  938. hp : tused_unit;
  939. tcb: ttai_typedconstbuilder;
  940. count: longint;
  941. sym: tasmsymbol;
  942. placeholder: ttypedconstplaceholder;
  943. tabledef: tdef;
  944. begin
  945. if (tf_section_threadvars in target_info.flags) then
  946. exit;
  947. count:=0;
  948. tcb:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  949. tcb.begin_anonymous_record('',1,sizeof(pint),
  950. targetinfos[target_info.system]^.alignment.recordalignmin,
  951. targetinfos[target_info.system]^.alignment.maxCrecordalign
  952. );
  953. placeholder:=tcb.emit_placeholder(u32inttype);
  954. hp:=tused_unit(usedunits.first);
  955. while assigned(hp) do
  956. begin
  957. if (hp.u.flags and uf_threadvars)=uf_threadvars then
  958. begin
  959. sym:=current_asmdata.RefAsmSymbol(make_mangledname('THREADVARLIST',hp.u.globalsymtable,''),AT_DATA,true);
  960. tcb.emit_tai(
  961. tai_const.Create_sym(sym),
  962. voidpointertype);
  963. inc(count);
  964. end;
  965. hp:=tused_unit(hp.next);
  966. end;
  967. { Add program threadvars, if any }
  968. if (current_module.flags and uf_threadvars)=uf_threadvars then
  969. begin
  970. sym:=current_asmdata.RefAsmSymbol(make_mangledname('THREADVARLIST',current_module.localsymtable,''),AT_DATA,true);
  971. tcb.emit_tai(
  972. Tai_const.Create_sym(sym),
  973. voidpointertype);
  974. inc(count);
  975. end;
  976. { set the count at the start }
  977. placeholder.replace(tai_const.Create_32bit(count),u32inttype);
  978. placeholder.free;
  979. { insert in data segment }
  980. tabledef:=tcb.end_anonymous_record;
  981. sym:=current_asmdata.DefineAsmSymbol('FPC_THREADVARTABLES',AB_GLOBAL,AT_DATA,tabledef);
  982. current_asmdata.asmlists[al_globals].concatlist(
  983. tcb.get_final_asmlist(
  984. sym,tabledef,sec_data,'FPC_THREADVARTABLES',sizeof(pint)
  985. )
  986. );
  987. tcb.free;
  988. end;
  989. procedure AddToThreadvarList(p:TObject;arg:pointer);
  990. var
  991. tcb: ttai_typedconstbuilder;
  992. field1, field2: tsym;
  993. begin
  994. if (tsym(p).typ=staticvarsym) and
  995. (vo_is_thread_var in tstaticvarsym(p).varoptions) then
  996. begin
  997. tcb:=ttai_typedconstbuilder(arg);
  998. { address of threadvar }
  999. tcb.emit_tai(tai_const.Createname(tstaticvarsym(p).mangledname,0),
  1000. cpointerdef.getreusable(
  1001. get_threadvar_record(tstaticvarsym(p).vardef,field1,field2)
  1002. )
  1003. );
  1004. { size of threadvar }
  1005. tcb.emit_ord_const(tstaticvarsym(p).getsize,u32inttype);
  1006. end;
  1007. end;
  1008. class procedure tnodeutils.InsertThreadvars;
  1009. var
  1010. s : string;
  1011. tcb: ttai_typedconstbuilder;
  1012. sym: tasmsymbol;
  1013. tabledef: trecorddef;
  1014. add : boolean;
  1015. begin
  1016. if (tf_section_threadvars in target_info.flags) then
  1017. exit;
  1018. tcb:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  1019. tabledef:=tcb.begin_anonymous_record('',1,sizeof(pint),
  1020. targetinfos[target_info.system]^.alignment.recordalignmin,
  1021. targetinfos[target_info.system]^.alignment.maxCrecordalign);
  1022. if assigned(current_module.globalsymtable) then
  1023. current_module.globalsymtable.SymList.ForEachCall(@AddToThreadvarList,tcb);
  1024. current_module.localsymtable.SymList.ForEachCall(@AddToThreadvarList,tcb);
  1025. if trecordsymtable(tabledef.symtable).datasize<>0 then
  1026. { terminator }
  1027. tcb.emit_tai(tai_const.Create_nil_dataptr,voidpointertype);
  1028. tcb.end_anonymous_record;
  1029. add:=trecordsymtable(tabledef.symtable).datasize<>0;
  1030. if add then
  1031. begin
  1032. s:=make_mangledname('THREADVARLIST',current_module.localsymtable,'');
  1033. sym:=current_asmdata.DefineAsmSymbol(s,AB_GLOBAL,AT_DATA,tabledef);
  1034. current_asmdata.asmlists[al_globals].concatlist(
  1035. tcb.get_final_asmlist(sym,tabledef,sec_data,s,sizeof(pint)));
  1036. current_module.flags:=current_module.flags or uf_threadvars;
  1037. end
  1038. else
  1039. s:='';
  1040. tcb.Free;
  1041. if add then
  1042. begin
  1043. { write indirect symbol }
  1044. tcb:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  1045. tcb.emit_tai(Tai_const.Create_sym(current_asmdata.RefAsmSymbol(s,AT_DATA,false)),cpointerdef.getreusable(tabledef));
  1046. sym:=current_asmdata.DefineAsmSymbol(s,AB_INDIRECT,AT_DATA,voidpointertype);
  1047. current_asmdata.AsmLists[al_globals].concatList(
  1048. tcb.get_final_asmlist(sym,cpointerdef.getreusable(tabledef),sec_rodata,sym.name,const_align(sizeof(pint))));
  1049. tcb.free;
  1050. end;
  1051. end;
  1052. class procedure tnodeutils.InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:cardinal);
  1053. var
  1054. hp: tused_unit;
  1055. tcb: ttai_typedconstbuilder;
  1056. countplaceholder: ttypedconstplaceholder;
  1057. tabledef: tdef;
  1058. count: longint;
  1059. begin
  1060. tcb:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  1061. tcb.begin_anonymous_record('',default_settings.packrecords,sizeof(pint),
  1062. targetinfos[target_info.system]^.alignment.recordalignmin,
  1063. targetinfos[target_info.system]^.alignment.maxCrecordalign
  1064. );
  1065. { placeholder for the count }
  1066. countplaceholder:=tcb.emit_placeholder(ptruinttype);
  1067. count:=0;
  1068. hp:=tused_unit(usedunits.first);
  1069. while assigned(hp) do
  1070. begin
  1071. if (hp.u.flags and unitflag)=unitflag then
  1072. begin
  1073. tcb.emit_tai(
  1074. Tai_const.Createname(make_mangledname(prefix,hp.u.globalsymtable,''),0),
  1075. voidcodepointertype);
  1076. inc(count);
  1077. end;
  1078. hp:=tused_unit(hp.next);
  1079. end;
  1080. { Add items from program, if any }
  1081. if (current_module.flags and unitflag)=unitflag then
  1082. begin
  1083. tcb.emit_tai(
  1084. Tai_const.Createname(make_mangledname(prefix,current_module.localsymtable,''),0),
  1085. voidcodepointertype);
  1086. inc(count);
  1087. end;
  1088. { Insert TableCount at start }
  1089. countplaceholder.replace(Tai_const.Create_pint(count),ptruinttype);
  1090. countplaceholder.free;
  1091. { insert in data segment }
  1092. tabledef:=tcb.end_anonymous_record;
  1093. current_asmdata.asmlists[al_globals].concatlist(
  1094. tcb.get_final_asmlist(
  1095. current_asmdata.DefineAsmSymbol(tablename,AB_GLOBAL,AT_DATA,tabledef),
  1096. tabledef,
  1097. sec_data,tablename,sizeof(pint)
  1098. )
  1099. );
  1100. tcb.free;
  1101. end;
  1102. class procedure tnodeutils.InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:cardinal);
  1103. var
  1104. s: string;
  1105. item: TTCInitItem;
  1106. begin
  1107. item:=TTCInitItem(list.First);
  1108. if item=nil then
  1109. exit;
  1110. s:=make_mangledname(prefix,current_module.localsymtable,'');
  1111. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  1112. new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
  1113. { TODO: def of the symbol to be fixed when this is converted to to the
  1114. typed constant builder }
  1115. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0,voidpointertype));
  1116. repeat
  1117. { optimize away unused local/static symbols }
  1118. if (item.sym.refs>0) or (item.sym.owner.symtabletype=globalsymtable) then
  1119. begin
  1120. { address to initialize }
  1121. current_asmdata.asmlists[al_globals].concat(Tai_const.createname(item.sym.mangledname, item.offset));
  1122. { value with which to initialize }
  1123. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(item.datalabel));
  1124. end;
  1125. item:=TTCInitItem(item.Next);
  1126. until item=nil;
  1127. { end-of-list marker }
  1128. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  1129. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
  1130. current_module.flags:=current_module.flags or unitflag;
  1131. end;
  1132. class procedure tnodeutils.InsertWideInits;
  1133. begin
  1134. InsertRuntimeInits('WIDEINITS',current_asmdata.WideInits,uf_wideinits);
  1135. end;
  1136. class procedure tnodeutils.InsertResStrInits;
  1137. begin
  1138. InsertRuntimeInits('RESSTRINITS',current_asmdata.ResStrInits,uf_resstrinits);
  1139. end;
  1140. class procedure tnodeutils.InsertWideInitsTablesTable;
  1141. begin
  1142. InsertRuntimeInitsTablesTable('WIDEINITS','FPC_WIDEINITTABLES',uf_wideinits);
  1143. end;
  1144. class procedure tnodeutils.InsertResStrTablesTable;
  1145. begin
  1146. InsertRuntimeInitsTablesTable('RESSTRINITS','FPC_RESSTRINITTABLES',uf_resstrinits);
  1147. end;
  1148. class procedure tnodeutils.InsertResourceTablesTable;
  1149. var
  1150. hp : tmodule;
  1151. count : longint;
  1152. tcb : ttai_typedconstbuilder;
  1153. countplaceholder : ttypedconstplaceholder;
  1154. tabledef: tdef;
  1155. begin
  1156. tcb:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  1157. count:=0;
  1158. hp:=tmodule(loaded_units.first);
  1159. tcb.begin_anonymous_record('',default_settings.packrecords,sizeof(pint),
  1160. targetinfos[target_info.system]^.alignment.recordalignmin,
  1161. targetinfos[target_info.system]^.alignment.maxCrecordalign);
  1162. countplaceholder:=tcb.emit_placeholder(ptruinttype);
  1163. while assigned(hp) do
  1164. begin
  1165. If (hp.flags and uf_has_resourcestrings)=uf_has_resourcestrings then
  1166. begin
  1167. tcb.emit_tai(Tai_const.Create_sym(
  1168. ctai_typedconstbuilder.get_vectorized_dead_strip_section_symbol_start('RESSTR',hp.localsymtable,false)),
  1169. voidpointertype
  1170. );
  1171. tcb.emit_tai(Tai_const.Create_sym(
  1172. ctai_typedconstbuilder.get_vectorized_dead_strip_section_symbol_end('RESSTR',hp.localsymtable,false)),
  1173. voidpointertype
  1174. );
  1175. inc(count);
  1176. end;
  1177. hp:=tmodule(hp.next);
  1178. end;
  1179. { Insert TableCount at start }
  1180. countplaceholder.replace(Tai_const.Create_pint(count),ptruinttype);
  1181. countplaceholder.free;
  1182. { Add to data segment }
  1183. tabledef:=tcb.end_anonymous_record;
  1184. current_asmdata.AsmLists[al_globals].concatList(
  1185. tcb.get_final_asmlist(
  1186. current_asmdata.DefineAsmSymbol('FPC_RESOURCESTRINGTABLES',AB_GLOBAL,AT_DATA,tabledef),
  1187. tabledef,sec_rodata,'FPC_RESOURCESTRINGTABLES',sizeof(pint)
  1188. )
  1189. );
  1190. tcb.free;
  1191. end;
  1192. class procedure tnodeutils.InsertResourceInfo(ResourcesUsed: boolean);
  1193. var
  1194. tcb: ttai_typedconstbuilder;
  1195. begin
  1196. if (target_res.id in [res_elf,res_macho,res_xcoff]) or
  1197. { generate the FPC_RESLOCATION symbol even when using external resources,
  1198. because in SysInit we can only reference it unconditionally }
  1199. ((target_res.id=res_ext) and (target_info.system in systems_darwin)) then
  1200. begin
  1201. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_make_dead_strippable]);
  1202. if ResourcesUsed and (target_res.id<>res_ext) then
  1203. tcb.emit_tai(Tai_const.Createname('FPC_RESSYMBOL',0),voidpointertype)
  1204. else
  1205. { Nil pointer to resource information }
  1206. tcb.emit_tai(tai_const.Create_nil_dataptr,voidpointertype);
  1207. current_asmdata.asmlists[al_globals].concatList(
  1208. tcb.get_final_asmlist(
  1209. current_asmdata.DefineAsmSymbol('FPC_RESLOCATION',AB_GLOBAL,AT_DATA,voidpointertype),
  1210. voidpointertype,
  1211. sec_rodata,
  1212. 'FPC_RESLOCATION',
  1213. sizeof(puint)
  1214. )
  1215. );
  1216. tcb.free;
  1217. end;
  1218. end;
  1219. class procedure tnodeutils.InsertMemorySizes;
  1220. var
  1221. tcb: ttai_typedconstbuilder;
  1222. s: shortstring;
  1223. sym: tasmsymbol;
  1224. def: tdef;
  1225. begin
  1226. { Insert Ident of the compiler in the .fpc.version section }
  1227. tcb:=ctai_typedconstbuilder.create([tcalo_no_dead_strip]);
  1228. s:='FPC '+full_version_string+
  1229. ' ['+date_string+'] for '+target_cpu_string+' - '+target_info.shortname;
  1230. def:=carraydef.getreusable(cansichartype,length(s));
  1231. tcb.maybe_begin_aggregate(def);
  1232. tcb.emit_tai(Tai_string.Create(s),def);
  1233. tcb.maybe_end_aggregate(def);
  1234. sym:=current_asmdata.DefineAsmSymbol('__fpc_ident',AB_LOCAL,AT_DATA,def);
  1235. current_asmdata.asmlists[al_globals].concatlist(
  1236. tcb.get_final_asmlist(sym,def,sec_fpc,'version',const_align(32))
  1237. );
  1238. tcb.free;
  1239. if (tf_emit_stklen in target_info.flags) or
  1240. not(tf_no_generic_stackcheck in target_info.flags) then
  1241. begin
  1242. { stacksize can be specified and is now simulated }
  1243. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_make_dead_strippable]);
  1244. tcb.emit_tai(Tai_const.Create_pint(stacksize),ptruinttype);
  1245. sym:=current_asmdata.DefineAsmSymbol('__stklen',AB_GLOBAL,AT_DATA,ptruinttype);
  1246. current_asmdata.asmlists[al_globals].concatlist(
  1247. tcb.get_final_asmlist(sym,ptruinttype,sec_data,'__stklen',sizeof(pint))
  1248. );
  1249. tcb.free;
  1250. end;
  1251. {$IFDEF POWERPC}
  1252. { AmigaOS4 "stack cookie" support }
  1253. if ( target_info.system = system_powerpc_amiga ) then
  1254. begin
  1255. { this symbol is needed to ignite powerpc amigaos' }
  1256. { stack allocation magic for us with the given stack size. }
  1257. { note: won't work for m68k amigaos or morphos. (KB) }
  1258. str(stacksize,s);
  1259. s:='$STACK: '+s+#0;
  1260. def:=carraydef.getreusable(cansichartype,length(s));
  1261. tcb:=ctai_typedconstbuilder.create([tcalo_new_section]);
  1262. tcb.maybe_begin_aggregate(def);
  1263. tcb.emit_tai(Tai_string.Create(s),def);
  1264. tcb.maybe_end_aggregate(def);
  1265. sym:=current_asmdata.DefineAsmSymbol('__stack_cookie',AB_GLOBAL,AT_DATA,def);
  1266. current_asmdata.asmlists[al_globals].concatlist(
  1267. tcb.get_final_asmlist(sym,def,sec_data,'__stack_cookie',sizeof(pint))
  1268. );
  1269. tcb.free;
  1270. end;
  1271. {$ENDIF POWERPC}
  1272. { Initial heapsize }
  1273. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_make_dead_strippable]);
  1274. tcb.emit_tai(Tai_const.Create_pint(heapsize),ptruinttype);
  1275. sym:=current_asmdata.DefineAsmSymbol('__heapsize',AB_GLOBAL,AT_DATA,ptruinttype);
  1276. current_asmdata.asmlists[al_globals].concatlist(
  1277. tcb.get_final_asmlist(sym,ptruinttype,sec_data,'__heapsize',sizeof(pint))
  1278. );
  1279. tcb.free;
  1280. { allocate an initial heap on embedded systems }
  1281. if target_info.system in systems_embedded then
  1282. begin
  1283. { tai_datablock cannot yet be handled via the high level typed const
  1284. builder, because it implies the generation of a symbol, while this
  1285. is separate in the builder }
  1286. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  1287. new_section(current_asmdata.asmlists[al_globals],sec_bss,'__fpc_initialheap',current_settings.alignment.varalignmax);
  1288. current_asmdata.asmlists[al_globals].concat(tai_datablock.Create_global('__fpc_initialheap',heapsize,carraydef.getreusable(u8inttype,heapsize)));
  1289. end;
  1290. { Valgrind usage }
  1291. tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_make_dead_strippable]);
  1292. tcb.emit_ord_const(byte(cs_gdb_valgrind in current_settings.globalswitches),u8inttype);
  1293. sym:=current_asmdata.DefineAsmSymbol('__fpc_valgrind',AB_GLOBAL,AT_DATA,u8inttype);
  1294. current_asmdata.asmlists[al_globals].concatlist(
  1295. tcb.get_final_asmlist(sym,ptruinttype,sec_data,'__fpc_valgrind',sizeof(pint))
  1296. );
  1297. tcb.free;
  1298. end;
  1299. class procedure tnodeutils.InsertObjectInfo;
  1300. begin
  1301. { don't do anything by default }
  1302. end;
  1303. class procedure tnodeutils.add_main_procdef_paras(pd: tdef);
  1304. var
  1305. pvs: tparavarsym;
  1306. begin
  1307. { stub for calling FPC_SYSTEMMAIN from the C main -> add argc/argv/argp }
  1308. if (tprocdef(pd).proctypeoption=potype_mainstub) and
  1309. (target_info.system in (systems_darwin+[system_powerpc_macos]+systems_aix)) then
  1310. begin
  1311. pvs:=cparavarsym.create('ARGC',1,vs_const,s32inttype,[]);
  1312. tprocdef(pd).parast.insert(pvs);
  1313. pvs:=cparavarsym.create('ARGV',2,vs_const,cpointerdef.getreusable(charpointertype),[]);
  1314. tprocdef(pd).parast.insert(pvs);
  1315. pvs:=cparavarsym.create('ARGP',3,vs_const,cpointerdef.getreusable(charpointertype),[]);
  1316. tprocdef(pd).parast.insert(pvs);
  1317. tprocdef(pd).calcparas;
  1318. end;
  1319. end;
  1320. end.