ncgvmt.pas 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047
  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. 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. case def.typ of
  877. recorddef :
  878. do_write_persistent_type_info(trecorddef(def).symtable,is_global);
  879. objectdef :
  880. begin
  881. { Skip generics and forward defs }
  882. if ([df_generic,df_genconstraint]*def.defoptions<>[]) or
  883. (oo_is_forward in tobjectdef(def).objectoptions) then
  884. continue;
  885. do_write_persistent_type_info(tobjectdef(def).symtable,is_global);
  886. { Write also VMT if not done yet }
  887. if not(ds_vmt_written in def.defstates) then
  888. begin
  889. vmtwriter:=CVMTWriter.create(tobjectdef(def));
  890. if is_interface(tobjectdef(def)) then
  891. vmtwriter.writeinterfaceids(current_asmdata.AsmLists[al_globals]);
  892. if (oo_has_vmt in tobjectdef(def).objectoptions) then
  893. vmtwriter.writevmt;
  894. vmtwriter.free;
  895. include(def.defstates,ds_vmt_written);
  896. end;
  897. if is_class(def) then
  898. gen_intf_wrapper(current_asmdata.asmlists[al_globals],tobjectdef(def));
  899. end;
  900. procdef :
  901. begin
  902. if assigned(tprocdef(def).localst) and
  903. (tprocdef(def).localst.symtabletype=localsymtable) then
  904. do_write_persistent_type_info(tprocdef(def).localst,false);
  905. if assigned(tprocdef(def).parast) then
  906. do_write_persistent_type_info(tprocdef(def).parast,false);
  907. end;
  908. end;
  909. { generate always persistent tables for types in the interface so it can
  910. be reused in other units and give always the same pointer location. }
  911. { Init }
  912. if (
  913. assigned(def.typesym) and
  914. is_global and
  915. not is_objc_class_or_protocol(def)
  916. ) or
  917. is_managed_type(def) or
  918. (ds_init_table_used in def.defstates) then
  919. RTTIWriter.write_rtti(def,initrtti);
  920. { RTTI }
  921. if (
  922. assigned(def.typesym) and
  923. is_global and
  924. not is_objc_class_or_protocol(def)
  925. ) or
  926. (ds_rtti_table_used in def.defstates) then
  927. RTTIWriter.write_rtti(def,fullrtti);
  928. end;
  929. end;
  930. procedure write_persistent_type_info(st:tsymtable;is_global:boolean);
  931. begin
  932. create_hlcodegen;
  933. do_write_persistent_type_info(st,is_global);
  934. destroy_hlcodegen;
  935. end;
  936. end.