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