ncgvmt.pas 39 KB

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