ngenutil.pas 38 KB

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