ncgrtti.pas 62 KB

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