nobj.pas 56 KB

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