nobj.pas 56 KB

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