nobj.pas 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Routines for the code generation of data structures
  4. like VMT, Messages, VTables, Interfaces descs
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit nobj;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. cutils,cclasses,
  23. globtype,
  24. symdef,symsym,
  25. aasmbase,aasmtai,aasmdata
  26. ;
  27. type
  28. pprocdefentry = ^tprocdefentry;
  29. tprocdefentry = record
  30. data : tprocdef;
  31. hidden : boolean;
  32. visible : boolean;
  33. end;
  34. { tvmtsymentry }
  35. tvmtsymentry = class(TFPHashObject)
  36. procdeflist : TFPList;
  37. constructor Create(AList:TFPHashObjectList;const AName:shortstring);
  38. destructor Destroy;override;
  39. end;
  40. TVMTBuilder=class
  41. private
  42. _Class : tobjectdef;
  43. VMTSymEntryList : TFPHashObjectList;
  44. has_constructor,
  45. has_virtual_method : boolean;
  46. function is_new_vmt_entry(VMTSymEntry:TVMTSymEntry;pd:tprocdef):boolean;
  47. procedure add_new_vmt_entry(VMTSymEntry:TVMTSymEntry;pd:tprocdef);
  48. procedure add_vmt_entries(objdef:tobjectdef);
  49. function intf_search_procdef_by_name(proc: tprocdef;const name: string): tprocdef;
  50. procedure intf_get_procdefs(ImplIntf:TImplementedInterface;IntfDef:TObjectDef);
  51. procedure intf_get_procdefs_recursive(ImplIntf:TImplementedInterface;IntfDef:TObjectDef);
  52. procedure intf_optimize_vtbls;
  53. procedure intf_allocate_vtbls;
  54. public
  55. constructor create(c:tobjectdef);
  56. destructor destroy;override;
  57. procedure generate_vmt;
  58. end;
  59. type
  60. pprocdeftree = ^tprocdeftree;
  61. tprocdeftree = record
  62. data : tprocdef;
  63. nl : tasmlabel;
  64. l,r : pprocdeftree;
  65. end;
  66. TVMTWriter=class
  67. private
  68. _Class : tobjectdef;
  69. { message tables }
  70. root : pprocdeftree;
  71. procedure disposeprocdeftree(p : pprocdeftree);
  72. procedure insertmsgint(p:TObject;arg:pointer);
  73. procedure insertmsgstr(p:TObject;arg:pointer);
  74. procedure insertint(p : pprocdeftree;var at : pprocdeftree;var count:longint);
  75. procedure insertstr(p : pprocdeftree;var at : pprocdeftree;var count:longint);
  76. procedure writenames(p : pprocdeftree);
  77. procedure writeintentry(p : pprocdeftree);
  78. procedure writestrentry(p : pprocdeftree);
  79. {$ifdef WITHDMT}
  80. { dmt }
  81. procedure insertdmtentry(p:TObject;arg:pointer);
  82. procedure writedmtindexentry(p : pprocdeftree);
  83. procedure writedmtaddressentry(p : pprocdeftree);
  84. {$endif}
  85. { published methods }
  86. procedure do_count_published_methods(p:TObject;arg:pointer);
  87. procedure do_gen_published_methods(p:TObject;arg:pointer);
  88. { virtual methods }
  89. procedure writevirtualmethods(List:TAsmList);
  90. { interface tables }
  91. function intf_get_vtbl_name(AImplIntf:TImplementedInterface): string;
  92. procedure intf_create_vtbl(rawdata: TAsmList;AImplIntf:TImplementedInterface);
  93. procedure intf_gen_intf_ref(rawdata: TAsmList;AImplIntf:TImplementedInterface);
  94. function intf_write_table:TAsmLabel;
  95. { generates the message tables for a class }
  96. function genstrmsgtab : tasmlabel;
  97. function genintmsgtab : tasmlabel;
  98. function genpublishedmethodstable : tasmlabel;
  99. function generate_field_table : tasmlabel;
  100. {$ifdef WITHDMT}
  101. { generates a DMT for _class }
  102. function gendmt : tasmlabel;
  103. {$endif WITHDMT}
  104. public
  105. constructor create(c:tobjectdef);
  106. destructor destroy;override;
  107. { write the VMT to al_globals }
  108. procedure writevmt;
  109. procedure writeinterfaceids;
  110. end;
  111. implementation
  112. uses
  113. SysUtils,
  114. globals,verbose,systems,
  115. 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 (_class=pd._class) and not(po_reintroduce in pd.procoptions) then
  248. MessagePos1(pd.fileinfo,parser_w_should_use_override,pd.fullprocname(false));
  249. end;
  250. end
  251. { if both are virtual we check the header }
  252. else if (po_virtualmethod in pd.procoptions) and
  253. (po_virtualmethod in procdefcoll^.data.procoptions) then
  254. begin
  255. { new one has not override }
  256. if is_class(_class) and
  257. not(po_overridingmethod in pd.procoptions) then
  258. begin
  259. { we start a new virtual tree, hide the old }
  260. if (not(pdoverload or hasoverloads) or
  261. (compare_paras(procdefcoll^.data.paras,pd.paras,cp_all,[])>=te_equal)) and
  262. (procdefcoll^.visible) then
  263. begin
  264. if is_visible then
  265. procdefcoll^.hidden:=true;
  266. if (_class=pd._class) and not(po_reintroduce in pd.procoptions) then
  267. MessagePos1(pd.fileinfo,parser_w_should_use_override,pd.fullprocname(false));
  268. end;
  269. end
  270. { same parameters }
  271. else if (compare_paras(procdefcoll^.data.paras,pd.paras,cp_all,[])>=te_equal) then
  272. begin
  273. { overload is inherited }
  274. if (po_overload in procdefcoll^.data.procoptions) then
  275. include(pd.procoptions,po_overload);
  276. { inherite calling convention when it was force and the
  277. current definition has none force }
  278. if (po_hascallingconvention in procdefcoll^.data.procoptions) and
  279. not(po_hascallingconvention in pd.procoptions) then
  280. begin
  281. pd.proccalloption:=procdefcoll^.data.proccalloption;
  282. include(pd.procoptions,po_hascallingconvention);
  283. end;
  284. { the flags have to match except abstract and override }
  285. { only if both are virtual !! }
  286. if (procdefcoll^.data.proccalloption<>pd.proccalloption) or
  287. (procdefcoll^.data.proctypeoption<>pd.proctypeoption) or
  288. ((procdefcoll^.data.procoptions*po_comp)<>(pd.procoptions*po_comp)) then
  289. begin
  290. MessagePos1(pd.fileinfo,parser_e_header_dont_match_forward,pd.fullprocname(false));
  291. tprocsym(procdefcoll^.data.procsym).write_parameter_lists(pd);
  292. end;
  293. { error, if the return types aren't equal }
  294. if not compatible_childmethod_resultdef(procdefcoll^.data.returndef,pd.returndef) then
  295. begin
  296. if not((m_delphi in current_settings.modeswitches) and
  297. is_interface(_class)) then
  298. Message2(parser_e_overridden_methods_not_same_ret,pd.fullprocname(false),
  299. procdefcoll^.data.fullprocname(false))
  300. else
  301. { Delphi allows changing the result type of interface methods from anything to
  302. anything (JM) }
  303. Message2(parser_w_overridden_methods_not_same_ret,pd.fullprocname(false),
  304. procdefcoll^.data.fullprocname(false));
  305. end;
  306. { check if the method to override is visible, check is only needed
  307. for the current parsed class. Parent classes are already validated and
  308. need to include all virtual methods including the ones not visible in the
  309. current class }
  310. if (_class=pd._class) and
  311. (po_overridingmethod in pd.procoptions) and
  312. (not procdefcoll^.visible) then
  313. MessagePos1(pd.fileinfo,parser_e_nothing_to_be_overridden,pd.fullprocname(false));
  314. { override old virtual method in VMT }
  315. if (procdefcoll^.data.extnumber>=_class.VMTEntries.Count) or
  316. (_class.VMTEntries[procdefcoll^.data.extnumber]<>procdefcoll^.data) then
  317. internalerror(200611084);
  318. _class.VMTEntries[procdefcoll^.data.extnumber]:=pd;
  319. pd.extnumber:=procdefcoll^.data.extnumber;
  320. procdefcoll^.data:=pd;
  321. if is_visible then
  322. procdefcoll^.visible:=true;
  323. exit;
  324. end
  325. { different parameters }
  326. else
  327. begin
  328. { when we got an override directive then can search futher for
  329. the procedure to override.
  330. If we are starting a new virtual tree then hide the old tree }
  331. if not(po_overridingmethod in pd.procoptions) and
  332. not pdoverload then
  333. begin
  334. if is_visible then
  335. procdefcoll^.hidden:=true;
  336. if (_class=pd._class) and not(po_reintroduce in pd.procoptions) then
  337. MessagePos1(pd.fileinfo,parser_w_should_use_override,pd.fullprocname(false));
  338. end;
  339. end;
  340. end
  341. else
  342. begin
  343. { the new definition is virtual and the old static, we hide the old one
  344. if the new defintion has not the overload directive }
  345. if is_visible and
  346. (
  347. (not(pdoverload or hasoverloads)) or
  348. (compare_paras(procdefcoll^.data.paras,pd.paras,cp_all,[])>=te_equal)
  349. ) then
  350. procdefcoll^.hidden:=true;
  351. end;
  352. end
  353. else
  354. begin
  355. { both are static, we hide the old one if the new defintion
  356. has not the overload directive }
  357. if is_visible and
  358. (
  359. (not pdoverload) or
  360. (compare_paras(procdefcoll^.data.paras,pd.paras,cp_all,[])>=te_equal)
  361. ) then
  362. procdefcoll^.hidden:=true;
  363. end;
  364. end;
  365. { No entry found, we need to create a new entry }
  366. result:=true;
  367. end;
  368. procedure TVMTBuilder.add_vmt_entries(objdef:tobjectdef);
  369. var
  370. pd : tprocdef;
  371. i,j : longint;
  372. sym : tsym;
  373. VMTSymEntry : TVMTSymEntry;
  374. begin
  375. { start with the base class }
  376. if assigned(objdef.childof) then
  377. add_vmt_entries(objdef.childof);
  378. { process all procsyms }
  379. for i:=0 to objdef.symtable.SymList.Count-1 do
  380. begin
  381. sym:=tsym(objdef.symtable.SymList[i]);
  382. if sym.typ=procsym then
  383. begin
  384. { Find VMT procsym }
  385. VMTSymEntry:=TVMTSymEntry(VMTSymEntryList.Find(sym.name));
  386. if not assigned(VMTSymEntry) then
  387. VMTSymEntry:=TVMTSymEntry.Create(VMTSymEntryList,sym.name);
  388. { Add all procdefs }
  389. for j:=0 to Tprocsym(sym).ProcdefList.Count-1 do
  390. begin
  391. pd:=tprocdef(Tprocsym(sym).ProcdefList[j]);
  392. if pd.procsym=tprocsym(sym) then
  393. begin
  394. if is_new_vmt_entry(VMTSymEntry,pd) then
  395. add_new_vmt_entry(VMTSymEntry,pd);
  396. end;
  397. end;
  398. end;
  399. end;
  400. end;
  401. function TVMTBuilder.intf_search_procdef_by_name(proc: tprocdef;const name: string): tprocdef;
  402. const
  403. po_comp = [po_classmethod,po_staticmethod,po_interrupt,po_iocheck,po_msgstr,po_msgint,
  404. po_exports,po_varargs,po_explicitparaloc,po_nostackframe];
  405. var
  406. sym: tsym;
  407. implprocdef : Tprocdef;
  408. i: cardinal;
  409. begin
  410. result:=nil;
  411. sym:=tsym(search_class_member(_class,name));
  412. if assigned(sym) and
  413. (sym.typ=procsym) then
  414. begin
  415. { when the definition has overload directive set, we search for
  416. overloaded definitions in the class, this only needs to be done once
  417. for class entries as the tree keeps always the same }
  418. if (not tprocsym(sym).overloadchecked) and
  419. (po_overload in tprocdef(tprocsym(sym).ProcdefList[0]).procoptions) and
  420. (tprocsym(sym).owner.symtabletype=ObjectSymtable) then
  421. search_class_overloads(tprocsym(sym));
  422. for i:=0 to Tprocsym(sym).ProcdefList.Count-1 do
  423. begin
  424. implprocdef:=tprocdef(Tprocsym(sym).ProcdefList[i]);
  425. if (compare_paras(proc.paras,implprocdef.paras,cp_none,[])>=te_equal) and
  426. (proc.proccalloption=implprocdef.proccalloption) and
  427. (proc.proctypeoption=implprocdef.proctypeoption) and
  428. ((proc.procoptions*po_comp)=((implprocdef.procoptions+[po_virtualmethod])*po_comp)) then
  429. begin
  430. result:=implprocdef;
  431. exit;
  432. end;
  433. end;
  434. end;
  435. end;
  436. procedure TVMTBuilder.intf_get_procdefs(ImplIntf:TImplementedInterface;IntfDef:TObjectDef);
  437. var
  438. i : longint;
  439. def : tdef;
  440. hs,
  441. prefix,
  442. mappedname: string;
  443. implprocdef: tprocdef;
  444. begin
  445. prefix:=ImplIntf.IntfDef.symtable.name^+'.';
  446. for i:=0 to IntfDef.symtable.DefList.Count-1 do
  447. begin
  448. def:=tdef(IntfDef.symtable.DefList[i]);
  449. if def.typ=procdef then
  450. begin
  451. { Find implementing procdef
  452. 1. Check for mapped name
  453. 2. Use symbol name }
  454. implprocdef:=nil;
  455. hs:=prefix+tprocdef(def).procsym.name;
  456. mappedname:=ImplIntf.GetMapping(hs);
  457. if mappedname<>'' then
  458. implprocdef:=intf_search_procdef_by_name(tprocdef(def),mappedname);
  459. if not assigned(implprocdef) then
  460. implprocdef:=intf_search_procdef_by_name(tprocdef(def),tprocdef(def).procsym.name);
  461. { Add procdef to the implemented interface }
  462. if assigned(implprocdef) then
  463. begin
  464. if (compare_paras(tprocdef(def).paras,implprocdef.paras,cp_all,[cpo_ignorehidden,cpo_comparedefaultvalue])<te_equal) or
  465. not compatible_childmethod_resultdef(tprocdef(def).returndef,implprocdef.returndef) then
  466. MessagePos1(tprocdef(implprocdef).fileinfo,parser_e_header_dont_match_forward,
  467. tprocdef(def).fullprocname(false));
  468. ImplIntf.AddImplProc(implprocdef)
  469. end
  470. else
  471. if ImplIntf.IntfDef.iitype = 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(aint));
  602. ImplIntf.Ioffset:=datasize;
  603. inc(datasize,sizeof(aint));
  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;
  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);
  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 assigned(_class.ImplementedInterfaces) then
  631. begin
  632. { Collect implementor functions into the tImplementedInterface.procdefs }
  633. for i:=0 to _class.ImplementedInterfaces.count-1 do
  634. begin
  635. ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]);
  636. intf_get_procdefs_recursive(ImplIntf,ImplIntf.IntfDef);
  637. end;
  638. { Optimize interface tables to reuse wrappers }
  639. intf_optimize_vtbls;
  640. { Allocate interface tables }
  641. intf_allocate_vtbls;
  642. end;
  643. end;
  644. {*****************************************************************************
  645. TVMTWriter
  646. *****************************************************************************}
  647. constructor TVMTWriter.create(c:tobjectdef);
  648. begin
  649. inherited Create;
  650. _Class:=c;
  651. end;
  652. destructor TVMTWriter.destroy;
  653. begin
  654. end;
  655. {**************************************
  656. Message Tables
  657. **************************************}
  658. procedure TVMTWriter.disposeprocdeftree(p : pprocdeftree);
  659. begin
  660. if assigned(p^.l) then
  661. disposeprocdeftree(p^.l);
  662. if assigned(p^.r) then
  663. disposeprocdeftree(p^.r);
  664. dispose(p);
  665. end;
  666. procedure TVMTWriter.insertint(p : pprocdeftree;var at : pprocdeftree;var count:longint);
  667. begin
  668. if at=nil then
  669. begin
  670. at:=p;
  671. inc(count);
  672. end
  673. else
  674. begin
  675. if p^.data.messageinf.i<at^.data.messageinf.i then
  676. insertint(p,at^.l,count)
  677. else if p^.data.messageinf.i>at^.data.messageinf.i then
  678. insertint(p,at^.r,count)
  679. else
  680. Message1(parser_e_duplicate_message_label,tostr(p^.data.messageinf.i));
  681. end;
  682. end;
  683. procedure TVMTWriter.insertstr(p : pprocdeftree;var at : pprocdeftree;var count:longint);
  684. var
  685. i : integer;
  686. begin
  687. if at=nil then
  688. begin
  689. at:=p;
  690. inc(count);
  691. end
  692. else
  693. begin
  694. i:=CompareStr(p^.data.messageinf.str^,at^.data.messageinf.str^);
  695. if i<0 then
  696. insertstr(p,at^.l,count)
  697. else if i>0 then
  698. insertstr(p,at^.r,count)
  699. else
  700. Message1(parser_e_duplicate_message_label,p^.data.messageinf.str^);
  701. end;
  702. end;
  703. procedure TVMTWriter.insertmsgint(p:TObject;arg:pointer);
  704. var
  705. i : longint;
  706. pd : Tprocdef;
  707. pt : pprocdeftree;
  708. begin
  709. if tsym(p).typ<>procsym then
  710. exit;
  711. for i:=0 to Tprocsym(p).ProcdefList.Count-1 do
  712. begin
  713. pd:=tprocdef(Tprocsym(p).ProcdefList[i]);
  714. if po_msgint in pd.procoptions then
  715. begin
  716. new(pt);
  717. pt^.data:=pd;
  718. pt^.l:=nil;
  719. pt^.r:=nil;
  720. insertint(pt,root,plongint(arg)^);
  721. end;
  722. end;
  723. end;
  724. procedure TVMTWriter.insertmsgstr(p:TObject;arg:pointer);
  725. var
  726. i : longint;
  727. pd : Tprocdef;
  728. pt : pprocdeftree;
  729. begin
  730. if tsym(p).typ<>procsym then
  731. exit;
  732. for i:=0 to Tprocsym(p).ProcdefList.Count-1 do
  733. begin
  734. pd:=tprocdef(Tprocsym(p).ProcdefList[i]);
  735. if po_msgstr in pd.procoptions then
  736. begin
  737. new(pt);
  738. pt^.data:=pd;
  739. pt^.l:=nil;
  740. pt^.r:=nil;
  741. insertstr(pt,root,plongint(arg)^);
  742. end;
  743. end;
  744. end;
  745. procedure TVMTWriter.writenames(p : pprocdeftree);
  746. var
  747. ca : pchar;
  748. len : byte;
  749. begin
  750. current_asmdata.getdatalabel(p^.nl);
  751. if assigned(p^.l) then
  752. writenames(p^.l);
  753. current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(aint))));
  754. current_asmdata.asmlists[al_globals].concat(Tai_label.Create(p^.nl));
  755. len:=length(p^.data.messageinf.str^);
  756. current_asmdata.asmlists[al_globals].concat(tai_const.create_8bit(len));
  757. getmem(ca,len+1);
  758. move(p^.data.messageinf.str[1],ca^,len);
  759. ca[len]:=#0;
  760. current_asmdata.asmlists[al_globals].concat(Tai_string.Create_pchar(ca,len));
  761. if assigned(p^.r) then
  762. writenames(p^.r);
  763. end;
  764. procedure TVMTWriter.writestrentry(p : pprocdeftree);
  765. begin
  766. if assigned(p^.l) then
  767. writestrentry(p^.l);
  768. { write name label }
  769. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(p^.nl));
  770. current_asmdata.asmlists[al_globals].concat(Tai_const.Createname(p^.data.mangledname,0));
  771. if assigned(p^.r) then
  772. writestrentry(p^.r);
  773. end;
  774. function TVMTWriter.genstrmsgtab : tasmlabel;
  775. var
  776. count : aint;
  777. begin
  778. root:=nil;
  779. count:=0;
  780. { insert all message handlers into a tree, sorted by name }
  781. _class.symtable.SymList.ForEachCall(@insertmsgstr,@count);
  782. { write all names }
  783. if assigned(root) then
  784. writenames(root);
  785. { now start writing of the message string table }
  786. current_asmdata.getdatalabel(result);
  787. current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(aint))));
  788. current_asmdata.asmlists[al_globals].concat(Tai_label.Create(result));
  789. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_aint(count));
  790. if assigned(root) then
  791. begin
  792. writestrentry(root);
  793. disposeprocdeftree(root);
  794. end;
  795. end;
  796. procedure TVMTWriter.writeintentry(p : pprocdeftree);
  797. begin
  798. if assigned(p^.l) then
  799. writeintentry(p^.l);
  800. { write name label }
  801. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_32bit(p^.data.messageinf.i));
  802. current_asmdata.asmlists[al_globals].concat(Tai_const.Createname(p^.data.mangledname,0));
  803. if assigned(p^.r) then
  804. writeintentry(p^.r);
  805. end;
  806. function TVMTWriter.genintmsgtab : tasmlabel;
  807. var
  808. r : tasmlabel;
  809. count : longint;
  810. begin
  811. root:=nil;
  812. count:=0;
  813. { insert all message handlers into a tree, sorted by name }
  814. _class.symtable.SymList.ForEachCall(@insertmsgint,@count);
  815. { now start writing of the message string table }
  816. current_asmdata.getdatalabel(r);
  817. current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(aint))));
  818. current_asmdata.asmlists[al_globals].concat(Tai_label.Create(r));
  819. genintmsgtab:=r;
  820. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_32bit(count));
  821. if assigned(root) then
  822. begin
  823. writeintentry(root);
  824. disposeprocdeftree(root);
  825. end;
  826. end;
  827. {$ifdef WITHDMT}
  828. {**************************************
  829. DMT
  830. **************************************}
  831. procedure TVMTWriter.insertdmtentry(p:TObject;arg:pointer);
  832. var
  833. hp : tprocdef;
  834. pt : pprocdeftree;
  835. begin
  836. if tsym(p).typ=procsym then
  837. begin
  838. hp:=tprocsym(p).definition;
  839. while assigned(hp) do
  840. begin
  841. if (po_msgint in hp.procoptions) then
  842. begin
  843. new(pt);
  844. pt^.p:=hp;
  845. pt^.l:=nil;
  846. pt^.r:=nil;
  847. insertint(pt,root);
  848. end;
  849. hp:=hp.nextoverloaded;
  850. end;
  851. end;
  852. end;
  853. procedure TVMTWriter.writedmtindexentry(p : pprocdeftree);
  854. begin
  855. if assigned(p^.l) then
  856. writedmtindexentry(p^.l);
  857. al_globals.concat(Tai_const.Create_32bit(p^.data.messageinf.i));
  858. if assigned(p^.r) then
  859. writedmtindexentry(p^.r);
  860. end;
  861. procedure TVMTWriter.writedmtaddressentry(p : pprocdeftree);
  862. begin
  863. if assigned(p^.l) then
  864. writedmtaddressentry(p^.l);
  865. al_globals.concat(Tai_const_symbol.Createname(p^.data.mangledname,0));
  866. if assigned(p^.r) then
  867. writedmtaddressentry(p^.r);
  868. end;
  869. function TVMTWriter.gendmt : tasmlabel;
  870. var
  871. r : tasmlabel;
  872. begin
  873. root:=nil;
  874. count:=0;
  875. gendmt:=nil;
  876. { insert all message handlers into a tree, sorted by number }
  877. _class.symtable.SymList.ForEachCall(insertdmtentry);
  878. if count>0 then
  879. begin
  880. current_asmdata.getdatalabel(r);
  881. gendmt:=r;
  882. al_globals.concat(cai_align.create(const_align(sizeof(aint))));
  883. al_globals.concat(Tai_label.Create(r));
  884. { entries for caching }
  885. al_globals.concat(Tai_const.Create_ptr(0));
  886. al_globals.concat(Tai_const.Create_ptr(0));
  887. al_globals.concat(Tai_const.Create_32bit(count));
  888. if assigned(root) then
  889. begin
  890. writedmtindexentry(root);
  891. writedmtaddressentry(root);
  892. disposeprocdeftree(root);
  893. end;
  894. end;
  895. end;
  896. {$endif WITHDMT}
  897. {**************************************
  898. Published Methods
  899. **************************************}
  900. procedure TVMTWriter.do_count_published_methods(p:TObject;arg:pointer);
  901. var
  902. i : longint;
  903. pd : tprocdef;
  904. begin
  905. if (tsym(p).typ<>procsym) then
  906. exit;
  907. for i:=0 to Tprocsym(p).ProcdefList.Count-1 do
  908. begin
  909. pd:=tprocdef(Tprocsym(p).ProcdefList[i]);
  910. if (pd.procsym=tsym(p)) and
  911. (sp_published in pd.symoptions) then
  912. inc(plongint(arg)^);
  913. end;
  914. end;
  915. procedure TVMTWriter.do_gen_published_methods(p:TObject;arg:pointer);
  916. var
  917. i : longint;
  918. l : tasmlabel;
  919. pd : tprocdef;
  920. begin
  921. if (tsym(p).typ<>procsym) then
  922. exit;
  923. for i:=0 to Tprocsym(p).ProcdefList.Count-1 do
  924. begin
  925. pd:=tprocdef(Tprocsym(p).ProcdefList[i]);
  926. if (pd.procsym=tsym(p)) and
  927. (sp_published in pd.symoptions) then
  928. begin
  929. current_asmdata.getdatalabel(l);
  930. current_asmdata.asmlists[al_typedconsts].concat(cai_align.create(const_align(sizeof(aint))));
  931. current_asmdata.asmlists[al_typedconsts].concat(Tai_label.Create(l));
  932. current_asmdata.asmlists[al_typedconsts].concat(Tai_const.Create_8bit(length(tsym(p).realname)));
  933. current_asmdata.asmlists[al_typedconsts].concat(Tai_string.Create(tsym(p).realname));
  934. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(l));
  935. if po_abstractmethod in pd.procoptions then
  936. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil))
  937. else
  938. current_asmdata.asmlists[al_globals].concat(Tai_const.Createname(pd.mangledname,0));
  939. end;
  940. end;
  941. end;
  942. function TVMTWriter.genpublishedmethodstable : tasmlabel;
  943. var
  944. l : tasmlabel;
  945. count : longint;
  946. begin
  947. count:=0;
  948. _class.symtable.SymList.ForEachCall(@do_count_published_methods,@count);
  949. if count>0 then
  950. begin
  951. current_asmdata.getdatalabel(l);
  952. current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(aint))));
  953. current_asmdata.asmlists[al_globals].concat(Tai_label.Create(l));
  954. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_32bit(count));
  955. _class.symtable.SymList.ForEachCall(@do_gen_published_methods,nil);
  956. genpublishedmethodstable:=l;
  957. end
  958. else
  959. genpublishedmethodstable:=nil;
  960. end;
  961. function TVMTWriter.generate_field_table : tasmlabel;
  962. var
  963. i : longint;
  964. sym : tsym;
  965. fieldtable,
  966. classtable : tasmlabel;
  967. classindex,
  968. fieldcount : longint;
  969. classtablelist : TFPList;
  970. begin
  971. classtablelist:=TFPList.Create;
  972. current_asmdata.getdatalabel(fieldtable);
  973. current_asmdata.getdatalabel(classtable);
  974. maybe_new_object_file(current_asmdata.asmlists[al_rtti]);
  975. new_section(current_asmdata.asmlists[al_rtti],sec_rodata,classtable.name,const_align(sizeof(aint)));
  976. { retrieve field info fields }
  977. fieldcount:=0;
  978. for i:=0 to _class.symtable.SymList.Count-1 do
  979. begin
  980. sym:=tsym(_class.symtable.SymList[i]);
  981. if (tsym(sym).typ=fieldvarsym) and
  982. (sp_published in tsym(sym).symoptions) then
  983. begin
  984. if tfieldvarsym(sym).vardef.typ<>objectdef then
  985. internalerror(200611032);
  986. classindex:=classtablelist.IndexOf(tfieldvarsym(sym).vardef);
  987. if classindex=-1 then
  988. classtablelist.Add(tfieldvarsym(sym).vardef);
  989. inc(fieldcount);
  990. end;
  991. end;
  992. { write fields }
  993. current_asmdata.asmlists[al_rtti].concat(Tai_label.Create(fieldtable));
  994. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_16bit(fieldcount));
  995. {$ifdef cpurequiresproperalignment}
  996. current_asmdata.asmlists[al_rtti].concat(cai_align.Create(sizeof(TConstPtrUInt)));
  997. {$endif cpurequiresproperalignment}
  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. {$ifdef cpurequiresproperalignment}
  1006. current_asmdata.asmlists[al_rtti].concat(cai_align.Create(sizeof(AInt)));
  1007. {$endif cpurequiresproperalignment}
  1008. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_aint(tfieldvarsym(sym).fieldoffset));
  1009. classindex:=classtablelist.IndexOf(tfieldvarsym(sym).vardef);
  1010. if classindex=-1 then
  1011. internalerror(200611033);
  1012. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_16bit(classindex+1));
  1013. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(length(tfieldvarsym(sym).realname)));
  1014. current_asmdata.asmlists[al_rtti].concat(Tai_string.Create(tfieldvarsym(sym).realname));
  1015. end;
  1016. end;
  1017. { generate the class table }
  1018. current_asmdata.asmlists[al_rtti].concat(cai_align.create(const_align(sizeof(aint))));
  1019. current_asmdata.asmlists[al_rtti].concat(Tai_label.Create(classtable));
  1020. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_16bit(classtablelist.count));
  1021. {$ifdef cpurequiresproperalignment}
  1022. current_asmdata.asmlists[al_rtti].concat(cai_align.Create(sizeof(TConstPtrUInt)));
  1023. {$endif cpurequiresproperalignment}
  1024. for i:=0 to classtablelist.Count-1 do
  1025. current_asmdata.asmlists[al_rtti].concat(Tai_const.Createname(tobjectdef(classtablelist[i]).vmt_mangledname,0));
  1026. classtablelist.free;
  1027. result:=fieldtable;
  1028. end;
  1029. {**************************************
  1030. Interface tables
  1031. **************************************}
  1032. function TVMTWriter.intf_get_vtbl_name(AImplIntf:TImplementedInterface): string;
  1033. begin
  1034. result:=make_mangledname('VTBL',_class.owner,_class.objname^+'_$_'+AImplIntf.IntfDef.objname^);
  1035. end;
  1036. procedure TVMTWriter.intf_create_vtbl(rawdata: TAsmList;AImplIntf:TImplementedInterface);
  1037. var
  1038. pd : tprocdef;
  1039. vtblstr,
  1040. hs : string;
  1041. i : longint;
  1042. begin
  1043. vtblstr:=intf_get_vtbl_name(AImplIntf);
  1044. section_symbol_start(rawdata,vtblstr,AT_DATA,true,sec_data,const_align(sizeof(aint)));
  1045. if assigned(AImplIntf.procdefs) then
  1046. begin
  1047. for i:=0 to AImplIntf.procdefs.count-1 do
  1048. begin
  1049. pd:=tprocdef(AImplIntf.procdefs[i]);
  1050. hs:=make_mangledname('WRPR',_class.owner,_class.objname^+'_$_'+AImplIntf.IntfDef.objname^+'_$_'+
  1051. tostr(i)+'_$_'+pd.mangledname);
  1052. { create reference }
  1053. rawdata.concat(Tai_const.Createname(hs,0));
  1054. end;
  1055. end;
  1056. section_symbol_end(rawdata,vtblstr);
  1057. end;
  1058. procedure TVMTWriter.intf_gen_intf_ref(rawdata: TAsmList;AImplIntf:TImplementedInterface);
  1059. var
  1060. iidlabel,
  1061. guidlabel : tasmlabel;
  1062. i: longint;
  1063. begin
  1064. { GUID }
  1065. if AImplIntf.IntfDef.objecttype in [odt_interfacecom] then
  1066. begin
  1067. { label for GUID }
  1068. current_asmdata.getdatalabel(guidlabel);
  1069. rawdata.concat(cai_align.create(const_align(sizeof(aint))));
  1070. rawdata.concat(Tai_label.Create(guidlabel));
  1071. with AImplIntf.IntfDef.iidguid^ do
  1072. begin
  1073. rawdata.concat(Tai_const.Create_32bit(longint(D1)));
  1074. rawdata.concat(Tai_const.Create_16bit(D2));
  1075. rawdata.concat(Tai_const.Create_16bit(D3));
  1076. for i:=Low(D4) to High(D4) do
  1077. rawdata.concat(Tai_const.Create_8bit(D4[i]));
  1078. end;
  1079. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(guidlabel));
  1080. end
  1081. else
  1082. begin
  1083. { nil for Corba interfaces }
  1084. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  1085. end;
  1086. { VTable }
  1087. current_asmdata.asmlists[al_globals].concat(Tai_const.Createname(intf_get_vtbl_name(AImplIntf.VtblImplIntf),0));
  1088. { IOffset field }
  1089. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_aint(AImplIntf.VtblImplIntf.ioffset));
  1090. { IIDStr }
  1091. current_asmdata.getdatalabel(iidlabel);
  1092. rawdata.concat(cai_align.create(const_align(sizeof(aint))));
  1093. rawdata.concat(Tai_label.Create(iidlabel));
  1094. rawdata.concat(Tai_const.Create_8bit(length(AImplIntf.IntfDef.iidstr^)));
  1095. if AImplIntf.IntfDef.objecttype=odt_interfacecom then
  1096. rawdata.concat(Tai_string.Create(upper(AImplIntf.IntfDef.iidstr^)))
  1097. else
  1098. rawdata.concat(Tai_string.Create(AImplIntf.IntfDef.iidstr^));
  1099. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(iidlabel));
  1100. { EntryType }
  1101. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_aint(aint(AImplIntf.IntfDef.iitype)));
  1102. { EntryOffset }
  1103. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_aint(aint(AImplIntf.IntfDef.iioffset)));
  1104. end;
  1105. function TVMTWriter.intf_write_table:TAsmLabel;
  1106. var
  1107. rawdata : TAsmList;
  1108. i : longint;
  1109. ImplIntf : TImplementedInterface;
  1110. intftablelab : tasmlabel;
  1111. begin
  1112. current_asmdata.getdatalabel(intftablelab);
  1113. current_asmdata.asmlists[al_globals].concat(cai_align.create(const_align(sizeof(aint))));
  1114. current_asmdata.asmlists[al_globals].concat(Tai_label.Create(intftablelab));
  1115. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_aint(_class.ImplementedInterfaces.count));
  1116. rawdata:=TAsmList.Create;
  1117. { Write vtbls }
  1118. for i:=0 to _class.ImplementedInterfaces.count-1 do
  1119. begin
  1120. ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]);
  1121. if ImplIntf.VtblImplIntf=ImplIntf then
  1122. intf_create_vtbl(rawdata,ImplIntf);
  1123. end;
  1124. { Write vtbl references }
  1125. for i:=0 to _class.ImplementedInterfaces.count-1 do
  1126. begin
  1127. ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]);
  1128. intf_gen_intf_ref(rawdata,ImplIntf);
  1129. end;
  1130. { Write interface table }
  1131. current_asmdata.asmlists[al_globals].concatlist(rawdata);
  1132. rawdata.free;
  1133. result:=intftablelab;
  1134. end;
  1135. { Write interface identifiers to the data section }
  1136. procedure TVMTWriter.writeinterfaceids;
  1137. var
  1138. i : longint;
  1139. s : string;
  1140. begin
  1141. if assigned(_class.iidguid) then
  1142. begin
  1143. s:=make_mangledname('IID',_class.owner,_class.objname^);
  1144. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  1145. new_section(current_asmdata.asmlists[al_globals],sec_rodata,s,const_align(sizeof(aint)));
  1146. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  1147. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_32bit(longint(_class.iidguid^.D1)));
  1148. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_16bit(_class.iidguid^.D2));
  1149. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_16bit(_class.iidguid^.D3));
  1150. for i:=Low(_class.iidguid^.D4) to High(_class.iidguid^.D4) do
  1151. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_8bit(_class.iidguid^.D4[i]));
  1152. end;
  1153. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  1154. s:=make_mangledname('IIDSTR',_class.owner,_class.objname^);
  1155. new_section(current_asmdata.asmlists[al_globals],sec_rodata,s,0);
  1156. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
  1157. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_8bit(length(_class.iidstr^)));
  1158. current_asmdata.asmlists[al_globals].concat(Tai_string.Create(_class.iidstr^));
  1159. end;
  1160. procedure TVMTWriter.writevirtualmethods(List:TAsmList);
  1161. var
  1162. pd : tprocdef;
  1163. i : longint;
  1164. procname : string;
  1165. {$ifdef vtentry}
  1166. hs : string;
  1167. {$endif vtentry}
  1168. begin
  1169. if not assigned(_class.VMTEntries) then
  1170. exit;
  1171. for i:=0 to _class.VMTEntries.Count-1 do
  1172. begin
  1173. pd:=tprocdef(_class.VMTEntries[i]);
  1174. if not(po_virtualmethod in pd.procoptions) then
  1175. internalerror(200611082);
  1176. if pd.extnumber<>i then
  1177. internalerror(200611083);
  1178. if (po_abstractmethod in pd.procoptions) then
  1179. procname:='FPC_ABSTRACTERROR'
  1180. else
  1181. procname:=pd.mangledname;
  1182. List.concat(Tai_const.createname(procname,0));
  1183. {$ifdef vtentry}
  1184. hs:='VTENTRY'+'_'+_class.vmt_mangledname+'$$'+tostr(_class.vmtmethodoffset(i) div sizeof(aint));
  1185. current_asmdata.asmlists[al_globals].concat(tai_symbol.CreateName(hs,AT_DATA,0));
  1186. {$endif vtentry}
  1187. end;
  1188. { release VMTEntries, we don't need them anymore }
  1189. _class.VMTEntries.free;
  1190. _class.VMTEntries:=nil;
  1191. end;
  1192. procedure TVMTWriter.writevmt;
  1193. var
  1194. methodnametable,intmessagetable,
  1195. strmessagetable,classnamelabel,
  1196. fieldtablelabel : tasmlabel;
  1197. {$ifdef WITHDMT}
  1198. dmtlabel : tasmlabel;
  1199. {$endif WITHDMT}
  1200. interfacetable : tasmlabel;
  1201. {$ifdef vtentry}
  1202. hs: string;
  1203. {$endif vtentry}
  1204. begin
  1205. {$ifdef WITHDMT}
  1206. dmtlabel:=gendmt;
  1207. {$endif WITHDMT}
  1208. { write tables for classes, this must be done before the actual
  1209. class is written, because we need the labels defined }
  1210. if is_class(_class) then
  1211. begin
  1212. current_asmdata.getdatalabel(classnamelabel);
  1213. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  1214. new_section(current_asmdata.asmlists[al_globals],sec_rodata,classnamelabel.name,const_align(sizeof(aint)));
  1215. { interface table }
  1216. if _class.ImplementedInterfaces.count>0 then
  1217. interfacetable:=intf_write_table;
  1218. methodnametable:=genpublishedmethodstable;
  1219. fieldtablelabel:=generate_field_table;
  1220. { write class name }
  1221. current_asmdata.asmlists[al_globals].concat(Tai_label.Create(classnamelabel));
  1222. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_8bit(length(_class.objrealname^)));
  1223. current_asmdata.asmlists[al_globals].concat(Tai_string.Create(_class.objrealname^));
  1224. { generate message and dynamic tables }
  1225. if (oo_has_msgstr in _class.objectoptions) then
  1226. strmessagetable:=genstrmsgtab;
  1227. if (oo_has_msgint in _class.objectoptions) then
  1228. intmessagetable:=genintmsgtab;
  1229. end;
  1230. { write debug info }
  1231. maybe_new_object_file(current_asmdata.asmlists[al_globals]);
  1232. new_section(current_asmdata.asmlists[al_globals],sec_rodata,_class.vmt_mangledname,const_align(sizeof(aint)));
  1233. current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(_class.vmt_mangledname,AT_DATA,0));
  1234. { determine the size with symtable.datasize, because }
  1235. { size gives back 4 for classes }
  1236. current_asmdata.asmlists[al_globals].concat(Tai_const.Create(aitconst_ptr,tObjectSymtable(_class.symtable).datasize));
  1237. current_asmdata.asmlists[al_globals].concat(Tai_const.Create(aitconst_ptr,-int64(tObjectSymtable(_class.symtable).datasize)));
  1238. {$ifdef WITHDMT}
  1239. if _class.classtype=ct_object then
  1240. begin
  1241. if assigned(dmtlabel) then
  1242. current_asmdata.asmlists[al_globals].concat(Tai_const_symbol.Create(dmtlabel)))
  1243. else
  1244. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_ptr(0));
  1245. end;
  1246. {$endif WITHDMT}
  1247. { write pointer to parent VMT, this isn't implemented in TP }
  1248. { but this is not used in FPC ? (PM) }
  1249. { it's not used yet, but the delphi-operators as and is need it (FK) }
  1250. { it is not written for parents that don't have any vmt !! }
  1251. if assigned(_class.childof) and
  1252. (oo_has_vmt in _class.childof.objectoptions) then
  1253. current_asmdata.asmlists[al_globals].concat(Tai_const.Createname(_class.childof.vmt_mangledname,0))
  1254. else
  1255. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  1256. { write extended info for classes, for the order see rtl/inc/objpash.inc }
  1257. if is_class(_class) then
  1258. begin
  1259. { pointer to class name string }
  1260. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(classnamelabel));
  1261. { pointer to dynamic table or nil }
  1262. if (oo_has_msgint in _class.objectoptions) then
  1263. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(intmessagetable))
  1264. else
  1265. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  1266. { pointer to method table or nil }
  1267. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(methodnametable));
  1268. { pointer to field table }
  1269. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(fieldtablelabel));
  1270. { pointer to type info of published section }
  1271. if (oo_can_have_published in _class.objectoptions) then
  1272. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(RTTIWriter.get_rtti_label(_class,fullrtti)))
  1273. else
  1274. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  1275. { inittable for con-/destruction }
  1276. if _class.members_need_inittable then
  1277. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(RTTIWriter.get_rtti_label(_class,initrtti)))
  1278. else
  1279. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  1280. { auto table }
  1281. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  1282. { interface table }
  1283. if _class.ImplementedInterfaces.count>0 then
  1284. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(interfacetable))
  1285. else
  1286. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  1287. { table for string messages }
  1288. if (oo_has_msgstr in _class.objectoptions) then
  1289. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(strmessagetable))
  1290. else
  1291. current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
  1292. end;
  1293. { write virtual methods }
  1294. writevirtualmethods(current_asmdata.asmlists[al_globals]);
  1295. current_asmdata.asmlists[al_globals].concat(Tai_const.create(aitconst_ptr,0));
  1296. { write the size of the VMT }
  1297. current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(_class.vmt_mangledname));
  1298. {$ifdef vtentry}
  1299. { write vtinherit symbol to notify the linker of the class inheritance tree }
  1300. hs:='VTINHERIT'+'_'+_class.vmt_mangledname+'$$';
  1301. if assigned(_class.childof) then
  1302. hs:=hs+_class.childof.vmt_mangledname
  1303. else
  1304. hs:=hs+_class.vmt_mangledname;
  1305. current_asmdata.asmlists[al_globals].concat(tai_symbol.CreateName(hs,AT_DATA,0));
  1306. {$endif vtentry}
  1307. end;
  1308. end.