ncgrtti.pas 54 KB

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