nobj.pas 59 KB

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