ncgrtti.pas 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Routines for the code generation of RTTI data structures
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit ncgrtti;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cclasses,constexp,
  22. aasmbase,
  23. symbase,symconst,symtype,symdef,symsym;
  24. type
  25. { TRTTIWriter }
  26. TRTTIWriter=class
  27. private
  28. procedure fields_write_rtti(st:tsymtable;rt:trttitype);
  29. procedure params_write_rtti(def:tabstractprocdef;rt:trttitype);
  30. procedure fields_write_rtti_data(def:tabstractrecorddef;rt:trttitype);
  31. procedure write_rtti_extrasyms(def:Tdef;rt:Trttitype;mainrtti:Tasmsymbol);
  32. procedure published_write_rtti(st:tsymtable;rt:trttitype);
  33. function published_properties_count(st:tsymtable):longint;
  34. procedure published_properties_write_rtti_data(propnamelist:TFPHashObjectList;st:tsymtable);
  35. procedure write_param_flag(parasym:tparavarsym);
  36. procedure methods_write_rtti(st:tsymtable);
  37. procedure collect_propnamelist(propnamelist:TFPHashObjectList;objdef:tobjectdef);
  38. function ref_rtti(def:tdef;rt:trttitype):tasmsymbol;
  39. procedure write_rtti_name(def:tdef);
  40. procedure write_rtti_data(def:tdef;rt:trttitype);
  41. procedure write_child_rtti_data(def:tdef;rt:trttitype);
  42. procedure write_rtti_reference(def:tdef;rt:trttitype);
  43. procedure write_header(def: tdef; typekind: byte);
  44. procedure write_string(const s: string);
  45. procedure maybe_write_align;
  46. public
  47. procedure write_rtti(def:tdef;rt:trttitype);
  48. function get_rtti_label(def:tdef;rt:trttitype):tasmsymbol;
  49. function get_rtti_label_ord2str(def:tdef;rt:trttitype):tasmsymbol;
  50. function get_rtti_label_str2ord(def:tdef;rt:trttitype):tasmsymbol;
  51. end;
  52. var
  53. RTTIWriter : TRTTIWriter;
  54. implementation
  55. uses
  56. cutils,
  57. globals,globtype,verbose,systems,
  58. fmodule, procinfo,
  59. aasmtai,aasmdata,
  60. defutil,
  61. wpobase
  62. ;
  63. const
  64. rttidefstate : array[trttitype] of tdefstate =
  65. (ds_rtti_table_written,ds_init_table_written,
  66. { Objective-C related, does not pass here }
  67. symconst.ds_none,symconst.ds_none,
  68. symconst.ds_none,symconst.ds_none);
  69. ProcCallOptionToCallConv: array[tproccalloption] of byte = (
  70. { pocall_none } 0,
  71. { pocall_cdecl } 1,
  72. { pocall_cppdecl } 5,
  73. { pocall_far16 } 6,
  74. { pocall_oldfpccall } 7,
  75. { pocall_internproc } 8,
  76. { pocall_syscall } 9,
  77. { pocall_pascal } 2,
  78. { pocall_register } 0,
  79. { pocall_safecall } 4,
  80. { pocall_stdcall } 3,
  81. { pocall_softfloat } 10,
  82. { pocall_mwpascal } 11,
  83. { pocall_interrupt } 12
  84. );
  85. type
  86. TPropNameListItem = class(TFPHashObject)
  87. propindex : longint;
  88. propowner : TSymtable;
  89. end;
  90. {***************************************************************************
  91. TRTTIWriter
  92. ***************************************************************************}
  93. procedure TRTTIWriter.maybe_write_align;
  94. begin
  95. if (tf_requires_proper_alignment in target_info.flags) then
  96. current_asmdata.asmlists[al_rtti].concat(cai_align.Create(sizeof(TConstPtrUInt)));
  97. end;
  98. procedure TRTTIWriter.write_string(const s: string);
  99. begin
  100. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(length(s)));
  101. current_asmdata.asmlists[al_rtti].concat(Tai_string.Create(s));
  102. end;
  103. procedure TRTTIWriter.write_header(def: tdef; typekind: byte);
  104. begin
  105. if def.typ=arraydef then
  106. InternalError(201012211);
  107. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(typekind));
  108. if assigned(def.typesym) then
  109. write_string(ttypesym(def.typesym).realname)
  110. else
  111. current_asmdata.asmlists[al_rtti].concat(Tai_string.Create(#0));
  112. end;
  113. procedure TRTTIWriter.write_rtti_name(def:tdef);
  114. var
  115. hs : string;
  116. begin
  117. if is_open_array(def) then
  118. { open arrays never have a typesym with a name, since you cannot
  119. define an "open array type". Kylix prints the type of the
  120. elements in the array in this case (so together with the pfArray
  121. flag, you can reconstruct the full typename, I assume (JM))
  122. }
  123. def:=tarraydef(def).elementdef;
  124. { name }
  125. if assigned(def.typesym) then
  126. begin
  127. hs:=ttypesym(def.typesym).realname;
  128. current_asmdata.asmlists[al_rtti].concat(Tai_string.Create(chr(length(hs))+hs));
  129. end
  130. else
  131. current_asmdata.asmlists[al_rtti].concat(Tai_string.Create(#0));
  132. end;
  133. { writes a 32-bit count followed by array of field infos for given symtable }
  134. procedure TRTTIWriter.fields_write_rtti_data(def:tabstractrecorddef;rt:trttitype);
  135. var
  136. i : longint;
  137. sym : tsym;
  138. fieldcnt: longint;
  139. lastai: TLinkedListItem;
  140. st: tsymtable;
  141. begin
  142. fieldcnt:=0;
  143. { Count will be inserted at this location. It cannot be nil as we've just
  144. written header for this symtable owner. But stay safe. }
  145. lastai:=current_asmdata.asmlists[al_rtti].last;
  146. if lastai=nil then
  147. InternalError(201012212);
  148. { For objects, treat parent (if any) as a field with offset 0. This
  149. provides correct handling of entire instance with RTL rtti routines. }
  150. if (def.typ=objectdef) and (tobjectdef(def).objecttype=odt_object) and
  151. Assigned(tobjectdef(def).childof) and
  152. ((rt=fullrtti) or (tobjectdef(def).childof.needs_inittable)) then
  153. begin
  154. write_rtti_reference(tobjectdef(def).childof,rt);
  155. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_pint(0));
  156. inc(fieldcnt);
  157. end;
  158. st:=def.symtable;
  159. for i:=0 to st.SymList.Count-1 do
  160. begin
  161. sym:=tsym(st.SymList[i]);
  162. if (tsym(sym).typ=fieldvarsym) and
  163. not(sp_static in tsym(sym).symoptions) and
  164. (
  165. (rt=fullrtti) or
  166. tfieldvarsym(sym).vardef.needs_inittable
  167. ) and
  168. not is_objc_class_or_protocol(tfieldvarsym(sym).vardef) then
  169. begin
  170. write_rtti_reference(tfieldvarsym(sym).vardef,rt);
  171. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_pint(tfieldvarsym(sym).fieldoffset));
  172. inc(fieldcnt);
  173. end;
  174. end;
  175. { insert field count before data }
  176. current_asmdata.asmlists[al_rtti].InsertAfter(Tai_const.Create_32bit(fieldcnt),lastai)
  177. end;
  178. procedure TRTTIWriter.fields_write_rtti(st:tsymtable;rt:trttitype);
  179. var
  180. i : longint;
  181. sym : tsym;
  182. begin
  183. for i:=0 to st.SymList.Count-1 do
  184. begin
  185. sym:=tsym(st.SymList[i]);
  186. if (tsym(sym).typ=fieldvarsym) and
  187. not(sp_static in tsym(sym).symoptions) and
  188. (
  189. (rt=fullrtti) or
  190. tfieldvarsym(sym).vardef.needs_inittable
  191. ) then
  192. write_rtti(tfieldvarsym(sym).vardef,rt);
  193. end;
  194. end;
  195. procedure TRTTIWriter.params_write_rtti(def:tabstractprocdef;rt:trttitype);
  196. var
  197. i : longint;
  198. sym : tparavarsym;
  199. begin
  200. for i:=0 to def.paras.count-1 do
  201. begin
  202. sym:=tparavarsym(def.paras[i]);
  203. if not (vo_is_hidden_para in sym.varoptions) then
  204. write_rtti(sym.vardef,rt);
  205. end;
  206. end;
  207. procedure TRTTIWriter.published_write_rtti(st:tsymtable;rt:trttitype);
  208. var
  209. i : longint;
  210. sym : tsym;
  211. begin
  212. for i:=0 to st.SymList.Count-1 do
  213. begin
  214. sym:=tsym(st.SymList[i]);
  215. if (sym.visibility=vis_published) then
  216. begin
  217. case tsym(sym).typ of
  218. propertysym:
  219. write_rtti(tpropertysym(sym).propdef,rt);
  220. fieldvarsym:
  221. write_rtti(tfieldvarsym(sym).vardef,rt);
  222. end;
  223. end;
  224. end;
  225. end;
  226. function TRTTIWriter.published_properties_count(st:tsymtable):longint;
  227. var
  228. i : longint;
  229. sym : tsym;
  230. begin
  231. result:=0;
  232. for i:=0 to st.SymList.Count-1 do
  233. begin
  234. sym:=tsym(st.SymList[i]);
  235. if (tsym(sym).typ=propertysym) and
  236. (sym.visibility=vis_published) then
  237. inc(result);
  238. end;
  239. end;
  240. procedure TRTTIWriter.collect_propnamelist(propnamelist:TFPHashObjectList;objdef:tobjectdef);
  241. var
  242. i : longint;
  243. sym : tsym;
  244. pn : tpropnamelistitem;
  245. begin
  246. if assigned(objdef.childof) then
  247. collect_propnamelist(propnamelist,objdef.childof);
  248. for i:=0 to objdef.symtable.SymList.Count-1 do
  249. begin
  250. sym:=tsym(objdef.symtable.SymList[i]);
  251. if (tsym(sym).typ=propertysym) and
  252. (sym.visibility=vis_published) then
  253. begin
  254. pn:=TPropNameListItem(propnamelist.Find(tsym(sym).name));
  255. if not assigned(pn) then
  256. begin
  257. pn:=tpropnamelistitem.create(propnamelist,tsym(sym).name);
  258. pn.propindex:=propnamelist.count-1;
  259. pn.propowner:=tsym(sym).owner;
  260. end;
  261. end;
  262. end;
  263. end;
  264. procedure TRTTIWriter.published_properties_write_rtti_data(propnamelist:TFPHashObjectList;st:tsymtable);
  265. var
  266. i : longint;
  267. sym : tsym;
  268. proctypesinfo : byte;
  269. propnameitem : tpropnamelistitem;
  270. procedure writeaccessproc(pap:tpropaccesslisttypes; shiftvalue : byte; unsetvalue: byte);
  271. var
  272. typvalue : byte;
  273. hp : ppropaccesslistitem;
  274. address,space : longint;
  275. def : tdef;
  276. hpropsym : tpropertysym;
  277. propaccesslist : tpropaccesslist;
  278. begin
  279. hpropsym:=tpropertysym(sym);
  280. repeat
  281. propaccesslist:=hpropsym.propaccesslist[pap];
  282. if not propaccesslist.empty then
  283. break;
  284. hpropsym:=hpropsym.overriddenpropsym;
  285. until not assigned(hpropsym);
  286. if not(assigned(propaccesslist) and assigned(propaccesslist.firstsym)) then
  287. begin
  288. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_int_codeptr(unsetvalue));
  289. typvalue:=3;
  290. end
  291. else if propaccesslist.firstsym^.sym.typ=fieldvarsym then
  292. begin
  293. address:=0;
  294. hp:=propaccesslist.firstsym;
  295. def:=nil;
  296. while assigned(hp) do
  297. begin
  298. case hp^.sltype of
  299. sl_load :
  300. begin
  301. def:=tfieldvarsym(hp^.sym).vardef;
  302. inc(address,tfieldvarsym(hp^.sym).fieldoffset);
  303. end;
  304. sl_subscript :
  305. begin
  306. if not(assigned(def) and
  307. ((def.typ=recorddef) or
  308. is_object(def))) then
  309. internalerror(200402171);
  310. inc(address,tfieldvarsym(hp^.sym).fieldoffset);
  311. def:=tfieldvarsym(hp^.sym).vardef;
  312. end;
  313. sl_vec :
  314. begin
  315. if not(assigned(def) and (def.typ=arraydef)) then
  316. internalerror(200402172);
  317. def:=tarraydef(def).elementdef;
  318. {Hp.value is a Tconstexprint, which can be rather large,
  319. sanity check for longint overflow.}
  320. space:=(high(address)-address) div def.size;
  321. if int64(space)<hp^.value then
  322. internalerror(200706101);
  323. inc(address,int64(def.size*hp^.value));
  324. end;
  325. end;
  326. hp:=hp^.next;
  327. end;
  328. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_int_codeptr(address));
  329. typvalue:=0;
  330. end
  331. else
  332. begin
  333. { When there was an error then procdef is not assigned }
  334. if not assigned(propaccesslist.procdef) then
  335. exit;
  336. if not(po_virtualmethod in tprocdef(propaccesslist.procdef).procoptions) or
  337. is_objectpascal_helper(tprocdef(propaccesslist.procdef).struct) then
  338. begin
  339. current_asmdata.asmlists[al_rtti].concat(Tai_const.createname(tprocdef(propaccesslist.procdef).mangledname,AT_FUNCTION,0));
  340. typvalue:=1;
  341. end
  342. else
  343. begin
  344. { virtual method, write vmt offset }
  345. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_int_codeptr(
  346. tobjectdef(tprocdef(propaccesslist.procdef).struct).vmtmethodoffset(tprocdef(propaccesslist.procdef).extnumber)));
  347. { register for wpo }
  348. tobjectdef(tprocdef(propaccesslist.procdef).struct).register_vmt_call(tprocdef(propaccesslist.procdef).extnumber);
  349. {$ifdef vtentry}
  350. { not sure if we can insert those vtentry symbols safely here }
  351. {$error register methods used for published properties}
  352. {$endif vtentry}
  353. typvalue:=2;
  354. end;
  355. end;
  356. proctypesinfo:=proctypesinfo or (typvalue shl shiftvalue);
  357. end;
  358. begin
  359. for i:=0 to st.SymList.Count-1 do
  360. begin
  361. sym:=tsym(st.SymList[i]);
  362. if (sym.typ=propertysym) and
  363. (sym.visibility=vis_published) then
  364. begin
  365. if ppo_indexed in tpropertysym(sym).propoptions then
  366. proctypesinfo:=$40
  367. else
  368. proctypesinfo:=0;
  369. write_rtti_reference(tpropertysym(sym).propdef,fullrtti);
  370. writeaccessproc(palt_read,0,0);
  371. writeaccessproc(palt_write,2,0);
  372. { is it stored ? }
  373. if not(ppo_stored in tpropertysym(sym).propoptions) then
  374. begin
  375. { no, so put a constant zero }
  376. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_nil_codeptr);
  377. proctypesinfo:=proctypesinfo or (3 shl 4);
  378. end
  379. else
  380. writeaccessproc(palt_stored,4,1); { maybe; if no procedure put a constant 1 (=true) }
  381. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_32bit(tpropertysym(sym).index));
  382. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_32bit(tpropertysym(sym).default));
  383. propnameitem:=TPropNameListItem(propnamelist.Find(tpropertysym(sym).name));
  384. if not assigned(propnameitem) then
  385. internalerror(200512201);
  386. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_16bit(propnameitem.propindex));
  387. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(proctypesinfo));
  388. write_string(tpropertysym(sym).realname);
  389. maybe_write_align;
  390. end;
  391. end;
  392. end;
  393. procedure TRTTIWriter.write_param_flag(parasym:tparavarsym);
  394. var
  395. paraspec : byte;
  396. begin
  397. case parasym.varspez of
  398. vs_value : paraspec := 0;
  399. vs_const : paraspec := pfConst;
  400. vs_var : paraspec := pfVar;
  401. vs_out : paraspec := pfOut;
  402. vs_constref: paraspec := pfConstRef;
  403. else
  404. internalerror(2013112904);
  405. end;
  406. { Kylix also seems to always add both pfArray and pfReference
  407. in this case
  408. }
  409. if is_open_array(parasym.vardef) then
  410. paraspec:=paraspec or pfArray or pfReference;
  411. { and these for classes and interfaces (maybe because they
  412. are themselves addresses?)
  413. }
  414. if is_class_or_interface(parasym.vardef) then
  415. paraspec:=paraspec or pfAddress;
  416. { set bits run from the highest to the lowest bit on
  417. big endian systems
  418. }
  419. if (target_info.endian = endian_big) then
  420. paraspec:=reverse_byte(paraspec);
  421. { write flags for current parameter }
  422. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(paraspec));
  423. end;
  424. procedure TRTTIWriter.methods_write_rtti(st: tsymtable);
  425. var
  426. count: Word;
  427. i,j,k: LongInt;
  428. sym : tprocsym;
  429. def : tabstractprocdef;
  430. para : tparavarsym;
  431. reg: Byte;
  432. off: LongInt;
  433. begin
  434. count:=0;
  435. for i:=0 to st.SymList.Count-1 do
  436. if (tsym(st.SymList[i]).typ=procsym) then
  437. inc(count);
  438. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_16bit(count));
  439. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_16bit(count));
  440. for i:=0 to st.SymList.Count-1 do
  441. if (tsym(st.SymList[i]).typ=procsym) then
  442. begin
  443. sym:=tprocsym(st.SymList[i]);
  444. for j:=0 to sym.ProcdefList.count-1 do
  445. begin
  446. def:=tabstractprocdef(sym.ProcdefList[j]);
  447. def.init_paraloc_info(callerside);
  448. write_string(sym.realname);
  449. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(3));
  450. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(ProcCallOptionToCallConv[def.proccalloption]));
  451. write_rtti_reference(def.returndef,fullrtti);
  452. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_16bit(def.callerargareasize));
  453. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(def.maxparacount + 1));
  454. for k:=0 to def.paras.count-1 do
  455. begin
  456. para:=tparavarsym(def.paras[k]);
  457. { write flags for current parameter }
  458. write_param_flag(para);
  459. maybe_write_align;
  460. { write param type }
  461. write_rtti_reference(para.vardef,fullrtti);
  462. reg:=0;
  463. off:=0;
  464. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(reg));
  465. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_32bit(off));
  466. { write name of current parameter }
  467. write_string(para.realname);
  468. end;
  469. end;
  470. end;
  471. end;
  472. procedure TRTTIWriter.write_rtti_data(def:tdef;rt:trttitype);
  473. procedure unknown_rtti(def:tstoreddef);
  474. begin
  475. current_asmdata.asmlists[al_rtti].concat(tai_const.create_8bit(tkUnknown));
  476. write_rtti_name(def);
  477. end;
  478. procedure variantdef_rtti(def:tvariantdef);
  479. begin
  480. write_header(def,tkVariant);
  481. end;
  482. procedure stringdef_rtti(def:tstringdef);
  483. begin
  484. case def.stringtype of
  485. st_ansistring:
  486. begin
  487. write_header(def,tkAString);
  488. maybe_write_align;
  489. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_16bit(def.encoding));
  490. end;
  491. st_widestring:
  492. write_header(def,tkWString);
  493. st_unicodestring:
  494. write_header(def,tkUString);
  495. st_longstring:
  496. write_header(def,tkLString);
  497. st_shortstring:
  498. begin
  499. write_header(def,tkSString);
  500. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(def.len));
  501. maybe_write_align; // is align necessary here?
  502. end;
  503. end;
  504. end;
  505. procedure enumdef_rtti(def:tenumdef);
  506. var
  507. i : integer;
  508. hp : tenumsym;
  509. begin
  510. write_header(def,tkEnumeration);
  511. maybe_write_align;
  512. case longint(def.size) of
  513. 1 :
  514. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(otUByte));
  515. 2 :
  516. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(otUWord));
  517. 4 :
  518. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(otULong));
  519. end;
  520. { we need to align by Tconstptruint here to satisfy the alignment rules set by
  521. records: in the typinfo unit we overlay a TTypeData record on this data, which at
  522. the innermost variant record needs an alignment of TConstPtrUint due to e.g.
  523. the "CompType" member for tkSet (also the "BaseType" member for tkEnumeration).
  524. We need to adhere to this, otherwise things will break.
  525. Note that other code (e.g. enumdef_rtti_calcstringtablestart()) relies on the
  526. exact sequence too. }
  527. maybe_write_align;
  528. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_32bit(def.min));
  529. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_32bit(def.max));
  530. maybe_write_align; // is align necessary here?
  531. { write base type }
  532. write_rtti_reference(def.basedef,rt);
  533. for i := 0 to def.symtable.SymList.Count - 1 do
  534. begin
  535. hp:=tenumsym(def.symtable.SymList[i]);
  536. if hp.value<def.minval then
  537. continue
  538. else
  539. if hp.value>def.maxval then
  540. break;
  541. write_string(hp.realname);
  542. end;
  543. { write unit name }
  544. write_string(current_module.realmodulename^);
  545. { write zero which is required by RTL }
  546. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(0));
  547. end;
  548. procedure orddef_rtti(def:torddef);
  549. procedure dointeger(typekind: byte);
  550. const
  551. trans : array[tordtype] of byte =
  552. (otUByte{otNone},
  553. otUByte,otUWord,otULong,otUByte{otNone},
  554. otSByte,otSWord,otSLong,otUByte{otNone},
  555. otUByte,otUWord,otULong,otUByte,
  556. otSByte,otSWord,otSLong,otSByte,
  557. otUByte,otUWord,otUByte);
  558. begin
  559. write_header(def,typekind);
  560. maybe_write_align;
  561. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(byte(trans[def.ordtype])));
  562. maybe_write_align;
  563. {Convert to longint to smuggle values in high(longint)+1..high(cardinal) into asmlist.}
  564. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_32bit(longint(def.low.svalue)));
  565. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_32bit(longint(def.high.svalue)));
  566. end;
  567. begin
  568. case def.ordtype of
  569. s64bit :
  570. begin
  571. write_header(def,tkInt64);
  572. maybe_write_align;
  573. { low }
  574. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_64bit(def.low.svalue));
  575. { high }
  576. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_64bit(def.high.svalue));
  577. end;
  578. u64bit :
  579. begin
  580. write_header(def,tkQWord);
  581. maybe_write_align;
  582. {use svalue because Create_64bit accepts int64, prevents range checks}
  583. { low }
  584. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_64bit(def.low.svalue));
  585. { high }
  586. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_64bit(def.high.svalue));
  587. end;
  588. pasbool8:
  589. dointeger(tkBool);
  590. uchar:
  591. dointeger(tkChar);
  592. uwidechar:
  593. dointeger(tkWChar);
  594. scurrency:
  595. begin
  596. write_header(def,tkFloat);
  597. maybe_write_align;
  598. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(ftCurr));
  599. end;
  600. else
  601. dointeger(tkInteger);
  602. end;
  603. end;
  604. procedure floatdef_rtti(def:tfloatdef);
  605. const
  606. {tfloattype = (s32real,s64real,s80real,sc80real,s64bit,s128bit);}
  607. translate : array[tfloattype] of byte =
  608. (ftSingle,ftDouble,ftExtended,ftExtended,ftComp,ftCurr,ftFloat128);
  609. begin
  610. write_header(def,tkFloat);
  611. maybe_write_align;
  612. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(translate[def.floattype]));
  613. end;
  614. procedure setdef_rtti(def:tsetdef);
  615. begin
  616. write_header(def,tkSet);
  617. maybe_write_align;
  618. case def.size of
  619. 1:
  620. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(otUByte));
  621. 2:
  622. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(otUWord));
  623. 4:
  624. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(otULong));
  625. else
  626. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(otUByte));
  627. end;
  628. maybe_write_align;
  629. write_rtti_reference(def.elementdef,rt);
  630. end;
  631. procedure arraydef_rtti(def:tarraydef);
  632. var
  633. lastai: TLinkedListItem;
  634. dimcount: byte;
  635. totalcount: asizeuint;
  636. curdef:tarraydef;
  637. begin
  638. if ado_IsDynamicArray in def.arrayoptions then
  639. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(tkdynarray))
  640. else
  641. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(tkarray));
  642. write_rtti_name(def);
  643. maybe_write_align;
  644. if not(ado_IsDynamicArray in def.arrayoptions) then
  645. begin
  646. { remember tha last instruction. we will need to insert some
  647. calculated values after it }
  648. lastai:=current_asmdata.asmlists[al_rtti].last;
  649. curdef:=def;
  650. totalcount:=1;
  651. dimcount:=0;
  652. while assigned(curdef) do
  653. begin
  654. { Dims[i] PTypeInfo }
  655. write_rtti_reference(curdef.rangedef,rt);
  656. inc(dimcount);
  657. totalcount:=totalcount*curdef.elecount;
  658. { get the next static array }
  659. if assigned(curdef.elementdef) and
  660. (curdef.elementdef.typ=arraydef) and
  661. not(ado_IsDynamicArray in tarraydef(curdef.elementdef).arrayoptions) then
  662. curdef:=tarraydef(curdef.elementdef)
  663. else
  664. break;
  665. end;
  666. if (tf_requires_proper_alignment in target_info.flags) then
  667. current_asmdata.asmlists[al_rtti].InsertAfter(cai_align.Create(sizeof(TConstPtrUInt)),lastai);
  668. { dimension count }
  669. current_asmdata.asmlists[al_rtti].InsertAfter(Tai_const.Create_8bit(dimcount),lastai);
  670. { last dimension element type }
  671. current_asmdata.asmlists[al_rtti].InsertAfter(Tai_const.Create_sym(ref_rtti(curdef.elementdef,rt)),lastai);
  672. { total element count }
  673. current_asmdata.asmlists[al_rtti].InsertAfter(Tai_const.Create_pint(pint(totalcount)),lastai);
  674. { total size = elecount * elesize of the first arraydef }
  675. current_asmdata.asmlists[al_rtti].InsertAfter(Tai_const.Create_pint(def.elecount*def.elesize),lastai);
  676. end
  677. else
  678. { write a delphi almost compatible dyn. array entry:
  679. there are two types, eltype and eltype2, the latter is nil if the element type needs
  680. no finalization, the former is always valid, delphi has this swapped, but for
  681. compatibility with older fpc versions we do it different, to be delphi compatible,
  682. the names are swapped in typinfo.pp
  683. }
  684. begin
  685. { size of elements }
  686. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_pint(def.elesize));
  687. { element type }
  688. write_rtti_reference(def.elementdef,rt);
  689. { variant type }
  690. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_32bit(tstoreddef(def.elementdef).getvardef));
  691. { element type }
  692. if def.elementdef.needs_inittable then
  693. write_rtti_reference(def.elementdef,rt)
  694. else
  695. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_nil_dataptr);
  696. { write unit name }
  697. write_string(current_module.realmodulename^);
  698. end;
  699. end;
  700. procedure classrefdef_rtti(def:tclassrefdef);
  701. begin
  702. write_header(def,tkClassRef);
  703. maybe_write_align;
  704. write_rtti_reference(def.pointeddef,rt);
  705. end;
  706. procedure pointerdef_rtti(def:tpointerdef);
  707. begin
  708. write_header(def,tkPointer);
  709. maybe_write_align;
  710. write_rtti_reference(def.pointeddef,rt);
  711. end;
  712. procedure recorddef_rtti(def:trecorddef);
  713. begin
  714. write_header(def,tkRecord);
  715. maybe_write_align;
  716. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_32bit(def.size));
  717. fields_write_rtti_data(def,rt);
  718. end;
  719. procedure procvardef_rtti(def:tprocvardef);
  720. procedure write_para(parasym:tparavarsym);
  721. begin
  722. { only store user visible parameters }
  723. if not(vo_is_hidden_para in parasym.varoptions) then
  724. begin
  725. { write flags for current parameter }
  726. write_param_flag(parasym);
  727. { write name of current parameter }
  728. write_string(parasym.realname);
  729. { write name of type of current parameter }
  730. write_rtti_name(parasym.vardef);
  731. end;
  732. end;
  733. procedure write_procedure_param(parasym:tparavarsym);
  734. begin
  735. { only store user visible parameters }
  736. if not(vo_is_hidden_para in parasym.varoptions) then
  737. begin
  738. { write flags for current parameter }
  739. write_param_flag(parasym);
  740. maybe_write_align;
  741. { write param type }
  742. write_rtti_reference(parasym.vardef,fullrtti);
  743. { write name of current parameter }
  744. write_string(parasym.realname);
  745. end;
  746. end;
  747. var
  748. methodkind : byte;
  749. i : integer;
  750. begin
  751. if po_methodpointer in def.procoptions then
  752. begin
  753. { write method id and name }
  754. write_header(def,tkMethod);
  755. maybe_write_align;
  756. { write kind of method }
  757. case def.proctypeoption of
  758. potype_constructor: methodkind:=mkConstructor;
  759. potype_destructor: methodkind:=mkDestructor;
  760. potype_class_constructor: methodkind:=mkClassConstructor;
  761. potype_class_destructor: methodkind:=mkClassDestructor;
  762. potype_operator: methodkind:=mkOperatorOverload;
  763. potype_procedure:
  764. if po_classmethod in def.procoptions then
  765. methodkind:=mkClassProcedure
  766. else
  767. methodkind:=mkProcedure;
  768. potype_function:
  769. if po_classmethod in def.procoptions then
  770. methodkind:=mkClassFunction
  771. else
  772. methodkind:=mkFunction;
  773. else
  774. begin
  775. if def.returndef = voidtype then
  776. methodkind:=mkProcedure
  777. else
  778. methodkind:=mkFunction;
  779. end;
  780. end;
  781. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(methodkind));
  782. { write parameter info. The parameters must be written in reverse order
  783. if this method uses right to left parameter pushing! }
  784. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(def.maxparacount));
  785. for i:=0 to def.paras.count-1 do
  786. write_para(tparavarsym(def.paras[i]));
  787. if (methodkind=mkFunction) or (methodkind=mkClassFunction) then
  788. begin
  789. { write name of result type }
  790. write_rtti_name(def.returndef);
  791. maybe_write_align;
  792. { write result typeinfo }
  793. write_rtti_reference(def.returndef,fullrtti);
  794. end;
  795. { write calling convention }
  796. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(ProcCallOptionToCallConv[def.proccalloption]));
  797. maybe_write_align;
  798. { write params typeinfo }
  799. for i:=0 to def.paras.count-1 do
  800. if not(vo_is_hidden_para in tparavarsym(def.paras[i]).varoptions) then
  801. write_rtti_reference(tparavarsym(def.paras[i]).vardef,fullrtti);
  802. end
  803. else
  804. begin
  805. write_header(def,tkProcvar);
  806. maybe_write_align;
  807. { flags }
  808. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(0));
  809. //maybe_write_align; // aligning between bytes is not necessary
  810. { write calling convention }
  811. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(ProcCallOptionToCallConv[def.proccalloption]));
  812. maybe_write_align;
  813. { write result typeinfo }
  814. write_rtti_reference(def.returndef,fullrtti);
  815. { write parameter count }
  816. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(def.maxparacount));
  817. for i:=0 to def.paras.count-1 do
  818. begin
  819. maybe_write_align;
  820. write_procedure_param(tparavarsym(def.paras[i]));
  821. end;
  822. end;
  823. end;
  824. procedure objectdef_rtti(def:tobjectdef);
  825. procedure objectdef_rtti_fields(def:tobjectdef);
  826. begin
  827. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_32bit(def.size));
  828. fields_write_rtti_data(def,rt);
  829. end;
  830. procedure objectdef_rtti_interface_init(def:tobjectdef);
  831. begin
  832. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_32bit(def.size));
  833. end;
  834. procedure objectdef_rtti_class_full(def:tobjectdef);
  835. var
  836. propnamelist : TFPHashObjectList;
  837. begin
  838. { Collect unique property names with nameindex }
  839. propnamelist:=TFPHashObjectList.Create;
  840. collect_propnamelist(propnamelist,def);
  841. if not is_objectpascal_helper(def) then
  842. if (oo_has_vmt in def.objectoptions) then
  843. current_asmdata.asmlists[al_rtti].concat(Tai_const.Createname(def.vmt_mangledname,AT_DATA,0))
  844. else
  845. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_nil_dataptr);
  846. { write parent typeinfo }
  847. write_rtti_reference(def.childof,fullrtti);
  848. { write typeinfo of extended type }
  849. if is_objectpascal_helper(def) then
  850. if assigned(def.extendeddef) then
  851. write_rtti_reference(def.extendeddef,fullrtti)
  852. else
  853. InternalError(2011033001);
  854. { total number of unique properties }
  855. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_16bit(propnamelist.count));
  856. { write unit name }
  857. write_string(current_module.realmodulename^);
  858. maybe_write_align;
  859. { write published properties for this object }
  860. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_16bit(published_properties_count(def.symtable)));
  861. maybe_write_align;
  862. published_properties_write_rtti_data(propnamelist,def.symtable);
  863. propnamelist.free;
  864. end;
  865. procedure objectdef_rtti_interface_full(def:tobjectdef);
  866. var
  867. i : longint;
  868. propnamelist : TFPHashObjectList;
  869. { if changed to a set, make sure it's still a byte large, and
  870. swap appropriately when cross-compiling
  871. }
  872. IntfFlags: byte;
  873. begin
  874. { Collect unique property names with nameindex }
  875. propnamelist:=TFPHashObjectList.Create;
  876. collect_propnamelist(propnamelist,def);
  877. { write parent typeinfo }
  878. write_rtti_reference(def.childof,fullrtti);
  879. { interface: write flags, iid and iidstr }
  880. IntfFlags:=0;
  881. if assigned(def.iidguid) then
  882. IntfFlags:=IntfFlags or (1 shl ord(ifHasGuid));
  883. if assigned(def.iidstr) then
  884. IntfFlags:=IntfFlags or (1 shl ord(ifHasStrGUID));
  885. if (def.objecttype=odt_dispinterface) then
  886. IntfFlags:=IntfFlags or (1 shl ord(ifDispInterface));
  887. if (target_info.endian=endian_big) then
  888. IntfFlags:=reverse_byte(IntfFlags);
  889. {
  890. ifDispatch, }
  891. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(IntfFlags));
  892. maybe_write_align;
  893. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_32bit(longint(def.iidguid^.D1)));
  894. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_16bit(def.iidguid^.D2));
  895. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_16bit(def.iidguid^.D3));
  896. for i:=Low(def.iidguid^.D4) to High(def.iidguid^.D4) do
  897. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(def.iidguid^.D4[i]));
  898. { write unit name }
  899. write_string(current_module.realmodulename^);
  900. maybe_write_align;
  901. { write iidstr }
  902. if def.objecttype = odt_interfacecorba then
  903. begin
  904. if assigned(def.iidstr) then
  905. write_string(def.iidstr^)
  906. else
  907. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(0));
  908. maybe_write_align;
  909. end;
  910. { write published properties for this object }
  911. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_16bit(published_properties_count(def.symtable)));
  912. maybe_write_align;
  913. published_properties_write_rtti_data(propnamelist,def.symtable);
  914. { write methods for this object }
  915. methods_write_rtti(def.symtable);
  916. propnamelist.free;
  917. end;
  918. begin
  919. case def.objecttype of
  920. odt_class:
  921. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(tkclass));
  922. odt_object:
  923. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(tkobject));
  924. odt_dispinterface,
  925. odt_interfacecom:
  926. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(tkinterface));
  927. odt_interfacecorba:
  928. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(tkinterfaceCorba));
  929. odt_helper:
  930. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_8bit(tkhelper));
  931. else
  932. internalerror(200611034);
  933. end;
  934. { generate the name }
  935. write_string(def.objrealname^);
  936. maybe_write_align;
  937. case rt of
  938. initrtti :
  939. begin
  940. if def.objecttype in [odt_class,odt_object,odt_helper] then
  941. objectdef_rtti_fields(def)
  942. else
  943. objectdef_rtti_interface_init(def);
  944. end;
  945. fullrtti :
  946. begin
  947. case def.objecttype of
  948. odt_helper,
  949. odt_class:
  950. objectdef_rtti_class_full(def);
  951. odt_object:
  952. objectdef_rtti_fields(def);
  953. else
  954. objectdef_rtti_interface_full(def);
  955. end;
  956. end;
  957. end;
  958. end;
  959. begin
  960. case def.typ of
  961. variantdef :
  962. variantdef_rtti(tvariantdef(def));
  963. stringdef :
  964. stringdef_rtti(tstringdef(def));
  965. enumdef :
  966. enumdef_rtti(tenumdef(def));
  967. orddef :
  968. orddef_rtti(torddef(def));
  969. floatdef :
  970. floatdef_rtti(tfloatdef(def));
  971. setdef :
  972. setdef_rtti(tsetdef(def));
  973. procvardef :
  974. procvardef_rtti(tprocvardef(def));
  975. arraydef :
  976. begin
  977. if ado_IsBitPacked in tarraydef(def).arrayoptions then
  978. unknown_rtti(tstoreddef(def))
  979. else
  980. arraydef_rtti(tarraydef(def));
  981. end;
  982. recorddef :
  983. begin
  984. if trecorddef(def).is_packed then
  985. unknown_rtti(tstoreddef(def))
  986. else
  987. recorddef_rtti(trecorddef(def));
  988. end;
  989. objectdef :
  990. objectdef_rtti(tobjectdef(def));
  991. classrefdef :
  992. classrefdef_rtti(tclassrefdef(def));
  993. pointerdef :
  994. pointerdef_rtti(tpointerdef(def));
  995. else
  996. unknown_rtti(tstoreddef(def));
  997. end;
  998. end;
  999. procedure TRTTIWriter.write_rtti_extrasyms(def:Tdef;rt:Trttitype;mainrtti:Tasmsymbol);
  1000. type Penumsym = ^Tenumsym;
  1001. function enumdef_rtti_calcstringtablestart(const def : Tenumdef) : integer;
  1002. begin
  1003. { the alignment calls must correspond to the ones used during generating the
  1004. actual data structure created elsewhere in this file }
  1005. result:=1;
  1006. if assigned(def.typesym) then
  1007. inc(result,length(def.typesym.realname)+1)
  1008. else
  1009. inc(result);
  1010. if (tf_requires_proper_alignment in target_info.flags) then
  1011. result:=align(result,sizeof(Tconstptruint));
  1012. inc(result);
  1013. if (tf_requires_proper_alignment in target_info.flags) then
  1014. result:=align(result,sizeof(Tconstptruint));
  1015. inc(result, sizeof(longint) * 2);
  1016. if (tf_requires_proper_alignment in target_info.flags) then
  1017. result:=align(result,sizeof(Tconstptruint));
  1018. inc(result, sizeof(pint));
  1019. end;
  1020. { Writes a helper table for accelerated conversion of ordinal enum values to strings.
  1021. If you change something in this method, make sure to adapt the corresponding code
  1022. in sstrings.inc. }
  1023. procedure enumdef_rtti_ord2stringindex(const sym_count:longint; const offsets:plongint; const syms:Penumsym; const st:longint);
  1024. var rttilab:Tasmsymbol;
  1025. h,i,o,prev_value:longint;
  1026. mode:(lookup,search); {Modify with care, ordinal value of enum is written.}
  1027. r:single; {Must be real type because of integer overflow risk.}
  1028. begin
  1029. {Decide wether a lookup array is size efficient.}
  1030. mode:=lookup;
  1031. if sym_count>0 then
  1032. begin
  1033. i:=1;
  1034. r:=0;
  1035. h:=syms[0].value; {Next expected enum value is min.}
  1036. { set prev_value for the first iteration to a value that is
  1037. different from the first one without risking overflow (it's used
  1038. to detect whether two enum values are the same) }
  1039. if h=0 then
  1040. prev_value:=1
  1041. else
  1042. prev_value:=0;
  1043. while i<sym_count do
  1044. begin
  1045. { if two enum values are the same, we have to create a table }
  1046. if (prev_value=h) then
  1047. begin
  1048. mode:=search;
  1049. break;
  1050. end;
  1051. {Calculate size of hole between values. Avoid integer overflows.}
  1052. r:=r+(single(syms[i].value)-single(h))-1;
  1053. prev_value:=h;
  1054. h:=syms[i].value;
  1055. inc(i);
  1056. end;
  1057. if r>sym_count then
  1058. mode:=search; {Don't waste more than 50% space.}
  1059. end;
  1060. { write rtti data; make sure that the alignment matches the corresponding data structure
  1061. in the code that uses it (if alignment is required). }
  1062. with current_asmdata do
  1063. begin
  1064. rttilab:=defineasmsymbol(Tstoreddef(def).rtti_mangledname(rt)+'_o2s',AB_GLOBAL,AT_DATA);
  1065. maybe_new_object_file(asmlists[al_rtti]);
  1066. new_section(asmlists[al_rtti],sec_rodata,rttilab.name,const_align(sizeof(pint)));
  1067. asmlists[al_rtti].concat(Tai_symbol.create_global(rttilab,0));
  1068. asmlists[al_rtti].concat(Tai_const.create_32bit(longint(mode)));
  1069. if mode=lookup then
  1070. begin
  1071. maybe_write_align;
  1072. o:=syms[0].value; {Start with min value.}
  1073. for i:=0 to sym_count-1 do
  1074. begin
  1075. while o<syms[i].value do
  1076. begin
  1077. asmlists[al_rtti].concat(Tai_const.create_pint(0));
  1078. inc(o);
  1079. end;
  1080. inc(o);
  1081. asmlists[al_rtti].concat(Tai_const.create_sym_offset(mainrtti,st+offsets[i]));
  1082. end;
  1083. end
  1084. else
  1085. begin
  1086. maybe_write_align;
  1087. asmlists[al_rtti].concat(Tai_const.create_32bit(sym_count));
  1088. for i:=0 to sym_count-1 do
  1089. begin
  1090. maybe_write_align;
  1091. asmlists[al_rtti].concat(Tai_const.create_32bit(syms[i].value));
  1092. maybe_write_align;
  1093. asmlists[al_rtti].concat(Tai_const.create_sym_offset(mainrtti,st+offsets[i]));
  1094. end;
  1095. end;
  1096. asmlists[al_rtti].concat(Tai_symbol_end.create(rttilab));
  1097. end;
  1098. end;
  1099. { Writes a helper table for accelerated conversion of string to ordinal enum values.
  1100. If you change something in this method, make sure to adapt the corresponding code
  1101. in sstrings.inc. }
  1102. procedure enumdef_rtti_string2ordindex(const sym_count:longint; const offsets:plongint; const syms:Penumsym; const st:longint);
  1103. var rttilab:Tasmsymbol;
  1104. i:longint;
  1105. begin
  1106. { write rtti data }
  1107. with current_asmdata do
  1108. begin
  1109. rttilab:=defineasmsymbol(Tstoreddef(def).rtti_mangledname(rt)+'_s2o',AB_GLOBAL,AT_DATA);
  1110. maybe_new_object_file(asmlists[al_rtti]);
  1111. new_section(asmlists[al_rtti],sec_rodata,rttilab.name,const_align(sizeof(pint)));
  1112. asmlists[al_rtti].concat(Tai_symbol.create_global(rttilab,0));
  1113. asmlists[al_rtti].concat(Tai_const.create_32bit(sym_count));
  1114. { need to align the entry record according to the largest member }
  1115. maybe_write_align;
  1116. for i:=0 to sym_count-1 do
  1117. begin
  1118. if (tf_requires_proper_alignment in target_info.flags) then
  1119. current_asmdata.asmlists[al_rtti].concat(cai_align.Create(4)); // necessary?
  1120. asmlists[al_rtti].concat(Tai_const.create_32bit(syms[i].value));
  1121. maybe_write_align;
  1122. asmlists[al_rtti].concat(Tai_const.create_sym_offset(mainrtti,st+offsets[i]));
  1123. end;
  1124. asmlists[al_rtti].concat(Tai_symbol_end.create(rttilab));
  1125. end;
  1126. end;
  1127. procedure enumdef_rtti_extrasyms(def:Tenumdef);
  1128. var
  1129. t:Tenumsym;
  1130. syms:Penumsym;
  1131. sym_count,sym_alloc:sizeuint;
  1132. offsets:^longint;
  1133. h,i,p,o,st:longint;
  1134. begin
  1135. {Random access needed, put in array.}
  1136. getmem(syms,64*sizeof(Tenumsym));
  1137. getmem(offsets,64*sizeof(longint));
  1138. sym_count:=0;
  1139. sym_alloc:=64;
  1140. st:=0;
  1141. for i := 0 to def.symtable.SymList.Count - 1 do
  1142. begin
  1143. t:=tenumsym(def.symtable.SymList[i]);
  1144. if t.value<def.minval then
  1145. continue
  1146. else
  1147. if t.value>def.maxval then
  1148. break;
  1149. if sym_count>=sym_alloc then
  1150. begin
  1151. reallocmem(syms,2*sym_alloc*sizeof(Tenumsym));
  1152. reallocmem(offsets,2*sym_alloc*sizeof(longint));
  1153. sym_alloc:=sym_alloc*2;
  1154. end;
  1155. syms[sym_count]:=t;
  1156. offsets[sym_count]:=st;
  1157. inc(sym_count);
  1158. st:=st+length(t.realname)+1;
  1159. end;
  1160. {Sort the syms by enum name}
  1161. if sym_count>=2 then
  1162. begin
  1163. p:=1;
  1164. while 2*p<sym_count do
  1165. p:=2*p;
  1166. while p<>0 do
  1167. begin
  1168. for h:=p to sym_count-1 do
  1169. begin
  1170. i:=h;
  1171. t:=syms[i];
  1172. o:=offsets[i];
  1173. repeat
  1174. if syms[i-p].name<=t.name then
  1175. break;
  1176. syms[i]:=syms[i-p];
  1177. offsets[i]:=offsets[i-p];
  1178. dec(i,p);
  1179. until i<p;
  1180. syms[i]:=t;
  1181. offsets[i]:=o;
  1182. end;
  1183. p:=p shr 1;
  1184. end;
  1185. end;
  1186. st:=enumdef_rtti_calcstringtablestart(def);
  1187. enumdef_rtti_string2ordindex(sym_count,offsets,syms,st);
  1188. { Sort the syms by enum value }
  1189. if sym_count>=2 then
  1190. begin
  1191. p:=1;
  1192. while 2*p<sym_count do
  1193. p:=2*p;
  1194. while p<>0 do
  1195. begin
  1196. for h:=p to sym_count-1 do
  1197. begin
  1198. i:=h;
  1199. t:=syms[i];
  1200. o:=offsets[i];
  1201. repeat
  1202. if syms[i-p].value<=t.value then
  1203. break;
  1204. syms[i]:=syms[i-p];
  1205. offsets[i]:=offsets[i-p];
  1206. dec(i,p);
  1207. until i<p;
  1208. syms[i]:=t;
  1209. offsets[i]:=o;
  1210. end;
  1211. p:=p shr 1;
  1212. end;
  1213. end;
  1214. enumdef_rtti_ord2stringindex(sym_count,offsets,syms,st);
  1215. freemem(syms);
  1216. freemem(offsets);
  1217. end;
  1218. begin
  1219. case def.typ of
  1220. enumdef:
  1221. if rt=fullrtti then
  1222. begin
  1223. enumdef_rtti_extrasyms(Tenumdef(def));
  1224. end;
  1225. end;
  1226. end;
  1227. procedure TRTTIWriter.write_child_rtti_data(def:tdef;rt:trttitype);
  1228. var
  1229. i,j: SizeInt;
  1230. begin
  1231. case def.typ of
  1232. enumdef :
  1233. if assigned(tenumdef(def).basedef) then
  1234. write_rtti(tenumdef(def).basedef,rt);
  1235. setdef :
  1236. write_rtti(tsetdef(def).elementdef,rt);
  1237. arraydef :
  1238. begin
  1239. write_rtti(tarraydef(def).rangedef,rt);
  1240. write_rtti(tarraydef(def).elementdef,rt);
  1241. end;
  1242. recorddef :
  1243. fields_write_rtti(trecorddef(def).symtable,rt);
  1244. objectdef :
  1245. begin
  1246. if assigned(tobjectdef(def).childof) then
  1247. write_rtti(tobjectdef(def).childof,rt);
  1248. if (rt=initrtti) or (tobjectdef(def).objecttype=odt_object) then
  1249. fields_write_rtti(tobjectdef(def).symtable,rt)
  1250. else
  1251. begin
  1252. published_write_rtti(tobjectdef(def).symtable,rt);
  1253. if is_any_interface_kind(def) then
  1254. with tobjectdef(def).symtable do
  1255. for i := 0 to SymList.Count-1 do
  1256. if (tsym(SymList[i]).typ=procsym) then
  1257. with tprocsym(tobjectdef(def).symtable.SymList[i]) do
  1258. for j := 0 to ProcdefList.Count - 1 do
  1259. begin
  1260. write_rtti(tabstractprocdef(ProcdefList[j]).returndef,rt);
  1261. params_write_rtti(tabstractprocdef(ProcdefList[j]),rt);
  1262. end;
  1263. end;
  1264. end;
  1265. classrefdef,
  1266. pointerdef:
  1267. if not is_objc_class_or_protocol(tabstractpointerdef(def).pointeddef) then
  1268. write_rtti(tabstractpointerdef(def).pointeddef,rt);
  1269. procvardef:
  1270. params_write_rtti(tabstractprocdef(def),rt);
  1271. end;
  1272. end;
  1273. procedure TRTTIWriter.write_rtti_reference(def:tdef;rt:trttitype);
  1274. begin
  1275. if not assigned(def) or is_void(def) or ((rt<>initrtti) and is_objc_class_or_protocol(def)) then
  1276. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_nil_dataptr)
  1277. else
  1278. current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_sym(ref_rtti(def,rt)));
  1279. end;
  1280. function TRTTIWriter.ref_rtti(def:tdef;rt:trttitype):tasmsymbol;
  1281. begin
  1282. result:=current_asmdata.RefAsmSymbol(def.rtti_mangledname(rt),AT_DATA);
  1283. if (cs_create_pic in current_settings.moduleswitches) and
  1284. assigned(current_procinfo) then
  1285. include(current_procinfo.flags,pi_needs_got);
  1286. end;
  1287. procedure TRTTIWriter.write_rtti(def:tdef;rt:trttitype);
  1288. var
  1289. rttilab : tasmsymbol;
  1290. begin
  1291. { only write rtti of definitions from the current module }
  1292. if not findunitsymtable(def.owner).iscurrentunit then
  1293. exit;
  1294. { check if separate initrtti is actually needed }
  1295. if (rt=initrtti) and (not def.needs_separate_initrtti) then
  1296. rt:=fullrtti;
  1297. { prevent recursion }
  1298. if rttidefstate[rt] in def.defstates then
  1299. exit;
  1300. include(def.defstates,rttidefstate[rt]);
  1301. { write first all dependencies }
  1302. write_child_rtti_data(def,rt);
  1303. { write rtti data }
  1304. rttilab:=current_asmdata.DefineAsmSymbol(tstoreddef(def).rtti_mangledname(rt),AB_GLOBAL,AT_DATA);
  1305. maybe_new_object_file(current_asmdata.asmlists[al_rtti]);
  1306. new_section(current_asmdata.asmlists[al_rtti],sec_rodata,rttilab.name,const_align(sizeof(pint)));
  1307. current_asmdata.asmlists[al_rtti].concat(Tai_symbol.Create_global(rttilab,0));
  1308. write_rtti_data(def,rt);
  1309. current_asmdata.asmlists[al_rtti].concat(Tai_symbol_end.Create(rttilab));
  1310. write_rtti_extrasyms(def,rt,rttilab);
  1311. end;
  1312. function TRTTIWriter.get_rtti_label(def:tdef;rt:trttitype):tasmsymbol;
  1313. begin
  1314. result:=current_asmdata.RefAsmSymbol(def.rtti_mangledname(rt),AT_DATA);
  1315. if (cs_create_pic in current_settings.moduleswitches) and
  1316. assigned(current_procinfo) then
  1317. include(current_procinfo.flags,pi_needs_got);
  1318. end;
  1319. function TRTTIWriter.get_rtti_label_ord2str(def:tdef;rt:trttitype):tasmsymbol;
  1320. begin
  1321. result:=current_asmdata.RefAsmSymbol(def.rtti_mangledname(rt)+'_o2s',AT_DATA);
  1322. if (cs_create_pic in current_settings.moduleswitches) and
  1323. assigned(current_procinfo) then
  1324. include(current_procinfo.flags,pi_needs_got);
  1325. end;
  1326. function TRTTIWriter.get_rtti_label_str2ord(def:tdef;rt:trttitype):tasmsymbol;
  1327. begin
  1328. result:=current_asmdata.RefAsmSymbol(def.rtti_mangledname(rt)+'_s2o',AT_DATA);
  1329. if (cs_create_pic in current_settings.moduleswitches) and
  1330. assigned(current_procinfo) then
  1331. include(current_procinfo.flags,pi_needs_got);
  1332. end;
  1333. end.