fpc/compiler/symtype.pas
2003-11-10 22:02:52 +00:00

1047 lines
30 KiB
ObjectPascal

{
$Id$
Copyright (c) 1998-2002 by Florian Klaempfl, Pierre Muller
This unit handles the symbol tables
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 symtype;
{$i fpcdefs.inc}
interface
uses
{ common }
cutils,
{$ifdef MEMDEBUG}
cclasses,
{$endif MEMDEBUG}
{ global }
globtype,globals,
{ symtable }
symconst,symbase,
{ aasm }
aasmbase
;
type
{************************************************
Required Forwards
************************************************}
tsym = class;
{************************************************
TRef
************************************************}
tref = class
nextref : tref;
posinfo : tfileposinfo;
moduleindex : longint;
is_written : boolean;
constructor create(ref:tref;pos:pfileposinfo);
procedure freechain;
destructor destroy;override;
end;
{************************************************
TDef
************************************************}
tgetsymtable = (gs_none,gs_record,gs_local,gs_para);
tdef = class(tdefentry)
typesym : tsym; { which type the definition was generated this def }
defoptions : tdefoptions;
constructor create;
procedure buildderef;virtual;abstract;
procedure buildderefimpl;virtual;abstract;
procedure deref;virtual;abstract;
procedure derefimpl;virtual;abstract;
function typename:string;
function gettypename:string;virtual;
function mangledparaname:string;
function getmangledparaname:string;virtual;abstract;
function size:longint;virtual;abstract;
function alignment:longint;virtual;abstract;
function getparentdef:tdef;virtual;
function getsymtable(t:tgetsymtable):tsymtable;virtual;
function is_publishable:boolean;virtual;abstract;
function needs_inittable:boolean;virtual;abstract;
end;
{************************************************
TSym
************************************************}
{ this object is the base for all symbol objects }
tsym = class(tsymentry)
_realname : pstring;
fileinfo : tfileposinfo;
symoptions : tsymoptions;
constructor create(const n : string);
destructor destroy;override;
function realname:string;
procedure buildderef;virtual;abstract;
procedure buildderefimpl;virtual;abstract;
procedure deref;virtual;abstract;
procedure derefimpl;virtual;abstract;
function gettypedef:tdef;virtual;
end;
{************************************************
TDeref
************************************************}
tderef = object
dataidx : longint;
procedure reset;
procedure build(s:tsymtableentry);
function resolve:tsymtableentry;
end;
{************************************************
TType
************************************************}
ttype = object
def : tdef;
sym : tsym;
deref : tderef;
procedure reset;
procedure setdef(p:tdef);
procedure setsym(p:tsym);
procedure resolve;
procedure buildderef;
end;
{************************************************
TSymList
************************************************}
psymlistitem = ^tsymlistitem;
tsymlistitem = record
sltype : tsltype;
next : psymlistitem;
case byte of
0 : (sym : tsym; symderef : tderef);
1 : (value : longint);
2 : (tt : ttype);
end;
tsymlist = class
procdef : tdef;
procdefderef : tderef;
firstsym,
lastsym : psymlistitem;
constructor create;
destructor destroy;override;
function empty:boolean;
procedure addsym(slt:tsltype;p:tsym);
procedure addsymderef(slt:tsltype;const d:tderef);
procedure addconst(slt:tsltype;v:longint);
procedure addtype(slt:tsltype;const tt:ttype);
procedure clear;
function getcopy:tsymlist;
procedure resolve;
procedure buildderef;
end;
{$ifdef MEMDEBUG}
var
membrowser,
memrealnames,
memmanglednames,
memprocpara,
memprocparast,
memproclocalst,
memprocnodetree : tmemdebug;
{$endif MEMDEBUG}
implementation
uses
verbose,
fmodule;
{****************************************************************************
Tdef
****************************************************************************}
constructor tdef.create;
begin
inherited create;
deftype:=abstractdef;
owner := nil;
typesym := nil;
defoptions:=[];
end;
function tdef.typename:string;
begin
if assigned(typesym) and
not(deftype in [procvardef,procdef]) and
assigned(typesym._realname) and
(typesym._realname^[1]<>'$') then
typename:=typesym._realname^
else
typename:=gettypename;
end;
function tdef.gettypename : string;
begin
gettypename:='<unknown type>'
end;
function tdef.mangledparaname:string;
begin
if assigned(typesym) then
mangledparaname:=typesym.name
else
mangledparaname:=getmangledparaname;
end;
function tdef.getparentdef:tdef;
begin
result:=nil;
end;
function tdef.getsymtable(t:tgetsymtable):tsymtable;
begin
getsymtable:=nil;
end;
{****************************************************************************
TSYM (base for all symtypes)
****************************************************************************}
constructor tsym.create(const n : string);
begin
if n[1]='$' then
inherited createname(copy(n,2,255))
else
inherited createname(upper(n));
_realname:=stringdup(n);
typ:=abstractsym;
symoptions:=[];
end;
destructor tsym.destroy;
begin
{$ifdef MEMDEBUG}
memrealnames.start;
{$endif MEMDEBUG}
stringdispose(_realname);
{$ifdef MEMDEBUG}
memrealnames.stop;
{$endif MEMDEBUG}
inherited destroy;
end;
function tsym.realname : string;
begin
if assigned(_realname) then
realname:=_realname^
else
realname:=name;
end;
function tsym.gettypedef:tdef;
begin
gettypedef:=nil;
end;
{****************************************************************************
TRef
****************************************************************************}
constructor tref.create(ref :tref;pos : pfileposinfo);
begin
nextref:=nil;
if pos<>nil then
posinfo:=pos^;
if assigned(current_module) then
moduleindex:=current_module.unit_index;
if assigned(ref) then
ref.nextref:=self;
is_written:=false;
end;
procedure tref.freechain;
var
p,q : tref;
begin
p:=nextref;
nextref:=nil;
while assigned(p) do
begin
q:=p.nextref;
p.free;
p:=q;
end;
end;
destructor tref.destroy;
begin
nextref:=nil;
end;
{****************************************************************************
TType
****************************************************************************}
procedure ttype.reset;
begin
def:=nil;
sym:=nil;
end;
procedure ttype.setdef(p:tdef);
begin
def:=p;
sym:=nil;
end;
procedure ttype.setsym(p:tsym);
begin
sym:=p;
def:=p.gettypedef;
if not assigned(def) then
internalerror(1234005);
end;
procedure ttype.resolve;
var
p : tsymtableentry;
begin
p:=deref.resolve;
if assigned(p) then
begin
if p is tsym then
begin
setsym(tsym(p));
if not assigned(def) then
internalerror(200212272);
end
else
begin
setdef(tdef(p));
end;
end
else
reset;
end;
procedure ttype.buildderef;
begin
{ Write symbol references when the symbol is a redefine,
but don't write symbol references for the current unit
and for the system unit }
if assigned(sym) and
(
(sym<>def.typesym) or
((sym.owner.unitid<>0) and
(sym.owner.unitid<>1))
) then
deref.build(sym)
else
deref.build(def);
end;
{****************************************************************************
TSymList
****************************************************************************}
constructor tsymlist.create;
begin
procdef:=nil; { needed for procedures }
firstsym:=nil;
lastsym:=nil;
end;
destructor tsymlist.destroy;
begin
clear;
end;
function tsymlist.empty:boolean;
begin
empty:=(firstsym=nil);
end;
procedure tsymlist.clear;
var
hp : psymlistitem;
begin
while assigned(firstsym) do
begin
hp:=firstsym;
firstsym:=firstsym^.next;
dispose(hp);
end;
firstsym:=nil;
lastsym:=nil;
procdef:=nil;
end;
procedure tsymlist.addsym(slt:tsltype;p:tsym);
var
hp : psymlistitem;
begin
if not assigned(p) then
internalerror(200110203);
new(hp);
fillchar(hp^,sizeof(tsymlistitem),0);
hp^.sltype:=slt;
hp^.sym:=p;
hp^.symderef.reset;
if assigned(lastsym) then
lastsym^.next:=hp
else
firstsym:=hp;
lastsym:=hp;
end;
procedure tsymlist.addsymderef(slt:tsltype;const d:tderef);
var
hp : psymlistitem;
begin
new(hp);
fillchar(hp^,sizeof(tsymlistitem),0);
hp^.sltype:=slt;
hp^.symderef:=d;
if assigned(lastsym) then
lastsym^.next:=hp
else
firstsym:=hp;
lastsym:=hp;
end;
procedure tsymlist.addconst(slt:tsltype;v:longint);
var
hp : psymlistitem;
begin
new(hp);
fillchar(hp^,sizeof(tsymlistitem),0);
hp^.sltype:=slt;
hp^.value:=v;
if assigned(lastsym) then
lastsym^.next:=hp
else
firstsym:=hp;
lastsym:=hp;
end;
procedure tsymlist.addtype(slt:tsltype;const tt:ttype);
var
hp : psymlistitem;
begin
new(hp);
fillchar(hp^,sizeof(tsymlistitem),0);
hp^.sltype:=slt;
hp^.tt:=tt;
if assigned(lastsym) then
lastsym^.next:=hp
else
firstsym:=hp;
lastsym:=hp;
end;
function tsymlist.getcopy:tsymlist;
var
hp : tsymlist;
hp2 : psymlistitem;
hpn : psymlistitem;
begin
hp:=tsymlist.create;
hp.procdef:=procdef;
hp2:=firstsym;
while assigned(hp2) do
begin
new(hpn);
hpn^:=hp2^;
hpn^.next:=nil;
if assigned(hp.lastsym) then
hp.lastsym^.next:=hpn
else
hp.firstsym:=hpn;
hp.lastsym:=hpn;
hp2:=hp2^.next;
end;
getcopy:=hp;
end;
procedure tsymlist.resolve;
var
hp : psymlistitem;
begin
procdef:=tdef(procdefderef.resolve);
hp:=firstsym;
while assigned(hp) do
begin
case hp^.sltype of
sl_call,
sl_load,
sl_subscript :
hp^.sym:=tsym(hp^.symderef.resolve);
sl_typeconv :
hp^.tt.resolve;
sl_vec :
;
else
internalerror(200110205);
end;
hp:=hp^.next;
end;
end;
procedure tsymlist.buildderef;
var
hp : psymlistitem;
begin
procdefderef.build(procdef);
hp:=firstsym;
while assigned(hp) do
begin
case hp^.sltype of
sl_call,
sl_load,
sl_subscript :
hp^.symderef.build(hp^.sym);
sl_typeconv :
hp^.tt.buildderef;
sl_vec :
;
else
internalerror(200110205);
end;
hp:=hp^.next;
end;
end;
{****************************************************************************
Tderef
****************************************************************************}
procedure tderef.reset;
begin
dataidx:=-1;
end;
procedure tderef.build(s:tsymtableentry);
var
len : byte;
data : array[0..255] of byte;
function is_child(currdef,ownerdef:tdef):boolean;
begin
while assigned(currdef) and
(currdef<>ownerdef) do
currdef:=currdef.getparentdef;
result:=assigned(currdef);
end;
procedure addowner(s:tsymtableentry);
begin
if not assigned(s.owner) then
internalerror(200306063);
case s.owner.symtabletype of
globalsymtable :
begin
if s.owner.unitid=0 then
begin
data[len]:=ord(deref_aktglobal);
inc(len);
end
else
begin
{ check if the unit is available in the uses
clause, else it's an error }
if s.owner.unitid=$ffff then
internalerror(200306063);
data[len]:=ord(deref_unit);
data[len+1]:=s.owner.unitid shr 8;
data[len+2]:=s.owner.unitid and $ff;
inc(len,3);
end;
end;
staticsymtable :
begin
{ only references to the current static symtable are allowed }
if s.owner<>aktstaticsymtable then
internalerror(200306233);
data[len]:=ord(deref_aktstatic);
inc(len);
end;
localsymtable :
begin
addowner(s.owner.defowner);
data[len]:=ord(deref_def);
data[len+1]:=s.owner.defowner.indexnr shr 8;
data[len+2]:=s.owner.defowner.indexnr and $ff;
data[len+3]:=ord(deref_local);
inc(len,4);
end;
parasymtable :
begin
addowner(s.owner.defowner);
data[len]:=ord(deref_def);
data[len+1]:=s.owner.defowner.indexnr shr 8;
data[len+2]:=s.owner.defowner.indexnr and $ff;
data[len+3]:=ord(deref_para);
inc(len,4);
end;
objectsymtable,
recordsymtable :
begin
addowner(s.owner.defowner);
data[len]:=ord(deref_def);
data[len+1]:=s.owner.defowner.indexnr shr 8;
data[len+2]:=s.owner.defowner.indexnr and $ff;
data[len+3]:=ord(deref_record);
inc(len,4);
end;
else
internalerror(200306065);
end;
if len>252 then
internalerror(200306062);
end;
procedure addparentobject(currdef,ownerdef:tdef);
var
nextdef : tdef;
begin
if not assigned(currdef) then
internalerror(200306185);
{ Already handled by derefaktrecordindex }
if currdef=ownerdef then
internalerror(200306188);
{ Generate a direct reference to the top parent
class available in the current unit, this is required because
the parent class is maybe not resolved yet and therefor
has the childof value not available yet }
while (currdef<>ownerdef) do
begin
nextdef:=currdef.getparentdef;
{ objects are only allowed in globalsymtable,staticsymtable this check is
needed because we need the unitid }
if not(nextdef.owner.symtabletype in [globalsymtable,staticsymtable]) then
internalerror(200306187);
{ Next parent is in a different unit, then stop }
if nextdef.owner.unitid<>0 then
break;
currdef:=nextdef;
end;
{ Add reference where to start the parent lookup }
if currdef=aktrecordsymtable.defowner then
begin
data[len]:=ord(deref_aktrecord);
inc(len);
end
else
begin
if currdef.owner.symtabletype=globalsymtable then
data[len]:=ord(deref_aktglobal)
else
data[len]:=ord(deref_aktstatic);
data[len+1]:=ord(deref_def);
data[len+2]:=currdef.indexnr shr 8;
data[len+3]:=currdef.indexnr and $ff;
data[len+4]:=ord(deref_record);
inc(len,5);
end;
{ When the current found parent in this module is not the owner we
add derefs for the parent classes not available in this unit }
while (currdef<>ownerdef) do
begin
data[len]:=ord(deref_parent_object);
inc(len);
currdef:=currdef.getparentdef;
{ It should be valid as it is checked by is_child }
if not assigned(currdef) then
internalerror(200306186);
end;
end;
begin
{ skip length byte }
len:=1;
if assigned(s) then
begin
{ Static symtable of current unit ? }
if (s.owner.symtabletype=staticsymtable) and
(s.owner.unitid=0) then
begin
data[len]:=ord(deref_aktstatic);
inc(len);
end
{ Global symtable of current unit ? }
else if (s.owner.symtabletype=globalsymtable) and
(s.owner.unitid=0) then
begin
data[len]:=ord(deref_aktglobal);
inc(len);
end
{ Current record/object symtable ? }
else if (s.owner=aktrecordsymtable) then
begin
data[len]:=ord(deref_aktrecord);
inc(len);
end
{ Current local symtable ? }
else if (s.owner=aktlocalsymtable) then
begin
data[len]:=ord(deref_aktlocal);
inc(len);
end
{ Current para symtable ? }
else if (s.owner=aktparasymtable) then
begin
data[len]:=ord(deref_aktpara);
inc(len);
end
{ Parent class? }
else if assigned(aktrecordsymtable) and
(aktrecordsymtable.symtabletype=objectsymtable) and
(s.owner.symtabletype=objectsymtable) and
is_child(tdef(aktrecordsymtable.defowner),tdef(s.owner.defowner)) then
begin
addparentobject(tdef(aktrecordsymtable.defowner),tdef(s.owner.defowner));
end
else
{ Default, start by building from unit symtable }
begin
addowner(s);
end;
{ Add index of the symbol/def }
if s is tsym then
data[len]:=ord(deref_sym)
else
data[len]:=ord(deref_def);
data[len+1]:=s.indexnr shr 8;
data[len+2]:=s.indexnr and $ff;
inc(len,3);
end
else
begin
{ nil pointer }
data[len]:=0;
inc(len);
end;
{ store data length in first byte }
data[0]:=len-1;
{ store index and write to derefdata }
dataidx:=current_module.derefdata.size;
current_module.derefdata.write(data,len);
end;
function tderef.resolve:tsymtableentry;
var
pd : tdef;
pm : tmodule;
typ : tdereftype;
st : tsymtable;
idx : word;
i : longint;
len : byte;
data : array[0..255] of byte;
begin
result:=nil;
{ not initialized }
if dataidx=-1 then
internalerror(200306067);
{ read data }
current_module.derefdata.seek(dataidx);
if current_module.derefdata.read(len,1)<>1 then
internalerror(200310221);
if len>0 then
begin
if current_module.derefdata.read(data,len)<>len then
internalerror(200310222);
end;
{ process data }
st:=nil;
i:=0;
while (i<len) do
begin
typ:=tdereftype(data[i]);
inc(i);
case typ of
deref_nil :
begin
result:=nil;
{ Only allowed when no other deref is available }
if len<>1 then
internalerror(200306232);
end;
deref_sym :
begin
if not assigned(st) then
internalerror(200309141);
idx:=(data[i] shl 8) or data[i+1];
inc(i,2);
result:=st.getsymnr(idx);
end;
deref_def :
begin
if not assigned(st) then
internalerror(200309142);
idx:=(data[i] shl 8) or data[i+1];
inc(i,2);
result:=st.getdefnr(idx);
end;
deref_aktrecord :
st:=aktrecordsymtable;
deref_aktstatic :
st:=aktstaticsymtable;
deref_aktglobal :
st:=aktglobalsymtable;
deref_aktlocal :
st:=aktlocalsymtable;
deref_aktpara :
st:=aktparasymtable;
deref_unit :
begin
idx:=(data[i] shl 8) or data[i+1];
inc(i,2);
if idx>current_module.mapsize then
internalerror(200306231);
pm:=current_module.map[idx].u;
if not assigned(pm) then
internalerror(200212273);
st:=pm.globalsymtable;
end;
deref_local :
begin
if not assigned(result) then
internalerror(200306069);
st:=tdef(result).getsymtable(gs_local);
result:=nil;
if not assigned(st) then
internalerror(200212275);
end;
deref_para :
begin
if not assigned(result) then
internalerror(2003060610);
st:=tdef(result).getsymtable(gs_para);
result:=nil;
if not assigned(st) then
internalerror(200212276);
end;
deref_record :
begin
if not assigned(result) then
internalerror(200306068);
st:=tdef(result).getsymtable(gs_record);
result:=nil;
if not assigned(st) then
internalerror(200212274);
end;
deref_parent_object :
begin
{ load current object symtable if no
symtable is available yet }
if st=nil then
begin
st:=aktrecordsymtable;
if not assigned(st) then
internalerror(200306068);
end;
if st.symtabletype<>objectsymtable then
internalerror(200306189);
pd:=tdef(st.defowner).getparentdef;
if not assigned(pd) then
internalerror(200306184);
st:=pd.getsymtable(gs_record);
if not assigned(st) then
internalerror(200212274);
end;
else
internalerror(200212277);
end;
end;
end;
{$ifdef MEMDEBUG}
initialization
membrowser:=TMemDebug.create('BrowserRefs');
membrowser.stop;
memrealnames:=TMemDebug.create('Realnames');
memrealnames.stop;
memmanglednames:=TMemDebug.create('Manglednames');
memmanglednames.stop;
memprocpara:=TMemDebug.create('ProcPara');
memprocpara.stop;
memprocparast:=TMemDebug.create('ProcParaSt');
memprocparast.stop;
memproclocalst:=TMemDebug.create('ProcLocalSt');
memproclocalst.stop;
memprocnodetree:=TMemDebug.create('ProcNodeTree');
memprocnodetree.stop;
finalization
membrowser.free;
memrealnames.free;
memmanglednames.free;
memprocpara.free;
memprocparast.free;
memproclocalst.free;
memprocnodetree.free;
{$endif MEMDEBUG}
end.
{
$Log$
Revision 1.34 2003-11-10 22:02:52 peter
* cross unit inlining fixed
Revision 1.33 2003/10/28 15:36:01 peter
* absolute to object field supported, fixes tb0458
Revision 1.32 2003/10/23 14:44:07 peter
* splitted buildderef and buildderefimpl to fix interface crc
calculation
Revision 1.31 2003/10/22 20:40:00 peter
* write derefdata in a separate ppu entry
Revision 1.30 2003/10/22 15:22:33 peter
* fixed unitsym-globalsymtable relation so the uses of a unit
is counted correctly
Revision 1.29 2003/10/17 14:38:32 peter
* 64k registers supported
* fixed some memory leaks
Revision 1.28 2003/10/07 16:06:30 peter
* tsymlist.def renamed to tsymlist.procdef
* tsymlist.procdef is now only used to store the procdef
Revision 1.27 2003/09/14 12:58:29 peter
* give IE when st is not assigned in deref
Revision 1.26 2003/06/25 18:31:23 peter
* sym,def resolving partly rewritten to support also parent objects
not directly available through the uses clause
Revision 1.25 2003/06/07 20:26:32 peter
* re-resolving added instead of reloading from ppu
* tderef object added to store deref info for resolving
Revision 1.24 2002/12/29 18:26:31 peter
* also use gettypename for procdef always
Revision 1.23 2002/12/29 14:57:50 peter
* unit loading changed to first register units and load them
afterwards. This is needed to support uses xxx in yyy correctly
* unit dependency check fixed
Revision 1.22 2002/09/05 19:29:46 peter
* memdebug enhancements
Revision 1.21 2002/08/18 20:06:28 peter
* inlining is now also allowed in interface
* renamed write/load to ppuwrite/ppuload
* tnode storing in ppu
* nld,ncon,nbas are already updated for storing in ppu
Revision 1.20 2002/08/11 13:24:16 peter
* saving of asmsymbols in ppu supported
* asmsymbollist global is removed and moved into a new class
tasmlibrarydata that will hold the info of a .a file which
corresponds with a single module. Added librarydata to tmodule
to keep the library info stored for the module. In the future the
objectfiles will also be stored to the tasmlibrarydata class
* all getlabel/newasmsymbol and friends are moved to the new class
Revision 1.19 2002/07/01 18:46:29 peter
* internal linker
* reorganized aasm layer
Revision 1.18 2002/05/18 13:34:21 peter
* readded missing revisions
Revision 1.17 2002/05/16 19:46:45 carl
+ defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
+ try to fix temp allocation (still in ifdef)
+ generic constructor calls
+ start of tassembler / tmodulebase class cleanup
Revision 1.15 2002/05/12 16:53:15 peter
* moved entry and exitcode to ncgutil and cgobj
* foreach gets extra argument for passing local data to the
iterator function
* -CR checks also class typecasts at runtime by changing them
into as
* fixed compiler to cycle with the -CR option
* fixed stabs with elf writer, finally the global variables can
be watched
* removed a lot of routines from cga unit and replaced them by
calls to cgobj
* u32bit-s32bit updates for and,or,xor nodes. When one element is
u32bit then the other is typecasted also to u32bit without giving
a rangecheck warning/error.
* fixed pascal calling method with reversing also the high tree in
the parast, detected by tcalcst3 test
Revision 1.14 2002/04/19 15:46:04 peter
* mangledname rewrite, tprocdef.mangledname is now created dynamicly
in most cases and not written to the ppu
* add mangeledname_prefix() routine to generate the prefix of
manglednames depending on the current procedure, object and module
* removed static procprefix since the mangledname is now build only
on demand from tprocdef.mangledname
}