123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- {
- 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
- cgbase,
- symtype,symdef,
- ncgcal;
- type
- tjvmcallparanode = class(tcgcallparanode)
- protected
- outcopybasereg: tregister;
- procedure push_formal_para; override;
- procedure push_copyout_para; override;
- procedure load_arrayref_para(useparadef: tdef);
- end;
- { 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,defutil,ncal,
- cgutils,tgobj,procinfo,
- cpubase,aasmdata,aasmcpu,
- hlcgobj,hlcgcpu,
- node,
- jvmdef;
- {*****************************************************************************
- TJVMCALLPARANODE
- *****************************************************************************}
- procedure tjvmcallparanode.load_arrayref_para(useparadef: tdef);
- var
- arrayloc: tlocation;
- arrayref: treference;
- begin
- { cannot be a regular array or record, because those are passed by
- plain reference (since they are reference types at the Java level,
- but not at the Pascal level) -> no special initialisation necessary }
- outcopybasereg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,java_jlobject);
- thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,java_jlobject,outcopybasereg);
- reference_reset_base(arrayref,outcopybasereg,0,4);
- arrayref.arrayreftype:=art_indexconst;
- arrayref.indexoffset:=0;
- { load the current parameter value into the array in case it's not an
- out-parameter; if it's an out-parameter the contents must be nil
- but that's already ok, since the anewarray opcode takes care of that }
- if (parasym.varspez<>vs_out) then
- hlcg.a_load_loc_ref(current_asmdata.CurrAsmList,useparadef,useparadef,left.location,arrayref);
- { store the array reference into the parameter location (don't change
- left.location, we may need it for copy-back after the call) }
- location_reset(arrayloc,LOC_REGISTER,OS_ADDR);
- arrayloc.register:=outcopybasereg;
- hlcg.gen_load_loc_cgpara(current_asmdata.CurrAsmList,java_jlobject,arrayloc,tempcgpara)
- end;
- procedure tjvmcallparanode.push_formal_para;
- var
- primitivetype: boolean;
- begin
- { create an array with one element of JLObject }
- thlcgjvm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,s32inttype,1,R_INTREGISTER);
- { left is either an object-derived type, or has been boxed into one }
- current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_anewarray,current_asmdata.RefAsmSymbol(jvmarrtype(java_jlobject,primitivetype))));
- load_arrayref_para(java_jlobject);
- end;
- procedure tjvmcallparanode.push_copyout_para;
- var
- mangledname: string;
- primitivetype: boolean;
- opc: tasmop;
- begin
- { create an array with one element of the parameter type }
- thlcgjvm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,s32inttype,1,R_INTREGISTER);
- mangledname:=jvmarrtype(left.resultdef,primitivetype);
- if primitivetype then
- opc:=a_newarray
- else
- opc:=a_anewarray;
- { doesn't change stack height: one int replaced by one reference }
- current_asmdata.CurrAsmList.concat(taicpu.op_sym(opc,current_asmdata.RefAsmSymbol(mangledname)));
- load_arrayref_para(left.resultdef);
- end;
- {*****************************************************************************
- 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 tabstractprocdef(procdefinition).proctypeoption<>potype_constructor then
- exit;
- if not(methodpointer.resultdef.typ in [classrefdef,recorddef]) then
- exit;
- current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_new,current_asmdata.RefAsmSymbol(tabstractrecorddef(tabstractprocdef(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 (tabstractprocdef(procdefinition).proctypeoption=potype_constructor) and
- (current_procinfo.procdef.proctypeoption=potype_constructor) then
- exit;
- if (location.loc=LOC_REFERENCE) then
- tg.ungetiftemp(current_asmdata.CurrAsmList,location.reference);
- if assigned(funcretnode) 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;
- ppn: tjvmcallparanode;
- pararef: treference;
- 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 (tabstractprocdef(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);
- { if this was an inherited constructor call, initialise all fields that
- are wrapped types following it }
- if (tabstractprocdef(procdefinition).proctypeoption=potype_constructor) and
- (cnf_inherited in callnodeflags) then
- thlcgjvm(hlcg).gen_initialize_fields_code(current_asmdata.CurrAsmList);
- { copy back the copyout parameter values, if any }
- { Release temps from parameters }
- ppn:=tjvmcallparanode(left);
- while assigned(ppn) do
- begin
- if assigned(ppn.left) then
- begin
- if (ppn.outcopybasereg<>NR_NO) then
- begin
- reference_reset_base(pararef,NR_NO,0,4);
- pararef.arrayreftype:=art_indexconst;
- pararef.base:=ppn.outcopybasereg;
- pararef.indexoffset:=0;
- { the value has to be copied back into persistent storage }
- if (ppn.parasym.vardef.typ<>formaldef) then
- begin
- case ppn.left.location.loc of
- LOC_REFERENCE:
- hlcg.a_load_ref_ref(current_asmdata.CurrAsmList,ppn.left.resultdef,ppn.left.resultdef,pararef,ppn.left.location.reference);
- LOC_CREGISTER:
- hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,ppn.left.resultdef,ppn.left.resultdef,pararef,ppn.left.location.register);
- else
- internalerror(2011051201);
- end;
- end
- else
- begin
- {$ifndef nounsupported}
- { to do: extract value from boxed parameter or load
- value back }
- {$else}
- internalerror(2011051901);
- {$endif}
- end;
- end;
- end;
- ppn:=tjvmcallparanode(ppn.right);
- end;
- end;
- begin
- ccallnode:=tjvmcallnode;
- ccallparanode:=tjvmcallparanode;
- end.
|