nobj.pas 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  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. ;
  26. type
  27. TVMTBuilder=class
  28. private
  29. _Class : tobjectdef;
  30. handledprotocols: tfpobjectlist;
  31. function is_new_vmt_entry(pd:tprocdef; out overridesclasshelper: boolean):boolean;
  32. procedure add_new_vmt_entry(pd:tprocdef; allowoverridingmethod: boolean);
  33. function check_msg_str(vmtpd, pd: tprocdef):boolean;
  34. function intf_search_procdef_by_name(proc: tprocdef;const name: string): tprocdef;
  35. procedure intf_get_procdefs(ImplIntf:TImplementedInterface;IntfDef:TObjectDef);
  36. procedure intf_get_procdefs_recursive(ImplIntf:TImplementedInterface;IntfDef:TObjectDef);
  37. procedure prot_get_procdefs_recursive(ImplProt:TImplementedInterface;ProtDef:TObjectDef);
  38. procedure intf_optimize_vtbls;
  39. procedure intf_allocate_vtbls;
  40. public
  41. constructor create(c:tobjectdef);
  42. procedure generate_vmt;
  43. procedure build_interface_mappings;
  44. end;
  45. implementation
  46. uses
  47. SysUtils,
  48. globals,verbose,systems,
  49. node,
  50. symbase,symtable,symconst,symtype,defcmp,
  51. symcpu,
  52. dbgbase,
  53. wpobase
  54. ;
  55. {*****************************************************************************
  56. TVMTBuilder
  57. *****************************************************************************}
  58. constructor TVMTBuilder.create(c:tobjectdef);
  59. begin
  60. inherited Create;
  61. _Class:=c;
  62. end;
  63. procedure TVMTBuilder.add_new_vmt_entry(pd:tprocdef; allowoverridingmethod: boolean);
  64. var
  65. i : longint;
  66. vmtentry : pvmtentry;
  67. vmtpd : tprocdef;
  68. begin
  69. { new entry is needed, override was not possible }
  70. { Allowed when overriding a category method for a parent class in a
  71. descendent Objective-C class }
  72. if not allowoverridingmethod and
  73. (po_overridingmethod in pd.procoptions) then
  74. MessagePos1(pd.fileinfo,parser_e_nothing_to_be_overridden,pd.fullprocname(false));
  75. { check that all methods have overload directive }
  76. if not(m_fpc in current_settings.modeswitches) then
  77. begin
  78. for i:=0 to _class.vmtentries.count-1 do
  79. begin
  80. vmtentry:=pvmtentry(_class.vmtentries[i]);
  81. vmtpd:=tprocdef(vmtentry^.procdef);
  82. if (vmtpd.procsym=pd.procsym) and
  83. (not(po_overload in pd.procoptions) or
  84. not(po_overload in vmtpd.procoptions)) then
  85. begin
  86. MessagePos1(pd.fileinfo,parser_e_no_overload_for_all_procs,pd.procsym.realname);
  87. { recover }
  88. include(vmtpd.procoptions,po_overload);
  89. include(pd.procoptions,po_overload);
  90. end;
  91. end;
  92. end;
  93. { Register virtual method and give it a number }
  94. if (po_virtualmethod in pd.procoptions) then
  95. begin
  96. { store vmt entry number in procdef }
  97. if (pd.extnumber<>$ffff) and
  98. (pd.extnumber<>_class.VMTEntries.Count) then
  99. internalerror(200810283);
  100. pd.extnumber:=_class.VMTEntries.Count;
  101. new(vmtentry);
  102. vmtentry^.procdef:=pd;
  103. vmtentry^.procdefderef.reset;
  104. vmtentry^.visibility:=pd.visibility;
  105. _class.VMTEntries.Add(vmtentry);
  106. end;
  107. end;
  108. function TVMTBuilder.check_msg_str(vmtpd, pd: tprocdef): boolean;
  109. begin
  110. result:=true;
  111. if not(is_objc_class_or_protocol(_class)) then
  112. begin
  113. { the only requirement for normal methods is that both either
  114. have a message string or not (the value is irrelevant) }
  115. if ((pd.procoptions * [po_msgstr]) <> (vmtpd.procoptions * [po_msgstr])) then
  116. begin
  117. MessagePos1(pd.fileinfo,parser_e_header_dont_match_forward,pd.fullprocname(false));
  118. tprocsym(vmtpd.procsym).write_parameter_lists(pd);
  119. result:=false;
  120. end
  121. end
  122. else
  123. begin
  124. { the compiler should have ensured that the protocol or parent
  125. class method has a message name specified }
  126. if not(po_msgstr in vmtpd.procoptions) then
  127. internalerror(2009070601);
  128. if not(po_msgstr in pd.procoptions) then
  129. begin
  130. { copy the protocol's/parent class' message name to the one in
  131. the class if none has been specified there }
  132. include(pd.procoptions,po_msgstr);
  133. pd.messageinf.str:=stringdup(vmtpd.messageinf.str^);
  134. end
  135. else
  136. begin
  137. { if both have a message name, make sure they are equal }
  138. if (vmtpd.messageinf.str^<>pd.messageinf.str^) then
  139. begin
  140. MessagePos2(pd.fileinfo,parser_e_objc_message_name_changed,vmtpd.messageinf.str^,pd.messageinf.str^);
  141. result:=false;
  142. end;
  143. end;
  144. end;
  145. end;
  146. function TVMTBuilder.is_new_vmt_entry(pd:tprocdef; out overridesclasshelper: boolean):boolean;
  147. const
  148. po_comp = [po_classmethod,po_virtualmethod,po_staticmethod,po_interrupt,po_iocheck,po_msgint,
  149. po_exports,po_varargs,po_explicitparaloc,po_nostackframe];
  150. var
  151. i : longint;
  152. hasequalpara,
  153. hasoverloads,
  154. pdoverload : boolean;
  155. srsym : tsym;
  156. st : tsymtable;
  157. // returns true if we can stop checking, false if we have to continue
  158. function found_entry(var vmtpd: tprocdef; var vmtentryvis: tvisibility; updatevalues: boolean): boolean;
  159. {$ifdef jvm}
  160. var
  161. javanewtreeok: boolean;
  162. {$endif jvm}
  163. begin
  164. result:=false;
  165. { ignore hidden entries (e.g. virtual overridden by a static) that are not visible anymore }
  166. if vmtentryvis=vis_hidden then
  167. exit;
  168. { ignore different names }
  169. if vmtpd.procsym.name<>pd.procsym.name then
  170. exit;
  171. { hide private methods that are not visible anymore. For this check we
  172. must override the visibility with the highest value in the override chain.
  173. This is required for case (see tw3292) with protected-private-protected where the
  174. same vmtentry is used (PFV) }
  175. if not is_visible_for_object(vmtpd.owner,vmtentryvis,_class) then
  176. exit;
  177. { inherit overload }
  178. if (po_overload in vmtpd.procoptions) then
  179. begin
  180. include(pd.procoptions,po_overload);
  181. pdoverload:=true;
  182. end;
  183. { compare parameter types only, no specifiers yet }
  184. hasequalpara:=(compare_paras(vmtpd.paras,pd.paras,cp_none,[cpo_ignoreuniv,cpo_ignorehidden])>=te_equal);
  185. { check that we are not trying to override a final method }
  186. { in Java, new virtual inheritance trees can never be started ->
  187. treat all methods as "overriding" in the context of this check
  188. (Java does check whether the mangled names are identical, so if they
  189. are not we can stil get away with it) }
  190. if (po_finalmethod in vmtpd.procoptions) and
  191. hasequalpara and
  192. ((po_overridingmethod in pd.procoptions) or
  193. (is_javaclass(_class) and
  194. (pd.mangledname=vmtpd.mangledname))) and
  195. (is_class(_class) or is_objectpascal_helper(_class) or is_javaclass(_class)) then
  196. MessagePos1(pd.fileinfo,parser_e_final_can_no_be_overridden,pd.fullprocname(false))
  197. else
  198. { old definition has virtual
  199. new definition has no virtual or override }
  200. if (po_virtualmethod in vmtpd.procoptions) and
  201. (
  202. not(po_virtualmethod in pd.procoptions) or
  203. (
  204. { new one does not have reintroduce in case of an objccategory }
  205. (is_objccategory(_class) and
  206. not(po_reintroduce in pd.procoptions)) or
  207. { new one does not have override in case of objpas/objc/java class/intf/proto }
  208. ((is_class_or_interface_or_objc_or_java(_class) or is_objectpascal_helper(_class)) and
  209. not is_objccategory(_class) and
  210. not(po_overridingmethod in pd.procoptions)
  211. )
  212. )
  213. ) then
  214. begin
  215. if (
  216. not(pdoverload or hasoverloads) or
  217. hasequalpara
  218. ) then
  219. begin
  220. {$ifdef jvm}
  221. { if the mangled names are different, the inheritance trees
  222. are different too in Java; exception: when the parent method
  223. is a virtual class method or virtual constructor, because
  224. those are looked up dynamicall by name }
  225. javanewtreeok:=
  226. is_java_class_or_interface(_class) and
  227. (tcpuprocdef(pd).jvmmangledbasename(false)<>tcpuprocdef(vmtpd).jvmmangledbasename(false)) and
  228. ((vmtpd.proctypeoption<>potype_constructor) and
  229. not(po_staticmethod in vmtpd.procoptions));
  230. {$endif}
  231. if not(po_reintroduce in pd.procoptions) and
  232. not(po_java_nonvirtual in vmtpd.procoptions) then
  233. if not(is_objc_class_or_protocol(_class))
  234. {$ifdef jvm}
  235. and (not is_java_class_or_interface(_class) or
  236. javanewtreeok)
  237. {$endif jvm}
  238. then
  239. MessagePos1(pd.fileinfo,parser_w_should_use_override,pd.fullprocname(false))
  240. else
  241. begin
  242. { In Objective-C, you cannot create a new VMT entry to
  243. start a new inheritance tree. We therefore give an
  244. error when the class is implemented in Pascal, to
  245. avoid confusion due to things working differently
  246. with Object Pascal classes.
  247. In case of external classes, we only give a hint,
  248. because requiring override everywhere may make
  249. automated header translation tools too complex.
  250. The same goes for Java. }
  251. {$ifndef jvm}
  252. if hasequalpara then
  253. {$endif}
  254. begin
  255. if not(oo_is_external in _class.objectoptions) then
  256. if not is_objccategory(_class) then
  257. MessagePos1(pd.fileinfo,parser_e_must_use_override,FullTypeName(tdef(vmtpd.owner.defowner),nil))
  258. else
  259. MessagePos1(pd.fileinfo,parser_e_must_use_reintroduce_objc,FullTypeName(tdef(vmtpd.owner.defowner),nil))
  260. { there may be a lot of these in auto-translated
  261. headers, so only calculate the fulltypename if
  262. the hint will be shown }
  263. else if CheckVerbosity(V_Hint) then
  264. if not is_objccategory(_class) then
  265. MessagePos1(pd.fileinfo,parser_h_should_use_override,FullTypeName(tdef(vmtpd.owner.defowner),nil))
  266. else
  267. MessagePos1(pd.fileinfo,parser_h_should_use_reintroduce_objc,FullTypeName(tdef(vmtpd.owner.defowner),nil));
  268. end;
  269. { no new entry, but copy the message name if any from
  270. the procdef in the parent class }
  271. if not is_objc_class_or_protocol(_class) or
  272. hasequalpara then
  273. check_msg_str(vmtpd,pd);
  274. if updatevalues then
  275. begin
  276. { in case of Java, copy the real name from the parent,
  277. since overriding "Destroy" with "destroy" is not
  278. going to work very well }
  279. if is_java_class_or_interface(_class) and
  280. (pd.procsym.realname<>vmtpd.procsym.realname) then
  281. pd.procsym.realname:=vmtpd.procsym.realname;
  282. { in case we are overriding an abstract method,
  283. decrease the number of abstract methods in this class }
  284. if (po_abstractmethod in vmtpd.procoptions) then
  285. dec(tobjectdef(pd.owner.defowner).abstractcnt);
  286. if (vmtpd.extnumber<>i) then
  287. internalerror(2011083101);
  288. pd.extnumber:=vmtpd.extnumber;
  289. vmtpd:=pd;
  290. end;
  291. result:=true;
  292. exit;
  293. {$ifdef jvm}
  294. end
  295. else
  296. if not javanewtreeok and
  297. is_java_class_or_interface(_class) then
  298. begin
  299. { mangled names are the same -> can only override }
  300. MessagePos1(pd.fileinfo,parser_e_must_use_override,FullTypeName(tdef(vmtpd.owner.defowner),nil))
  301. {$endif jvm}
  302. end;
  303. { disable/hide old VMT entry }
  304. if updatevalues then
  305. vmtentryvis:=vis_hidden;
  306. end;
  307. end
  308. { both are virtual? }
  309. else if (po_virtualmethod in pd.procoptions) and
  310. (po_virtualmethod in vmtpd.procoptions) then
  311. begin
  312. { same parameter and return types (parameter specifiers will be checked below) }
  313. if hasequalpara and
  314. compatible_childmethod_resultdef(vmtpd.returndef,pd.returndef) then
  315. begin
  316. { inherite calling convention when it was explicit and the
  317. current definition has none explicit set }
  318. if (po_hascallingconvention in vmtpd.procoptions) and
  319. not(po_hascallingconvention in pd.procoptions) then
  320. begin
  321. pd.proccalloption:=vmtpd.proccalloption;
  322. include(pd.procoptions,po_hascallingconvention);
  323. end;
  324. { All parameter specifiers and some procedure the flags have to match
  325. except abstract and override }
  326. if (compare_paras(vmtpd.paras,pd.paras,cp_all,[cpo_ignoreuniv,cpo_ignorehidden])<te_equal) or
  327. (vmtpd.proccalloption<>pd.proccalloption) or
  328. (vmtpd.proctypeoption<>pd.proctypeoption) or
  329. ((vmtpd.procoptions*po_comp)<>(pd.procoptions*po_comp)) then
  330. begin
  331. MessagePos1(pd.fileinfo,parser_e_header_dont_match_forward,pd.fullprocname(false));
  332. tprocsym(vmtpd.procsym).write_parameter_lists(pd);
  333. end;
  334. check_msg_str(vmtpd,pd);
  335. { Give a note if the new visibility is lower. For a higher
  336. visibility update the vmt info }
  337. if vmtentryvis>pd.visibility then
  338. begin
  339. if po_auto_raised_visibility in vmtpd.procoptions then
  340. begin
  341. if updatevalues then
  342. begin
  343. pd.visibility:=vmtentryvis;
  344. { this one's visibility is now also auto-raised }
  345. include(pd.procoptions,po_auto_raised_visibility);
  346. end
  347. end
  348. else
  349. {$ifdef jvm}
  350. MessagePos4(pd.fileinfo,parser_e_method_lower_visibility,
  351. {$else jvm}
  352. MessagePos4(pd.fileinfo,parser_n_ignore_lower_visibility,
  353. {$endif jvm}
  354. pd.fullprocname(false),
  355. visibilityname[pd.visibility],tobjectdef(vmtpd.owner.defowner).objrealname^,visibilityname[vmtentryvis])
  356. end
  357. else if pd.visibility>vmtentryvis then
  358. begin
  359. if updatevalues then
  360. vmtentryvis:=pd.visibility;
  361. end;
  362. { override old virtual method in VMT }
  363. if updatevalues then
  364. begin
  365. { in case we are overriding an abstract method,
  366. decrease the number of abstract methods in this class }
  367. if (po_overridingmethod in pd.procoptions) and
  368. (po_abstractmethod in vmtpd.procoptions) then
  369. dec(tobjectdef(pd.owner.defowner).abstractcnt);
  370. if (vmtpd.extnumber<>i) then
  371. internalerror(200611084);
  372. pd.extnumber:=vmtpd.extnumber;
  373. { in case of Java, copy the real name from the parent,
  374. since overriding "Destroy" with "destroy" is not
  375. going to work very well }
  376. if is_java_class_or_interface(_class) and
  377. (pd.procsym.realname<>vmtpd.procsym.realname) then
  378. pd.procsym.realname:=vmtpd.procsym.realname;
  379. vmtpd:=pd;
  380. end;
  381. result:=true;
  382. exit;
  383. end
  384. { different parameters }
  385. else
  386. begin
  387. { when we got an override directive then can search futher for
  388. the procedure to override.
  389. If we are starting a new virtual tree then hide the old tree }
  390. if not(po_overridingmethod in pd.procoptions) and
  391. not(pdoverload or hasoverloads) then
  392. begin
  393. if not(po_reintroduce in pd.procoptions) then
  394. begin
  395. if not is_object(_class) and
  396. not is_objc_class_or_protocol(_class) and
  397. not is_java_class_or_interface(_class) then
  398. MessagePos1(pd.fileinfo,parser_w_should_use_override,pd.fullprocname(false))
  399. else
  400. { objects don't allow starting a new virtual tree
  401. and neither do Objective-C or Java }
  402. MessagePos1(pd.fileinfo,parser_e_header_dont_match_forward,vmtpd.fullprocname(false));
  403. end;
  404. { disable/hide old VMT entry }
  405. if updatevalues then
  406. vmtentryvis:=vis_hidden;
  407. end;
  408. end;
  409. end;
  410. end;
  411. function found_category_method(st: tsymtable): boolean;
  412. var
  413. entrycount: longint;
  414. cat: tobjectdef;
  415. vmtpd: tprocdef;
  416. vmtvis: tvisibility;
  417. begin
  418. result:=false;
  419. if is_objccategory(tdef(st.defowner)) then
  420. begin
  421. cat:=tobjectdef(st.defowner);
  422. { go through all of the category's methods to find the
  423. vmtentry corresponding to the procdef we are handling }
  424. for entrycount:=0 to cat.vmtentries.Count-1 do
  425. begin
  426. vmtpd:=pvmtentry(cat.vmtentries[entrycount])^.procdef;
  427. vmtvis:=pvmtentry(cat.vmtentries[entrycount])^.visibility;
  428. { don't change the vmtentry of the category }
  429. if found_entry(vmtpd,vmtvis,false) then
  430. begin
  431. result:=true;
  432. exit;
  433. end;
  434. end;
  435. end;
  436. end;
  437. begin
  438. result:=false;
  439. overridesclasshelper:=false;
  440. { Load other values for easier readability }
  441. hasoverloads:=(tprocsym(pd.procsym).ProcdefList.Count>1);
  442. pdoverload:=(po_overload in pd.procoptions);
  443. { compare with all stored definitions }
  444. for i:=0 to _class.vmtentries.Count-1 do
  445. begin
  446. if found_entry(pvmtentry(_class.vmtentries[i])^.procdef, pvmtentry(_class.vmtentries[i])^.visibility,true) then
  447. exit;
  448. end;
  449. { in case of Objective-C, also check the categories that apply to this
  450. class' *parent* for methods to override (don't allow class X to
  451. "override" a method added by a category to class X itself, since in
  452. that case the category method will in fact replace class X'
  453. "overriding" method }
  454. if is_objcclass(_class) and
  455. assigned(_class.childof) and
  456. search_objc_helper(_class.childof,pd.procsym.name,srsym,st) then
  457. begin
  458. overridesclasshelper:=found_category_method(st);
  459. end;
  460. { No entry found, we need to create a new entry }
  461. result:=true;
  462. end;
  463. function TVMTBuilder.intf_search_procdef_by_name(proc: tprocdef;const name: string): tprocdef;
  464. const
  465. po_comp = [po_classmethod,po_staticmethod,po_interrupt,po_iocheck,po_msgint,
  466. po_exports,po_varargs,po_explicitparaloc,po_nostackframe];
  467. var
  468. implprocdef : Tprocdef;
  469. i: cardinal;
  470. hclass : tobjectdef;
  471. hashedid : THashedIDString;
  472. srsym : tsym;
  473. begin
  474. result:=nil;
  475. hashedid.id:=name;
  476. hclass:=_class;
  477. while assigned(hclass) do
  478. begin
  479. srsym:=tsym(hclass.symtable.FindWithHash(hashedid));
  480. if assigned(srsym) and
  481. (srsym.typ=procsym) then
  482. begin
  483. for i:=0 to Tprocsym(srsym).ProcdefList.Count-1 do
  484. begin
  485. implprocdef:=tprocdef(tprocsym(srsym).ProcdefList[i]);
  486. if (implprocdef.procsym=tprocsym(srsym)) and
  487. (compare_paras(proc.paras,implprocdef.paras,cp_all,[cpo_ignorehidden,cpo_ignoreuniv])>=te_equal) and
  488. (compare_defs(proc.returndef,implprocdef.returndef,nothingn)>=te_equal) and
  489. (proc.proccalloption=implprocdef.proccalloption) and
  490. (proc.proctypeoption=implprocdef.proctypeoption) and
  491. ((proc.procoptions*po_comp)=((implprocdef.procoptions+[po_virtualmethod])*po_comp)) and
  492. check_msg_str(proc,implprocdef) then
  493. begin
  494. { does the interface increase the visibility of the
  495. implementing method? }
  496. if implprocdef.visibility<proc.visibility then
  497. {$ifdef jvm}
  498. MessagePos2(implprocdef.fileinfo,type_e_interface_lower_visibility,proc.fullprocname(false),implprocdef.fullprocname(false));
  499. {$else}
  500. MessagePos2(implprocdef.fileinfo,type_w_interface_lower_visibility,proc.fullprocname(false),implprocdef.fullprocname(false));
  501. {$endif}
  502. result:=implprocdef;
  503. exit;
  504. end;
  505. end;
  506. end;
  507. hclass:=hclass.childof;
  508. end;
  509. end;
  510. procedure TVMTBuilder.intf_get_procdefs(ImplIntf:TImplementedInterface;IntfDef:TObjectDef);
  511. var
  512. i : longint;
  513. def : tdef;
  514. hs,
  515. prefix,
  516. mappedname: string;
  517. implprocdef: tprocdef;
  518. begin
  519. prefix:=ImplIntf.IntfDef.symtable.name^+'.';
  520. for i:=0 to IntfDef.symtable.DefList.Count-1 do
  521. begin
  522. def:=tdef(IntfDef.symtable.DefList[i]);
  523. if assigned(def) and
  524. (def.typ=procdef) then
  525. begin
  526. { Find implementing procdef
  527. 1. Check for mapped name
  528. 2. Use symbol name, but only if there's no mapping,
  529. or we're processing ancestor of interface.
  530. When modifying this code, ensure that webtbs/tw11862, webtbs/tw4950
  531. and webtbf/tw19591 stay correct. }
  532. implprocdef:=nil;
  533. hs:=prefix+tprocdef(def).procsym.name;
  534. mappedname:=ImplIntf.GetMapping(hs);
  535. if mappedname<>'' then
  536. implprocdef:=intf_search_procdef_by_name(tprocdef(def),mappedname);
  537. if not assigned(implprocdef) then
  538. if (mappedname='') or (ImplIntf.IntfDef<>IntfDef) then
  539. implprocdef:=intf_search_procdef_by_name(tprocdef(def),tprocdef(def).procsym.name);
  540. { Add procdef to the implemented interface }
  541. if assigned(implprocdef) then
  542. begin
  543. if (tobjectdef(implprocdef.struct).objecttype<>odt_objcclass) then
  544. begin
  545. { in case of Java, copy the real name from the parent,
  546. since overriding "Destroy" with "destroy" is not
  547. going to work very well }
  548. if is_javaclass(implprocdef.struct) and
  549. (implprocdef.procsym.realname<>tprocdef(def).procsym.realname) then
  550. implprocdef.procsym.realname:=tprocdef(def).procsym.realname;
  551. ImplIntf.AddImplProc(implprocdef);
  552. end
  553. else
  554. begin
  555. { If no message name has been specified for the method
  556. in the objcclass, copy it from the protocol
  557. definition. }
  558. if not(po_msgstr in tprocdef(def).procoptions) then
  559. begin
  560. include(tprocdef(def).procoptions,po_msgstr);
  561. implprocdef.messageinf.str:=stringdup(tprocdef(def).messageinf.str^);
  562. end
  563. else
  564. begin
  565. { If a message name has been specified in the
  566. objcclass, it has to match the message name in the
  567. protocol definition. }
  568. if (implprocdef.messageinf.str^<>tprocdef(def).messageinf.str^) then
  569. MessagePos2(implprocdef.fileinfo,parser_e_objc_message_name_changed,tprocdef(def).messageinf.str^,implprocdef.messageinf.str^);
  570. end;
  571. end;
  572. end
  573. else
  574. if (ImplIntf.IType=etStandard) and
  575. not(po_optional in tprocdef(def).procoptions) then
  576. MessagePos1(_Class.typesym.fileinfo,sym_e_no_matching_implementation_found,tprocdef(def).fullprocname(false));
  577. end;
  578. end;
  579. end;
  580. procedure TVMTBuilder.intf_get_procdefs_recursive(ImplIntf:TImplementedInterface;IntfDef:TObjectDef);
  581. begin
  582. if assigned(IntfDef.childof) then
  583. intf_get_procdefs_recursive(ImplIntf,IntfDef.childof);
  584. intf_get_procdefs(ImplIntf,IntfDef);
  585. end;
  586. procedure TVMTBuilder.prot_get_procdefs_recursive(ImplProt:TImplementedInterface;ProtDef:TObjectDef);
  587. var
  588. i: longint;
  589. begin
  590. { don't check the same protocol twice }
  591. if handledprotocols.IndexOf(ProtDef)<>-1 then
  592. exit;
  593. handledprotocols.add(ProtDef);
  594. for i:=0 to ProtDef.ImplementedInterfaces.count-1 do
  595. prot_get_procdefs_recursive(ImplProt,TImplementedInterface(ProtDef.ImplementedInterfaces[i]).intfdef);
  596. intf_get_procdefs(ImplProt,ProtDef);
  597. end;
  598. procedure TVMTBuilder.intf_optimize_vtbls;
  599. type
  600. tcompintfentry = record
  601. weight: longint;
  602. compintf: longint;
  603. end;
  604. { Max 1000 interface in the class header interfaces it's enough imho }
  605. tcompintfs = array[0..1000] of tcompintfentry;
  606. pcompintfs = ^tcompintfs;
  607. tequals = array[0..1000] of longint;
  608. pequals = ^tequals;
  609. timpls = array[0..1000] of longint;
  610. pimpls = ^timpls;
  611. var
  612. aequals: pequals;
  613. compats: pcompintfs;
  614. impls: pimpls;
  615. ImplIntfCount,
  616. w,i,j,k: longint;
  617. ImplIntfI,
  618. ImplIntfJ : TImplementedInterface;
  619. cij: boolean;
  620. cji: boolean;
  621. begin
  622. ImplIntfCount:=_class.ImplementedInterfaces.count;
  623. if ImplIntfCount>=High(tequals) then
  624. Internalerror(200006135);
  625. getmem(compats,sizeof(tcompintfentry)*ImplIntfCount);
  626. getmem(aequals,sizeof(longint)*ImplIntfCount);
  627. getmem(impls,sizeof(longint)*ImplIntfCount);
  628. filldword(compats^,(sizeof(tcompintfentry) div sizeof(dword))*ImplIntfCount,dword(-1));
  629. filldword(aequals^,ImplIntfCount,dword(-1));
  630. filldword(impls^,ImplIntfCount,dword(-1));
  631. { ismergepossible is a containing relation
  632. meaning of ismergepossible(a,b,w) =
  633. if implementorfunction map of a is contained implementorfunction map of b
  634. imp(a,b) and imp(b,c) => imp(a,c) ; imp(a,b) and imp(b,a) => a == b
  635. }
  636. { the order is very important for correct allocation }
  637. for i:=0 to ImplIntfCount-1 do
  638. begin
  639. for j:=i+1 to ImplIntfCount-1 do
  640. begin
  641. ImplIntfI:=TImplementedInterface(_class.ImplementedInterfaces[i]);
  642. ImplIntfJ:=TImplementedInterface(_class.ImplementedInterfaces[j]);
  643. cij:=ImplIntfI.IsImplMergePossible(ImplIntfJ,w);
  644. cji:=ImplIntfJ.IsImplMergePossible(ImplIntfI,w);
  645. if cij and cji then { i equal j }
  646. begin
  647. { get minimum index of equal }
  648. if aequals^[j]=-1 then
  649. aequals^[j]:=i;
  650. end
  651. else if cij then
  652. begin
  653. { get minimum index of maximum weight }
  654. if compats^[i].weight<w then
  655. begin
  656. compats^[i].weight:=w;
  657. compats^[i].compintf:=j;
  658. end;
  659. end
  660. else if cji then
  661. begin
  662. { get minimum index of maximum weight }
  663. if (compats^[j].weight<w) then
  664. begin
  665. compats^[j].weight:=w;
  666. compats^[j].compintf:=i;
  667. end;
  668. end;
  669. end;
  670. end;
  671. { Reset, no replacements by default }
  672. for i:=0 to ImplIntfCount-1 do
  673. impls^[i]:=i;
  674. { Replace vtbls when equal or compat, repeat
  675. until there are no replacements possible anymore. This is
  676. needed for the cases like:
  677. First loop: 2->3, 3->1
  678. Second loop: 2->1 (because 3 was replaced with 1)
  679. }
  680. repeat
  681. k:=0;
  682. for i:=0 to ImplIntfCount-1 do
  683. begin
  684. if compats^[impls^[i]].compintf<>-1 then
  685. impls^[i]:=compats^[impls^[i]].compintf
  686. else if aequals^[impls^[i]]<>-1 then
  687. impls^[i]:=aequals^[impls^[i]]
  688. else
  689. inc(k);
  690. end;
  691. until k=ImplIntfCount;
  692. { Update the VtblImplIntf }
  693. for i:=0 to ImplIntfCount-1 do
  694. begin
  695. ImplIntfI:=TImplementedInterface(_class.ImplementedInterfaces[i]);
  696. ImplIntfI.VtblImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[impls^[i]]);
  697. end;
  698. freemem(compats);
  699. freemem(aequals);
  700. freemem(impls);
  701. end;
  702. procedure TVMTBuilder.intf_allocate_vtbls;
  703. var
  704. i : longint;
  705. ImplIntf : TImplementedInterface;
  706. begin
  707. { Allocation vtbl space }
  708. for i:=0 to _class.ImplementedInterfaces.count-1 do
  709. begin
  710. ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]);
  711. { if it implements itself and if it's not implemented by delegation }
  712. if (ImplIntf.VtblImplIntf=ImplIntf) and (ImplIntf.IType=etStandard) then
  713. begin
  714. { allocate a pointer in the object memory }
  715. with tObjectSymtable(_class.symtable) do
  716. begin
  717. datasize:=align(datasize,voidpointertype.alignment);
  718. ImplIntf.Ioffset:=datasize;
  719. datasize:=datasize+voidpointertype.size;
  720. end;
  721. end;
  722. end;
  723. { Update ioffset of current interface with the ioffset from
  724. the interface that is reused to implements this interface }
  725. for i:=0 to _class.ImplementedInterfaces.count-1 do
  726. begin
  727. ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]);
  728. if ImplIntf.VtblImplIntf<>ImplIntf then
  729. ImplIntf.IOffset:=ImplIntf.VtblImplIntf.IOffset;
  730. end;
  731. end;
  732. procedure TVMTBuilder.generate_vmt;
  733. var
  734. i : longint;
  735. def : tdef;
  736. old_current_structdef : tabstractrecorddef;
  737. overridesclasshelper : boolean;
  738. begin
  739. old_current_structdef:=current_structdef;
  740. current_structdef:=_class;
  741. _class.resetvmtentries;
  742. { inherit (copy) VMT from parent object }
  743. if assigned(_class.childof) then
  744. begin
  745. if not assigned(_class.childof.vmtentries) then
  746. internalerror(200810281);
  747. _class.copyvmtentries(_class.childof);
  748. end;
  749. { process all procdefs, we must process the defs to
  750. keep the same order as that is written in the source
  751. to be compatible with the indexes in the interface vtable (PFV) }
  752. for i:=0 to _class.symtable.DefList.Count-1 do
  753. begin
  754. def:=tdef(_class.symtable.DefList[i]);
  755. if def.typ=procdef then
  756. begin
  757. { VMT entry }
  758. if is_new_vmt_entry(tprocdef(def),overridesclasshelper) then
  759. add_new_vmt_entry(tprocdef(def),overridesclasshelper);
  760. end;
  761. end;
  762. build_interface_mappings;
  763. if assigned(_class.ImplementedInterfaces) and
  764. not(is_objc_class_or_protocol(_class)) and
  765. not(is_java_class_or_interface(_class)) then
  766. begin
  767. { Optimize interface tables to reuse wrappers }
  768. intf_optimize_vtbls;
  769. { Allocate interface tables }
  770. intf_allocate_vtbls;
  771. end;
  772. current_structdef:=old_current_structdef;
  773. end;
  774. procedure TVMTBuilder.build_interface_mappings;
  775. var
  776. ImplIntf : TImplementedInterface;
  777. i: longint;
  778. begin
  779. { Find Procdefs implementing the interfaces (both Objective-C protocols
  780. and Java interfaces can have multiple parent interfaces, but in that
  781. case obviously no implementations are required) }
  782. if assigned(_class.ImplementedInterfaces) and
  783. not(_class.objecttype in [odt_objcprotocol,odt_interfacejava]) and
  784. // abstract java classes do not have to implement all interface
  785. // methods. todo: check that non-abstract descendents do!
  786. not((_class.objecttype=odt_javaclass) and (oo_is_abstract in _class.objectoptions)) then
  787. begin
  788. { Collect implementor functions into the tImplementedInterface.procdefs }
  789. case _class.objecttype of
  790. odt_class:
  791. begin
  792. for i:=0 to _class.ImplementedInterfaces.count-1 do
  793. begin
  794. ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]);
  795. intf_get_procdefs_recursive(ImplIntf,ImplIntf.IntfDef)
  796. end;
  797. end;
  798. odt_objcclass,
  799. odt_javaclass:
  800. begin
  801. { Object Pascal interfaces are afterwards optimized via the
  802. intf_optimize_vtbls() method, but we can't do this for
  803. protocols/Java interfaces -> check for duplicates here
  804. already. }
  805. handledprotocols:=tfpobjectlist.create(false);
  806. for i:=0 to _class.ImplementedInterfaces.count-1 do
  807. begin
  808. ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]);
  809. prot_get_procdefs_recursive(ImplIntf,ImplIntf.IntfDef);
  810. end;
  811. handledprotocols.free;
  812. end
  813. else
  814. internalerror(2009091801);
  815. end
  816. end;
  817. end;
  818. end.