{ Copyright (c) 1998-2002 by Florian Klaempfl Routines for the code generation of RTTI data structures This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. **************************************************************************** } unit ncgrtti; {$i fpcdefs.inc} interface uses cclasses,constexp, aasmbase, symbase,symconst,symtype,symdef; type { TRTTIWriter } TRTTIWriter=class private function fields_count(st:tsymtable;rt:trttitype):longint; procedure fields_write_rtti(st:tsymtable;rt:trttitype); procedure fields_write_rtti_data(st:tsymtable;rt:trttitype); procedure write_rtti_extrasyms(def:Tdef;rt:Trttitype;mainrtti:Tasmsymbol); procedure published_write_rtti(st:tsymtable;rt:trttitype); function published_properties_count(st:tsymtable):longint; procedure published_properties_write_rtti_data(propnamelist:TFPHashObjectList;st:tsymtable); procedure collect_propnamelist(propnamelist:TFPHashObjectList;objdef:tobjectdef); procedure write_rtti_name(def:tdef); procedure write_rtti_data(def:tdef;rt:trttitype); procedure write_child_rtti_data(def:tdef;rt:trttitype); function ref_rtti(def:tdef;rt:trttitype):tasmsymbol; public procedure write_rtti(def:tdef;rt:trttitype); function get_rtti_label(def:tdef;rt:trttitype):tasmsymbol; function get_rtti_label_ord2str(def:tdef;rt:trttitype):tasmsymbol; function get_rtti_label_str2ord(def:tdef;rt:trttitype):tasmsymbol; end; var RTTIWriter : TRTTIWriter; implementation uses cutils, globals,globtype,verbose,systems, fmodule, symsym, aasmtai,aasmdata ; const rttidefstate : array[trttitype] of tdefstate = (ds_rtti_table_written,ds_init_table_written); type TPropNameListItem = class(TFPHashObject) propindex : longint; propowner : TSymtable; end; {*************************************************************************** TRTTIWriter ***************************************************************************} procedure TRTTIWriter.write_rtti_name(def:tdef); var hs : string; begin { name } if assigned(def.typesym) then begin hs:=ttypesym(def.typesym).realname; current_asmdata.asmlists[al_rtti].concat(Tai_string.Create(chr(length(hs))+hs)); end else current_asmdata.asmlists[al_rtti].concat(Tai_string.Create(#0)); end; function TRTTIWriter.fields_count(st:tsymtable;rt:trttitype):longint; var i : longint; sym : tsym; begin result:=0; for i:=0 to st.SymList.Count-1 do begin sym:=tsym(st.SymList[i]); if (rt=fullrtti) or ( (tsym(sym).typ=fieldvarsym) and tfieldvarsym(sym).vardef.needs_inittable ) then inc(result); end; end; procedure TRTTIWriter.fields_write_rtti_data(st:tsymtable;rt:trttitype); var i : longint; sym : tsym; begin for i:=0 to st.SymList.Count-1 do begin sym:=tsym(st.SymList[i]); if (rt=fullrtti) or ( (tsym(sym).typ=fieldvarsym) and tfieldvarsym(sym).vardef.needs_inittable ) then begin current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_sym(ref_rtti(tfieldvarsym(sym).vardef,rt))); current_asmdata.asmlists[al_rtti].concat(Tai_const.Create_32bit(tfieldvarsym(sym).fieldoffset)); end; end; end; procedure TRTTIWriter.fields_write_rtti(st:tsymtable;rt:trttitype); var i : longint; sym : tsym; begin for i:=0 to st.SymList.Count-1 do begin sym:=tsym(st.SymList[i]); if (rt=fullrtti) or ( (tsym(sym).typ=fieldvarsym) and tfieldvarsym(sym).vardef.needs_inittable ) then write_rtti(tfieldvarsym(sym).vardef,rt); end; end; procedure TRTTIWriter.published_write_rtti(st:tsymtable;rt:trttitype); var i : longint; sym : tsym; begin for i:=0 to st.SymList.Count-1 do begin sym:=tsym(st.SymList[i]); if (sp_published in tsym(sym).symoptions) then begin case tsym(sym).typ of propertysym: write_rtti(tpropertysym(sym).propdef,rt); fieldvarsym: write_rtti(tfieldvarsym(sym).vardef,rt); end; end; end; end; function TRTTIWriter.published_properties_count(st:tsymtable):longint; var i : longint; sym : tsym; begin result:=0; for i:=0 to st.SymList.Count-1 do begin sym:=tsym(st.SymList[i]); if (tsym(sym).typ=propertysym) and (sp_published in tsym(sym).symoptions) then inc(result); end; end; procedure TRTTIWriter.collect_propnamelist(propnamelist:TFPHashObjectList;objdef:tobjectdef); var i : longint; sym : tsym; pn : tpropnamelistitem; begin if assigned(objdef.childof) then collect_propnamelist(propnamelist,objdef.childof); for i:=0 to objdef.symtable.SymList.Count-1 do begin sym:=tsym(objdef.symtable.SymList[i]); if (tsym(sym).typ=propertysym) and (sp_published in tsym(sym).symoptions) then begin pn:=TPropNameListItem(propnamelist.Find(tsym(sym).name)); if not assigned(pn) then begin pn:=tpropnamelistitem.create(propnamelist,tsym(sym).name); pn.propindex:=propnamelist.count-1; pn.propowner:=tsym(sym).owner; end; end; end; end; procedure TRTTIWriter.published_properties_write_rtti_data(propnamelist:TFPHashObjectList;st:tsymtable); var i : longint; sym : tsym; proctypesinfo : byte; propnameitem : tpropnamelistitem; procedure writeaccessproc(pap:tpropaccesslisttypes; shiftvalue : byte; unsetvalue: byte); var typvalue : byte; hp : ppropaccesslistitem; address,space : longint; def : tdef; hpropsym : tpropertysym; propaccesslist : tpropaccesslist; begin hpropsym:=tpropertysym(sym); repeat propaccesslist:=hpropsym.propaccesslist[pap]; if not propaccesslist.empty then break; hpropsym:=hpropsym.overridenpropsym; until not assigned(hpropsym); if not(assigned(propaccesslist) and assigned(propaccesslist.firstsym)) then begin current_asmdata.asmlists[al_rtti].concat(Tai_const.create(aitconst_ptr,unsetvalue)); typvalue:=3; end else if propaccesslist.firstsym^.sym.typ=fieldvarsym then begin address:=0; hp:=propaccesslist.firstsym; def:=nil; while assigned(hp) do begin case hp^.sltype of sl_load : begin def:=tfieldvarsym(hp^.sym).vardef; inc(address,tfieldvarsym(hp^.sym).fieldoffset); end; sl_subscript : begin if not(assigned(def) and (def.typ=recorddef)) then internalerror(200402171); inc(address,tfieldvarsym(hp^.sym).fieldoffset); def:=tfieldvarsym(hp^.sym).vardef; end; sl_vec : begin if not(assigned(def) and (def.typ=arraydef)) then internalerror(200402172); def:=tarraydef(def).elementdef; {Hp.value is a Tconstexprint, which can be rather large, sanity check for longint overflow.} space:=(high(address)-address) div def.size; if int64(space)=sym_alloc then begin reallocmem(syms,2*sym_alloc*sizeof(Tenumsym)); reallocmem(offsets,2*sym_alloc*sizeof(longint)); sym_alloc:=sym_alloc*2; end; syms[sym_count]:=t; offsets[sym_count]:=st; inc(sym_count); st:=st+length(t.realname)+1; t:=t.nextenum; end; {Sort the syms by enum value} if sym_count>=2 then begin p:=1; while 2*p0 do begin for h:=p to sym_count-1 do begin i:=h; t:=syms[i]; o:=offsets[i]; repeat if syms[i-p].value<=t.value then break; syms[i]:=syms[i-p]; offsets[i]:=offsets[i-p]; dec(i,p); until i0 then begin i:=1; r:=0; h:=syms[0].value; {Next expected enum value is min.} while isym_count then mode:=search; {Don't waste more than 50% space.} end; {Calculate start of string table.} st:=1; if assigned(def.typesym) then inc(st,length(def.typesym.realname)+1) else inc(st); if (tf_requires_proper_alignment in target_info.flags) then st:=align(st,sizeof(Tconstptruint)); inc(st); if (tf_requires_proper_alignment in target_info.flags) then st:=align(st,sizeof(Tconstptruint)); inc(st,8+sizeof(pint)); { write rtti data } with current_asmdata do begin rttilab:=defineasmsymbol(Tstoreddef(def).rtti_mangledname(rt)+'_o2s',AB_GLOBAL,AT_DATA); maybe_new_object_file(asmlists[al_rtti]); new_section(asmlists[al_rtti],sec_rodata,rttilab.name,const_align(sizeof(pint))); asmlists[al_rtti].concat(Tai_symbol.create_global(rttilab,0)); asmlists[al_rtti].concat(Tai_const.create_32bit(longint(mode))); if mode=lookup then begin o:=syms[0].value; {Start with min value.} for i:=0 to sym_count-1 do begin while o=sym_alloc then begin reallocmem(syms,2*sym_alloc*sizeof(Tenumsym)); reallocmem(offsets,2*sym_alloc*sizeof(longint)); sym_alloc:=sym_alloc*2; end; syms[sym_count]:=t; offsets[sym_count]:=st; inc(sym_count); st:=st+length(t.realname)+1; t:=t.nextenum; end; {Sort the syms by enum name} if sym_count>=2 then begin p:=1; while 2*p0 do begin for h:=p to sym_count-1 do begin i:=h; t:=syms[i]; o:=offsets[i]; repeat if syms[i-p].name<=t.name then break; syms[i]:=syms[i-p]; offsets[i]:=offsets[i-p]; dec(i,p); until i