• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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