mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-06-02 17:22:42 +02:00
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:
parent
afb4992113
commit
06192a8137
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
@ -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 :
|
||||||
|
@ -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 }
|
||||||
|
@ -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',
|
||||||
|
@ -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;
|
||||||
|
@ -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}
|
||||||
|
@ -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 }
|
||||||
|
Loading…
Reference in New Issue
Block a user