nobj.pas 64 KB

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