nobj.pas 57 KB

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