2
0

njvmld.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. {
  2. Copyright (c) 2011 by Jonas Maebe
  3. Generate JVM assembler for nodes that handle loads and assignments
  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 njvmld;
  18. {$I fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. aasmdata,
  23. symtype,
  24. cgutils,
  25. node, ncgld, ncgnstld;
  26. type
  27. tjvmloadnode = class(tcgnestloadnode)
  28. protected
  29. function is_copyout_addr_param_load: boolean;
  30. function handle_threadvar_access: tnode; override;
  31. function keep_param_address_in_nested_struct: boolean; override;
  32. public
  33. function is_addr_param_load: boolean; override;
  34. procedure pass_generate_code; override;
  35. end;
  36. tjvmassignmentnode = class(tcgassignmentnode)
  37. protected
  38. function direct_shortstring_assignment: boolean; override;
  39. function maybechangetemp(list: TAsmList; var n: tnode; const newref: treference): boolean;override;
  40. public
  41. function pass_1: tnode; override;
  42. end;
  43. tjvmarrayconstructornode = class(tcgarrayconstructornode)
  44. protected
  45. procedure makearrayref(var ref: treference; eledef: tdef); override;
  46. procedure advancearrayoffset(var ref: treference; elesize: asizeint); override;
  47. procedure wrapmanagedvarrec(var n: tnode);override;
  48. end;
  49. implementation
  50. uses
  51. verbose,globals,compinnr,
  52. nbas,nld,ncal,ncon,ninl,nmem,ncnv,nutils,
  53. symconst,symsym,symdef,symtable,defutil,jvmdef,
  54. paramgr,
  55. pass_1,
  56. cpubase,cgbase,hlcgobj,cpuinfo;
  57. { tjvmassignmentnode }
  58. function tjvmassignmentnode.direct_shortstring_assignment: boolean;
  59. begin
  60. if maybe_find_real_class_definition(right.resultdef,false)=java_jlstring then
  61. inserttypeconv_explicit(right,cunicodestringtype);
  62. result:=right.resultdef.typ=stringdef;
  63. end;
  64. function tjvmassignmentnode.maybechangetemp(list: TAsmList; var n: tnode; const newref: treference): boolean;
  65. begin
  66. { don't do this when compiling for Dalvik, because it can invalidate the
  67. debug information (which Dalvik uses as extra type information) }
  68. if current_settings.cputype<>cpu_dalvik then
  69. result:=inherited
  70. else
  71. result:=false;
  72. end;
  73. function tjvmassignmentnode.pass_1: tnode;
  74. var
  75. block: tblocknode;
  76. tempn: ttempcreatenode;
  77. stat: tstatementnode;
  78. target: tnode;
  79. psym: tsym;
  80. begin
  81. { intercept writes to string elements, because Java strings are immutable
  82. -> detour via StringBuilder
  83. }
  84. target:=actualtargetnode(@left)^;
  85. if (target.nodetype=vecn) and
  86. (is_wide_or_unicode_string(tvecnode(target).left.resultdef) or
  87. is_ansistring(tvecnode(target).left.resultdef)) then
  88. begin
  89. { prevent errors in case of an expression such as
  90. word(unicodestr[x]):=1234;
  91. }
  92. if is_wide_or_unicode_string(tvecnode(target).left.resultdef) then
  93. inserttypeconv_explicit(right,cwidechartype)
  94. else
  95. inserttypeconv_explicit(right,cansichartype);
  96. result:=ccallnode.createintern('fpc_'+tstringdef(tvecnode(target).left.resultdef).stringtypname+'_setchar',
  97. ccallparanode.create(right,
  98. ccallparanode.create(tvecnode(target).right,
  99. ccallparanode.create(tvecnode(target).left.getcopy,nil))));
  100. result:=cassignmentnode.create(tvecnode(target).left,result);
  101. right:=nil;
  102. tvecnode(target).left:=nil;
  103. tvecnode(target).right:=nil;
  104. exit;
  105. end
  106. else if (target.nodetype=vecn) and
  107. is_shortstring(tvecnode(target).left.resultdef) then
  108. begin
  109. { prevent errors in case of an expression such as
  110. byte(str[x]):=12;
  111. }
  112. inserttypeconv_explicit(right,cansichartype);
  113. { call ShortstringClass(@shortstring).setChar(index,char) }
  114. tvecnode(target).left:=caddrnode.create_internal(tvecnode(target).left);
  115. { avoid useless typecheck when casting to shortstringclass }
  116. include(taddrnode(tvecnode(target).left).addrnodeflags,anf_typedaddr);
  117. inserttypeconv_explicit(tvecnode(target).left,java_shortstring);
  118. psym:=search_struct_member(tabstractrecorddef(java_shortstring),'SETCHAR');
  119. if not assigned(psym) or
  120. (psym.typ<>procsym) then
  121. internalerror(2011052408);
  122. result:=
  123. ccallnode.create(
  124. ccallparanode.create(right,
  125. ccallparanode.create(tvecnode(target).right,nil)),
  126. tprocsym(psym),psym.owner,tvecnode(target).left,[],nil);
  127. right:=nil;
  128. tvecnode(target).left:=nil;
  129. tvecnode(target).right:=nil;
  130. exit;
  131. end
  132. else if target.resultdef.typ=formaldef then
  133. begin
  134. if right.resultdef.typ in [orddef,floatdef] then
  135. right:=cinlinenode.create(in_box_x,false,right)
  136. else if jvmimplicitpointertype(right.resultdef) then
  137. begin
  138. { we have to assign the address of a deep copy of the type to the
  139. object in the formalpara -> create a temp, assign the value to
  140. the temp, then assign the address in the temp to the para }
  141. block:=internalstatements(stat);
  142. tempn:=ctempcreatenode.create_value(right.resultdef,right.resultdef.size,
  143. tt_persistent,false,right);
  144. addstatement(stat,tempn);
  145. right:=caddrnode.create(ctemprefnode.create(tempn));
  146. inserttypeconv_explicit(right,java_jlobject);
  147. addstatement(stat,ctempdeletenode.create_normal_temp(tempn));
  148. addstatement(stat,ctypeconvnode.create_explicit(
  149. caddrnode.create(ctemprefnode.create(tempn)),java_jlobject));
  150. right:=block;
  151. end;
  152. typecheckpass(right);
  153. result:=inherited;
  154. exit;
  155. end
  156. else
  157. result:=inherited;
  158. end;
  159. function tjvmloadnode.is_copyout_addr_param_load: boolean;
  160. begin
  161. result:=
  162. { passed via array of one element }
  163. ((symtable.symtabletype=parasymtable) and
  164. (symtableentry.typ=paravarsym) and
  165. paramanager.push_copyout_param(tparavarsym(symtableentry).varspez,resultdef,tprocdef(symtable.defowner).proccalloption));
  166. end;
  167. function tjvmloadnode.handle_threadvar_access: tnode;
  168. var
  169. vs: tsym;
  170. begin
  171. { get the variable wrapping the threadvar }
  172. vs:=tsym(symtable.find(symtableentry.name+'$THREADVAR'));
  173. if not assigned(vs) or
  174. (vs.typ<>staticvarsym) then
  175. internalerror(2011082201);
  176. { get a read/write reference to the threadvar value }
  177. result:=cloadnode.create(vs,vs.owner);
  178. typecheckpass(result);
  179. result:=ccallnode.createinternmethod(result,'GETREADWRITEREFERENCE',nil);
  180. if not(tstaticvarsym(symtableentry).vardef.typ in [orddef,floatdef]) and
  181. not jvmimplicitpointertype(tstaticvarsym(symtableentry).vardef) then
  182. begin
  183. { in these cases, the threadvar was internally constructed as an
  184. "array of jlobject", while the variable itself is a different kind of
  185. pointer (dynarmic array, class, interface, pointer type). We cannot
  186. typecast an "array of jlobject" to e.g. an "array of array of byte",
  187. even if all elements inside the array are "array of byte" (since the
  188. outer array type is simply different) -> first dereference (= select
  189. the array element) and then typecast to the result type. This works
  190. even on the left-hand side because then we get e.g.
  191. jlobject(threavarinstance.getreadwritereference^):=value;
  192. threavarinstance.getreadwritereference returns a ppointer in these
  193. cases.
  194. }
  195. result:=cderefnode.create(result);
  196. result:=ctypeconvnode.create_explicit(result,resultdef);
  197. end
  198. else
  199. begin
  200. result:=ctypeconvnode.create_explicit(result,cpointerdef.getreusable(resultdef));
  201. result:=cderefnode.create(result);
  202. end;
  203. end;
  204. function tjvmloadnode.keep_param_address_in_nested_struct: boolean;
  205. begin
  206. { we don't need an extra load when implicit pointer types are passed as
  207. var/out/constref parameter (since they are already pointers). However,
  208. when transfering them into a nestedfp struct, we do want to transfer the
  209. pointer and not make a deep copy in case they are var/out/constref (since
  210. changes made to the var/out parameter should propagate up) }
  211. result:=
  212. is_addr_param_load or
  213. ((symtableentry.typ=paravarsym) and
  214. jvmimplicitpointertype(tparavarsym(symtableentry).vardef) and
  215. (tparavarsym(symtableentry).varspez in [vs_var,vs_constref,vs_out]));
  216. end;
  217. function tjvmloadnode.is_addr_param_load: boolean;
  218. begin
  219. result:=
  220. (inherited is_addr_param_load and
  221. not jvmimplicitpointertype(tparavarsym(symtableentry).vardef) and
  222. (tparavarsym(symtableentry).vardef.typ<>formaldef)) or
  223. is_copyout_addr_param_load;
  224. end;
  225. procedure tjvmloadnode.pass_generate_code;
  226. begin
  227. if is_copyout_addr_param_load then
  228. begin
  229. { in case of nested access, load address of field in nestedfpstruct }
  230. if assigned(left) then
  231. generate_nested_access(tabstractnormalvarsym(symtableentry));
  232. location_reset_ref(location,LOC_REFERENCE,def_cgsize(resultdef),4,[]);
  233. location.reference.arrayreftype:=art_indexconst;
  234. location.reference.base:=hlcg.getaddressregister(current_asmdata.CurrAsmList,java_jlobject);
  235. location.reference.indexoffset:=0;
  236. { load the field from the nestedfpstruct, or the parameter location.
  237. In both cases, the result is an array of one element containing the
  238. parameter value }
  239. if assigned(left) then
  240. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,java_jlobject,java_jlobject,left.location,location.reference.base)
  241. else
  242. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,java_jlobject,java_jlobject,tparavarsym(symtableentry).localloc,location.reference.base);
  243. end
  244. else if symtableentry.typ=procsym then
  245. { handled in tjvmcnvnode.first_proc_to_procvar }
  246. internalerror(2011072408)
  247. else
  248. inherited pass_generate_code;
  249. end;
  250. { tjvmarrayconstructornode }
  251. procedure tjvmarrayconstructornode.makearrayref(var ref: treference; eledef: tdef);
  252. var
  253. basereg: tregister;
  254. begin
  255. { arrays are implicitly dereferenced }
  256. basereg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,java_jlobject);
  257. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,java_jlobject,java_jlobject,ref,basereg);
  258. reference_reset_base(ref,basereg,0,ctempposinvalid,1,[]);
  259. ref.arrayreftype:=art_indexconst;
  260. ref.indexoffset:=0;
  261. end;
  262. procedure tjvmarrayconstructornode.advancearrayoffset(var ref: treference; elesize: asizeint);
  263. begin
  264. inc(ref.indexoffset);
  265. end;
  266. procedure tjvmarrayconstructornode.wrapmanagedvarrec(var n: tnode);
  267. var
  268. varrecdef: trecorddef;
  269. block: tblocknode;
  270. stat: tstatementnode;
  271. temp: ttempcreatenode;
  272. begin
  273. varrecdef:=trecorddef(search_system_type('TVARREC').typedef);
  274. block:=internalstatements(stat);
  275. temp:=ctempcreatenode.create(varrecdef,varrecdef.size,tt_persistent,false);
  276. addstatement(stat,temp);
  277. addstatement(stat,
  278. ccallnode.createinternmethod(
  279. ctemprefnode.create(temp),'INIT',ccallparanode.create(n,nil)));
  280. { note: this will not free the record contents, but just let its reference
  281. on the stack be reused -- which is ok, because the reference will be
  282. stored into the open array parameter }
  283. addstatement(stat,ctempdeletenode.create_normal_temp(temp));
  284. addstatement(stat,ctemprefnode.create(temp));
  285. n:=block;
  286. firstpass(n);
  287. end;
  288. begin
  289. cloadnode:=tjvmloadnode;
  290. cassignmentnode:=tjvmassignmentnode;
  291. carrayconstructornode:=tjvmarrayconstructornode;
  292. end.