mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-26 14:53:42 +02:00

Merged revision(s) 28239-28289 from branches/svenbarth/packages: Provide the possiblity to switch between the direct and indirect RTTI symbols. ncgrtti.pas, TRTTIWriter: + get_rtti_label, get_rtti_label_ord2str & get_rtti_label_str2ord: add new "indirect" parameter and pass that along to rtti_mangledname hlcgobj.pas, thlcgobj: * g_incrrefcount, g_initialize, g_finalize, g_array_rtti_helper: for now pass along False to get_rtti_label() ncgvmt.pas, TVMTWriter: * writevmt: for now pass along False to get_rtti_label() ncgld.pas, tcgrttinode: * pass_generate_code: for now pass along False to the get_rtti_label*() methods ........ Provide possibility to select between using a direct and an indirect RTTI reference. This way the references can be changed for selected cases. ncgrtti, TRTTIWriter: * ref_rtti: new "indirect" parameter that's relayed to rtti_mangledname() * write_rtti_reference: new "indirect" paramater that's relayed to ref_rtti() ........ Switch properties to use the indirect type information without breaking backwards compatiblity. :) compiler/ncgrtti.pas, TRTTIWriter: * published_properties_write_rtti_data: use the indirect reference, not the direct one rtl/objpas/typinfo.pp: * to allow compilation with both 2.6.x and 2.7.1 and too avoid too many ifdefs at least in the declarations we define a macro TypeInfoPtr which is either PTypeInfo (2.6.x) or PPTypeInfo (2.7.1 and newer) * TPropInfo: rename PropType to PropTypeRef and change type to TypeInfoPtr + TPropInfo: add a new property PropType which returns a PTypeInfo out of the PropTypeRef depending on the compiler version ........ Switch further simple types (sets, enums, class references, pointers) to indirect type information (again without breaking backwards compatibility). compiler/ncgrtti.pas, TRTTIWriter.write_rtti_data: * enumdef_rtti, setdef_rtti, classrefdef_rtti & pointerdef_rtti: write an indirect RTTI reference rtl/objpas/typinfo.pp, TTypeData: * rename BaseType to BaseTypeRef, CompType to CompTypeRef, InstanceType to InstanceTypeRef and RefType to RefTypeRef and change their type to TypeInfoPtr + add properties BaseType, CompType, InstanceType & RefType which return a PTypeInfo out of the corresponding *Ref field depending on the compiler version ........ Switch class and interface parent as well as extended type to indirect type information compiler/ncgrtti.pas, TRTTIWriter: * write_rtti_data.objectdef_rtti.objectdef_rtti_class_full: use indirect reference for class parent and extended type * write_rtti_data.objectdef_rtti.objectdef_rtti_interface_full: use indirect reference for interface parent rtl/objpas/typinfo.pp, TTypeData: + add new method DerefTypeInfoPtr which returns Nil if the indirect reference is Nil and otherwise returns the dereferences indirect reference (for 2.6.x the direct reference is returned as is) * rename ParentInfo to ParentInfoRef, HelperParent to HelperParentRef, ExtendedInfo to ExtendedInfoRef, IntfParent ot IntfParentRef and RawIntfParent to RawIntfParentRef and change their type to TypeInfoPtr + introduce ParentInfo, HelperParent, ExtendedInfo, IntfParent and RawIntfParent properties that return a PTypeInfo and use the new DerefTypeInfoPtr to return the correct type info value * change the other newly introduced properties of TTypeData to use DerefTypeInfoPtr as well to be on the safe side ........ Switch record/object fields to indirect type information references. compiler/ncgrtti.pas, TRTTIWriter.fields_write_rtti_data: * use the indirect reference for the object parent type * use the indirect reference for the field type rtl/inc/rtti.inc: * TRecordElement: change TypeInfo to PPointer for 2.7.1 and newer * RecordRTTI: correctly dereference the element type for 2.7.1 and newer * fpc_copy: correctly reference the element type for 2.7.1 and newer ........ Switch static arrays to indirect RTTI reference. compiler/ncgrtti.pas, TRTTIWriter.write_rtti_data: * arraydef_rtti: write the dimension types and the final field type as indirect references rtl/inc/rtti.inc: * TArrayInfo: switch ElInfo to PPointer for 2.7.1+ * ArrayRTTI & fpc_copy: correctly dereference ElInfo for 2.7.1+ rtl/objpas/typinfo.pp, TArrayTypeData: * switch ElType and Dims to PPTypeInfo; no backwards compatibility needed here as TArrayTypeData was added in 2.7.1 only tests/test/trtti8.pp: fix test ........ Switch dynamic arrays to indirect RTTI references. compiler/ncgrtti.pas, TRTTIWriter.write_rtti_data.arraydef_rtti: * write indirect references for the two element entries rtl/inc/dynarr.inc: * tdynarraytypedata: change elType2 to PPointer for 2.7.1+ * fpc_dynarray_clear, fpc_dynarray_setlength & fpc_dynarray_copy: correctly dereference elType2 for 2.7.1+ rtl/objpas/typinfo.pp, TTypeData: * rename elType and elType2 to elTypeRef and elType2Ref respectively and change type to TypeInfoPtr * add properties elType and elType2 which return PTypeInfo by dereferencing elTypeRef and elType2Ref respecively correctly * remove a few stray "inline" directives in the implementation ........ Switch procedure parameters and result type to indirect RTTI references. compiler/ncgrtti.pas, TRTTIWriter.write_rtti_data.procvardef_rtti: * write_procedure_param: use indirect RTTI reference * write result info for both methods and procvars as indirect RTTI reference * write parameters for procvars as indirect RTTI reference rtl/objpas/typinfo.pp: * TProcedureParam: change type of ParamType to PPTypeInfo (no backwards compatiblity needed here; was added for 2.7.1) * TProcedureSignature: change type of RseultType to PPTypeInfo (no backwards compatibility needed here; was added for 2.7.1) * TTypeData: remark in the comments of tkMethod that ResultTypeRef and ParamTypeRefs are of type PPTypeInfo and not PTypeInfo tests/test/trtti9.pp: * fix test ........ Remove no longer needed "indirect" parameter for TRTTIWriter methods. ncgrtti.pas, TRTTIWriter: - ref_rtti & write_rtti_reference: remove "indirect" parameter * ref_rtti: call rtti_mangledname with "indirect" always set to "true" - remove "true" parameter on callsites of write_rtti_reference & ref_rtti ........ git-svn-id: trunk@33944 -
431 lines
13 KiB
PHP
431 lines
13 KiB
PHP
{
|
|
This file is part of the Free Pascal run time library.
|
|
Copyright (c) 2000 by Florian Klaempfl
|
|
member of the Free Pascal development team.
|
|
|
|
This file implements the helper routines for dyn. Arrays in FPC
|
|
|
|
See the file COPYING.FPC, included in this distribution,
|
|
for details about the copyright.
|
|
|
|
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.
|
|
|
|
**********************************************************************
|
|
}
|
|
|
|
type
|
|
{ don't add new fields, the size is used }
|
|
{ to calculate memory requirements }
|
|
pdynarray = ^tdynarray;
|
|
tdynarray = packed record
|
|
refcount : ptrint;
|
|
high : tdynarrayindex;
|
|
end;
|
|
|
|
pdynarraytypedata = ^tdynarraytypedata;
|
|
tdynarraytypedata =
|
|
{$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
|
|
packed
|
|
{$endif FPC_REQUIRES_PROPER_ALIGNMENT}
|
|
record
|
|
elSize : SizeUInt;
|
|
{$ifdef VER3_0}
|
|
elType2 : Pointer;
|
|
{$else}
|
|
elType2 : PPointer;
|
|
{$endif}
|
|
varType : Longint;
|
|
{$ifdef VER3_0}
|
|
elType : Pointer;
|
|
{$else}
|
|
elType : PPointer;
|
|
{$endif}
|
|
end;
|
|
|
|
procedure fpc_dynarray_rangecheck(p : pointer;i : tdynarrayindex);[Public,Alias:'FPC_DYNARRAY_RANGECHECK']; compilerproc;
|
|
begin
|
|
if not(assigned(p)) or (i<0) or (i>pdynarray(p-sizeof(tdynarray))^.high) then
|
|
HandleErrorAddrFrameInd(201,get_pc_addr,get_frame);
|
|
end;
|
|
|
|
|
|
function fpc_dynarray_length(p : pointer) : tdynarrayindex;[Public,Alias:'FPC_DYNARRAY_LENGTH']; compilerproc;
|
|
begin
|
|
if assigned(p) then
|
|
fpc_dynarray_length:=pdynarray(p-sizeof(tdynarray))^.high+1
|
|
else
|
|
fpc_dynarray_length:=0;
|
|
end;
|
|
|
|
|
|
function fpc_dynarray_high(p : pointer) : tdynarrayindex;[Public,Alias:'FPC_DYNARRAY_HIGH']; compilerproc;
|
|
begin
|
|
if assigned(p) then
|
|
fpc_dynarray_high:=pdynarray(p-sizeof(tdynarray))^.high
|
|
else
|
|
fpc_dynarray_high:=-1;
|
|
end;
|
|
|
|
|
|
procedure fpc_dynarray_clear(var p : pointer;ti : pointer); [Public,Alias:'FPC_DYNARRAY_CLEAR']; compilerproc;
|
|
var
|
|
realp : pdynarray;
|
|
begin
|
|
if (P=Nil) then
|
|
exit;
|
|
realp:=pdynarray(p-sizeof(tdynarray));
|
|
if realp^.refcount=0 then
|
|
HandleErrorAddrFrameInd(204,get_pc_addr,get_frame);
|
|
|
|
if declocked(realp^.refcount) then
|
|
begin
|
|
ti:=aligntoptr(ti+2+PByte(ti)[1]);
|
|
if assigned(pdynarraytypedata(ti)^.elType) then
|
|
int_finalizearray(p,pdynarraytypedata(ti)^.elType{$ifndef VER3_0}^{$endif},realp^.high+1);
|
|
freemem(realp);
|
|
end;
|
|
p:=nil;
|
|
end;
|
|
|
|
{ alias for internal use }
|
|
Procedure fpc_dynarray_clear (var p : pointer;ti : pointer);[external name 'FPC_DYNARRAY_CLEAR'];
|
|
|
|
|
|
procedure fpc_dynarray_incr_ref(p : pointer);[Public,Alias:'FPC_DYNARRAY_INCR_REF']; compilerproc;
|
|
var
|
|
realp : pdynarray;
|
|
begin
|
|
if p=nil then
|
|
exit;
|
|
|
|
realp:=pdynarray(p-sizeof(tdynarray));
|
|
if realp^.refcount=0 then
|
|
HandleErrorAddrFrameInd(204,get_pc_addr,get_frame);
|
|
|
|
inclocked(realp^.refcount);
|
|
end;
|
|
|
|
{ provide local access to dynarr_decr_ref for dynarr_setlength }
|
|
procedure fpc_dynarray_incr_ref(p : pointer); [external name 'FPC_DYNARRAY_INCR_REF'];
|
|
|
|
|
|
procedure fpc_dynarray_assign(var dest: Pointer; src: Pointer; ti: pointer);[public,alias:'FPC_DYNARRAY_ASSIGN']; compilerproc;
|
|
begin
|
|
fpc_dynarray_incr_ref(src);
|
|
fpc_dynarray_clear(dest,ti);
|
|
Dest:=Src;
|
|
end;
|
|
|
|
procedure fpc_dynarray_assign(var dest: Pointer; src: Pointer; ti: pointer);[external name 'FPC_DYNARRAY_ASSIGN'];
|
|
|
|
{ provide local access to dynarr_setlength }
|
|
procedure int_dynarray_setlength(var p : pointer;pti : pointer;
|
|
dimcount : sizeint;dims : pdynarrayindex);[external name 'FPC_DYNARR_SETLENGTH'];
|
|
|
|
procedure fpc_dynarray_setlength(var p : pointer;pti : pointer;
|
|
dimcount : sizeint;dims : pdynarrayindex);[Public,Alias:'FPC_DYNARR_SETLENGTH']; compilerproc;
|
|
|
|
var
|
|
i : tdynarrayindex;
|
|
movelen,
|
|
size : sizeint;
|
|
{ contains the "fixed" pointers where the refcount }
|
|
{ and high are at positive offsets }
|
|
realp,newp : pdynarray;
|
|
ti : pointer;
|
|
updatep: boolean;
|
|
elesize : sizeint;
|
|
eletype,eletypemngd : pointer;
|
|
movsize : sizeint;
|
|
|
|
begin
|
|
{ negative length is not allowed }
|
|
if dims[0]<0 then
|
|
HandleErrorAddrFrameInd(201,get_pc_addr,get_frame);
|
|
|
|
{ skip kind and name }
|
|
ti:=aligntoptr(Pointer(pti)+2+PByte(pti)[1]);
|
|
|
|
elesize:=pdynarraytypedata(ti)^.elSize;
|
|
{$ifdef VER3_0}
|
|
eletype:=pdynarraytypedata(ti)^.elType2;
|
|
{$else}
|
|
eletype:=pdynarraytypedata(ti)^.elType2^;
|
|
{$endif}
|
|
{ only set if type needs finalization }
|
|
{$ifdef VER3_0}
|
|
eletypemngd:=pdynarraytypedata(ti)^.elType;
|
|
{$else}
|
|
if assigned(pdynarraytypedata(ti)^.elType) then
|
|
eletypemngd:=pdynarraytypedata(ti)^.elType^
|
|
else
|
|
eletypemngd:=nil;
|
|
{$endif}
|
|
|
|
{ determine new memory size }
|
|
size:=elesize*dims[0]+sizeof(tdynarray);
|
|
updatep := false;
|
|
|
|
{ not assigned yet? }
|
|
if not(assigned(p)) then
|
|
begin
|
|
{ do we have to allocate memory? }
|
|
if dims[0] = 0 then
|
|
exit;
|
|
getmem(newp,size);
|
|
fillchar(newp^,size,0);
|
|
updatep := true;
|
|
end
|
|
else
|
|
begin
|
|
{ if the new dimension is 0, we've to release all data }
|
|
if dims[0]=0 then
|
|
begin
|
|
fpc_dynarray_clear(p,pti);
|
|
exit;
|
|
end;
|
|
|
|
realp:=pdynarray(p-sizeof(tdynarray));
|
|
newp := realp;
|
|
|
|
if realp^.refcount<>1 then
|
|
begin
|
|
updatep := true;
|
|
{ make an unique copy }
|
|
getmem(newp,size);
|
|
fillchar(newp^,sizeof(tdynarray),0);
|
|
if realp^.high < dims[0] then
|
|
movelen := realp^.high+1
|
|
else
|
|
movelen := dims[0];
|
|
movsize := elesize*movelen;
|
|
move(p^,(pointer(newp)+sizeof(tdynarray))^, movsize);
|
|
if size-sizeof(tdynarray)>movsize then
|
|
fillchar((pointer(newp)+sizeof(tdynarray)+movsize)^,size-sizeof(tdynarray)-movsize,0);
|
|
|
|
{ increment ref. count of managed members }
|
|
if assigned(eletypemngd) then
|
|
for i:= 0 to movelen-1 do
|
|
int_addref(pointer(newp)+sizeof(tdynarray)+elesize*i,eletypemngd);
|
|
|
|
{ a declock(ref. count) isn't enough here }
|
|
{ it could be that the in MT environments }
|
|
{ in the mean time the refcount was }
|
|
{ decremented }
|
|
|
|
{ it is, because it doesn't really matter }
|
|
{ if the array is now removed }
|
|
fpc_dynarray_clear(p,pti);
|
|
end
|
|
else if dims[0]<>realp^.high+1 then
|
|
begin
|
|
{ range checking is quite difficult ... }
|
|
{ if size overflows then it is less than }
|
|
{ the values it was calculated from }
|
|
if (size<sizeof(tdynarray)) or
|
|
((elesize>0) and (size<elesize)) then
|
|
HandleErrorAddrFrameInd(201,get_pc_addr,get_frame);
|
|
|
|
{ resize? }
|
|
{ here, realp^.refcount has to be one, otherwise the previous }
|
|
{ if-statement would have been taken. Or is this also for MT }
|
|
{ code? (JM) }
|
|
if realp^.refcount=1 then
|
|
begin
|
|
{ shrink the array? }
|
|
if dims[0]<realp^.high+1 then
|
|
begin
|
|
if assigned(eletypemngd) then
|
|
int_finalizearray(pointer(realp)+sizeof(tdynarray)+
|
|
elesize*dims[0],
|
|
eletypemngd,realp^.high-dims[0]+1);
|
|
reallocmem(realp,size);
|
|
end
|
|
else if dims[0]>realp^.high+1 then
|
|
begin
|
|
reallocmem(realp,size);
|
|
fillchar((pointer(realp)+sizeof(tdynarray)+elesize*(realp^.high+1))^,
|
|
(dims[0]-realp^.high-1)*elesize,0);
|
|
end;
|
|
newp := realp;
|
|
updatep := true;
|
|
end;
|
|
end;
|
|
end;
|
|
{ handle nested arrays }
|
|
if dimcount>1 then
|
|
begin
|
|
for i:=0 to dims[0]-1 do
|
|
int_dynarray_setlength(pointer((pointer(newp)+sizeof(tdynarray)+i*elesize)^),
|
|
eletype,dimcount-1,@dims[1]);
|
|
end;
|
|
if updatep then
|
|
begin
|
|
p:=pointer(newp)+sizeof(tdynarray);
|
|
newp^.refcount:=1;
|
|
newp^.high:=dims[0]-1;
|
|
end;
|
|
end;
|
|
|
|
|
|
{ provide local access to dynarr_copy }
|
|
function int_dynarray_copy(psrc : pointer;ti : pointer;
|
|
lowidx,count:tdynarrayindex) : fpc_stub_dynarray;[external name 'FPC_DYNARR_COPY'];
|
|
|
|
function fpc_dynarray_copy(psrc : pointer;ti : pointer;
|
|
lowidx,count:tdynarrayindex) : fpc_stub_dynarray;[Public,Alias:'FPC_DYNARR_COPY'];compilerproc;
|
|
var
|
|
realpsrc : pdynarray;
|
|
i,size : sizeint;
|
|
elesize : sizeint;
|
|
eletype : pointer;
|
|
begin
|
|
fpc_dynarray_clear(pointer(result),ti);
|
|
if psrc=nil then
|
|
exit;
|
|
{$ifndef FPC_DYNARRAYCOPY_FIXED}
|
|
if (lowidx=-1) and (count=-1) then
|
|
begin
|
|
lowidx:=0;
|
|
count:=high(tdynarrayindex);
|
|
end;
|
|
{$endif FPC_DYNARRAYCOPY_FIXED}
|
|
realpsrc:=pdynarray(psrc-sizeof(tdynarray));
|
|
if (lowidx<0) then
|
|
begin
|
|
{ Decrease count if index is negative, this is different from how copy()
|
|
works on strings. Checked against D7. }
|
|
if count<=0 then
|
|
exit; { may overflow when adding lowidx }
|
|
count:=count+lowidx;
|
|
lowidx:=0;
|
|
end;
|
|
if (count>realpsrc^.high-lowidx+1) then
|
|
count:=realpsrc^.high-lowidx+1;
|
|
if count<=0 then
|
|
exit;
|
|
|
|
{ skip kind and name }
|
|
ti:=aligntoptr(ti+2+PByte(ti)[1]);
|
|
|
|
elesize:=pdynarraytypedata(ti)^.elSize;
|
|
{ only set if type needs finalization }
|
|
{$ifdef VER3_0}
|
|
eletype:=pdynarraytypedata(ti)^.elType;
|
|
{$else}
|
|
if assigned(pdynarraytypedata(ti)^.elType) then
|
|
eletype:=pdynarraytypedata(ti)^.elType^
|
|
else
|
|
eletype:=nil;
|
|
{$endif}
|
|
|
|
{ create new array }
|
|
size:=elesize*count;
|
|
getmem(pointer(result),size+sizeof(tdynarray));
|
|
pdynarray(result)^.refcount:=1;
|
|
pdynarray(result)^.high:=count-1;
|
|
inc(pointer(result),sizeof(tdynarray));
|
|
{ copy data }
|
|
move(pointer(psrc+elesize*lowidx)^,pointer(result)^,size);
|
|
|
|
{ increment ref. count of members? }
|
|
if assigned(eletype) then
|
|
for i:=0 to count-1 do
|
|
int_addref(pointer(pointer(result)+elesize*i),eletype);
|
|
end;
|
|
|
|
|
|
procedure DynArraySetLength(var a: Pointer; typeInfo: Pointer; dimCnt: SizeInt; lengthVec: PSizeInt);
|
|
external name 'FPC_DYNARR_SETLENGTH';
|
|
|
|
function DynArraySize(a : pointer): tdynarrayindex;
|
|
external name 'FPC_DYNARRAY_LENGTH';
|
|
|
|
procedure DynArrayClear(var a: Pointer; typeInfo: Pointer);
|
|
external name 'FPC_DYNARRAY_CLEAR';
|
|
|
|
function DynArrayDim(typeInfo: Pointer): Integer;
|
|
begin
|
|
result:=0;
|
|
while (typeInfo <> nil) and (pdynarraytypeinfo(typeInfo)^.kind = tkDynArray) do
|
|
begin
|
|
{ skip kind and name }
|
|
typeInfo:=aligntoptr(typeInfo+2+PByte(typeInfo)[1]);
|
|
|
|
{ element type info}
|
|
typeInfo:=pdynarraytypedata(typeInfo)^.elType2;
|
|
|
|
Inc(result);
|
|
end;
|
|
end;
|
|
|
|
function DynArrayBounds(a: Pointer; typeInfo: Pointer): TBoundArray;
|
|
var
|
|
i,dim: sizeint;
|
|
begin
|
|
dim:=DynArrayDim(typeInfo);
|
|
SetLength(result, dim);
|
|
|
|
for i:=0 to pred(dim) do
|
|
if a = nil then
|
|
exit
|
|
else
|
|
begin
|
|
result[i]:=DynArraySize(a)-1;
|
|
a:=PPointerArray(a)^[0];
|
|
end;
|
|
end;
|
|
|
|
function IsDynArrayRectangular(a: Pointer; typeInfo: Pointer): Boolean;
|
|
var
|
|
i,j: sizeint;
|
|
dim,count: sizeint;
|
|
begin
|
|
dim:=DynArrayDim(typeInfo);
|
|
for i:=1 to pred(dim) do
|
|
begin
|
|
count:=DynArraySize(PPointerArray(a)^[0]);
|
|
|
|
for j:=1 to Pred(DynArraySize(a)) do
|
|
if count<>DynArraySize(PPointerArray(a)^[j]) then
|
|
exit(false);
|
|
|
|
a:=PPointerArray(a)^[0];
|
|
end;
|
|
result:=true;
|
|
end;
|
|
|
|
function DynArrayIndex(a: Pointer; const indices: array of SizeInt; typeInfo: Pointer): Pointer;
|
|
var
|
|
i,h: sizeint;
|
|
begin
|
|
h:=High(indices);
|
|
for i:=0 to h do
|
|
begin
|
|
if i<h then
|
|
a := PPointerArray(a)^[indices[i]];
|
|
|
|
{ skip kind and name }
|
|
typeInfo:=(typeInfo+2+PByte(typeInfo)[1]);
|
|
{ element type info}
|
|
typeInfo:=pdynarraytypedata(typeInfo)^.elType2;
|
|
|
|
if typeInfo=nil then
|
|
exit(nil);
|
|
end;
|
|
|
|
{ skip kind and name }
|
|
typeInfo:=(typeInfo+2+PByte(typeInfo)[1]);
|
|
|
|
result:=@(PByte(a)[indices[h]*pdynarraytypedata(typeInfo)^.elSize]);
|
|
end;
|
|
|
|
{ obsolete but needed for bootstrapping }
|
|
procedure fpc_dynarray_decr_ref(var p : pointer;ti : pointer); [Public,Alias:'FPC_DYNARRAY_DECR_REF']; compilerproc;
|
|
begin
|
|
fpc_dynarray_clear(p,ti);
|
|
end;
|
|
|