ngenutil.pas 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096
  1. {
  2. Copyright (c) 1998-2011 by Florian Klaempfl
  3. Generic version of some node tree helper routines that can be overridden
  4. by cpu-specific versions
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit ngenutil;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. cclasses,globtype,
  23. aasmdata,
  24. node,nbas,symtype,symsym,symconst,symdef;
  25. type
  26. tnodeutils = class
  27. class function call_fail_node:tnode; virtual;
  28. class function initialize_data_node(p:tnode; force: boolean):tnode; virtual;
  29. class function finalize_data_node(p:tnode):tnode; virtual;
  30. { returns true if the unit requires an initialisation section (e.g.,
  31. to force class constructors for the JVM target to initialise global
  32. records/arrays) }
  33. class function force_init: boolean; virtual;
  34. { idem for finalization }
  35. class function force_final: boolean; virtual;
  36. { called after parsing a routine with the code of the entire routine
  37. as argument; can be used to modify the node tree. By default handles
  38. insertion of code for systems that perform the typed constant
  39. initialisation via the node tree }
  40. class function wrap_proc_body(pd: tprocdef; n: tnode): tnode; virtual;
  41. { trashes a paravarsym or localvarsym if possible (not a managed type,
  42. "out" in case of parameter, ...) }
  43. class procedure maybe_trash_variable(var stat: tstatementnode; p: tabstractnormalvarsym; trashn: tnode); virtual;
  44. strict protected
  45. { called from wrap_proc_body to insert the trashing for the wrapped
  46. routine's local variables and parameters }
  47. class function maybe_insert_trashing(pd: tprocdef; n: tnode): tnode;
  48. class function check_insert_trashing(pd: tprocdef): boolean; virtual;
  49. { callback called for every local variable and parameter by
  50. maybe_insert_trashing(), calls through to maybe_trash_variable() }
  51. class procedure maybe_trash_variable_callback(p: TObject; statn: pointer);
  52. { returns whether a particular sym can be trashed. If not,
  53. maybe_trash_variable won't do anything }
  54. class function trashable_sym(p: tsym): boolean; virtual;
  55. { trashing for 1/2/3/4/8-byte sized variables }
  56. class procedure trash_small(var stat: tstatementnode; trashn: tnode; trashvaln: tnode); virtual;
  57. { trashing for differently sized variables that those handled by
  58. trash_small() }
  59. class procedure trash_large(var stat: tstatementnode; trashn, sizen: tnode; trashintval: int64); virtual;
  60. { insert a single bss sym, called by insert bssdata (factored out
  61. non-common part for llvm) }
  62. class procedure insertbsssym(list: tasmlist; sym: tstaticvarsym; size: asizeint; varalign: shortint); virtual;
  63. { initialization of iso styled program parameters }
  64. class procedure initialize_textrec(p : TObject; statn : pointer);
  65. { finalization of iso styled program parameters }
  66. class procedure finalize_textrec(p : TObject; statn : pointer);
  67. public
  68. class procedure insertbssdata(sym : tstaticvarsym); virtual;
  69. class function create_main_procdef(const name: string; potype:tproctypeoption; ps: tprocsym):tdef; virtual;
  70. class procedure InsertInitFinalTable; virtual;
  71. protected
  72. class procedure InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:cardinal); virtual;
  73. class procedure InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:cardinal); virtual;
  74. public
  75. class procedure InsertThreadvarTablesTable; virtual;
  76. class procedure InsertThreadvars; virtual;
  77. class procedure InsertWideInitsTablesTable; virtual;
  78. class procedure InsertWideInits; virtual;
  79. class procedure InsertResStrInits; virtual;
  80. class procedure InsertResStrTablesTable; virtual;
  81. class procedure InsertResourceTablesTable; virtual;
  82. class procedure InsertResourceInfo(ResourcesUsed : boolean); virtual;
  83. class procedure InsertMemorySizes; virtual;
  84. { called right before an object is assembled, can be used to insert
  85. global information into the assembler list (used by LLVM to insert type
  86. info) }
  87. class procedure InsertObjectInfo; virtual;
  88. strict protected
  89. class procedure add_main_procdef_paras(pd: tdef); virtual;
  90. end;
  91. tnodeutilsclass = class of tnodeutils;
  92. const
  93. cnodeutils: tnodeutilsclass = tnodeutils;
  94. implementation
  95. uses
  96. verbose,version,globals,cutils,constexp,
  97. scanner,systems,procinfo,fmodule,
  98. aasmbase,aasmtai,aasmcnst,
  99. symbase,symtable,defutil,
  100. nadd,ncal,ncnv,ncon,nflw,ninl,nld,nmem,nobj,nutils,
  101. ppu,
  102. pass_1;
  103. class function tnodeutils.call_fail_node:tnode;
  104. var
  105. para : tcallparanode;
  106. newstatement : tstatementnode;
  107. srsym : tsym;
  108. begin
  109. result:=internalstatements(newstatement);
  110. { call fail helper and exit normal }
  111. if is_class(current_structdef) then
  112. begin
  113. srsym:=search_struct_member(current_structdef,'FREEINSTANCE');
  114. if assigned(srsym) and
  115. (srsym.typ=procsym) then
  116. begin
  117. { if self<>0 and vmt<>0 then freeinstance }
  118. addstatement(newstatement,cifnode.create(
  119. caddnode.create(andn,
  120. caddnode.create(unequaln,
  121. load_self_pointer_node,
  122. cnilnode.create),
  123. caddnode.create(unequaln,
  124. load_vmt_pointer_node,
  125. cnilnode.create)),
  126. ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[]),
  127. nil));
  128. end
  129. else
  130. internalerror(200305108);
  131. end
  132. else
  133. if is_object(current_structdef) then
  134. begin
  135. { parameter 3 : vmt_offset }
  136. { parameter 2 : pointer to vmt }
  137. { parameter 1 : self pointer }
  138. para:=ccallparanode.create(
  139. cordconstnode.create(tobjectdef(current_structdef).vmt_offset,s32inttype,false),
  140. ccallparanode.create(
  141. ctypeconvnode.create_internal(
  142. load_vmt_pointer_node,
  143. voidpointertype),
  144. ccallparanode.create(
  145. ctypeconvnode.create_internal(
  146. load_self_pointer_node,
  147. voidpointertype),
  148. nil)));
  149. addstatement(newstatement,
  150. ccallnode.createintern('fpc_help_fail',para));
  151. end
  152. else
  153. internalerror(200305132);
  154. { self:=nil }
  155. addstatement(newstatement,cassignmentnode.create(
  156. load_self_pointer_node,
  157. cnilnode.create));
  158. { exit }
  159. addstatement(newstatement,cexitnode.create(nil));
  160. end;
  161. class function tnodeutils.initialize_data_node(p:tnode; force: boolean):tnode;
  162. begin
  163. if not assigned(p.resultdef) then
  164. typecheckpass(p);
  165. if is_ansistring(p.resultdef) or
  166. is_wide_or_unicode_string(p.resultdef) or
  167. is_interfacecom_or_dispinterface(p.resultdef) or
  168. is_dynamic_array(p.resultdef) then
  169. begin
  170. result:=cassignmentnode.create(
  171. ctypeconvnode.create_internal(p,voidpointertype),
  172. cnilnode.create
  173. );
  174. end
  175. else if (p.resultdef.typ=variantdef) then
  176. begin
  177. result:=ccallnode.createintern('fpc_variant_init',
  178. ccallparanode.create(
  179. ctypeconvnode.create_internal(p,search_system_type('TVARDATA').typedef),
  180. nil));
  181. end
  182. else
  183. begin
  184. result:=ccallnode.createintern('fpc_initialize',
  185. ccallparanode.create(
  186. caddrnode.create_internal(
  187. crttinode.create(
  188. tstoreddef(p.resultdef),initrtti,rdt_normal)),
  189. ccallparanode.create(
  190. caddrnode.create_internal(p),
  191. nil)));
  192. end;
  193. end;
  194. class function tnodeutils.finalize_data_node(p:tnode):tnode;
  195. var
  196. hs : string;
  197. begin
  198. if not assigned(p.resultdef) then
  199. typecheckpass(p);
  200. { 'decr_ref' suffix is somewhat misleading, all these helpers
  201. set the passed pointer to nil now }
  202. if is_ansistring(p.resultdef) then
  203. hs:='fpc_ansistr_decr_ref'
  204. else if is_widestring(p.resultdef) then
  205. hs:='fpc_widestr_decr_ref'
  206. else if is_unicodestring(p.resultdef) then
  207. hs:='fpc_unicodestr_decr_ref'
  208. else if is_interfacecom_or_dispinterface(p.resultdef) then
  209. hs:='fpc_intf_decr_ref'
  210. else
  211. hs:='';
  212. if hs<>'' then
  213. result:=ccallnode.createintern(hs,
  214. ccallparanode.create(
  215. ctypeconvnode.create_internal(p,voidpointertype),
  216. nil))
  217. else if p.resultdef.typ=variantdef then
  218. begin
  219. result:=ccallnode.createintern('fpc_variant_clear',
  220. ccallparanode.create(
  221. ctypeconvnode.create_internal(p,search_system_type('TVARDATA').typedef),
  222. nil));
  223. end
  224. else
  225. result:=ccallnode.createintern('fpc_finalize',
  226. ccallparanode.create(
  227. caddrnode.create_internal(
  228. crttinode.create(
  229. tstoreddef(p.resultdef),initrtti,rdt_normal)),
  230. ccallparanode.create(
  231. caddrnode.create_internal(p),
  232. nil)));
  233. end;
  234. class function tnodeutils.force_init: boolean;
  235. begin
  236. result:=
  237. (target_info.system in systems_typed_constants_node_init) and
  238. assigned(current_module.tcinitcode);
  239. end;
  240. class function tnodeutils.force_final: boolean;
  241. begin
  242. result:=false;
  243. end;
  244. class procedure tnodeutils.initialize_textrec(p:TObject;statn:pointer);
  245. var
  246. stat: ^tstatementnode absolute statn;
  247. begin
  248. if (tsym(p).typ=staticvarsym) and
  249. (tstaticvarsym(p).vardef.typ=filedef) and
  250. (tfiledef(tstaticvarsym(p).vardef).filetyp=ft_text) and
  251. (tstaticvarsym(p).isoindex<>0) then
  252. begin
  253. addstatement(stat^,ccallnode.createintern('fpc_textinit_iso',
  254. ccallparanode.create(
  255. cordconstnode.create(tstaticvarsym(p).isoindex,uinttype,false),
  256. ccallparanode.create(
  257. cloadnode.create(tstaticvarsym(p),tstaticvarsym(p).Owner),
  258. nil))));
  259. end;
  260. end;
  261. class procedure tnodeutils.finalize_textrec(p:TObject;statn:pointer);
  262. var
  263. stat: ^tstatementnode absolute statn;
  264. begin
  265. if (tsym(p).typ=staticvarsym) and
  266. (tstaticvarsym(p).vardef.typ=filedef) and
  267. (tfiledef(tstaticvarsym(p).vardef).filetyp=ft_text) and
  268. (tstaticvarsym(p).isoindex<>0) then
  269. begin
  270. addstatement(stat^,ccallnode.createintern('fpc_textclose_iso',
  271. ccallparanode.create(
  272. cloadnode.create(tstaticvarsym(p),tstaticvarsym(p).Owner),
  273. nil)));
  274. end;
  275. end;
  276. class function tnodeutils.wrap_proc_body(pd: tprocdef; n: tnode): tnode;
  277. var
  278. stat: tstatementnode;
  279. block: tnode;
  280. psym: tsym;
  281. begin
  282. result:=maybe_insert_trashing(pd,n);
  283. if (m_iso in current_settings.modeswitches) and
  284. (pd.proctypeoption=potype_proginit) then
  285. begin
  286. block:=internalstatements(stat);
  287. pd.localst.SymList.ForEachCall(@initialize_textrec,@stat);
  288. addstatement(stat,result);
  289. pd.localst.SymList.ForEachCall(@finalize_textrec,@stat);
  290. result:=block;
  291. end;
  292. if target_info.system in systems_typed_constants_node_init then
  293. begin
  294. case pd.proctypeoption of
  295. potype_class_constructor:
  296. begin
  297. { even though the initialisation code for typed constants may
  298. not yet be complete at this point (there may be more inside
  299. method definitions coming after this class constructor), the
  300. ones from inside the class definition have already been parsed.
  301. in case of $j-, these are marked "final" in Java and such
  302. static fields must be initialsed in the class constructor
  303. itself -> add them here }
  304. block:=internalstatements(stat);
  305. if assigned(pd.struct.tcinitcode) then
  306. begin
  307. addstatement(stat,pd.struct.tcinitcode);
  308. pd.struct.tcinitcode:=nil;
  309. end;
  310. psym:=tsym(pd.struct.symtable.find('FPC_INIT_TYPED_CONSTS_HELPER'));
  311. if assigned(psym) then
  312. begin
  313. if (psym.typ<>procsym) or
  314. (tprocsym(psym).procdeflist.count<>1) then
  315. internalerror(2011040301);
  316. addstatement(stat,ccallnode.create(nil,tprocsym(psym),
  317. pd.struct.symtable,nil,[]));
  318. end;
  319. addstatement(stat,result);
  320. result:=block
  321. end;
  322. potype_unitinit:
  323. begin
  324. if assigned(current_module.tcinitcode) then
  325. begin
  326. block:=internalstatements(stat);
  327. addstatement(stat,tnode(current_module.tcinitcode));
  328. current_module.tcinitcode:=nil;
  329. addstatement(stat,result);
  330. result:=block;
  331. end;
  332. end;
  333. else case pd.synthetickind of
  334. tsk_tcinit:
  335. begin
  336. if assigned(pd.struct.tcinitcode) then
  337. begin
  338. block:=internalstatements(stat);
  339. addstatement(stat,pd.struct.tcinitcode);
  340. pd.struct.tcinitcode:=nil;
  341. addstatement(stat,result);
  342. result:=block
  343. end
  344. end;
  345. end;
  346. end;
  347. end;
  348. end;
  349. class function tnodeutils.maybe_insert_trashing(pd: tprocdef; n: tnode): tnode;
  350. var
  351. stat: tstatementnode;
  352. begin
  353. result:=n;
  354. if check_insert_trashing(pd) then
  355. begin
  356. result:=internalstatements(stat);
  357. pd.parast.SymList.ForEachCall(@maybe_trash_variable_callback,@stat);
  358. pd.localst.SymList.ForEachCall(@maybe_trash_variable_callback,@stat);
  359. addstatement(stat,n);
  360. end;
  361. end;
  362. class function tnodeutils.check_insert_trashing(pd: tprocdef): boolean;
  363. begin
  364. result:=
  365. (localvartrashing<>-1) and
  366. not(po_assembler in pd.procoptions);
  367. end;
  368. class function tnodeutils.trashable_sym(p: tsym): boolean;
  369. begin
  370. result:=
  371. ((p.typ=localvarsym) or
  372. ((p.typ=paravarsym) and
  373. ((vo_is_funcret in tabstractnormalvarsym(p).varoptions) or
  374. (tabstractnormalvarsym(p).varspez=vs_out)))) and
  375. not (vo_is_default_var in tabstractnormalvarsym(p).varoptions) and
  376. not is_managed_type(tabstractnormalvarsym(p).vardef) and
  377. not assigned(tabstractnormalvarsym(p).defaultconstsym);
  378. end;
  379. class procedure tnodeutils.maybe_trash_variable(var stat: tstatementnode; p: tabstractnormalvarsym; trashn: tnode);
  380. var
  381. size: asizeint;
  382. trashintval: int64;
  383. begin
  384. if trashable_sym(p) then
  385. begin
  386. trashintval:=trashintvalues[localvartrashing];
  387. if (p.vardef.typ=procvardef) and
  388. ([m_tp_procvar,m_mac_procvar]*current_settings.modeswitches<>[]) then
  389. begin
  390. if tprocvardef(p.vardef).is_addressonly then
  391. { in tp/delphi mode, you need @procvar to get at the contents of
  392. a procvar ... }
  393. trashn:=caddrnode.create(trashn)
  394. else
  395. { ... but if it's a procedure of object, that will only return
  396. the procedure address -> cast to tmethod instead }
  397. trashn:=ctypeconvnode.create_explicit(trashn,methodpointertype);
  398. end;
  399. if ((p.typ=localvarsym) and
  400. (not(vo_is_funcret in p.varoptions) or
  401. not is_shortstring(p.vardef))) or
  402. ((p.typ=paravarsym) and
  403. not is_shortstring(p.vardef)) then
  404. begin
  405. size:=p.getsize;
  406. case size of
  407. 0:
  408. begin
  409. { open array -> at least size 1. Can also be zero-sized
  410. record, so check it's actually an array }
  411. if p.vardef.typ=arraydef then
  412. trash_large(stat,trashn,caddnode.create(addn,cinlinenode.create(in_high_x,false,trashn.getcopy),genintconstnode(1)),trashintval)
  413. else
  414. trashn.free;
  415. end;
  416. 1: trash_small(stat,
  417. ctypeconvnode.create_internal(trashn,s8inttype),
  418. genintconstnode(shortint(trashintval)));
  419. 2: trash_small(stat,
  420. ctypeconvnode.create_internal(trashn,s16inttype),
  421. genintconstnode(smallint(trashintval)));
  422. 4: trash_small(stat,
  423. ctypeconvnode.create_internal(trashn,s32inttype),
  424. genintconstnode(longint(trashintval)));
  425. 8: trash_small(stat,
  426. ctypeconvnode.create_internal(trashn,s64inttype),
  427. genintconstnode(int64(trashintval)));
  428. else
  429. trash_large(stat,trashn,genintconstnode(size),trashintval);
  430. end;
  431. end
  432. else
  433. begin
  434. { may be an open string, even if is_open_string() returns false
  435. (for some helpers in the system unit) }
  436. { an open string has at least size 2 }
  437. trash_small(stat,
  438. cvecnode.create(trashn.getcopy,genintconstnode(0)),
  439. cordconstnode.create(tconstexprint(byte(trashintval)),cansichartype,false));
  440. trash_small(stat,
  441. cvecnode.create(trashn,genintconstnode(1)),
  442. cordconstnode.create(tconstexprint(byte(trashintval)),cansichartype,false));
  443. end;
  444. end
  445. else
  446. trashn.free;
  447. end;
  448. class procedure tnodeutils.maybe_trash_variable_callback(p:TObject;statn:pointer);
  449. var
  450. stat: ^tstatementnode absolute statn;
  451. begin
  452. if not(tsym(p).typ in [localvarsym,paravarsym]) then
  453. exit;
  454. maybe_trash_variable(stat^,tabstractnormalvarsym(p),cloadnode.create(tsym(p),tsym(p).owner));
  455. end;
  456. class procedure tnodeutils.trash_small(var stat: tstatementnode; trashn: tnode; trashvaln: tnode);
  457. begin
  458. addstatement(stat,cassignmentnode.create(trashn,trashvaln));
  459. end;
  460. class procedure tnodeutils.trash_large(var stat: tstatementnode; trashn, sizen: tnode; trashintval: int64);
  461. begin
  462. addstatement(stat,ccallnode.createintern('fpc_fillmem',
  463. ccallparanode.Create(cordconstnode.create(tconstexprint(byte(trashintval)),u8inttype,false),
  464. ccallparanode.Create(sizen,
  465. ccallparanode.Create(trashn,nil)))
  466. ));
  467. end;
  468. class procedure tnodeutils.insertbsssym(list: tasmlist; sym: tstaticvarsym; size: asizeint; varalign: shortint);
  469. begin
  470. if sym.globalasmsym then
  471. begin
  472. { on AIX/stabx, we cannot generate debug information that encodes
  473. the address of a global symbol, you need a symbol with the same
  474. name as the identifier -> create an extra *local* symbol.
  475. Moreover, such a local symbol will be removed if it's not
  476. referenced anywhere, so also create a reference }
  477. if (target_dbg.id=dbg_stabx) and
  478. (cs_debuginfo in current_settings.moduleswitches) and
  479. not assigned(current_asmdata.GetAsmSymbol(sym.name)) then
  480. begin
  481. list.concat(tai_symbol.Create(current_asmdata.DefineAsmSymbol(sym.name,AB_LOCAL,AT_DATA),0));
  482. list.concat(tai_directive.Create(asd_reference,sym.name));
  483. end;
  484. list.concat(Tai_datablock.create_global(sym.mangledname,size));
  485. end
  486. else
  487. list.concat(Tai_datablock.create(sym.mangledname,size));
  488. end;
  489. class procedure tnodeutils.insertbssdata(sym: tstaticvarsym);
  490. var
  491. l : asizeint;
  492. varalign : shortint;
  493. storefilepos : tfileposinfo;
  494. list : TAsmList;
  495. sectype : TAsmSectiontype;
  496. begin
  497. storefilepos:=current_filepos;
  498. current_filepos:=sym.fileinfo;
  499. l:=sym.getsize;
  500. varalign:=sym.vardef.alignment;
  501. if (varalign=0) then
  502. varalign:=var_align_size(l)
  503. else
  504. varalign:=var_align(varalign);
  505. if tf_section_threadvars in target_info.flags then
  506. begin
  507. if (vo_is_thread_var in sym.varoptions) then
  508. begin
  509. list:=current_asmdata.asmlists[al_threadvars];
  510. sectype:=sec_threadvar;
  511. end
  512. else
  513. begin
  514. list:=current_asmdata.asmlists[al_globals];
  515. sectype:=sec_bss;
  516. end;
  517. end
  518. else
  519. begin
  520. if (vo_is_thread_var in sym.varoptions) then
  521. begin
  522. inc(l,sizeof(pint));
  523. { it doesn't help to set a higher alignment, as }
  524. { the first sizeof(pint) bytes field will offset }
  525. { everything anyway }
  526. varalign:=sizeof(pint);
  527. end;
  528. list:=current_asmdata.asmlists[al_globals];
  529. sectype:=sec_bss;
  530. end;
  531. maybe_new_object_file(list);
  532. if vo_has_section in sym.varoptions then
  533. new_section(list,sec_user,sym.section,varalign)
  534. else
  535. new_section(list,sectype,lower(sym.mangledname),varalign);
  536. insertbsssym(list,sym,l,varalign);
  537. current_filepos:=storefilepos;
  538. end;
  539. class function tnodeutils.create_main_procdef(const name: string; potype: tproctypeoption; ps: tprocsym): tdef;
  540. var
  541. pd: tprocdef;
  542. begin
  543. if potype<>potype_mainstub then
  544. pd:=cprocdef.create(main_program_level,true)
  545. else
  546. pd:=cprocdef.create(normal_function_level,true);
  547. pd.procsym:=ps;
  548. ps.ProcdefList.Add(pd);
  549. include(pd.procoptions,po_global);
  550. { set procdef options }
  551. pd.proctypeoption:=potype;
  552. pd.proccalloption:=pocall_default;
  553. include(pd.procoptions,po_hascallingconvention);
  554. pd.forwarddef:=false;
  555. { may be required to calculate the mangled name }
  556. add_main_procdef_paras(pd);
  557. pd.setmangledname(name);
  558. { the mainstub is generated via a synthetic proc -> parsed via
  559. psub.read_proc_body() -> that one will insert the mangled name in the
  560. alias names already }
  561. if potype<>potype_mainstub then
  562. pd.aliasnames.insert(pd.mangledname);
  563. result:=pd;
  564. end;
  565. procedure AddToStructInits(p:TObject;arg:pointer);
  566. var
  567. StructList: TFPList absolute arg;
  568. begin
  569. if (tdef(p).typ in [objectdef,recorddef]) and
  570. not (df_generic in tdef(p).defoptions) then
  571. begin
  572. { first add the class... }
  573. if ([oo_has_class_constructor,oo_has_class_destructor] * tabstractrecorddef(p).objectoptions <> []) then
  574. StructList.Add(p);
  575. { ... and then also add all subclasses }
  576. tabstractrecorddef(p).symtable.deflist.foreachcall(@AddToStructInits,arg);
  577. end;
  578. end;
  579. class procedure tnodeutils.InsertInitFinalTable;
  580. var
  581. hp : tused_unit;
  582. unitinits : ttai_typedconstbuilder;
  583. count : aint;
  584. tablecountplaceholder: ttypedconstplaceholder;
  585. procedure write_struct_inits(u: tmodule);
  586. var
  587. i: integer;
  588. structlist: TFPList;
  589. pd: tprocdef;
  590. begin
  591. structlist := TFPList.Create;
  592. if assigned(u.globalsymtable) then
  593. u.globalsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  594. u.localsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  595. { write structures }
  596. for i:=0 to structlist.Count-1 do
  597. begin
  598. pd:=tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_constructor);
  599. if assigned(pd) then
  600. unitinits.emit_procdef_const(pd)
  601. else
  602. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  603. pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_destructor);
  604. if assigned(pd) then
  605. unitinits.emit_procdef_const(pd)
  606. else
  607. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  608. inc(count);
  609. end;
  610. structlist.free;
  611. end;
  612. begin
  613. unitinits:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  614. unitinits.begin_anonymous_record('',default_settings.packrecords,sizeof(pint),
  615. targetinfos[target_info.system]^.alignment.recordalignmin,
  616. targetinfos[target_info.system]^.alignment.maxCrecordalign);
  617. { placeholder for tablecount }
  618. tablecountplaceholder:=unitinits.emit_placeholder(sinttype);
  619. { initcount (initialised at run time }
  620. unitinits.emit_ord_const(0,sinttype);
  621. count:=0;
  622. hp:=tused_unit(usedunits.first);
  623. while assigned(hp) do
  624. begin
  625. { insert class constructors/destructors of the unit }
  626. if (hp.u.flags and uf_classinits) <> 0 then
  627. write_struct_inits(hp.u);
  628. { call the unit init code and make it external }
  629. if (hp.u.flags and (uf_init or uf_finalize))<>0 then
  630. begin
  631. if count=high(aint) then
  632. Message1(cg_f_max_units_reached,tostr(count));
  633. if (hp.u.flags and uf_init)<>0 then
  634. unitinits.emit_tai(
  635. Tai_const.Createname(make_mangledname('INIT$',hp.u.globalsymtable,''),AT_FUNCTION,0),
  636. voidcodepointertype)
  637. else
  638. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  639. if (hp.u.flags and uf_finalize)<>0 then
  640. unitinits.emit_tai(
  641. Tai_const.Createname(make_mangledname('FINALIZE$',hp.u.globalsymtable,''),AT_FUNCTION,0),
  642. voidcodepointertype)
  643. else
  644. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  645. inc(count);
  646. end;
  647. hp:=tused_unit(hp.next);
  648. end;
  649. { insert class constructors/destructor of the program }
  650. if (current_module.flags and uf_classinits) <> 0 then
  651. write_struct_inits(current_module);
  652. { Insert initialization/finalization of the program }
  653. if (current_module.flags and (uf_init or uf_finalize))<>0 then
  654. begin
  655. if (current_module.flags and uf_init)<>0 then
  656. unitinits.emit_tai(
  657. Tai_const.Createname(make_mangledname('INIT$',current_module.localsymtable,''),AT_FUNCTION,0),
  658. voidcodepointertype)
  659. else
  660. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  661. if (current_module.flags and uf_finalize)<>0 then
  662. unitinits.emit_tai(
  663. Tai_const.Createname(make_mangledname('FINALIZE$',current_module.localsymtable,''),AT_FUNCTION,0),
  664. voidcodepointertype)
  665. else
  666. unitinits.emit_tai(Tai_const.Create_nil_codeptr,voidcodepointertype);
  667. inc(count);
  668. end;
  669. { fill in tablecount }
  670. tablecountplaceholder.replace(tai_const.Create_aint(count),sinttype);
  671. tablecountplaceholder.free;
  672. { Add to data segment }
  673. current_asmdata.asmlists[al_globals].concatlist(
  674. unitinits.get_final_asmlist(
  675. current_asmdata.DefineAsmSymbol('INITFINAL',AB_GLOBAL,AT_DATA),
  676. unitinits.end_anonymous_record,
  677. sec_data,'INITFINAL',sizeof(pint)
  678. )
  679. );
  680. unitinits.free;
  681. end;
  682. class procedure tnodeutils.InsertThreadvarTablesTable;
  683. var
  684. hp : tused_unit;
  685. tcb: ttai_typedconstbuilder;
  686. count: longint;
  687. sym: tasmsymbol;
  688. placeholder: ttypedconstplaceholder;
  689. begin
  690. if (tf_section_threadvars in target_info.flags) then
  691. exit;
  692. count:=0;
  693. tcb:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  694. tcb.begin_anonymous_record('',1,sizeof(pint),
  695. targetinfos[target_info.system]^.alignment.recordalignmin,
  696. targetinfos[target_info.system]^.alignment.maxCrecordalign
  697. );
  698. placeholder:=tcb.emit_placeholder(u32inttype);
  699. hp:=tused_unit(usedunits.first);
  700. while assigned(hp) do
  701. begin
  702. if (hp.u.flags and uf_threadvars)=uf_threadvars then
  703. begin
  704. tcb.emit_tai(
  705. tai_const.Createname(make_mangledname('THREADVARLIST',hp.u.globalsymtable,''),0),
  706. voidpointertype);
  707. inc(count);
  708. end;
  709. hp:=tused_unit(hp.next);
  710. end;
  711. { Add program threadvars, if any }
  712. if (current_module.flags and uf_threadvars)=uf_threadvars then
  713. begin
  714. tcb.emit_tai(
  715. Tai_const.Createname(make_mangledname('THREADVARLIST',current_module.localsymtable,''),0),
  716. voidpointertype);
  717. inc(count);
  718. end;
  719. { set the count at the start }
  720. placeholder.replace(tai_const.Create_32bit(count),u32inttype);
  721. placeholder.free;
  722. { insert in data segment }
  723. sym:=current_asmdata.DefineAsmSymbol('FPC_THREADVARTABLES',AB_GLOBAL,AT_DATA);
  724. current_asmdata.asmlists[al_globals].concatlist(
  725. tcb.get_final_asmlist(
  726. sym,tcb.end_anonymous_record,sec_data,'FPC_THREADVARTABLES',sizeof(pint)
  727. )
  728. );
  729. tcb.free;
  730. end;
  731. procedure AddToThreadvarList(p:TObject;arg:pointer);
  732. var
  733. tcb: ttai_typedconstbuilder;
  734. field1, field2: tsym;
  735. begin
  736. if (tsym(p).typ=staticvarsym) and
  737. (vo_is_thread_var in tstaticvarsym(p).varoptions) then
  738. begin
  739. tcb:=ttai_typedconstbuilder(arg);
  740. { address of threadvar }
  741. tcb.emit_tai(tai_const.Createname(tstaticvarsym(p).mangledname,0),
  742. cpointerdef.getreusable(
  743. get_threadvar_record(tstaticvarsym(p).vardef,field1,field2)
  744. )
  745. );
  746. { size of threadvar }
  747. tcb.emit_ord_const(tstaticvarsym(p).getsize,u32inttype);
  748. end;
  749. end;
  750. class procedure tnodeutils.InsertThreadvars;
  751. var
  752. s : string;
  753. tcb: ttai_typedconstbuilder;
  754. sym: tasmsymbol;
  755. tabledef: trecorddef;
  756. begin
  757. if (tf_section_threadvars in target_info.flags) then
  758. exit;
  759. tcb:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  760. tabledef:=tcb.begin_anonymous_record('',1,sizeof(pint),
  761. targetinfos[target_info.system]^.alignment.recordalignmin,
  762. targetinfos[target_info.system]^.alignment.maxCrecordalign);
  763. if assigned(current_module.globalsymtable) then
  764. current_module.globalsymtable.SymList.ForEachCall(@AddToThreadvarList,tcb);
  765. current_module.localsymtable.SymList.ForEachCall(@AddToThreadvarList,tcb);
  766. if trecordsymtable(tabledef.symtable).datasize<>0 then
  767. { terminator }
  768. tcb.emit_tai(tai_const.Create_nil_dataptr,voidpointertype);
  769. tcb.end_anonymous_record;
  770. if trecordsymtable(tabledef.symtable).datasize<>0 then
  771. begin
  772. s:=make_mangledname('THREADVARLIST',current_module.localsymtable,'');
  773. sym:=current_asmdata.DefineAsmSymbol(s,AB_GLOBAL,AT_DATA);
  774. current_asmdata.asmlists[al_globals].concatlist(
  775. tcb.get_final_asmlist(sym,tabledef,sec_data,s,sizeof(pint)));
  776. current_module.flags:=current_module.flags or uf_threadvars;
  777. end;
  778. tcb.Free;
  779. end;
  780. class procedure tnodeutils.InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:cardinal);
  781. var
  782. hp: tused_unit;
  783. tcb: ttai_typedconstbuilder;
  784. countplaceholder: ttypedconstplaceholder;
  785. count: longint;
  786. begin
  787. tcb:=ctai_typedconstbuilder.create([tcalo_make_dead_strippable,tcalo_new_section]);
  788. tcb.begin_anonymous_record('',default_settings.packrecords,sizeof(pint),
  789. targetinfos[target_info.system]^.alignment.recordalignmin,
  790. targetinfos[target_info.system]^.alignment.maxCrecordalign
  791. );
  792. { placeholder for the count }
  793. countplaceholder:=tcb.emit_placeholder(ptruinttype);
  794. count:=0;
  795. hp:=tused_unit(usedunits.first);
  796. while assigned(hp) do
  797. begin
  798. if (hp.u.flags and unitflag)=unitflag then
  799. begin
  800. tcb.emit_tai(
  801. Tai_const.Createname(make_mangledname(prefix,hp.u.globalsymtable,''),0),
  802. voidcodepointertype);
  803. inc(count);
  804. end;
  805. hp:=tused_unit(hp.next);
  806. end;
  807. { Add items from program, if any }
  808. if (current_module.flags and unitflag)=unitflag then
  809. begin
  810. tcb.emit_tai(
  811. Tai_const.Createname(make_mangledname(prefix,current_module.localsymtable,''),0),
  812. voidcodepointertype);
  813. inc(count);
  814. end;
  815. { Insert TableCount at start }
  816. countplaceholder.replace(Tai_const.Create_pint(count),ptruinttype);
  817. countplaceholder.free;
  818. { insert in data segment }
  819. current_asmdata.asmlists[al_globals].concatlist(
  820. tcb.get_final_asmlist(
  821. current_asmdata.DefineAsmSymbol(tablename,AB_GLOBAL,AT_DATA),
  822. tcb.end_anonymous_record,
  823. sec_data,tablename,sizeof(pint)
  824. )
  825. );
  826. tcb.free;
  827. end;
  828. class procedure tnodeutils.InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:cardinal);
  829. var
  830. s: string;
  831. item: TTCInitItem;
  832. begin
  833. item:=TTCInitItem(list.First);
  834. if item=nil then
  835. exit;
  836. s:=make_mangledname(prefix,current_module.localsymtable,'');
  837. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  838. new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
  839. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  840. repeat
  841. { optimize away unused local/static symbols }
  842. if (item.sym.refs>0) or (item.sym.owner.symtabletype=globalsymtable) then
  843. begin
  844. { address to initialize }
  845. current_asmdata.asmlists[al_globals].concat(Tai_const.createname(item.sym.mangledname, item.offset));
  846. { value with which to initialize }
  847. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(item.datalabel));
  848. end;
  849. item:=TTCInitItem(item.Next);
  850. until item=nil;
  851. { end-of-list marker }
  852. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  853. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
  854. current_module.flags:=current_module.flags or unitflag;
  855. end;
  856. class procedure tnodeutils.InsertWideInits;
  857. begin
  858. InsertRuntimeInits('WIDEINITS',current_asmdata.WideInits,uf_wideinits);
  859. end;
  860. class procedure tnodeutils.InsertResStrInits;
  861. begin
  862. InsertRuntimeInits('RESSTRINITS',current_asmdata.ResStrInits,uf_resstrinits);
  863. end;
  864. class procedure tnodeutils.InsertWideInitsTablesTable;
  865. begin
  866. InsertRuntimeInitsTablesTable('WIDEINITS','FPC_WIDEINITTABLES',uf_wideinits);
  867. end;
  868. class procedure tnodeutils.InsertResStrTablesTable;
  869. begin
  870. InsertRuntimeInitsTablesTable('RESSTRINITS','FPC_RESSTRINITTABLES',uf_resstrinits);
  871. end;
  872. class procedure tnodeutils.InsertResourceTablesTable;
  873. var
  874. hp : tmodule;
  875. ResourceStringTables : tasmlist;
  876. count : longint;
  877. begin
  878. ResourceStringTables:=tasmlist.Create;
  879. count:=0;
  880. hp:=tmodule(loaded_units.first);
  881. while assigned(hp) do
  882. begin
  883. If (hp.flags and uf_has_resourcestrings)=uf_has_resourcestrings then
  884. begin
  885. ResourceStringTables.concat(Tai_const.Createname(make_mangledname('RESSTR',hp.localsymtable,'START'),AT_DATA,0));
  886. ResourceStringTables.concat(Tai_const.Createname(make_mangledname('RESSTR',hp.localsymtable,'END'),AT_DATA,0));
  887. inc(count);
  888. end;
  889. hp:=tmodule(hp.next);
  890. end;
  891. { Insert TableCount at start }
  892. ResourceStringTables.insert(Tai_const.Create_pint(count));
  893. { Add to data segment }
  894. maybe_new_object_file(current_asmdata.AsmLists[al_globals]);
  895. new_section(current_asmdata.AsmLists[al_globals],sec_data,'FPC_RESOURCESTRINGTABLES',const_align(sizeof(pint)));
  896. current_asmdata.AsmLists[al_globals].concat(Tai_symbol.Createname_global('FPC_RESOURCESTRINGTABLES',AT_DATA,0));
  897. current_asmdata.AsmLists[al_globals].concatlist(ResourceStringTables);
  898. current_asmdata.AsmLists[al_globals].concat(Tai_symbol_end.Createname('FPC_RESOURCESTRINGTABLES'));
  899. ResourceStringTables.free;
  900. end;
  901. class procedure tnodeutils.InsertResourceInfo(ResourcesUsed: boolean);
  902. var
  903. ResourceInfo : TAsmList;
  904. begin
  905. if (target_res.id in [res_elf,res_macho,res_xcoff]) then
  906. begin
  907. ResourceInfo:=current_asmdata.asmlists[al_globals];
  908. maybe_new_object_file(ResourceInfo);
  909. new_section(ResourceInfo,sec_data,'FPC_RESLOCATION',sizeof(aint));
  910. ResourceInfo.concat(Tai_symbol.Createname_global('FPC_RESLOCATION',AT_DATA,0));
  911. if ResourcesUsed then
  912. { Valid pointer to resource information }
  913. ResourceInfo.concat(Tai_const.Createname('FPC_RESSYMBOL',0))
  914. else
  915. { Nil pointer to resource information }
  916. {$IFNDEF cpu64bitaddr}
  917. ResourceInfo.Concat(Tai_const.Create_32bit(0));
  918. {$ELSE}
  919. ResourceInfo.Concat(Tai_const.Create_64bit(0));
  920. {$ENDIF}
  921. end;
  922. end;
  923. class procedure tnodeutils.InsertMemorySizes;
  924. {$IFDEF POWERPC}
  925. var
  926. stkcookie: string;
  927. {$ENDIF POWERPC}
  928. begin
  929. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  930. { Insert Ident of the compiler in the .fpc.version section }
  931. new_section(current_asmdata.asmlists[al_globals],sec_fpc,'version',const_align(32));
  932. current_asmdata.asmlists[al_globals].concat(Tai_string.Create('FPC '+full_version_string+
  933. ' ['+date_string+'] for '+target_cpu_string+' - '+target_info.shortname));
  934. if not(tf_no_generic_stackcheck in target_info.flags) then
  935. begin
  936. { stacksize can be specified and is now simulated }
  937. new_section(current_asmdata.asmlists[al_globals],sec_data,'__stklen', sizeof(pint));
  938. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__stklen',AT_DATA,sizeof(pint)));
  939. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(stacksize));
  940. end;
  941. {$IFDEF POWERPC}
  942. { AmigaOS4 "stack cookie" support }
  943. if ( target_info.system = system_powerpc_amiga ) then
  944. begin
  945. { this symbol is needed to ignite powerpc amigaos' }
  946. { stack allocation magic for us with the given stack size. }
  947. { note: won't work for m68k amigaos or morphos. (KB) }
  948. str(stacksize,stkcookie);
  949. stkcookie:='$STACK: '+stkcookie+#0;
  950. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  951. new_section(current_asmdata.asmlists[al_globals],sec_data,'__stack_cookie',length(stkcookie));
  952. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__stack_cookie',AT_DATA,length(stkcookie)));
  953. current_asmdata.asmlists[al_globals].concat(Tai_string.Create(stkcookie));
  954. end;
  955. {$ENDIF POWERPC}
  956. { Initial heapsize }
  957. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  958. new_section(current_asmdata.asmlists[al_globals],sec_data,'__heapsize',const_align(sizeof(pint)));
  959. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__heapsize',AT_DATA,sizeof(pint)));
  960. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(heapsize));
  961. { allocate an initial heap on embedded systems }
  962. if target_info.system in systems_embedded then
  963. begin
  964. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  965. new_section(current_asmdata.asmlists[al_globals],sec_bss,'__fpc_initialheap',current_settings.alignment.varalignmax);
  966. current_asmdata.asmlists[al_globals].concat(tai_datablock.Create_global('__fpc_initialheap',heapsize));
  967. end;
  968. { Valgrind usage }
  969. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  970. new_section(current_asmdata.asmlists[al_globals],sec_data,'__fpc_valgrind',const_align(sizeof(pint)));
  971. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__fpc_valgrind',AT_DATA,sizeof(boolean)));
  972. current_asmdata.asmlists[al_globals].concat(Tai_const.create_8bit(byte(cs_gdb_valgrind in current_settings.globalswitches)));
  973. end;
  974. class procedure tnodeutils.InsertObjectInfo;
  975. begin
  976. { don't do anything by default }
  977. end;
  978. class procedure tnodeutils.add_main_procdef_paras(pd: tdef);
  979. var
  980. pvs: tparavarsym;
  981. begin
  982. { stub for calling FPC_SYSTEMMAIN from the C main -> add argc/argv/argp }
  983. if (tprocdef(pd).proctypeoption=potype_mainstub) and
  984. (target_info.system in (systems_darwin+[system_powerpc_macos]+systems_aix)) then
  985. begin
  986. pvs:=cparavarsym.create('ARGC',1,vs_const,s32inttype,[]);
  987. tprocdef(pd).parast.insert(pvs);
  988. pvs:=cparavarsym.create('ARGV',2,vs_const,cpointerdef.getreusable(charpointertype),[]);
  989. tprocdef(pd).parast.insert(pvs);
  990. pvs:=cparavarsym.create('ARGP',3,vs_const,cpointerdef.getreusable(charpointertype),[]);
  991. tprocdef(pd).parast.insert(pvs);
  992. tprocdef(pd).calcparas;
  993. end;
  994. end;
  995. end.