nobj.pas 56 KB

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