nobj.pas 59 KB

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