* Fixed reference counting of open array parameters passed by value. RTTI of the array itself is useless in this case, as it does not provide correct element count. Now using dedicated helpers which take RTTI of array element and the element count. Resolves .

git-svn-id: trunk@17068 -
This commit is contained in:
sergei 2011-03-03 18:38:46 +00:00
parent 4be36c4b2b
commit 54bc8efa0b
6 changed files with 157 additions and 2 deletions

1
.gitattributes vendored
View File

@ -11199,6 +11199,7 @@ tests/webtbs/tw1867.pp svneol=native#text/plain
tests/webtbs/tw18690.pp svneol=native#text/plain
tests/webtbs/tw1873.pp svneol=native#text/plain
tests/webtbs/tw1883.pp svneol=native#text/plain
tests/webtbs/tw18859.pp svneol=native#text/plain
tests/webtbs/tw1888.pp svneol=native#text/plain
tests/webtbs/tw1889.pp svneol=native#text/plain
tests/webtbs/tw1896.pp svneol=native#text/plain

View File

@ -451,6 +451,8 @@ unit cgobj;
procedure g_incrrefcount(list : TAsmList;t: tdef; const ref: treference);
procedure g_decrrefcount(list : TAsmList;t: tdef; const ref: treference);
procedure g_array_rtti_helper(list: TAsmList; t: tdef; const ref: treference; const highloc: tlocation;
const name: string);
procedure g_initialize(list : TAsmList;t : tdef;const ref : treference);
procedure g_finalize(list : TAsmList;t : tdef;const ref : treference);
@ -3580,6 +3582,44 @@ implementation
cgpara1.done;
end;
procedure tcg.g_array_rtti_helper(list: TAsmList; t: tdef; const ref: treference; const highloc: tlocation; const name: string);
var
cgpara1,cgpara2,cgpara3: TCGPara;
href: TReference;
hreg: TRegister;
begin
cgpara1.init;
cgpara2.init;
cgpara3.init;
paramanager.getintparaloc(pocall_default,1,cgpara1);
paramanager.getintparaloc(pocall_default,2,cgpara2);
paramanager.getintparaloc(pocall_default,3,cgpara3);
reference_reset_symbol(href,RTTIWriter.get_rtti_label(t,initrtti),0,sizeof(pint));
if highloc.loc in [LOC_REGISTER,LOC_CREGISTER] then
hreg:=highloc.register
else
begin
hreg:=getintregister(list,OS_INT);
a_load_loc_reg(list,OS_INT,highloc,hreg);
end;
{ increment, converts high(x) to length(x) }
a_op_const_reg(list,OP_ADD,OS_INT,1,hreg);
a_load_reg_cgpara(list,OS_INT,hreg,cgpara3);
a_loadaddr_ref_cgpara(list,href,cgpara2);
a_loadaddr_ref_cgpara(list,ref,cgpara1);
paramanager.freecgpara(list,cgpara1);
paramanager.freecgpara(list,cgpara2);
paramanager.freecgpara(list,cgpara3);
allocallcpuregisters(list);
a_call_name(list,name,false);
deallocallcpuregisters(list);
cgpara3.done;
cgpara2.done;
cgpara1.done;
end;
procedure tcg.g_initialize(list : TAsmList;t : tdef;const ref : treference);
var

View File

@ -1561,6 +1561,8 @@ implementation
procedure init_paras(p:TObject;arg:pointer);
var
href : treference;
hsym : tparavarsym;
eldef : tdef;
tmpreg : tregister;
list : TAsmList;
needs_inittable,
@ -1584,7 +1586,18 @@ implementation
paramanager.push_addr_param(tparavarsym(p).varspez,tparavarsym(p).vardef,current_procinfo.procdef.proccalloption)) then
begin
location_get_data_ref(list,tparavarsym(p).initialloc,href,is_open_array(tparavarsym(p).vardef),sizeof(pint));
cg.g_incrrefcount(list,tparavarsym(p).vardef,href);
if is_open_array(tparavarsym(p).vardef) then
begin
{ open arrays do not contain correct element count in their rtti,
the actual count must be passed separately. }
hsym:=tparavarsym(tsym(p).owner.Find('high'+tsym(p).name));
eldef:=tarraydef(tparavarsym(p).vardef).elementdef;
if not assigned(hsym) then
internalerror(201003031);
cg.g_array_rtti_helper(list,eldef,href,hsym.initialloc,'FPC_ADDREF_ARRAY');
end
else
cg.g_incrrefcount(list,tparavarsym(p).vardef,href);
end;
end;
vs_out :
@ -1642,6 +1655,8 @@ implementation
var
list : TAsmList;
href : treference;
hsym : tparavarsym;
eldef : tdef;
begin
if not(tsym(p).typ=paravarsym) then
exit;
@ -1652,7 +1667,16 @@ implementation
begin
include(current_procinfo.flags,pi_needs_implicit_finally);
location_get_data_ref(list,tparavarsym(p).localloc,href,is_open_array(tparavarsym(p).vardef),sizeof(pint));
cg.g_decrrefcount(list,tparavarsym(p).vardef,href);
if is_open_array(tparavarsym(p).vardef) then
begin
hsym:=tparavarsym(tsym(p).owner.Find('high'+tsym(p).name));
eldef:=tarraydef(tparavarsym(p).vardef).elementdef;
if not assigned(hsym) then
internalerror(201003032);
cg.g_array_rtti_helper(list,eldef,href,hsym.initialloc,'FPC_DECREF_ARRAY');
end
else
cg.g_decrrefcount(list,tparavarsym(p).vardef,href);
end;
end;
{ open arrays can contain elements requiring init/final code, so the else has been removed here }

View File

@ -673,6 +673,8 @@ Procedure fpc_Addref (Data,TypeInfo : Pointer); compilerproc;
Procedure fpc_DecRef (Data,TypeInfo : Pointer); compilerproc;
procedure fpc_initialize_array(data,typeinfo : pointer;count,size : SizeInt); compilerproc;
procedure fpc_finalize_array(data,typeinfo : pointer;count,size : SizeInt); compilerproc;
procedure fpc_addref_array(data,typeinfo: pointer; count: SizeInt); compilerproc;
procedure fpc_decref_array(data,typeinfo: pointer; count: sizeint); compilerproc;
Function fpc_Copy (Src, Dest, TypeInfo : Pointer) : SizeInt; compilerproc;
Procedure fpc_Copy_proc (Src, Dest, TypeInfo : Pointer); compilerproc; inline;
{$endif FPC_HAS_FEATURE_RTTI}

View File

@ -19,6 +19,37 @@
type
TRTTIProc=procedure(Data,TypeInfo:Pointer);
function RTTIArraySize(typeInfo: Pointer): SizeInt;
begin
typeInfo:=aligntoptr(typeInfo+2+PByte(typeInfo)[1]);
result:=PSizeInt(typeInfo)[0] * PSizeInt(typeInfo)[1];
end;
function RTTIRecordSize(typeInfo: Pointer): SizeInt;
begin
typeInfo:=aligntoptr(typeInfo+2+PByte(typeInfo)[1]);
result:=PLongInt(typeInfo)^;
end;
function RTTISize(typeInfo: Pointer): SizeInt;
begin
case PByte(typeinfo)^ of
tkAString,tkWString,tkUString,
tkInterface,tkDynarray:
result:=sizeof(Pointer);
{$ifdef FPC_HAS_FEATURE_VARIANTS}
tkVariant:
result:=sizeof(TVarData);
{$endif FPC_HAS_FEATURE_VARIANTS}
tkArray:
result:=RTTIArraySize(typeinfo);
tkObject,tkRecord:
result:=RTTIRecordSize(typeinfo);
else
result:=-1;
end;
end;
{ if you modify this procedure, fpc_copy must be probably modified as well }
procedure RecordRTTI(Data,TypeInfo:Pointer;rttiproc:TRTTIProc);
{
@ -413,3 +444,23 @@ procedure fpc_finalize_array(data,typeinfo : pointer;count,size : SizeInt); [Pub
int_finalize(data+size*i,typeinfo);
end;
procedure fpc_addref_array(data,typeinfo: pointer; count: SizeInt); [public,alias:'FPC_ADDREF_ARRAY']; compilerproc;
var
i, size: SizeInt;
begin
size:=RTTISize(typeinfo);
if size>0 then
for i:=0 to count-1 do
int_addref(data+size*i,typeinfo);
end;
procedure fpc_decref_array(data,typeinfo: pointer; count: SizeInt); [public,alias:'FPC_DECREF_ARRAY']; compilerproc;
var
i, size: SizeInt;
begin
size:=RTTISize(typeinfo);
if size>0 then
for i:=0 to count-1 do
int_decref(data+size*i,typeinfo);
end;

37
tests/webtbs/tw18859.pp Normal file
View File

@ -0,0 +1,37 @@
{ %OPT=-gh }
Program project1;
{$mode objfpc}
{$h+}
type
trec = record
s: string;
end;
procedure test1(values: array of string);
begin
if paramcount = 0 then
values[0] := values[0] + '1'
else
values[0] := '1';
end;
procedure test2(values: array of trec);
begin
if paramcount = 0 then
values[0].s := values[0].s + '1'
else
values[0].s := '1';
end;
var
tr: trec;
begin
tr.s := 'test';
uniquestring(tr.s);
test1([tr.s]);
test2([tr]);
end.