mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-13 12:39:09 +02:00
* also set aktcallnode during tcallnode.pass_1, so that the callparanode
pass_1 code can make use of it git-svn-id: trunk@29818 -
This commit is contained in:
parent
863e81315e
commit
aae879d28a
@ -3600,123 +3600,131 @@ implementation
|
|||||||
|
|
||||||
var
|
var
|
||||||
para: tcallparanode;
|
para: tcallparanode;
|
||||||
|
oldcallnode: tcallnode;
|
||||||
begin
|
begin
|
||||||
result:=nil;
|
result:=nil;
|
||||||
|
|
||||||
{ as pass_1 is never called on the methodpointer node, we must check
|
oldcallnode:=aktcallnode;
|
||||||
here that it's not a helper type }
|
aktcallnode:=self;
|
||||||
if assigned(methodpointer) and
|
|
||||||
(methodpointer.nodetype=typen) and
|
|
||||||
is_objectpascal_helper(ttypenode(methodpointer).typedef) and
|
|
||||||
not ttypenode(methodpointer).helperallowed then
|
|
||||||
Message(parser_e_no_category_as_types);
|
|
||||||
|
|
||||||
{ can we get rid of the call? }
|
try
|
||||||
if (cs_opt_remove_emtpy_proc in current_settings.optimizerswitches) and
|
{ as pass_1 is never called on the methodpointer node, we must check
|
||||||
not(cnf_return_value_used in callnodeflags) and
|
here that it's not a helper type }
|
||||||
(procdefinition.typ=procdef) and
|
if assigned(methodpointer) and
|
||||||
tprocdef(procdefinition).isempty and
|
(methodpointer.nodetype=typen) and
|
||||||
{ allow only certain proc options }
|
is_objectpascal_helper(ttypenode(methodpointer).typedef) and
|
||||||
((tprocdef(procdefinition).procoptions-[po_none,po_classmethod,po_staticmethod,
|
not ttypenode(methodpointer).helperallowed then
|
||||||
po_interrupt,po_iocheck,po_assembler,po_msgstr,po_msgint,po_exports,po_external,po_overload,
|
Message(parser_e_no_category_as_types);
|
||||||
po_nostackframe,po_has_mangledname,po_has_public_name,po_forward,po_global,
|
|
||||||
po_inline,po_compilerproc,po_has_importdll,po_has_importname,po_kylixlocal,po_dispid,po_delphi_nested_cc,
|
|
||||||
po_rtlproc,po_ignore_for_overload_resolution,po_auto_raised_visibility])=[]) then
|
|
||||||
begin
|
|
||||||
{ check parameters for side effects }
|
|
||||||
para:=tcallparanode(left);
|
|
||||||
while assigned(para) do
|
|
||||||
begin
|
|
||||||
if (para.parasym.typ = paravarsym) and
|
|
||||||
((para.parasym.refs>0) or
|
|
||||||
{ array of consts are converted later on so we need to skip them here
|
|
||||||
else no error detection is done }
|
|
||||||
is_array_of_const(para.parasym.vardef) or
|
|
||||||
not(cs_opt_dead_values in current_settings.optimizerswitches) or
|
|
||||||
might_have_sideeffects(para.left)) then
|
|
||||||
break;
|
|
||||||
para:=tcallparanode(para.right);
|
|
||||||
end;
|
|
||||||
{ finally, remove it if no parameter with side effect has been found }
|
|
||||||
if para=nil then
|
|
||||||
begin
|
|
||||||
result:=cnothingnode.create;
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ convert Objective-C calls into a message call }
|
{ can we get rid of the call? }
|
||||||
if (procdefinition.typ=procdef) and
|
if (cs_opt_remove_emtpy_proc in current_settings.optimizerswitches) and
|
||||||
(po_objc in tprocdef(procdefinition).procoptions) then
|
not(cnf_return_value_used in callnodeflags) and
|
||||||
begin
|
(procdefinition.typ=procdef) and
|
||||||
if not(cnf_objc_processed in callnodeflags) then
|
tprocdef(procdefinition).isempty and
|
||||||
objc_convert_to_message_send;
|
{ allow only certain proc options }
|
||||||
end
|
((tprocdef(procdefinition).procoptions-[po_none,po_classmethod,po_staticmethod,
|
||||||
else
|
po_interrupt,po_iocheck,po_assembler,po_msgstr,po_msgint,po_exports,po_external,po_overload,
|
||||||
begin
|
po_nostackframe,po_has_mangledname,po_has_public_name,po_forward,po_global,
|
||||||
{ The following don't apply to obj-c: obj-c methods can never be
|
po_inline,po_compilerproc,po_has_importdll,po_has_importname,po_kylixlocal,po_dispid,po_delphi_nested_cc,
|
||||||
inlined because they're always virtual and the destination can
|
po_rtlproc,po_ignore_for_overload_resolution,po_auto_raised_visibility])=[]) then
|
||||||
change at run, and for the same reason we also can't perform
|
begin
|
||||||
WPO on them (+ they have no constructors) }
|
{ check parameters for side effects }
|
||||||
|
para:=tcallparanode(left);
|
||||||
|
while assigned(para) do
|
||||||
|
begin
|
||||||
|
if (para.parasym.typ = paravarsym) and
|
||||||
|
((para.parasym.refs>0) or
|
||||||
|
{ array of consts are converted later on so we need to skip them here
|
||||||
|
else no error detection is done }
|
||||||
|
is_array_of_const(para.parasym.vardef) or
|
||||||
|
not(cs_opt_dead_values in current_settings.optimizerswitches) or
|
||||||
|
might_have_sideeffects(para.left)) then
|
||||||
|
break;
|
||||||
|
para:=tcallparanode(para.right);
|
||||||
|
end;
|
||||||
|
{ finally, remove it if no parameter with side effect has been found }
|
||||||
|
if para=nil then
|
||||||
|
begin
|
||||||
|
result:=cnothingnode.create;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{ Check if the call can be inlined, sets the cnf_do_inline flag }
|
{ convert Objective-C calls into a message call }
|
||||||
check_inlining;
|
if (procdefinition.typ=procdef) and
|
||||||
|
(po_objc in tprocdef(procdefinition).procoptions) then
|
||||||
|
begin
|
||||||
|
if not(cnf_objc_processed in callnodeflags) then
|
||||||
|
objc_convert_to_message_send;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
{ The following don't apply to obj-c: obj-c methods can never be
|
||||||
|
inlined because they're always virtual and the destination can
|
||||||
|
change at run, and for the same reason we also can't perform
|
||||||
|
WPO on them (+ they have no constructors) }
|
||||||
|
|
||||||
{ must be called before maybe_load_in_temp(methodpointer), because
|
{ Check if the call can be inlined, sets the cnf_do_inline flag }
|
||||||
it converts the methodpointer into a temp in case it's a call
|
check_inlining;
|
||||||
(and we want to know the original call)
|
|
||||||
}
|
|
||||||
register_created_object_types;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ Maybe optimize the loading of the methodpointer using a temp. When the methodpointer
|
{ must be called before maybe_load_in_temp(methodpointer), because
|
||||||
is a calln this is even required to not execute the calln twice.
|
it converts the methodpointer into a temp in case it's a call
|
||||||
This needs to be done after the resulttype pass, because in the resulttype we can still convert the
|
(and we want to know the original call)
|
||||||
calln to a loadn (PFV) }
|
}
|
||||||
if assigned(methodpointer) then
|
register_created_object_types;
|
||||||
maybe_load_in_temp(methodpointer);
|
end;
|
||||||
|
|
||||||
{ Create destination (temp or assignment-variable reuse) for function result if it not yet set }
|
{ Maybe optimize the loading of the methodpointer using a temp. When the methodpointer
|
||||||
maybe_create_funcret_node;
|
is a calln this is even required to not execute the calln twice.
|
||||||
|
This needs to be done after the resulttype pass, because in the resulttype we can still convert the
|
||||||
|
calln to a loadn (PFV) }
|
||||||
|
if assigned(methodpointer) then
|
||||||
|
maybe_load_in_temp(methodpointer);
|
||||||
|
|
||||||
{ Insert the self,vmt,function result in the parameters }
|
{ Create destination (temp or assignment-variable reuse) for function result if it not yet set }
|
||||||
gen_hidden_parameters;
|
maybe_create_funcret_node;
|
||||||
|
|
||||||
{ Remove useless nodes from init/final blocks }
|
{ Insert the self,vmt,function result in the parameters }
|
||||||
{ (simplify depends on typecheck info) }
|
gen_hidden_parameters;
|
||||||
if assigned(callinitblock) then
|
|
||||||
begin
|
|
||||||
typecheckpass(tnode(callinitblock));
|
|
||||||
doinlinesimplify(tnode(callinitblock));
|
|
||||||
end;
|
|
||||||
if assigned(callcleanupblock) then
|
|
||||||
begin
|
|
||||||
typecheckpass(tnode(callcleanupblock));
|
|
||||||
doinlinesimplify(tnode(callcleanupblock));
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ If a constructor calls another constructor of the same or of an
|
{ Remove useless nodes from init/final blocks }
|
||||||
inherited class, some targets (jvm) have to generate different
|
{ (simplify depends on typecheck info) }
|
||||||
entry code for the constructor. }
|
if assigned(callinitblock) then
|
||||||
if (current_procinfo.procdef.proctypeoption=potype_constructor) and
|
begin
|
||||||
(procdefinition.typ=procdef) and
|
typecheckpass(tnode(callinitblock));
|
||||||
(tprocdef(procdefinition).proctypeoption=potype_constructor) and
|
doinlinesimplify(tnode(callinitblock));
|
||||||
([cnf_member_call,cnf_inherited] * callnodeflags <> []) then
|
end;
|
||||||
current_procinfo.ConstructorCallingConstructor:=true;
|
if assigned(callcleanupblock) then
|
||||||
|
begin
|
||||||
|
typecheckpass(tnode(callcleanupblock));
|
||||||
|
doinlinesimplify(tnode(callcleanupblock));
|
||||||
|
end;
|
||||||
|
|
||||||
{ object check helper will load VMT -> needs GOT }
|
{ If a constructor calls another constructor of the same or of an
|
||||||
if (cs_check_object in current_settings.localswitches) and
|
inherited class, some targets (jvm) have to generate different
|
||||||
(cs_create_pic in current_settings.moduleswitches) then
|
entry code for the constructor. }
|
||||||
include(current_procinfo.flags,pi_needs_got);
|
if (current_procinfo.procdef.proctypeoption=potype_constructor) and
|
||||||
|
(procdefinition.typ=procdef) and
|
||||||
|
(tprocdef(procdefinition).proctypeoption=potype_constructor) and
|
||||||
|
([cnf_member_call,cnf_inherited] * callnodeflags <> []) then
|
||||||
|
current_procinfo.ConstructorCallingConstructor:=true;
|
||||||
|
|
||||||
{ Continue with checking a normal call or generate the inlined code }
|
{ object check helper will load VMT -> needs GOT }
|
||||||
if cnf_do_inline in callnodeflags then
|
if (cs_check_object in current_settings.localswitches) and
|
||||||
result:=pass1_inline
|
(cs_create_pic in current_settings.moduleswitches) then
|
||||||
else
|
include(current_procinfo.flags,pi_needs_got);
|
||||||
begin
|
|
||||||
mark_unregable_parameters;
|
{ Continue with checking a normal call or generate the inlined code }
|
||||||
result:=pass1_normal;
|
if cnf_do_inline in callnodeflags then
|
||||||
end;
|
result:=pass1_inline
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
mark_unregable_parameters;
|
||||||
|
result:=pass1_normal;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
aktcallnode:=oldcallnode;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user