nobj.pas 57 KB

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