fpc/compiler/jvm/njvmcal.pas
Jonas Maebe 254636ab84 * don't create (useless) temporary array/record/... for the result
of functions at the caller side, since these will already be allocated
    at the callee side
  * added comment to cpupara explaining why we never allocate the function
    result on the caller side and then pass it as an invisible parameter,
    but instead always let the callee allocate it

git-svn-id: branches/jvmbackend@18420 -
2011-08-20 07:58:09 +00:00

143 lines
5.0 KiB
ObjectPascal

{
Copyright (c) 2011 by Jonas Maebe
JVM-specific code for call nodes
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
unit njvmcal;
{$i fpcdefs.inc}
interface
uses
symdef,
ncgcal;
type
{ tjvmcallnode }
tjvmcallnode = class(tcgcallnode)
protected
procedure extra_pre_call_code; override;
procedure set_result_location(realresdef: tstoreddef); override;
procedure do_release_unused_return_value;override;
procedure extra_post_call_code; override;
end;
implementation
uses
verbose,globtype,
symconst,symtype,defutil,ncal,
cgbase,cgutils,tgobj,procinfo,
cpubase,aasmdata,aasmcpu,
hlcgobj,hlcgcpu,
jvmdef;
{*****************************************************************************
TJVMCALLNODE
*****************************************************************************}
procedure tjvmcallnode.extra_pre_call_code;
begin
{ when calling a constructor, first create a new instance, except
when calling it from another constructor (because then this has
already been done before calling the current constructor) }
if procdefinition.typ<>procdef then
exit;
if tprocdef(procdefinition).proctypeoption<>potype_constructor then
exit;
if (methodpointer.resultdef.typ<>classrefdef) then
exit;
current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_new,current_asmdata.RefAsmSymbol(tobjectdef(tprocdef(procdefinition).owner.defowner).jvm_full_typename(true))));
{ the constructor doesn't return anything, so put a duplicate of the
self pointer on the evaluation stack for use as function result
after the constructor has run }
current_asmdata.CurrAsmList.concat(taicpu.op_none(a_dup));
thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,2);
end;
procedure tjvmcallnode.set_result_location(realresdef: tstoreddef);
begin
location_reset_ref(location,LOC_REFERENCE,def_cgsize(realresdef),1);
{ in case of jvmimplicitpointertype(), the function will have allocated
it already and we don't have to allocate it again here }
if not jvmimplicitpointertype(realresdef) then
tg.gethltemp(current_asmdata.CurrAsmList,realresdef,realresdef.size,tt_normal,location.reference)
else
tg.gethltemp(current_asmdata.CurrAsmList,java_jlobject,java_jlobject.size,tt_normal,location.reference);
end;
procedure tjvmcallnode.do_release_unused_return_value;
begin
if (tprocdef(procdefinition).proctypeoption=potype_constructor) and
(current_procinfo.procdef.proctypeoption=potype_constructor) then
exit;
case resultdef.size of
0:
;
1..4:
begin
current_asmdata.CurrAsmList.concat(taicpu.op_none(a_pop));
thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,1);
end;
8:
begin
current_asmdata.CurrAsmList.concat(taicpu.op_none(a_pop2));
thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,2);
end
else
internalerror(2011010305);
end;
end;
procedure tjvmcallnode.extra_post_call_code;
var
totalremovesize: longint;
realresdef: tdef;
begin
if not assigned(typedef) then
realresdef:=tstoreddef(resultdef)
else
realresdef:=tstoreddef(typedef);
{ a constructor doesn't actually return a value in the jvm }
if (tprocdef(procdefinition).proctypeoption=potype_constructor) then
totalremovesize:=pushedparasize
else
{ even a byte takes up a full stackslot -> align size to multiple of 4 }
totalremovesize:=pushedparasize-(align(realresdef.size,4) shr 2);
{ remove parameters from internal evaluation stack counter (in case of
e.g. no parameters and a result, it can also increase) }
if totalremovesize>0 then
thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,totalremovesize)
else if totalremovesize<0 then
thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,-totalremovesize);
end;
begin
ccallnode:=tjvmcallnode;
end.