ncgvmt.pas 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057
  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(const_align(sizeof(pint))));
  217. list.concat(Tai_const.Create_sym(p^.nl));
  218. list.concat(cai_align.create(const_align(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(const_align(sizeof(pint))));
  237. list.concat(Tai_label.Create(result));
  238. list.concat(cai_align.create(const_align(sizeof(longint))));
  239. list.concat(Tai_const.Create_32bit(count));
  240. list.concat(cai_align.create(const_align(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(const_align(sizeof(longint))));
  253. list.concat(Tai_const.Create_32bit(p^.data.messageinf.i));
  254. list.concat(cai_align.create(const_align(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(const_align(sizeof(pint))));
  271. list.concat(Tai_label.Create(r));
  272. genintmsgtab:=r;
  273. list.concat(cai_align.create(const_align(sizeof(longint))));
  274. list.concat(Tai_const.Create_32bit(count));
  275. list.concat(cai_align.create(const_align(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. offsetsym : tfieldvarsym;
  714. begin
  715. {$ifdef WITHDMT}
  716. dmtlabel:=gendmt;
  717. {$endif WITHDMT}
  718. templist:=TAsmList.Create;
  719. strmessagetable:=nil;
  720. interfacetable:=nil;
  721. fieldtablelabel:=nil;
  722. methodnametable:=nil;
  723. intmessagetable:=nil;
  724. classnamelabel:=nil;
  725. { write tables for classes, this must be done before the actual
  726. class is written, because we need the labels defined }
  727. if is_class(_class) then
  728. begin
  729. { write class name }
  730. current_asmdata.getlabel(classnamelabel,alt_data);
  731. templist.concat(cai_align.create(const_align(sizeof(pint))));
  732. templist.concat(Tai_label.Create(classnamelabel));
  733. hs:=_class.RttiName;
  734. templist.concat(Tai_const.Create_8bit(length(hs)));
  735. templist.concat(Tai_string.Create(hs));
  736. { interface table }
  737. if _class.ImplementedInterfaces.count>0 then
  738. interfacetable:=intf_write_table(templist);
  739. methodnametable:=genpublishedmethodstable(templist);
  740. fieldtablelabel:=generate_field_table(templist);
  741. { generate message and dynamic tables }
  742. if (oo_has_msgstr in _class.objectoptions) then
  743. strmessagetable:=genstrmsgtab(templist);
  744. if (oo_has_msgint in _class.objectoptions) then
  745. intmessagetable:=genintmsgtab(templist);
  746. end;
  747. { write debug info }
  748. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  749. new_section(current_asmdata.asmlists[al_globals],sec_rodata,_class.vmt_mangledname,const_align(sizeof(pint)));
  750. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(_class.vmt_mangledname,AT_DATA,0));
  751. { determine the size with symtable.datasize, because }
  752. { size gives back 4 for classes }
  753. current_asmdata.asmlists[al_globals].concat(Tai_const.Create(aitconst_ptr,tObjectSymtable(_class.symtable).datasize));
  754. current_asmdata.asmlists[al_globals].concat(Tai_const.Create(aitconst_ptr,-int64(tObjectSymtable(_class.symtable).datasize)));
  755. {$ifdef WITHDMT}
  756. if _class.classtype=ct_object then
  757. begin
  758. if assigned(dmtlabel) then
  759. current_asmdata.asmlists[al_globals].concat(Tai_const_symbol.Create(dmtlabel)))
  760. else
  761. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_ptr(0));
  762. end;
  763. {$endif WITHDMT}
  764. { write pointer to parent VMT, this isn't implemented in TP }
  765. { but this is not used in FPC ? (PM) }
  766. { it's not used yet, but the delphi-operators as and is need it (FK) }
  767. { it is not written for parents that don't have any vmt !! }
  768. if assigned(_class.childof) and
  769. (oo_has_vmt in _class.childof.objectoptions) then
  770. current_asmdata.asmlists[al_globals].concat(Tai_const.Createname(_class.childof.vmt_mangledname,AT_DATA,0))
  771. else
  772. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_nil_dataptr);
  773. { write extended info for classes, for the order see rtl/inc/objpash.inc }
  774. if is_class(_class) then
  775. begin
  776. { pointer to class name string }
  777. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(classnamelabel));
  778. { pointer to dynamic table or nil }
  779. if (oo_has_msgint in _class.objectoptions) then
  780. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(intmessagetable))
  781. else
  782. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_nil_dataptr);
  783. { pointer to method table or nil }
  784. if assigned(methodnametable) then
  785. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(methodnametable))
  786. else
  787. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_nil_dataptr);
  788. { pointer to field table }
  789. if assigned(fieldtablelabel) then
  790. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(fieldtablelabel))
  791. else
  792. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_nil_dataptr);
  793. { pointer to type info of published section }
  794. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(RTTIWriter.get_rtti_label(_class,fullrtti)));
  795. { inittable for con-/destruction }
  796. if _class.members_need_inittable then
  797. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(RTTIWriter.get_rtti_label(_class,initrtti)))
  798. else
  799. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_nil_dataptr);
  800. { auto table }
  801. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_nil_dataptr);
  802. { interface table }
  803. if _class.ImplementedInterfaces.count>0 then
  804. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(interfacetable))
  805. else if _class.implements_any_interfaces then
  806. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_nil_dataptr)
  807. else
  808. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(current_asmdata.RefAsmSymbol('FPC_EMPTYINTF',AT_DATA)));
  809. { table for string messages }
  810. if (oo_has_msgstr in _class.objectoptions) then
  811. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(strmessagetable))
  812. else
  813. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_nil_dataptr);
  814. if oo_is_reference_counted in _class.objectoptions then
  815. begin
  816. offsetsym:=tfieldvarsym(_class.refcount_field);
  817. if not assigned(offsetsym) or (offsetsym.typ<>fieldvarsym) then
  818. internalerror(2014101201);
  819. current_asmdata.asmlists[al_globals].concat(Tai_const.Create(aitconst_ptr,offsetsym.fieldoffset));
  820. end
  821. else
  822. current_asmdata.asmlists[al_globals].concat(Tai_const.Create(aitconst_ptr,0));
  823. end;
  824. { write virtual methods }
  825. writevirtualmethods(current_asmdata.asmlists[al_globals]);
  826. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_nil_codeptr);
  827. { write the size of the VMT }
  828. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(_class.vmt_mangledname));
  829. {$ifdef vtentry}
  830. { write vtinherit symbol to notify the linker of the class inheritance tree }
  831. hs:='VTINHERIT'+'_'+_class.vmt_mangledname+'$$';
  832. if assigned(_class.childof) then
  833. hs:=hs+_class.childof.vmt_mangledname
  834. else
  835. hs:=hs+_class.vmt_mangledname;
  836. current_asmdata.asmlists[al_globals].concat(tai_symbol.CreateName(hs,AT_DATA,0));
  837. {$endif vtentry}
  838. if is_class(_class) then
  839. current_asmdata.asmlists[al_globals].concatlist(templist);
  840. templist.Free;
  841. end;
  842. procedure gen_intf_wrapper(list:TAsmList;_class:tobjectdef);
  843. var
  844. i,j : longint;
  845. tmps : string;
  846. pd : TProcdef;
  847. ImplIntf : TImplementedInterface;
  848. begin
  849. for i:=0 to _class.ImplementedInterfaces.count-1 do
  850. begin
  851. ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]);
  852. if (ImplIntf=ImplIntf.VtblImplIntf) and
  853. assigned(ImplIntf.ProcDefs) then
  854. begin
  855. for j:=0 to ImplIntf.ProcDefs.Count-1 do
  856. begin
  857. pd:=TProcdef(ImplIntf.ProcDefs[j]);
  858. { we don't track method calls via interfaces yet ->
  859. assume that every method called via an interface call
  860. is reachable for now }
  861. if (po_virtualmethod in pd.procoptions) and
  862. not is_objectpascal_helper(tprocdef(pd).struct) then
  863. tobjectdef(tprocdef(pd).struct).register_vmt_call(tprocdef(pd).extnumber);
  864. tmps:=make_mangledname('WRPR',_class.owner,_class.objname^+'_$_'+
  865. ImplIntf.IntfDef.objname^+'_$_'+tostr(j)+'_$_'+pd.mangledname);
  866. { create wrapper code }
  867. new_section(list,sec_code,tmps,target_info.alignment.procalign);
  868. hlcg.init_register_allocators;
  869. cg.g_intf_wrapper(list,pd,tmps,ImplIntf.ioffset);
  870. hlcg.done_register_allocators;
  871. end;
  872. end;
  873. end;
  874. end;
  875. procedure do_write_persistent_type_info(st:tsymtable;is_global:boolean);
  876. var
  877. i : longint;
  878. def : tdef;
  879. vmtwriter : TVMTWriter;
  880. begin
  881. if not CVMTWriter.use_vmt_writer then
  882. exit;
  883. for i:=0 to st.DefList.Count-1 do
  884. begin
  885. def:=tdef(st.DefList[i]);
  886. case def.typ of
  887. recorddef :
  888. do_write_persistent_type_info(trecorddef(def).symtable,is_global);
  889. objectdef :
  890. begin
  891. { Skip generics and forward defs }
  892. if ([df_generic,df_genconstraint]*def.defoptions<>[]) or
  893. (oo_is_forward in tobjectdef(def).objectoptions) then
  894. continue;
  895. do_write_persistent_type_info(tobjectdef(def).symtable,is_global);
  896. { Write also VMT if not done yet }
  897. if not(ds_vmt_written in def.defstates) then
  898. begin
  899. vmtwriter:=CVMTWriter.create(tobjectdef(def));
  900. if is_interface(tobjectdef(def)) then
  901. vmtwriter.writeinterfaceids(current_asmdata.AsmLists[al_globals]);
  902. if (oo_has_vmt in tobjectdef(def).objectoptions) then
  903. vmtwriter.writevmt;
  904. vmtwriter.free;
  905. include(def.defstates,ds_vmt_written);
  906. end;
  907. if is_class(def) then
  908. gen_intf_wrapper(current_asmdata.asmlists[al_globals],tobjectdef(def));
  909. end;
  910. procdef :
  911. begin
  912. if assigned(tprocdef(def).localst) and
  913. (tprocdef(def).localst.symtabletype=localsymtable) then
  914. do_write_persistent_type_info(tprocdef(def).localst,false);
  915. if assigned(tprocdef(def).parast) then
  916. do_write_persistent_type_info(tprocdef(def).parast,false);
  917. end;
  918. end;
  919. { generate always persistent tables for types in the interface so it can
  920. be reused in other units and give always the same pointer location. }
  921. { Init }
  922. if (
  923. assigned(def.typesym) and
  924. is_global and
  925. not is_objc_class_or_protocol(def)
  926. ) or
  927. is_managed_type(def) or
  928. (ds_init_table_used in def.defstates) then
  929. RTTIWriter.write_rtti(def,initrtti);
  930. { RTTI }
  931. if (
  932. assigned(def.typesym) and
  933. is_global and
  934. not is_objc_class_or_protocol(def)
  935. ) or
  936. (ds_rtti_table_used in def.defstates) then
  937. RTTIWriter.write_rtti(def,fullrtti);
  938. end;
  939. end;
  940. procedure write_persistent_type_info(st:tsymtable;is_global:boolean);
  941. begin
  942. create_hlcodegen;
  943. do_write_persistent_type_info(st,is_global);
  944. destroy_hlcodegen;
  945. end;
  946. end.