* Changed code generation for assignments of managed types, it now generates a single call to helper procedure (significantly reducing code size) and is handled entirely in firstpass.

git-svn-id: trunk@20118 -
This commit is contained in:
sergei 2012-01-19 22:28:29 +00:00
parent 76fb845f4a
commit afb4992113
2 changed files with 54 additions and 65 deletions

View File

@ -574,6 +574,9 @@ implementation
oldflowcontrol : tflowcontrol;
begin
location_reset(location,LOC_VOID,OS_NO);
{ managed types should be handled in firstpass }
if is_managed_type(left.resultdef) or is_managed_type(right.resultdef) then
InternalError(2012011901);
otlabel:=current_procinfo.CurrTrueLabel;
oflabel:=current_procinfo.CurrFalseLabel;
@ -594,31 +597,13 @@ implementation
loading the left node afterwards can destroy the flags.
}
if not(right.expectloc in [LOC_FLAGS,LOC_JUMP]) and
(is_managed_type(right.resultdef) or
(node_complexity(right)>node_complexity(left))) then
(node_complexity(right)>node_complexity(left)) then
begin
secondpass(right);
{ increment source reference counter, this is
useless for constants }
if is_managed_type(right.resultdef) and
not is_constnode(right) then
begin
location_force_mem(current_asmdata.CurrAsmList,right.location);
location_get_data_ref(current_asmdata.CurrAsmList,right.location,href,false,sizeof(pint));
cg.g_incrrefcount(current_asmdata.CurrAsmList,right.resultdef,href);
end;
if codegenerror then
exit;
{ left can't be never a 64 bit LOC_REGISTER, so the 3. arg }
{ can be false }
secondpass(left);
{ decrement destination reference counter }
if is_managed_type(left.resultdef) then
begin
location_get_data_ref(current_asmdata.CurrAsmList,left.location,href,false,sizeof(pint));
cg.g_decrrefcount(current_asmdata.CurrAsmList,left.resultdef,href);
end;
if codegenerror then
exit;
end
@ -626,12 +611,6 @@ implementation
begin
{ calculate left sides }
secondpass(left);
{ decrement destination reference counter }
if is_managed_type(left.resultdef) then
begin
location_get_data_ref(current_asmdata.CurrAsmList,left.location,href,false,sizeof(pint));
cg.g_decrrefcount(current_asmdata.CurrAsmList,left.resultdef,href);
end;
if codegenerror then
exit;
@ -641,19 +620,8 @@ implementation
oldflowcontrol:=flowcontrol;
include(flowcontrol,fc_lefthandled);
{ left can't be never a 64 bit LOC_REGISTER, so the 3. arg }
{ can be false }
secondpass(right);
flowcontrol:=oldflowcontrol;
{ increment source reference counter, this is
useless for string constants}
if is_managed_type(right.resultdef) and
(right.nodetype<>stringconstn) then
begin
location_force_mem(current_asmdata.CurrAsmList,right.location);
location_get_data_ref(current_asmdata.CurrAsmList,right.location,href,false,sizeof(pint));
cg.g_incrrefcount(current_asmdata.CurrAsmList,right.resultdef,href);
end;
if codegenerror then
exit;

View File

@ -702,6 +702,8 @@ implementation
hp: tnode;
oldassignmentnode : tassignmentnode;
hdef: tdef;
hs: string;
needrtti: boolean;
begin
result:=nil;
expectloc:=LOC_VOID;
@ -731,6 +733,8 @@ implementation
if is_managed_type(left.resultdef) then
include(current_procinfo.flags,pi_do_call);
needrtti:=false;
if (is_shortstring(left.resultdef)) then
begin
if right.resultdef.typ=stringdef then
@ -748,9 +752,9 @@ implementation
firstpass(result);
left:=nil;
right:=nil;
exit;
end;
end;
exit;
end
{ call helpers for composite types containing automated types }
else if is_managed_type(left.resultdef) and
@ -790,34 +794,51 @@ implementation
right:=nil;
exit;
end
{ call helpers for windows widestrings, they aren't ref. counted }
else if (tf_winlikewidestring in target_info.flags) and is_widestring(left.resultdef) then
begin
{ The first argument of fpc_widestr_assign is a var parameter. Properties cannot }
{ be passed to var or out parameters, because in that case setters/getters are not }
{ used. Further, if we would allow it in case there are no getters or setters, you }
{ would need source changes in case these are introduced later on, thus defeating }
{ part of the transparency advantages of properties. In this particular case, }
{ however: }
{ a) if there is a setter, this code will not be used since then the assignment }
{ will be converted to a procedure call }
{ b) the getter is irrelevant, because fpc_widestr_assign must always decrease }
{ the refcount of the field to which we are writing }
{ c) source code changes are not required if a setter is added/removed, because }
{ this transformation is handled at compile time }
{ -> we can remove the nf_isproperty flag (if any) from left, so that in case it }
{ is a property which refers to a field without a setter call, we will not get }
{ an error about trying to pass a property as a var parameter }
exclude(left.flags,nf_isproperty);
hp:=ccallparanode.create(ctypeconvnode.create_internal(right,voidpointertype),
ccallparanode.create(ctypeconvnode.create_internal(left,voidpointertype),
nil));
result:=ccallnode.createintern('fpc_widestr_assign',hp);
firstpass(result);
left:=nil;
right:=nil;
exit;
end;
{ call helpers for pointer-sized managed types }
else if is_widestring(left.resultdef) then
hs:='fpc_widestr_assign'
else if is_ansistring(left.resultdef) then
hs:='fpc_ansistr_assign'
else if is_unicodestring(left.resultdef) then
hs:='fpc_unicodestr_assign'
else if is_interfacecom_or_dispinterface(left.resultdef) then
hs:='fpc_intf_assign'
else if is_dynamic_array(left.resultdef) then
begin
hs:='fpc_dynarray_assign';
needrtti:=true;
end
else
exit;
{ The first argument of these procedures is a var parameter. Properties cannot }
{ be passed to var or out parameters, because in that case setters/getters are not }
{ used. Further, if we would allow it in case there are no getters or setters, you }
{ would need source changes in case these are introduced later on, thus defeating }
{ part of the transparency advantages of properties. In this particular case, }
{ however: }
{ a) if there is a setter, this code will not be used since then the assignment }
{ will be converted to a procedure call }
{ b) the getter is irrelevant, because fpc_widestr_assign must always decrease }
{ the refcount of the field to which we are writing }
{ c) source code changes are not required if a setter is added/removed, because }
{ this transformation is handled at compile time }
{ -> we can remove the nf_isproperty flag (if any) from left, so that in case it }
{ is a property which refers to a field without a setter call, we will not get }
{ an error about trying to pass a property as a var parameter }
exclude(left.flags,nf_isproperty);
hp:=ccallparanode.create(ctypeconvnode.create_internal(right,voidpointertype),
ccallparanode.create(ctypeconvnode.create_internal(left,voidpointertype),
nil));
if needrtti then
hp:=ccallparanode.create(
caddrnode.create_internal(
crttinode.create(tstoreddef(left.resultdef),initrtti,rdt_normal)),
hp);
result:=ccallnode.createintern(hs,hp);
firstpass(result);
left:=nil;
right:=nil;
end;