hcgdata.pas 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. Routines for the code generation of data structures
  5. like VMT, Messages, VTables, Interfaces descs
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit hcgdata;
  20. {$i defines.inc}
  21. interface
  22. uses
  23. symtable,aasm;
  24. { generates the message tables for a class }
  25. function genstrmsgtab(_class : pobjectdef) : pasmlabel;
  26. function genintmsgtab(_class : pobjectdef) : pasmlabel;
  27. { generates the method name table }
  28. function genpublishedmethodstable(_class : pobjectdef) : pasmlabel;
  29. { generates a VMT for _class }
  30. procedure genvmt(list : paasmoutput;_class : pobjectdef);
  31. {$ifdef WITHDMT}
  32. { generates a DMT for _class }
  33. function gendmt(_class : pobjectdef) : pasmlabel;
  34. {$endif WITHDMT}
  35. { define INTERFACE_SUPPORT}
  36. {$ifdef INTERFACE_SUPPORT}
  37. function genintftable(_class: pobjectdef): pasmlabel;
  38. {$endif INTERFACE_SUPPORT}
  39. implementation
  40. uses
  41. {$ifdef delphi}
  42. sysutils,
  43. {$else}
  44. strings,
  45. {$endif}
  46. cutils,cobjects,
  47. globtype,globals,verbose,
  48. symconst,types,
  49. hcodegen, systems,fmodule
  50. {$ifdef INTERFACE_SUPPORT}
  51. {$ifdef i386}
  52. ,cg386ic
  53. {$endif}
  54. {$endif INTERFACE_SUPPORT}
  55. ;
  56. {*****************************************************************************
  57. Message
  58. *****************************************************************************}
  59. type
  60. pprocdeftree = ^tprocdeftree;
  61. tprocdeftree = record
  62. p : pprocdef;
  63. nl : pasmlabel;
  64. l,r : pprocdeftree;
  65. end;
  66. var
  67. root : pprocdeftree;
  68. count : longint;
  69. procedure insertstr(p : pprocdeftree;var at : pprocdeftree);
  70. var
  71. i : longint;
  72. begin
  73. if at=nil then
  74. begin
  75. at:=p;
  76. inc(count);
  77. end
  78. else
  79. begin
  80. i:=strcomp(p^.p^.messageinf.str,at^.p^.messageinf.str);
  81. if i<0 then
  82. insertstr(p,at^.l)
  83. else if i>0 then
  84. insertstr(p,at^.r)
  85. else
  86. Message1(parser_e_duplicate_message_label,strpas(p^.p^.messageinf.str));
  87. end;
  88. end;
  89. procedure disposeprocdeftree(p : pprocdeftree);
  90. begin
  91. if assigned(p^.l) then
  92. disposeprocdeftree(p^.l);
  93. if assigned(p^.r) then
  94. disposeprocdeftree(p^.r);
  95. dispose(p);
  96. end;
  97. procedure insertmsgstr(p : pnamedindexobject);
  98. var
  99. hp : pprocdef;
  100. pt : pprocdeftree;
  101. begin
  102. if psym(p)^.typ=procsym then
  103. begin
  104. hp:=pprocsym(p)^.definition;
  105. while assigned(hp) do
  106. begin
  107. if (po_msgstr in hp^.procoptions) then
  108. begin
  109. new(pt);
  110. pt^.p:=hp;
  111. pt^.l:=nil;
  112. pt^.r:=nil;
  113. insertstr(pt,root);
  114. end;
  115. hp:=hp^.nextoverloaded;
  116. end;
  117. end;
  118. end;
  119. procedure insertint(p : pprocdeftree;var at : pprocdeftree);
  120. begin
  121. if at=nil then
  122. begin
  123. at:=p;
  124. inc(count);
  125. end
  126. else
  127. begin
  128. if p^.p^.messageinf.i<at^.p^.messageinf.i then
  129. insertint(p,at^.l)
  130. else if p^.p^.messageinf.i>at^.p^.messageinf.i then
  131. insertint(p,at^.r)
  132. else
  133. Message1(parser_e_duplicate_message_label,tostr(p^.p^.messageinf.i));
  134. end;
  135. end;
  136. procedure insertmsgint(p : pnamedindexobject);
  137. var
  138. hp : pprocdef;
  139. pt : pprocdeftree;
  140. begin
  141. if psym(p)^.typ=procsym then
  142. begin
  143. hp:=pprocsym(p)^.definition;
  144. while assigned(hp) do
  145. begin
  146. if (po_msgint in hp^.procoptions) then
  147. begin
  148. new(pt);
  149. pt^.p:=hp;
  150. pt^.l:=nil;
  151. pt^.r:=nil;
  152. insertint(pt,root);
  153. end;
  154. hp:=hp^.nextoverloaded;
  155. end;
  156. end;
  157. end;
  158. procedure writenames(p : pprocdeftree);
  159. begin
  160. getdatalabel(p^.nl);
  161. if assigned(p^.l) then
  162. writenames(p^.l);
  163. datasegment^.concat(new(pai_label,init(p^.nl)));
  164. datasegment^.concat(new(pai_const,init_8bit(strlen(p^.p^.messageinf.str))));
  165. datasegment^.concat(new(pai_string,init_pchar(p^.p^.messageinf.str)));
  166. if assigned(p^.r) then
  167. writenames(p^.r);
  168. end;
  169. procedure writestrentry(p : pprocdeftree);
  170. begin
  171. if assigned(p^.l) then
  172. writestrentry(p^.l);
  173. { write name label }
  174. datasegment^.concat(new(pai_const_symbol,init(p^.nl)));
  175. datasegment^.concat(new(pai_const_symbol,initname(p^.p^.mangledname)));
  176. if assigned(p^.r) then
  177. writestrentry(p^.r);
  178. end;
  179. function genstrmsgtab(_class : pobjectdef) : pasmlabel;
  180. var
  181. r : pasmlabel;
  182. begin
  183. root:=nil;
  184. count:=0;
  185. { insert all message handlers into a tree, sorted by name }
  186. _class^.symtable^.foreach({$ifdef FPCPROCVAR}@{$endif}insertmsgstr);
  187. { write all names }
  188. if assigned(root) then
  189. writenames(root);
  190. { now start writing of the message string table }
  191. getdatalabel(r);
  192. datasegment^.concat(new(pai_label,init(r)));
  193. genstrmsgtab:=r;
  194. datasegment^.concat(new(pai_const,init_32bit(count)));
  195. if assigned(root) then
  196. begin
  197. writestrentry(root);
  198. disposeprocdeftree(root);
  199. end;
  200. end;
  201. procedure writeintentry(p : pprocdeftree);
  202. begin
  203. if assigned(p^.l) then
  204. writeintentry(p^.l);
  205. { write name label }
  206. datasegment^.concat(new(pai_const,init_32bit(p^.p^.messageinf.i)));
  207. datasegment^.concat(new(pai_const_symbol,initname(p^.p^.mangledname)));
  208. if assigned(p^.r) then
  209. writeintentry(p^.r);
  210. end;
  211. function genintmsgtab(_class : pobjectdef) : pasmlabel;
  212. var
  213. r : pasmlabel;
  214. begin
  215. root:=nil;
  216. count:=0;
  217. { insert all message handlers into a tree, sorted by name }
  218. _class^.symtable^.foreach({$ifdef FPCPROCVAR}@{$endif}insertmsgint);
  219. { now start writing of the message string table }
  220. getdatalabel(r);
  221. datasegment^.concat(new(pai_label,init(r)));
  222. genintmsgtab:=r;
  223. datasegment^.concat(new(pai_const,init_32bit(count)));
  224. if assigned(root) then
  225. begin
  226. writeintentry(root);
  227. disposeprocdeftree(root);
  228. end;
  229. end;
  230. {$ifdef WITHDMT}
  231. procedure insertdmtentry(p : pnamedindexobject);
  232. var
  233. hp : pprocdef;
  234. pt : pprocdeftree;
  235. begin
  236. if psym(p)^.typ=procsym then
  237. begin
  238. hp:=pprocsym(p)^.definition;
  239. while assigned(hp) do
  240. begin
  241. if (po_msgint in hp^.procoptions) then
  242. begin
  243. new(pt);
  244. pt^.p:=hp;
  245. pt^.l:=nil;
  246. pt^.r:=nil;
  247. insertint(pt,root);
  248. end;
  249. hp:=hp^.nextoverloaded;
  250. end;
  251. end;
  252. end;
  253. procedure writedmtindexentry(p : pprocdeftree);
  254. begin
  255. if assigned(p^.l) then
  256. writedmtindexentry(p^.l);
  257. datasegment^.concat(new(pai_const,init_32bit(p^.p^.messageinf.i)));
  258. if assigned(p^.r) then
  259. writedmtindexentry(p^.r);
  260. end;
  261. procedure writedmtaddressentry(p : pprocdeftree);
  262. begin
  263. if assigned(p^.l) then
  264. writedmtaddressentry(p^.l);
  265. datasegment^.concat(new(pai_const_symbol,initname(p^.p^.mangledname)));
  266. if assigned(p^.r) then
  267. writedmtaddressentry(p^.r);
  268. end;
  269. function gendmt(_class : pobjectdef) : pasmlabel;
  270. var
  271. r : pasmlabel;
  272. begin
  273. root:=nil;
  274. count:=0;
  275. gendmt:=nil;
  276. { insert all message handlers into a tree, sorted by number }
  277. _class^.symtable^.foreach({$ifdef FPCPROCVAR}@{$endif}insertdmtentry);
  278. if count>0 then
  279. begin
  280. getdatalabel(r);
  281. gendmt:=r;
  282. datasegment^.concat(new(pai_label,init(r)));
  283. { entries for caching }
  284. datasegment^.concat(new(pai_const,init_32bit(0)));
  285. datasegment^.concat(new(pai_const,init_32bit(0)));
  286. datasegment^.concat(new(pai_const,init_32bit(count)));
  287. if assigned(root) then
  288. begin
  289. writedmtindexentry(root);
  290. writedmtaddressentry(root);
  291. disposeprocdeftree(root);
  292. end;
  293. end;
  294. end;
  295. {$endif WITHDMT}
  296. procedure do_count(p : pnamedindexobject);
  297. begin
  298. if (psym(p)^.typ=procsym) and (sp_published in psym(p)^.symoptions) then
  299. inc(count);
  300. end;
  301. procedure genpubmethodtableentry(p : pnamedindexobject);
  302. var
  303. hp : pprocdef;
  304. l : pasmlabel;
  305. begin
  306. if (psym(p)^.typ=procsym) and (sp_published in psym(p)^.symoptions) then
  307. begin
  308. hp:=pprocsym(p)^.definition;
  309. if assigned(hp^.nextoverloaded) then
  310. internalerror(1209992);
  311. getdatalabel(l);
  312. consts^.concat(new(pai_label,init(l)));
  313. consts^.concat(new(pai_const,init_8bit(length(p^.name))));
  314. consts^.concat(new(pai_string,init(p^.name)));
  315. datasegment^.concat(new(pai_const_symbol,init(l)));
  316. datasegment^.concat(new(pai_const_symbol,initname(hp^.mangledname)));
  317. end;
  318. end;
  319. function genpublishedmethodstable(_class : pobjectdef) : pasmlabel;
  320. var
  321. l : pasmlabel;
  322. begin
  323. count:=0;
  324. _class^.symtable^.foreach({$ifdef FPCPROCVAR}@{$endif}do_count);
  325. if count>0 then
  326. begin
  327. getdatalabel(l);
  328. datasegment^.concat(new(pai_label,init(l)));
  329. datasegment^.concat(new(pai_const,init_32bit(count)));
  330. _class^.symtable^.foreach({$ifdef FPCPROCVAR}@{$endif}genpubmethodtableentry);
  331. genpublishedmethodstable:=l;
  332. end
  333. else
  334. genpublishedmethodstable:=nil;
  335. end;
  336. {*****************************************************************************
  337. VMT
  338. *****************************************************************************}
  339. type
  340. pprocdefcoll = ^tprocdefcoll;
  341. tprocdefcoll = record
  342. next : pprocdefcoll;
  343. data : pprocdef;
  344. end;
  345. psymcoll = ^tsymcoll;
  346. tsymcoll = record
  347. next : psymcoll;
  348. name : pstring;
  349. data : pprocdefcoll;
  350. end;
  351. var
  352. wurzel : psymcoll;
  353. nextvirtnumber : longint;
  354. _c : pobjectdef;
  355. has_constructor,has_virtual_method : boolean;
  356. procedure eachsym(sym : pnamedindexobject);
  357. var
  358. procdefcoll : pprocdefcoll;
  359. hp : pprocdef;
  360. symcoll : psymcoll;
  361. _name : string;
  362. stored : boolean;
  363. { creates a new entry in the procsym list }
  364. procedure newentry;
  365. begin
  366. { if not, generate a new symbol item }
  367. new(symcoll);
  368. symcoll^.name:=stringdup(sym^.name);
  369. symcoll^.next:=wurzel;
  370. symcoll^.data:=nil;
  371. wurzel:=symcoll;
  372. hp:=pprocsym(sym)^.definition;
  373. { inserts all definitions }
  374. while assigned(hp) do
  375. begin
  376. new(procdefcoll);
  377. procdefcoll^.data:=hp;
  378. procdefcoll^.next:=symcoll^.data;
  379. symcoll^.data:=procdefcoll;
  380. { if it's a virtual method }
  381. if (po_virtualmethod in hp^.procoptions) then
  382. begin
  383. { then it gets a number ... }
  384. hp^.extnumber:=nextvirtnumber;
  385. { and we inc the number }
  386. inc(nextvirtnumber);
  387. has_virtual_method:=true;
  388. end;
  389. if (hp^.proctypeoption=potype_constructor) then
  390. has_constructor:=true;
  391. { check, if a method should be overridden }
  392. if (po_overridingmethod in hp^.procoptions) then
  393. MessagePos1(hp^.fileinfo,parser_e_nothing_to_be_overridden,_c^.objname^+'.'+_name+hp^.demangled_paras);
  394. { next overloaded method }
  395. hp:=hp^.nextoverloaded;
  396. end;
  397. end;
  398. procedure newdefentry;
  399. begin
  400. new(procdefcoll);
  401. procdefcoll^.data:=hp;
  402. procdefcoll^.next:=symcoll^.data;
  403. symcoll^.data:=procdefcoll;
  404. { if it's a virtual method }
  405. if (po_virtualmethod in hp^.procoptions) then
  406. begin
  407. { then it gets a number ... }
  408. hp^.extnumber:=nextvirtnumber;
  409. { and we inc the number }
  410. inc(nextvirtnumber);
  411. has_virtual_method:=true;
  412. end;
  413. if (hp^.proctypeoption=potype_constructor) then
  414. has_constructor:=true;
  415. { check, if a method should be overridden }
  416. if (po_overridingmethod in hp^.procoptions) then
  417. MessagePos1(hp^.fileinfo,parser_e_nothing_to_be_overridden,_c^.objname^+'.'+_name+hp^.demangled_paras);
  418. end;
  419. label
  420. handlenextdef;
  421. begin
  422. { put only sub routines into the VMT }
  423. if psym(sym)^.typ=procsym then
  424. begin
  425. _name:=sym^.name;
  426. symcoll:=wurzel;
  427. while assigned(symcoll) do
  428. begin
  429. { does the symbol already exist in the list ? }
  430. if _name=symcoll^.name^ then
  431. begin
  432. { walk through all defs of the symbol }
  433. hp:=pprocsym(sym)^.definition;
  434. while assigned(hp) do
  435. begin
  436. { compare with all stored definitions }
  437. procdefcoll:=symcoll^.data;
  438. stored:=false;
  439. while assigned(procdefcoll) do
  440. begin
  441. { compare parameters }
  442. if equal_paras(procdefcoll^.data^.para,hp^.para,cp_all) and
  443. (
  444. (po_virtualmethod in procdefcoll^.data^.procoptions) or
  445. (po_virtualmethod in hp^.procoptions)
  446. ) then
  447. begin { same parameters }
  448. { wenn sie gleich sind }
  449. { und eine davon virtual deklariert ist }
  450. { Fehler falls nur eine VIRTUAL }
  451. if (po_virtualmethod in procdefcoll^.data^.procoptions)<>
  452. (po_virtualmethod in hp^.procoptions) then
  453. begin
  454. { in classes, we hide the old method }
  455. if _c^.is_class then
  456. begin
  457. { warn only if it is the first time,
  458. we hide the method }
  459. if _c=hp^._class then
  460. Message1(parser_w_should_use_override,_c^.objname^+'.'+_name);
  461. end
  462. else
  463. if _c=hp^._class then
  464. begin
  465. if (po_virtualmethod in procdefcoll^.data^.procoptions) then
  466. Message1(parser_w_overloaded_are_not_both_virtual,_c^.objname^+'.'+_name)
  467. else
  468. Message1(parser_w_overloaded_are_not_both_non_virtual,
  469. _c^.objname^+'.'+_name);
  470. end;
  471. { was newentry; exit; (FK) }
  472. newdefentry;
  473. goto handlenextdef;
  474. end
  475. else
  476. { the flags have to match }
  477. { except abstract and override }
  478. { only if both are virtual !! }
  479. if (procdefcoll^.data^.proccalloptions<>hp^.proccalloptions) or
  480. (procdefcoll^.data^.proctypeoption<>hp^.proctypeoption) or
  481. ((procdefcoll^.data^.procoptions-
  482. [po_abstractmethod,po_overridingmethod,po_assembler])<>
  483. (hp^.procoptions-[po_abstractmethod,po_overridingmethod,po_assembler])) then
  484. Message1(parser_e_header_dont_match_forward,_c^.objname^+'.'+_name);
  485. { check, if the overridden directive is set }
  486. { (povirtualmethod is set! }
  487. { class ? }
  488. if _c^.is_class and
  489. not(po_overridingmethod in hp^.procoptions) then
  490. begin
  491. { warn only if it is the first time,
  492. we hide the method }
  493. if _c=hp^._class then
  494. Message1(parser_w_should_use_override,_c^.objname^+'.'+_name);
  495. { was newentry; (FK) }
  496. newdefentry;
  497. exit;
  498. end;
  499. { error, if the return types aren't equal }
  500. if not(is_equal(procdefcoll^.data^.rettype.def,hp^.rettype.def)) and
  501. not((procdefcoll^.data^.rettype.def^.deftype=objectdef) and
  502. (hp^.rettype.def^.deftype=objectdef) and
  503. (pobjectdef(procdefcoll^.data^.rettype.def)^.is_class) and
  504. (pobjectdef(hp^.rettype.def)^.is_class) and
  505. (pobjectdef(hp^.rettype.def)^.is_related(
  506. pobjectdef(procdefcoll^.data^.rettype.def)))) then
  507. Message1(parser_e_overloaded_methodes_not_same_ret,_c^.objname^+'.'+_name);
  508. { now set the number }
  509. hp^.extnumber:=procdefcoll^.data^.extnumber;
  510. { and exchange }
  511. procdefcoll^.data:=hp;
  512. stored:=true;
  513. goto handlenextdef;
  514. end; { same parameters }
  515. procdefcoll:=procdefcoll^.next;
  516. end;
  517. { if it isn't saved in the list }
  518. { we create a new entry }
  519. if not(stored) then
  520. begin
  521. new(procdefcoll);
  522. procdefcoll^.data:=hp;
  523. procdefcoll^.next:=symcoll^.data;
  524. symcoll^.data:=procdefcoll;
  525. { if the method is virtual ... }
  526. if (po_virtualmethod in hp^.procoptions) then
  527. begin
  528. { ... it will get a number }
  529. hp^.extnumber:=nextvirtnumber;
  530. inc(nextvirtnumber);
  531. end;
  532. { check, if a method should be overridden }
  533. if (po_overridingmethod in hp^.procoptions) then
  534. MessagePos1(hp^.fileinfo,parser_e_nothing_to_be_overridden,
  535. _c^.objname^+'.'+_name+hp^.demangled_paras);
  536. end;
  537. handlenextdef:
  538. hp:=hp^.nextoverloaded;
  539. end;
  540. exit;
  541. end;
  542. symcoll:=symcoll^.next;
  543. end;
  544. newentry;
  545. end;
  546. end;
  547. procedure disposevmttree;
  548. var
  549. symcoll : psymcoll;
  550. procdefcoll : pprocdefcoll;
  551. begin
  552. { disposes the above generated tree }
  553. symcoll:=wurzel;
  554. while assigned(symcoll) do
  555. begin
  556. wurzel:=symcoll^.next;
  557. stringdispose(symcoll^.name);
  558. procdefcoll:=symcoll^.data;
  559. while assigned(procdefcoll) do
  560. begin
  561. symcoll^.data:=procdefcoll^.next;
  562. dispose(procdefcoll);
  563. procdefcoll:=symcoll^.data;
  564. end;
  565. dispose(symcoll);
  566. symcoll:=wurzel;
  567. end;
  568. end;
  569. procedure genvmt(list : paasmoutput;_class : pobjectdef);
  570. procedure do_genvmt(p : pobjectdef);
  571. begin
  572. { start with the base class }
  573. if assigned(p^.childof) then
  574. do_genvmt(p^.childof);
  575. { walk through all public syms }
  576. { I had to change that to solve bug0260 (PM)}
  577. { _c:=p; }
  578. _c:=_class;
  579. { Florian, please check if you agree (PM) }
  580. { no it wasn't correct, but I fixed it at }
  581. { another place: your fix hides only a bug }
  582. { _c is only used to give correct warnings }
  583. p^.symtable^.foreach({$ifdef FPCPROCVAR}@{$endif}eachsym);
  584. end;
  585. var
  586. symcoll : psymcoll;
  587. procdefcoll : pprocdefcoll;
  588. i : longint;
  589. begin
  590. wurzel:=nil;
  591. nextvirtnumber:=0;
  592. has_constructor:=false;
  593. has_virtual_method:=false;
  594. { generates a tree of all used methods }
  595. do_genvmt(_class);
  596. if has_virtual_method and not(has_constructor) then
  597. Message1(parser_w_virtual_without_constructor,_class^.objname^);
  598. { generates the VMT }
  599. { walk trough all numbers for virtual methods and search }
  600. { the method }
  601. for i:=0 to nextvirtnumber-1 do
  602. begin
  603. symcoll:=wurzel;
  604. { walk trough all symbols }
  605. while assigned(symcoll) do
  606. begin
  607. { walk trough all methods }
  608. procdefcoll:=symcoll^.data;
  609. while assigned(procdefcoll) do
  610. begin
  611. { writes the addresses to the VMT }
  612. { but only this which are declared as virtual }
  613. if procdefcoll^.data^.extnumber=i then
  614. begin
  615. if (po_virtualmethod in procdefcoll^.data^.procoptions) then
  616. begin
  617. { if a method is abstract, then is also the }
  618. { class abstract and it's not allow to }
  619. { generates an instance }
  620. if (po_abstractmethod in procdefcoll^.data^.procoptions) then
  621. begin
  622. include(_class^.objectoptions,oo_has_abstract);
  623. list^.concat(new(pai_const_symbol,initname('FPC_ABSTRACTERROR')));
  624. end
  625. else
  626. begin
  627. list^.concat(new(pai_const_symbol,
  628. initname(procdefcoll^.data^.mangledname)));
  629. end;
  630. end;
  631. end;
  632. procdefcoll:=procdefcoll^.next;
  633. end;
  634. symcoll:=symcoll^.next;
  635. end;
  636. end;
  637. disposevmttree;
  638. end;
  639. {$ifdef SUPPORT_INTERFACES}
  640. function gintfgetvtbllabelname(_class: pobjectdef; intfindex: integer): string;
  641. begin
  642. gintfgetvtbllabelname:='_$$_'+_class^.objname^+'_$$_'+
  643. _class^.implementedinterfaces^.interfaces(intfindex)^.objname^+'_$$_VTBL';
  644. end;
  645. procedure gintfcreatevtbl(_class: pobjectdef; intfindex: integer; rawdata: paasmoutput);
  646. var
  647. implintf: pimplementedinterfaces;
  648. curintf: pobjectdef;
  649. count: integer;
  650. tmps: string;
  651. i: longint;
  652. begin
  653. implintf:=_class^.implementedinterfaces;
  654. curintf:=implintf^.interfaces(intfindex);
  655. rawdata^.concat(new(pai_symbol,initname(gintfgetvtbllabelname(_class,intfindex),0)));
  656. count:=implintf^.implproccount(intfindex);
  657. for i:=1 to count do
  658. begin
  659. tmps:=implintf^.implprocs(intfindex,i)^.mangledname+'_$$_'+curintf^.objname^;
  660. { create wrapper code }
  661. cgintfwrapper(implintf^.implprocs(intfindex,i),tmps,implintf^.ioffsets(intfindex)^);
  662. { create reference }
  663. rawdata^.concat(new(pai_const_symbol,initname(tmps)));
  664. end;
  665. end;
  666. procedure gintfgenentry(_class: pobjectdef; intfindex, contintfindex: integer; rawdata: paasmoutput);
  667. var
  668. implintf: pimplementedinterfaces;
  669. curintf: pobjectdef;
  670. tmplabel: pasmlabel;
  671. i: longint;
  672. begin
  673. implintf:=_class^.implementedinterfaces;
  674. curintf:=implintf^.interfaces(intfindex);
  675. { GUID }
  676. if curintf^.objecttype in [odt_interfacecom] then
  677. begin
  678. { label for GUID }
  679. getdatalabel(tmplabel);
  680. rawdata^.concat(new(pai_label,init(tmplabel)));
  681. rawdata^.concat(new(pai_const,init_32bit(curintf^.iidguid.D1)));
  682. rawdata^.concat(new(pai_const,init_16bit(curintf^.iidguid.D2)));
  683. rawdata^.concat(new(pai_const,init_16bit(curintf^.iidguid.D3)));
  684. for i:=Low(curintf^.iidguid.D4) to High(curintf^.iidguid.D4) do
  685. rawdata^.concat(new(pai_const,init_8bit(curintf^.iidguid.D4[i])));
  686. datasegment^.concat(new(pai_const_symbol,init(tmplabel)));
  687. end
  688. else
  689. begin
  690. { nil for Corba interfaces }
  691. datasegment^.concat(new(pai_const,init_32bit(0))); { nil }
  692. end;
  693. { VTable }
  694. datasegment^.concat(new(pai_const_symbol,initname(gintfgetvtbllabelname(_class,contintfindex))));
  695. { IOffset field }
  696. datasegment^.concat(new(pai_const,init_32bit(implintf^.ioffsets(contintfindex)^)));
  697. { IIDStr }
  698. getdatalabel(tmplabel);
  699. rawdata^.concat(new(pai_label,init(tmplabel)));
  700. rawdata^.concat(new(pai_const,init_8bit(length(curintf^.iidstr^))));
  701. if curintf^.objecttype=odt_interfacecom then
  702. rawdata^.concat(new(pai_string,init(upper(curintf^.iidstr^))))
  703. else
  704. rawdata^.concat(new(pai_string,init(curintf^.iidstr^)));
  705. datasegment^.concat(new(pai_const_symbol,init(tmplabel)));
  706. end;
  707. procedure gintfoptimizevtbls(_class: pobjectdef; var implvtbl: tlongintarr);
  708. type
  709. tcompintfentry = record
  710. weight: longint;
  711. compintf: longint;
  712. end;
  713. { Max 1000 interface in the class header interfaces it's enough imho }
  714. tcompintfs = {$ifndef tp} packed {$endif} array[1..1000] of tcompintfentry;
  715. pcompintfs = ^tcompintfs;
  716. tequals = {$ifndef tp} packed {$endif} array[1..1000] of longint;
  717. pequals = ^tequals;
  718. var
  719. max: longint;
  720. equals: pequals;
  721. compats: pcompintfs;
  722. i: longint;
  723. j: longint;
  724. w: longint;
  725. cij: boolean;
  726. cji: boolean;
  727. begin
  728. max:=_class^.implementedinterfaces^.count;
  729. if max>High(tequals) then
  730. Internalerror(200006135);
  731. getmem(compats,sizeof(tcompintfentry)*max);
  732. getmem(equals,sizeof(longint)*max);
  733. fillchar(compats^,sizeof(tcompintfentry)*max,0);
  734. fillchar(equals^,sizeof(longint)*max,0);
  735. { ismergepossible is a containing relation
  736. meaning of ismergepossible(a,b,w) =
  737. if implementorfunction map of a is contained implementorfunction map of b
  738. imp(a,b) and imp(b,c) => imp(a,c) ; imp(a,b) and imp(b,a) => a == b
  739. }
  740. { the order is very important for correct allocation }
  741. for i:=1 to max do
  742. begin
  743. for j:=i+1 to max do
  744. begin
  745. cij:=_class^.implementedinterfaces^.isimplmergepossible(i,j,w);
  746. cji:=_class^.implementedinterfaces^.isimplmergepossible(j,i,w);
  747. if cij and cji then { i equal j }
  748. begin
  749. { get minimum index of equal }
  750. if equals^[j]=0 then
  751. equals^[j]:=i;
  752. end
  753. else if cij then
  754. begin
  755. { get minimum index of maximum weight }
  756. if compats^[i].weight<w then
  757. begin
  758. compats^[i].weight:=w;
  759. compats^[i].compintf:=j;
  760. end;
  761. end
  762. else if cji then
  763. begin
  764. { get minimum index of maximum weight }
  765. if (compats^[j].weight<w) then
  766. begin
  767. compats^[j].weight:=w;
  768. compats^[j].compintf:=i;
  769. end;
  770. end;
  771. end;
  772. end;
  773. for i:=1 to max do
  774. begin
  775. if compats^[i].compintf<>0 then
  776. implvtbl[i]:=compats^[i].compintf
  777. else if equals^[i]<>0 then
  778. implvtbl[i]:=equals^[i]
  779. else
  780. implvtbl[i]:=i;
  781. end;
  782. freemem(compats,sizeof(tcompintfentry)*max);
  783. freemem(equals,sizeof(longint)*max);
  784. end;
  785. procedure gintfwritedata(_class: pobjectdef);
  786. var
  787. rawdata: taasmoutput;
  788. impintfindexes: plongintarr;
  789. max: longint;
  790. i: longint;
  791. begin
  792. max:=_class^.implementedinterfaces^.count;
  793. getmem(impintfindexes,(max+1)*sizeof(longint));
  794. gintfoptimizevtbls(_class,impintfindexes^);
  795. rawdata.init;
  796. datasegment^.concat(new(pai_const,init_16bit(max)));
  797. { Two pass, one for allocation and vtbl creation }
  798. for i:=1 to max do
  799. begin
  800. if impintfindexes^[i]=i then { if implement itself }
  801. begin
  802. { allocate a pointer in the object memory }
  803. with _class^.symtable^ do
  804. begin
  805. if (alignment>=target_os.size_of_pointer) then
  806. datasize:=align(datasize,alignment)
  807. else
  808. datasize:=align(datasize,target_os.size_of_pointer);
  809. _class^.implementedinterfaces^.ioffsets(i)^:=datasize;
  810. datasize:=datasize+target_os.size_of_pointer;
  811. end;
  812. { write vtbl }
  813. gintfcreatevtbl(_class,i,@rawdata);
  814. end;
  815. end;
  816. { second pass: for fill interfacetable and remained ioffsets }
  817. for i:=1 to max do
  818. begin
  819. if i<>impintfindexes^[i] then { why execute x:=x ? }
  820. with _class^.implementedinterfaces^ do ioffsets(i)^:=ioffsets(impintfindexes^[i])^;
  821. gintfgenentry(_class,i,impintfindexes^[i],@rawdata);
  822. end;
  823. datasegment^.insertlist(@rawdata);
  824. rawdata.done;
  825. freemem(impintfindexes,(max+1)*sizeof(longint));
  826. end;
  827. function gintfgetcprocdef(_class: pobjectdef; proc: pprocdef;const name: string): pprocdef;
  828. var
  829. sym: pprocsym;
  830. implprocdef: pprocdef;
  831. begin
  832. implprocdef:=nil;
  833. sym:=pprocsym(search_class_member(_class,name));
  834. if assigned(sym) and (sym^.typ=procsym) and not (sp_private in sym^.symoptions) then
  835. begin
  836. implprocdef:=sym^.definition;
  837. while assigned(implprocdef) and not equal_paras(proc^.para,implprocdef^.para,false) and
  838. (proc^.proccalloptions<>implprocdef^.proccalloptions) do
  839. implprocdef:=implprocdef^.nextoverloaded;
  840. end;
  841. gintfgetcprocdef:=implprocdef;
  842. end;
  843. procedure gintfdoonintf(intf, _class: pobjectdef; intfindex: longint);
  844. var
  845. i: longint;
  846. proc: pprocdef;
  847. procname: string; { for error }
  848. mappedname: string;
  849. nextexist: pointer;
  850. implprocdef: pprocdef;
  851. begin
  852. for i:=1 to intf^.symtable^.defindex^.count do
  853. begin
  854. proc:=pprocdef(intf^.symtable^.defindex^.search(i));
  855. if proc^.deftype=procdef then
  856. begin
  857. procname:='';
  858. implprocdef:=nil;
  859. nextexist:=nil;
  860. repeat
  861. mappedname:=_class^.implementedinterfaces^.getmappings(intfindex,proc^.procsym^.name,nextexist);
  862. if procname='' then
  863. procname:=mappedname; { for error messages }
  864. if mappedname<>'' then
  865. implprocdef:=gintfgetcprocdef(_class,proc,mappedname);
  866. until assigned(implprocdef) or not assigned(nextexist);
  867. if not assigned(implprocdef) then
  868. implprocdef:=gintfgetcprocdef(_class,proc,proc^.procsym^.name);
  869. if procname='' then
  870. procname:=proc^.procsym^.name;
  871. if assigned(implprocdef) then
  872. _class^.implementedinterfaces^.addimplproc(intfindex,implprocdef)
  873. else
  874. Message1(sym_e_id_not_found,procname);
  875. end;
  876. end;
  877. end;
  878. procedure gintfwalkdowninterface(intf, _class: pobjectdef; intfindex: longint);
  879. begin
  880. if assigned(intf^.childof) then
  881. gintfwalkdowninterface(intf^.childof,_class,intfindex);
  882. gintfdoonintf(intf,_class,intfindex);
  883. end;
  884. function genintftable(_class: pobjectdef): pasmlabel;
  885. var
  886. intfindex: longint;
  887. curintf: pobjectdef;
  888. intftable: pasmlabel;
  889. begin
  890. { 1. step collect implementor functions into the implementedinterfaces^.implprocs }
  891. for intfindex:=1 to _class^.implementedinterfaces^.count do
  892. begin
  893. curintf:=_class^.implementedinterfaces^.interfaces(intfindex);
  894. gintfwalkdowninterface(curintf,_class,intfindex);
  895. end;
  896. { 2. step calc required fieldcount and their offsets in the object memory map
  897. and write data }
  898. getdatalabel(intftable);
  899. datasegment^.concat(new(pai_label,init(intftable)));
  900. gintfwritedata(_class);
  901. _class^.implementedinterfaces^.clearimplprocs; { release temporary information }
  902. genintftable:=intftable;
  903. end;
  904. {$endif SUPPORT_INTERFACES}
  905. end.
  906. {
  907. $Log$
  908. Revision 1.7 2000-10-14 10:14:47 peter
  909. * moehrendorf oct 2000 rewrite
  910. Revision 1.6 2000/09/24 21:19:50 peter
  911. * delphi compile fixes
  912. Revision 1.5 2000/09/24 15:06:17 peter
  913. * use defines.inc
  914. Revision 1.4 2000/08/27 16:11:51 peter
  915. * moved some util functions from globals,cobjects to cutils
  916. * splitted files into finput,fmodule
  917. Revision 1.3 2000/07/13 12:08:26 michael
  918. + patched to 1.1.0 with former 1.09patch from peter
  919. Revision 1.2 2000/07/13 11:32:41 michael
  920. + removed logs
  921. }