hcgdata.pas 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069
  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. symdef,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,symtype,symsym,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,hp^.fullprocname);
  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,
  467. hp^.fullprocname)
  468. else
  469. Message1(parser_w_overloaded_are_not_both_non_virtual,
  470. hp^.fullprocname);
  471. end;
  472. { was newentry; exit; (FK) }
  473. newdefentry;
  474. goto handlenextdef;
  475. end
  476. else
  477. { the flags have to match }
  478. { except abstract and override }
  479. { only if both are virtual !! }
  480. if (procdefcoll^.data^.proccalloptions<>hp^.proccalloptions) or
  481. (procdefcoll^.data^.proctypeoption<>hp^.proctypeoption) or
  482. ((procdefcoll^.data^.procoptions-
  483. [po_abstractmethod,po_overridingmethod,po_assembler])<>
  484. (hp^.procoptions-[po_abstractmethod,po_overridingmethod,po_assembler])) then
  485. Message1(parser_e_header_dont_match_forward,hp^.fullprocname);
  486. { check, if the overridden directive is set }
  487. { (povirtualmethod is set! }
  488. { class ? }
  489. if _c^.is_class and
  490. not(po_overridingmethod in hp^.procoptions) then
  491. begin
  492. { warn only if it is the first time,
  493. we hide the method }
  494. if _c=hp^._class then
  495. Message1(parser_w_should_use_override,hp^.fullprocname);
  496. { was newentry; (FK) }
  497. newdefentry;
  498. exit;
  499. end;
  500. { error, if the return types aren't equal }
  501. if not(is_equal(procdefcoll^.data^.rettype.def,hp^.rettype.def)) and
  502. not((procdefcoll^.data^.rettype.def^.deftype=objectdef) and
  503. (hp^.rettype.def^.deftype=objectdef) and
  504. (pobjectdef(procdefcoll^.data^.rettype.def)^.is_class) and
  505. (pobjectdef(hp^.rettype.def)^.is_class) and
  506. (pobjectdef(hp^.rettype.def)^.is_related(
  507. pobjectdef(procdefcoll^.data^.rettype.def)))) then
  508. Message1(parser_e_overloaded_methodes_not_same_ret,hp^.fullprocname);
  509. { now set the number }
  510. hp^.extnumber:=procdefcoll^.data^.extnumber;
  511. { and exchange }
  512. procdefcoll^.data:=hp;
  513. stored:=true;
  514. goto handlenextdef;
  515. end; { same parameters }
  516. procdefcoll:=procdefcoll^.next;
  517. end;
  518. { if it isn't saved in the list }
  519. { we create a new entry }
  520. if not(stored) then
  521. begin
  522. new(procdefcoll);
  523. procdefcoll^.data:=hp;
  524. procdefcoll^.next:=symcoll^.data;
  525. symcoll^.data:=procdefcoll;
  526. { if the method is virtual ... }
  527. if (po_virtualmethod in hp^.procoptions) then
  528. begin
  529. { ... it will get a number }
  530. hp^.extnumber:=nextvirtnumber;
  531. inc(nextvirtnumber);
  532. end;
  533. { check, if a method should be overridden }
  534. if (po_overridingmethod in hp^.procoptions) then
  535. MessagePos1(hp^.fileinfo,parser_e_nothing_to_be_overridden,
  536. hp^.fullprocname);
  537. end;
  538. handlenextdef:
  539. hp:=hp^.nextoverloaded;
  540. end;
  541. exit;
  542. end;
  543. symcoll:=symcoll^.next;
  544. end;
  545. newentry;
  546. end;
  547. end;
  548. procedure disposevmttree;
  549. var
  550. symcoll : psymcoll;
  551. procdefcoll : pprocdefcoll;
  552. begin
  553. { disposes the above generated tree }
  554. symcoll:=wurzel;
  555. while assigned(symcoll) do
  556. begin
  557. wurzel:=symcoll^.next;
  558. stringdispose(symcoll^.name);
  559. procdefcoll:=symcoll^.data;
  560. while assigned(procdefcoll) do
  561. begin
  562. symcoll^.data:=procdefcoll^.next;
  563. dispose(procdefcoll);
  564. procdefcoll:=symcoll^.data;
  565. end;
  566. dispose(symcoll);
  567. symcoll:=wurzel;
  568. end;
  569. end;
  570. procedure genvmt(list : paasmoutput;_class : pobjectdef);
  571. procedure do_genvmt(p : pobjectdef);
  572. begin
  573. { start with the base class }
  574. if assigned(p^.childof) then
  575. do_genvmt(p^.childof);
  576. { walk through all public syms }
  577. { I had to change that to solve bug0260 (PM)}
  578. { _c:=p; }
  579. _c:=_class;
  580. { Florian, please check if you agree (PM) }
  581. { no it wasn't correct, but I fixed it at }
  582. { another place: your fix hides only a bug }
  583. { _c is only used to give correct warnings }
  584. p^.symtable^.foreach({$ifdef FPCPROCVAR}@{$endif}eachsym);
  585. end;
  586. var
  587. symcoll : psymcoll;
  588. procdefcoll : pprocdefcoll;
  589. i : longint;
  590. begin
  591. wurzel:=nil;
  592. nextvirtnumber:=0;
  593. has_constructor:=false;
  594. has_virtual_method:=false;
  595. { generates a tree of all used methods }
  596. do_genvmt(_class);
  597. if has_virtual_method and not(has_constructor) then
  598. Message1(parser_w_virtual_without_constructor,_class^.objname^);
  599. { generates the VMT }
  600. { walk trough all numbers for virtual methods and search }
  601. { the method }
  602. for i:=0 to nextvirtnumber-1 do
  603. begin
  604. symcoll:=wurzel;
  605. { walk trough all symbols }
  606. while assigned(symcoll) do
  607. begin
  608. { walk trough all methods }
  609. procdefcoll:=symcoll^.data;
  610. while assigned(procdefcoll) do
  611. begin
  612. { writes the addresses to the VMT }
  613. { but only this which are declared as virtual }
  614. if procdefcoll^.data^.extnumber=i then
  615. begin
  616. if (po_virtualmethod in procdefcoll^.data^.procoptions) then
  617. begin
  618. { if a method is abstract, then is also the }
  619. { class abstract and it's not allow to }
  620. { generates an instance }
  621. if (po_abstractmethod in procdefcoll^.data^.procoptions) then
  622. begin
  623. include(_class^.objectoptions,oo_has_abstract);
  624. list^.concat(new(pai_const_symbol,initname('FPC_ABSTRACTERROR')));
  625. end
  626. else
  627. begin
  628. list^.concat(new(pai_const_symbol,
  629. initname(procdefcoll^.data^.mangledname)));
  630. end;
  631. end;
  632. end;
  633. procdefcoll:=procdefcoll^.next;
  634. end;
  635. symcoll:=symcoll^.next;
  636. end;
  637. end;
  638. disposevmttree;
  639. end;
  640. {$ifdef SUPPORT_INTERFACES}
  641. function gintfgetvtbllabelname(_class: pobjectdef; intfindex: integer): string;
  642. begin
  643. gintfgetvtbllabelname:='_$$_'+_class^.objname^+'_$$_'+
  644. _class^.implementedinterfaces^.interfaces(intfindex)^.objname^+'_$$_VTBL';
  645. end;
  646. procedure gintfcreatevtbl(_class: pobjectdef; intfindex: integer; rawdata: paasmoutput);
  647. var
  648. implintf: pimplementedinterfaces;
  649. curintf: pobjectdef;
  650. count: integer;
  651. tmps: string;
  652. i: longint;
  653. begin
  654. implintf:=_class^.implementedinterfaces;
  655. curintf:=implintf^.interfaces(intfindex);
  656. rawdata^.concat(new(pai_symbol,initname(gintfgetvtbllabelname(_class,intfindex),0)));
  657. count:=implintf^.implproccount(intfindex);
  658. for i:=1 to count do
  659. begin
  660. tmps:=implintf^.implprocs(intfindex,i)^.mangledname+'_$$_'+curintf^.objname^;
  661. { create wrapper code }
  662. cgintfwrapper(implintf^.implprocs(intfindex,i),tmps,implintf^.ioffsets(intfindex)^);
  663. { create reference }
  664. rawdata^.concat(new(pai_const_symbol,initname(tmps)));
  665. end;
  666. end;
  667. procedure gintfgenentry(_class: pobjectdef; intfindex, contintfindex: integer; rawdata: paasmoutput);
  668. var
  669. implintf: pimplementedinterfaces;
  670. curintf: pobjectdef;
  671. tmplabel: pasmlabel;
  672. i: longint;
  673. begin
  674. implintf:=_class^.implementedinterfaces;
  675. curintf:=implintf^.interfaces(intfindex);
  676. { GUID }
  677. if curintf^.objecttype in [odt_interfacecom] then
  678. begin
  679. { label for GUID }
  680. getdatalabel(tmplabel);
  681. rawdata^.concat(new(pai_label,init(tmplabel)));
  682. rawdata^.concat(new(pai_const,init_32bit(curintf^.iidguid.D1)));
  683. rawdata^.concat(new(pai_const,init_16bit(curintf^.iidguid.D2)));
  684. rawdata^.concat(new(pai_const,init_16bit(curintf^.iidguid.D3)));
  685. for i:=Low(curintf^.iidguid.D4) to High(curintf^.iidguid.D4) do
  686. rawdata^.concat(new(pai_const,init_8bit(curintf^.iidguid.D4[i])));
  687. datasegment^.concat(new(pai_const_symbol,init(tmplabel)));
  688. end
  689. else
  690. begin
  691. { nil for Corba interfaces }
  692. datasegment^.concat(new(pai_const,init_32bit(0))); { nil }
  693. end;
  694. { VTable }
  695. datasegment^.concat(new(pai_const_symbol,initname(gintfgetvtbllabelname(_class,contintfindex))));
  696. { IOffset field }
  697. datasegment^.concat(new(pai_const,init_32bit(implintf^.ioffsets(contintfindex)^)));
  698. { IIDStr }
  699. getdatalabel(tmplabel);
  700. rawdata^.concat(new(pai_label,init(tmplabel)));
  701. rawdata^.concat(new(pai_const,init_8bit(length(curintf^.iidstr^))));
  702. if curintf^.objecttype=odt_interfacecom then
  703. rawdata^.concat(new(pai_string,init(upper(curintf^.iidstr^))))
  704. else
  705. rawdata^.concat(new(pai_string,init(curintf^.iidstr^)));
  706. datasegment^.concat(new(pai_const_symbol,init(tmplabel)));
  707. end;
  708. procedure gintfoptimizevtbls(_class: pobjectdef; var implvtbl: tlongintarr);
  709. type
  710. tcompintfentry = record
  711. weight: longint;
  712. compintf: longint;
  713. end;
  714. { Max 1000 interface in the class header interfaces it's enough imho }
  715. tcompintfs = {$ifndef tp} packed {$endif} array[1..1000] of tcompintfentry;
  716. pcompintfs = ^tcompintfs;
  717. tequals = {$ifndef tp} packed {$endif} array[1..1000] of longint;
  718. pequals = ^tequals;
  719. var
  720. max: longint;
  721. equals: pequals;
  722. compats: pcompintfs;
  723. i: longint;
  724. j: longint;
  725. w: longint;
  726. cij: boolean;
  727. cji: boolean;
  728. begin
  729. max:=_class^.implementedinterfaces^.count;
  730. if max>High(tequals) then
  731. Internalerror(200006135);
  732. getmem(compats,sizeof(tcompintfentry)*max);
  733. getmem(equals,sizeof(longint)*max);
  734. fillchar(compats^,sizeof(tcompintfentry)*max,0);
  735. fillchar(equals^,sizeof(longint)*max,0);
  736. { ismergepossible is a containing relation
  737. meaning of ismergepossible(a,b,w) =
  738. if implementorfunction map of a is contained implementorfunction map of b
  739. imp(a,b) and imp(b,c) => imp(a,c) ; imp(a,b) and imp(b,a) => a == b
  740. }
  741. { the order is very important for correct allocation }
  742. for i:=1 to max do
  743. begin
  744. for j:=i+1 to max do
  745. begin
  746. cij:=_class^.implementedinterfaces^.isimplmergepossible(i,j,w);
  747. cji:=_class^.implementedinterfaces^.isimplmergepossible(j,i,w);
  748. if cij and cji then { i equal j }
  749. begin
  750. { get minimum index of equal }
  751. if equals^[j]=0 then
  752. equals^[j]:=i;
  753. end
  754. else if cij then
  755. begin
  756. { get minimum index of maximum weight }
  757. if compats^[i].weight<w then
  758. begin
  759. compats^[i].weight:=w;
  760. compats^[i].compintf:=j;
  761. end;
  762. end
  763. else if cji then
  764. begin
  765. { get minimum index of maximum weight }
  766. if (compats^[j].weight<w) then
  767. begin
  768. compats^[j].weight:=w;
  769. compats^[j].compintf:=i;
  770. end;
  771. end;
  772. end;
  773. end;
  774. for i:=1 to max do
  775. begin
  776. if compats^[i].compintf<>0 then
  777. implvtbl[i]:=compats^[i].compintf
  778. else if equals^[i]<>0 then
  779. implvtbl[i]:=equals^[i]
  780. else
  781. implvtbl[i]:=i;
  782. end;
  783. freemem(compats,sizeof(tcompintfentry)*max);
  784. freemem(equals,sizeof(longint)*max);
  785. end;
  786. procedure gintfwritedata(_class: pobjectdef);
  787. var
  788. rawdata: taasmoutput;
  789. impintfindexes: plongintarr;
  790. max: longint;
  791. i: longint;
  792. begin
  793. max:=_class^.implementedinterfaces^.count;
  794. getmem(impintfindexes,(max+1)*sizeof(longint));
  795. gintfoptimizevtbls(_class,impintfindexes^);
  796. rawdata.init;
  797. datasegment^.concat(new(pai_const,init_16bit(max)));
  798. { Two pass, one for allocation and vtbl creation }
  799. for i:=1 to max do
  800. begin
  801. if impintfindexes^[i]=i then { if implement itself }
  802. begin
  803. { allocate a pointer in the object memory }
  804. with _class^.symtable^ do
  805. begin
  806. if (alignment>=target_os.size_of_pointer) then
  807. datasize:=align(datasize,alignment)
  808. else
  809. datasize:=align(datasize,target_os.size_of_pointer);
  810. _class^.implementedinterfaces^.ioffsets(i)^:=datasize;
  811. datasize:=datasize+target_os.size_of_pointer;
  812. end;
  813. { write vtbl }
  814. gintfcreatevtbl(_class,i,@rawdata);
  815. end;
  816. end;
  817. { second pass: for fill interfacetable and remained ioffsets }
  818. for i:=1 to max do
  819. begin
  820. if i<>impintfindexes^[i] then { why execute x:=x ? }
  821. with _class^.implementedinterfaces^ do ioffsets(i)^:=ioffsets(impintfindexes^[i])^;
  822. gintfgenentry(_class,i,impintfindexes^[i],@rawdata);
  823. end;
  824. datasegment^.insertlist(@rawdata);
  825. rawdata.done;
  826. freemem(impintfindexes,(max+1)*sizeof(longint));
  827. end;
  828. function gintfgetcprocdef(_class: pobjectdef; proc: pprocdef;const name: string): pprocdef;
  829. var
  830. sym: pprocsym;
  831. implprocdef: pprocdef;
  832. begin
  833. implprocdef:=nil;
  834. sym:=pprocsym(search_class_member(_class,name));
  835. if assigned(sym) and (sym^.typ=procsym) and not (sp_private in sym^.symoptions) then
  836. begin
  837. implprocdef:=sym^.definition;
  838. while assigned(implprocdef) and not equal_paras(proc^.para,implprocdef^.para,false) and
  839. (proc^.proccalloptions<>implprocdef^.proccalloptions) do
  840. implprocdef:=implprocdef^.nextoverloaded;
  841. end;
  842. gintfgetcprocdef:=implprocdef;
  843. end;
  844. procedure gintfdoonintf(intf, _class: pobjectdef; intfindex: longint);
  845. var
  846. i: longint;
  847. proc: pprocdef;
  848. procname: string; { for error }
  849. mappedname: string;
  850. nextexist: pointer;
  851. implprocdef: pprocdef;
  852. begin
  853. for i:=1 to intf^.symtable^.defindex^.count do
  854. begin
  855. proc:=pprocdef(intf^.symtable^.defindex^.search(i));
  856. if proc^.deftype=procdef then
  857. begin
  858. procname:='';
  859. implprocdef:=nil;
  860. nextexist:=nil;
  861. repeat
  862. mappedname:=_class^.implementedinterfaces^.getmappings(intfindex,proc^.procsym^.name,nextexist);
  863. if procname='' then
  864. procname:=mappedname; { for error messages }
  865. if mappedname<>'' then
  866. implprocdef:=gintfgetcprocdef(_class,proc,mappedname);
  867. until assigned(implprocdef) or not assigned(nextexist);
  868. if not assigned(implprocdef) then
  869. implprocdef:=gintfgetcprocdef(_class,proc,proc^.procsym^.name);
  870. if procname='' then
  871. procname:=proc^.procsym^.name;
  872. if assigned(implprocdef) then
  873. _class^.implementedinterfaces^.addimplproc(intfindex,implprocdef)
  874. else
  875. Message1(sym_e_id_not_found,procname);
  876. end;
  877. end;
  878. end;
  879. procedure gintfwalkdowninterface(intf, _class: pobjectdef; intfindex: longint);
  880. begin
  881. if assigned(intf^.childof) then
  882. gintfwalkdowninterface(intf^.childof,_class,intfindex);
  883. gintfdoonintf(intf,_class,intfindex);
  884. end;
  885. function genintftable(_class: pobjectdef): pasmlabel;
  886. var
  887. intfindex: longint;
  888. curintf: pobjectdef;
  889. intftable: pasmlabel;
  890. begin
  891. { 1. step collect implementor functions into the implementedinterfaces^.implprocs }
  892. for intfindex:=1 to _class^.implementedinterfaces^.count do
  893. begin
  894. curintf:=_class^.implementedinterfaces^.interfaces(intfindex);
  895. gintfwalkdowninterface(curintf,_class,intfindex);
  896. end;
  897. { 2. step calc required fieldcount and their offsets in the object memory map
  898. and write data }
  899. getdatalabel(intftable);
  900. datasegment^.concat(new(pai_label,init(intftable)));
  901. gintfwritedata(_class);
  902. _class^.implementedinterfaces^.clearimplprocs; { release temporary information }
  903. genintftable:=intftable;
  904. end;
  905. {$endif SUPPORT_INTERFACES}
  906. end.
  907. {
  908. $Log$
  909. Revision 1.9 2000-11-01 23:04:37 peter
  910. * tprocdef.fullprocname added for better casesensitve writing of
  911. procedures
  912. Revision 1.8 2000/10/31 22:02:47 peter
  913. * symtable splitted, no real code changes
  914. Revision 1.7 2000/10/14 10:14:47 peter
  915. * moehrendorf oct 2000 rewrite
  916. Revision 1.6 2000/09/24 21:19:50 peter
  917. * delphi compile fixes
  918. Revision 1.5 2000/09/24 15:06:17 peter
  919. * use defines.inc
  920. Revision 1.4 2000/08/27 16:11:51 peter
  921. * moved some util functions from globals,cobjects to cutils
  922. * splitted files into finput,fmodule
  923. Revision 1.3 2000/07/13 12:08:26 michael
  924. + patched to 1.1.0 with former 1.09patch from peter
  925. Revision 1.2 2000/07/13 11:32:41 michael
  926. + removed logs
  927. }