nobj.pas 57 KB

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