njvmcal.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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. symtype,symdef,
  23. ncgcal;
  24. type
  25. tjvmcallparanode = class(tcgcallparanode)
  26. protected
  27. outcopybasereg: tregister;
  28. procedure push_formal_para; override;
  29. procedure push_copyout_para; override;
  30. procedure load_arrayref_para(useparadef: tdef);
  31. end;
  32. { tjvmcallnode }
  33. tjvmcallnode = class(tcgcallnode)
  34. protected
  35. procedure extra_pre_call_code; override;
  36. procedure set_result_location(realresdef: tstoreddef); override;
  37. procedure do_release_unused_return_value;override;
  38. procedure extra_post_call_code; override;
  39. end;
  40. implementation
  41. uses
  42. verbose,globtype,
  43. symconst,defutil,ncal,
  44. cgutils,tgobj,procinfo,
  45. cpubase,aasmdata,aasmcpu,
  46. hlcgobj,hlcgcpu,
  47. node,
  48. jvmdef;
  49. {*****************************************************************************
  50. TJVMCALLPARANODE
  51. *****************************************************************************}
  52. procedure tjvmcallparanode.load_arrayref_para(useparadef: tdef);
  53. var
  54. arrayloc: tlocation;
  55. arrayref: treference;
  56. begin
  57. { cannot be a regular array or record, because those are passed by
  58. plain reference (since they are reference types at the Java level,
  59. but not at the Pascal level) -> no special initialisation necessary }
  60. outcopybasereg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,java_jlobject);
  61. thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,java_jlobject,outcopybasereg);
  62. reference_reset_base(arrayref,outcopybasereg,0,4);
  63. arrayref.arrayreftype:=art_indexconst;
  64. arrayref.indexoffset:=0;
  65. { load the current parameter value into the array in case it's not an
  66. out-parameter; if it's an out-parameter the contents must be nil
  67. but that's already ok, since the anewarray opcode takes care of that }
  68. if (parasym.varspez<>vs_out) then
  69. hlcg.a_load_loc_ref(current_asmdata.CurrAsmList,useparadef,useparadef,left.location,arrayref);
  70. { store the array reference into the parameter location (don't change
  71. left.location, we may need it for copy-back after the call) }
  72. location_reset(arrayloc,LOC_REGISTER,OS_ADDR);
  73. arrayloc.register:=outcopybasereg;
  74. hlcg.gen_load_loc_cgpara(current_asmdata.CurrAsmList,java_jlobject,arrayloc,tempcgpara)
  75. end;
  76. procedure tjvmcallparanode.push_formal_para;
  77. var
  78. primitivetype: boolean;
  79. begin
  80. { create an array with one element of JLObject }
  81. thlcgjvm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,s32inttype,1,R_INTREGISTER);
  82. { left is either an object-derived type, or has been boxed into one }
  83. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_anewarray,current_asmdata.RefAsmSymbol(jvmarrtype(java_jlobject,primitivetype))));
  84. load_arrayref_para(java_jlobject);
  85. end;
  86. procedure tjvmcallparanode.push_copyout_para;
  87. var
  88. mangledname: string;
  89. primitivetype: boolean;
  90. opc: tasmop;
  91. begin
  92. { create an array with one element of the parameter type }
  93. thlcgjvm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,s32inttype,1,R_INTREGISTER);
  94. mangledname:=jvmarrtype(left.resultdef,primitivetype);
  95. if primitivetype then
  96. opc:=a_newarray
  97. else
  98. opc:=a_anewarray;
  99. { doesn't change stack height: one int replaced by one reference }
  100. current_asmdata.CurrAsmList.concat(taicpu.op_sym(opc,current_asmdata.RefAsmSymbol(mangledname)));
  101. load_arrayref_para(left.resultdef);
  102. end;
  103. {*****************************************************************************
  104. TJVMCALLNODE
  105. *****************************************************************************}
  106. procedure tjvmcallnode.extra_pre_call_code;
  107. begin
  108. { when calling a constructor, first create a new instance, except
  109. when calling it from another constructor (because then this has
  110. already been done before calling the current constructor) }
  111. if procdefinition.typ<>procdef then
  112. exit;
  113. if tabstractprocdef(procdefinition).proctypeoption<>potype_constructor then
  114. exit;
  115. if not(methodpointer.resultdef.typ in [classrefdef,recorddef]) then
  116. exit;
  117. current_asmdata.CurrAsmList.concat(taicpu.op_sym(a_new,current_asmdata.RefAsmSymbol(tabstractrecorddef(tabstractprocdef(procdefinition).owner.defowner).jvm_full_typename(true))));
  118. { the constructor doesn't return anything, so put a duplicate of the
  119. self pointer on the evaluation stack for use as function result
  120. after the constructor has run }
  121. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_dup));
  122. thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,2);
  123. end;
  124. procedure tjvmcallnode.set_result_location(realresdef: tstoreddef);
  125. begin
  126. location_reset_ref(location,LOC_REFERENCE,def_cgsize(realresdef),1);
  127. { in case of jvmimplicitpointertype(), the function will have allocated
  128. it already and we don't have to allocate it again here }
  129. if not jvmimplicitpointertype(realresdef) then
  130. tg.gethltemp(current_asmdata.CurrAsmList,realresdef,realresdef.size,tt_normal,location.reference)
  131. else
  132. tg.gethltemp(current_asmdata.CurrAsmList,java_jlobject,java_jlobject.size,tt_normal,location.reference);
  133. end;
  134. procedure tjvmcallnode.do_release_unused_return_value;
  135. begin
  136. if (tabstractprocdef(procdefinition).proctypeoption=potype_constructor) and
  137. (current_procinfo.procdef.proctypeoption=potype_constructor) then
  138. exit;
  139. if (location.loc=LOC_REFERENCE) then
  140. tg.ungetiftemp(current_asmdata.CurrAsmList,location.reference);
  141. if assigned(funcretnode) then
  142. exit;
  143. case resultdef.size of
  144. 0:
  145. ;
  146. 1..4:
  147. begin
  148. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_pop));
  149. thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  150. end;
  151. 8:
  152. begin
  153. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_pop2));
  154. thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,2);
  155. end
  156. else
  157. internalerror(2011010305);
  158. end;
  159. end;
  160. procedure tjvmcallnode.extra_post_call_code;
  161. var
  162. totalremovesize: longint;
  163. realresdef: tdef;
  164. ppn: tjvmcallparanode;
  165. pararef: treference;
  166. begin
  167. if not assigned(typedef) then
  168. realresdef:=tstoreddef(resultdef)
  169. else
  170. realresdef:=tstoreddef(typedef);
  171. { a constructor doesn't actually return a value in the jvm }
  172. if (tabstractprocdef(procdefinition).proctypeoption=potype_constructor) then
  173. totalremovesize:=pushedparasize
  174. else
  175. { even a byte takes up a full stackslot -> align size to multiple of 4 }
  176. totalremovesize:=pushedparasize-(align(realresdef.size,4) shr 2);
  177. { remove parameters from internal evaluation stack counter (in case of
  178. e.g. no parameters and a result, it can also increase) }
  179. if totalremovesize>0 then
  180. thlcgjvm(hlcg).decstack(current_asmdata.CurrAsmList,totalremovesize)
  181. else if totalremovesize<0 then
  182. thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,-totalremovesize);
  183. { if this was an inherited constructor call, initialise all fields that
  184. are wrapped types following it }
  185. if (tabstractprocdef(procdefinition).proctypeoption=potype_constructor) and
  186. (cnf_inherited in callnodeflags) then
  187. thlcgjvm(hlcg).gen_initialize_fields_code(current_asmdata.CurrAsmList);
  188. { copy back the copyout parameter values, if any }
  189. { Release temps from parameters }
  190. ppn:=tjvmcallparanode(left);
  191. while assigned(ppn) do
  192. begin
  193. if assigned(ppn.left) then
  194. begin
  195. if (ppn.outcopybasereg<>NR_NO) then
  196. begin
  197. reference_reset_base(pararef,NR_NO,0,4);
  198. pararef.arrayreftype:=art_indexconst;
  199. pararef.base:=ppn.outcopybasereg;
  200. pararef.indexoffset:=0;
  201. { the value has to be copied back into persistent storage }
  202. if (ppn.parasym.vardef.typ<>formaldef) then
  203. begin
  204. case ppn.left.location.loc of
  205. LOC_REFERENCE:
  206. hlcg.a_load_ref_ref(current_asmdata.CurrAsmList,ppn.left.resultdef,ppn.left.resultdef,pararef,ppn.left.location.reference);
  207. LOC_CREGISTER:
  208. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,ppn.left.resultdef,ppn.left.resultdef,pararef,ppn.left.location.register);
  209. else
  210. internalerror(2011051201);
  211. end;
  212. end
  213. else
  214. begin
  215. {$ifndef nounsupported}
  216. { to do: extract value from boxed parameter or load
  217. value back }
  218. {$else}
  219. internalerror(2011051901);
  220. {$endif}
  221. end;
  222. end;
  223. end;
  224. ppn:=tjvmcallparanode(ppn.right);
  225. end;
  226. end;
  227. begin
  228. ccallnode:=tjvmcallnode;
  229. ccallparanode:=tjvmcallparanode;
  230. end.