ngenutil.pas 38 KB

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