ngenutil.pas 36 KB

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