ngenutil.pas 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964
  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. class procedure InsertExtRTTITable; 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. tcinitproc: tprocdef;
  238. begin
  239. result:=maybe_insert_trashing(pd,n);
  240. if target_info.system in systems_typed_constants_node_init then
  241. begin
  242. case pd.proctypeoption of
  243. potype_class_constructor:
  244. begin
  245. { even though the initialisation code for typed constants may
  246. not yet be complete at this point (there may be more inside
  247. method definitions coming after this class constructor), the
  248. ones from inside the class definition have already been parsed.
  249. in case of $j-, these are marked "final" in Java and such
  250. static fields must be initialsed in the class constructor
  251. itself -> add them here }
  252. block:=internalstatements(stat);
  253. if assigned(pd.struct.tcinitcode) then
  254. begin
  255. addstatement(stat,pd.struct.tcinitcode);
  256. pd.struct.tcinitcode:=nil;
  257. end;
  258. psym:=tsym(pd.struct.symtable.find('FPC_INIT_TYPED_CONSTS_HELPER'));
  259. if assigned(psym) then
  260. begin
  261. if (psym.typ<>procsym) or
  262. (tprocsym(psym).procdeflist.count<>1) then
  263. internalerror(2011040301);
  264. tcinitproc:=tprocdef(tprocsym(psym).procdeflist[0]);
  265. addstatement(stat,ccallnode.create(nil,tprocsym(psym),
  266. pd.struct.symtable,nil,[]));
  267. end;
  268. addstatement(stat,result);
  269. result:=block
  270. end;
  271. potype_unitinit:
  272. begin
  273. if assigned(current_module.tcinitcode) then
  274. begin
  275. block:=internalstatements(stat);
  276. addstatement(stat,tnode(current_module.tcinitcode));
  277. current_module.tcinitcode:=nil;
  278. addstatement(stat,result);
  279. result:=block;
  280. end;
  281. end;
  282. else case pd.synthetickind of
  283. tsk_tcinit:
  284. begin
  285. if assigned(pd.struct.tcinitcode) then
  286. begin
  287. block:=internalstatements(stat);
  288. addstatement(stat,pd.struct.tcinitcode);
  289. pd.struct.tcinitcode:=nil;
  290. addstatement(stat,result);
  291. result:=block
  292. end
  293. end;
  294. end;
  295. end;
  296. end;
  297. end;
  298. class function tnodeutils.maybe_insert_trashing(pd: tprocdef; n: tnode): tnode;
  299. var
  300. stat: tstatementnode;
  301. begin
  302. result:=n;
  303. if (localvartrashing<>-1) and
  304. not(po_assembler in pd.procoptions) then
  305. begin
  306. result:=internalstatements(stat);
  307. pd.parast.SymList.ForEachCall(@maybe_trash_variable_callback,@stat);
  308. pd.localst.SymList.ForEachCall(@maybe_trash_variable_callback,@stat);
  309. addstatement(stat,n);
  310. end;
  311. end;
  312. class function tnodeutils.trashable_sym(p: tsym): boolean;
  313. begin
  314. result:=
  315. ((p.typ=localvarsym) or
  316. ((p.typ=paravarsym) and
  317. ((vo_is_funcret in tabstractnormalvarsym(p).varoptions) or
  318. (tabstractnormalvarsym(p).varspez=vs_out)))) and
  319. not is_managed_type(tabstractnormalvarsym(p).vardef) and
  320. not assigned(tabstractnormalvarsym(p).defaultconstsym);
  321. end;
  322. class procedure tnodeutils.maybe_trash_variable(var stat: tstatementnode; p: tabstractnormalvarsym; trashn: tnode);
  323. var
  324. size: asizeint;
  325. trashintval: int64;
  326. begin
  327. if trashable_sym(p) then
  328. begin
  329. trashintval:=trashintvalues[localvartrashing];
  330. if (p.vardef.typ=procvardef) and
  331. ([m_tp_procvar,m_mac_procvar]*current_settings.modeswitches<>[]) then
  332. begin
  333. if tprocvardef(p.vardef).is_addressonly then
  334. { in tp/delphi mode, you need @procvar to get at the contents of
  335. a procvar ... }
  336. trashn:=caddrnode.create(trashn)
  337. else
  338. { ... but if it's a procedure of object, that will only return
  339. the procedure address -> cast to tmethod instead }
  340. trashn:=ctypeconvnode.create_explicit(trashn,methodpointertype);
  341. end;
  342. if ((p.typ=localvarsym) and
  343. (not(vo_is_funcret in p.varoptions) or
  344. not is_shortstring(p.vardef))) or
  345. ((p.typ=paravarsym) and
  346. not is_shortstring(p.vardef)) then
  347. begin
  348. size:=p.getsize;
  349. case size of
  350. 0:
  351. begin
  352. { open array -> at least size 1. Can also be zero-sized
  353. record, so check it's actually an array }
  354. if p.vardef.typ=arraydef then
  355. trash_large(stat,trashn,caddnode.create(addn,cinlinenode.create(in_high_x,false,trashn.getcopy),genintconstnode(1)),trashintval)
  356. else
  357. trashn.free;
  358. end;
  359. 1: trash_small(stat,
  360. ctypeconvnode.create_internal(trashn,s8inttype),
  361. genintconstnode(shortint(trashintval)));
  362. 2: trash_small(stat,
  363. ctypeconvnode.create_internal(trashn,s16inttype),
  364. genintconstnode(smallint(trashintval)));
  365. 4: trash_small(stat,
  366. ctypeconvnode.create_internal(trashn,s32inttype),
  367. genintconstnode(longint(trashintval)));
  368. 8: trash_small(stat,
  369. ctypeconvnode.create_internal(trashn,s64inttype),
  370. genintconstnode(int64(trashintval)));
  371. else
  372. trash_large(stat,trashn,genintconstnode(size),trashintval);
  373. end;
  374. end
  375. else
  376. begin
  377. { may be an open string, even if is_open_string() returns false
  378. (for some helpers in the system unit) }
  379. { an open string has at least size 2 }
  380. trash_small(stat,
  381. cvecnode.create(trashn.getcopy,genintconstnode(0)),
  382. cordconstnode.create(tconstexprint(byte(trashintval)),cansichartype,false));
  383. trash_small(stat,
  384. cvecnode.create(trashn,genintconstnode(1)),
  385. cordconstnode.create(tconstexprint(byte(trashintval)),cansichartype,false));
  386. end;
  387. end
  388. else
  389. trashn.free;
  390. end;
  391. class procedure tnodeutils.maybe_trash_variable_callback(p:TObject;statn:pointer);
  392. var
  393. stat: ^tstatementnode absolute statn;
  394. begin
  395. if not(tsym(p).typ in [localvarsym,paravarsym]) then
  396. exit;
  397. maybe_trash_variable(stat^,tabstractnormalvarsym(p),cloadnode.create(tsym(p),tsym(p).owner));
  398. end;
  399. class procedure tnodeutils.trash_small(var stat: tstatementnode; trashn: tnode; trashvaln: tnode);
  400. begin
  401. addstatement(stat,cassignmentnode.create(trashn,trashvaln));
  402. end;
  403. class procedure tnodeutils.trash_large(var stat: tstatementnode; trashn, sizen: tnode; trashintval: int64);
  404. begin
  405. addstatement(stat,ccallnode.createintern('fpc_fillmem',
  406. ccallparanode.Create(cordconstnode.create(tconstexprint(byte(trashintval)),u8inttype,false),
  407. ccallparanode.Create(sizen,
  408. ccallparanode.Create(trashn,nil)))
  409. ));
  410. end;
  411. class procedure tnodeutils.insertbssdata(sym: tstaticvarsym);
  412. var
  413. l : asizeint;
  414. varalign : shortint;
  415. storefilepos : tfileposinfo;
  416. list : TAsmList;
  417. sectype : TAsmSectiontype;
  418. begin
  419. storefilepos:=current_filepos;
  420. current_filepos:=sym.fileinfo;
  421. l:=sym.getsize;
  422. varalign:=sym.vardef.alignment;
  423. if (varalign=0) then
  424. varalign:=var_align_size(l)
  425. else
  426. varalign:=var_align(varalign);
  427. if tf_section_threadvars in target_info.flags then
  428. begin
  429. if (vo_is_thread_var in sym.varoptions) then
  430. begin
  431. list:=current_asmdata.asmlists[al_threadvars];
  432. sectype:=sec_threadvar;
  433. end
  434. else
  435. begin
  436. list:=current_asmdata.asmlists[al_globals];
  437. sectype:=sec_bss;
  438. end;
  439. end
  440. else
  441. begin
  442. if (vo_is_thread_var in sym.varoptions) then
  443. begin
  444. inc(l,sizeof(pint));
  445. { it doesn't help to set a higher alignment, as }
  446. { the first sizeof(pint) bytes field will offset }
  447. { everything anyway }
  448. varalign:=sizeof(pint);
  449. end;
  450. list:=current_asmdata.asmlists[al_globals];
  451. sectype:=sec_bss;
  452. end;
  453. maybe_new_object_file(list);
  454. if vo_has_section in sym.varoptions then
  455. new_section(list,sec_user,sym.section,varalign)
  456. else
  457. new_section(list,sectype,lower(sym.mangledname),varalign);
  458. if (sym.owner.symtabletype=globalsymtable) or
  459. create_smartlink or
  460. DLLSource or
  461. (assigned(current_procinfo) and
  462. (po_inline in current_procinfo.procdef.procoptions)) or
  463. (vo_is_public in sym.varoptions) then
  464. begin
  465. { on AIX/stabx, we cannot generate debug information that encodes
  466. the address of a global symbol, you need a symbol with the same
  467. name as the identifier -> create an extra *local* symbol.
  468. Moreover, such a local symbol will be removed if it's not
  469. referenced anywhere, so also create a reference }
  470. if (target_dbg.id=dbg_stabx) and
  471. (cs_debuginfo in current_settings.moduleswitches) and
  472. not assigned(current_asmdata.GetAsmSymbol(sym.name)) then
  473. begin
  474. list.concat(tai_symbol.Create(current_asmdata.DefineAsmSymbol(sym.name,AB_LOCAL,AT_DATA),0));
  475. list.concat(tai_directive.Create(asd_reference,sym.name));
  476. end;
  477. list.concat(Tai_datablock.create_global(sym.mangledname,l));
  478. end
  479. else
  480. list.concat(Tai_datablock.create(sym.mangledname,l));
  481. current_filepos:=storefilepos;
  482. end;
  483. class function tnodeutils.create_main_procdef(const name: string; potype: tproctypeoption; ps: tprocsym): tdef;
  484. var
  485. pd: tprocdef;
  486. begin
  487. pd:=tprocdef.create(main_program_level);
  488. pd.procsym:=ps;
  489. ps.ProcdefList.Add(pd);
  490. include(pd.procoptions,po_global);
  491. { set procdef options }
  492. pd.proctypeoption:=potype;
  493. pd.proccalloption:=pocall_default;
  494. include(pd.procoptions,po_hascallingconvention);
  495. pd.forwarddef:=false;
  496. { may be required to calculate the mangled name }
  497. add_main_procdef_paras(pd);
  498. pd.setmangledname(name);
  499. pd.aliasnames.insert(pd.mangledname);
  500. result:=pd;
  501. end;
  502. procedure AddToStructInits(p:TObject;arg:pointer);
  503. var
  504. StructList: TFPList absolute arg;
  505. begin
  506. if (tdef(p).typ in [objectdef,recorddef]) and
  507. ([oo_has_class_constructor,oo_has_class_destructor] * tabstractrecorddef(p).objectoptions <> []) then
  508. StructList.Add(p);
  509. end;
  510. class procedure tnodeutils.InsertInitFinalTable;
  511. var
  512. hp : tused_unit;
  513. unitinits : TAsmList;
  514. count : longint;
  515. procedure write_struct_inits(u: tmodule);
  516. var
  517. i: integer;
  518. structlist: TFPList;
  519. pd: tprocdef;
  520. begin
  521. structlist := TFPList.Create;
  522. if assigned(u.globalsymtable) then
  523. u.globalsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  524. u.localsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  525. { write structures }
  526. for i := 0 to structlist.Count - 1 do
  527. begin
  528. pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_constructor);
  529. if assigned(pd) then
  530. unitinits.concat(Tai_const.Createname(pd.mangledname,0))
  531. else
  532. unitinits.concat(Tai_const.Create_pint(0));
  533. pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_destructor);
  534. if assigned(pd) then
  535. unitinits.concat(Tai_const.Createname(pd.mangledname,0))
  536. else
  537. unitinits.concat(Tai_const.Create_pint(0));
  538. inc(count);
  539. end;
  540. structlist.free;
  541. end;
  542. begin
  543. unitinits:=TAsmList.Create;
  544. count:=0;
  545. hp:=tused_unit(usedunits.first);
  546. while assigned(hp) do
  547. begin
  548. { insert class constructors/destructors of the unit }
  549. if (hp.u.flags and uf_classinits) <> 0 then
  550. write_struct_inits(hp.u);
  551. { call the unit init code and make it external }
  552. if (hp.u.flags and (uf_init or uf_finalize))<>0 then
  553. begin
  554. if (hp.u.flags and uf_init)<>0 then
  555. unitinits.concat(Tai_const.Createname(make_mangledname('INIT$',hp.u.globalsymtable,''),0))
  556. else
  557. unitinits.concat(Tai_const.Create_sym(nil));
  558. if (hp.u.flags and uf_finalize)<>0 then
  559. unitinits.concat(Tai_const.Createname(make_mangledname('FINALIZE$',hp.u.globalsymtable,''),0))
  560. else
  561. unitinits.concat(Tai_const.Create_sym(nil));
  562. inc(count);
  563. end;
  564. hp:=tused_unit(hp.next);
  565. end;
  566. { insert class constructors/destructor of the program }
  567. if (current_module.flags and uf_classinits) <> 0 then
  568. write_struct_inits(current_module);
  569. { Insert initialization/finalization of the program }
  570. if (current_module.flags and (uf_init or uf_finalize))<>0 then
  571. begin
  572. if (current_module.flags and uf_init)<>0 then
  573. unitinits.concat(Tai_const.Createname(make_mangledname('INIT$',current_module.localsymtable,''),0))
  574. else
  575. unitinits.concat(Tai_const.Create_sym(nil));
  576. if (current_module.flags and uf_finalize)<>0 then
  577. unitinits.concat(Tai_const.Createname(make_mangledname('FINALIZE$',current_module.localsymtable,''),0))
  578. else
  579. unitinits.concat(Tai_const.Create_sym(nil));
  580. inc(count);
  581. end;
  582. { Insert TableCount,InitCount at start }
  583. unitinits.insert(Tai_const.Create_32bit(0));
  584. unitinits.insert(Tai_const.Create_32bit(count));
  585. { Add to data segment }
  586. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  587. new_section(current_asmdata.asmlists[al_globals],sec_data,'INITFINAL',sizeof(pint));
  588. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('INITFINAL',AT_DATA,0));
  589. current_asmdata.asmlists[al_globals].concatlist(unitinits);
  590. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname('INITFINAL'));
  591. unitinits.free;
  592. end;
  593. class procedure tnodeutils.InsertExtRTTITable;
  594. var
  595. hp : tused_unit;
  596. unitinits : TAsmList;
  597. count : longint;
  598. begin
  599. unitinits:=TAsmList.Create;
  600. count:=0;
  601. hp:=tused_unit(usedunits.first);
  602. while assigned(hp) do
  603. begin
  604. if (hp.u.flags and uf_extrtti) <> 0 then
  605. begin
  606. unitinits.concat(Tai_const.Createname(make_mangledname('EXTR',hp.u.globalsymtable,''),0));
  607. inc(count);
  608. end;
  609. hp:=tused_unit(hp.next);
  610. end;
  611. { Insert TableCount,InitCount at start }
  612. unitinits.insert(Tai_const.Create_32bit(count));
  613. { Add to data segment }
  614. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  615. new_section(current_asmdata.asmlists[al_globals],sec_data,'INITEXTRTTIUNITS',sizeof(pint));
  616. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('INITEXTRTTIUNITS',AT_DATA,0));
  617. current_asmdata.asmlists[al_globals].concatlist(unitinits);
  618. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname('INITEXTRTTIUNITS'));
  619. unitinits.free;
  620. end;
  621. class procedure tnodeutils.InsertThreadvarTablesTable;
  622. var
  623. hp : tused_unit;
  624. ltvTables : TAsmList;
  625. count : longint;
  626. begin
  627. if (tf_section_threadvars in target_info.flags) then
  628. exit;
  629. ltvTables:=TAsmList.Create;
  630. count:=0;
  631. hp:=tused_unit(usedunits.first);
  632. while assigned(hp) do
  633. begin
  634. If (hp.u.flags and uf_threadvars)=uf_threadvars then
  635. begin
  636. ltvTables.concat(Tai_const.Createname(make_mangledname('THREADVARLIST',hp.u.globalsymtable,''),0));
  637. inc(count);
  638. end;
  639. hp:=tused_unit(hp.next);
  640. end;
  641. { Add program threadvars, if any }
  642. If (current_module.flags and uf_threadvars)=uf_threadvars then
  643. begin
  644. ltvTables.concat(Tai_const.Createname(make_mangledname('THREADVARLIST',current_module.localsymtable,''),0));
  645. inc(count);
  646. end;
  647. { Insert TableCount at start }
  648. ltvTables.insert(Tai_const.Create_32bit(count));
  649. { insert in data segment }
  650. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  651. new_section(current_asmdata.asmlists[al_globals],sec_data,'FPC_THREADVARTABLES',sizeof(pint));
  652. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('FPC_THREADVARTABLES',AT_DATA,0));
  653. current_asmdata.asmlists[al_globals].concatlist(ltvTables);
  654. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname('FPC_THREADVARTABLES'));
  655. ltvTables.free;
  656. end;
  657. procedure AddToThreadvarList(p:TObject;arg:pointer);
  658. var
  659. ltvTable : TAsmList;
  660. begin
  661. ltvTable:=TAsmList(arg);
  662. if (tsym(p).typ=staticvarsym) and
  663. (vo_is_thread_var in tstaticvarsym(p).varoptions) then
  664. begin
  665. { address of threadvar }
  666. ltvTable.concat(tai_const.Createname(tstaticvarsym(p).mangledname,0));
  667. { size of threadvar }
  668. ltvTable.concat(tai_const.create_32bit(tstaticvarsym(p).getsize));
  669. end;
  670. end;
  671. class procedure tnodeutils.InsertThreadvars;
  672. var
  673. s : string;
  674. ltvTable : TAsmList;
  675. begin
  676. if (tf_section_threadvars in target_info.flags) then
  677. exit;
  678. ltvTable:=TAsmList.create;
  679. if assigned(current_module.globalsymtable) then
  680. current_module.globalsymtable.SymList.ForEachCall(@AddToThreadvarList,ltvTable);
  681. current_module.localsymtable.SymList.ForEachCall(@AddToThreadvarList,ltvTable);
  682. if ltvTable.first<>nil then
  683. begin
  684. s:=make_mangledname('THREADVARLIST',current_module.localsymtable,'');
  685. { end of the list marker }
  686. ltvTable.concat(tai_const.create_sym(nil));
  687. { add to datasegment }
  688. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  689. new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
  690. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  691. current_asmdata.asmlists[al_globals].concatlist(ltvTable);
  692. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
  693. current_module.flags:=current_module.flags or uf_threadvars;
  694. end;
  695. ltvTable.Free;
  696. end;
  697. class procedure tnodeutils.InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:cardinal);
  698. var
  699. hp: tused_unit;
  700. hlist: TAsmList;
  701. count: longint;
  702. begin
  703. hlist:=TAsmList.Create;
  704. count:=0;
  705. hp:=tused_unit(usedunits.first);
  706. while assigned(hp) do
  707. begin
  708. if (hp.u.flags and unitflag)=unitflag then
  709. begin
  710. hlist.concat(Tai_const.Createname(make_mangledname(prefix,hp.u.globalsymtable,''),0));
  711. inc(count);
  712. end;
  713. hp:=tused_unit(hp.next);
  714. end;
  715. { Add items from program, if any }
  716. if (current_module.flags and unitflag)=unitflag then
  717. begin
  718. hlist.concat(Tai_const.Createname(make_mangledname(prefix,current_module.localsymtable,''),0));
  719. inc(count);
  720. end;
  721. { Insert TableCount at start }
  722. hlist.insert(Tai_const.Create_32bit(count));
  723. { insert in data segment }
  724. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  725. new_section(current_asmdata.asmlists[al_globals],sec_data,tablename,sizeof(pint));
  726. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(tablename,AT_DATA,0));
  727. current_asmdata.asmlists[al_globals].concatlist(hlist);
  728. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(tablename));
  729. hlist.free;
  730. end;
  731. class procedure tnodeutils.InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:cardinal);
  732. var
  733. s: string;
  734. item: TTCInitItem;
  735. begin
  736. item:=TTCInitItem(list.First);
  737. if item=nil then
  738. exit;
  739. s:=make_mangledname(prefix,current_module.localsymtable,'');
  740. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  741. new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
  742. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  743. repeat
  744. { optimize away unused local/static symbols }
  745. if (item.sym.refs>0) or (item.sym.owner.symtabletype=globalsymtable) then
  746. begin
  747. { address to initialize }
  748. current_asmdata.asmlists[al_globals].concat(Tai_const.createname(item.sym.mangledname, item.offset));
  749. { value with which to initialize }
  750. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(item.datalabel));
  751. end;
  752. item:=TTCInitItem(item.Next);
  753. until item=nil;
  754. { end-of-list marker }
  755. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  756. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
  757. current_module.flags:=current_module.flags or unitflag;
  758. end;
  759. class procedure tnodeutils.InsertWideInits;
  760. begin
  761. InsertRuntimeInits('WIDEINITS',current_asmdata.WideInits,uf_wideinits);
  762. end;
  763. class procedure tnodeutils.InsertResStrInits;
  764. begin
  765. InsertRuntimeInits('RESSTRINITS',current_asmdata.ResStrInits,uf_resstrinits);
  766. end;
  767. class procedure tnodeutils.InsertWideInitsTablesTable;
  768. begin
  769. InsertRuntimeInitsTablesTable('WIDEINITS','FPC_WIDEINITTABLES',uf_wideinits);
  770. end;
  771. class procedure tnodeutils.InsertResStrTablesTable;
  772. begin
  773. InsertRuntimeInitsTablesTable('RESSTRINITS','FPC_RESSTRINITTABLES',uf_resstrinits);
  774. end;
  775. class procedure tnodeutils.InsertResourceTablesTable;
  776. var
  777. hp : tmodule;
  778. ResourceStringTables : tasmlist;
  779. count : longint;
  780. begin
  781. ResourceStringTables:=tasmlist.Create;
  782. count:=0;
  783. hp:=tmodule(loaded_units.first);
  784. while assigned(hp) do
  785. begin
  786. If (hp.flags and uf_has_resourcestrings)=uf_has_resourcestrings then
  787. begin
  788. ResourceStringTables.concat(Tai_const.Createname(make_mangledname('RESSTR',hp.localsymtable,'START'),0));
  789. ResourceStringTables.concat(Tai_const.Createname(make_mangledname('RESSTR',hp.localsymtable,'END'),0));
  790. inc(count);
  791. end;
  792. hp:=tmodule(hp.next);
  793. end;
  794. { Insert TableCount at start }
  795. ResourceStringTables.insert(Tai_const.Create_pint(count));
  796. { Add to data segment }
  797. maybe_new_object_file(current_asmdata.AsmLists[al_globals]);
  798. new_section(current_asmdata.AsmLists[al_globals],sec_data,'FPC_RESOURCESTRINGTABLES',sizeof(pint));
  799. current_asmdata.AsmLists[al_globals].concat(Tai_symbol.Createname_global('FPC_RESOURCESTRINGTABLES',AT_DATA,0));
  800. current_asmdata.AsmLists[al_globals].concatlist(ResourceStringTables);
  801. current_asmdata.AsmLists[al_globals].concat(Tai_symbol_end.Createname('FPC_RESOURCESTRINGTABLES'));
  802. ResourceStringTables.free;
  803. end;
  804. class procedure tnodeutils.InsertResourceInfo(ResourcesUsed: boolean);
  805. var
  806. ResourceInfo : TAsmList;
  807. begin
  808. if (target_res.id in [res_elf,res_macho,res_xcoff]) then
  809. begin
  810. ResourceInfo:=TAsmList.Create;
  811. maybe_new_object_file(ResourceInfo);
  812. new_section(ResourceInfo,sec_data,'FPC_RESLOCATION',sizeof(aint));
  813. ResourceInfo.concat(Tai_symbol.Createname_global('FPC_RESLOCATION',AT_DATA,0));
  814. if ResourcesUsed then
  815. { Valid pointer to resource information }
  816. ResourceInfo.concat(Tai_const.Createname('FPC_RESSYMBOL',0))
  817. else
  818. { Nil pointer to resource information }
  819. {$IFNDEF cpu64bitaddr}
  820. ResourceInfo.Concat(Tai_const.Create_32bit(0));
  821. {$ELSE}
  822. ResourceInfo.Concat(Tai_const.Create_64bit(0));
  823. {$ENDIF}
  824. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  825. current_asmdata.asmlists[al_globals].concatlist(ResourceInfo);
  826. ResourceInfo.free;
  827. end;
  828. end;
  829. class procedure tnodeutils.InsertMemorySizes;
  830. {$IFDEF POWERPC}
  831. var
  832. stkcookie: string;
  833. {$ENDIF POWERPC}
  834. begin
  835. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  836. { Insert Ident of the compiler in the .fpc.version section }
  837. new_section(current_asmdata.asmlists[al_globals],sec_fpc,'version',const_align(32));
  838. current_asmdata.asmlists[al_globals].concat(Tai_string.Create('FPC '+full_version_string+
  839. ' ['+date_string+'] for '+target_cpu_string+' - '+target_info.shortname));
  840. if not(tf_no_generic_stackcheck in target_info.flags) then
  841. begin
  842. { stacksize can be specified and is now simulated }
  843. new_section(current_asmdata.asmlists[al_globals],sec_data,'__stklen', sizeof(pint));
  844. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__stklen',AT_DATA,sizeof(pint)));
  845. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(stacksize));
  846. end;
  847. {$IFDEF POWERPC}
  848. { AmigaOS4 "stack cookie" support }
  849. if ( target_info.system = system_powerpc_amiga ) then
  850. begin
  851. { this symbol is needed to ignite powerpc amigaos' }
  852. { stack allocation magic for us with the given stack size. }
  853. { note: won't work for m68k amigaos or morphos. (KB) }
  854. str(stacksize,stkcookie);
  855. stkcookie:='$STACK: '+stkcookie+#0;
  856. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  857. new_section(current_asmdata.asmlists[al_globals],sec_data,'__stack_cookie',length(stkcookie));
  858. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__stack_cookie',AT_DATA,length(stkcookie)));
  859. current_asmdata.asmlists[al_globals].concat(Tai_string.Create(stkcookie));
  860. end;
  861. {$ENDIF POWERPC}
  862. { Initial heapsize }
  863. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  864. new_section(current_asmdata.asmlists[al_globals],sec_data,'__heapsize',sizeof(pint));
  865. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__heapsize',AT_DATA,sizeof(pint)));
  866. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(heapsize));
  867. { Initial heapsize }
  868. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  869. new_section(current_asmdata.asmlists[al_globals],sec_data,'__fpc_valgrind',sizeof(boolean));
  870. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__fpc_valgrind',AT_DATA,sizeof(boolean)));
  871. current_asmdata.asmlists[al_globals].concat(Tai_const.create_8bit(byte(cs_gdb_valgrind in current_settings.globalswitches)));
  872. end;
  873. class procedure tnodeutils.add_main_procdef_paras(pd: tdef);
  874. begin
  875. { no parameters by default }
  876. end;
  877. end.