2
0

ngenutil.pas 62 KB

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