nobj.pas 57 KB

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