Values of managed variables are never ever used after decrementing reference on the variable, so there is no point of having a 'decrement reference' as a separate operation. We can always do 'finalize', i.e. clear the contents after decref.

* Modified fpc_ansistr_decr_ref and fpc_widestr_decr_ref so they always zero the pointer passed by reference. Other _decr_ref helpers already do it.
- Removed tcg.g_decrrefcount, calling cg.g_finalize instead.
- finalize_data_node and tcg.g_finalize: removed code generation for zeroing locations, because it is now done by RTL helpers. This further reduces code size.

As a total result of this change and r20118, the size of Lazarus executable is reduced by about 12%.

git-svn-id: trunk@20119 -
This commit is contained in:
sergei 2012-01-19 23:11:09 +00:00
parent afb4992113
commit 06192a8137
7 changed files with 73 additions and 192 deletions

View File

@ -446,7 +446,6 @@ unit cgobj;
procedure g_copyvariant(list : TAsmList;const source,dest : treference);
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);
@ -3514,72 +3513,6 @@ implementation
end;
procedure tcg.g_decrrefcount(list : TAsmList;t: tdef; const ref: treference);
var
href : treference;
decrfunc : string;
needrtti : boolean;
cgpara1,cgpara2 : TCGPara;
tempreg1,tempreg2 : TRegister;
begin
cgpara1.init;
cgpara2.init;
paramanager.getintparaloc(pocall_default,1,cgpara1);
paramanager.getintparaloc(pocall_default,2,cgpara2);
needrtti:=false;
if is_interfacecom_or_dispinterface(t) then
decrfunc:='FPC_INTF_DECR_REF'
else if is_ansistring(t) then
decrfunc:='FPC_ANSISTR_DECR_REF'
else if is_widestring(t) then
decrfunc:='FPC_WIDESTR_DECR_REF'
else if is_unicodestring(t) then
decrfunc:='FPC_UNICODESTR_DECR_REF'
else if is_dynamic_array(t) then
begin
decrfunc:='FPC_DYNARRAY_DECR_REF';
needrtti:=true;
end
else
decrfunc:='';
{ call the special decr function or the generic decref }
if decrfunc<>'' then
begin
if needrtti then
begin
reference_reset_symbol(href,RTTIWriter.get_rtti_label(t,initrtti),0,sizeof(pint));
tempreg2:=getaddressregister(list);
a_loadaddr_ref_reg(list,href,tempreg2);
end;
tempreg1:=getaddressregister(list);
a_loadaddr_ref_reg(list,ref,tempreg1);
if needrtti then
a_load_reg_cgpara(list,OS_ADDR,tempreg2,cgpara2);
a_load_reg_cgpara(list,OS_ADDR,tempreg1,cgpara1);
paramanager.freecgpara(list,cgpara1);
if needrtti then
paramanager.freecgpara(list,cgpara2);
allocallcpuregisters(list);
a_call_name(list,decrfunc,false);
deallocallcpuregisters(list);
end
else
begin
if is_open_array(t) then
InternalError(201103053);
reference_reset_symbol(href,RTTIWriter.get_rtti_label(t,initrtti),0,sizeof(pint));
a_loadaddr_ref_cgpara(list,href,cgpara2);
a_loadaddr_ref_cgpara(list,ref,cgpara1);
paramanager.freecgpara(list,cgpara1);
paramanager.freecgpara(list,cgpara2);
allocallcpuregisters(list);
a_call_name(list,'FPC_DECREF',false);
deallocallcpuregisters(list);
end;
cgpara2.done;
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;
@ -3671,43 +3604,45 @@ implementation
var
href : treference;
cgpara1,cgpara2 : TCGPara;
decrfunc : string;
begin
if is_interfacecom_or_dispinterface(t) then
decrfunc:='FPC_INTF_DECR_REF'
else if is_ansistring(t) then
decrfunc:='FPC_ANSISTR_DECR_REF'
else if is_widestring(t) then
decrfunc:='FPC_WIDESTR_DECR_REF'
else if is_unicodestring(t) then
decrfunc:='FPC_UNICODESTR_DECR_REF'
else if t.typ=variantdef then
decrfunc:='FPC_VARIANT_CLEAR'
else
begin
cgpara1.init;
cgpara2.init;
if is_open_array(t) then
InternalError(201103051);
paramanager.getintparaloc(pocall_default,1,cgpara1);
paramanager.getintparaloc(pocall_default,2,cgpara2);
reference_reset_symbol(href,RTTIWriter.get_rtti_label(t,initrtti),0,sizeof(pint));
a_loadaddr_ref_cgpara(list,href,cgpara2);
a_loadaddr_ref_cgpara(list,ref,cgpara1);
paramanager.freecgpara(list,cgpara1);
paramanager.freecgpara(list,cgpara2);
if is_dynamic_array(t) then
g_call(list,'FPC_DYNARRAY_CLEAR')
else
g_call(list,'FPC_FINALIZE');
cgpara1.done;
cgpara2.done;
exit;
end;
cgpara1.init;
cgpara2.init;
if is_ansistring(t) or
is_widestring(t) or
is_unicodestring(t) or
is_interfacecom_or_dispinterface(t) then
begin
g_decrrefcount(list,t,ref);
a_load_const_ref(list,OS_ADDR,0,ref);
end
else if t.typ=variantdef then
begin
paramanager.getintparaloc(pocall_default,1,cgpara1);
a_loadaddr_ref_cgpara(list,ref,cgpara1);
paramanager.freecgpara(list,cgpara1);
allocallcpuregisters(list);
a_call_name(list,'FPC_VARIANT_CLEAR',false);
deallocallcpuregisters(list);
end
else
begin
if is_open_array(t) then
InternalError(201103051);
paramanager.getintparaloc(pocall_default,1,cgpara1);
paramanager.getintparaloc(pocall_default,2,cgpara2);
reference_reset_symbol(href,RTTIWriter.get_rtti_label(t,initrtti),0,sizeof(pint));
a_loadaddr_ref_cgpara(list,href,cgpara2);
a_loadaddr_ref_cgpara(list,ref,cgpara1);
paramanager.freecgpara(list,cgpara1);
paramanager.freecgpara(list,cgpara2);
allocallcpuregisters(list);
a_call_name(list,'FPC_FINALIZE',false);
deallocallcpuregisters(list);
end;
paramanager.getintparaloc(pocall_default,1,cgpara1);
a_loadaddr_ref_cgpara(list,ref,cgpara1);
paramanager.freecgpara(list,cgpara1);
g_call(list,decrfunc);
cgpara1.done;
cgpara2.done;
end;

View File

@ -177,15 +177,11 @@ implementation
InternalError(201103063);
secondpass(third);
cg.g_array_rtti_helper(current_asmdata.CurrAsmList,tarraydef(resultdef).elementdef,
href,third.location,'FPC_DECREF_ARRAY');
href,third.location,'FPC_FINALIZE_ARRAY');
end;
end
else if (resultdef.typ=formaldef) then
{ stuff being passed to formal parameter has to be completely cleaned,
because it cannot be initialized at callee side (bug #20962) }
cg.g_finalize(current_asmdata.CurrAsmList,left.resultdef,href)
else
cg.g_decrrefcount(current_asmdata.CurrAsmList,left.resultdef,href);
cg.g_finalize(current_asmdata.CurrAsmList,left.resultdef,href)
end;
paramanager.createtempparaloc(current_asmdata.CurrAsmList,aktcallnode.procdefinition.proccalloption,parasym,not followed_by_stack_tainting_call_cached,tempcgpara);
@ -397,7 +393,7 @@ implementation
function since this is code is only executed after the function call has returned }
if is_managed_type(funcretnode.resultdef) and
(funcretnode.nodetype<>temprefn) then
cg.g_decrrefcount(current_asmdata.CurrAsmList,funcretnode.resultdef,funcretnode.location.reference);
cg.g_finalize(current_asmdata.CurrAsmList,funcretnode.resultdef,funcretnode.location.reference);
case location.loc of
LOC_REGISTER :

View File

@ -1712,10 +1712,10 @@ implementation
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');
cg.g_array_rtti_helper(list,eldef,href,hsym.initialloc,'FPC_FINALIZE_ARRAY');
end
else
cg.g_decrrefcount(list,tparavarsym(p).vardef,href);
cg.g_finalize(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

@ -626,57 +626,27 @@ implementation
function finalize_data_node(p:tnode):tnode;
var
newstatement : tstatementnode;
hs : string;
begin
if not assigned(p.resultdef) then
typecheckpass(p);
{ 'decr_ref' suffix is somewhat misleading, all these helpers
set the passed pointer to nil now }
if is_ansistring(p.resultdef) then
begin
result:=internalstatements(newstatement);
addstatement(newstatement,ccallnode.createintern('fpc_ansistr_decr_ref',
ccallparanode.create(
ctypeconvnode.create_internal(p,voidpointertype),
nil)));
addstatement(newstatement,cassignmentnode.create(
ctypeconvnode.create_internal(p.getcopy,voidpointertype),
cnilnode.create
));
end
hs:='fpc_ansistr_decr_ref'
else if is_widestring(p.resultdef) then
begin
result:=internalstatements(newstatement);
addstatement(newstatement,ccallnode.createintern('fpc_widestr_decr_ref',
ccallparanode.create(
ctypeconvnode.create_internal(p,voidpointertype),
nil)));
addstatement(newstatement,cassignmentnode.create(
ctypeconvnode.create_internal(p.getcopy,voidpointertype),
cnilnode.create
));
end
hs:='fpc_widestr_decr_ref'
else if is_unicodestring(p.resultdef) then
begin
result:=internalstatements(newstatement);
addstatement(newstatement,ccallnode.createintern('fpc_unicodestr_decr_ref',
ccallparanode.create(
ctypeconvnode.create_internal(p,voidpointertype),
nil)));
addstatement(newstatement,cassignmentnode.create(
ctypeconvnode.create_internal(p.getcopy,voidpointertype),
cnilnode.create
));
end
hs:='fpc_unicodestr_decr_ref'
else if is_interfacecom_or_dispinterface(p.resultdef) then
begin
result:=internalstatements(newstatement);
addstatement(newstatement,ccallnode.createintern('fpc_intf_decr_ref',
ccallparanode.create(
ctypeconvnode.create_internal(p,voidpointertype),
nil)));
addstatement(newstatement,cassignmentnode.create(
ctypeconvnode.create_internal(p.getcopy,voidpointertype),
cnilnode.create
));
end
hs:='fpc_intf_decr_ref'
else
hs:='';
if hs<>'' then
result:=ccallnode.createintern(hs,
ccallparanode.create(
ctypeconvnode.create_internal(p,voidpointertype),
nil))
else if p.resultdef.typ=variantdef then
begin
result:=ccallnode.createintern('fpc_variant_clear',

View File

@ -1333,23 +1333,14 @@ function fpc_freemem_x(p:pointer):ptrint; [external name 'FPC_FREEMEM_X'];
Procedure fpc_AnsiStr_Decr_Ref (Var S : Pointer); [Public,Alias:'FPC_ANSISTR_DECR_REF']; compilerproc; nostackframe; assembler;
asm
cmpl $0,(%eax)
jne .Ldecr_ref_continue
ret
.Ldecr_ref_continue:
// Temps allocated between ebp-24 and ebp+0
subl $4,%esp
// Var S located in register
// Var l located in register
movl %eax,(%esp)
// [101] l:=@PAnsiRec(S-FirstOff)^.Ref;
movl (%eax),%edx
subl $8,%edx
// [102] If l^<0 then exit;
cmpl $0,(%edx)
cmpl $0,(%eax)
je .Lquit
pushl %esi
movl (%eax),%esi
subl $12,%esi // points to start of allocation
movl $0,(%eax) // s:=nil
cmpl $0,4(%esi) // exit if refcount<0
jl .Lj3596
.Lj3603:
// [104] If declocked(l^) then
{$ifdef FPC_PIC}
pushl %ebx
call fpc_geteipasebx
@ -1362,27 +1353,20 @@ asm
cmpl $0,ismultithread
{$endif FPC_PIC}
jne .Lj3610
decl (%edx)
decl 4(%esi)
je .Lj3620
addl $4,%esp
ret
jmp .Lj3596
.Lj3610:
movl %edx,%eax
leal 4(%esi),%eax
call cpudeclocked
testb %al,%al
je .Lj3605
je .Lj3596
.Lj3620:
movl (%esp),%eax
movl (%eax),%eax
subl $12,%eax
movl %esi,%eax
call FPC_FREEMEM_X
movl (%esp),%eax
movl $0,(%eax)
.Lj3618:
.Lj3605:
.Lj3596:
// [107] end;
addl $4,%esp
popl %esi
.Lquit:
end;
function fpc_truely_ansistr_unique(Var S : Pointer): Pointer; forward;

View File

@ -92,13 +92,11 @@ Begin
exit;
{ check for constant strings ...}
p:=PAnsiRec(S-AnsiFirstOff);
s:=nil;
If p^.ref<0 then exit;
{ declocked does a MT safe dec and returns true, if the counter is 0 }
If declocked(p^.ref) then
begin
FreeMem(p);
s:=nil;
end;
FreeMem(p);
end;
{$endif FPC_SYSTEM_HAS_ANSISTR_DECR_REF}

View File

@ -216,15 +216,13 @@ Begin
exit;
{ check for constant strings ...}
p:=PUnicodeRec(S-UnicodeFirstOff);
S:=nil;
if p^.Ref<0 then
exit;
{ declocked does a MT safe dec and returns true, if the counter is 0 }
if declocked(p^.Ref) then
begin
FreeMem(p);
S:=nil;
end;
FreeMem(p);
end;
{ alias for internal use }