ngenutil.pas 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999
  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) then
  552. begin
  553. { first add the class... }
  554. if ([oo_has_class_constructor,oo_has_class_destructor] * tabstractrecorddef(p).objectoptions <> []) then
  555. StructList.Add(p);
  556. { ... and then also add all subclasses }
  557. tabstractrecorddef(p).symtable.deflist.foreachcall(@AddToStructInits,arg);
  558. end;
  559. end;
  560. class procedure tnodeutils.InsertInitFinalTable;
  561. var
  562. hp : tused_unit;
  563. unitinits : TAsmList;
  564. count : longint;
  565. procedure write_struct_inits(u: tmodule);
  566. var
  567. i: integer;
  568. structlist: TFPList;
  569. pd: tprocdef;
  570. begin
  571. structlist := TFPList.Create;
  572. if assigned(u.globalsymtable) then
  573. u.globalsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  574. u.localsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
  575. { write structures }
  576. for i := 0 to structlist.Count - 1 do
  577. begin
  578. pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_constructor);
  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. pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_destructor);
  584. if assigned(pd) then
  585. unitinits.concat(Tai_const.Createname(pd.mangledname,AT_FUNCTION,0))
  586. else
  587. unitinits.concat(Tai_const.Create_nil_codeptr);
  588. inc(count);
  589. end;
  590. structlist.free;
  591. end;
  592. begin
  593. unitinits:=TAsmList.Create;
  594. count:=0;
  595. hp:=tused_unit(usedunits.first);
  596. while assigned(hp) do
  597. begin
  598. { insert class constructors/destructors of the unit }
  599. if (hp.u.flags and uf_classinits) <> 0 then
  600. write_struct_inits(hp.u);
  601. { call the unit init code and make it external }
  602. if (hp.u.flags and (uf_init or uf_finalize))<>0 then
  603. begin
  604. if (hp.u.flags and uf_init)<>0 then
  605. unitinits.concat(Tai_const.Createname(make_mangledname('INIT$',hp.u.globalsymtable,''),AT_FUNCTION,0))
  606. else
  607. unitinits.concat(Tai_const.Create_nil_codeptr);
  608. if (hp.u.flags and uf_finalize)<>0 then
  609. unitinits.concat(Tai_const.Createname(make_mangledname('FINALIZE$',hp.u.globalsymtable,''),AT_FUNCTION,0))
  610. else
  611. unitinits.concat(Tai_const.Create_nil_codeptr);
  612. inc(count);
  613. end;
  614. hp:=tused_unit(hp.next);
  615. end;
  616. { insert class constructors/destructor of the program }
  617. if (current_module.flags and uf_classinits) <> 0 then
  618. write_struct_inits(current_module);
  619. { Insert initialization/finalization of the program }
  620. if (current_module.flags and (uf_init or uf_finalize))<>0 then
  621. begin
  622. if (current_module.flags and uf_init)<>0 then
  623. unitinits.concat(Tai_const.Createname(make_mangledname('INIT$',current_module.localsymtable,''),AT_FUNCTION,0))
  624. else
  625. unitinits.concat(Tai_const.Create_nil_codeptr);
  626. if (current_module.flags and uf_finalize)<>0 then
  627. unitinits.concat(Tai_const.Createname(make_mangledname('FINALIZE$',current_module.localsymtable,''),AT_FUNCTION,0))
  628. else
  629. unitinits.concat(Tai_const.Create_nil_codeptr);
  630. inc(count);
  631. end;
  632. { Insert TableCount,InitCount at start }
  633. unitinits.insert(Tai_const.Create_pint(0));
  634. unitinits.insert(Tai_const.Create_pint(count));
  635. { Add to data segment }
  636. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  637. new_section(current_asmdata.asmlists[al_globals],sec_data,'INITFINAL',sizeof(pint));
  638. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('INITFINAL',AT_DATA,0));
  639. current_asmdata.asmlists[al_globals].concatlist(unitinits);
  640. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname('INITFINAL'));
  641. unitinits.free;
  642. end;
  643. class procedure tnodeutils.InsertThreadvarTablesTable;
  644. var
  645. hp : tused_unit;
  646. ltvTables : TAsmList;
  647. count : longint;
  648. begin
  649. if (tf_section_threadvars in target_info.flags) then
  650. exit;
  651. ltvTables:=TAsmList.Create;
  652. count:=0;
  653. hp:=tused_unit(usedunits.first);
  654. while assigned(hp) do
  655. begin
  656. If (hp.u.flags and uf_threadvars)=uf_threadvars then
  657. begin
  658. ltvTables.concat(Tai_const.Createname(make_mangledname('THREADVARLIST',hp.u.globalsymtable,''),0));
  659. inc(count);
  660. end;
  661. hp:=tused_unit(hp.next);
  662. end;
  663. { Add program threadvars, if any }
  664. If (current_module.flags and uf_threadvars)=uf_threadvars then
  665. begin
  666. ltvTables.concat(Tai_const.Createname(make_mangledname('THREADVARLIST',current_module.localsymtable,''),0));
  667. inc(count);
  668. end;
  669. { Insert TableCount at start }
  670. ltvTables.insert(Tai_const.Create_32bit(count));
  671. { insert in data segment }
  672. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  673. new_section(current_asmdata.asmlists[al_globals],sec_data,'FPC_THREADVARTABLES',sizeof(pint));
  674. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('FPC_THREADVARTABLES',AT_DATA,0));
  675. current_asmdata.asmlists[al_globals].concatlist(ltvTables);
  676. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname('FPC_THREADVARTABLES'));
  677. ltvTables.free;
  678. end;
  679. procedure AddToThreadvarList(p:TObject;arg:pointer);
  680. var
  681. ltvTable : TAsmList;
  682. begin
  683. ltvTable:=TAsmList(arg);
  684. if (tsym(p).typ=staticvarsym) and
  685. (vo_is_thread_var in tstaticvarsym(p).varoptions) then
  686. begin
  687. { address of threadvar }
  688. ltvTable.concat(tai_const.Createname(tstaticvarsym(p).mangledname,0));
  689. { size of threadvar }
  690. ltvTable.concat(tai_const.create_32bit(tstaticvarsym(p).getsize));
  691. end;
  692. end;
  693. class procedure tnodeutils.InsertThreadvars;
  694. var
  695. s : string;
  696. ltvTable : TAsmList;
  697. begin
  698. if (tf_section_threadvars in target_info.flags) then
  699. exit;
  700. ltvTable:=TAsmList.create;
  701. if assigned(current_module.globalsymtable) then
  702. current_module.globalsymtable.SymList.ForEachCall(@AddToThreadvarList,ltvTable);
  703. current_module.localsymtable.SymList.ForEachCall(@AddToThreadvarList,ltvTable);
  704. if not ltvTable.Empty then
  705. begin
  706. s:=make_mangledname('THREADVARLIST',current_module.localsymtable,'');
  707. { end of the list marker }
  708. ltvTable.concat(tai_const.create_sym(nil));
  709. { add to datasegment }
  710. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  711. new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
  712. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  713. current_asmdata.asmlists[al_globals].concatlist(ltvTable);
  714. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
  715. current_module.flags:=current_module.flags or uf_threadvars;
  716. end;
  717. ltvTable.Free;
  718. end;
  719. class procedure tnodeutils.InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:cardinal);
  720. var
  721. hp: tused_unit;
  722. hlist: TAsmList;
  723. count: longint;
  724. begin
  725. hlist:=TAsmList.Create;
  726. count:=0;
  727. hp:=tused_unit(usedunits.first);
  728. while assigned(hp) do
  729. begin
  730. if (hp.u.flags and unitflag)=unitflag then
  731. begin
  732. hlist.concat(Tai_const.Createname(make_mangledname(prefix,hp.u.globalsymtable,''),0));
  733. inc(count);
  734. end;
  735. hp:=tused_unit(hp.next);
  736. end;
  737. { Add items from program, if any }
  738. if (current_module.flags and unitflag)=unitflag then
  739. begin
  740. hlist.concat(Tai_const.Createname(make_mangledname(prefix,current_module.localsymtable,''),0));
  741. inc(count);
  742. end;
  743. { Insert TableCount at start }
  744. hlist.insert(Tai_const.Create_pint(count));
  745. { insert in data segment }
  746. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  747. new_section(current_asmdata.asmlists[al_globals],sec_data,tablename,sizeof(pint));
  748. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(tablename,AT_DATA,0));
  749. current_asmdata.asmlists[al_globals].concatlist(hlist);
  750. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(tablename));
  751. hlist.free;
  752. end;
  753. class procedure tnodeutils.InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:cardinal);
  754. var
  755. s: string;
  756. item: TTCInitItem;
  757. begin
  758. item:=TTCInitItem(list.First);
  759. if item=nil then
  760. exit;
  761. s:=make_mangledname(prefix,current_module.localsymtable,'');
  762. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  763. new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
  764. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  765. repeat
  766. { optimize away unused local/static symbols }
  767. if (item.sym.refs>0) or (item.sym.owner.symtabletype=globalsymtable) then
  768. begin
  769. { address to initialize }
  770. current_asmdata.asmlists[al_globals].concat(Tai_const.createname(item.sym.mangledname, item.offset));
  771. { value with which to initialize }
  772. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(item.datalabel));
  773. end;
  774. item:=TTCInitItem(item.Next);
  775. until item=nil;
  776. { end-of-list marker }
  777. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  778. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
  779. current_module.flags:=current_module.flags or unitflag;
  780. end;
  781. class procedure tnodeutils.InsertWideInits;
  782. begin
  783. InsertRuntimeInits('WIDEINITS',current_asmdata.WideInits,uf_wideinits);
  784. end;
  785. class procedure tnodeutils.InsertResStrInits;
  786. begin
  787. InsertRuntimeInits('RESSTRINITS',current_asmdata.ResStrInits,uf_resstrinits);
  788. end;
  789. class procedure tnodeutils.InsertWideInitsTablesTable;
  790. begin
  791. InsertRuntimeInitsTablesTable('WIDEINITS','FPC_WIDEINITTABLES',uf_wideinits);
  792. end;
  793. class procedure tnodeutils.InsertResStrTablesTable;
  794. begin
  795. InsertRuntimeInitsTablesTable('RESSTRINITS','FPC_RESSTRINITTABLES',uf_resstrinits);
  796. end;
  797. class procedure tnodeutils.InsertResourceTablesTable;
  798. var
  799. hp : tmodule;
  800. ResourceStringTables : tasmlist;
  801. count : longint;
  802. begin
  803. ResourceStringTables:=tasmlist.Create;
  804. count:=0;
  805. hp:=tmodule(loaded_units.first);
  806. while assigned(hp) do
  807. begin
  808. If (hp.flags and uf_has_resourcestrings)=uf_has_resourcestrings then
  809. begin
  810. ResourceStringTables.concat(Tai_const.Createname(make_mangledname('RESSTR',hp.localsymtable,'START'),AT_DATA,0));
  811. ResourceStringTables.concat(Tai_const.Createname(make_mangledname('RESSTR',hp.localsymtable,'END'),AT_DATA,0));
  812. inc(count);
  813. end;
  814. hp:=tmodule(hp.next);
  815. end;
  816. { Insert TableCount at start }
  817. ResourceStringTables.insert(Tai_const.Create_pint(count));
  818. { Add to data segment }
  819. maybe_new_object_file(current_asmdata.AsmLists[al_globals]);
  820. new_section(current_asmdata.AsmLists[al_globals],sec_data,'FPC_RESOURCESTRINGTABLES',sizeof(pint));
  821. current_asmdata.AsmLists[al_globals].concat(Tai_symbol.Createname_global('FPC_RESOURCESTRINGTABLES',AT_DATA,0));
  822. current_asmdata.AsmLists[al_globals].concatlist(ResourceStringTables);
  823. current_asmdata.AsmLists[al_globals].concat(Tai_symbol_end.Createname('FPC_RESOURCESTRINGTABLES'));
  824. ResourceStringTables.free;
  825. end;
  826. class procedure tnodeutils.InsertResourceInfo(ResourcesUsed: boolean);
  827. var
  828. ResourceInfo : TAsmList;
  829. begin
  830. if (target_res.id in [res_elf,res_macho,res_xcoff]) then
  831. begin
  832. ResourceInfo:=TAsmList.Create;
  833. maybe_new_object_file(ResourceInfo);
  834. new_section(ResourceInfo,sec_data,'FPC_RESLOCATION',sizeof(aint));
  835. ResourceInfo.concat(Tai_symbol.Createname_global('FPC_RESLOCATION',AT_DATA,0));
  836. if ResourcesUsed then
  837. { Valid pointer to resource information }
  838. ResourceInfo.concat(Tai_const.Createname('FPC_RESSYMBOL',0))
  839. else
  840. { Nil pointer to resource information }
  841. {$IFNDEF cpu64bitaddr}
  842. ResourceInfo.Concat(Tai_const.Create_32bit(0));
  843. {$ELSE}
  844. ResourceInfo.Concat(Tai_const.Create_64bit(0));
  845. {$ENDIF}
  846. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  847. current_asmdata.asmlists[al_globals].concatlist(ResourceInfo);
  848. ResourceInfo.free;
  849. end;
  850. end;
  851. class procedure tnodeutils.InsertMemorySizes;
  852. {$IFDEF POWERPC}
  853. var
  854. stkcookie: string;
  855. {$ENDIF POWERPC}
  856. begin
  857. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  858. { Insert Ident of the compiler in the .fpc.version section }
  859. new_section(current_asmdata.asmlists[al_globals],sec_fpc,'version',const_align(32));
  860. current_asmdata.asmlists[al_globals].concat(Tai_string.Create('FPC '+full_version_string+
  861. ' ['+date_string+'] for '+target_cpu_string+' - '+target_info.shortname));
  862. if not(tf_no_generic_stackcheck in target_info.flags) then
  863. begin
  864. { stacksize can be specified and is now simulated }
  865. new_section(current_asmdata.asmlists[al_globals],sec_data,'__stklen', sizeof(pint));
  866. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__stklen',AT_DATA,sizeof(pint)));
  867. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(stacksize));
  868. end;
  869. {$IFDEF POWERPC}
  870. { AmigaOS4 "stack cookie" support }
  871. if ( target_info.system = system_powerpc_amiga ) then
  872. begin
  873. { this symbol is needed to ignite powerpc amigaos' }
  874. { stack allocation magic for us with the given stack size. }
  875. { note: won't work for m68k amigaos or morphos. (KB) }
  876. str(stacksize,stkcookie);
  877. stkcookie:='$STACK: '+stkcookie+#0;
  878. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  879. new_section(current_asmdata.asmlists[al_globals],sec_data,'__stack_cookie',length(stkcookie));
  880. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__stack_cookie',AT_DATA,length(stkcookie)));
  881. current_asmdata.asmlists[al_globals].concat(Tai_string.Create(stkcookie));
  882. end;
  883. {$ENDIF POWERPC}
  884. { Initial heapsize }
  885. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  886. new_section(current_asmdata.asmlists[al_globals],sec_data,'__heapsize',sizeof(pint));
  887. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__heapsize',AT_DATA,sizeof(pint)));
  888. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(heapsize));
  889. { allocate an initial heap on embedded systems }
  890. if target_info.system in systems_embedded then
  891. begin
  892. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  893. new_section(current_asmdata.asmlists[al_globals],sec_data,'__fpc_initialheap',current_settings.alignment.varalignmax);
  894. current_asmdata.asmlists[al_globals].concat(tai_datablock.Create_global('__fpc_initialheap',heapsize));
  895. end;
  896. { Valgrind usage }
  897. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  898. new_section(current_asmdata.asmlists[al_globals],sec_data,'__fpc_valgrind',sizeof(boolean));
  899. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__fpc_valgrind',AT_DATA,sizeof(boolean)));
  900. current_asmdata.asmlists[al_globals].concat(Tai_const.create_8bit(byte(cs_gdb_valgrind in current_settings.globalswitches)));
  901. end;
  902. class procedure tnodeutils.add_main_procdef_paras(pd: tdef);
  903. begin
  904. { no parameters by default }
  905. end;
  906. end.