cpupara.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. {
  2. Copyright (c) 1998-2010 by Florian Klaempfl, Jonas Maebe
  3. Calling conventions for the JVM
  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. unit cpupara;
  17. {$i fpcdefs.inc}
  18. interface
  19. uses
  20. globtype,
  21. cclasses,
  22. aasmtai,aasmdata,
  23. cpubase,cpuinfo,
  24. symconst,symbase,symsym,symtype,symdef,paramgr,parabase,cgbase,cgutils;
  25. type
  26. { tcpuparamanager }
  27. tcpuparamanager=class(TParaManager)
  28. function get_saved_registers_int(calloption: tproccalloption): tcpuregisterarray;override;
  29. function push_high_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
  30. function keep_para_array_range(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean; override;
  31. function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
  32. function push_copyout_param(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean; override;
  33. function push_size(varspez: tvarspez; def: tdef; calloption: tproccalloption): longint;override;
  34. {Returns a structure giving the information on the storage of the parameter
  35. (which must be an integer parameter)
  36. @param(nr Parameter number of routine, starting from 1)}
  37. procedure getintparaloc(list: TAsmList; pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);override;
  38. function create_paraloc_info(p : TAbstractProcDef; side: tcallercallee):longint;override;
  39. function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override;
  40. function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
  41. function param_use_paraloc(const cgpara: tcgpara): boolean; override;
  42. function ret_in_param(def:tdef;pd:tabstractprocdef):boolean;override;
  43. function is_stack_paraloc(paraloc: pcgparalocation): boolean;override;
  44. private
  45. procedure create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  46. var parasize:longint);
  47. end;
  48. implementation
  49. uses
  50. cutils,verbose,systems,
  51. defutil,jvmdef,
  52. aasmcpu,
  53. hlcgobj;
  54. procedure tcpuparamanager.GetIntParaLoc(list: TAsmList; pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);
  55. begin
  56. { not yet implemented/used }
  57. internalerror(2010121001);
  58. end;
  59. function tcpuparamanager.get_saved_registers_int(calloption: tproccalloption): tcpuregisterarray;
  60. const
  61. { dummy, not used for JVM }
  62. saved_regs: array [0..0] of tsuperregister = (RS_NO);
  63. begin
  64. result:=saved_regs;
  65. end;
  66. function tcpuparamanager.push_high_param(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean;
  67. begin
  68. { we don't need a separate high parameter, since all arrays in Java
  69. have an implicit associated length }
  70. if not is_open_array(def) and
  71. not is_array_of_const(def) then
  72. result:=inherited
  73. else
  74. result:=false;
  75. end;
  76. function tcpuparamanager.keep_para_array_range(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean;
  77. begin
  78. { even though these don't need a high parameter (see push_high_param),
  79. we do have to keep the original parameter's array length because it's
  80. used by the compiler (to determine the size of the array to construct
  81. to pass to an array of const parameter) }
  82. if not is_array_of_const(def) then
  83. result:=inherited
  84. else
  85. result:=true;
  86. end;
  87. { true if a parameter is too large to copy and only the address is pushed }
  88. function tcpuparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  89. begin
  90. result:=
  91. jvmimplicitpointertype(def) or
  92. ((def.typ=formaldef) and
  93. not(varspez in [vs_var,vs_out]));
  94. end;
  95. function tcpuparamanager.push_copyout_param(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean;
  96. begin
  97. { in principle also for vs_constref, but since we can't have real
  98. references, that won't make a difference }
  99. result:=
  100. (varspez in [vs_var,vs_out,vs_constref]) and
  101. not jvmimplicitpointertype(def);
  102. end;
  103. function tcpuparamanager.push_size(varspez: tvarspez; def: tdef; calloption: tproccalloption): longint;
  104. begin
  105. { all aggregate types are emulated using indirect pointer types }
  106. if def.typ in [arraydef,recorddef,setdef,stringdef] then
  107. result:=4
  108. else
  109. result:=inherited;
  110. end;
  111. function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  112. var
  113. paraloc : pcgparalocation;
  114. retcgsize : tcgsize;
  115. begin
  116. result.init;
  117. result.alignment:=get_para_align(p.proccalloption);
  118. if not assigned(forcetempdef) then
  119. result.def:=p.returndef
  120. else
  121. begin
  122. result.def:=forcetempdef;
  123. result.temporary:=true;
  124. end;
  125. result.def:=get_para_push_size(result.def);
  126. { void has no location }
  127. if is_void(result.def) then
  128. begin
  129. paraloc:=result.add_location;
  130. result.size:=OS_NO;
  131. result.intsize:=0;
  132. paraloc^.size:=OS_NO;
  133. paraloc^.def:=voidtype;
  134. paraloc^.loc:=LOC_VOID;
  135. exit;
  136. end;
  137. { Constructors return self instead of a boolean }
  138. if (p.proctypeoption=potype_constructor) then
  139. begin
  140. retcgsize:=OS_INT;
  141. result.intsize:=sizeof(pint);
  142. end
  143. else if jvmimplicitpointertype(result.def) then
  144. begin
  145. retcgsize:=OS_ADDR;
  146. result.def:=cpointerdef.getreusable_no_free(result.def);
  147. end
  148. else
  149. begin
  150. retcgsize:=def_cgsize(result.def);
  151. result.intsize:=result.def.size;
  152. end;
  153. result.size:=retcgsize;
  154. paraloc:=result.add_location;
  155. { all values are returned on the evaluation stack }
  156. paraloc^.loc:=LOC_REFERENCE;
  157. paraloc^.reference.index:=NR_EVAL_STACK_BASE;
  158. paraloc^.reference.offset:=0;
  159. paraloc^.size:=result.size;
  160. paraloc^.def:=result.def;
  161. end;
  162. function tcpuparamanager.param_use_paraloc(const cgpara: tcgpara): boolean;
  163. begin
  164. { all parameters are copied by the VM to local variable locations }
  165. result:=true;
  166. end;
  167. function tcpuparamanager.ret_in_param(def:tdef;pd:tabstractprocdef):boolean;
  168. begin
  169. { not as efficient as returning in param for jvmimplicitpointertypes,
  170. but in the latter case the routines are harder to use from Java
  171. (especially for arrays), because the caller then manually has to
  172. allocate the instance/array of the right size }
  173. Result:=false;
  174. end;
  175. function tcpuparamanager.is_stack_paraloc(paraloc: pcgparalocation): boolean;
  176. begin
  177. { all parameters are passed on the evaluation stack }
  178. result:=true;
  179. end;
  180. function tcpuparamanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
  181. var
  182. parasize : longint;
  183. begin
  184. parasize:=0;
  185. { calculate the registers for the normal parameters }
  186. create_paraloc_info_intern(p,callerside,p.paras,parasize);
  187. { append the varargs }
  188. create_paraloc_info_intern(p,callerside,varargspara,parasize);
  189. result:=parasize;
  190. end;
  191. procedure tcpuparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee;paras:tparalist;
  192. var parasize:longint);
  193. var
  194. paraloc : pcgparalocation;
  195. i : integer;
  196. hp : tparavarsym;
  197. paracgsize : tcgsize;
  198. paraofs : longint;
  199. paradef : tdef;
  200. begin
  201. paraofs:=0;
  202. for i:=0 to paras.count-1 do
  203. begin
  204. hp:=tparavarsym(paras[i]);
  205. if push_copyout_param(hp.varspez,hp.vardef,p.proccalloption) then
  206. begin
  207. { passed via array reference (instead of creating a new array
  208. type for every single parameter, use java_jlobject) }
  209. paracgsize:=OS_ADDR;
  210. paradef:=java_jlobject;
  211. end
  212. else if jvmimplicitpointertype(hp.vardef) then
  213. begin
  214. paracgsize:=OS_ADDR;
  215. paradef:=cpointerdef.getreusable_no_free(hp.vardef);
  216. end
  217. else
  218. begin
  219. paracgsize:=def_cgsize(hp.vardef);
  220. if paracgsize=OS_NO then
  221. paracgsize:=OS_ADDR;
  222. paradef:=hp.vardef;
  223. end;
  224. paradef:=get_para_push_size(paradef);
  225. hp.paraloc[side].reset;
  226. hp.paraloc[side].size:=paracgsize;
  227. hp.paraloc[side].def:=paradef;
  228. hp.paraloc[side].alignment:=std_param_align;
  229. hp.paraloc[side].intsize:=tcgsize2size[paracgsize];
  230. paraloc:=hp.paraloc[side].add_location;
  231. { All parameters are passed on the evaluation stack, pushed from
  232. left to right (including self, if applicable). At the callee side,
  233. they're available as local variables 0..n-1 (with 64 bit values
  234. taking up two slots) }
  235. paraloc^.loc:=LOC_REFERENCE;;
  236. paraloc^.reference.offset:=paraofs;
  237. paraloc^.size:=paracgsize;
  238. paraloc^.def:=paradef;
  239. case side of
  240. callerside:
  241. begin
  242. paraloc^.loc:=LOC_REFERENCE;
  243. { we use a fake loc_reference to indicate the stack location;
  244. the offset (set above) will be used by ncal to order the
  245. parameters so they will be pushed in the right order }
  246. paraloc^.reference.index:=NR_EVAL_STACK_BASE;
  247. end;
  248. calleeside:
  249. begin
  250. paraloc^.loc:=LOC_REFERENCE;
  251. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  252. end;
  253. end;
  254. { 2 slots for 64 bit integers and floats, 1 slot for the rest }
  255. if not(is_64bit(paradef) or
  256. ((paradef.typ=floatdef) and
  257. (tfloatdef(paradef).floattype=s64real))) then
  258. inc(paraofs)
  259. else
  260. inc(paraofs,2);
  261. end;
  262. parasize:=paraofs;
  263. end;
  264. function tcpuparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  265. var
  266. parasize : longint;
  267. begin
  268. parasize:=0;
  269. create_paraloc_info_intern(p,side,p.paras,parasize);
  270. { Create Function result paraloc }
  271. create_funcretloc_info(p,side);
  272. { We need to return the size allocated on the stack }
  273. result:=parasize;
  274. end;
  275. begin
  276. ParaManager:=tcpuparamanager.create;
  277. end.