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_copyvariant(list : TAsmList;const source,dest : treference);
procedure g_incrrefcount(list : TAsmList;t: tdef; const ref: 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; procedure g_array_rtti_helper(list: TAsmList; t: tdef; const ref: treference; const highloc: tlocation;
const name: string); const name: string);
procedure g_initialize(list : TAsmList;t : tdef;const ref : treference); procedure g_initialize(list : TAsmList;t : tdef;const ref : treference);
@ -3514,72 +3513,6 @@ implementation
end; 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); procedure tcg.g_array_rtti_helper(list: TAsmList; t: tdef; const ref: treference; const highloc: tlocation; const name: string);
var var
cgpara1,cgpara2,cgpara3: TCGPara; cgpara1,cgpara2,cgpara3: TCGPara;
@ -3671,43 +3604,45 @@ implementation
var var
href : treference; href : treference;
cgpara1,cgpara2 : TCGPara; cgpara1,cgpara2 : TCGPara;
decrfunc : string;
begin 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; cgpara1.init;
cgpara2.init; paramanager.getintparaloc(pocall_default,1,cgpara1);
if is_ansistring(t) or a_loadaddr_ref_cgpara(list,ref,cgpara1);
is_widestring(t) or paramanager.freecgpara(list,cgpara1);
is_unicodestring(t) or g_call(list,decrfunc);
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;
cgpara1.done; cgpara1.done;
cgpara2.done;
end; end;

View File

@ -177,15 +177,11 @@ implementation
InternalError(201103063); InternalError(201103063);
secondpass(third); secondpass(third);
cg.g_array_rtti_helper(current_asmdata.CurrAsmList,tarraydef(resultdef).elementdef, 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;
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 else
cg.g_decrrefcount(current_asmdata.CurrAsmList,left.resultdef,href); cg.g_finalize(current_asmdata.CurrAsmList,left.resultdef,href)
end; end;
paramanager.createtempparaloc(current_asmdata.CurrAsmList,aktcallnode.procdefinition.proccalloption,parasym,not followed_by_stack_tainting_call_cached,tempcgpara); 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 } function since this is code is only executed after the function call has returned }
if is_managed_type(funcretnode.resultdef) and if is_managed_type(funcretnode.resultdef) and
(funcretnode.nodetype<>temprefn) then (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 case location.loc of
LOC_REGISTER : LOC_REGISTER :

View File

@ -1712,10 +1712,10 @@ implementation
eldef:=tarraydef(tparavarsym(p).vardef).elementdef; eldef:=tarraydef(tparavarsym(p).vardef).elementdef;
if not assigned(hsym) then if not assigned(hsym) then
internalerror(201003032); 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 end
else else
cg.g_decrrefcount(list,tparavarsym(p).vardef,href); cg.g_finalize(list,tparavarsym(p).vardef,href);
end; end;
end; end;
{ open arrays can contain elements requiring init/final code, so the else has been removed here } { 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; function finalize_data_node(p:tnode):tnode;
var var
newstatement : tstatementnode; newstatement : tstatementnode;
hs : string;
begin begin
if not assigned(p.resultdef) then if not assigned(p.resultdef) then
typecheckpass(p); typecheckpass(p);
{ 'decr_ref' suffix is somewhat misleading, all these helpers
set the passed pointer to nil now }
if is_ansistring(p.resultdef) then if is_ansistring(p.resultdef) then
begin hs:='fpc_ansistr_decr_ref'
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
else if is_widestring(p.resultdef) then else if is_widestring(p.resultdef) then
begin hs:='fpc_widestr_decr_ref'
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
else if is_unicodestring(p.resultdef) then else if is_unicodestring(p.resultdef) then
begin hs:='fpc_unicodestr_decr_ref'
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
else if is_interfacecom_or_dispinterface(p.resultdef) then else if is_interfacecom_or_dispinterface(p.resultdef) then
begin hs:='fpc_intf_decr_ref'
result:=internalstatements(newstatement); else
addstatement(newstatement,ccallnode.createintern('fpc_intf_decr_ref', hs:='';
ccallparanode.create( if hs<>'' then
ctypeconvnode.create_internal(p,voidpointertype), result:=ccallnode.createintern(hs,
nil))); ccallparanode.create(
addstatement(newstatement,cassignmentnode.create( ctypeconvnode.create_internal(p,voidpointertype),
ctypeconvnode.create_internal(p.getcopy,voidpointertype), nil))
cnilnode.create
));
end
else if p.resultdef.typ=variantdef then else if p.resultdef.typ=variantdef then
begin begin
result:=ccallnode.createintern('fpc_variant_clear', 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; Procedure fpc_AnsiStr_Decr_Ref (Var S : Pointer); [Public,Alias:'FPC_ANSISTR_DECR_REF']; compilerproc; nostackframe; assembler;
asm asm
cmpl $0,(%eax) cmpl $0,(%eax)
jne .Ldecr_ref_continue je .Lquit
ret pushl %esi
.Ldecr_ref_continue: movl (%eax),%esi
// Temps allocated between ebp-24 and ebp+0 subl $12,%esi // points to start of allocation
subl $4,%esp movl $0,(%eax) // s:=nil
// Var S located in register cmpl $0,4(%esi) // exit if refcount<0
// 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)
jl .Lj3596 jl .Lj3596
.Lj3603:
// [104] If declocked(l^) then
{$ifdef FPC_PIC} {$ifdef FPC_PIC}
pushl %ebx pushl %ebx
call fpc_geteipasebx call fpc_geteipasebx
@ -1362,27 +1353,20 @@ asm
cmpl $0,ismultithread cmpl $0,ismultithread
{$endif FPC_PIC} {$endif FPC_PIC}
jne .Lj3610 jne .Lj3610
decl (%edx) decl 4(%esi)
je .Lj3620 je .Lj3620
addl $4,%esp jmp .Lj3596
ret
.Lj3610: .Lj3610:
movl %edx,%eax leal 4(%esi),%eax
call cpudeclocked call cpudeclocked
testb %al,%al testb %al,%al
je .Lj3605 je .Lj3596
.Lj3620: .Lj3620:
movl (%esp),%eax movl %esi,%eax
movl (%eax),%eax
subl $12,%eax
call FPC_FREEMEM_X call FPC_FREEMEM_X
movl (%esp),%eax
movl $0,(%eax)
.Lj3618:
.Lj3605:
.Lj3596: .Lj3596:
// [107] end; popl %esi
addl $4,%esp .Lquit:
end; end;
function fpc_truely_ansistr_unique(Var S : Pointer): Pointer; forward; function fpc_truely_ansistr_unique(Var S : Pointer): Pointer; forward;

View File

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

View File

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