ngenutil.pas 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951
  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); virtual;
  63. public
  64. class procedure insertbssdata(sym : tstaticvarsym); virtual;
  65. class function create_main_procdef(const name: string; potype:tproctypeoption; ps: tprocsym):tdef; virtual;
  66. class procedure InsertInitFinalTable; virtual;
  67. protected
  68. class procedure InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:cardinal); virtual;
  69. class procedure InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:cardinal); virtual;
  70. public
  71. class procedure InsertThreadvarTablesTable; virtual;
  72. class procedure InsertThreadvars; virtual;
  73. class procedure InsertWideInitsTablesTable; virtual;
  74. class procedure InsertWideInits; virtual;
  75. class procedure InsertResStrInits; virtual;
  76. class procedure InsertResStrTablesTable; virtual;
  77. class procedure InsertResourceTablesTable; virtual;
  78. class procedure InsertResourceInfo(ResourcesUsed : boolean); virtual;
  79. class procedure InsertMemorySizes; virtual;
  80. strict protected
  81. class procedure add_main_procdef_paras(pd: tdef); virtual;
  82. end;
  83. tnodeutilsclass = class of tnodeutils;
  84. const
  85. cnodeutils: tnodeutilsclass = tnodeutils;
  86. implementation
  87. uses
  88. verbose,version,globals,cutils,constexp,
  89. scanner,systems,procinfo,fmodule,
  90. aasmbase,aasmtai,
  91. symbase,symtable,defutil,
  92. nadd,ncal,ncnv,ncon,nflw,ninl,nld,nmem,nobj,nutils,
  93. ppu,
  94. pass_1;
  95. class function tnodeutils.call_fail_node:tnode;
  96. var
  97. para : tcallparanode;
  98. newstatement : tstatementnode;
  99. srsym : tsym;
  100. begin
  101. result:=internalstatements(newstatement);
  102. { call fail helper and exit normal }
  103. if is_class(current_structdef) then
  104. begin
  105. srsym:=search_struct_member(current_structdef,'FREEINSTANCE');
  106. if assigned(srsym) and
  107. (srsym.typ=procsym) then
  108. begin
  109. { if self<>0 and vmt<>0 then freeinstance }
  110. addstatement(newstatement,cifnode.create(
  111. caddnode.create(andn,
  112. caddnode.create(unequaln,
  113. load_self_pointer_node,
  114. cnilnode.create),
  115. caddnode.create(unequaln,
  116. load_vmt_pointer_node,
  117. cnilnode.create)),
  118. ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[]),
  119. nil));
  120. end
  121. else
  122. internalerror(200305108);
  123. end
  124. else
  125. if is_object(current_structdef) then
  126. begin
  127. { parameter 3 : vmt_offset }
  128. { parameter 2 : pointer to vmt }
  129. { parameter 1 : self pointer }
  130. para:=ccallparanode.create(
  131. cordconstnode.create(tobjectdef(current_structdef).vmt_offset,s32inttype,false),
  132. ccallparanode.create(
  133. ctypeconvnode.create_internal(
  134. load_vmt_pointer_node,
  135. voidpointertype),
  136. ccallparanode.create(
  137. ctypeconvnode.create_internal(
  138. load_self_pointer_node,
  139. voidpointertype),
  140. nil)));
  141. addstatement(newstatement,
  142. ccallnode.createintern('fpc_help_fail',para));
  143. end
  144. else
  145. internalerror(200305132);
  146. { self:=nil }
  147. addstatement(newstatement,cassignmentnode.create(
  148. load_self_pointer_node,
  149. cnilnode.create));
  150. { exit }
  151. addstatement(newstatement,cexitnode.create(nil));
  152. end;
  153. class function tnodeutils.initialize_data_node(p:tnode; force: boolean):tnode;
  154. begin
  155. if not assigned(p.resultdef) then
  156. typecheckpass(p);
  157. if is_ansistring(p.resultdef) or
  158. is_wide_or_unicode_string(p.resultdef) or
  159. is_interfacecom_or_dispinterface(p.resultdef) or
  160. is_dynamic_array(p.resultdef) then
  161. begin
  162. result:=cassignmentnode.create(
  163. ctypeconvnode.create_internal(p,voidpointertype),
  164. cnilnode.create
  165. );
  166. end
  167. else if (p.resultdef.typ=variantdef) then
  168. begin
  169. result:=ccallnode.createintern('fpc_variant_init',
  170. ccallparanode.create(
  171. ctypeconvnode.create_internal(p,search_system_type('TVARDATA').typedef),
  172. nil));
  173. end
  174. else
  175. begin
  176. result:=ccallnode.createintern('fpc_initialize',
  177. ccallparanode.create(
  178. caddrnode.create_internal(
  179. crttinode.create(
  180. tstoreddef(p.resultdef),initrtti,rdt_normal)),
  181. ccallparanode.create(
  182. caddrnode.create_internal(p),
  183. nil)));
  184. end;
  185. end;
  186. class function tnodeutils.finalize_data_node(p:tnode):tnode;
  187. var
  188. hs : string;
  189. begin
  190. if not assigned(p.resultdef) then
  191. typecheckpass(p);
  192. { 'decr_ref' suffix is somewhat misleading, all these helpers
  193. set the passed pointer to nil now }
  194. if is_ansistring(p.resultdef) then
  195. hs:='fpc_ansistr_decr_ref'
  196. else if is_widestring(p.resultdef) then
  197. hs:='fpc_widestr_decr_ref'
  198. else if is_unicodestring(p.resultdef) then
  199. hs:='fpc_unicodestr_decr_ref'
  200. else if is_interfacecom_or_dispinterface(p.resultdef) then
  201. hs:='fpc_intf_decr_ref'
  202. else
  203. hs:='';
  204. if hs<>'' then
  205. result:=ccallnode.createintern(hs,
  206. ccallparanode.create(
  207. ctypeconvnode.create_internal(p,voidpointertype),
  208. nil))
  209. else if p.resultdef.typ=variantdef then
  210. begin
  211. result:=ccallnode.createintern('fpc_variant_clear',
  212. ccallparanode.create(
  213. ctypeconvnode.create_internal(p,search_system_type('TVARDATA').typedef),
  214. nil));
  215. end
  216. else
  217. result:=ccallnode.createintern('fpc_finalize',
  218. ccallparanode.create(
  219. caddrnode.create_internal(
  220. crttinode.create(
  221. tstoreddef(p.resultdef),initrtti,rdt_normal)),
  222. ccallparanode.create(
  223. caddrnode.create_internal(p),
  224. nil)));
  225. end;
  226. class function tnodeutils.force_init: boolean;
  227. begin
  228. result:=
  229. (target_info.system in systems_typed_constants_node_init) and
  230. assigned(current_module.tcinitcode);
  231. end;
  232. class function tnodeutils.force_final: boolean;
  233. begin
  234. result:=false;
  235. end;
  236. class function tnodeutils.wrap_proc_body(pd: tprocdef; n: tnode): tnode;
  237. var
  238. stat: tstatementnode;
  239. block: tnode;
  240. psym: tsym;
  241. begin
  242. result:=maybe_insert_trashing(pd,n);
  243. if target_info.system in systems_typed_constants_node_init then
  244. begin
  245. case pd.proctypeoption of
  246. potype_class_constructor:
  247. begin
  248. { even though the initialisation code for typed constants may
  249. not yet be complete at this point (there may be more inside
  250. method definitions coming after this class constructor), the
  251. ones from inside the class definition have already been parsed.
  252. in case of $j-, these are marked "final" in Java and such
  253. static fields must be initialsed in the class constructor
  254. itself -> add them here }
  255. block:=internalstatements(stat);
  256. if assigned(pd.struct.tcinitcode) then
  257. begin
  258. addstatement(stat,pd.struct.tcinitcode);
  259. pd.struct.tcinitcode:=nil;
  260. end;
  261. psym:=tsym(pd.struct.symtable.find('FPC_INIT_TYPED_CONSTS_HELPER'));
  262. if assigned(psym) then
  263. begin
  264. if (psym.typ<>procsym) or
  265. (tprocsym(psym).procdeflist.count<>1) then
  266. internalerror(2011040301);
  267. addstatement(stat,ccallnode.create(nil,tprocsym(psym),
  268. pd.struct.symtable,nil,[]));
  269. end;
  270. addstatement(stat,result);
  271. result:=block
  272. end;
  273. potype_unitinit:
  274. begin
  275. if assigned(current_module.tcinitcode) then
  276. begin
  277. block:=internalstatements(stat);
  278. addstatement(stat,tnode(current_module.tcinitcode));
  279. current_module.tcinitcode:=nil;
  280. addstatement(stat,result);
  281. result:=block;
  282. end;
  283. end;
  284. else case pd.synthetickind of
  285. tsk_tcinit:
  286. begin
  287. if assigned(pd.struct.tcinitcode) then
  288. begin
  289. block:=internalstatements(stat);
  290. addstatement(stat,pd.struct.tcinitcode);
  291. pd.struct.tcinitcode:=nil;
  292. addstatement(stat,result);
  293. result:=block
  294. end
  295. end;
  296. end;
  297. end;
  298. end;
  299. end;
  300. class function tnodeutils.maybe_insert_trashing(pd: tprocdef; n: tnode): tnode;
  301. var
  302. stat: tstatementnode;
  303. begin
  304. result:=n;
  305. if check_insert_trashing(pd) then
  306. begin
  307. result:=internalstatements(stat);
  308. pd.parast.SymList.ForEachCall(@maybe_trash_variable_callback,@stat);
  309. pd.localst.SymList.ForEachCall(@maybe_trash_variable_callback,@stat);
  310. addstatement(stat,n);
  311. end;
  312. end;
  313. class function tnodeutils.check_insert_trashing(pd: tprocdef): boolean;
  314. begin
  315. result:=
  316. (localvartrashing<>-1) and
  317. not(po_assembler in pd.procoptions);
  318. end;
  319. class function tnodeutils.trashable_sym(p: tsym): boolean;
  320. begin
  321. result:=
  322. ((p.typ=localvarsym) or
  323. ((p.typ=paravarsym) and
  324. ((vo_is_funcret in tabstractnormalvarsym(p).varoptions) or
  325. (tabstractnormalvarsym(p).varspez=vs_out)))) and
  326. not is_managed_type(tabstractnormalvarsym(p).vardef) and
  327. not assigned(tabstractnormalvarsym(p).defaultconstsym);
  328. end;
  329. class procedure tnodeutils.maybe_trash_variable(var stat: tstatementnode; p: tabstractnormalvarsym; trashn: tnode);
  330. var
  331. size: asizeint;
  332. trashintval: int64;
  333. begin
  334. if trashable_sym(p) then
  335. begin
  336. trashintval:=trashintvalues[localvartrashing];
  337. if (p.vardef.typ=procvardef) and
  338. ([m_tp_procvar,m_mac_procvar]*current_settings.modeswitches<>[]) then
  339. begin
  340. if tprocvardef(p.vardef).is_addressonly then
  341. { in tp/delphi mode, you need @procvar to get at the contents of
  342. a procvar ... }
  343. trashn:=caddrnode.create(trashn)
  344. else
  345. { ... but if it's a procedure of object, that will only return
  346. the procedure address -> cast to tmethod instead }
  347. trashn:=ctypeconvnode.create_explicit(trashn,methodpointertype);
  348. end;
  349. if ((p.typ=localvarsym) and
  350. (not(vo_is_funcret in p.varoptions) or
  351. not is_shortstring(p.vardef))) or
  352. ((p.typ=paravarsym) and
  353. not is_shortstring(p.vardef)) then
  354. begin
  355. size:=p.getsize;
  356. case size of
  357. 0:
  358. begin
  359. { open array -> at least size 1. Can also be zero-sized
  360. record, so check it's actually an array }
  361. if p.vardef.typ=arraydef then
  362. trash_large(stat,trashn,caddnode.create(addn,cinlinenode.create(in_high_x,false,trashn.getcopy),genintconstnode(1)),trashintval)
  363. else
  364. trashn.free;
  365. end;
  366. 1: trash_small(stat,
  367. ctypeconvnode.create_internal(trashn,s8inttype),
  368. genintconstnode(shortint(trashintval)));
  369. 2: trash_small(stat,
  370. ctypeconvnode.create_internal(trashn,s16inttype),
  371. genintconstnode(smallint(trashintval)));
  372. 4: trash_small(stat,
  373. ctypeconvnode.create_internal(trashn,s32inttype),
  374. genintconstnode(longint(trashintval)));
  375. 8: trash_small(stat,
  376. ctypeconvnode.create_internal(trashn,s64inttype),
  377. genintconstnode(int64(trashintval)));
  378. else
  379. trash_large(stat,trashn,genintconstnode(size),trashintval);
  380. end;
  381. end
  382. else
  383. begin
  384. { may be an open string, even if is_open_string() returns false
  385. (for some helpers in the system unit) }
  386. { an open string has at least size 2 }
  387. trash_small(stat,
  388. cvecnode.create(trashn.getcopy,genintconstnode(0)),
  389. cordconstnode.create(tconstexprint(byte(trashintval)),cansichartype,false));
  390. trash_small(stat,
  391. cvecnode.create(trashn,genintconstnode(1)),
  392. cordconstnode.create(tconstexprint(byte(trashintval)),cansichartype,false));
  393. end;
  394. end
  395. else
  396. trashn.free;
  397. end;
  398. class procedure tnodeutils.maybe_trash_variable_callback(p:TObject;statn:pointer);
  399. var
  400. stat: ^tstatementnode absolute statn;
  401. begin
  402. if not(tsym(p).typ in [localvarsym,paravarsym]) then
  403. exit;
  404. maybe_trash_variable(stat^,tabstractnormalvarsym(p),cloadnode.create(tsym(p),tsym(p).owner));
  405. end;
  406. class procedure tnodeutils.trash_small(var stat: tstatementnode; trashn: tnode; trashvaln: tnode);
  407. begin
  408. addstatement(stat,cassignmentnode.create(trashn,trashvaln));
  409. end;
  410. class procedure tnodeutils.trash_large(var stat: tstatementnode; trashn, sizen: tnode; trashintval: int64);
  411. begin
  412. addstatement(stat,ccallnode.createintern('fpc_fillmem',
  413. ccallparanode.Create(cordconstnode.create(tconstexprint(byte(trashintval)),u8inttype,false),
  414. ccallparanode.Create(sizen,
  415. ccallparanode.Create(trashn,nil)))
  416. ));
  417. end;
  418. class procedure tnodeutils.insertbsssym(list: tasmlist; sym: tstaticvarsym; size: asizeint);
  419. begin
  420. if sym.globalasmsym then
  421. begin
  422. { on AIX/stabx, we cannot generate debug information that encodes
  423. the address of a global symbol, you need a symbol with the same
  424. name as the identifier -> create an extra *local* symbol.
  425. Moreover, such a local symbol will be removed if it's not
  426. referenced anywhere, so also create a reference }
  427. if (target_dbg.id=dbg_stabx) and
  428. (cs_debuginfo in current_settings.moduleswitches) and
  429. not assigned(current_asmdata.GetAsmSymbol(sym.name)) then
  430. begin
  431. list.concat(tai_symbol.Create(current_asmdata.DefineAsmSymbol(sym.name,AB_LOCAL,AT_DATA),0));
  432. list.concat(tai_directive.Create(asd_reference,sym.name));
  433. end;
  434. list.concat(Tai_datablock.create_global(sym.mangledname,size));
  435. end
  436. else
  437. list.concat(Tai_datablock.create(sym.mangledname,size));
  438. end;
  439. class procedure tnodeutils.insertbssdata(sym: tstaticvarsym);
  440. var
  441. l : asizeint;
  442. varalign : shortint;
  443. storefilepos : tfileposinfo;
  444. list : TAsmList;
  445. sectype : TAsmSectiontype;
  446. begin
  447. storefilepos:=current_filepos;
  448. current_filepos:=sym.fileinfo;
  449. l:=sym.getsize;
  450. varalign:=sym.vardef.alignment;
  451. if (varalign=0) then
  452. varalign:=var_align_size(l)
  453. else
  454. varalign:=var_align(varalign);
  455. if tf_section_threadvars in target_info.flags then
  456. begin
  457. if (vo_is_thread_var in sym.varoptions) then
  458. begin
  459. list:=current_asmdata.asmlists[al_threadvars];
  460. sectype:=sec_threadvar;
  461. end
  462. else
  463. begin
  464. list:=current_asmdata.asmlists[al_globals];
  465. sectype:=sec_bss;
  466. end;
  467. end
  468. else
  469. begin
  470. if (vo_is_thread_var in sym.varoptions) then
  471. begin
  472. inc(l,sizeof(pint));
  473. { it doesn't help to set a higher alignment, as }
  474. { the first sizeof(pint) bytes field will offset }
  475. { everything anyway }
  476. varalign:=sizeof(pint);
  477. end;
  478. list:=current_asmdata.asmlists[al_globals];
  479. sectype:=sec_bss;
  480. end;
  481. maybe_new_object_file(list);
  482. if vo_has_section in sym.varoptions then
  483. new_section(list,sec_user,sym.section,varalign)
  484. else
  485. new_section(list,sectype,lower(sym.mangledname),varalign);
  486. insertbsssym(list,sym,l);
  487. current_filepos:=storefilepos;
  488. end;
  489. class function tnodeutils.create_main_procdef(const name: string; potype: tproctypeoption; ps: tprocsym): tdef;
  490. var
  491. pd: tprocdef;
  492. begin
  493. pd:=tprocdef.create(main_program_level);
  494. pd.procsym:=ps;
  495. ps.ProcdefList.Add(pd);
  496. include(pd.procoptions,po_global);
  497. { set procdef options }
  498. pd.proctypeoption:=potype;
  499. pd.proccalloption:=pocall_default;
  500. include(pd.procoptions,po_hascallingconvention);
  501. pd.forwarddef:=false;
  502. { may be required to calculate the mangled name }
  503. add_main_procdef_paras(pd);
  504. pd.setmangledname(name);
  505. pd.aliasnames.insert(pd.mangledname);
  506. result:=pd;
  507. end;
  508. procedure AddToStructInits(p:TObject;arg:pointer);
  509. var
  510. StructList: TFPList absolute arg;
  511. begin
  512. if (tdef(p).typ in [objectdef,recorddef]) and
  513. not (df_generic in tdef(p).defoptions) and
  514. ([oo_has_class_constructor,oo_has_class_destructor] * tabstractrecorddef(p).objectoptions <> []) then
  515. StructList.Add(p);
  516. end;
  517. class procedure tnodeutils.InsertInitFinalTable;
  518. var
  519. hp : tused_unit;
  520. unitinits : TAsmList;
  521. count : longint;
  522. procedure write_struct_inits(u: tmodule);
  523. var
  524. i: integer;
  525. structlist: TFPList;
  526. pd: tprocdef;
  527. begin
  528. structlist := TFPList.Create;
  529. if assigned(u.globalsymtable) then
  530. u.globalsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  531. u.localsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  532. { write structures }
  533. for i := 0 to structlist.Count - 1 do
  534. begin
  535. pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_constructor);
  536. if assigned(pd) then
  537. unitinits.concat(Tai_const.Createname(pd.mangledname,AT_FUNCTION,0))
  538. else
  539. unitinits.concat(Tai_const.Create_nil_codeptr);
  540. pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_destructor);
  541. if assigned(pd) then
  542. unitinits.concat(Tai_const.Createname(pd.mangledname,AT_FUNCTION,0))
  543. else
  544. unitinits.concat(Tai_const.Create_nil_codeptr);
  545. inc(count);
  546. end;
  547. structlist.free;
  548. end;
  549. begin
  550. unitinits:=TAsmList.Create;
  551. count:=0;
  552. hp:=tused_unit(usedunits.first);
  553. while assigned(hp) do
  554. begin
  555. { insert class constructors/destructors of the unit }
  556. if (hp.u.flags and uf_classinits) <> 0 then
  557. write_struct_inits(hp.u);
  558. { call the unit init code and make it external }
  559. if (hp.u.flags and (uf_init or uf_finalize))<>0 then
  560. begin
  561. if (hp.u.flags and uf_init)<>0 then
  562. unitinits.concat(Tai_const.Createname(make_mangledname('INIT$',hp.u.globalsymtable,''),AT_FUNCTION,0))
  563. else
  564. unitinits.concat(Tai_const.Create_nil_codeptr);
  565. if (hp.u.flags and uf_finalize)<>0 then
  566. unitinits.concat(Tai_const.Createname(make_mangledname('FINALIZE$',hp.u.globalsymtable,''),AT_FUNCTION,0))
  567. else
  568. unitinits.concat(Tai_const.Create_nil_codeptr);
  569. inc(count);
  570. end;
  571. hp:=tused_unit(hp.next);
  572. end;
  573. { insert class constructors/destructor of the program }
  574. if (current_module.flags and uf_classinits) <> 0 then
  575. write_struct_inits(current_module);
  576. { Insert initialization/finalization of the program }
  577. if (current_module.flags and (uf_init or uf_finalize))<>0 then
  578. begin
  579. if (current_module.flags and uf_init)<>0 then
  580. unitinits.concat(Tai_const.Createname(make_mangledname('INIT$',current_module.localsymtable,''),AT_FUNCTION,0))
  581. else
  582. unitinits.concat(Tai_const.Create_nil_codeptr);
  583. if (current_module.flags and uf_finalize)<>0 then
  584. unitinits.concat(Tai_const.Createname(make_mangledname('FINALIZE$',current_module.localsymtable,''),AT_FUNCTION,0))
  585. else
  586. unitinits.concat(Tai_const.Create_nil_codeptr);
  587. inc(count);
  588. end;
  589. { Insert TableCount,InitCount at start }
  590. unitinits.insert(Tai_const.Create_32bit(0));
  591. unitinits.insert(Tai_const.Create_32bit(count));
  592. { Add to data segment }
  593. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  594. new_section(current_asmdata.asmlists[al_globals],sec_data,'INITFINAL',sizeof(pint));
  595. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('INITFINAL',AT_DATA,0));
  596. current_asmdata.asmlists[al_globals].concatlist(unitinits);
  597. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname('INITFINAL'));
  598. unitinits.free;
  599. end;
  600. class procedure tnodeutils.InsertThreadvarTablesTable;
  601. var
  602. hp : tused_unit;
  603. ltvTables : TAsmList;
  604. count : longint;
  605. begin
  606. if (tf_section_threadvars in target_info.flags) then
  607. exit;
  608. ltvTables:=TAsmList.Create;
  609. count:=0;
  610. hp:=tused_unit(usedunits.first);
  611. while assigned(hp) do
  612. begin
  613. If (hp.u.flags and uf_threadvars)=uf_threadvars then
  614. begin
  615. ltvTables.concat(Tai_const.Createname(make_mangledname('THREADVARLIST',hp.u.globalsymtable,''),0));
  616. inc(count);
  617. end;
  618. hp:=tused_unit(hp.next);
  619. end;
  620. { Add program threadvars, if any }
  621. If (current_module.flags and uf_threadvars)=uf_threadvars then
  622. begin
  623. ltvTables.concat(Tai_const.Createname(make_mangledname('THREADVARLIST',current_module.localsymtable,''),0));
  624. inc(count);
  625. end;
  626. { Insert TableCount at start }
  627. ltvTables.insert(Tai_const.Create_32bit(count));
  628. { insert in data segment }
  629. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  630. new_section(current_asmdata.asmlists[al_globals],sec_data,'FPC_THREADVARTABLES',sizeof(pint));
  631. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('FPC_THREADVARTABLES',AT_DATA,0));
  632. current_asmdata.asmlists[al_globals].concatlist(ltvTables);
  633. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname('FPC_THREADVARTABLES'));
  634. ltvTables.free;
  635. end;
  636. procedure AddToThreadvarList(p:TObject;arg:pointer);
  637. var
  638. ltvTable : TAsmList;
  639. begin
  640. ltvTable:=TAsmList(arg);
  641. if (tsym(p).typ=staticvarsym) and
  642. (vo_is_thread_var in tstaticvarsym(p).varoptions) then
  643. begin
  644. { address of threadvar }
  645. ltvTable.concat(tai_const.Createname(tstaticvarsym(p).mangledname,0));
  646. { size of threadvar }
  647. ltvTable.concat(tai_const.create_32bit(tstaticvarsym(p).getsize));
  648. end;
  649. end;
  650. class procedure tnodeutils.InsertThreadvars;
  651. var
  652. s : string;
  653. ltvTable : TAsmList;
  654. begin
  655. if (tf_section_threadvars in target_info.flags) then
  656. exit;
  657. ltvTable:=TAsmList.create;
  658. if assigned(current_module.globalsymtable) then
  659. current_module.globalsymtable.SymList.ForEachCall(@AddToThreadvarList,ltvTable);
  660. current_module.localsymtable.SymList.ForEachCall(@AddToThreadvarList,ltvTable);
  661. if not ltvTable.Empty then
  662. begin
  663. s:=make_mangledname('THREADVARLIST',current_module.localsymtable,'');
  664. { end of the list marker }
  665. ltvTable.concat(tai_const.create_sym(nil));
  666. { add to datasegment }
  667. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  668. new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
  669. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  670. current_asmdata.asmlists[al_globals].concatlist(ltvTable);
  671. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
  672. current_module.flags:=current_module.flags or uf_threadvars;
  673. end;
  674. ltvTable.Free;
  675. end;
  676. class procedure tnodeutils.InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:cardinal);
  677. var
  678. hp: tused_unit;
  679. hlist: TAsmList;
  680. count: longint;
  681. begin
  682. hlist:=TAsmList.Create;
  683. count:=0;
  684. hp:=tused_unit(usedunits.first);
  685. while assigned(hp) do
  686. begin
  687. if (hp.u.flags and unitflag)=unitflag then
  688. begin
  689. hlist.concat(Tai_const.Createname(make_mangledname(prefix,hp.u.globalsymtable,''),0));
  690. inc(count);
  691. end;
  692. hp:=tused_unit(hp.next);
  693. end;
  694. { Add items from program, if any }
  695. if (current_module.flags and unitflag)=unitflag then
  696. begin
  697. hlist.concat(Tai_const.Createname(make_mangledname(prefix,current_module.localsymtable,''),0));
  698. inc(count);
  699. end;
  700. { Insert TableCount at start }
  701. hlist.insert(Tai_const.Create_32bit(count));
  702. { insert in data segment }
  703. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  704. new_section(current_asmdata.asmlists[al_globals],sec_data,tablename,sizeof(pint));
  705. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(tablename,AT_DATA,0));
  706. current_asmdata.asmlists[al_globals].concatlist(hlist);
  707. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(tablename));
  708. hlist.free;
  709. end;
  710. class procedure tnodeutils.InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:cardinal);
  711. var
  712. s: string;
  713. item: TTCInitItem;
  714. begin
  715. item:=TTCInitItem(list.First);
  716. if item=nil then
  717. exit;
  718. s:=make_mangledname(prefix,current_module.localsymtable,'');
  719. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  720. new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
  721. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  722. repeat
  723. { optimize away unused local/static symbols }
  724. if (item.sym.refs>0) or (item.sym.owner.symtabletype=globalsymtable) then
  725. begin
  726. { address to initialize }
  727. current_asmdata.asmlists[al_globals].concat(Tai_const.createname(item.sym.mangledname, item.offset));
  728. { value with which to initialize }
  729. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(item.datalabel));
  730. end;
  731. item:=TTCInitItem(item.Next);
  732. until item=nil;
  733. { end-of-list marker }
  734. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  735. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
  736. current_module.flags:=current_module.flags or unitflag;
  737. end;
  738. class procedure tnodeutils.InsertWideInits;
  739. begin
  740. InsertRuntimeInits('WIDEINITS',current_asmdata.WideInits,uf_wideinits);
  741. end;
  742. class procedure tnodeutils.InsertResStrInits;
  743. begin
  744. InsertRuntimeInits('RESSTRINITS',current_asmdata.ResStrInits,uf_resstrinits);
  745. end;
  746. class procedure tnodeutils.InsertWideInitsTablesTable;
  747. begin
  748. InsertRuntimeInitsTablesTable('WIDEINITS','FPC_WIDEINITTABLES',uf_wideinits);
  749. end;
  750. class procedure tnodeutils.InsertResStrTablesTable;
  751. begin
  752. InsertRuntimeInitsTablesTable('RESSTRINITS','FPC_RESSTRINITTABLES',uf_resstrinits);
  753. end;
  754. class procedure tnodeutils.InsertResourceTablesTable;
  755. var
  756. hp : tmodule;
  757. ResourceStringTables : tasmlist;
  758. count : longint;
  759. begin
  760. ResourceStringTables:=tasmlist.Create;
  761. count:=0;
  762. hp:=tmodule(loaded_units.first);
  763. while assigned(hp) do
  764. begin
  765. If (hp.flags and uf_has_resourcestrings)=uf_has_resourcestrings then
  766. begin
  767. ResourceStringTables.concat(Tai_const.Createname(make_mangledname('RESSTR',hp.localsymtable,'START'),AT_DATA,0));
  768. ResourceStringTables.concat(Tai_const.Createname(make_mangledname('RESSTR',hp.localsymtable,'END'),AT_DATA,0));
  769. inc(count);
  770. end;
  771. hp:=tmodule(hp.next);
  772. end;
  773. { Insert TableCount at start }
  774. ResourceStringTables.insert(Tai_const.Create_pint(count));
  775. { Add to data segment }
  776. maybe_new_object_file(current_asmdata.AsmLists[al_globals]);
  777. new_section(current_asmdata.AsmLists[al_globals],sec_data,'FPC_RESOURCESTRINGTABLES',sizeof(pint));
  778. current_asmdata.AsmLists[al_globals].concat(Tai_symbol.Createname_global('FPC_RESOURCESTRINGTABLES',AT_DATA,0));
  779. current_asmdata.AsmLists[al_globals].concatlist(ResourceStringTables);
  780. current_asmdata.AsmLists[al_globals].concat(Tai_symbol_end.Createname('FPC_RESOURCESTRINGTABLES'));
  781. ResourceStringTables.free;
  782. end;
  783. class procedure tnodeutils.InsertResourceInfo(ResourcesUsed: boolean);
  784. var
  785. ResourceInfo : TAsmList;
  786. begin
  787. if (target_res.id in [res_elf,res_macho,res_xcoff]) then
  788. begin
  789. ResourceInfo:=TAsmList.Create;
  790. maybe_new_object_file(ResourceInfo);
  791. new_section(ResourceInfo,sec_data,'FPC_RESLOCATION',sizeof(aint));
  792. ResourceInfo.concat(Tai_symbol.Createname_global('FPC_RESLOCATION',AT_DATA,0));
  793. if ResourcesUsed then
  794. { Valid pointer to resource information }
  795. ResourceInfo.concat(Tai_const.Createname('FPC_RESSYMBOL',0))
  796. else
  797. { Nil pointer to resource information }
  798. {$IFNDEF cpu64bitaddr}
  799. ResourceInfo.Concat(Tai_const.Create_32bit(0));
  800. {$ELSE}
  801. ResourceInfo.Concat(Tai_const.Create_64bit(0));
  802. {$ENDIF}
  803. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  804. current_asmdata.asmlists[al_globals].concatlist(ResourceInfo);
  805. ResourceInfo.free;
  806. end;
  807. end;
  808. class procedure tnodeutils.InsertMemorySizes;
  809. {$IFDEF POWERPC}
  810. var
  811. stkcookie: string;
  812. {$ENDIF POWERPC}
  813. begin
  814. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  815. { Insert Ident of the compiler in the .fpc.version section }
  816. new_section(current_asmdata.asmlists[al_globals],sec_fpc,'version',const_align(32));
  817. current_asmdata.asmlists[al_globals].concat(Tai_string.Create('FPC '+full_version_string+
  818. ' ['+date_string+'] for '+target_cpu_string+' - '+target_info.shortname));
  819. if not(tf_no_generic_stackcheck in target_info.flags) then
  820. begin
  821. { stacksize can be specified and is now simulated }
  822. new_section(current_asmdata.asmlists[al_globals],sec_data,'__stklen', sizeof(pint));
  823. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__stklen',AT_DATA,sizeof(pint)));
  824. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(stacksize));
  825. end;
  826. {$IFDEF POWERPC}
  827. { AmigaOS4 "stack cookie" support }
  828. if ( target_info.system = system_powerpc_amiga ) then
  829. begin
  830. { this symbol is needed to ignite powerpc amigaos' }
  831. { stack allocation magic for us with the given stack size. }
  832. { note: won't work for m68k amigaos or morphos. (KB) }
  833. str(stacksize,stkcookie);
  834. stkcookie:='$STACK: '+stkcookie+#0;
  835. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  836. new_section(current_asmdata.asmlists[al_globals],sec_data,'__stack_cookie',length(stkcookie));
  837. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__stack_cookie',AT_DATA,length(stkcookie)));
  838. current_asmdata.asmlists[al_globals].concat(Tai_string.Create(stkcookie));
  839. end;
  840. {$ENDIF POWERPC}
  841. { Initial heapsize }
  842. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  843. new_section(current_asmdata.asmlists[al_globals],sec_data,'__heapsize',sizeof(pint));
  844. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__heapsize',AT_DATA,sizeof(pint)));
  845. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(heapsize));
  846. { allocate an initial heap on embedded systems }
  847. if target_info.system in systems_embedded then
  848. begin
  849. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  850. new_section(current_asmdata.asmlists[al_globals],sec_data,'__fpc_initialheap',current_settings.alignment.varalignmax);
  851. current_asmdata.asmlists[al_globals].concat(tai_datablock.Create_global('__fpc_initialheap',heapsize));
  852. end;
  853. { Valgrind usage }
  854. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  855. new_section(current_asmdata.asmlists[al_globals],sec_data,'__fpc_valgrind',sizeof(boolean));
  856. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__fpc_valgrind',AT_DATA,sizeof(boolean)));
  857. current_asmdata.asmlists[al_globals].concat(Tai_const.create_8bit(byte(cs_gdb_valgrind in current_settings.globalswitches)));
  858. end;
  859. class procedure tnodeutils.add_main_procdef_paras(pd: tdef);
  860. begin
  861. { no parameters by default }
  862. end;
  863. end.