ngenutil.pas 39 KB

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