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