nobj.pas 57 KB

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