ncgvmt.pas 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generates VMT for classes/objects and interface wrappers
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit ncgvmt;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. aasmdata,aasmbase,
  22. symbase,symdef;
  23. type
  24. pprocdeftree = ^tprocdeftree;
  25. tprocdeftree = record
  26. data : tprocdef;
  27. nl : tasmlabel;
  28. l,r : pprocdeftree;
  29. end;
  30. TVMTWriter=class
  31. private
  32. _Class : tobjectdef;
  33. { message tables }
  34. root : pprocdeftree;
  35. procedure disposeprocdeftree(p : pprocdeftree);
  36. procedure insertmsgint(p:TObject;arg:pointer);
  37. procedure insertmsgstr(p:TObject;arg:pointer);
  38. procedure insertint(p : pprocdeftree;var at : pprocdeftree;var count:longint);
  39. procedure insertstr(p : pprocdeftree;var at : pprocdeftree;var count:longint);
  40. function RedirectToEmpty(procdef: tprocdef): boolean;
  41. procedure writenames(list : TAsmList;p : pprocdeftree);
  42. procedure writeintentry(list : TAsmList;p : pprocdeftree);
  43. procedure writestrentry(list : TAsmList;p : pprocdeftree);
  44. {$ifdef WITHDMT}
  45. { dmt }
  46. procedure insertdmtentry(p:TObject;arg:pointer);
  47. procedure writedmtindexentry(p : pprocdeftree);
  48. procedure writedmtaddressentry(p : pprocdeftree);
  49. {$endif}
  50. { published methods }
  51. procedure do_count_published_methods(p:TObject;arg:pointer);
  52. procedure do_gen_published_methods(p:TObject;arg:pointer);
  53. { virtual methods }
  54. procedure writevirtualmethods(List:TAsmList);
  55. { interface tables }
  56. function intf_get_vtbl_name(AImplIntf:TImplementedInterface): string;
  57. procedure intf_create_vtbl(rawdata: TAsmList;AImplIntf:TImplementedInterface);
  58. procedure intf_gen_intf_ref(rawdata: TAsmList;AImplIntf:TImplementedInterface);
  59. function intf_write_table(list : TAsmList):TAsmLabel;
  60. { generates the message tables for a class }
  61. function genstrmsgtab(list : TAsmList) : tasmlabel;
  62. function genintmsgtab(list : TAsmList) : tasmlabel;
  63. function genpublishedmethodstable(list : TAsmList) : tasmlabel;
  64. function generate_field_table(list : TAsmList) : tasmlabel;
  65. procedure generate_abstract_stub(list:TAsmList;pd:tprocdef);
  66. {$ifdef WITHDMT}
  67. { generates a DMT for _class }
  68. function gendmt : tasmlabel;
  69. {$endif WITHDMT}
  70. public
  71. constructor create(c:tobjectdef); virtual;
  72. { write the VMT to al_globals }
  73. procedure writevmt;
  74. procedure writeinterfaceids(list: TAsmList);
  75. { should the VMT writer be used at all (e.g., not for the JVM target) }
  76. class function use_vmt_writer: boolean; virtual;
  77. end;
  78. TVMTWriterClass = class of TVMTWriter;
  79. { generate persistent type information like VMT, RTTI and inittables }
  80. procedure write_persistent_type_info(st:tsymtable;is_global:boolean);
  81. var
  82. CVMTWriter: TVMTWriterClass = TVMTWriter;
  83. implementation
  84. uses
  85. cutils,cclasses,
  86. globtype,globals,verbose,constexp,
  87. systems,
  88. symconst,symtype,symsym,symtable,defutil,
  89. aasmtai,
  90. wpobase,
  91. nobj,
  92. cgbase,parabase,paramgr,cgobj,cgcpu,hlcgobj,hlcgcpu,
  93. ncgrtti;
  94. {*****************************************************************************
  95. TVMTWriter
  96. *****************************************************************************}
  97. constructor TVMTWriter.create(c:tobjectdef);
  98. begin
  99. inherited Create;
  100. _Class:=c;
  101. end;
  102. {**************************************
  103. Message Tables
  104. **************************************}
  105. procedure TVMTWriter.disposeprocdeftree(p : pprocdeftree);
  106. begin
  107. if assigned(p^.l) then
  108. disposeprocdeftree(p^.l);
  109. if assigned(p^.r) then
  110. disposeprocdeftree(p^.r);
  111. dispose(p);
  112. end;
  113. procedure TVMTWriter.insertint(p : pprocdeftree;var at : pprocdeftree;var count:longint);
  114. begin
  115. if at=nil then
  116. begin
  117. at:=p;
  118. inc(count);
  119. end
  120. else
  121. begin
  122. if p^.data.messageinf.i<at^.data.messageinf.i then
  123. insertint(p,at^.l,count)
  124. else if p^.data.messageinf.i>at^.data.messageinf.i then
  125. insertint(p,at^.r,count)
  126. else
  127. Message1(parser_e_duplicate_message_label,tostr(p^.data.messageinf.i));
  128. end;
  129. end;
  130. procedure TVMTWriter.insertstr(p : pprocdeftree;var at : pprocdeftree;var count:longint);
  131. var
  132. i : integer;
  133. begin
  134. if at=nil then
  135. begin
  136. at:=p;
  137. inc(count);
  138. end
  139. else
  140. begin
  141. i:=CompareStr(p^.data.messageinf.str^,at^.data.messageinf.str^);
  142. if i<0 then
  143. insertstr(p,at^.l,count)
  144. else if i>0 then
  145. insertstr(p,at^.r,count)
  146. else
  147. Message1(parser_e_duplicate_message_label,p^.data.messageinf.str^);
  148. end;
  149. end;
  150. procedure TVMTWriter.insertmsgint(p:TObject;arg:pointer);
  151. var
  152. i : longint;
  153. pd : Tprocdef;
  154. pt : pprocdeftree;
  155. begin
  156. if tsym(p).typ<>procsym then
  157. exit;
  158. for i:=0 to Tprocsym(p).ProcdefList.Count-1 do
  159. begin
  160. pd:=tprocdef(Tprocsym(p).ProcdefList[i]);
  161. if po_msgint in pd.procoptions then
  162. begin
  163. new(pt);
  164. pt^.data:=pd;
  165. pt^.l:=nil;
  166. pt^.r:=nil;
  167. insertint(pt,root,plongint(arg)^);
  168. end;
  169. end;
  170. end;
  171. procedure TVMTWriter.insertmsgstr(p:TObject;arg:pointer);
  172. var
  173. i : longint;
  174. pd : Tprocdef;
  175. pt : pprocdeftree;
  176. begin
  177. if tsym(p).typ<>procsym then
  178. exit;
  179. for i:=0 to Tprocsym(p).ProcdefList.Count-1 do
  180. begin
  181. pd:=tprocdef(Tprocsym(p).ProcdefList[i]);
  182. if po_msgstr in pd.procoptions then
  183. begin
  184. new(pt);
  185. pt^.data:=pd;
  186. pt^.l:=nil;
  187. pt^.r:=nil;
  188. insertstr(pt,root,plongint(arg)^);
  189. end;
  190. end;
  191. end;
  192. procedure TVMTWriter.writenames(list : TAsmList;p : pprocdeftree);
  193. var
  194. ca : pchar;
  195. len : byte;
  196. begin
  197. current_asmdata.getdatalabel(p^.nl);
  198. if assigned(p^.l) then
  199. writenames(list,p^.l);
  200. list.concat(cai_align.create(const_align(sizeof(pint))));
  201. list.concat(Tai_label.Create(p^.nl));
  202. len:=length(p^.data.messageinf.str^);
  203. list.concat(tai_const.create_8bit(len));
  204. getmem(ca,len+1);
  205. move(p^.data.messageinf.str^[1],ca^,len);
  206. ca[len]:=#0;
  207. list.concat(Tai_string.Create_pchar(ca,len));
  208. if assigned(p^.r) then
  209. writenames(list,p^.r);
  210. end;
  211. procedure TVMTWriter.writestrentry(list : TAsmList;p : pprocdeftree);
  212. begin
  213. if assigned(p^.l) then
  214. writestrentry(list,p^.l);
  215. { write name label }
  216. list.concat(cai_align.create(sizeof(pint)));
  217. list.concat(Tai_const.Create_sym(p^.nl));
  218. list.concat(cai_align.create(sizeof(pint)));
  219. list.concat(Tai_const.Createname(p^.data.mangledname,AT_FUNCTION,0));
  220. if assigned(p^.r) then
  221. writestrentry(list,p^.r);
  222. end;
  223. function TVMTWriter.genstrmsgtab(list : TAsmList) : tasmlabel;
  224. var
  225. count : longint;
  226. begin
  227. root:=nil;
  228. count:=0;
  229. { insert all message handlers into a tree, sorted by name }
  230. _class.symtable.SymList.ForEachCall(@insertmsgstr,@count);
  231. { write all names }
  232. if assigned(root) then
  233. writenames(list,root);
  234. { now start writing of the message string table }
  235. current_asmdata.getlabel(result,alt_data);
  236. list.concat(cai_align.create(sizeof(pint)));
  237. list.concat(Tai_label.Create(result));
  238. list.concat(cai_align.create(sizeof(longint)));
  239. list.concat(Tai_const.Create_32bit(count));
  240. list.concat(cai_align.create(sizeof(pint)));
  241. if assigned(root) then
  242. begin
  243. writestrentry(list,root);
  244. disposeprocdeftree(root);
  245. end;
  246. end;
  247. procedure TVMTWriter.writeintentry(list : TAsmList;p : pprocdeftree);
  248. begin
  249. if assigned(p^.l) then
  250. writeintentry(list,p^.l);
  251. { write name label }
  252. list.concat(cai_align.create(sizeof(longint)));
  253. list.concat(Tai_const.Create_32bit(p^.data.messageinf.i));
  254. list.concat(cai_align.create(sizeof(pint)));
  255. list.concat(Tai_const.Createname(p^.data.mangledname,AT_FUNCTION,0));
  256. if assigned(p^.r) then
  257. writeintentry(list,p^.r);
  258. end;
  259. function TVMTWriter.genintmsgtab(list : TAsmList) : tasmlabel;
  260. var
  261. r : tasmlabel;
  262. count : longint;
  263. begin
  264. root:=nil;
  265. count:=0;
  266. { insert all message handlers into a tree, sorted by name }
  267. _class.symtable.SymList.ForEachCall(@insertmsgint,@count);
  268. { now start writing of the message string table }
  269. current_asmdata.getlabel(r,alt_data);
  270. list.concat(cai_align.create(sizeof(pint)));
  271. list.concat(Tai_label.Create(r));
  272. genintmsgtab:=r;
  273. list.concat(cai_align.create(sizeof(longint)));
  274. list.concat(Tai_const.Create_32bit(count));
  275. list.concat(cai_align.create(sizeof(pint)));
  276. if assigned(root) then
  277. begin
  278. writeintentry(list,root);
  279. disposeprocdeftree(root);
  280. end;
  281. end;
  282. {$ifdef WITHDMT}
  283. {**************************************
  284. DMT
  285. **************************************}
  286. procedure TVMTWriter.insertdmtentry(p:TObject;arg:pointer);
  287. var
  288. hp : tprocdef;
  289. pt : pprocdeftree;
  290. begin
  291. if tsym(p).typ=procsym then
  292. begin
  293. hp:=tprocsym(p).definition;
  294. while assigned(hp) do
  295. begin
  296. if (po_msgint in hp.procoptions) then
  297. begin
  298. new(pt);
  299. pt^.p:=hp;
  300. pt^.l:=nil;
  301. pt^.r:=nil;
  302. insertint(pt,root);
  303. end;
  304. hp:=hp.nextoverloaded;
  305. end;
  306. end;
  307. end;
  308. procedure TVMTWriter.writedmtindexentry(p : pprocdeftree);
  309. begin
  310. if assigned(p^.l) then
  311. writedmtindexentry(p^.l);
  312. al_globals.concat(Tai_const.Create_32bit(p^.data.messageinf.i));
  313. if assigned(p^.r) then
  314. writedmtindexentry(p^.r);
  315. end;
  316. procedure TVMTWriter.writedmtaddressentry(p : pprocdeftree);
  317. begin
  318. if assigned(p^.l) then
  319. writedmtaddressentry(p^.l);
  320. al_globals.concat(Tai_const_symbol.Createname(p^.data.mangledname,0));
  321. if assigned(p^.r) then
  322. writedmtaddressentry(p^.r);
  323. end;
  324. function TVMTWriter.gendmt : tasmlabel;
  325. var
  326. r : tasmlabel;
  327. begin
  328. root:=nil;
  329. count:=0;
  330. gendmt:=nil;
  331. { insert all message handlers into a tree, sorted by number }
  332. _class.symtable.SymList.ForEachCall(insertdmtentry);
  333. if count>0 then
  334. begin
  335. current_asmdata.getdatalabel(r);
  336. gendmt:=r;
  337. al_globals.concat(cai_align.create(const_align(sizeof(pint))));
  338. al_globals.concat(Tai_label.Create(r));
  339. { entries for caching }
  340. al_globals.concat(Tai_const.Create_ptr(0));
  341. al_globals.concat(Tai_const.Create_ptr(0));
  342. al_globals.concat(Tai_const.Create_32bit(count));
  343. if assigned(root) then
  344. begin
  345. writedmtindexentry(root);
  346. writedmtaddressentry(root);
  347. disposeprocdeftree(root);
  348. end;
  349. end;
  350. end;
  351. {$endif WITHDMT}
  352. {**************************************
  353. Published Methods
  354. **************************************}
  355. procedure TVMTWriter.do_count_published_methods(p:TObject;arg:pointer);
  356. var
  357. i : longint;
  358. pd : tprocdef;
  359. begin
  360. if (tsym(p).typ<>procsym) then
  361. exit;
  362. for i:=0 to Tprocsym(p).ProcdefList.Count-1 do
  363. begin
  364. pd:=tprocdef(Tprocsym(p).ProcdefList[i]);
  365. if (pd.procsym=tsym(p)) and
  366. (pd.visibility=vis_published) then
  367. inc(plongint(arg)^);
  368. end;
  369. end;
  370. procedure TVMTWriter.do_gen_published_methods(p:TObject;arg:pointer);
  371. var
  372. i : longint;
  373. l : tasmlabel;
  374. pd : tprocdef;
  375. lists: ^TAsmList absolute arg;
  376. begin
  377. if (tsym(p).typ<>procsym) then
  378. exit;
  379. for i:=0 to Tprocsym(p).ProcdefList.Count-1 do
  380. begin
  381. pd:=tprocdef(Tprocsym(p).ProcdefList[i]);
  382. if (pd.procsym=tsym(p)) and
  383. (pd.visibility=vis_published) then
  384. begin
  385. current_asmdata.getlabel(l,alt_data);
  386. lists[1].concat(cai_align.Create(const_align(sizeof(pint))));
  387. lists[1].concat(Tai_label.Create(l));
  388. lists[1].concat(Tai_const.Create_8bit(length(tsym(p).realname)));
  389. lists[1].concat(Tai_string.Create(tsym(p).realname));
  390. lists[0].concat(Tai_const.Create_sym(l));
  391. if po_abstractmethod in pd.procoptions then
  392. lists[0].concat(Tai_const.Create_nil_codeptr)
  393. else
  394. lists[0].concat(Tai_const.Createname(pd.mangledname,AT_FUNCTION,0));
  395. end;
  396. end;
  397. end;
  398. function TVMTWriter.genpublishedmethodstable(list : TAsmList) : tasmlabel;
  399. var
  400. l : tasmlabel;
  401. count : longint;
  402. lists : array[0..1] of TAsmList;
  403. begin
  404. count:=0;
  405. _class.symtable.SymList.ForEachCall(@do_count_published_methods,@count);
  406. if count>0 then
  407. begin
  408. lists[0]:=list;
  409. lists[1]:=TAsmList.Create;
  410. current_asmdata.getlabel(l,alt_data);
  411. list.concat(cai_align.create(const_align(sizeof(pint))));
  412. list.concat(Tai_label.Create(l));
  413. list.concat(Tai_const.Create_32bit(count));
  414. _class.symtable.SymList.ForEachCall(@do_gen_published_methods,@lists);
  415. list.concatlist(lists[1]);
  416. lists[1].Free;
  417. genpublishedmethodstable:=l;
  418. end
  419. else
  420. genpublishedmethodstable:=nil;
  421. end;
  422. function TVMTWriter.generate_field_table(list : TAsmList) : tasmlabel;
  423. var
  424. i : longint;
  425. sym : tsym;
  426. fieldtable,
  427. classtable : tasmlabel;
  428. classindex,
  429. fieldcount : longint;
  430. classtablelist : TFPList;
  431. begin
  432. classtablelist:=TFPList.Create;
  433. { retrieve field info fields }
  434. fieldcount:=0;
  435. for i:=0 to _class.symtable.SymList.Count-1 do
  436. begin
  437. sym:=tsym(_class.symtable.SymList[i]);
  438. if (sym.typ=fieldvarsym) and
  439. (sym.visibility=vis_published) then
  440. begin
  441. if tfieldvarsym(sym).vardef.typ<>objectdef then
  442. internalerror(200611032);
  443. classindex:=classtablelist.IndexOf(tfieldvarsym(sym).vardef);
  444. if classindex=-1 then
  445. classtablelist.Add(tfieldvarsym(sym).vardef);
  446. inc(fieldcount);
  447. end;
  448. end;
  449. if fieldcount>0 then
  450. begin
  451. current_asmdata.getlabel(fieldtable,alt_data);
  452. current_asmdata.getlabel(classtable,alt_data);
  453. list.concat(cai_align.create(const_align(sizeof(pint))));
  454. { write fields }
  455. list.concat(Tai_label.Create(fieldtable));
  456. list.concat(Tai_const.Create_16bit(fieldcount));
  457. if (tf_requires_proper_alignment in target_info.flags) then
  458. list.concat(cai_align.Create(sizeof(TConstPtrUInt)));
  459. list.concat(Tai_const.Create_sym(classtable));
  460. for i:=0 to _class.symtable.SymList.Count-1 do
  461. begin
  462. sym:=tsym(_class.symtable.SymList[i]);
  463. if (sym.typ=fieldvarsym) and
  464. (sym.visibility=vis_published) then
  465. begin
  466. if (tf_requires_proper_alignment in target_info.flags) then
  467. list.concat(cai_align.Create(sizeof(pint)));
  468. list.concat(Tai_const.Create_pint(tfieldvarsym(sym).fieldoffset));
  469. classindex:=classtablelist.IndexOf(tfieldvarsym(sym).vardef);
  470. if classindex=-1 then
  471. internalerror(200611033);
  472. list.concat(Tai_const.Create_16bit(classindex+1));
  473. list.concat(Tai_const.Create_8bit(length(tfieldvarsym(sym).realname)));
  474. list.concat(Tai_string.Create(tfieldvarsym(sym).realname));
  475. end;
  476. end;
  477. { generate the class table }
  478. list.concat(cai_align.create(const_align(sizeof(pint))));
  479. list.concat(Tai_label.Create(classtable));
  480. list.concat(Tai_const.Create_16bit(classtablelist.count));
  481. if (tf_requires_proper_alignment in target_info.flags) then
  482. list.concat(cai_align.Create(sizeof(TConstPtrUInt)));
  483. for i:=0 to classtablelist.Count-1 do
  484. list.concat(Tai_const.Createname(tobjectdef(classtablelist[i]).vmt_mangledname,AT_DATA,0));
  485. result:=fieldtable;
  486. end
  487. else
  488. result:=nil;
  489. classtablelist.free;
  490. end;
  491. {**************************************
  492. Interface tables
  493. **************************************}
  494. function TVMTWriter.intf_get_vtbl_name(AImplIntf:TImplementedInterface): string;
  495. begin
  496. result:=make_mangledname('VTBL',_class.owner,_class.objname^+'_$_'+AImplIntf.IntfDef.objname^);
  497. end;
  498. procedure TVMTWriter.intf_create_vtbl(rawdata: TAsmList;AImplIntf:TImplementedInterface);
  499. var
  500. pd : tprocdef;
  501. vtblstr,
  502. hs : string;
  503. i : longint;
  504. begin
  505. vtblstr:=intf_get_vtbl_name(AImplIntf);
  506. rawdata.concat(cai_align.create(const_align(sizeof(pint))));
  507. rawdata.concat(tai_symbol.createname(vtblstr,AT_DATA,0));
  508. if assigned(AImplIntf.procdefs) then
  509. begin
  510. for i:=0 to AImplIntf.procdefs.count-1 do
  511. begin
  512. pd:=tprocdef(AImplIntf.procdefs[i]);
  513. hs:=make_mangledname('WRPR',_class.owner,_class.objname^+'_$_'+AImplIntf.IntfDef.objname^+'_$_'+
  514. tostr(i)+'_$_'+pd.mangledname);
  515. { create reference }
  516. rawdata.concat(Tai_const.Createname(hs,AT_FUNCTION,0));
  517. end;
  518. end;
  519. rawdata.concat(tai_symbol_end.createname(vtblstr));
  520. end;
  521. procedure TVMTWriter.intf_gen_intf_ref(rawdata: TAsmList;AImplIntf:TImplementedInterface);
  522. var
  523. pd: tprocdef;
  524. begin
  525. { GUID (or nil for Corba interfaces) }
  526. if AImplIntf.IntfDef.objecttype in [odt_interfacecom] then
  527. rawdata.concat(Tai_const.CreateName(
  528. make_mangledname('IID',AImplIntf.IntfDef.owner,AImplIntf.IntfDef.objname^),AT_DATA,0))
  529. else
  530. rawdata.concat(Tai_const.Create_nil_dataptr);
  531. { VTable }
  532. rawdata.concat(Tai_const.Createname(intf_get_vtbl_name(AImplIntf.VtblImplIntf),AT_DATA,0));
  533. { IOffset field }
  534. case AImplIntf.VtblImplIntf.IType of
  535. etFieldValue, etFieldValueClass,
  536. etStandard:
  537. rawdata.concat(Tai_const.Create_pint(AImplIntf.VtblImplIntf.IOffset));
  538. etStaticMethodResult, etStaticMethodClass:
  539. rawdata.concat(Tai_const.Createname(
  540. tprocdef(tpropertysym(AImplIntf.ImplementsGetter).propaccesslist[palt_read].procdef).mangledname,
  541. AT_FUNCTION,
  542. 0
  543. ));
  544. etVirtualMethodResult, etVirtualMethodClass:
  545. begin
  546. pd := tprocdef(tpropertysym(AImplIntf.ImplementsGetter).propaccesslist[palt_read].procdef);
  547. rawdata.concat(Tai_const.Create_pint(tobjectdef(pd.struct).vmtmethodoffset(pd.extnumber)));
  548. end;
  549. else
  550. internalerror(200802162);
  551. end;
  552. { IIDStr }
  553. rawdata.concat(Tai_const.CreateName(
  554. make_mangledname('IIDSTR',AImplIntf.IntfDef.owner,AImplIntf.IntfDef.objname^),AT_DATA,0));
  555. { IType }
  556. rawdata.concat(Tai_const.Create_pint(aint(AImplIntf.VtblImplIntf.IType)));
  557. end;
  558. function TVMTWriter.intf_write_table(list : TAsmList):TAsmLabel;
  559. var
  560. i : longint;
  561. ImplIntf : TImplementedInterface;
  562. begin
  563. current_asmdata.getlabel(result,alt_data);
  564. list.concat(cai_align.create(const_align(sizeof(pint))));
  565. list.concat(Tai_label.Create(result));
  566. list.concat(Tai_const.Create_pint(_class.ImplementedInterfaces.count));
  567. { Write vtbl references }
  568. for i:=0 to _class.ImplementedInterfaces.count-1 do
  569. begin
  570. ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]);
  571. intf_gen_intf_ref(list,ImplIntf);
  572. end;
  573. { Write vtbls }
  574. for i:=0 to _class.ImplementedInterfaces.count-1 do
  575. begin
  576. ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]);
  577. if ImplIntf.VtblImplIntf=ImplIntf then
  578. intf_create_vtbl(list,ImplIntf);
  579. end;
  580. end;
  581. { Write interface identifiers to the data section }
  582. procedure TVMTWriter.writeinterfaceids(list: TAsmList);
  583. var
  584. i : longint;
  585. s : string;
  586. begin
  587. if assigned(_class.iidguid) then
  588. begin
  589. s:=make_mangledname('IID',_class.owner,_class.objname^);
  590. maybe_new_object_file(list);
  591. new_section(list,sec_rodata_norel,s,const_align(sizeof(pint)));
  592. list.concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  593. list.concat(Tai_const.Create_32bit(longint(_class.iidguid^.D1)));
  594. list.concat(Tai_const.Create_16bit(_class.iidguid^.D2));
  595. list.concat(Tai_const.Create_16bit(_class.iidguid^.D3));
  596. for i:=Low(_class.iidguid^.D4) to High(_class.iidguid^.D4) do
  597. list.concat(Tai_const.Create_8bit(_class.iidguid^.D4[i]));
  598. end;
  599. maybe_new_object_file(list);
  600. s:=make_mangledname('IIDSTR',_class.owner,_class.objname^);
  601. new_section(list,sec_rodata_norel,s,sizeof(pint));
  602. list.concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  603. list.concat(Tai_const.Create_8bit(length(_class.iidstr^)));
  604. list.concat(Tai_string.Create(_class.iidstr^));
  605. end;
  606. class function TVMTWriter.use_vmt_writer: boolean;
  607. begin
  608. result:=true;
  609. end;
  610. function TVMTWriter.RedirectToEmpty(procdef : tprocdef) : boolean;
  611. var
  612. i : longint;
  613. hp : PCGParaLocation;
  614. begin
  615. result:=false;
  616. if procdef.isempty then
  617. begin
  618. {$ifdef x86}
  619. paramanager.create_funcretloc_info(procdef,calleeside);
  620. if (procdef.funcretloc[calleeside].Location^.loc=LOC_FPUREGISTER) then
  621. exit;
  622. {$endif x86}
  623. procdef.init_paraloc_info(callerside);
  624. { we can redirect the call if no memory parameter is passed }
  625. for i:=0 to procdef.paras.count-1 do
  626. begin
  627. hp:=tparavarsym(procdef.paras[i]).paraloc[callerside].Location;
  628. while assigned(hp) do
  629. begin
  630. if not(hp^.Loc in [LOC_REGISTER,LOC_MMREGISTER,LOC_FPUREGISTER]) then
  631. exit;
  632. hp:=hp^.Next;
  633. end;
  634. end;
  635. result:=true;
  636. end;
  637. end;
  638. procedure TVMTWriter.generate_abstract_stub(list:TAsmList;pd:tprocdef);
  639. var
  640. sym: TAsmSymbol;
  641. begin
  642. { Generate stubs for abstract methods, so their symbols are present and
  643. can be used e.g. to take address (see issue #24536). }
  644. if (po_global in pd.procoptions) and
  645. (pd.owner.defowner<>self._class) then
  646. exit;
  647. sym:=current_asmdata.GetAsmSymbol(pd.mangledname);
  648. if assigned(sym) and (sym.bind<>AB_EXTERNAL) then
  649. exit;
  650. maybe_new_object_file(list);
  651. new_section(list,sec_code,lower(pd.mangledname),target_info.alignment.procalign);
  652. if (po_global in pd.procoptions) then
  653. begin
  654. sym:=current_asmdata.DefineAsmSymbol(pd.mangledname,AB_GLOBAL,AT_FUNCTION);
  655. list.concat(Tai_symbol.Create_global(sym,0));
  656. end
  657. else
  658. begin
  659. sym:=current_asmdata.DefineAsmSymbol(pd.mangledname,AB_LOCAL,AT_FUNCTION);
  660. list.concat(Tai_symbol.Create(sym,0));
  661. end;
  662. cg.g_external_wrapper(list,pd,'FPC_ABSTRACTERROR');
  663. list.concat(Tai_symbol_end.Create(sym));
  664. end;
  665. procedure TVMTWriter.writevirtualmethods(List:TAsmList);
  666. var
  667. vmtpd : tprocdef;
  668. vmtentry : pvmtentry;
  669. i : longint;
  670. procname : TSymStr;
  671. {$ifdef vtentry}
  672. hs : string;
  673. {$endif vtentry}
  674. begin
  675. if not assigned(_class.VMTEntries) then
  676. exit;
  677. for i:=0 to _class.VMTEntries.Count-1 do
  678. begin
  679. vmtentry:=pvmtentry(_class.vmtentries[i]);
  680. vmtpd:=vmtentry^.procdef;
  681. { safety checks }
  682. if not(po_virtualmethod in vmtpd.procoptions) then
  683. internalerror(200611082);
  684. if vmtpd.extnumber<>i then
  685. internalerror(200611083);
  686. if (po_abstractmethod in vmtpd.procoptions) then
  687. begin
  688. procname:='FPC_ABSTRACTERROR';
  689. generate_abstract_stub(current_asmdata.AsmLists[al_procedures],vmtpd);
  690. end
  691. else if (cs_opt_remove_emtpy_proc in current_settings.optimizerswitches) and RedirectToEmpty(vmtpd) then
  692. procname:='FPC_EMPTYMETHOD'
  693. else if not wpoinfomanager.optimized_name_for_vmt(_class,vmtpd,procname) then
  694. procname:=vmtpd.mangledname;
  695. List.concat(Tai_const.createname(procname,AT_FUNCTION,0));
  696. {$ifdef vtentry}
  697. hs:='VTENTRY'+'_'+_class.vmt_mangledname+'$$'+tostr(_class.vmtmethodoffset(i) div sizeof(pint));
  698. current_asmdata.asmlists[al_globals].concat(tai_symbol.CreateName(hs,AT_DATA,0));
  699. {$endif vtentry}
  700. end;
  701. end;
  702. procedure TVMTWriter.writevmt;
  703. var
  704. methodnametable,intmessagetable,
  705. strmessagetable,classnamelabel,
  706. fieldtablelabel : tasmlabel;
  707. hs: string;
  708. {$ifdef WITHDMT}
  709. dmtlabel : tasmlabel;
  710. {$endif WITHDMT}
  711. interfacetable : tasmlabel;
  712. templist : TAsmList;
  713. begin
  714. {$ifdef WITHDMT}
  715. dmtlabel:=gendmt;
  716. {$endif WITHDMT}
  717. templist:=TAsmList.Create;
  718. strmessagetable:=nil;
  719. interfacetable:=nil;
  720. fieldtablelabel:=nil;
  721. methodnametable:=nil;
  722. intmessagetable:=nil;
  723. classnamelabel:=nil;
  724. { write tables for classes, this must be done before the actual
  725. class is written, because we need the labels defined }
  726. if is_class(_class) then
  727. begin
  728. { write class name }
  729. current_asmdata.getlabel(classnamelabel,alt_data);
  730. templist.concat(cai_align.create(const_align(sizeof(pint))));
  731. templist.concat(Tai_label.Create(classnamelabel));
  732. hs:=_class.RttiName;
  733. templist.concat(Tai_const.Create_8bit(length(hs)));
  734. templist.concat(Tai_string.Create(hs));
  735. { interface table }
  736. if _class.ImplementedInterfaces.count>0 then
  737. interfacetable:=intf_write_table(templist);
  738. methodnametable:=genpublishedmethodstable(templist);
  739. fieldtablelabel:=generate_field_table(templist);
  740. { generate message and dynamic tables }
  741. if (oo_has_msgstr in _class.objectoptions) then
  742. strmessagetable:=genstrmsgtab(templist);
  743. if (oo_has_msgint in _class.objectoptions) then
  744. intmessagetable:=genintmsgtab(templist);
  745. end;
  746. { write debug info }
  747. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  748. new_section(current_asmdata.asmlists[al_globals],sec_rodata,_class.vmt_mangledname,const_align(sizeof(pint)));
  749. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(_class.vmt_mangledname,AT_DATA,0));
  750. { determine the size with symtable.datasize, because }
  751. { size gives back 4 for classes }
  752. current_asmdata.asmlists[al_globals].concat(Tai_const.Create(aitconst_ptr,tObjectSymtable(_class.symtable).datasize));
  753. current_asmdata.asmlists[al_globals].concat(Tai_const.Create(aitconst_ptr,-int64(tObjectSymtable(_class.symtable).datasize)));
  754. {$ifdef WITHDMT}
  755. if _class.classtype=ct_object then
  756. begin
  757. if assigned(dmtlabel) then
  758. current_asmdata.asmlists[al_globals].concat(Tai_const_symbol.Create(dmtlabel)))
  759. else
  760. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_ptr(0));
  761. end;
  762. {$endif WITHDMT}
  763. { write pointer to parent VMT, this isn't implemented in TP }
  764. { but this is not used in FPC ? (PM) }
  765. { it's not used yet, but the delphi-operators as and is need it (FK) }
  766. { it is not written for parents that don't have any vmt !! }
  767. if assigned(_class.childof) and
  768. (oo_has_vmt in _class.childof.objectoptions) then
  769. current_asmdata.asmlists[al_globals].concat(Tai_const.Createname(_class.childof.vmt_mangledname,AT_DATA,0))
  770. else
  771. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_nil_dataptr);
  772. { write extended info for classes, for the order see rtl/inc/objpash.inc }
  773. if is_class(_class) then
  774. begin
  775. { pointer to class name string }
  776. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(classnamelabel));
  777. { pointer to dynamic table or nil }
  778. if (oo_has_msgint in _class.objectoptions) then
  779. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(intmessagetable))
  780. else
  781. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_nil_dataptr);
  782. { pointer to method table or nil }
  783. if assigned(methodnametable) then
  784. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(methodnametable))
  785. else
  786. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_nil_dataptr);
  787. { pointer to field table }
  788. if assigned(fieldtablelabel) then
  789. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(fieldtablelabel))
  790. else
  791. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_nil_dataptr);
  792. { pointer to type info of published section }
  793. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(RTTIWriter.get_rtti_label(_class,fullrtti)));
  794. { inittable for con-/destruction }
  795. if _class.members_need_inittable then
  796. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(RTTIWriter.get_rtti_label(_class,initrtti)))
  797. else
  798. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_nil_dataptr);
  799. { auto table }
  800. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_nil_dataptr);
  801. { interface table }
  802. if _class.ImplementedInterfaces.count>0 then
  803. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(interfacetable))
  804. else if _class.implements_any_interfaces then
  805. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_nil_dataptr)
  806. else
  807. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(current_asmdata.RefAsmSymbol('FPC_EMPTYINTF',AT_DATA)));
  808. { table for string messages }
  809. if (oo_has_msgstr in _class.objectoptions) then
  810. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(strmessagetable))
  811. else
  812. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_nil_dataptr);
  813. end;
  814. { write virtual methods }
  815. writevirtualmethods(current_asmdata.asmlists[al_globals]);
  816. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_nil_codeptr);
  817. { write the size of the VMT }
  818. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(_class.vmt_mangledname));
  819. {$ifdef vtentry}
  820. { write vtinherit symbol to notify the linker of the class inheritance tree }
  821. hs:='VTINHERIT'+'_'+_class.vmt_mangledname+'$$';
  822. if assigned(_class.childof) then
  823. hs:=hs+_class.childof.vmt_mangledname
  824. else
  825. hs:=hs+_class.vmt_mangledname;
  826. current_asmdata.asmlists[al_globals].concat(tai_symbol.CreateName(hs,AT_DATA,0));
  827. {$endif vtentry}
  828. if is_class(_class) then
  829. current_asmdata.asmlists[al_globals].concatlist(templist);
  830. templist.Free;
  831. end;
  832. procedure gen_intf_wrapper(list:TAsmList;_class:tobjectdef);
  833. var
  834. i,j : longint;
  835. tmps : string;
  836. pd : TProcdef;
  837. ImplIntf : TImplementedInterface;
  838. begin
  839. for i:=0 to _class.ImplementedInterfaces.count-1 do
  840. begin
  841. ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]);
  842. if (ImplIntf=ImplIntf.VtblImplIntf) and
  843. assigned(ImplIntf.ProcDefs) then
  844. begin
  845. for j:=0 to ImplIntf.ProcDefs.Count-1 do
  846. begin
  847. pd:=TProcdef(ImplIntf.ProcDefs[j]);
  848. { we don't track method calls via interfaces yet ->
  849. assume that every method called via an interface call
  850. is reachable for now }
  851. if (po_virtualmethod in pd.procoptions) and
  852. not is_objectpascal_helper(tprocdef(pd).struct) then
  853. tobjectdef(tprocdef(pd).struct).register_vmt_call(tprocdef(pd).extnumber);
  854. tmps:=make_mangledname('WRPR',_class.owner,_class.objname^+'_$_'+
  855. ImplIntf.IntfDef.objname^+'_$_'+tostr(j)+'_$_'+pd.mangledname);
  856. { create wrapper code }
  857. new_section(list,sec_code,tmps,target_info.alignment.procalign);
  858. hlcg.init_register_allocators;
  859. cg.g_intf_wrapper(list,pd,tmps,ImplIntf.ioffset);
  860. hlcg.done_register_allocators;
  861. end;
  862. end;
  863. end;
  864. end;
  865. procedure do_write_persistent_type_info(st:tsymtable;is_global:boolean);
  866. var
  867. i : longint;
  868. def : tdef;
  869. vmtwriter : TVMTWriter;
  870. begin
  871. if not CVMTWriter.use_vmt_writer then
  872. exit;
  873. for i:=0 to st.DefList.Count-1 do
  874. begin
  875. def:=tdef(st.DefList[i]);
  876. { skip generics and generic constraints }
  877. if [df_generic,df_genconstraint]*def.defoptions<>[] then
  878. continue;
  879. case def.typ of
  880. recorddef :
  881. do_write_persistent_type_info(trecorddef(def).symtable,is_global);
  882. objectdef :
  883. begin
  884. { Skip forward defs }
  885. if (oo_is_forward in tobjectdef(def).objectoptions) then
  886. continue;
  887. do_write_persistent_type_info(tobjectdef(def).symtable,is_global);
  888. { Write also VMT if not done yet }
  889. if not(ds_vmt_written in def.defstates) then
  890. begin
  891. vmtwriter:=CVMTWriter.create(tobjectdef(def));
  892. if is_interface(tobjectdef(def)) then
  893. vmtwriter.writeinterfaceids(current_asmdata.AsmLists[al_globals]);
  894. if (oo_has_vmt in tobjectdef(def).objectoptions) then
  895. vmtwriter.writevmt;
  896. vmtwriter.free;
  897. include(def.defstates,ds_vmt_written);
  898. end;
  899. if is_class(def) then
  900. gen_intf_wrapper(current_asmdata.asmlists[al_globals],tobjectdef(def));
  901. end;
  902. procdef :
  903. begin
  904. if assigned(tprocdef(def).localst) and
  905. (tprocdef(def).localst.symtabletype=localsymtable) then
  906. do_write_persistent_type_info(tprocdef(def).localst,false);
  907. if assigned(tprocdef(def).parast) then
  908. do_write_persistent_type_info(tprocdef(def).parast,false);
  909. end;
  910. end;
  911. { generate always persistent tables for types in the interface so it can
  912. be reused in other units and give always the same pointer location. }
  913. { Init }
  914. if (
  915. assigned(def.typesym) and
  916. is_global and
  917. not is_objc_class_or_protocol(def)
  918. ) or
  919. is_managed_type(def) or
  920. (ds_init_table_used in def.defstates) then
  921. RTTIWriter.write_rtti(def,initrtti);
  922. { RTTI }
  923. if (
  924. assigned(def.typesym) and
  925. is_global and
  926. not is_objc_class_or_protocol(def)
  927. ) or
  928. (ds_rtti_table_used in def.defstates) then
  929. RTTIWriter.write_rtti(def,fullrtti);
  930. end;
  931. end;
  932. procedure write_persistent_type_info(st:tsymtable;is_global:boolean);
  933. begin
  934. create_hlcodegen;
  935. do_write_persistent_type_info(st,is_global);
  936. destroy_hlcodegen;
  937. end;
  938. end.