hcgdata.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Daniel Mantione,
  4. and other members of the Free Pascal development team
  5. Routines for the code generation of data structures
  6. like VMT,Messages
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. ****************************************************************************
  19. }
  20. unit hcgdata;
  21. interface
  22. uses
  23. symtable,aasm,defs;
  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(Aclass: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. implementation
  36. uses
  37. strings,cobjects,globtype,globals,verbose,
  38. types,hcodegen,symbols,objects,xobjects;
  39. {*****************************************************************************
  40. Message
  41. *****************************************************************************}
  42. type
  43. pprocdeftree = ^tprocdeftree;
  44. tprocdeftree = record
  45. p : pprocdef;
  46. nl : pasmlabel;
  47. l,r : pprocdeftree;
  48. end;
  49. var
  50. root : pprocdeftree;
  51. count : longint;
  52. procedure insertstr(p : pprocdeftree;var at : pprocdeftree);
  53. var
  54. i : longint;
  55. begin
  56. if at=nil then
  57. begin
  58. at:=p;
  59. inc(count);
  60. end
  61. else
  62. begin
  63. i:=strcomp(p^.p^.messageinf.str,at^.p^.messageinf.str);
  64. if i<0 then
  65. insertstr(p,at^.l)
  66. else if i>0 then
  67. insertstr(p,at^.r)
  68. else
  69. Message1(parser_e_duplicate_message_label,strpas(p^.p^.messageinf.str));
  70. end;
  71. end;
  72. procedure disposeprocdeftree(p : pprocdeftree);
  73. begin
  74. if assigned(p^.l) then
  75. disposeprocdeftree(p^.l);
  76. if assigned(p^.r) then
  77. disposeprocdeftree(p^.r);
  78. dispose(p);
  79. end;
  80. procedure insertmsgstr(p:pnamedindexobject);{$ifndef FPC}far;{$endif FPC}
  81. procedure inserter(p:pointer);{$IFDEF TP}far;{$ENDIF}
  82. var pt:Pprocdeftree;
  83. begin
  84. if pomsgstr in Pprocdef(p)^.options then
  85. begin
  86. new(pt);
  87. pt^.p:=p;
  88. pt^.l:=nil;
  89. pt^.r:=nil;
  90. insertstr(pt,root);
  91. end;
  92. end;
  93. begin
  94. if typeof(p^)=typeof(Tprocsym) then
  95. Pprocsym(p)^.foreach(@inserter);
  96. end;
  97. procedure insertint(p : pprocdeftree;var at : pprocdeftree);
  98. begin
  99. if at=nil then
  100. begin
  101. at:=p;
  102. inc(count);
  103. end
  104. else
  105. begin
  106. if p^.p^.messageinf.i<at^.p^.messageinf.i then
  107. insertint(p,at^.l)
  108. else if p^.p^.messageinf.i>at^.p^.messageinf.i then
  109. insertint(p,at^.r)
  110. else
  111. Message1(parser_e_duplicate_message_label,tostr(p^.p^.messageinf.i));
  112. end;
  113. end;
  114. procedure insertmsgint(p:pnamedindexobject);{$ifndef FPC}far;{$endif FPC}
  115. procedure inserter(p:pointer);{$IFDEF TP}far;{$ENDIF}
  116. var pt:Pprocdeftree;
  117. begin
  118. if pomsgint in Pprocdef(p)^.options then
  119. begin
  120. new(pt);
  121. pt^.p:=p;
  122. pt^.l:=nil;
  123. pt^.r:=nil;
  124. insertint(pt,root);
  125. end;
  126. end;
  127. begin
  128. if typeof(p^)=typeof(Tprocsym) then
  129. Pprocsym(p)^.foreach(@inserter);
  130. end;
  131. procedure writenames(p : pprocdeftree);
  132. begin
  133. getdatalabel(p^.nl);
  134. if assigned(p^.l) then
  135. writenames(p^.l);
  136. datasegment^.concat(new(pai_label,init(p^.nl)));
  137. datasegment^.concat(new(pai_const,init_8bit(strlen(p^.p^.messageinf.str))));
  138. datasegment^.concat(new(pai_string,init_pchar(p^.p^.messageinf.str)));
  139. if assigned(p^.r) then
  140. writenames(p^.r);
  141. end;
  142. procedure writestrentry(p : pprocdeftree);
  143. begin
  144. if assigned(p^.l) then
  145. writestrentry(p^.l);
  146. { write name label }
  147. datasegment^.concat(new(pai_const_symbol,init(p^.nl)));
  148. datasegment^.concat(new(pai_const_symbol,initname(p^.p^.mangledname)));
  149. if assigned(p^.r) then
  150. writestrentry(p^.r);
  151. end;
  152. function genstrmsgtab(_class : pobjectdef) : pasmlabel;
  153. var
  154. r : pasmlabel;
  155. begin
  156. root:=nil;
  157. count:=0;
  158. if _class^.privatesyms<>nil then
  159. _class^.privatesyms^.foreach({$ifndef TP}@{$endif}insertmsgstr);
  160. if _class^.privatesyms<>nil then
  161. _class^.protectedsyms^.foreach({$ifndef TP}@{$endif}insertmsgstr);
  162. if _class^.privatesyms<>nil then
  163. _class^.publicsyms^.foreach({$ifndef TP}@{$endif}insertmsgstr);
  164. { write all names }
  165. if assigned(root) then
  166. writenames(root);
  167. { now start writing of the message string table }
  168. getdatalabel(r);
  169. datasegment^.concat(new(pai_label,init(r)));
  170. genstrmsgtab:=r;
  171. datasegment^.concat(new(pai_const,init_32bit(count)));
  172. if assigned(root) then
  173. begin
  174. writestrentry(root);
  175. disposeprocdeftree(root);
  176. end;
  177. end;
  178. procedure writeintentry(p : pprocdeftree);
  179. begin
  180. if assigned(p^.l) then
  181. writeintentry(p^.l);
  182. { write name label }
  183. datasegment^.concat(new(pai_const,init_32bit(p^.p^.messageinf.i)));
  184. datasegment^.concat(new(pai_const_symbol,initname(p^.p^.mangledname)));
  185. if assigned(p^.r) then
  186. writeintentry(p^.r);
  187. end;
  188. function genintmsgtab(_class : pobjectdef) : pasmlabel;
  189. var
  190. r : pasmlabel;
  191. begin
  192. root:=nil;
  193. count:=0;
  194. if _class^.privatesyms<>nil then
  195. _class^.privatesyms^.foreach({$ifndef TP}@{$endif}insertmsgint);
  196. if _class^.privatesyms<>nil then
  197. _class^.protectedsyms^.foreach({$ifndef TP}@{$endif}insertmsgint);
  198. if _class^.privatesyms<>nil then
  199. _class^.publicsyms^.foreach({$ifndef TP}@{$endif}insertmsgint);
  200. { now start writing of the message string table }
  201. getdatalabel(r);
  202. datasegment^.concat(new(pai_label,init(r)));
  203. genintmsgtab:=r;
  204. datasegment^.concat(new(pai_const,init_32bit(count)));
  205. if assigned(root) then
  206. begin
  207. writeintentry(root);
  208. disposeprocdeftree(root);
  209. end;
  210. end;
  211. {$ifdef WITHDMT}
  212. procedure insertdmtentry(p : pnamedindexobject);{$ifndef FPC}far;{$endif FPC}
  213. var
  214. hp : pprocdef;
  215. pt : pprocdeftree;
  216. begin
  217. if psym(p)^.typ=procsym then
  218. begin
  219. hp:=pprocsym(p)^.definition;
  220. while assigned(hp) do
  221. begin
  222. if (po_msgint in hp^.procoptions) then
  223. begin
  224. new(pt);
  225. pt^.p:=hp;
  226. pt^.l:=nil;
  227. pt^.r:=nil;
  228. insertint(pt,root);
  229. end;
  230. hp:=hp^.nextoverloaded;
  231. end;
  232. end;
  233. end;
  234. procedure writedmtindexentry(p : pprocdeftree);
  235. begin
  236. if assigned(p^.l) then
  237. writedmtindexentry(p^.l);
  238. datasegment^.concat(new(pai_const,init_32bit(p^.p^.messageinf.i)));
  239. if assigned(p^.r) then
  240. writedmtindexentry(p^.r);
  241. end;
  242. procedure writedmtaddressentry(p : pprocdeftree);
  243. begin
  244. if assigned(p^.l) then
  245. writedmtaddressentry(p^.l);
  246. datasegment^.concat(new(pai_const_symbol,initname(p^.p^.mangledname)));
  247. if assigned(p^.r) then
  248. writedmtaddressentry(p^.r);
  249. end;
  250. function gendmt(_class : pobjectdef) : pasmlabel;
  251. var
  252. r : pasmlabel;
  253. begin
  254. root:=nil;
  255. count:=0;
  256. gendmt:=nil;
  257. { insert all message handlers into a tree, sorted by number }
  258. _class^.symtable^.foreach({$ifndef TP}@{$endif}insertdmtentry);
  259. if count>0 then
  260. begin
  261. getdatalabel(r);
  262. gendmt:=r;
  263. datasegment^.concat(new(pai_label,init(r)));
  264. { entries for caching }
  265. datasegment^.concat(new(pai_const,init_32bit(0)));
  266. datasegment^.concat(new(pai_const,init_32bit(0)));
  267. datasegment^.concat(new(pai_const,init_32bit(count)));
  268. if assigned(root) then
  269. begin
  270. writedmtindexentry(root);
  271. writedmtaddressentry(root);
  272. disposeprocdeftree(root);
  273. end;
  274. end;
  275. end;
  276. {$endif WITHDMT}
  277. procedure genpubmethodtableentry(p : pnamedindexobject);{$ifndef FPC}far;{$endif}
  278. procedure do_concat(q:pointer);{$ifndef FPC}far;{$endif}
  279. var l:Pasmlabel;
  280. begin
  281. if (sp_published in Pprocdef(q)^.objprop) then
  282. begin
  283. getlabel(l);
  284. consts^.concat(new(pai_label,init(l)));
  285. consts^.concat(new(pai_const,init_8bit(length(p^.name))));
  286. consts^.concat(new(pai_string,init(p^.name)));
  287. datasegment^.concat(new(pai_const_symbol,init(l)));
  288. datasegment^.concat(new(pai_const_symbol,initname(Pprocdef(q)^.mangledname)));
  289. end;
  290. end;
  291. begin
  292. if p^.is_object(typeof(Tprocsym)) then
  293. Pprocsym(p)^.foreach(@do_concat);
  294. end;
  295. procedure sym_do_count(p:Pnamedindexobject);{$ifndef FPC}far;{$endif}
  296. procedure def_do_count(p:pointer);{$ifndef FPC}far;{$endif}
  297. begin
  298. if (sp_published in Pprocdef(p)^.objprop) then
  299. inc(count);
  300. end;
  301. begin
  302. if Pobject(p)^.is_object(typeof(Tprocsym)) then
  303. Pprocsym(p)^.foreach(@def_do_count);
  304. end;
  305. function genpublishedmethodstable(Aclass:Pobjectdef):Pasmlabel;
  306. var l:Pasmlabel;
  307. begin
  308. count:=0;
  309. if Aclass^.privatesyms<>nil then
  310. Aclass^.privatesyms^.foreach({$ifndef TP}@{$endif}sym_do_count);
  311. if Aclass^.protectedsyms<>nil then
  312. Aclass^.publicsyms^.foreach({$ifndef TP}@{$endif}sym_do_count);
  313. if Aclass^.publicsyms<>nil then
  314. Aclass^.publicsyms^.foreach({$ifndef TP}@{$endif}sym_do_count);
  315. if count>0 then
  316. begin
  317. getlabel(l);
  318. datasegment^.concat(new(pai_label,init(l)));
  319. datasegment^.concat(new(pai_const,init_32bit(count)));
  320. if Aclass^.privatesyms<>nil then
  321. Aclass^.privatesyms^.foreach({$ifndef TP}@{$endif}genpubmethodtableentry);
  322. if Aclass^.protectedsyms<>nil then
  323. Aclass^.protectedsyms^.foreach({$ifndef TP}@{$endif}genpubmethodtableentry);
  324. if Aclass^.publicsyms<>nil then
  325. Aclass^.publicsyms^.foreach({$ifndef TP}@{$endif}genpubmethodtableentry);
  326. genpublishedmethodstable:=l;
  327. end
  328. else
  329. genpublishedmethodstable:=nil;
  330. end;
  331. {*****************************************************************************
  332. VMT
  333. *****************************************************************************}
  334. var wurzel:Pcollection;
  335. nextvirtnumber : longint;
  336. _c : pobjectdef;
  337. has_constructor,has_virtual_method : boolean;
  338. procedure eachsym(sym:Pnamedindexobject);{$ifndef FPC}far;{$endif FPC}
  339. var symcoll:Pcollection;
  340. _name:string;
  341. stored:boolean;
  342. {Creates a new entry in the procsym list.}
  343. procedure newentry;
  344. procedure numbervirtual(p:pointer);{$IFDEF TP}far;{$ENDIF TP}
  345. begin
  346. { if it's a virtual method }
  347. if (povirtualmethod in Pprocdef(p)^.options) then
  348. begin
  349. {Then it gets a number ...}
  350. Pprocdef(p)^.extnumber:=nextvirtnumber;
  351. {And we inc the number }
  352. inc(nextvirtnumber);
  353. has_virtual_method:=true;
  354. end;
  355. if (Pprocdef(p)^.proctype=potype_constructor) then
  356. has_constructor:=true;
  357. { check, if a method should be overridden }
  358. if (pooverridingmethod in Pprocdef(p)^.options) then
  359. messagepos1(Pprocdef(p)^.fileinfo,parser_e_nothing_to_be_overridden,
  360. _c^.objname^+'.'+_name+Pprocdef(p)^.demangled_paras);
  361. end;
  362. begin
  363. symcoll^.insert(sym);
  364. Pprocsym(sym)^.foreach(@numbervirtual);
  365. end;
  366. function match(p:pointer):boolean;{$IFDEF TP}far;{$ENDIF}
  367. begin
  368. {Does the symbol already exist in the list ?}
  369. match:=_name=Psym(p)^.name;
  370. end;
  371. procedure eachdef(p:pointer);{$IFDEF TP}far;{$ENDIF}
  372. function check_override(q:pointer):boolean;{$IFDEF TP}far;{$ENDIF}
  373. begin
  374. check_override:=false;
  375. {Check if the parameters are equal and if one of the methods
  376. is virtual.}
  377. if equal_paras(Pprocdef(p)^.parameters,
  378. Pprocdef(q)^.parameters,false) and
  379. ((povirtualmethod in Pprocdef(p)^.options) or
  380. (povirtualmethod in Pprocdef(q)^.options)) then
  381. begin
  382. {Wenn sie gleich sind
  383. und eine davon virtual deklariert ist
  384. Fehler falls nur eine VIRTUAL }
  385. if (povirtualmethod in Pprocdef(p)^.options)<>
  386. (povirtualmethod in Pprocdef(q)^.options) then
  387. begin
  388. { in classes, we hide the old method }
  389. if oo_is_class in _c^.options then
  390. begin
  391. {Warn only if it is the first time,
  392. we hide the method.}
  393. if _c=Pprocsym(Pprocdef(p)^.sym)^._class then
  394. message1(parser_w_should_use_override,_c^.objname^+'.'+_name);
  395. newentry;
  396. check_override:=true;
  397. exit;
  398. end
  399. else
  400. if _c=Pprocsym(Pprocdef(p)^.sym)^._class then
  401. begin
  402. if (povirtualmethod in Pprocdef(q)^.options) then
  403. message1(parser_w_overloaded_are_not_both_virtual,_c^.objname^+'.'+_name)
  404. else
  405. message1(parser_w_overloaded_are_not_both_non_virtual,
  406. _c^.objname^+'.'+_name);
  407. newentry;
  408. check_override:=true;
  409. exit;
  410. end;
  411. end
  412. else
  413. {The flags have to match except abstract
  414. and override, but only if both are virtual!!}
  415. if (Pprocdef(q)^.calloptions<>Pprocdef(p)^.calloptions) or
  416. (Pprocdef(q)^.proctype<>Pprocdef(p)^.proctype) or
  417. ((Pprocdef(q)^.options-[poabstractmethod,pooverridingmethod,poassembler])<>
  418. (Pprocdef(p)^.options-[poabstractmethod,pooverridingmethod,poassembler])) then
  419. message1(parser_e_header_dont_match_forward,_c^.objname^+'.'+_name);
  420. {Check, if the override directive is set
  421. (povirtualmethod is set!}
  422. {Class ?}
  423. if (oo_is_class in _c^.options) and
  424. not(pooverridingmethod in Pprocdef(p)^.options) then
  425. begin
  426. {Warn only if it is the first time,
  427. we hide the method.}
  428. if _c=Pprocsym(Pprocdef(p)^.sym)^._class then
  429. message1(parser_w_should_use_override,_c^.objname^+'.'+_name);
  430. newentry;
  431. check_override:=true;
  432. exit;
  433. end;
  434. { error, if the return types aren't equal }
  435. if not(is_equal(Pprocdef(q)^.retdef,Pprocdef(p)^.retdef)) and
  436. not(Pprocdef(q)^.retdef^.is_object(typeof(Tobjectdef)) and
  437. Pprocdef(p)^.retdef^.is_object(typeof(Tobjectdef)) and
  438. (oo_is_class in Pobjectdef(Pprocdef(q)^.retdef)^.options) and
  439. (oo_is_class in Pobjectdef(Pprocdef(p)^.retdef)^.options) and
  440. (pobjectdef(Pprocdef(p)^.retdef)^.is_related(
  441. pobjectdef(Pprocdef(q)^.retdef)))) then
  442. message1(parser_e_overloaded_methodes_not_same_ret,_c^.objname^+'.'+_name);
  443. {now set the number }
  444. Pprocdef(p)^.extnumber:=Pprocdef(q)^.extnumber;
  445. end; { same parameters }
  446. end;
  447. begin
  448. if Pprocsym(sym)^.firstthat(@check_override)=nil then
  449. newentry;
  450. end;
  451. begin
  452. {Put only subroutines into the VMT.}
  453. if sym^.is_object(typeof(Tprocsym)) then
  454. begin
  455. symcoll:=wurzel;
  456. Pprocsym(symcoll^.firstthat(@match))^.foreach(@eachdef);
  457. newentry;
  458. end;
  459. end;
  460. procedure genvmt(list:Paasmoutput;_class:Pobjectdef);
  461. var symcoll:Pcollection;
  462. i:longint;
  463. procedure do_genvmt(p:Pobjectdef);
  464. begin
  465. {Start with the base class.}
  466. if assigned(p^.childof) then
  467. do_genvmt(p^.childof);
  468. { walk through all public syms }
  469. { I had to change that to solve bug0260 (PM)}
  470. _c:=p;
  471. { Florian, please check if you agree (PM) }
  472. p^.privatesyms^.foreach({$ifndef TP}@{$endif}eachsym);
  473. p^.protectedsyms^.foreach({$ifndef TP}@{$endif}eachsym);
  474. p^.publicsyms^.foreach({$ifndef TP}@{$endif}eachsym);
  475. end;
  476. procedure symwritevmt(p:pointer);{$IFDEF TP}far;{$ENDIF}
  477. procedure defwritevmt(q:pointer);{$IFDEF TP}far;{$ENDIF}
  478. begin
  479. { writes the addresses to the VMT }
  480. { but only this which are declared as virtual }
  481. if (Pprocdef(q)^.extnumber=i) and
  482. (povirtualmethod in Pprocdef(q)^.options) then
  483. begin
  484. { if a method is abstract, then is also the }
  485. { class abstract and it's not allow to }
  486. { generates an instance }
  487. if (poabstractmethod in Pprocdef(q)^.options) then
  488. begin
  489. include(_class^.options,oo_has_abstract);
  490. list^.concat(new(pai_const_symbol,initname('FPC_ABSTRACTERROR')));
  491. end
  492. else
  493. begin
  494. list^.concat(new(pai_const_symbol,
  495. initname(Pprocdef(q)^.mangledname)));
  496. end;
  497. end;
  498. end;
  499. begin
  500. Pprocsym(p)^.foreach(@defwritevmt);
  501. end;
  502. begin
  503. new(wurzel,init(64,16));
  504. nextvirtnumber:=0;
  505. has_constructor:=false;
  506. has_virtual_method:=false;
  507. { generates a tree of all used methods }
  508. do_genvmt(_class);
  509. if has_virtual_method and not(has_constructor) then
  510. message1(parser_w_virtual_without_constructor,_class^.objname^);
  511. { generates the VMT }
  512. { walk trough all numbers for virtual methods and search }
  513. { the method }
  514. for i:=0 to nextvirtnumber-1 do
  515. begin
  516. symcoll:=wurzel;
  517. symcoll^.foreach(@symwritevmt);
  518. end;
  519. dispose(symcoll,done);
  520. end;
  521. end.
  522. {
  523. $Log$
  524. Revision 1.1 2000-03-11 21:11:25 daniel
  525. * Ported hcgdata to new symtable.
  526. * Alignment code changed as suggested by Peter
  527. + Usage of my is operator replacement, is_object
  528. }