ngenutil.pas 68 KB

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