ngenutil.pas 62 KB

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