nobj.pas 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Routines for the code generation of data structures
  4. like VMT, Messages, VTables, Interfaces descs
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit nobj;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. cutils,cclasses,
  23. globtype,
  24. symdef,symsym,
  25. aasmbase,aasmtai,aasmdata
  26. ;
  27. type
  28. pprocdeftree = ^tprocdeftree;
  29. tprocdeftree = record
  30. data : tprocdef;
  31. nl : tasmlabel;
  32. l,r : pprocdeftree;
  33. end;
  34. pprocdefcoll = ^tprocdefcoll;
  35. tprocdefcoll = record
  36. data : tprocdef;
  37. hidden : boolean;
  38. visible : boolean;
  39. next : pprocdefcoll;
  40. end;
  41. pvmtentry = ^tvmtentry;
  42. tvmtentry = record
  43. speedvalue : cardinal;
  44. name : pstring;
  45. firstprocdef : pprocdefcoll;
  46. next : pvmtentry;
  47. end;
  48. tclassheader=class
  49. private
  50. _Class : tobjectdef;
  51. private
  52. { message tables }
  53. root : pprocdeftree;
  54. procedure disposeprocdeftree(p : pprocdeftree);
  55. procedure insertmsgint(p : tnamedindexitem;arg:pointer);
  56. procedure insertmsgstr(p : tnamedindexitem;arg:pointer);
  57. procedure insertint(p : pprocdeftree;var at : pprocdeftree;var count:longint);
  58. procedure insertstr(p : pprocdeftree;var at : pprocdeftree;var count:longint);
  59. procedure writenames(p : pprocdeftree);
  60. procedure writeintentry(p : pprocdeftree);
  61. procedure writestrentry(p : pprocdeftree);
  62. {$ifdef WITHDMT}
  63. private
  64. { dmt }
  65. procedure insertdmtentry(p : tnamedindexitem;arg:pointer);
  66. procedure writedmtindexentry(p : pprocdeftree);
  67. procedure writedmtaddressentry(p : pprocdeftree);
  68. {$endif}
  69. private
  70. { published methods }
  71. procedure do_count_published_methods(p : tnamedindexitem;arg:pointer);
  72. procedure do_gen_published_methods(p : tnamedindexitem;arg:pointer);
  73. private
  74. { vmt }
  75. firstvmtentry : pvmtentry;
  76. nextvirtnumber : integer;
  77. has_constructor,
  78. has_virtual_method : boolean;
  79. procedure newdefentry(vmtentry:pvmtentry;pd:tprocdef;is_visible:boolean);
  80. function newvmtentry(sym:tprocsym):pvmtentry;
  81. procedure eachsym(sym : tnamedindexitem;arg:pointer);
  82. procedure disposevmttree;
  83. procedure writevirtualmethods(List:TAsmList);
  84. private
  85. { interface tables }
  86. function gintfgetvtbllabelname(intfindex: integer): string;
  87. procedure gintfcreatevtbl(intfindex: integer; rawdata: TAsmList);
  88. procedure gintfgenentry(intfindex, contintfindex: integer; rawdata: TAsmList);
  89. procedure gintfoptimizevtbls;
  90. procedure gintfwritedata;
  91. function gintfgetcprocdef(proc: tprocdef;const name: string): tprocdef;
  92. procedure gintfdoonintf(intf: tobjectdef; intfindex: longint);
  93. procedure gintfwalkdowninterface(intf: tobjectdef; intfindex: longint);
  94. public
  95. constructor create(c:tobjectdef);
  96. destructor destroy;override;
  97. { generates the message tables for a class }
  98. function genstrmsgtab : tasmlabel;
  99. function genintmsgtab : tasmlabel;
  100. function genpublishedmethodstable : tasmlabel;
  101. { generates a VMT entries }
  102. procedure genvmt;
  103. {$ifdef WITHDMT}
  104. { generates a DMT for _class }
  105. function gendmt : tasmlabel;
  106. {$endif WITHDMT}
  107. { interfaces }
  108. function genintftable: tasmlabel;
  109. { write the VMT to al_globals }
  110. procedure writevmt;
  111. procedure writeinterfaceids;
  112. end;
  113. implementation
  114. uses
  115. strings,
  116. globals,verbose,systems,
  117. symtable,symconst,symtype,defcmp,defutil,
  118. dbgbase
  119. ;
  120. {*****************************************************************************
  121. TClassHeader
  122. *****************************************************************************}
  123. constructor tclassheader.create(c:tobjectdef);
  124. begin
  125. inherited Create;
  126. _Class:=c;
  127. end;
  128. destructor tclassheader.destroy;
  129. begin
  130. disposevmttree;
  131. end;
  132. {**************************************
  133. Message Tables
  134. **************************************}
  135. procedure tclassheader.disposeprocdeftree(p : pprocdeftree);
  136. begin
  137. if assigned(p^.l) then
  138. disposeprocdeftree(p^.l);
  139. if assigned(p^.r) then
  140. disposeprocdeftree(p^.r);
  141. dispose(p);
  142. end;
  143. procedure tclassheader.insertint(p : pprocdeftree;var at : pprocdeftree;var count:longint);
  144. begin
  145. if at=nil then
  146. begin
  147. at:=p;
  148. inc(count);
  149. end
  150. else
  151. begin
  152. if p^.data.messageinf.i<at^.data.messageinf.i then
  153. insertint(p,at^.l,count)
  154. else if p^.data.messageinf.i>at^.data.messageinf.i then
  155. insertint(p,at^.r,count)
  156. else
  157. Message1(parser_e_duplicate_message_label,tostr(p^.data.messageinf.i));
  158. end;
  159. end;
  160. procedure tclassheader.insertstr(p : pprocdeftree;var at : pprocdeftree;var count:longint);
  161. var
  162. i : integer;
  163. begin
  164. if at=nil then
  165. begin
  166. at:=p;
  167. inc(count);
  168. end
  169. else
  170. begin
  171. i:=CompareStr(p^.data.messageinf.str^,at^.data.messageinf.str^);
  172. if i<0 then
  173. insertstr(p,at^.l,count)
  174. else if i>0 then
  175. insertstr(p,at^.r,count)
  176. else
  177. Message1(parser_e_duplicate_message_label,p^.data.messageinf.str^);
  178. end;
  179. end;
  180. procedure tclassheader.insertmsgint(p : tnamedindexitem;arg:pointer);
  181. var
  182. i : cardinal;
  183. def: Tprocdef;
  184. pt : pprocdeftree;
  185. begin
  186. if tsym(p).typ=procsym then
  187. for i:=1 to Tprocsym(p).procdef_count do
  188. begin
  189. def:=Tprocsym(p).procdef[i];
  190. if po_msgint in def.procoptions then
  191. begin
  192. new(pt);
  193. pt^.data:=def;
  194. pt^.l:=nil;
  195. pt^.r:=nil;
  196. insertint(pt,root,plongint(arg)^);
  197. end;
  198. end;
  199. end;
  200. procedure tclassheader.insertmsgstr(p : tnamedindexitem;arg:pointer);
  201. var
  202. i : cardinal;
  203. def: Tprocdef;
  204. pt : pprocdeftree;
  205. begin
  206. if tsym(p).typ=procsym then
  207. for i:=1 to Tprocsym(p).procdef_count do
  208. begin
  209. def:=Tprocsym(p).procdef[i];
  210. if po_msgstr in def.procoptions then
  211. begin
  212. new(pt);
  213. pt^.data:=def;
  214. pt^.l:=nil;
  215. pt^.r:=nil;
  216. insertstr(pt,root,plongint(arg)^);
  217. end;
  218. end;
  219. end;
  220. procedure tclassheader.writenames(p : pprocdeftree);
  221. var
  222. ca : pchar;
  223. len : longint;
  224. begin
  225. current_asmdata.getdatalabel(p^.nl);
  226. if assigned(p^.l) then
  227. writenames(p^.l);
  228. current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(aint))));
  229. current_asmdata.asmlists[al_globals].concat(Tai_label.Create(p^.nl));
  230. len:=length(p^.data.messageinf.str^);
  231. current_asmdata.asmlists[al_globals].concat(tai_const.create_8bit(len));
  232. getmem(ca,len+1);
  233. move(p^.data.messageinf.str[1],ca^,len);
  234. ca[len]:=#0;
  235. current_asmdata.asmlists[al_globals].concat(Tai_string.Create_pchar(ca,len));
  236. if assigned(p^.r) then
  237. writenames(p^.r);
  238. end;
  239. procedure tclassheader.writestrentry(p : pprocdeftree);
  240. begin
  241. if assigned(p^.l) then
  242. writestrentry(p^.l);
  243. { write name label }
  244. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(p^.nl));
  245. current_asmdata.asmlists[al_globals].concat(Tai_const.Createname(p^.data.mangledname,0));
  246. if assigned(p^.r) then
  247. writestrentry(p^.r);
  248. end;
  249. function tclassheader.genstrmsgtab : tasmlabel;
  250. var
  251. r : tasmlabel;
  252. count : aint;
  253. begin
  254. root:=nil;
  255. count:=0;
  256. { insert all message handlers into a tree, sorted by name }
  257. _class.symtable.foreach(@insertmsgstr,@count);
  258. { write all names }
  259. if assigned(root) then
  260. writenames(root);
  261. { now start writing of the message string table }
  262. current_asmdata.getdatalabel(r);
  263. current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(aint))));
  264. current_asmdata.asmlists[al_globals].concat(Tai_label.Create(r));
  265. genstrmsgtab:=r;
  266. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_aint(count));
  267. if assigned(root) then
  268. begin
  269. writestrentry(root);
  270. disposeprocdeftree(root);
  271. end;
  272. end;
  273. procedure tclassheader.writeintentry(p : pprocdeftree);
  274. begin
  275. if assigned(p^.l) then
  276. writeintentry(p^.l);
  277. { write name label }
  278. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_32bit(p^.data.messageinf.i));
  279. current_asmdata.asmlists[al_globals].concat(Tai_const.Createname(p^.data.mangledname,0));
  280. if assigned(p^.r) then
  281. writeintentry(p^.r);
  282. end;
  283. function tclassheader.genintmsgtab : tasmlabel;
  284. var
  285. r : tasmlabel;
  286. count : longint;
  287. begin
  288. root:=nil;
  289. count:=0;
  290. { insert all message handlers into a tree, sorted by name }
  291. _class.symtable.foreach(@insertmsgint,@count);
  292. { now start writing of the message string table }
  293. current_asmdata.getdatalabel(r);
  294. current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(aint))));
  295. current_asmdata.asmlists[al_globals].concat(Tai_label.Create(r));
  296. genintmsgtab:=r;
  297. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_32bit(count));
  298. if assigned(root) then
  299. begin
  300. writeintentry(root);
  301. disposeprocdeftree(root);
  302. end;
  303. end;
  304. {$ifdef WITHDMT}
  305. {**************************************
  306. DMT
  307. **************************************}
  308. procedure tclassheader.insertdmtentry(p : tnamedindexitem;arg:pointer);
  309. var
  310. hp : tprocdef;
  311. pt : pprocdeftree;
  312. begin
  313. if tsym(p).typ=procsym then
  314. begin
  315. hp:=tprocsym(p).definition;
  316. while assigned(hp) do
  317. begin
  318. if (po_msgint in hp.procoptions) then
  319. begin
  320. new(pt);
  321. pt^.p:=hp;
  322. pt^.l:=nil;
  323. pt^.r:=nil;
  324. insertint(pt,root);
  325. end;
  326. hp:=hp.nextoverloaded;
  327. end;
  328. end;
  329. end;
  330. procedure tclassheader.writedmtindexentry(p : pprocdeftree);
  331. begin
  332. if assigned(p^.l) then
  333. writedmtindexentry(p^.l);
  334. al_globals.concat(Tai_const.Create_32bit(p^.data.messageinf.i));
  335. if assigned(p^.r) then
  336. writedmtindexentry(p^.r);
  337. end;
  338. procedure tclassheader.writedmtaddressentry(p : pprocdeftree);
  339. begin
  340. if assigned(p^.l) then
  341. writedmtaddressentry(p^.l);
  342. al_globals.concat(Tai_const_symbol.Createname(p^.data.mangledname,0));
  343. if assigned(p^.r) then
  344. writedmtaddressentry(p^.r);
  345. end;
  346. function tclassheader.gendmt : tasmlabel;
  347. var
  348. r : tasmlabel;
  349. begin
  350. root:=nil;
  351. count:=0;
  352. gendmt:=nil;
  353. { insert all message handlers into a tree, sorted by number }
  354. _class.symtable.foreach(insertdmtentry);
  355. if count>0 then
  356. begin
  357. current_asmdata.getdatalabel(r);
  358. gendmt:=r;
  359. al_globals.concat(cai_align.create(const_align(sizeof(aint))));
  360. al_globals.concat(Tai_label.Create(r));
  361. { entries for caching }
  362. al_globals.concat(Tai_const.Create_ptr(0));
  363. al_globals.concat(Tai_const.Create_ptr(0));
  364. al_globals.concat(Tai_const.Create_32bit(count));
  365. if assigned(root) then
  366. begin
  367. writedmtindexentry(root);
  368. writedmtaddressentry(root);
  369. disposeprocdeftree(root);
  370. end;
  371. end;
  372. end;
  373. {$endif WITHDMT}
  374. {**************************************
  375. Published Methods
  376. **************************************}
  377. procedure tclassheader.do_count_published_methods(p : tnamedindexitem;arg:pointer);
  378. var
  379. i : longint;
  380. pd : tprocdef;
  381. begin
  382. if (tsym(p).typ=procsym) then
  383. begin
  384. for i:=1 to tprocsym(p).procdef_count do
  385. begin
  386. pd:=tprocsym(p).procdef[i];
  387. if (pd.procsym=tsym(p)) and
  388. (sp_published in pd.symoptions) then
  389. inc(plongint(arg)^);
  390. end;
  391. end;
  392. end;
  393. procedure tclassheader.do_gen_published_methods(p : tnamedindexitem;arg:pointer);
  394. var
  395. i : longint;
  396. l : tasmlabel;
  397. pd : tprocdef;
  398. begin
  399. if (tsym(p).typ=procsym) then
  400. begin
  401. for i:=1 to tprocsym(p).procdef_count do
  402. begin
  403. pd:=tprocsym(p).procdef[i];
  404. if (pd.procsym=tsym(p)) and
  405. (sp_published in pd.symoptions) then
  406. begin
  407. current_asmdata.getdatalabel(l);
  408. current_asmdata.asmlists[al_typedconsts].concat(cai_align.create(const_align(sizeof(aint))));
  409. current_asmdata.asmlists[al_typedconsts].concat(Tai_label.Create(l));
  410. current_asmdata.asmlists[al_typedconsts].concat(Tai_const.Create_8bit(length(tsym(p).realname)));
  411. current_asmdata.asmlists[al_typedconsts].concat(Tai_string.Create(tsym(p).realname));
  412. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(l));
  413. if po_abstractmethod in pd.procoptions then
  414. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil))
  415. else
  416. current_asmdata.asmlists[al_globals].concat(Tai_const.Createname(pd.mangledname,0));
  417. end;
  418. end;
  419. end;
  420. end;
  421. function tclassheader.genpublishedmethodstable : tasmlabel;
  422. var
  423. l : tasmlabel;
  424. count : longint;
  425. begin
  426. count:=0;
  427. _class.symtable.foreach(@do_count_published_methods,@count);
  428. if count>0 then
  429. begin
  430. current_asmdata.getdatalabel(l);
  431. current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(aint))));
  432. current_asmdata.asmlists[al_globals].concat(Tai_label.Create(l));
  433. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_32bit(count));
  434. _class.symtable.foreach(@do_gen_published_methods,nil);
  435. genpublishedmethodstable:=l;
  436. end
  437. else
  438. genpublishedmethodstable:=nil;
  439. end;
  440. {**************************************
  441. VMT
  442. **************************************}
  443. procedure tclassheader.newdefentry(vmtentry:pvmtentry;pd:tprocdef;is_visible:boolean);
  444. var
  445. procdefcoll : pprocdefcoll;
  446. begin
  447. if (_class=pd._class) then
  448. begin
  449. { new entry is needed, override was not possible }
  450. if (po_overridingmethod in pd.procoptions) then
  451. MessagePos1(pd.fileinfo,parser_e_nothing_to_be_overridden,pd.fullprocname(false));
  452. { check that all methods have overload directive }
  453. if not(m_fpc in aktmodeswitches) then
  454. begin
  455. procdefcoll:=vmtentry^.firstprocdef;
  456. while assigned(procdefcoll) do
  457. begin
  458. if (procdefcoll^.data._class=pd._class) and
  459. ((po_overload in pd.procoptions)<>(po_overload in procdefcoll^.data.procoptions)) then
  460. begin
  461. MessagePos1(pd.fileinfo,parser_e_no_overload_for_all_procs,pd.procsym.realname);
  462. { recover }
  463. include(procdefcoll^.data.procoptions,po_overload);
  464. include(pd.procoptions,po_overload);
  465. end;
  466. procdefcoll:=procdefcoll^.next;
  467. end;
  468. end;
  469. end;
  470. { generate new entry }
  471. new(procdefcoll);
  472. procdefcoll^.data:=pd;
  473. procdefcoll^.hidden:=false;
  474. procdefcoll^.visible:=is_visible;
  475. procdefcoll^.next:=vmtentry^.firstprocdef;
  476. vmtentry^.firstprocdef:=procdefcoll;
  477. { give virtual method a number }
  478. if (po_virtualmethod in pd.procoptions) then
  479. begin
  480. pd.extnumber:=nextvirtnumber;
  481. inc(nextvirtnumber);
  482. has_virtual_method:=true;
  483. end;
  484. if (pd.proctypeoption=potype_constructor) then
  485. has_constructor:=true;
  486. end;
  487. function tclassheader.newvmtentry(sym:tprocsym):pvmtentry;
  488. begin
  489. { generate new vmtentry }
  490. new(result);
  491. result^.speedvalue:=sym.speedvalue;
  492. result^.name:=stringdup(sym.name);
  493. result^.next:=firstvmtentry;
  494. result^.firstprocdef:=nil;
  495. firstvmtentry:=result;
  496. end;
  497. procedure tclassheader.eachsym(sym : tnamedindexitem;arg:pointer);
  498. const
  499. po_comp = [po_classmethod,po_virtualmethod,po_staticmethod,po_interrupt,po_iocheck,po_msgstr,po_msgint,
  500. po_exports,po_varargs,po_explicitparaloc,po_nostackframe];
  501. label
  502. handlenextdef;
  503. var
  504. pd : tprocdef;
  505. i : cardinal;
  506. is_visible,
  507. hasoverloads,
  508. pdoverload : boolean;
  509. procdefcoll : pprocdefcoll;
  510. vmtentry : pvmtentry;
  511. _name : string;
  512. _speed : cardinal;
  513. begin
  514. if (tsym(sym).typ<>procsym) then
  515. exit;
  516. { check the current list of symbols }
  517. _name:=sym.name;
  518. _speed:=sym.speedvalue;
  519. vmtentry:=firstvmtentry;
  520. while assigned(vmtentry) do
  521. begin
  522. { does the symbol already exist in the list? First
  523. compare speedvalue before doing the string compare to
  524. speed it up a little }
  525. if (_speed=vmtentry^.speedvalue) and
  526. (_name=vmtentry^.name^) then
  527. begin
  528. hasoverloads:=(Tprocsym(sym).procdef_count>1);
  529. { walk through all defs of the symbol }
  530. for i:=1 to Tprocsym(sym).procdef_count do
  531. begin
  532. pd:=Tprocsym(sym).procdef[i];
  533. { is this procdef visible from the class that we are
  534. generating. This will be used to hide the other procdefs.
  535. When the symbol is not visible we don't hide the other
  536. procdefs, because they can be reused in the next class.
  537. The check to skip the invisible methods that are in the
  538. list is futher down in the code }
  539. is_visible:=pd.is_visible_for_object(_class,nil);
  540. if pd.procsym=sym then
  541. begin
  542. pdoverload:=(po_overload in pd.procoptions);
  543. { compare with all stored definitions }
  544. procdefcoll:=vmtentry^.firstprocdef;
  545. while assigned(procdefcoll) do
  546. begin
  547. { compare only if the definition is not hidden }
  548. if not procdefcoll^.hidden then
  549. begin
  550. { check if one of the two methods has virtual }
  551. if (po_virtualmethod in procdefcoll^.data.procoptions) or
  552. (po_virtualmethod in pd.procoptions) then
  553. begin
  554. { if the current definition has no virtual then hide the
  555. old virtual if the new definition has the same arguments or
  556. when it has no overload directive and no overloads }
  557. if not(po_virtualmethod in pd.procoptions) then
  558. begin
  559. if procdefcoll^.visible and
  560. (not(pdoverload or hasoverloads) or
  561. (compare_paras(procdefcoll^.data.paras,pd.paras,cp_all,[])>=te_equal)) then
  562. begin
  563. if is_visible then
  564. procdefcoll^.hidden:=true;
  565. if (_class=pd._class) and not(po_reintroduce in pd.procoptions) then
  566. MessagePos1(pd.fileinfo,parser_w_should_use_override,pd.fullprocname(false));
  567. end;
  568. end
  569. { if both are virtual we check the header }
  570. else if (po_virtualmethod in pd.procoptions) and
  571. (po_virtualmethod in procdefcoll^.data.procoptions) then
  572. begin
  573. { new one has not override }
  574. if is_class(_class) and
  575. not(po_overridingmethod in pd.procoptions) then
  576. begin
  577. { we start a new virtual tree, hide the old }
  578. if (not(pdoverload or hasoverloads) or
  579. (compare_paras(procdefcoll^.data.paras,pd.paras,cp_all,[])>=te_equal)) and
  580. (procdefcoll^.visible) then
  581. begin
  582. if is_visible then
  583. procdefcoll^.hidden:=true;
  584. if (_class=pd._class) and not(po_reintroduce in pd.procoptions) then
  585. MessagePos1(pd.fileinfo,parser_w_should_use_override,pd.fullprocname(false));
  586. end;
  587. end
  588. { same parameters }
  589. else if (compare_paras(procdefcoll^.data.paras,pd.paras,cp_all,[])>=te_equal) then
  590. begin
  591. { overload is inherited }
  592. if (po_overload in procdefcoll^.data.procoptions) then
  593. include(pd.procoptions,po_overload);
  594. { inherite calling convention when it was force and the
  595. current definition has none force }
  596. if (po_hascallingconvention in procdefcoll^.data.procoptions) and
  597. not(po_hascallingconvention in pd.procoptions) then
  598. begin
  599. pd.proccalloption:=procdefcoll^.data.proccalloption;
  600. include(pd.procoptions,po_hascallingconvention);
  601. end;
  602. { the flags have to match except abstract and override }
  603. { only if both are virtual !! }
  604. if (procdefcoll^.data.proccalloption<>pd.proccalloption) or
  605. (procdefcoll^.data.proctypeoption<>pd.proctypeoption) or
  606. ((procdefcoll^.data.procoptions*po_comp)<>(pd.procoptions*po_comp)) then
  607. begin
  608. MessagePos1(pd.fileinfo,parser_e_header_dont_match_forward,pd.fullprocname(false));
  609. tprocsym(procdefcoll^.data.procsym).write_parameter_lists(pd);
  610. end;
  611. { error, if the return types aren't equal }
  612. if not(equal_defs(procdefcoll^.data.returndef,pd.returndef)) and
  613. not((procdefcoll^.data.returndef.deftype=objectdef) and
  614. (pd.returndef.deftype=objectdef) and
  615. is_class_or_interface(procdefcoll^.data.returndef) and
  616. is_class_or_interface(pd.returndef) and
  617. (tobjectdef(pd.returndef).is_related(
  618. tobjectdef(procdefcoll^.data.returndef)))) then
  619. begin
  620. if not((m_delphi in aktmodeswitches) and
  621. is_interface(_class)) then
  622. Message2(parser_e_overridden_methods_not_same_ret,pd.fullprocname(false),
  623. procdefcoll^.data.fullprocname(false))
  624. else
  625. { Delphi allows changing the result type }
  626. { of interface methods from anything to }
  627. { anything (JM) }
  628. Message2(parser_w_overridden_methods_not_same_ret,pd.fullprocname(false),
  629. procdefcoll^.data.fullprocname(false));
  630. end;
  631. { check if the method to override is visible, check is only needed
  632. for the current parsed class. Parent classes are already validated and
  633. need to include all virtual methods including the ones not visible in the
  634. current class }
  635. if (_class=pd._class) and
  636. (po_overridingmethod in pd.procoptions) and
  637. (not procdefcoll^.visible) then
  638. MessagePos1(pd.fileinfo,parser_e_nothing_to_be_overridden,pd.fullprocname(false));
  639. { override old virtual method in VMT }
  640. pd.extnumber:=procdefcoll^.data.extnumber;
  641. procdefcoll^.data:=pd;
  642. if is_visible then
  643. procdefcoll^.visible:=true;
  644. goto handlenextdef;
  645. end
  646. { different parameters }
  647. else
  648. begin
  649. { when we got an override directive then can search futher for
  650. the procedure to override.
  651. If we are starting a new virtual tree then hide the old tree }
  652. if not(po_overridingmethod in pd.procoptions) and
  653. not pdoverload then
  654. begin
  655. if is_visible then
  656. procdefcoll^.hidden:=true;
  657. if (_class=pd._class) and not(po_reintroduce in pd.procoptions) then
  658. MessagePos1(pd.fileinfo,parser_w_should_use_override,pd.fullprocname(false));
  659. end;
  660. end;
  661. end
  662. else
  663. begin
  664. { the new definition is virtual and the old static, we hide the old one
  665. if the new defintion has not the overload directive }
  666. if is_visible and
  667. ((not(pdoverload or hasoverloads)) or
  668. (compare_paras(procdefcoll^.data.paras,pd.paras,cp_all,[])>=te_equal)) then
  669. procdefcoll^.hidden:=true;
  670. end;
  671. end
  672. else
  673. begin
  674. { both are static, we hide the old one if the new defintion
  675. has not the overload directive }
  676. if is_visible and
  677. ((not pdoverload) or
  678. (compare_paras(procdefcoll^.data.paras,pd.paras,cp_all,[])>=te_equal)) then
  679. procdefcoll^.hidden:=true;
  680. end;
  681. end; { not hidden }
  682. procdefcoll:=procdefcoll^.next;
  683. end;
  684. { if it isn't saved in the list we create a new entry }
  685. newdefentry(vmtentry,pd,is_visible);
  686. end;
  687. handlenextdef:
  688. end;
  689. exit;
  690. end;
  691. vmtentry:=vmtentry^.next;
  692. end;
  693. { Generate new procsym entry in vmt }
  694. vmtentry:=newvmtentry(tprocsym(sym));
  695. { Add procdefs }
  696. for i:=1 to Tprocsym(sym).procdef_count do
  697. begin
  698. pd:=Tprocsym(sym).procdef[i];
  699. newdefentry(vmtentry,pd,pd.is_visible_for_object(_class,nil));
  700. end;
  701. end;
  702. procedure tclassheader.disposevmttree;
  703. var
  704. vmtentry : pvmtentry;
  705. procdefcoll : pprocdefcoll;
  706. begin
  707. { disposes the above generated tree }
  708. vmtentry:=firstvmtentry;
  709. while assigned(vmtentry) do
  710. begin
  711. firstvmtentry:=vmtentry^.next;
  712. stringdispose(vmtentry^.name);
  713. procdefcoll:=vmtentry^.firstprocdef;
  714. while assigned(procdefcoll) do
  715. begin
  716. vmtentry^.firstprocdef:=procdefcoll^.next;
  717. dispose(procdefcoll);
  718. procdefcoll:=vmtentry^.firstprocdef;
  719. end;
  720. dispose(vmtentry);
  721. vmtentry:=firstvmtentry;
  722. end;
  723. end;
  724. procedure tclassheader.genvmt;
  725. procedure do_genvmt(p : tobjectdef);
  726. begin
  727. { start with the base class }
  728. if assigned(p.childof) then
  729. do_genvmt(p.childof);
  730. { walk through all public syms }
  731. p.symtable.foreach(@eachsym,nil);
  732. end;
  733. begin
  734. firstvmtentry:=nil;
  735. nextvirtnumber:=0;
  736. has_constructor:=false;
  737. has_virtual_method:=false;
  738. { generates a tree of all used methods }
  739. do_genvmt(_class);
  740. if not(is_interface(_class)) and
  741. has_virtual_method and
  742. not(has_constructor) then
  743. Message1(parser_w_virtual_without_constructor,_class.objrealname^);
  744. end;
  745. {**************************************
  746. Interface tables
  747. **************************************}
  748. function tclassheader.gintfgetvtbllabelname(intfindex: integer): string;
  749. begin
  750. gintfgetvtbllabelname:=make_mangledname('VTBL',_class.owner,_class.objname^+
  751. '_$_'+_class.implementedinterfaces.interfaces(intfindex).objname^);
  752. end;
  753. procedure tclassheader.gintfcreatevtbl(intfindex: integer; rawdata: TAsmList);
  754. var
  755. implintf: timplementedinterfaces;
  756. curintf: tobjectdef;
  757. proccount: integer;
  758. tmps: string;
  759. i: longint;
  760. begin
  761. implintf:=_class.implementedinterfaces;
  762. curintf:=implintf.interfaces(intfindex);
  763. section_symbol_start(rawdata,gintfgetvtbllabelname(intfindex),AT_DATA,true,sec_data,const_align(sizeof(aint)));
  764. proccount:=implintf.implproccount(intfindex);
  765. for i:=1 to proccount do
  766. begin
  767. tmps:=make_mangledname('WRPR',_class.owner,_class.objname^+'_$_'+curintf.objname^+'_$_'+
  768. tostr(i)+'_$_'+
  769. implintf.implprocs(intfindex,i).mangledname);
  770. { create reference }
  771. rawdata.concat(Tai_const.Createname(tmps,0));
  772. end;
  773. section_symbol_end(rawdata,gintfgetvtbllabelname(intfindex));
  774. end;
  775. procedure tclassheader.gintfgenentry(intfindex, contintfindex: integer; rawdata: TAsmList);
  776. var
  777. implintf: timplementedinterfaces;
  778. curintf: tobjectdef;
  779. tmplabel: tasmlabel;
  780. i: longint;
  781. begin
  782. implintf:=_class.implementedinterfaces;
  783. curintf:=implintf.interfaces(intfindex);
  784. { GUID }
  785. if curintf.objecttype in [odt_interfacecom] then
  786. begin
  787. { label for GUID }
  788. current_asmdata.getdatalabel(tmplabel);
  789. rawdata.concat(cai_align.create(const_align(sizeof(aint))));
  790. rawdata.concat(Tai_label.Create(tmplabel));
  791. rawdata.concat(Tai_const.Create_32bit(longint(curintf.iidguid^.D1)));
  792. rawdata.concat(Tai_const.Create_16bit(curintf.iidguid^.D2));
  793. rawdata.concat(Tai_const.Create_16bit(curintf.iidguid^.D3));
  794. for i:=Low(curintf.iidguid^.D4) to High(curintf.iidguid^.D4) do
  795. rawdata.concat(Tai_const.Create_8bit(curintf.iidguid^.D4[i]));
  796. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(tmplabel));
  797. end
  798. else
  799. begin
  800. { nil for Corba interfaces }
  801. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  802. end;
  803. { VTable }
  804. current_asmdata.asmlists[al_globals].concat(Tai_const.Createname(gintfgetvtbllabelname(contintfindex),0));
  805. { IOffset field }
  806. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_aint(implintf.ioffsets(contintfindex)));
  807. { IIDStr }
  808. current_asmdata.getdatalabel(tmplabel);
  809. rawdata.concat(cai_align.create(const_align(sizeof(aint))));
  810. rawdata.concat(Tai_label.Create(tmplabel));
  811. rawdata.concat(Tai_const.Create_8bit(length(curintf.iidstr^)));
  812. if curintf.objecttype=odt_interfacecom then
  813. rawdata.concat(Tai_string.Create(upper(curintf.iidstr^)))
  814. else
  815. rawdata.concat(Tai_string.Create(curintf.iidstr^));
  816. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(tmplabel));
  817. { EntryType }
  818. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_aint(integer(curintf.iitype)));
  819. { EntryOffset }
  820. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_aint(integer(curintf.iioffset)));
  821. end;
  822. procedure tclassheader.gintfoptimizevtbls;
  823. type
  824. tcompintfentry = record
  825. weight: longint;
  826. compintf: longint;
  827. end;
  828. { Max 1000 interface in the class header interfaces it's enough imho }
  829. tcompintfs = array[1..1000] of tcompintfentry;
  830. pcompintfs = ^tcompintfs;
  831. tequals = array[1..1000] of longint;
  832. pequals = ^tequals;
  833. timpls = array[1..1000] of longint;
  834. pimpls = ^timpls;
  835. var
  836. max: longint;
  837. equals: pequals;
  838. compats: pcompintfs;
  839. impls: pimpls;
  840. w,i,j,k: longint;
  841. cij: boolean;
  842. cji: boolean;
  843. begin
  844. max:=_class.implementedinterfaces.count;
  845. if max>High(tequals) then
  846. Internalerror(200006135);
  847. getmem(compats,sizeof(tcompintfentry)*max);
  848. getmem(equals,sizeof(longint)*max);
  849. getmem(impls,sizeof(longint)*max);
  850. fillchar(compats^,sizeof(tcompintfentry)*max,0);
  851. fillchar(equals^,sizeof(longint)*max,0);
  852. fillchar(impls^,sizeof(longint)*max,0);
  853. { ismergepossible is a containing relation
  854. meaning of ismergepossible(a,b,w) =
  855. if implementorfunction map of a is contained implementorfunction map of b
  856. imp(a,b) and imp(b,c) => imp(a,c) ; imp(a,b) and imp(b,a) => a == b
  857. }
  858. { the order is very important for correct allocation }
  859. for i:=1 to max do
  860. begin
  861. for j:=i+1 to max do
  862. begin
  863. cij:=_class.implementedinterfaces.isimplmergepossible(i,j,w);
  864. cji:=_class.implementedinterfaces.isimplmergepossible(j,i,w);
  865. if cij and cji then { i equal j }
  866. begin
  867. { get minimum index of equal }
  868. if equals^[j]=0 then
  869. equals^[j]:=i;
  870. end
  871. else if cij then
  872. begin
  873. { get minimum index of maximum weight }
  874. if compats^[i].weight<w then
  875. begin
  876. compats^[i].weight:=w;
  877. compats^[i].compintf:=j;
  878. end;
  879. end
  880. else if cji then
  881. begin
  882. { get minimum index of maximum weight }
  883. if (compats^[j].weight<w) then
  884. begin
  885. compats^[j].weight:=w;
  886. compats^[j].compintf:=i;
  887. end;
  888. end;
  889. end;
  890. end;
  891. { Reset, no replacements by default }
  892. for i:=1 to max do
  893. impls^[i]:=i;
  894. { Replace vtbls when equal or compat, repeat
  895. until there are no replacements possible anymore. This is
  896. needed for the cases like:
  897. First loop: 2->3, 3->1
  898. Second loop: 2->1 (because 3 was replaced with 1)
  899. }
  900. repeat
  901. k:=0;
  902. for i:=1 to max do
  903. begin
  904. if compats^[impls^[i]].compintf<>0 then
  905. impls^[i]:=compats^[impls^[i]].compintf
  906. else if equals^[impls^[i]]<>0 then
  907. impls^[i]:=equals^[impls^[i]]
  908. else
  909. inc(k);
  910. end;
  911. until k=max;
  912. { Update the implindex }
  913. for i:=1 to max do
  914. _class.implementedinterfaces.setimplindex(i,impls^[i]);
  915. freemem(compats);
  916. freemem(equals);
  917. freemem(impls);
  918. end;
  919. procedure tclassheader.gintfwritedata;
  920. var
  921. rawdata: TAsmList;
  922. max,i,j : smallint;
  923. begin
  924. max:=_class.implementedinterfaces.count;
  925. rawdata:=TAsmList.Create;
  926. { Two pass, one for allocation and vtbl creation }
  927. for i:=1 to max do
  928. begin
  929. if _class.implementedinterfaces.implindex(i)=i then { if implement itself }
  930. begin
  931. { allocate a pointer in the object memory }
  932. with tobjectsymtable(_class.symtable) do
  933. begin
  934. datasize:=align(datasize,sizeof(aint));
  935. _class.implementedinterfaces.setioffsets(i,datasize);
  936. inc(datasize,sizeof(aint));
  937. end;
  938. { write vtbl }
  939. gintfcreatevtbl(i,rawdata);
  940. end;
  941. end;
  942. { second pass: for fill interfacetable and remained ioffsets }
  943. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_aint(max));
  944. for i:=1 to max do
  945. begin
  946. j:=_class.implementedinterfaces.implindex(i);
  947. if j<>i then
  948. _class.implementedinterfaces.setioffsets(i,_class.implementedinterfaces.ioffsets(j));
  949. gintfgenentry(i,j,rawdata);
  950. end;
  951. current_asmdata.asmlists[al_globals].concatlist(rawdata);
  952. rawdata.free;
  953. end;
  954. function tclassheader.gintfgetcprocdef(proc: tprocdef;const name: string): tprocdef;
  955. const
  956. po_comp = [po_classmethod,po_staticmethod,po_interrupt,po_iocheck,po_msgstr,po_msgint,
  957. po_exports,po_varargs,po_explicitparaloc,po_nostackframe];
  958. var
  959. sym: tsym;
  960. implprocdef : Tprocdef;
  961. i: cardinal;
  962. begin
  963. gintfgetcprocdef:=nil;
  964. sym:=tsym(search_class_member(_class,name));
  965. if assigned(sym) and
  966. (sym.typ=procsym) then
  967. begin
  968. { when the definition has overload directive set, we search for
  969. overloaded definitions in the class, this only needs to be done once
  970. for class entries as the tree keeps always the same }
  971. if (not tprocsym(sym).overloadchecked) and
  972. (po_overload in tprocsym(sym).first_procdef.procoptions) and
  973. (tprocsym(sym).owner.symtabletype=objectsymtable) then
  974. search_class_overloads(tprocsym(sym));
  975. for i:=1 to tprocsym(sym).procdef_count do
  976. begin
  977. implprocdef:=tprocsym(sym).procdef[i];
  978. if (compare_paras(proc.paras,implprocdef.paras,cp_none,[])>=te_equal) and
  979. (proc.proccalloption=implprocdef.proccalloption) and
  980. (proc.proctypeoption=implprocdef.proctypeoption) and
  981. ((proc.procoptions*po_comp)=((implprocdef.procoptions+[po_virtualmethod])*po_comp)) then
  982. begin
  983. gintfgetcprocdef:=implprocdef;
  984. exit;
  985. end;
  986. end;
  987. end;
  988. end;
  989. procedure tclassheader.gintfdoonintf(intf: tobjectdef; intfindex: longint);
  990. var
  991. def: tdef;
  992. hs,
  993. prefix,
  994. mappedname: string;
  995. nextexist: pointer;
  996. implprocdef: tprocdef;
  997. begin
  998. prefix:=_class.implementedinterfaces.interfaces(intfindex).symtable.name^+'.';
  999. def:=tdef(intf.symtable.defindex.first);
  1000. while assigned(def) do
  1001. begin
  1002. if def.deftype=procdef then
  1003. begin
  1004. implprocdef:=nil;
  1005. nextexist:=nil;
  1006. repeat
  1007. hs:=prefix+tprocdef(def).procsym.name;
  1008. mappedname:=_class.implementedinterfaces.getmappings(intfindex,hs,nextexist);
  1009. if mappedname<>'' then
  1010. implprocdef:=gintfgetcprocdef(tprocdef(def),mappedname);
  1011. until assigned(implprocdef) or not assigned(nextexist);
  1012. if not assigned(implprocdef) then
  1013. implprocdef:=gintfgetcprocdef(tprocdef(def),tprocdef(def).procsym.name);
  1014. if assigned(implprocdef) then
  1015. _class.implementedinterfaces.addimplproc(intfindex,implprocdef)
  1016. else
  1017. if _class.implementedinterfaces.interfaces(intfindex).iitype = etStandard then
  1018. Message1(sym_e_no_matching_implementation_found,tprocdef(def).fullprocname(false));
  1019. end;
  1020. def:=tdef(def.indexnext);
  1021. end;
  1022. end;
  1023. procedure tclassheader.gintfwalkdowninterface(intf: tobjectdef; intfindex: longint);
  1024. begin
  1025. if assigned(intf.childof) then
  1026. gintfwalkdowninterface(intf.childof,intfindex);
  1027. gintfdoonintf(intf,intfindex);
  1028. end;
  1029. function tclassheader.genintftable: tasmlabel;
  1030. var
  1031. intfindex: longint;
  1032. curintf: tobjectdef;
  1033. intftable: tasmlabel;
  1034. begin
  1035. { 1. step collect implementor functions into the implementedinterfaces.implprocs }
  1036. for intfindex:=1 to _class.implementedinterfaces.count do
  1037. begin
  1038. curintf:=_class.implementedinterfaces.interfaces(intfindex);
  1039. gintfwalkdowninterface(curintf,intfindex);
  1040. end;
  1041. { 2. Optimize interface tables to reuse wrappers }
  1042. gintfoptimizevtbls;
  1043. { 3. Calculate offsets in object map and Write interface tables }
  1044. current_asmdata.getdatalabel(intftable);
  1045. current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(aint))));
  1046. current_asmdata.asmlists[al_globals].concat(Tai_label.Create(intftable));
  1047. gintfwritedata;
  1048. genintftable:=intftable;
  1049. end;
  1050. { Write interface identifiers to the data section }
  1051. procedure tclassheader.writeinterfaceids;
  1052. var
  1053. i : longint;
  1054. s : string;
  1055. begin
  1056. if assigned(_class.iidguid) then
  1057. begin
  1058. s:=make_mangledname('IID',_class.owner,_class.objname^);
  1059. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  1060. new_section(current_asmdata.asmlists[al_globals],sec_rodata,s,const_align(sizeof(aint)));
  1061. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  1062. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_32bit(longint(_class.iidguid^.D1)));
  1063. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_16bit(_class.iidguid^.D2));
  1064. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_16bit(_class.iidguid^.D3));
  1065. for i:=Low(_class.iidguid^.D4) to High(_class.iidguid^.D4) do
  1066. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_8bit(_class.iidguid^.D4[i]));
  1067. end;
  1068. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  1069. s:=make_mangledname('IIDSTR',_class.owner,_class.objname^);
  1070. new_section(current_asmdata.asmlists[al_globals],sec_rodata,s,0);
  1071. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  1072. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_8bit(length(_class.iidstr^)));
  1073. current_asmdata.asmlists[al_globals].concat(Tai_string.Create(_class.iidstr^));
  1074. end;
  1075. procedure tclassheader.writevirtualmethods(List:TAsmList);
  1076. var
  1077. vmtentry : pvmtentry;
  1078. procdefcoll : pprocdefcoll;
  1079. i : longint;
  1080. procname : string;
  1081. {$ifdef vtentry}
  1082. hs : string;
  1083. {$endif vtentry}
  1084. begin
  1085. { walk trough all numbers for virtual methods and search }
  1086. { the method }
  1087. for i:=0 to nextvirtnumber-1 do
  1088. begin
  1089. { walk trough all symbols }
  1090. vmtentry:=firstvmtentry;
  1091. while assigned(vmtentry) do
  1092. begin
  1093. { walk trough all methods }
  1094. procdefcoll:=vmtentry^.firstprocdef;
  1095. while assigned(procdefcoll) do
  1096. begin
  1097. { writes the addresses to the VMT }
  1098. { but only this which are declared as virtual }
  1099. if (procdefcoll^.data.extnumber=i) and
  1100. (po_virtualmethod in procdefcoll^.data.procoptions) then
  1101. begin
  1102. if (po_abstractmethod in procdefcoll^.data.procoptions) then
  1103. procname:='FPC_ABSTRACTERROR'
  1104. else
  1105. procname:=procdefcoll^.data.mangledname;
  1106. List.concat(Tai_const.createname(procname,0));
  1107. {$ifdef vtentry}
  1108. hs:='VTENTRY'+'_'+_class.vmt_mangledname+'$$'+tostr(_class.vmtmethodoffset(i) div sizeof(aint));
  1109. current_asmdata.asmlists[al_globals].concat(tai_symbol.CreateName(hs,AT_DATA,0));
  1110. {$endif vtentry}
  1111. break;
  1112. end;
  1113. procdefcoll:=procdefcoll^.next;
  1114. end;
  1115. vmtentry:=vmtentry^.next;
  1116. end;
  1117. end;
  1118. end;
  1119. { generates the vmt for classes as well as for objects }
  1120. procedure tclassheader.writevmt;
  1121. var
  1122. methodnametable,intmessagetable,
  1123. strmessagetable,classnamelabel,
  1124. fieldtablelabel : tasmlabel;
  1125. {$ifdef WITHDMT}
  1126. dmtlabel : tasmlabel;
  1127. {$endif WITHDMT}
  1128. interfacetable : tasmlabel;
  1129. {$ifdef vtentry}
  1130. hs: string;
  1131. {$endif vtentry}
  1132. begin
  1133. {$ifdef WITHDMT}
  1134. dmtlabel:=gendmt;
  1135. {$endif WITHDMT}
  1136. { write tables for classes, this must be done before the actual
  1137. class is written, because we need the labels defined }
  1138. if is_class(_class) then
  1139. begin
  1140. current_asmdata.getdatalabel(classnamelabel);
  1141. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  1142. new_section(current_asmdata.asmlists[al_globals],sec_rodata,classnamelabel.name,const_align(sizeof(aint)));
  1143. { interface table }
  1144. if _class.implementedinterfaces.count>0 then
  1145. interfacetable:=genintftable;
  1146. methodnametable:=genpublishedmethodstable;
  1147. fieldtablelabel:=_class.generate_field_table;
  1148. { write class name }
  1149. current_asmdata.asmlists[al_globals].concat(Tai_label.Create(classnamelabel));
  1150. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_8bit(length(_class.objrealname^)));
  1151. current_asmdata.asmlists[al_globals].concat(Tai_string.Create(_class.objrealname^));
  1152. { generate message and dynamic tables }
  1153. if (oo_has_msgstr in _class.objectoptions) then
  1154. strmessagetable:=genstrmsgtab;
  1155. if (oo_has_msgint in _class.objectoptions) then
  1156. intmessagetable:=genintmsgtab;
  1157. end;
  1158. { write debug info }
  1159. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  1160. new_section(current_asmdata.asmlists[al_globals],sec_rodata,_class.vmt_mangledname,const_align(sizeof(aint)));
  1161. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(_class.vmt_mangledname,AT_DATA,0));
  1162. { determine the size with symtable.datasize, because }
  1163. { size gives back 4 for classes }
  1164. current_asmdata.asmlists[al_globals].concat(Tai_const.Create(aitconst_ptr,tobjectsymtable(_class.symtable).datasize));
  1165. current_asmdata.asmlists[al_globals].concat(Tai_const.Create(aitconst_ptr,-int64(tobjectsymtable(_class.symtable).datasize)));
  1166. {$ifdef WITHDMT}
  1167. if _class.classtype=ct_object then
  1168. begin
  1169. if assigned(dmtlabel) then
  1170. current_asmdata.asmlists[al_globals].concat(Tai_const_symbol.Create(dmtlabel)))
  1171. else
  1172. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_ptr(0));
  1173. end;
  1174. {$endif WITHDMT}
  1175. { write pointer to parent VMT, this isn't implemented in TP }
  1176. { but this is not used in FPC ? (PM) }
  1177. { it's not used yet, but the delphi-operators as and is need it (FK) }
  1178. { it is not written for parents that don't have any vmt !! }
  1179. if assigned(_class.childof) and
  1180. (oo_has_vmt in _class.childof.objectoptions) then
  1181. current_asmdata.asmlists[al_globals].concat(Tai_const.Createname(_class.childof.vmt_mangledname,0))
  1182. else
  1183. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  1184. { write extended info for classes, for the order see rtl/inc/objpash.inc }
  1185. if is_class(_class) then
  1186. begin
  1187. { pointer to class name string }
  1188. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(classnamelabel));
  1189. { pointer to dynamic table or nil }
  1190. if (oo_has_msgint in _class.objectoptions) then
  1191. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(intmessagetable))
  1192. else
  1193. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  1194. { pointer to method table or nil }
  1195. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(methodnametable));
  1196. { pointer to field table }
  1197. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(fieldtablelabel));
  1198. { pointer to type info of published section }
  1199. if (oo_can_have_published in _class.objectoptions) then
  1200. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(_class.get_rtti_label(fullrtti)))
  1201. else
  1202. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  1203. { inittable for con-/destruction }
  1204. if _class.members_need_inittable then
  1205. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(_class.get_rtti_label(initrtti)))
  1206. else
  1207. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  1208. { auto table }
  1209. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  1210. { interface table }
  1211. if _class.implementedinterfaces.count>0 then
  1212. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(interfacetable))
  1213. else
  1214. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  1215. { table for string messages }
  1216. if (oo_has_msgstr in _class.objectoptions) then
  1217. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(strmessagetable))
  1218. else
  1219. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  1220. end;
  1221. { write virtual methods }
  1222. writevirtualmethods(current_asmdata.asmlists[al_globals]);
  1223. current_asmdata.asmlists[al_globals].concat(Tai_const.create(aitconst_ptr,0));
  1224. { write the size of the VMT }
  1225. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(_class.vmt_mangledname));
  1226. {$ifdef vtentry}
  1227. { write vtinherit symbol to notify the linker of the class inheritance tree }
  1228. hs:='VTINHERIT'+'_'+_class.vmt_mangledname+'$$';
  1229. if assigned(_class.childof) then
  1230. hs:=hs+_class.childof.vmt_mangledname
  1231. else
  1232. hs:=hs+_class.vmt_mangledname;
  1233. current_asmdata.asmlists[al_globals].concat(tai_symbol.CreateName(hs,AT_DATA,0));
  1234. {$endif vtentry}
  1235. end;
  1236. end.