ngenutil.pas 37 KB

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