mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-05-29 22:22:38 +02:00

+ use {$bitpacking on/+} to change the meaning of "packed" into "bitpacked" for arrays. This is the default for MacPas. You can also define individual arrays as "bitpacked", but this is not encouraged since this keyword is not known by other compilers and therefore makes your code unportable. + pack(unpackedarray,index,packedarray) to pack length(packedarray) elements starting at unpackedarray[index] into packedarray. + unpack(packedarray,unpackedarray,index) to unpack packedarray into unpackedarray, with the first element being stored at unpackedarray[index] * todo: * "open packed arrays" and rtti for packed arrays are not yet supported * gdb does not properly support bitpacked arrays git-svn-id: trunk@4449 -
1460 lines
40 KiB
ObjectPascal
1460 lines
40 KiB
ObjectPascal
{
|
|
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,ppu,cpuinfo
|
|
;
|
|
|
|
type
|
|
{************************************************
|
|
Required Forwards
|
|
************************************************}
|
|
|
|
tsym = class;
|
|
Tcompilerppufile=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 }
|
|
{ maybe it's useful to merge the dwarf and stabs debugging info with some hacking }
|
|
{ dwarf debugging }
|
|
dwarf_lab : tasmlabel;
|
|
{ stabs debugging }
|
|
stab_number : word;
|
|
dbg_state : tdefdbgstatus;
|
|
defoptions : tdefoptions;
|
|
constructor create(dt:tdeftype);
|
|
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;
|
|
function size:aint;virtual;abstract;
|
|
function packedbitsize:aint;virtual;
|
|
function alignment:shortint;virtual;abstract;
|
|
function getvartype: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;
|
|
function is_related(def:tdef):boolean;virtual;
|
|
end;
|
|
|
|
{************************************************
|
|
TSym
|
|
************************************************}
|
|
|
|
{ this object is the base for all symbol objects }
|
|
tsym = class(tsymentry)
|
|
protected
|
|
public
|
|
_realname : pstring;
|
|
fileinfo : tfileposinfo;
|
|
symoptions : tsymoptions;
|
|
refs : longint;
|
|
lastref,
|
|
defref,
|
|
lastwritten : tref;
|
|
refcount : longint;
|
|
isstabwritten : boolean;
|
|
constructor create(st:tsymtyp;const n : string);
|
|
destructor destroy;override;
|
|
function realname:string;
|
|
function mangledname:string; virtual;
|
|
procedure buildderef;virtual;
|
|
procedure deref;virtual;
|
|
procedure derefimpl; virtual;
|
|
function gettypedef:tdef;virtual;
|
|
procedure load_references(ppufile:tcompilerppufile;locals:boolean);virtual;
|
|
function write_references(ppufile:tcompilerppufile;locals:boolean):boolean;virtual;
|
|
{ currobjdef is the object def to assume, this is necessary for protected and
|
|
private,
|
|
context is the object def we're really in, this is for the strict stuff
|
|
}
|
|
function is_visible_for_object(currobjdef:tdef;context : tdef):boolean;virtual;
|
|
end;
|
|
|
|
tsymarr = array[0..maxlongint div sizeof(pointer)-1] of tsym;
|
|
psymarr = ^tsymarr;
|
|
|
|
{************************************************
|
|
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 : TConstExprInt; valuett: ttype);
|
|
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:TConstExprInt;const tt:ttype);
|
|
procedure addtype(slt:tsltype;const tt:ttype);
|
|
procedure clear;
|
|
function getcopy:tsymlist;
|
|
procedure resolve;
|
|
procedure buildderef;
|
|
end;
|
|
|
|
{************************************************
|
|
Tcompilerppufile
|
|
************************************************}
|
|
tcompilerppufile=class(tppufile)
|
|
public
|
|
procedure checkerror;
|
|
procedure getguid(var g: tguid);
|
|
function getexprint:tconstexprint;
|
|
function getptruint:TConstPtrUInt;
|
|
procedure getposinfo(var p:tfileposinfo);
|
|
procedure getderef(var d:tderef);
|
|
function getsymlist:tsymlist;
|
|
procedure gettype(var t:ttype);
|
|
function getasmsymbol:tasmsymbol;
|
|
procedure putguid(const g: tguid);
|
|
procedure putexprint(v:tconstexprint);
|
|
procedure PutPtrUInt(v:TConstPtrUInt);
|
|
procedure putposinfo(const p:tfileposinfo);
|
|
procedure putderef(const d:tderef);
|
|
procedure putsymlist(p:tsymlist);
|
|
procedure puttype(const t:ttype);
|
|
procedure putasmsymbol(s:tasmsymbol);
|
|
end;
|
|
|
|
{$ifdef MEMDEBUG}
|
|
var
|
|
membrowser,
|
|
memrealnames,
|
|
memmanglednames,
|
|
memprocpara,
|
|
memprocparast,
|
|
memproclocalst,
|
|
memprocnodetree : tmemdebug;
|
|
{$endif MEMDEBUG}
|
|
|
|
const
|
|
current_object_option : tsymoptions = [sp_public];
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
verbose,
|
|
fmodule
|
|
;
|
|
|
|
|
|
{****************************************************************************
|
|
Tdef
|
|
****************************************************************************}
|
|
|
|
constructor tdef.create(dt:tdeftype);
|
|
begin
|
|
inherited create;
|
|
deftype:=dt;
|
|
owner := nil;
|
|
typesym := nil;
|
|
defoptions:=[];
|
|
dbg_state:=dbg_state_unused;
|
|
stab_number:=0;
|
|
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.getmangledparaname:string;
|
|
begin
|
|
result:='<unknown type>';
|
|
end;
|
|
|
|
|
|
function tdef.getparentdef:tdef;
|
|
begin
|
|
result:=nil;
|
|
end;
|
|
|
|
|
|
function tdef.getsymtable(t:tgetsymtable):tsymtable;
|
|
begin
|
|
result:=nil;
|
|
end;
|
|
|
|
|
|
function tdef.is_related(def:tdef):boolean;
|
|
begin
|
|
result:=false;
|
|
end;
|
|
|
|
|
|
function tdef.packedbitsize:aint;
|
|
begin
|
|
result:=size * 8;
|
|
end;
|
|
|
|
|
|
{****************************************************************************
|
|
TSYM (base for all symtypes)
|
|
****************************************************************************}
|
|
|
|
constructor tsym.create(st:tsymtyp;const n : string);
|
|
begin
|
|
if n[1]='$' then
|
|
inherited createname(copy(n,2,255))
|
|
else
|
|
inherited createname(upper(n));
|
|
_realname:=stringdup(n);
|
|
typ:=st;
|
|
symoptions:=[];
|
|
defref:=nil;
|
|
refs:=0;
|
|
lastwritten:=nil;
|
|
refcount:=0;
|
|
fileinfo:=akttokenpos;
|
|
if (cs_browser in aktmoduleswitches) and make_ref then
|
|
begin
|
|
defref:=tref.create(defref,@akttokenpos);
|
|
inc(refcount);
|
|
end;
|
|
lastref:=defref;
|
|
isstabwritten := false;
|
|
symoptions:=current_object_option;
|
|
end;
|
|
|
|
|
|
destructor tsym.destroy;
|
|
begin
|
|
{$ifdef MEMDEBUG}
|
|
memrealnames.start;
|
|
{$endif MEMDEBUG}
|
|
stringdispose(_realname);
|
|
{$ifdef MEMDEBUG}
|
|
memrealnames.stop;
|
|
{$endif MEMDEBUG}
|
|
inherited destroy;
|
|
end;
|
|
|
|
|
|
procedure Tsym.buildderef;
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure Tsym.deref;
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure Tsym.derefimpl;
|
|
begin
|
|
end;
|
|
|
|
|
|
function tsym.realname : string;
|
|
begin
|
|
if assigned(_realname) then
|
|
realname:=_realname^
|
|
else
|
|
realname:=name;
|
|
end;
|
|
|
|
|
|
function tsym.mangledname : string;
|
|
begin
|
|
internalerror(200204171);
|
|
end;
|
|
|
|
|
|
function tsym.gettypedef:tdef;
|
|
begin
|
|
gettypedef:=nil;
|
|
end;
|
|
|
|
|
|
procedure Tsym.load_references(ppufile:tcompilerppufile;locals:boolean);
|
|
var
|
|
pos : tfileposinfo;
|
|
move_last : boolean;
|
|
begin
|
|
move_last:=lastwritten=lastref;
|
|
while (not ppufile.endofentry) do
|
|
begin
|
|
ppufile.getposinfo(pos);
|
|
inc(refcount);
|
|
lastref:=tref.create(lastref,@pos);
|
|
lastref.is_written:=true;
|
|
if refcount=1 then
|
|
defref:=lastref;
|
|
end;
|
|
if move_last then
|
|
lastwritten:=lastref;
|
|
end;
|
|
|
|
{ big problem here :
|
|
wrong refs were written because of
|
|
interface parsing of other units PM
|
|
moduleindex must be checked !! }
|
|
|
|
function Tsym.write_references(ppufile:tcompilerppufile;locals:boolean):boolean;
|
|
var
|
|
d : tderef;
|
|
ref : tref;
|
|
symref_written,move_last : boolean;
|
|
begin
|
|
write_references:=false;
|
|
if lastwritten=lastref then
|
|
exit;
|
|
{ should we update lastref }
|
|
move_last:=true;
|
|
symref_written:=false;
|
|
{ write symbol refs }
|
|
d.reset;
|
|
if assigned(lastwritten) then
|
|
ref:=lastwritten
|
|
else
|
|
ref:=defref;
|
|
while assigned(ref) do
|
|
begin
|
|
if ref.moduleindex=current_module.unit_index then
|
|
begin
|
|
{ write address to this symbol }
|
|
if not symref_written then
|
|
begin
|
|
d.build(self);
|
|
ppufile.putderef(d);
|
|
symref_written:=true;
|
|
end;
|
|
ppufile.putposinfo(ref.posinfo);
|
|
ref.is_written:=true;
|
|
if move_last then
|
|
lastwritten:=ref;
|
|
end
|
|
else if not ref.is_written then
|
|
move_last:=false
|
|
else if move_last then
|
|
lastwritten:=ref;
|
|
ref:=ref.nextref;
|
|
end;
|
|
if symref_written then
|
|
ppufile.writeentry(ibsymref);
|
|
write_references:=symref_written;
|
|
end;
|
|
|
|
|
|
function tsym.is_visible_for_object(currobjdef:Tdef;context : tdef):boolean;
|
|
begin
|
|
is_visible_for_object:=false;
|
|
|
|
{ private symbols are allowed when we are in the same
|
|
module as they are defined }
|
|
if (sp_private in symoptions) and
|
|
assigned(owner.defowner) and
|
|
(owner.defowner.owner.symtabletype in [globalsymtable,staticsymtable]) and
|
|
(not owner.defowner.owner.iscurrentunit) then
|
|
exit;
|
|
|
|
if (sp_strictprivate in symoptions) then
|
|
begin
|
|
result:=assigned(currobjdef) and
|
|
(context=tdef(owner.defowner));
|
|
exit;
|
|
end;
|
|
|
|
if (sp_strictprotected in symoptions) then
|
|
begin
|
|
result:=assigned(context) and
|
|
context.is_related(tdef(owner.defowner));
|
|
exit;
|
|
end;
|
|
|
|
{ protected symbols are visible in the module that defines them and
|
|
also visible to related objects }
|
|
if (sp_protected in symoptions) and
|
|
(
|
|
(
|
|
assigned(owner.defowner) and
|
|
(owner.defowner.owner.symtabletype in [globalsymtable,staticsymtable]) and
|
|
(not owner.defowner.owner.iscurrentunit)
|
|
) and
|
|
not(
|
|
assigned(currobjdef) and
|
|
(currobjdef.owner.symtabletype in [globalsymtable,staticsymtable]) and
|
|
(currobjdef.owner.iscurrentunit) and
|
|
currobjdef.is_related(tdef(owner.defowner))
|
|
)
|
|
) then
|
|
exit;
|
|
|
|
is_visible_for_object:=true;
|
|
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
|
|
(
|
|
not((sym.owner.symtabletype in [globalsymtable,staticsymtable]) and
|
|
sym.owner.iscurrentunit)
|
|
)
|
|
) 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:TConstExprInt;const tt:ttype);
|
|
var
|
|
hp : psymlistitem;
|
|
begin
|
|
new(hp);
|
|
fillchar(hp^,sizeof(tsymlistitem),0);
|
|
hp^.sltype:=slt;
|
|
hp^.value:=v;
|
|
hp^.valuett:=tt;
|
|
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_absolutetype,
|
|
sl_typeconv :
|
|
hp^.tt.resolve;
|
|
sl_vec:
|
|
hp^.valuett.resolve;
|
|
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_absolutetype,
|
|
sl_typeconv :
|
|
hp^.tt.buildderef;
|
|
sl_vec:
|
|
hp^.valuett.buildderef;
|
|
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);
|
|
var
|
|
idx : longint;
|
|
begin
|
|
if not assigned(s.owner) then
|
|
internalerror(200306063);
|
|
case s.owner.symtabletype of
|
|
globalsymtable :
|
|
begin
|
|
if s.owner.iscurrentunit then
|
|
begin
|
|
data[len]:=ord(deref_aktglobal);
|
|
inc(len);
|
|
end
|
|
else
|
|
begin
|
|
{ register that the unit is needed for resolving }
|
|
idx:=current_module.derefidx_unit(s.owner.moduleid);
|
|
data[len]:=ord(deref_unit);
|
|
data[len+1]:=idx shr 8;
|
|
data[len+2]:=idx and $ff;
|
|
inc(len,3);
|
|
end;
|
|
end;
|
|
staticsymtable :
|
|
begin
|
|
{ only references to the current static symtable are allowed }
|
|
if not s.owner.iscurrentunit 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 }
|
|
if not(nextdef.owner.symtabletype in [globalsymtable,staticsymtable]) then
|
|
internalerror(200306187);
|
|
{ Next parent is in a different unit, then stop }
|
|
if not(nextdef.owner.iscurrentunit) 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.iscurrentunit then
|
|
begin
|
|
data[len]:=ord(deref_aktstatic);
|
|
inc(len);
|
|
end
|
|
{ Global symtable of current unit ? }
|
|
else if (s.owner.symtabletype=globalsymtable) and
|
|
s.owner.iscurrentunit 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 : aint;
|
|
len : byte;
|
|
data : array[0..255] of byte;
|
|
begin
|
|
result:=nil;
|
|
{ not initialized or error }
|
|
if dataidx<0 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:=current_module.localsymtable;
|
|
deref_aktglobal :
|
|
st:=current_module.globalsymtable;
|
|
deref_aktlocal :
|
|
st:=aktlocalsymtable;
|
|
deref_aktpara :
|
|
st:=aktparasymtable;
|
|
deref_unit :
|
|
begin
|
|
idx:=(data[i] shl 8) or data[i+1];
|
|
inc(i,2);
|
|
pm:=current_module.resolve_unit(idx);
|
|
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;
|
|
|
|
{*****************************************************************************
|
|
TCompilerPPUFile
|
|
*****************************************************************************}
|
|
|
|
procedure tcompilerppufile.checkerror;
|
|
begin
|
|
if error then
|
|
Message(unit_f_ppu_read_error);
|
|
end;
|
|
|
|
|
|
procedure tcompilerppufile.getguid(var g: tguid);
|
|
begin
|
|
getdata(g,sizeof(g));
|
|
end;
|
|
|
|
|
|
function tcompilerppufile.getexprint:tconstexprint;
|
|
begin
|
|
if sizeof(tconstexprint)=8 then
|
|
result:=tconstexprint(getint64)
|
|
else
|
|
result:=tconstexprint(getlongint);
|
|
end;
|
|
|
|
|
|
function tcompilerppufile.getPtrUInt:TConstPtrUInt;
|
|
begin
|
|
if sizeof(TConstPtrUInt)=8 then
|
|
result:=tconstptruint(getint64)
|
|
else
|
|
result:=TConstPtrUInt(getlongint);
|
|
end;
|
|
|
|
|
|
procedure tcompilerppufile.getposinfo(var p:tfileposinfo);
|
|
var
|
|
info : byte;
|
|
begin
|
|
{
|
|
info byte layout in bits:
|
|
0-1 - amount of bytes for fileindex
|
|
2-3 - amount of bytes for line
|
|
4-5 - amount of bytes for column
|
|
}
|
|
info:=getbyte;
|
|
case (info and $03) of
|
|
0 : p.fileindex:=getbyte;
|
|
1 : p.fileindex:=getword;
|
|
2 : p.fileindex:=(getbyte shl 16) or getword;
|
|
3 : p.fileindex:=getlongint;
|
|
end;
|
|
case ((info shr 2) and $03) of
|
|
0 : p.line:=getbyte;
|
|
1 : p.line:=getword;
|
|
2 : p.line:=(getbyte shl 16) or getword;
|
|
3 : p.line:=getlongint;
|
|
end;
|
|
case ((info shr 4) and $03) of
|
|
0 : p.column:=getbyte;
|
|
1 : p.column:=getword;
|
|
2 : p.column:=(getbyte shl 16) or getword;
|
|
3 : p.column:=getlongint;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure tcompilerppufile.getderef(var d:tderef);
|
|
begin
|
|
d.dataidx:=getlongint;
|
|
end;
|
|
|
|
|
|
function tcompilerppufile.getsymlist:tsymlist;
|
|
var
|
|
symderef : tderef;
|
|
tt : ttype;
|
|
slt : tsltype;
|
|
idx : longint;
|
|
p : tsymlist;
|
|
begin
|
|
p:=tsymlist.create;
|
|
getderef(p.procdefderef);
|
|
repeat
|
|
slt:=tsltype(getbyte);
|
|
case slt of
|
|
sl_none :
|
|
break;
|
|
sl_call,
|
|
sl_load,
|
|
sl_subscript :
|
|
begin
|
|
getderef(symderef);
|
|
p.addsymderef(slt,symderef);
|
|
end;
|
|
sl_absolutetype,
|
|
sl_typeconv :
|
|
begin
|
|
gettype(tt);
|
|
p.addtype(slt,tt);
|
|
end;
|
|
sl_vec :
|
|
begin
|
|
idx:=getlongint;
|
|
gettype(tt);
|
|
p.addconst(slt,idx,tt);
|
|
end;
|
|
else
|
|
internalerror(200110204);
|
|
end;
|
|
until false;
|
|
getsymlist:=tsymlist(p);
|
|
end;
|
|
|
|
|
|
procedure tcompilerppufile.gettype(var t:ttype);
|
|
begin
|
|
getderef(t.deref);
|
|
t.def:=nil;
|
|
t.sym:=nil;
|
|
end;
|
|
|
|
|
|
function tcompilerppufile.getasmsymbol:tasmsymbol;
|
|
begin
|
|
getlongint;
|
|
getasmsymbol:=nil;
|
|
end;
|
|
|
|
|
|
procedure tcompilerppufile.putposinfo(const p:tfileposinfo);
|
|
var
|
|
oldcrc : boolean;
|
|
info : byte;
|
|
begin
|
|
{ posinfo is not relevant for changes in PPU }
|
|
oldcrc:=do_crc;
|
|
do_crc:=false;
|
|
{
|
|
info byte layout in bits:
|
|
0-1 - amount of bytes for fileindex
|
|
2-3 - amount of bytes for line
|
|
4-5 - amount of bytes for column
|
|
}
|
|
info:=0;
|
|
{ calculate info byte }
|
|
if (p.fileindex>$ff) then
|
|
begin
|
|
if (p.fileindex<=$ffff) then
|
|
info:=info or $1
|
|
else
|
|
if (p.fileindex<=$ffffff) then
|
|
info:=info or $2
|
|
else
|
|
info:=info or $3;
|
|
end;
|
|
if (p.line>$ff) then
|
|
begin
|
|
if (p.line<=$ffff) then
|
|
info:=info or $4
|
|
else
|
|
if (p.line<=$ffffff) then
|
|
info:=info or $8
|
|
else
|
|
info:=info or $c;
|
|
end;
|
|
if (p.column>$ff) then
|
|
begin
|
|
if (p.column<=$ffff) then
|
|
info:=info or $10
|
|
else
|
|
if (p.column<=$ffffff) then
|
|
info:=info or $20
|
|
else
|
|
info:=info or $30;
|
|
end;
|
|
{ write data }
|
|
putbyte(info);
|
|
case (info and $03) of
|
|
0 : putbyte(p.fileindex);
|
|
1 : putword(p.fileindex);
|
|
2 : begin
|
|
putbyte(p.fileindex shr 16);
|
|
putword(p.fileindex and $ffff);
|
|
end;
|
|
3 : putlongint(p.fileindex);
|
|
end;
|
|
case ((info shr 2) and $03) of
|
|
0 : putbyte(p.line);
|
|
1 : putword(p.line);
|
|
2 : begin
|
|
putbyte(p.line shr 16);
|
|
putword(p.line and $ffff);
|
|
end;
|
|
3 : putlongint(p.line);
|
|
end;
|
|
case ((info shr 4) and $03) of
|
|
0 : putbyte(p.column);
|
|
1 : putword(p.column);
|
|
2 : begin
|
|
putbyte(p.column shr 16);
|
|
putword(p.column and $ffff);
|
|
end;
|
|
3 : putlongint(p.column);
|
|
end;
|
|
do_crc:=oldcrc;
|
|
end;
|
|
|
|
|
|
procedure tcompilerppufile.putguid(const g: tguid);
|
|
begin
|
|
putdata(g,sizeof(g));
|
|
end;
|
|
|
|
|
|
procedure tcompilerppufile.putexprint(v:tconstexprint);
|
|
begin
|
|
if sizeof(TConstExprInt)=8 then
|
|
putint64(int64(v))
|
|
else if sizeof(TConstExprInt)=4 then
|
|
putlongint(longint(v))
|
|
else
|
|
internalerror(2002082601);
|
|
end;
|
|
|
|
|
|
procedure tcompilerppufile.PutPtrUInt(v:TConstPtrUInt);
|
|
begin
|
|
if sizeof(TConstPtrUInt)=8 then
|
|
putint64(int64(v))
|
|
else if sizeof(TConstPtrUInt)=4 then
|
|
putlongint(longint(v))
|
|
else
|
|
internalerror(2002082601);
|
|
end;
|
|
|
|
|
|
procedure tcompilerppufile.putderef(const d:tderef);
|
|
var
|
|
oldcrc : boolean;
|
|
begin
|
|
oldcrc:=do_crc;
|
|
do_crc:=false;
|
|
putlongint(d.dataidx);
|
|
do_crc:=oldcrc;
|
|
end;
|
|
|
|
|
|
procedure tcompilerppufile.putsymlist(p:tsymlist);
|
|
var
|
|
hp : psymlistitem;
|
|
begin
|
|
putderef(p.procdefderef);
|
|
hp:=p.firstsym;
|
|
while assigned(hp) do
|
|
begin
|
|
putbyte(byte(hp^.sltype));
|
|
case hp^.sltype of
|
|
sl_call,
|
|
sl_load,
|
|
sl_subscript :
|
|
putderef(hp^.symderef);
|
|
sl_absolutetype,
|
|
sl_typeconv :
|
|
puttype(hp^.tt);
|
|
sl_vec :
|
|
begin
|
|
putlongint(hp^.value);
|
|
puttype(hp^.valuett);
|
|
end;
|
|
else
|
|
internalerror(200110205);
|
|
end;
|
|
hp:=hp^.next;
|
|
end;
|
|
putbyte(byte(sl_none));
|
|
end;
|
|
|
|
|
|
procedure tcompilerppufile.puttype(const t:ttype);
|
|
begin
|
|
putderef(t.deref);
|
|
end;
|
|
|
|
|
|
procedure tcompilerppufile.putasmsymbol(s:tasmsymbol);
|
|
begin
|
|
putlongint(0);
|
|
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.
|