fpc/compiler/ncgvmt.pas
sergei d54d38b4ab * Moved all code responsible for writing VMTs and interface wrappers (nobj.TVMTWriter, ncgutil.gen_intf_wrappers, ptype.write_persistent_type_info) into a new unit ncgvmt.pas.
This improves compiling speed a bit (two iterations over symtables replaced by one, code generator is created once per unit rather than once per class).
In perspective it makes possible to reduce amount of generated smartlink sections and global labels.

git-svn-id: trunk@24269 -
2013-04-19 13:31:27 +00:00

1008 lines
37 KiB
ObjectPascal

{
Copyright (c) 1998-2002 by Florian Klaempfl
Generates VMT for classes/objects and interface wrappers
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 ncgvmt;
{$i fpcdefs.inc}
interface
uses
symbase;
{ generate persistent type information like VMT, RTTI and inittables }
procedure write_persistent_type_info(st:tsymtable;is_global:boolean);
implementation
uses
cutils,cclasses,
globtype,globals,verbose,constexp,
systems,
symconst,symtype,symdef,symsym,symtable,defutil,
aasmbase,aasmtai,aasmdata,
wpobase,
nobj,
cgbase,parabase,paramgr,cgobj,cgcpu,hlcgobj,hlcgcpu,
ncgrtti;
type
pprocdeftree = ^tprocdeftree;
tprocdeftree = record
data : tprocdef;
nl : tasmlabel;
l,r : pprocdeftree;
end;
TVMTWriter=class
private
_Class : tobjectdef;
{ message tables }
root : pprocdeftree;
procedure disposeprocdeftree(p : pprocdeftree);
procedure insertmsgint(p:TObject;arg:pointer);
procedure insertmsgstr(p:TObject;arg:pointer);
procedure insertint(p : pprocdeftree;var at : pprocdeftree;var count:longint);
procedure insertstr(p : pprocdeftree;var at : pprocdeftree;var count:longint);
function RedirectToEmpty(procdef: tprocdef): boolean;
procedure writenames(list : TAsmList;p : pprocdeftree);
procedure writeintentry(list : TAsmList;p : pprocdeftree);
procedure writestrentry(list : TAsmList;p : pprocdeftree);
{$ifdef WITHDMT}
{ dmt }
procedure insertdmtentry(p:TObject;arg:pointer);
procedure writedmtindexentry(p : pprocdeftree);
procedure writedmtaddressentry(p : pprocdeftree);
{$endif}
{ published methods }
procedure do_count_published_methods(p:TObject;arg:pointer);
procedure do_gen_published_methods(p:TObject;arg:pointer);
{ virtual methods }
procedure writevirtualmethods(List:TAsmList);
{ interface tables }
function intf_get_vtbl_name(AImplIntf:TImplementedInterface): string;
procedure intf_create_vtbl(rawdata: TAsmList;AImplIntf:TImplementedInterface);
procedure intf_gen_intf_ref(rawdata: TAsmList;AImplIntf:TImplementedInterface);
function intf_write_table(list : TAsmList):TAsmLabel;
{ generates the message tables for a class }
function genstrmsgtab(list : TAsmList) : tasmlabel;
function genintmsgtab(list : TAsmList) : tasmlabel;
function genpublishedmethodstable(list : TAsmList) : tasmlabel;
function generate_field_table(list : TAsmList) : tasmlabel;
{$ifdef WITHDMT}
{ generates a DMT for _class }
function gendmt : tasmlabel;
{$endif WITHDMT}
public
constructor create(c:tobjectdef);
{ write the VMT to al_globals }
procedure writevmt;
procedure writeinterfaceids;
end;
{*****************************************************************************
TVMTWriter
*****************************************************************************}
constructor TVMTWriter.create(c:tobjectdef);
begin
inherited Create;
_Class:=c;
end;
{**************************************
Message Tables
**************************************}
procedure TVMTWriter.disposeprocdeftree(p : pprocdeftree);
begin
if assigned(p^.l) then
disposeprocdeftree(p^.l);
if assigned(p^.r) then
disposeprocdeftree(p^.r);
dispose(p);
end;
procedure TVMTWriter.insertint(p : pprocdeftree;var at : pprocdeftree;var count:longint);
begin
if at=nil then
begin
at:=p;
inc(count);
end
else
begin
if p^.data.messageinf.i<at^.data.messageinf.i then
insertint(p,at^.l,count)
else if p^.data.messageinf.i>at^.data.messageinf.i then
insertint(p,at^.r,count)
else
Message1(parser_e_duplicate_message_label,tostr(p^.data.messageinf.i));
end;
end;
procedure TVMTWriter.insertstr(p : pprocdeftree;var at : pprocdeftree;var count:longint);
var
i : integer;
begin
if at=nil then
begin
at:=p;
inc(count);
end
else
begin
i:=CompareStr(p^.data.messageinf.str^,at^.data.messageinf.str^);
if i<0 then
insertstr(p,at^.l,count)
else if i>0 then
insertstr(p,at^.r,count)
else
Message1(parser_e_duplicate_message_label,p^.data.messageinf.str^);
end;
end;
procedure TVMTWriter.insertmsgint(p:TObject;arg:pointer);
var
i : longint;
pd : Tprocdef;
pt : pprocdeftree;
begin
if tsym(p).typ<>procsym then
exit;
for i:=0 to Tprocsym(p).ProcdefList.Count-1 do
begin
pd:=tprocdef(Tprocsym(p).ProcdefList[i]);
if po_msgint in pd.procoptions then
begin
new(pt);
pt^.data:=pd;
pt^.l:=nil;
pt^.r:=nil;
insertint(pt,root,plongint(arg)^);
end;
end;
end;
procedure TVMTWriter.insertmsgstr(p:TObject;arg:pointer);
var
i : longint;
pd : Tprocdef;
pt : pprocdeftree;
begin
if tsym(p).typ<>procsym then
exit;
for i:=0 to Tprocsym(p).ProcdefList.Count-1 do
begin
pd:=tprocdef(Tprocsym(p).ProcdefList[i]);
if po_msgstr in pd.procoptions then
begin
new(pt);
pt^.data:=pd;
pt^.l:=nil;
pt^.r:=nil;
insertstr(pt,root,plongint(arg)^);
end;
end;
end;
procedure TVMTWriter.writenames(list : TAsmList;p : pprocdeftree);
var
ca : pchar;
len : byte;
begin
current_asmdata.getdatalabel(p^.nl);
if assigned(p^.l) then
writenames(list,p^.l);
list.concat(cai_align.create(const_align(sizeof(pint))));
list.concat(Tai_label.Create(p^.nl));
len:=length(p^.data.messageinf.str^);
list.concat(tai_const.create_8bit(len));
getmem(ca,len+1);
move(p^.data.messageinf.str^[1],ca^,len);
ca[len]:=#0;
list.concat(Tai_string.Create_pchar(ca,len));
if assigned(p^.r) then
writenames(list,p^.r);
end;
procedure TVMTWriter.writestrentry(list : TAsmList;p : pprocdeftree);
begin
if assigned(p^.l) then
writestrentry(list,p^.l);
{ write name label }
list.concat(cai_align.create(const_align(sizeof(pint))));
list.concat(Tai_const.Create_sym(p^.nl));
list.concat(cai_align.create(const_align(sizeof(pint))));
list.concat(Tai_const.Createname(p^.data.mangledname,0));
if assigned(p^.r) then
writestrentry(list,p^.r);
end;
function TVMTWriter.genstrmsgtab(list : TAsmList) : tasmlabel;
var
count : longint;
begin
root:=nil;
count:=0;
{ insert all message handlers into a tree, sorted by name }
_class.symtable.SymList.ForEachCall(@insertmsgstr,@count);
{ write all names }
if assigned(root) then
writenames(list,root);
{ now start writing of the message string table }
current_asmdata.getlabel(result,alt_data);
list.concat(cai_align.create(const_align(sizeof(pint))));
list.concat(Tai_label.Create(result));
list.concat(cai_align.create(const_align(sizeof(longint))));
list.concat(Tai_const.Create_32bit(count));
list.concat(cai_align.create(const_align(sizeof(pint))));
if assigned(root) then
begin
writestrentry(list,root);
disposeprocdeftree(root);
end;
end;
procedure TVMTWriter.writeintentry(list : TAsmList;p : pprocdeftree);
begin
if assigned(p^.l) then
writeintentry(list,p^.l);
{ write name label }
list.concat(cai_align.create(const_align(sizeof(longint))));
list.concat(Tai_const.Create_32bit(p^.data.messageinf.i));
list.concat(cai_align.create(const_align(sizeof(pint))));
list.concat(Tai_const.Createname(p^.data.mangledname,0));
if assigned(p^.r) then
writeintentry(list,p^.r);
end;
function TVMTWriter.genintmsgtab(list : TAsmList) : tasmlabel;
var
r : tasmlabel;
count : longint;
begin
root:=nil;
count:=0;
{ insert all message handlers into a tree, sorted by name }
_class.symtable.SymList.ForEachCall(@insertmsgint,@count);
{ now start writing of the message string table }
current_asmdata.getlabel(r,alt_data);
list.concat(cai_align.create(const_align(sizeof(pint))));
list.concat(Tai_label.Create(r));
genintmsgtab:=r;
list.concat(cai_align.create(const_align(sizeof(longint))));
list.concat(Tai_const.Create_32bit(count));
list.concat(cai_align.create(const_align(sizeof(pint))));
if assigned(root) then
begin
writeintentry(list,root);
disposeprocdeftree(root);
end;
end;
{$ifdef WITHDMT}
{**************************************
DMT
**************************************}
procedure TVMTWriter.insertdmtentry(p:TObject;arg:pointer);
var
hp : tprocdef;
pt : pprocdeftree;
begin
if tsym(p).typ=procsym then
begin
hp:=tprocsym(p).definition;
while assigned(hp) do
begin
if (po_msgint in hp.procoptions) then
begin
new(pt);
pt^.p:=hp;
pt^.l:=nil;
pt^.r:=nil;
insertint(pt,root);
end;
hp:=hp.nextoverloaded;
end;
end;
end;
procedure TVMTWriter.writedmtindexentry(p : pprocdeftree);
begin
if assigned(p^.l) then
writedmtindexentry(p^.l);
al_globals.concat(Tai_const.Create_32bit(p^.data.messageinf.i));
if assigned(p^.r) then
writedmtindexentry(p^.r);
end;
procedure TVMTWriter.writedmtaddressentry(p : pprocdeftree);
begin
if assigned(p^.l) then
writedmtaddressentry(p^.l);
al_globals.concat(Tai_const_symbol.Createname(p^.data.mangledname,0));
if assigned(p^.r) then
writedmtaddressentry(p^.r);
end;
function TVMTWriter.gendmt : tasmlabel;
var
r : tasmlabel;
begin
root:=nil;
count:=0;
gendmt:=nil;
{ insert all message handlers into a tree, sorted by number }
_class.symtable.SymList.ForEachCall(insertdmtentry);
if count>0 then
begin
current_asmdata.getdatalabel(r);
gendmt:=r;
al_globals.concat(cai_align.create(const_align(sizeof(pint))));
al_globals.concat(Tai_label.Create(r));
{ entries for caching }
al_globals.concat(Tai_const.Create_ptr(0));
al_globals.concat(Tai_const.Create_ptr(0));
al_globals.concat(Tai_const.Create_32bit(count));
if assigned(root) then
begin
writedmtindexentry(root);
writedmtaddressentry(root);
disposeprocdeftree(root);
end;
end;
end;
{$endif WITHDMT}
{**************************************
Published Methods
**************************************}
procedure TVMTWriter.do_count_published_methods(p:TObject;arg:pointer);
var
i : longint;
pd : tprocdef;
begin
if (tsym(p).typ<>procsym) then
exit;
for i:=0 to Tprocsym(p).ProcdefList.Count-1 do
begin
pd:=tprocdef(Tprocsym(p).ProcdefList[i]);
if (pd.procsym=tsym(p)) and
(pd.visibility=vis_published) then
inc(plongint(arg)^);
end;
end;
procedure TVMTWriter.do_gen_published_methods(p:TObject;arg:pointer);
var
i : longint;
l : tasmlabel;
pd : tprocdef;
lists: ^TAsmList absolute arg;
begin
if (tsym(p).typ<>procsym) then
exit;
for i:=0 to Tprocsym(p).ProcdefList.Count-1 do
begin
pd:=tprocdef(Tprocsym(p).ProcdefList[i]);
if (pd.procsym=tsym(p)) and
(pd.visibility=vis_published) then
begin
current_asmdata.getlabel(l,alt_data);
lists[1].concat(cai_align.Create(const_align(sizeof(pint))));
lists[1].concat(Tai_label.Create(l));
lists[1].concat(Tai_const.Create_8bit(length(tsym(p).realname)));
lists[1].concat(Tai_string.Create(tsym(p).realname));
lists[0].concat(Tai_const.Create_sym(l));
if po_abstractmethod in pd.procoptions then
lists[0].concat(Tai_const.Create_sym(nil))
else
lists[0].concat(Tai_const.Createname(pd.mangledname,0));
end;
end;
end;
function TVMTWriter.genpublishedmethodstable(list : TAsmList) : tasmlabel;
var
l : tasmlabel;
count : longint;
lists : array[0..1] of TAsmList;
begin
count:=0;
_class.symtable.SymList.ForEachCall(@do_count_published_methods,@count);
if count>0 then
begin
lists[0]:=list;
lists[1]:=TAsmList.Create;
current_asmdata.getlabel(l,alt_data);
list.concat(cai_align.create(const_align(sizeof(pint))));
list.concat(Tai_label.Create(l));
list.concat(Tai_const.Create_32bit(count));
_class.symtable.SymList.ForEachCall(@do_gen_published_methods,@lists);
list.concatlist(lists[1]);
lists[1].Free;
genpublishedmethodstable:=l;
end
else
genpublishedmethodstable:=nil;
end;
function TVMTWriter.generate_field_table(list : TAsmList) : tasmlabel;
var
i : longint;
sym : tsym;
fieldtable,
classtable : tasmlabel;
classindex,
fieldcount : longint;
classtablelist : TFPList;
begin
classtablelist:=TFPList.Create;
{ retrieve field info fields }
fieldcount:=0;
for i:=0 to _class.symtable.SymList.Count-1 do
begin
sym:=tsym(_class.symtable.SymList[i]);
if (sym.typ=fieldvarsym) and
(sym.visibility=vis_published) then
begin
if tfieldvarsym(sym).vardef.typ<>objectdef then
internalerror(200611032);
classindex:=classtablelist.IndexOf(tfieldvarsym(sym).vardef);
if classindex=-1 then
classtablelist.Add(tfieldvarsym(sym).vardef);
inc(fieldcount);
end;
end;
if fieldcount>0 then
begin
current_asmdata.getlabel(fieldtable,alt_data);
current_asmdata.getlabel(classtable,alt_data);
list.concat(cai_align.create(const_align(sizeof(pint))));
{ write fields }
list.concat(Tai_label.Create(fieldtable));
list.concat(Tai_const.Create_16bit(fieldcount));
if (tf_requires_proper_alignment in target_info.flags) then
list.concat(cai_align.Create(sizeof(TConstPtrUInt)));
list.concat(Tai_const.Create_sym(classtable));
for i:=0 to _class.symtable.SymList.Count-1 do
begin
sym:=tsym(_class.symtable.SymList[i]);
if (sym.typ=fieldvarsym) and
(sym.visibility=vis_published) then
begin
if (tf_requires_proper_alignment in target_info.flags) then
list.concat(cai_align.Create(sizeof(pint)));
list.concat(Tai_const.Create_pint(tfieldvarsym(sym).fieldoffset));
classindex:=classtablelist.IndexOf(tfieldvarsym(sym).vardef);
if classindex=-1 then
internalerror(200611033);
list.concat(Tai_const.Create_16bit(classindex+1));
list.concat(Tai_const.Create_8bit(length(tfieldvarsym(sym).realname)));
list.concat(Tai_string.Create(tfieldvarsym(sym).realname));
end;
end;
{ generate the class table }
list.concat(cai_align.create(const_align(sizeof(pint))));
list.concat(Tai_label.Create(classtable));
list.concat(Tai_const.Create_16bit(classtablelist.count));
if (tf_requires_proper_alignment in target_info.flags) then
list.concat(cai_align.Create(sizeof(TConstPtrUInt)));
for i:=0 to classtablelist.Count-1 do
list.concat(Tai_const.Createname(tobjectdef(classtablelist[i]).vmt_mangledname,0));
result:=fieldtable;
end
else
result:=nil;
classtablelist.free;
end;
{**************************************
Interface tables
**************************************}
function TVMTWriter.intf_get_vtbl_name(AImplIntf:TImplementedInterface): string;
begin
result:=make_mangledname('VTBL',_class.owner,_class.objname^+'_$_'+AImplIntf.IntfDef.objname^);
end;
procedure TVMTWriter.intf_create_vtbl(rawdata: TAsmList;AImplIntf:TImplementedInterface);
var
pd : tprocdef;
vtblstr,
hs : string;
i : longint;
begin
vtblstr:=intf_get_vtbl_name(AImplIntf);
rawdata.concat(cai_align.create(const_align(sizeof(pint))));
rawdata.concat(tai_symbol.createname(vtblstr,AT_DATA,0));
if assigned(AImplIntf.procdefs) then
begin
for i:=0 to AImplIntf.procdefs.count-1 do
begin
pd:=tprocdef(AImplIntf.procdefs[i]);
hs:=make_mangledname('WRPR',_class.owner,_class.objname^+'_$_'+AImplIntf.IntfDef.objname^+'_$_'+
tostr(i)+'_$_'+pd.mangledname);
{ create reference }
rawdata.concat(Tai_const.Createname(hs,0));
end;
end;
rawdata.concat(tai_symbol_end.createname(vtblstr));
end;
procedure TVMTWriter.intf_gen_intf_ref(rawdata: TAsmList;AImplIntf:TImplementedInterface);
var
pd: tprocdef;
begin
{ GUID (or nil for Corba interfaces) }
if AImplIntf.IntfDef.objecttype in [odt_interfacecom] then
rawdata.concat(Tai_const.CreateName(
make_mangledname('IID',AImplIntf.IntfDef.owner,AImplIntf.IntfDef.objname^),0))
else
rawdata.concat(Tai_const.Create_sym(nil));
{ VTable }
rawdata.concat(Tai_const.Createname(intf_get_vtbl_name(AImplIntf.VtblImplIntf),0));
{ IOffset field }
case AImplIntf.VtblImplIntf.IType of
etFieldValue, etFieldValueClass,
etStandard:
rawdata.concat(Tai_const.Create_pint(AImplIntf.VtblImplIntf.IOffset));
etStaticMethodResult, etStaticMethodClass:
rawdata.concat(Tai_const.Createname(
tprocdef(tpropertysym(AImplIntf.ImplementsGetter).propaccesslist[palt_read].procdef).mangledname,
0
));
etVirtualMethodResult, etVirtualMethodClass:
begin
pd := tprocdef(tpropertysym(AImplIntf.ImplementsGetter).propaccesslist[palt_read].procdef);
rawdata.concat(Tai_const.Create_pint(tobjectdef(pd.struct).vmtmethodoffset(pd.extnumber)));
end;
else
internalerror(200802162);
end;
{ IIDStr }
rawdata.concat(Tai_const.CreateName(
make_mangledname('IIDSTR',AImplIntf.IntfDef.owner,AImplIntf.IntfDef.objname^),0));
{ IType }
rawdata.concat(Tai_const.Create_pint(aint(AImplIntf.VtblImplIntf.IType)));
end;
function TVMTWriter.intf_write_table(list : TAsmList):TAsmLabel;
var
i : longint;
ImplIntf : TImplementedInterface;
begin
current_asmdata.getlabel(result,alt_data);
list.concat(cai_align.create(const_align(sizeof(pint))));
list.concat(Tai_label.Create(result));
list.concat(Tai_const.Create_pint(_class.ImplementedInterfaces.count));
{ Write vtbl references }
for i:=0 to _class.ImplementedInterfaces.count-1 do
begin
ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]);
intf_gen_intf_ref(list,ImplIntf);
end;
{ Write vtbls }
for i:=0 to _class.ImplementedInterfaces.count-1 do
begin
ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]);
if ImplIntf.VtblImplIntf=ImplIntf then
intf_create_vtbl(list,ImplIntf);
end;
end;
{ Write interface identifiers to the data section }
procedure TVMTWriter.writeinterfaceids;
var
i : longint;
s : string;
begin
if assigned(_class.iidguid) then
begin
s:=make_mangledname('IID',_class.owner,_class.objname^);
maybe_new_object_file(current_asmdata.asmlists[al_globals]);
new_section(current_asmdata.asmlists[al_globals],sec_rodata,s,const_align(sizeof(pint)));
current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_32bit(longint(_class.iidguid^.D1)));
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_16bit(_class.iidguid^.D2));
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_16bit(_class.iidguid^.D3));
for i:=Low(_class.iidguid^.D4) to High(_class.iidguid^.D4) do
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_8bit(_class.iidguid^.D4[i]));
end;
maybe_new_object_file(current_asmdata.asmlists[al_globals]);
s:=make_mangledname('IIDSTR',_class.owner,_class.objname^);
new_section(current_asmdata.asmlists[al_globals],sec_rodata,s,sizeof(pint));
current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_8bit(length(_class.iidstr^)));
current_asmdata.asmlists[al_globals].concat(Tai_string.Create(_class.iidstr^));
end;
function TVMTWriter.RedirectToEmpty(procdef : tprocdef) : boolean;
var
i : longint;
hp : PCGParaLocation;
begin
result:=false;
if procdef.isempty then
begin
{$ifdef x86}
paramanager.create_funcretloc_info(procdef,calleeside);
if (procdef.funcretloc[calleeside].Location^.loc=LOC_FPUREGISTER) then
exit;
{$endif x86}
procdef.init_paraloc_info(callerside);
{ we can redirect the call if no memory parameter is passed }
for i:=0 to procdef.paras.count-1 do
begin
hp:=tparavarsym(procdef.paras[i]).paraloc[callerside].Location;
while assigned(hp) do
begin
if not(hp^.Loc in [LOC_REGISTER,LOC_MMREGISTER,LOC_FPUREGISTER]) then
exit;
hp:=hp^.Next;
end;
end;
result:=true;
end;
end;
procedure TVMTWriter.writevirtualmethods(List:TAsmList);
var
vmtpd : tprocdef;
vmtentry : pvmtentry;
i : longint;
procname : string;
{$ifdef vtentry}
hs : string;
{$endif vtentry}
begin
if not assigned(_class.VMTEntries) then
exit;
for i:=0 to _class.VMTEntries.Count-1 do
begin
vmtentry:=pvmtentry(_class.vmtentries[i]);
vmtpd:=vmtentry^.procdef;
{ safety checks }
if not(po_virtualmethod in vmtpd.procoptions) then
internalerror(200611082);
if vmtpd.extnumber<>i then
internalerror(200611083);
if (po_abstractmethod in vmtpd.procoptions) then
procname:='FPC_ABSTRACTERROR'
else if (cs_opt_remove_emtpy_proc in current_settings.optimizerswitches) and RedirectToEmpty(vmtpd) then
procname:='FPC_EMPTYMETHOD'
else if not wpoinfomanager.optimized_name_for_vmt(_class,vmtpd,procname) then
procname:=vmtpd.mangledname;
List.concat(Tai_const.createname(procname,0));
{$ifdef vtentry}
hs:='VTENTRY'+'_'+_class.vmt_mangledname+'$$'+tostr(_class.vmtmethodoffset(i) div sizeof(pint));
current_asmdata.asmlists[al_globals].concat(tai_symbol.CreateName(hs,AT_DATA,0));
{$endif vtentry}
end;
end;
procedure TVMTWriter.writevmt;
var
methodnametable,intmessagetable,
strmessagetable,classnamelabel,
fieldtablelabel : tasmlabel;
hs: string;
{$ifdef WITHDMT}
dmtlabel : tasmlabel;
{$endif WITHDMT}
interfacetable : tasmlabel;
templist : TAsmList;
begin
{$ifdef WITHDMT}
dmtlabel:=gendmt;
{$endif WITHDMT}
templist:=TAsmList.Create;
{ write tables for classes, this must be done before the actual
class is written, because we need the labels defined }
if is_class(_class) then
begin
{ write class name }
current_asmdata.getlabel(classnamelabel,alt_data);
templist.concat(cai_align.create(const_align(sizeof(pint))));
templist.concat(Tai_label.Create(classnamelabel));
hs:=_class.RttiName;
templist.concat(Tai_const.Create_8bit(length(hs)));
templist.concat(Tai_string.Create(hs));
{ interface table }
if _class.ImplementedInterfaces.count>0 then
interfacetable:=intf_write_table(templist);
methodnametable:=genpublishedmethodstable(templist);
fieldtablelabel:=generate_field_table(templist);
{ generate message and dynamic tables }
if (oo_has_msgstr in _class.objectoptions) then
strmessagetable:=genstrmsgtab(templist);
if (oo_has_msgint in _class.objectoptions) then
intmessagetable:=genintmsgtab(templist);
end;
{ write debug info }
maybe_new_object_file(current_asmdata.asmlists[al_globals]);
new_section(current_asmdata.asmlists[al_globals],sec_rodata,_class.vmt_mangledname,const_align(sizeof(pint)));
current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(_class.vmt_mangledname,AT_DATA,0));
{ determine the size with symtable.datasize, because }
{ size gives back 4 for classes }
current_asmdata.asmlists[al_globals].concat(Tai_const.Create(aitconst_ptr,tObjectSymtable(_class.symtable).datasize));
current_asmdata.asmlists[al_globals].concat(Tai_const.Create(aitconst_ptr,-int64(tObjectSymtable(_class.symtable).datasize)));
{$ifdef WITHDMT}
if _class.classtype=ct_object then
begin
if assigned(dmtlabel) then
current_asmdata.asmlists[al_globals].concat(Tai_const_symbol.Create(dmtlabel)))
else
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_ptr(0));
end;
{$endif WITHDMT}
{ write pointer to parent VMT, this isn't implemented in TP }
{ but this is not used in FPC ? (PM) }
{ it's not used yet, but the delphi-operators as and is need it (FK) }
{ it is not written for parents that don't have any vmt !! }
if assigned(_class.childof) and
(oo_has_vmt in _class.childof.objectoptions) then
current_asmdata.asmlists[al_globals].concat(Tai_const.Createname(_class.childof.vmt_mangledname,0))
else
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
{ write extended info for classes, for the order see rtl/inc/objpash.inc }
if is_class(_class) then
begin
{ pointer to class name string }
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(classnamelabel));
{ pointer to dynamic table or nil }
if (oo_has_msgint in _class.objectoptions) then
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(intmessagetable))
else
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
{ pointer to method table or nil }
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(methodnametable));
{ pointer to field table }
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(fieldtablelabel));
{ pointer to type info of published section }
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(RTTIWriter.get_rtti_label(_class,fullrtti)));
{ inittable for con-/destruction }
if _class.members_need_inittable then
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(RTTIWriter.get_rtti_label(_class,initrtti)))
else
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
{ auto table }
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
{ interface table }
if _class.ImplementedInterfaces.count>0 then
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(interfacetable))
else if _class.implements_any_interfaces then
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil))
else
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(current_asmdata.RefAsmSymbol('FPC_EMPTYINTF')));
{ table for string messages }
if (oo_has_msgstr in _class.objectoptions) then
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(strmessagetable))
else
current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
end;
{ write virtual methods }
writevirtualmethods(current_asmdata.asmlists[al_globals]);
current_asmdata.asmlists[al_globals].concat(Tai_const.create(aitconst_ptr,0));
{ write the size of the VMT }
current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(_class.vmt_mangledname));
{$ifdef vtentry}
{ write vtinherit symbol to notify the linker of the class inheritance tree }
hs:='VTINHERIT'+'_'+_class.vmt_mangledname+'$$';
if assigned(_class.childof) then
hs:=hs+_class.childof.vmt_mangledname
else
hs:=hs+_class.vmt_mangledname;
current_asmdata.asmlists[al_globals].concat(tai_symbol.CreateName(hs,AT_DATA,0));
{$endif vtentry}
if is_class(_class) then
current_asmdata.asmlists[al_globals].concatlist(templist);
templist.Free;
end;
procedure gen_intf_wrapper(list:TAsmList;_class:tobjectdef);
var
i,j : longint;
tmps : string;
pd : TProcdef;
ImplIntf : TImplementedInterface;
begin
for i:=0 to _class.ImplementedInterfaces.count-1 do
begin
ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]);
if (ImplIntf=ImplIntf.VtblImplIntf) and
assigned(ImplIntf.ProcDefs) then
begin
maybe_new_object_file(list);
for j:=0 to ImplIntf.ProcDefs.Count-1 do
begin
pd:=TProcdef(ImplIntf.ProcDefs[j]);
{ we don't track method calls via interfaces yet ->
assume that every method called via an interface call
is reachable for now }
if (po_virtualmethod in pd.procoptions) and
not is_objectpascal_helper(tprocdef(pd).struct) then
tobjectdef(tprocdef(pd).struct).register_vmt_call(tprocdef(pd).extnumber);
tmps:=make_mangledname('WRPR',_class.owner,_class.objname^+'_$_'+
ImplIntf.IntfDef.objname^+'_$_'+tostr(j)+'_$_'+pd.mangledname);
{ create wrapper code }
new_section(list,sec_code,tmps,0);
hlcg.init_register_allocators;
cg.g_intf_wrapper(list,pd,tmps,ImplIntf.ioffset);
hlcg.done_register_allocators;
end;
end;
end;
end;
procedure gen_intf_wrappers(list:TAsmList;st:TSymtable);
var
i : longint;
def : tdef;
begin
for i:=0 to st.DefList.Count-1 do
begin
def:=tdef(st.DefList[i]);
{ if def can contain nested types then handle it symtable }
if def.typ in [objectdef,recorddef] then
gen_intf_wrappers(list,tabstractrecorddef(def).symtable);
if is_class(def) then
gen_intf_wrapper(list,tobjectdef(def));
end;
end;
procedure do_write_persistent_type_info(st:tsymtable;is_global:boolean);
var
i : longint;
def : tdef;
vmtwriter : TVMTWriter;
begin
{$ifdef jvm}
{ no Delphi-style RTTI }
exit;
{$endif jvm}
for i:=0 to st.DefList.Count-1 do
begin
def:=tdef(st.DefList[i]);
case def.typ of
recorddef :
do_write_persistent_type_info(trecorddef(def).symtable,is_global);
objectdef :
begin
{ Skip generics and forward defs }
if ([df_generic,df_genconstraint]*def.defoptions<>[]) or
(oo_is_forward in tobjectdef(def).objectoptions) then
continue;
do_write_persistent_type_info(tobjectdef(def).symtable,is_global);
{ Write also VMT if not done yet }
if not(ds_vmt_written in def.defstates) then
begin
vmtwriter:=TVMTWriter.create(tobjectdef(def));
if is_interface(tobjectdef(def)) then
vmtwriter.writeinterfaceids;
if (oo_has_vmt in tobjectdef(def).objectoptions) then
vmtwriter.writevmt;
vmtwriter.free;
include(def.defstates,ds_vmt_written);
end;
end;
procdef :
begin
if assigned(tprocdef(def).localst) and
(tprocdef(def).localst.symtabletype=localsymtable) then
do_write_persistent_type_info(tprocdef(def).localst,false);
if assigned(tprocdef(def).parast) then
do_write_persistent_type_info(tprocdef(def).parast,false);
end;
end;
{ generate always persistent tables for types in the interface so it can
be reused in other units and give always the same pointer location. }
{ Init }
if (
assigned(def.typesym) and
is_global and
not is_objc_class_or_protocol(def)
) or
is_managed_type(def) or
(ds_init_table_used in def.defstates) then
RTTIWriter.write_rtti(def,initrtti);
{ RTTI }
if (
assigned(def.typesym) and
is_global and
not is_objc_class_or_protocol(def)
) or
(ds_rtti_table_used in def.defstates) then
RTTIWriter.write_rtti(def,fullrtti);
end;
end;
procedure write_persistent_type_info(st:tsymtable;is_global:boolean);
begin
create_hlcodegen;
gen_intf_wrappers(current_asmdata.asmlists[al_procedures],st);
do_write_persistent_type_info(st,is_global);
destroy_hlcodegen;
end;
end.