1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18 /*! \file LowerGetPut.cpp
19 \brief This file lowers the following bytecodes: XGET|PUT_XXX
20 */
21 #include "libdex/DexOpcodes.h"
22 #include "libdex/DexFile.h"
23 #include "Lower.h"
24 #include "NcgAot.h"
25 #include "enc_wrapper.h"
26
27 #define P_GPR_1 PhysicalReg_EBX
28 #define P_GPR_2 PhysicalReg_ECX
29 #define P_GPR_3 PhysicalReg_ESI
30 #define P_GPR_4 PhysicalReg_EDX
31 //! LOWER bytecode AGET without usage of helper function
32
33 //! It has null check and length check
aget_common_nohelper(int flag,u2 vA,u2 vref,u2 vindex)34 int aget_common_nohelper(int flag, u2 vA, u2 vref, u2 vindex) {
35 ////////////////////////////
36 // Request VR free delays before register allocation for the temporaries
37 if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_NULL_CHECK))
38 requestVRFreeDelay(vref,VRDELAY_NULLCHECK);
39 if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
40 requestVRFreeDelay(vref,VRDELAY_BOUNDCHECK);
41 requestVRFreeDelay(vindex,VRDELAY_BOUNDCHECK);
42 }
43
44 get_virtual_reg(vref, OpndSize_32, 1, false); //array
45 get_virtual_reg(vindex, OpndSize_32, 2, false); //index
46
47 if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
48 //last argument is the exception number for this bytecode
49 nullCheck(1, false, 1, vref); //maybe optimized away, if not, call
50 cancelVRFreeDelayRequest(vref,VRDELAY_NULLCHECK);
51 } else {
52 updateRefCount2(1, LowOpndRegType_gp, false); //update reference count for tmp1
53 }
54
55 if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
56 boundCheck(vref, 1, false,
57 vindex, 2, false,
58 2);
59 cancelVRFreeDelayRequest(vref,VRDELAY_BOUNDCHECK);
60 cancelVRFreeDelayRequest(vindex,VRDELAY_BOUNDCHECK);
61 } else {
62 updateRefCount2(1, LowOpndRegType_gp, false); //update reference count for tmp1
63 updateRefCount2(2, LowOpndRegType_gp, false); //update reference count for tmp2
64 }
65
66 if(flag == AGET) {
67 move_mem_disp_scale_to_reg(OpndSize_32, 1, false, offArrayObject_contents, 2, false, 4, 4, false);
68 }
69 else if(flag == AGET_WIDE) {
70 move_mem_disp_scale_to_reg(OpndSize_64, 1, false, offArrayObject_contents, 2, false, 8, 1, false);
71 }
72 else if(flag == AGET_CHAR) {
73 movez_mem_disp_scale_to_reg(OpndSize_16, 1, false, offArrayObject_contents, 2, false, 2, 4, false);
74 }
75 else if(flag == AGET_SHORT) {
76 moves_mem_disp_scale_to_reg(OpndSize_16, 1, false, offArrayObject_contents, 2, false, 2, 4, false);
77 }
78 else if(flag == AGET_BOOLEAN) {
79 movez_mem_disp_scale_to_reg(OpndSize_8, 1, false, offArrayObject_contents, 2, false, 1, 4, false);
80 }
81 else if(flag == AGET_BYTE) {
82 moves_mem_disp_scale_to_reg(OpndSize_8, 1, false, offArrayObject_contents, 2, false, 1, 4, false);
83 }
84 if(flag == AGET_WIDE) {
85 set_virtual_reg(vA, OpndSize_64, 1, false);
86 }
87 else {
88 set_virtual_reg(vA, OpndSize_32, 4, false);
89 }
90 //////////////////////////////////
91 return 0;
92 }
93 //! wrapper to call either aget_common_helper or aget_common_nohelper
94
95 //!
aget_common(int flag,u2 vA,u2 vref,u2 vindex)96 int aget_common(int flag, u2 vA, u2 vref, u2 vindex) {
97 return aget_common_nohelper(flag, vA, vref, vindex);
98 }
99 #undef P_GPR_1
100 #undef P_GPR_2
101 #undef P_GPR_3
102 #undef P_GPR_4
103 //! lower bytecode AGET by calling aget_common
104
105 //!
op_aget()106 int op_aget() {
107 u2 vA = INST_AA(inst);
108 u2 vref = FETCH(1) & 0xff;
109 u2 vindex = FETCH(1) >> 8;
110 int retval = aget_common(AGET, vA, vref, vindex);
111 rPC += 2;
112 return retval;
113 }
114 //! lower bytecode AGET_WIDE by calling aget_common
115
116 //!
op_aget_wide()117 int op_aget_wide() {
118 u2 vA = INST_AA(inst);
119 u2 vref = FETCH(1) & 0xff;
120 u2 vindex = FETCH(1) >> 8;
121 int retval = aget_common(AGET_WIDE, vA, vref, vindex);
122 rPC += 2;
123 return retval;
124 }
125 //! lower bytecode AGET_OBJECT by calling aget_common
126
127 //!
op_aget_object()128 int op_aget_object() {
129 return op_aget();
130 }
131 //! lower bytecode BOOLEAN by calling aget_common
132
133 //!
op_aget_boolean()134 int op_aget_boolean() {
135 u2 vA = INST_AA(inst);
136 u2 vref = FETCH(1) & 0xff;
137 u2 vindex = FETCH(1) >> 8;
138 int retval = aget_common(AGET_BOOLEAN, vA, vref, vindex);
139 rPC += 2;
140 return retval;
141 }
142 //! lower bytecode AGET_BYTE by calling aget_common
143
144 //!
op_aget_byte()145 int op_aget_byte() {
146 u2 vA = INST_AA(inst);
147 u2 vref = FETCH(1) & 0xff;
148 u2 vindex = FETCH(1) >> 8;
149 int retval = aget_common(AGET_BYTE, vA, vref, vindex);
150 rPC += 2;
151 return retval;
152 }
153 //! lower bytecode AGET_CHAR by calling aget_common
154
155 //!
op_aget_char()156 int op_aget_char() {
157 u2 vA = INST_AA(inst);
158 u2 vref = FETCH(1) & 0xff;
159 u2 vindex = FETCH(1) >> 8;
160 int retval = aget_common(AGET_CHAR, vA, vref, vindex);
161 rPC += 2;
162 return retval;
163 }
164 //! lower bytecode AGET_SHORT by calling aget_common
165
166 //!
op_aget_short()167 int op_aget_short() {
168 u2 vA = INST_AA(inst);
169 u2 vref = FETCH(1) & 0xff;
170 u2 vindex = FETCH(1) >> 8;
171 int retval = aget_common(AGET_SHORT, vA, vref, vindex);
172 rPC += 2;
173 return retval;
174 }
175
176 #define P_GPR_1 PhysicalReg_EBX
177 #define P_GPR_2 PhysicalReg_ECX
178 #define P_GPR_3 PhysicalReg_ESI
179 #define P_GPR_4 PhysicalReg_EDX
180 //! LOWER bytecode APUT without usage of helper function
181
182 //! It has null check and length check
aput_common_nohelper(int flag,u2 vA,u2 vref,u2 vindex)183 int aput_common_nohelper(int flag, u2 vA, u2 vref, u2 vindex) {
184 //////////////////////////////////////
185 // Request VR free delays before register allocation for the temporaries.
186 // No need to request delay for vA since it will be transferred to temporary
187 // after the null check and bound check.
188 if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_NULL_CHECK))
189 requestVRFreeDelay(vref,VRDELAY_NULLCHECK);
190 if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
191 requestVRFreeDelay(vref,VRDELAY_BOUNDCHECK);
192 requestVRFreeDelay(vindex,VRDELAY_BOUNDCHECK);
193 }
194
195 get_virtual_reg(vref, OpndSize_32, 1, false); //array
196 get_virtual_reg(vindex, OpndSize_32, 2, false); //index
197
198 if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
199 //last argument is the exception number for this bytecode
200 nullCheck(1, false, 1, vref); //maybe optimized away, if not, call
201 cancelVRFreeDelayRequest(vref,VRDELAY_NULLCHECK);
202 } else {
203 updateRefCount2(1, LowOpndRegType_gp, false); //update reference count for tmp1
204 }
205
206 if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
207 boundCheck(vref, 1, false,
208 vindex, 2, false,
209 2);
210 cancelVRFreeDelayRequest(vref,VRDELAY_BOUNDCHECK);
211 cancelVRFreeDelayRequest(vindex,VRDELAY_BOUNDCHECK);
212 } else {
213 updateRefCount2(1, LowOpndRegType_gp, false); //update reference count for tmp1
214 updateRefCount2(2, LowOpndRegType_gp, false); //update reference count for tmp2
215 }
216
217 if(flag == APUT_WIDE) {
218 get_virtual_reg(vA, OpndSize_64, 1, false);
219 }
220 else {
221 get_virtual_reg(vA, OpndSize_32, 4, false);
222 }
223 if(flag == APUT)
224 move_reg_to_mem_disp_scale(OpndSize_32, 4, false, 1, false, offArrayObject_contents, 2, false, 4);
225 else if(flag == APUT_WIDE)
226 move_reg_to_mem_disp_scale(OpndSize_64, 1, false, 1, false, offArrayObject_contents, 2, false, 8);
227 else if(flag == APUT_CHAR || flag == APUT_SHORT)
228 move_reg_to_mem_disp_scale(OpndSize_16, 4, false, 1, false, offArrayObject_contents, 2, false, 2);
229 else if(flag == APUT_BOOLEAN || flag == APUT_BYTE)
230 move_reg_to_mem_disp_scale(OpndSize_8, 4, false, 1, false, offArrayObject_contents, 2, false, 1);
231 //////////////////////////////////
232 return 0;
233 }
234 //! wrapper to call either aput_common_helper or aput_common_nohelper
235
236 //!
aput_common(int flag,u2 vA,u2 vref,u2 vindex)237 int aput_common(int flag, u2 vA, u2 vref, u2 vindex) {
238 return aput_common_nohelper(flag, vA, vref, vindex);
239 }
240 #undef P_GPR_1
241 #undef P_GPR_2
242 #undef P_GPR_3
243 #undef P_GPR_4
244 //! lower bytecode APUT by calling aput_common
245
246 //!
op_aput()247 int op_aput() {
248 u2 vA = INST_AA(inst);
249 u2 vref = FETCH(1) & 0xff;
250 u2 vindex = FETCH(1) >> 8;
251 int retval = aput_common(APUT, vA, vref, vindex);
252 rPC += 2;
253 return retval;
254 }
255 //! lower bytecode APUT_WIDE by calling aput_common
256
257 //!
op_aput_wide()258 int op_aput_wide() {
259 u2 vA = INST_AA(inst);
260 u2 vref = FETCH(1) & 0xff;
261 u2 vindex = FETCH(1) >> 8;
262 int retval = aput_common(APUT_WIDE, vA, vref, vindex);
263 rPC += 2;
264 return retval;
265 }
266 //! lower bytecode APUT_BOOLEAN by calling aput_common
267
268 //!
op_aput_boolean()269 int op_aput_boolean() {
270 u2 vA = INST_AA(inst);
271 u2 vref = FETCH(1) & 0xff;
272 u2 vindex = FETCH(1) >> 8;
273 int retval = aput_common(APUT_BOOLEAN, vA, vref, vindex);
274 rPC += 2;
275 return retval;
276 }
277 //! lower bytecode APUT_BYTE by calling aput_common
278
279 //!
op_aput_byte()280 int op_aput_byte() {
281 u2 vA = INST_AA(inst);
282 u2 vref = FETCH(1) & 0xff;
283 u2 vindex = FETCH(1) >> 8;
284 int retval = aput_common(APUT_BYTE, vA, vref, vindex);
285 rPC += 2;
286 return retval;
287 }
288 //! lower bytecode APUT_CHAR by calling aput_common
289
290 //!
op_aput_char()291 int op_aput_char() {
292 u2 vA = INST_AA(inst);
293 u2 vref = FETCH(1) & 0xff;
294 u2 vindex = FETCH(1) >> 8;
295 int retval = aput_common(APUT_CHAR, vA, vref, vindex);
296 rPC += 2;
297 return retval;
298 }
299 //! lower bytecode APUT_SHORT by calling aput_common
300
301 //!
op_aput_short()302 int op_aput_short() {
303 u2 vA = INST_AA(inst);
304 u2 vref = FETCH(1) & 0xff;
305 u2 vindex = FETCH(1) >> 8;
306 int retval = aput_common(APUT_SHORT, vA, vref, vindex);
307 rPC += 2;
308 return retval;
309 }
310
311 #define P_GPR_1 PhysicalReg_EBX //callee-saved valid after CanPutArray
312 #define P_GPR_2 PhysicalReg_ECX
313 #define P_GPR_3 PhysicalReg_ESI //callee-saved
314 #define P_SCRATCH_1 PhysicalReg_EDX
315 #define P_SCRATCH_2 PhysicalReg_EAX
316 #define P_SCRATCH_3 PhysicalReg_EDX
317
318 void markCard_notNull(int tgtAddrReg, int scratchReg, bool isPhysical);
319
320 //! lower bytecode APUT_OBJECT
321
322 //! Lower the bytecode using helper function ".aput_obj_helper" if helper switch is on
op_aput_object()323 int op_aput_object() { //type checking
324 u2 vA = INST_AA(inst);
325 u2 vref = FETCH(1) & 0xff;
326 u2 vindex = FETCH(1) >> 8;
327
328 ///////////////////////////
329 // Request VR free delays before register allocation for the temporaries
330 // No need to request delay for vA since it will be transferred to temporary
331 // after the null check and bound check.
332 if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_NULL_CHECK))
333 requestVRFreeDelay(vref,VRDELAY_NULLCHECK);
334 if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
335 requestVRFreeDelay(vref,VRDELAY_BOUNDCHECK);
336 requestVRFreeDelay(vindex,VRDELAY_BOUNDCHECK);
337 }
338
339 get_virtual_reg(vref, OpndSize_32, 1, false); //array
340 export_pc(); //use %edx
341
342 if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
343 compare_imm_reg(OpndSize_32, 0, 1, false);
344 conditional_jump_global_API(Condition_E, "common_errNullObject", false);
345 cancelVRFreeDelayRequest(vref,VRDELAY_NULLCHECK);
346 } else {
347 updateRefCount2(1, LowOpndRegType_gp, false); //update reference count for tmp1
348 }
349
350 get_virtual_reg(vindex, OpndSize_32, 2, false); //index
351 if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
352 compare_mem_reg(OpndSize_32, offArrayObject_length, 1, false, 2, false);
353 conditional_jump_global_API(Condition_NC, "common_errArrayIndex", false);
354 cancelVRFreeDelayRequest(vref,VRDELAY_BOUNDCHECK);
355 cancelVRFreeDelayRequest(vindex,VRDELAY_BOUNDCHECK);
356 } else {
357 updateRefCount2(1, LowOpndRegType_gp, false); //update reference count for tmp1
358 updateRefCount2(2, LowOpndRegType_gp, false); //update reference count for tmp2
359 }
360
361 get_virtual_reg(vA, OpndSize_32, 4, false);
362 compare_imm_reg(OpndSize_32, 0, 4, false);
363 conditional_jump(Condition_E, ".aput_object_skip_check", true);
364 rememberState(1);
365 move_mem_to_reg(OpndSize_32, offObject_clazz, 4, false, 5, false);
366 load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
367 move_reg_to_mem(OpndSize_32, 5, false, 0, PhysicalReg_ESP, true);
368 move_mem_to_reg(OpndSize_32, offObject_clazz, 1, false, 6, false);
369 move_reg_to_mem(OpndSize_32, 6, false, 4, PhysicalReg_ESP, true);
370
371 scratchRegs[0] = PhysicalReg_SCRATCH_1;
372 call_dvmCanPutArrayElement(); //scratch??
373 load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
374 compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
375 conditional_jump_global_API(Condition_E, "common_errArrayStore", false);
376
377 //NOTE: "2, false" is live through function call
378 move_reg_to_mem_disp_scale(OpndSize_32, 4, false, 1, false, offArrayObject_contents, 2, false, 4);
379 markCard_notNull(1, 11, false);
380 rememberState(2);
381 ////TODO NCG O1 + code cache
382 unconditional_jump(".aput_object_after_check", true);
383
384 insertLabel(".aput_object_skip_check", true);
385 goToState(1);
386 //NOTE: "2, false" is live through function call
387 move_reg_to_mem_disp_scale(OpndSize_32, 4, false, 1, false, offArrayObject_contents, 2, false, 4);
388
389 transferToState(2);
390 insertLabel(".aput_object_after_check", true);
391 ///////////////////////////////
392 rPC += 2;
393 return 0;
394 }
395 #undef P_GPR_1
396 #undef P_GPR_2
397 #undef P_GPR_3
398 #undef P_SCRATCH_1
399 #undef P_SCRATCH_2
400 #undef P_SCRATCH_3
401
402 //////////////////////////////////////////
403 #define P_GPR_1 PhysicalReg_ECX
404 #define P_GPR_2 PhysicalReg_EBX //should be callee-saved to avoid overwritten by inst_field_resolve
405 #define P_GPR_3 PhysicalReg_ESI
406 #define P_SCRATCH_1 PhysicalReg_EDX
407
408 /*
409 movl offThread_cardTable(self), scratchReg
410 compare_imm_reg 0, valReg (testl valReg, valReg)
411 je .markCard_skip
412 shrl $GC_CARD_SHIFT, tgtAddrReg
413 movb %, (scratchReg, tgtAddrReg)
414 NOTE: scratchReg can be accessed with the corresponding byte
415 tgtAddrReg will be updated
416 for O1, update the corresponding reference count
417 */
markCard(int valReg,int tgtAddrReg,bool targetPhysical,int scratchReg,bool isPhysical)418 void markCard(int valReg, int tgtAddrReg, bool targetPhysical, int scratchReg, bool isPhysical) {
419 get_self_pointer(PhysicalReg_SCRATCH_6, isScratchPhysical);
420 move_mem_to_reg(OpndSize_32, offsetof(Thread, cardTable), PhysicalReg_SCRATCH_6, isScratchPhysical, scratchReg, isPhysical);
421 compare_imm_reg(OpndSize_32, 0, valReg, isPhysical);
422 conditional_jump(Condition_E, ".markCard_skip", true);
423 alu_binary_imm_reg(OpndSize_32, shr_opc, GC_CARD_SHIFT, tgtAddrReg, targetPhysical);
424 move_reg_to_mem_disp_scale(OpndSize_8, scratchReg, isPhysical, scratchReg, isPhysical, 0, tgtAddrReg, targetPhysical, 1);
425 insertLabel(".markCard_skip", true);
426 }
427
markCard_notNull(int tgtAddrReg,int scratchReg,bool isPhysical)428 void markCard_notNull(int tgtAddrReg, int scratchReg, bool isPhysical) {
429 get_self_pointer(PhysicalReg_SCRATCH_2, isScratchPhysical);
430 move_mem_to_reg(OpndSize_32, offsetof(Thread, cardTable), PhysicalReg_SCRATCH_2, isScratchPhysical, scratchReg, isPhysical);
431 alu_binary_imm_reg(OpndSize_32, shr_opc, GC_CARD_SHIFT, tgtAddrReg, isPhysical);
432 move_reg_to_mem_disp_scale(OpndSize_8, scratchReg, isPhysical, scratchReg, isPhysical, 0, tgtAddrReg, isPhysical, 1);
433 }
434
markCard_filled(int tgtAddrReg,bool isTgtPhysical,int scratchReg,bool isScratchPhysical)435 void markCard_filled(int tgtAddrReg, bool isTgtPhysical, int scratchReg, bool isScratchPhysical) {
436 get_self_pointer(PhysicalReg_SCRATCH_2, false/*isPhysical*/);
437 move_mem_to_reg(OpndSize_32, offsetof(Thread, cardTable), PhysicalReg_SCRATCH_2, isScratchPhysical, scratchReg, isScratchPhysical);
438 alu_binary_imm_reg(OpndSize_32, shr_opc, GC_CARD_SHIFT, tgtAddrReg, isTgtPhysical);
439 move_reg_to_mem_disp_scale(OpndSize_8, scratchReg, isScratchPhysical, scratchReg, isScratchPhysical, 0, tgtAddrReg, isTgtPhysical, 1);
440 }
441 //! LOWER bytecode IGET,IPUT without usage of helper function
442
443 //! It has null check and calls assembly function inst_field_resolve
iget_iput_common_nohelper(int tmp,int flag,u2 vA,u2 vB,int isObj,bool isVolatile)444 int iget_iput_common_nohelper(int tmp, int flag, u2 vA, u2 vB, int isObj, bool isVolatile) {
445 #ifdef WITH_JIT_INLINING
446 const Method *method = (traceCurrentMIR->OptimizationFlags & MIR_CALLEE) ?
447 traceCurrentMIR->meta.calleeMethod : currentMethod;
448 InstField *pInstField = (InstField *)
449 method->clazz->pDvmDex->pResFields[tmp];
450 #else
451 InstField *pInstField = (InstField *)
452 currentMethod->clazz->pDvmDex->pResFields[tmp];
453 #endif
454 int fieldOffset;
455
456 assert(pInstField != NULL);
457 fieldOffset = pInstField->byteOffset;
458 move_imm_to_reg(OpndSize_32, fieldOffset, 8, false);
459 // Request VR delay before transfer to temporary. Only vB needs delay.
460 // vA will have non-zero reference count since transfer to temporary for
461 // it happens after null check, thus no delay is needed.
462 requestVRFreeDelay(vB,VRDELAY_NULLCHECK);
463 get_virtual_reg(vB, OpndSize_32, 7, false);
464 nullCheck(7, false, 2, vB); //maybe optimized away, if not, call
465 cancelVRFreeDelayRequest(vB,VRDELAY_NULLCHECK);
466 if(flag == IGET) {
467 move_mem_scale_to_reg(OpndSize_32, 7, false, 8, false, 1, 9, false);
468 set_virtual_reg(vA, OpndSize_32, 9, false);
469 #ifdef DEBUG_IGET_OBJ
470 if(isObj > 0) {
471 pushAllRegs();
472 load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
473 move_reg_to_mem(OpndSize_32, 9, false, 12, PhysicalReg_ESP, true); //field
474 move_reg_to_mem(OpndSize_32, 7, false, 8, PhysicalReg_ESP, true); //object
475 move_imm_to_mem(OpndSize_32, tmp, 4, PhysicalReg_ESP, true); //field
476 move_imm_to_mem(OpndSize_32, 0, 0, PhysicalReg_ESP, true); //iget
477 call_dvmDebugIgetIput();
478 load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
479 popAllRegs();
480 }
481 #endif
482 } else if(flag == IGET_WIDE) {
483 if(isVolatile) {
484 /* call dvmQuasiAtomicRead64(addr) */
485 load_effective_addr(fieldOffset, 7, false, 9, false);
486 move_reg_to_mem(OpndSize_32, 9, false, -4, PhysicalReg_ESP, true); //1st argument
487 load_effective_addr(-4, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
488 nextVersionOfHardReg(PhysicalReg_EAX, 2);
489 nextVersionOfHardReg(PhysicalReg_EDX, 2);
490 scratchRegs[0] = PhysicalReg_SCRATCH_3;
491 call_dvmQuasiAtomicRead64();
492 load_effective_addr(4, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
493 //memory content in %edx, %eax
494 set_virtual_reg(vA, OpndSize_32, PhysicalReg_EAX, true);
495 set_virtual_reg(vA+1, OpndSize_32, PhysicalReg_EDX, true);
496 } else {
497 move_mem_scale_to_reg(OpndSize_64, 7, false, 8, false, 1, 1, false); //access field
498 set_virtual_reg(vA, OpndSize_64, 1, false);
499 }
500 } else if(flag == IPUT) {
501 get_virtual_reg(vA, OpndSize_32, 9, false);
502 move_reg_to_mem_scale(OpndSize_32, 9, false, 7, false, 8, false, 1); //access field
503 if(isObj) {
504 markCard(9, 7, false, 11, false);
505 }
506 } else if(flag == IPUT_WIDE) {
507 get_virtual_reg(vA, OpndSize_64, 1, false);
508 if(isVolatile) {
509 /* call dvmQuasiAtomicSwap64(val, addr) */
510 load_effective_addr(fieldOffset, 7, false, 9, false);
511 move_reg_to_mem(OpndSize_32, 9, false, -4, PhysicalReg_ESP, true); //2nd argument
512 move_reg_to_mem(OpndSize_64, 1, false, -12, PhysicalReg_ESP, true); //1st argument
513 load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
514 scratchRegs[0] = PhysicalReg_SCRATCH_3;
515 call_dvmQuasiAtomicSwap64();
516 load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
517 }
518 else {
519 move_reg_to_mem_scale(OpndSize_64, 1, false, 7, false, 8, false, 1);
520 }
521 }
522 ///////////////////////////
523 return 0;
524 }
525 //! wrapper to call either iget_iput_common_helper or iget_iput_common_nohelper
526
527 //!
iget_iput_common(int tmp,int flag,u2 vA,u2 vB,int isObj,bool isVolatile)528 int iget_iput_common(int tmp, int flag, u2 vA, u2 vB, int isObj, bool isVolatile) {
529 return iget_iput_common_nohelper(tmp, flag, vA, vB, isObj, isVolatile);
530 }
531 #undef P_GPR_1
532 #undef P_GPR_2
533 #undef P_GPR_3
534 #undef P_SCRATCH_1
535 //! lower bytecode IGET by calling iget_iput_common
536
537 //!
op_iget()538 int op_iget() {
539 u2 vA = INST_A(inst);
540 u2 vB = INST_B(inst);
541 u2 tmp = FETCH(1);
542 int retval = iget_iput_common(tmp, IGET, vA, vB, 0, false);
543 rPC += 2;
544 return retval;
545 }
546 //! lower bytecode IGET_WIDE by calling iget_iput_common
547
548 //!
op_iget_wide(bool isVolatile)549 int op_iget_wide(bool isVolatile) {
550 u2 vA = INST_A(inst);
551 u2 vB = INST_B(inst);
552 u2 tmp = FETCH(1);
553 int retval = iget_iput_common(tmp, IGET_WIDE, vA, vB, 0, isVolatile);
554 rPC += 2;
555 return retval;
556 }
557 //! lower bytecode IGET_OBJECT by calling iget_iput_common
558
559 //!
op_iget_object()560 int op_iget_object() {
561 u2 vA = INST_A(inst);
562 u2 vB = INST_B(inst);
563 u2 tmp = FETCH(1);
564 int retval = iget_iput_common(tmp, IGET, vA, vB, 1, false);
565 rPC += 2;
566 return retval;
567 }
568 //! lower bytecode IGET_BOOLEAN by calling iget_iput_common
569
570 //!
op_iget_boolean()571 int op_iget_boolean() {
572 return op_iget();
573 }
574 //! lower bytecode IGET_BYTE by calling iget_iput_common
575
576 //!
op_iget_byte()577 int op_iget_byte() {
578 return op_iget();
579 }
580 //! lower bytecode IGET_CHAR by calling iget_iput_common
581
582 //!
op_iget_char()583 int op_iget_char() {
584 return op_iget();
585 }
586 //! lower bytecode IGET_SHORT by calling iget_iput_common
587
588 //!
op_iget_short()589 int op_iget_short() {
590 return op_iget();
591 }
592 //! lower bytecode IPUT by calling iget_iput_common
593
594 //!
op_iput()595 int op_iput() {
596 u2 vA = INST_A(inst);
597 u2 vB = INST_B(inst);
598 u2 tmp = FETCH(1);
599 int retval = iget_iput_common(tmp, IPUT, vA, vB, 0, false);
600 rPC += 2;
601 return retval;
602 }
603 //! lower bytecode IPUT_WIDE by calling iget_iput_common
604
605 //!
op_iput_wide(bool isVolatile)606 int op_iput_wide(bool isVolatile) {
607 u2 vA = INST_A(inst);
608 u2 vB = INST_B(inst);
609 u2 tmp = FETCH(1);
610 int retval = iget_iput_common(tmp, IPUT_WIDE, vA, vB, 0, isVolatile);
611 rPC += 2;
612 return retval;
613 }
614 //! lower bytecode IPUT_OBJECT by calling iget_iput_common
615
616 //!
op_iput_object()617 int op_iput_object() {
618 u2 vA = INST_A(inst);
619 u2 vB = INST_B(inst);
620 u2 tmp = FETCH(1);
621 int retval = iget_iput_common(tmp, IPUT, vA, vB, 1, false);
622 rPC += 2;
623 return retval;
624 }
625 //! lower bytecode IPUT_BOOLEAN by calling iget_iput_common
626
627 //!
op_iput_boolean()628 int op_iput_boolean() {
629 return op_iput();
630 }
631 //! lower bytecode IPUT_BYTE by calling iget_iput_common
632
633 //!
op_iput_byte()634 int op_iput_byte() {
635 return op_iput();
636 }
637 //! lower bytecode IPUT_CHAR by calling iget_iput_common
638
639 //!
op_iput_char()640 int op_iput_char() {
641 return op_iput();
642 }
643 //! lower bytecode IPUT_SHORT by calling iget_iput_common
644
645 //!
op_iput_short()646 int op_iput_short() {
647 return op_iput();
648 }
649
650 #define P_GPR_1 PhysicalReg_EBX
651 #define P_GPR_2 PhysicalReg_ECX
652 #define P_GPR_3 PhysicalReg_EDX //used by helper only
653
654 //! common section to lower IGET & IPUT
655
656 //! It will use helper function sget_helper if the switch is on
sget_sput_common(int flag,u2 vA,u2 tmp,bool isObj,bool isVolatile)657 int sget_sput_common(int flag, u2 vA, u2 tmp, bool isObj, bool isVolatile) {
658 //call assembly static_field_resolve
659 //no exception
660 //glue: get_res_fields
661 //hard-coded: eax (one version?)
662 //////////////////////////////////////////
663 #ifdef WITH_JIT_INLINING
664 const Method *method = (traceCurrentMIR->OptimizationFlags & MIR_CALLEE) ? traceCurrentMIR->meta.calleeMethod : currentMethod;
665 void *fieldPtr = (void*)
666 (method->clazz->pDvmDex->pResFields[tmp]);
667 #else
668 void *fieldPtr = (void*)
669 (currentMethod->clazz->pDvmDex->pResFields[tmp]);
670 #endif
671
672 /* Usually, fieldPtr should not be null. The interpreter should resolve
673 * it before we come here, or not allow this opcode in a trace. However,
674 * we can be in a loop trace and this opcode might have been picked up
675 * by exhaustTrace. Sending a -1 here will terminate the loop formation
676 * and fall back to normal trace, which will not have this opcode.
677 */
678 if (!fieldPtr) {
679 return -1;
680 }
681
682 move_imm_to_reg(OpndSize_32, (int)fieldPtr, PhysicalReg_EAX, true);
683 if(flag == SGET) {
684 move_mem_to_reg(OpndSize_32, offStaticField_value, PhysicalReg_EAX, true, 7, false); //access field
685 set_virtual_reg(vA, OpndSize_32, 7, false);
686 } else if(flag == SGET_WIDE) {
687 if(isVolatile) {
688 /* call dvmQuasiAtomicRead64(addr) */
689 load_effective_addr(offStaticField_value, PhysicalReg_EAX, true, 9, false);
690 move_reg_to_mem(OpndSize_32, 9, false, -4, PhysicalReg_ESP, true); //1st argument
691 load_effective_addr(-4, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
692 nextVersionOfHardReg(PhysicalReg_EAX, 2);
693 nextVersionOfHardReg(PhysicalReg_EDX, 2);
694 scratchRegs[0] = PhysicalReg_SCRATCH_3;
695 call_dvmQuasiAtomicRead64();
696 load_effective_addr(4, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
697 //memory content in %edx, %eax
698 set_virtual_reg(vA, OpndSize_32, PhysicalReg_EAX, true);
699 set_virtual_reg(vA+1, OpndSize_32, PhysicalReg_EDX, true);
700 }
701 else {
702 move_mem_to_reg(OpndSize_64, offStaticField_value, PhysicalReg_EAX, true, 1, false); //access field
703 set_virtual_reg(vA, OpndSize_64, 1, false);
704 }
705 } else if(flag == SPUT) {
706 get_virtual_reg(vA, OpndSize_32, 7, false);
707 move_reg_to_mem(OpndSize_32, 7, false, offStaticField_value, PhysicalReg_EAX, true); //access field
708 if(isObj) {
709 /* get clazz object, then use clazz object to mark card */
710 move_mem_to_reg(OpndSize_32, offField_clazz, PhysicalReg_EAX, true, 12, false);
711 markCard(7/*valReg*/, 12, false, 11, false);
712 }
713 } else if(flag == SPUT_WIDE) {
714 get_virtual_reg(vA, OpndSize_64, 1, false);
715 if(isVolatile) {
716 /* call dvmQuasiAtomicSwap64(val, addr) */
717 load_effective_addr(offStaticField_value, PhysicalReg_EAX, true, 9, false);
718 move_reg_to_mem(OpndSize_32, 9, false, -4, PhysicalReg_ESP, true); //2nd argument
719 move_reg_to_mem(OpndSize_64, 1, false, -12, PhysicalReg_ESP, true); //1st argument
720 load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
721 scratchRegs[0] = PhysicalReg_SCRATCH_3;
722 call_dvmQuasiAtomicSwap64();
723 load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
724 }
725 else {
726 move_reg_to_mem(OpndSize_64, 1, false, offStaticField_value, PhysicalReg_EAX, true); //access field
727 }
728 }
729 //////////////////////////////////////////////
730 return 0;
731 }
732 #undef P_GPR_1
733 #undef P_GPR_2
734 #undef P_GPR_3
735 //! lower bytecode SGET by calling sget_sput_common
736
737 //!
op_sget()738 int op_sget() {
739 u2 vA = INST_AA(inst);
740 u2 tmp = FETCH(1);
741 int retval = sget_sput_common(SGET, vA, tmp, false, false);
742 rPC += 2;
743 return retval;
744 }
745 //! lower bytecode SGET_WIDE by calling sget_sput_common
746
747 //!
op_sget_wide(bool isVolatile)748 int op_sget_wide(bool isVolatile) {
749 u2 vA = INST_AA(inst);
750 u2 tmp = FETCH(1);
751 int retval = sget_sput_common(SGET_WIDE, vA, tmp, false, isVolatile);
752 rPC += 2;
753 return retval;
754 }
755 //! lower bytecode SGET_OBJECT by calling sget_sput_common
756
757 //!
op_sget_object()758 int op_sget_object() {
759 return op_sget();
760 }
761 //! lower bytecode SGET_BOOLEAN by calling sget_sput_common
762
763 //!
op_sget_boolean()764 int op_sget_boolean() {
765 return op_sget();
766 }
767 //! lower bytecode SGET_BYTE by calling sget_sput_common
768
769 //!
op_sget_byte()770 int op_sget_byte() {
771 return op_sget();
772 }
773 //! lower bytecode SGET_CHAR by calling sget_sput_common
774
775 //!
op_sget_char()776 int op_sget_char() {
777 return op_sget();
778 }
779 //! lower bytecode SGET_SHORT by calling sget_sput_common
780
781 //!
op_sget_short()782 int op_sget_short() {
783 return op_sget();
784 }
785 //! lower bytecode SPUT by calling sget_sput_common
786
787 //!
op_sput(bool isObj)788 int op_sput(bool isObj) {
789 u2 vA = INST_AA(inst);
790 u2 tmp = FETCH(1);
791 int retval = sget_sput_common(SPUT, vA, tmp, isObj, false);
792 rPC += 2;
793 return retval;
794 }
795 //! lower bytecode SPUT_WIDE by calling sget_sput_common
796
797 //!
op_sput_wide(bool isVolatile)798 int op_sput_wide(bool isVolatile) {
799 u2 vA = INST_AA(inst);
800 u2 tmp = FETCH(1);
801 int retval = sget_sput_common(SPUT_WIDE, vA, tmp, false, isVolatile);
802 rPC += 2;
803 return retval;
804 }
805 //! lower bytecode SPUT_OBJECT by calling sget_sput_common
806
807 //!
op_sput_object()808 int op_sput_object() {
809 return op_sput(true);
810 }
811 //! lower bytecode SPUT_OBJECT by calling sget_sput_common
812
813 //!
op_sput_boolean()814 int op_sput_boolean() {
815 return op_sput(false);
816 }
817 //! lower bytecode SPUT_BOOLEAN by calling sget_sput_common
818
819 //!
op_sput_byte()820 int op_sput_byte() {
821 return op_sput(false);
822 }
823 //! lower bytecode SPUT_BYTE by calling sget_sput_common
824
825 //!
op_sput_char()826 int op_sput_char() {
827 return op_sput(false);
828 }
829 //! lower bytecode SPUT_SHORT by calling sget_sput_common
830
831 //!
op_sput_short()832 int op_sput_short() {
833 return op_sput(false);
834 }
835 #define P_GPR_1 PhysicalReg_EBX
836 #define P_GPR_2 PhysicalReg_ECX
837 //! lower bytecode IGET_QUICK
838
839 //!
op_iget_quick()840 int op_iget_quick() {
841 u2 vA = INST_A(inst);
842 u2 vB = INST_B(inst); //object
843 u2 tmp = FETCH(1);
844
845 requestVRFreeDelay(vB,VRDELAY_NULLCHECK); // Request VR delay before transfer to temporary
846 get_virtual_reg(vB, OpndSize_32, 1, false);
847 nullCheck(1, false, 1, vB); //maybe optimized away, if not, call
848 cancelVRFreeDelayRequest(vB,VRDELAY_NULLCHECK);
849
850 move_mem_to_reg(OpndSize_32, tmp, 1, false, 2, false);
851 set_virtual_reg(vA, OpndSize_32, 2, false);
852 rPC += 2;
853 return 0;
854 }
855 #undef P_GPR_1
856 #undef P_GPR_2
857 #define P_GPR_1 PhysicalReg_EBX
858 //! lower bytecode IGET_WIDE_QUICK
859
860 //!
op_iget_wide_quick()861 int op_iget_wide_quick() {
862 u2 vA = INST_A(inst);
863 u2 vB = INST_B(inst); //object
864 u2 tmp = FETCH(1);
865
866 requestVRFreeDelay(vB,VRDELAY_NULLCHECK); // Request VR delay before transfer to temporary
867 get_virtual_reg(vB, OpndSize_32, 1, false);
868 nullCheck(1, false, 1, vB); //maybe optimized away, if not, call
869 cancelVRFreeDelayRequest(vB,VRDELAY_NULLCHECK);
870
871 move_mem_to_reg(OpndSize_64, tmp, 1, false, 1, false);
872 set_virtual_reg(vA, OpndSize_64, 1, false);
873 rPC += 2;
874 return 0;
875 }
876 #undef P_GPR_1
877 //! lower bytecode IGET_OBJECT_QUICK
878
879 //!
op_iget_object_quick()880 int op_iget_object_quick() {
881 return op_iget_quick();
882 }
883 #define P_GPR_1 PhysicalReg_EBX
884 #define P_GPR_2 PhysicalReg_ECX
885 //! lower bytecode IPUT_QUICK
886
887 //!
iput_quick_common(bool isObj)888 int iput_quick_common(bool isObj) {
889 u2 vA = INST_A(inst);
890 u2 vB = INST_B(inst); //object
891 u2 tmp = FETCH(1);
892
893 // Request VR delay before transfer to temporary. Only vB needs delay.
894 // vA will have non-zero reference count since transfer to temporary for
895 // it happens after null check, thus no delay is needed.
896 requestVRFreeDelay(vB,VRDELAY_NULLCHECK);
897 get_virtual_reg(vB, OpndSize_32, 1, false);
898 nullCheck(1, false, 1, vB); //maybe optimized away, if not, call
899 cancelVRFreeDelayRequest(vB,VRDELAY_NULLCHECK);
900
901 get_virtual_reg(vA, OpndSize_32, 2, false);
902 move_reg_to_mem(OpndSize_32, 2, false, tmp, 1, false);
903 if(isObj) {
904 markCard(2/*valReg*/, 1, false, 11, false);
905 }
906 rPC += 2;
907 return 0;
908 }
op_iput_quick()909 int op_iput_quick() {
910 return iput_quick_common(false);
911 }
912 #undef P_GPR_1
913 #undef P_GPR_2
914 #define P_GPR_1 PhysicalReg_EBX
915 //! lower bytecode IPUT_WIDE_QUICK
916
917 //!
op_iput_wide_quick()918 int op_iput_wide_quick() {
919 u2 vA = INST_A(inst);
920 u2 vB = INST_B(inst); //object
921 u2 tmp = FETCH(1); //byte offset
922
923 // Request VR delay before transfer to temporary. Only vB needs delay.
924 // vA will have non-zero reference count since transfer to temporary for
925 // it happens after null check, thus no delay is needed.
926 requestVRFreeDelay(vB,VRDELAY_NULLCHECK);
927 get_virtual_reg(vB, OpndSize_32, 1, false);
928 nullCheck(1, false, 1, vB); //maybe optimized away, if not, call
929 cancelVRFreeDelayRequest(vB,VRDELAY_NULLCHECK);
930
931 get_virtual_reg(vA, OpndSize_64, 1, false);
932 move_reg_to_mem(OpndSize_64, 1, false, tmp, 1, false);
933 rPC += 2;
934 return 0;
935 }
936 #undef P_GPR_1
937 //! lower bytecode IPUT_OBJECT_QUICK
938
939 //!
op_iput_object_quick()940 int op_iput_object_quick() {
941 return iput_quick_common(true);
942 }
943
944