njvmcal.pas 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. {
  2. Copyright (c) 2011 by Jonas Maebe
  3. JVM-specific code for call nodes
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit njvmcal;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cgbase,
  22. symdef,
  23. ncgcal;
  24. type
  25. tjvmcallparanode = class(tcgcallparanode)
  26. protected
  27. outcopybasereg: tregister;
  28. procedure push_copyout_para; override;
  29. end;
  30. { tjvmcallnode }
  31. tjvmcallnode = class(tcgcallnode)
  32. protected
  33. procedure extra_pre_call_code; override;
  34. procedure set_result_location(realresdef: tstoreddef); override;
  35. procedure do_release_unused_return_value;override;
  36. procedure extra_post_call_code; override;
  37. end;
  38. implementation
  39. uses
  40. verbose,globtype,
  41. symconst,symtype,defutil,ncal,
  42. cgutils,tgobj,procinfo,
  43. cpubase,aasmdata,aasmcpu,
  44. hlcgobj,hlcgcpu,
  45. node,
  46. jvmdef;
  47. {*****************************************************************************
  48. TJVMCALLPARANODE
  49. *****************************************************************************}
  50. procedure tjvmcallparanode.push_copyout_para;
  51. var
  52. mangledname: string;
  53. primitivetype: boolean;
  54. opc: tasmop;
  55. arrayloc: tlocation;
  56. arrayref: treference;
  57. begin
  58. { create an array with one element of the parameter type }
  59. thlcgjvm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,s32inttype,1,R_INTREGISTER);
  60. mangledname:=jvmarrtype(left.resultdef,primitivetype);
  61. if primitivetype then
  62. opc:=a_newarray
  63. else
  64. opc:=a_anewarray;
  65. { doesn't change stack height: one int replaced by one reference }
  66. current_asmdata.CurrAsmList.concat(taicpu.op_sym(opc,current_asmdata.RefAsmSymbol(mangledname)));
  67. { cannot be a regular array or record, because those are passed by
  68. plain reference (since they are reference types at the Java level,
  69. but not at the Pascal level) -> no special initialisation necessary }
  70. outcopybasereg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,java_jlobject);
  71. thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,java_jlobject,outcopybasereg);
  72. reference_reset_base(arrayref,outcopybasereg,0,4);
  73. arrayref.arrayreftype:=art_indexconst;
  74. arrayref.indexoffset:=0;
  75. { load the current parameter value into the array in case it's not an
  76. out-parameter; if it's an out-parameter the contents must be nil
  77. but that's already ok, since the anewarray opcode takes care of that }
  78. if (parasym.varspez<>vs_out) then
  79. hlcg.a_load_loc_ref(current_asmdata.CurrAsmList,left.resultdef,left.resultdef,left.location,arrayref);
  80. { store the array reference into the parameter location (don't change
  81. left.location, we may need it for copy-back after the call) }
  82. location_reset(arrayloc,LOC_REGISTER,OS_ADDR);
  83. arrayloc.register:=outcopybasereg;
  84. hlcg.gen_load_loc_cgpara(current_asmdata.CurrAsmList,java_jlobject,arrayloc,tempcgpara)
  85. end;
  86. {*****************************************************************************
  87. TJVMCALLNODE
  88. *****************************************************************************}
  89. procedure tjvmcallnode.extra_pre_call_code;
  90. begin
  91. { when calling a constructor, first create a new instance, except
  92. when calling it from another constructor (because then this has
  93. already been done before calling the current constructor) }
  94. if procdefinition.typ<>procdef then
  95. exit;
  96. if tabstractprocdef(procdefinition).proctypeoption<>potype_constructor then
  97. exit;
  98. if not(methodpointer.resultdef.typ in [classrefdef,recorddef]) then
  99. exit;
  100. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_new,current_asmdata.RefAsmSymbol(tabstractrecorddef(tabstractprocdef(procdefinition).owner.defowner).jvm_full_typename(true))));
  101. { the constructor doesn't return anything, so put a duplicate of the
  102. self pointer on the evaluation stack for use as function result
  103. after the constructor has run }
  104. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_dup));
  105. thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,2);
  106. end;
  107. procedure tjvmcallnode.set_result_location(realresdef: tstoreddef);
  108. begin
  109. location_reset_ref(location,LOC_REFERENCE,def_cgsize(realresdef),1);
  110. { in case of jvmimplicitpointertype(), the function will have allocated
  111. it already and we don't have to allocate it again here }
  112. if not jvmimplicitpointertype(realresdef) then
  113. tg.gethltemp(current_asmdata.CurrAsmList,realresdef,realresdef.size,tt_normal,location.reference)
  114. else
  115. tg.gethltemp(current_asmdata.CurrAsmList,java_jlobject,java_jlobject.size,tt_normal,location.reference);
  116. end;
  117. procedure tjvmcallnode.do_release_unused_return_value;
  118. begin
  119. if (tabstractprocdef(procdefinition).proctypeoption=potype_constructor) and
  120. (current_procinfo.procdef.proctypeoption=potype_constructor) then
  121. exit;
  122. case resultdef.size of
  123. 0:
  124. ;
  125. 1..4:
  126. begin
  127. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_pop));
  128. thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  129. end;
  130. 8:
  131. begin
  132. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_pop2));
  133. thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,2);
  134. end
  135. else
  136. internalerror(2011010305);
  137. end;
  138. end;
  139. procedure tjvmcallnode.extra_post_call_code;
  140. var
  141. totalremovesize: longint;
  142. realresdef: tdef;
  143. ppn: tjvmcallparanode;
  144. pararef: treference;
  145. begin
  146. if not assigned(typedef) then
  147. realresdef:=tstoreddef(resultdef)
  148. else
  149. realresdef:=tstoreddef(typedef);
  150. { a constructor doesn't actually return a value in the jvm }
  151. if (tabstractprocdef(procdefinition).proctypeoption=potype_constructor) then
  152. totalremovesize:=pushedparasize
  153. else
  154. { even a byte takes up a full stackslot -> align size to multiple of 4 }
  155. totalremovesize:=pushedparasize-(align(realresdef.size,4) shr 2);
  156. { remove parameters from internal evaluation stack counter (in case of
  157. e.g. no parameters and a result, it can also increase) }
  158. if totalremovesize>0 then
  159. thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,totalremovesize)
  160. else if totalremovesize<0 then
  161. thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,-totalremovesize);
  162. { if this was an inherited constructor call, initialise all fields that
  163. are wrapped types following it }
  164. if (tabstractprocdef(procdefinition).proctypeoption=potype_constructor) and
  165. (cnf_inherited in callnodeflags) then
  166. thlcgjvm(hlcg).gen_initialize_fields_code(current_asmdata.CurrAsmList);
  167. { copy back the copyout parameter values, if any }
  168. { Release temps from parameters }
  169. ppn:=tjvmcallparanode(left);
  170. while assigned(ppn) do
  171. begin
  172. if assigned(ppn.left) then
  173. begin
  174. if (ppn.outcopybasereg<>NR_NO) then
  175. begin
  176. reference_reset_base(pararef,NR_NO,0,4);
  177. pararef.arrayreftype:=art_indexconst;
  178. pararef.base:=ppn.outcopybasereg;
  179. pararef.indexoffset:=0;
  180. { the value has to be copied back into persistent storage }
  181. case ppn.left.location.loc of
  182. LOC_REFERENCE:
  183. hlcg.a_load_ref_ref(current_asmdata.CurrAsmList,ppn.left.resultdef,ppn.left.resultdef,pararef,ppn.left.location.reference);
  184. LOC_CREGISTER:
  185. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,ppn.left.resultdef,ppn.left.resultdef,pararef,ppn.left.location.register);
  186. else
  187. internalerror(2011051201);
  188. end;
  189. end;
  190. end;
  191. ppn:=tjvmcallparanode(ppn.right);
  192. end;
  193. end;
  194. begin
  195. ccallnode:=tjvmcallnode;
  196. ccallparanode:=tjvmcallparanode;
  197. end.