• 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 /*! \file LowerObject.cpp
18     \brief This file lowers the following bytecodes: CHECK_CAST,
19 */
20 #include "libdex/DexOpcodes.h"
21 #include "libdex/DexFile.h"
22 #include "Lower.h"
23 #include "NcgAot.h"
24 #include "enc_wrapper.h"
25 
26 extern void markCard_filled(int tgtAddrReg, bool isTgtPhysical, int scratchReg, bool isScratchPhysical);
27 
28 #define P_GPR_1 PhysicalReg_EBX
29 #define P_GPR_2 PhysicalReg_ECX
30 #define P_GPR_3 PhysicalReg_ESI
31 //! LOWER bytecode CHECK_CAST and INSTANCE_OF
32 //!   CALL class_resolve (%ebx is live across the call)
33 //!        dvmInstanceofNonTrivial
34 //!   NO register is live through function check_cast_helper
check_cast_nohelper(u2 vA,u4 tmp,bool instance,u2 vDest)35 int check_cast_nohelper(u2 vA, u4 tmp, bool instance, u2 vDest) {
36     get_virtual_reg(vA, OpndSize_32, 1, false); //object
37     scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
38     /* for trace-based JIT, it is likely that the class is already resolved */
39     bool needToResolve = true;
40     ClassObject *classPtr =
41                 (currentMethod->clazz->pDvmDex->pResClasses[tmp]);
42     ALOGV("in check_cast, class is resolved to %p", classPtr);
43     if(classPtr != NULL) {
44         needToResolve = false;
45         ALOGV("check_cast class %s", classPtr->descriptor);
46     }
47     if(needToResolve) {
48         //get_res_classes is moved here for NCG O1 to improve performance of GLUE optimization
49         scratchRegs[0] = PhysicalReg_SCRATCH_1; scratchRegs[1] = PhysicalReg_SCRATCH_2;
50         get_res_classes(4, false);
51     }
52     compare_imm_reg(OpndSize_32, 0, 1, false);
53 
54     rememberState(1);
55     //for private code cache, previously it jumped to .instance_of_okay_1
56     //if object reference is null, jump to the handler for this special case
57     if(instance) {
58         conditional_jump(Condition_E, ".instance_of_null", true);
59     }
60     else {
61         conditional_jump(Condition_E, ".check_cast_null", true);
62     }
63     //check whether the class is already resolved
64     //if yes, jump to check_cast_resolved
65     //if not, call class_resolve
66     if(needToResolve) {
67         move_mem_to_reg(OpndSize_32, tmp*4, 4, false, PhysicalReg_EAX, true);
68         compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
69         if(instance)
70             conditional_jump(Condition_NE, ".instance_of_resolved", true);
71         else
72             conditional_jump(Condition_NE, ".check_cast_resolved", true);
73         //try to resolve the class
74         rememberState(2);
75         move_imm_to_reg(OpndSize_32, tmp, PhysicalReg_EAX, true);
76         export_pc(); //trying to resolve the class
77         call_helper_API(".class_resolve");
78         transferToState(2);
79     } //needToResolve
80     else {
81         /* the class is already resolved and is constant */
82         move_imm_to_reg(OpndSize_32, (int)classPtr, PhysicalReg_EAX, true);
83     }
84     //class is resolved, and it is in %eax
85     if(!instance) {
86         insertLabel(".check_cast_resolved", true);
87     }
88     else insertLabel(".instance_of_resolved", true);
89 
90     move_mem_to_reg(OpndSize_32, offObject_clazz, 1, false, 6, false); //object->clazz
91 
92     //%eax: resolved class
93     //compare resolved class and object->clazz
94     //if the same, jump to the handler for this special case
95     compare_reg_reg(PhysicalReg_EAX, true, 6, false);
96     rememberState(3);
97     if(instance) {
98         conditional_jump(Condition_E, ".instance_of_equal", true);
99     } else {
100         conditional_jump(Condition_E, ".check_cast_equal", true);
101     }
102 
103     //prepare to call dvmInstanceofNonTrivial
104     //INPUT: the resolved class & object reference
105     load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
106     move_reg_to_mem(OpndSize_32, 6, false, 0, PhysicalReg_ESP, true);
107     move_reg_to_mem(OpndSize_32, PhysicalReg_EAX, true, 4, PhysicalReg_ESP, true); //resolved class
108     scratchRegs[0] = PhysicalReg_SCRATCH_3;
109     nextVersionOfHardReg(PhysicalReg_EAX, 2); //next version has 2 refs
110     call_dvmInstanceofNonTrivial();
111     load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
112     //
113     if(instance) {
114         //move return value to P_GPR_2
115         move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, 3, false);
116         rememberState(4);
117         unconditional_jump(".instance_of_okay", true);
118     } else {
119         //if return value of dvmInstanceofNonTrivial is zero, throw exception
120         compare_imm_reg(OpndSize_32, 0,  PhysicalReg_EAX, true);
121         rememberState(4);
122         conditional_jump(Condition_NE, ".check_cast_okay", true);
123         //two inputs for common_throw_message: object reference in eax, exception pointer in ecx
124         nextVersionOfHardReg(PhysicalReg_EAX, 1); //next version has 1 ref
125         move_reg_to_reg(OpndSize_32, 1, false, PhysicalReg_EAX, true);
126 
127         load_imm_global_data_API("strClassCastExceptionPtr", OpndSize_32, PhysicalReg_ECX, true);
128 
129         nextVersionOfHardReg(PhysicalReg_EDX, 2); //next version has 2 ref count
130         export_pc();
131 
132         unconditional_jump_global_API("common_throw_message", false);
133     }
134     //handler for speical case where object reference is null
135     if(instance)
136         insertLabel(".instance_of_null", true);
137     else insertLabel(".check_cast_null", true);
138     goToState(1);
139     if(instance) {
140         move_imm_to_reg(OpndSize_32, 0, 3, false);
141     }
142     transferToState(4);
143     if(instance)
144         unconditional_jump(".instance_of_okay", true);
145     else
146         unconditional_jump(".check_cast_okay", true);
147 
148     //handler for special case where class of object is the same as the resolved class
149     if(instance)
150         insertLabel(".instance_of_equal", true);
151     else insertLabel(".check_cast_equal", true);
152     goToState(3);
153     if(instance) {
154         move_imm_to_reg(OpndSize_32, 1, 3, false);
155     }
156     transferToState(4);
157     if(instance)
158         insertLabel(".instance_of_okay", true);
159     else insertLabel(".check_cast_okay", true);
160     //all cases merge here and the value is put to virtual register
161     if(instance) {
162         set_virtual_reg(vDest, OpndSize_32, 3, false);
163     }
164     return 0;
165 }
166 //! common code to lower CHECK_CAST & INSTANCE_OF
167 
168 //!
common_check_cast_instance_of(u2 vA,u4 tmp,bool instance,u2 vDest)169 int common_check_cast_instance_of(u2 vA, u4 tmp, bool instance, u2 vDest) {
170     return check_cast_nohelper(vA, tmp, instance, vDest);
171 }
172 #undef P_GPR_1
173 #undef P_GPR_2
174 #undef P_GPR_3
175 
176 //! LOWER bytecode CHECK_CAST
177 
178 //!
op_check_cast()179 int op_check_cast() {
180     u2 vA = INST_AA(inst);
181     u4 tmp = (u4)FETCH(1);
182     common_check_cast_instance_of(vA, tmp, false, 0);
183     rPC += 2;
184     return 0;
185 }
186 //!LOWER bytecode INSTANCE_OF
187 
188 //!
op_instance_of()189 int op_instance_of() {
190     u2 vB = INST_B(inst);
191     u2 vA = INST_A(inst);
192     u4 tmp = (u4)FETCH(1);
193     common_check_cast_instance_of(vB, tmp, true, vA);
194     rPC += 2;
195     return 0;
196 }
197 
198 #define P_GPR_1 PhysicalReg_EBX
199 #define P_GPR_2 PhysicalReg_ECX
200 //! LOWER bytecode MONITOR_ENTER without usage of helper function
201 
202 //!   CALL dvmLockObject
monitor_enter_nohelper(u2 vA)203 int monitor_enter_nohelper(u2 vA) {
204     scratchRegs[0] = PhysicalReg_SCRATCH_1;
205     scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
206 
207     requestVRFreeDelay(vA,VRDELAY_NULLCHECK); // Request VR delay before transfer to temporary
208     //get_self_pointer is separated
209     get_virtual_reg(vA, OpndSize_32, 1, false);
210     //to optimize redundant null check, NCG O1 wraps up null check in a function: nullCheck
211     get_self_pointer(3, false);
212     nullCheck(1, false, 1, vA); //maybe optimized away
213     cancelVRFreeDelayRequest(vA,VRDELAY_NULLCHECK);
214 
215     /////////////////////////////
216     //prepare to call dvmLockObject, inputs: object reference and self
217     // TODO: Should reset inJitCodeCache before calling dvmLockObject
218     //       so that code cache can be reset if needed when locking object
219     //       taking a long time. Not resetting inJitCodeCache may delay
220     //       code cache reset when code cache is full, preventing traces from
221     //       JIT compilation. This has performance implication.
222     //       However, after resetting inJitCodeCache, the code should be
223     //       wrapped in a helper instead of directly inlined in code cache.
224     //       If the code after dvmLockObject call is in code cache and the code
225     //       cache is reset during dvmLockObject call, execution after
226     //       dvmLockObject will return to a cleared code cache region,
227     //       resulting in seg fault.
228     load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
229     move_reg_to_mem(OpndSize_32, 1, false, 4, PhysicalReg_ESP, true);
230     move_reg_to_mem(OpndSize_32, 3, false, 0, PhysicalReg_ESP, true);
231     scratchRegs[0] = PhysicalReg_SCRATCH_2;
232     call_dvmLockObject();
233     load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
234     /////////////////////////////
235     return 0;
236 }
237 //! lower bytecode MONITOR_ENTER
238 
239 //! It will use helper function if switch is on
op_monitor_enter()240 int op_monitor_enter() {
241     u2 vA = INST_AA(inst);
242     export_pc();
243     monitor_enter_nohelper(vA);
244     rPC += 1;
245     return 0;
246 }
247 #undef P_GPR_1
248 #undef P_GPR_2
249 
250 #define P_GPR_1 PhysicalReg_EBX
251 #define P_GPR_2 PhysicalReg_ECX
252 //! lower bytecode MONITOR_EXIT
253 
254 //! It will use helper function if switch is on
op_monitor_exit()255 int op_monitor_exit() {
256     u2 vA = INST_AA(inst);
257     ////////////////////
258     //LOWER bytecode MONITOR_EXIT without helper function
259     //   CALL dvmUnlockObject
260     scratchRegs[0] = PhysicalReg_SCRATCH_1; scratchRegs[1] = PhysicalReg_SCRATCH_2;
261     scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
262     requestVRFreeDelay(vA,VRDELAY_NULLCHECK); // Request VR delay before transfer to temporary
263     get_virtual_reg(vA, OpndSize_32, 1, false);
264     nullCheck(1, false, 1, vA); //maybe optimized away
265     cancelVRFreeDelayRequest(vA,VRDELAY_NULLCHECK);
266 
267     /////////////////////////////
268     //prepare to call dvmUnlockObject, inputs: object reference and self
269     push_reg_to_stack(OpndSize_32, 1, false);
270     push_mem_to_stack(OpndSize_32, offEBP_self, PhysicalReg_EBP, true);
271     scratchRegs[0] = PhysicalReg_SCRATCH_2;
272     call_dvmUnlockObject();
273     compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
274     load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
275 
276     conditional_jump(Condition_NE, ".unlock_object_done", true);
277     //jump to dvmJitToExceptionThrown
278     scratchRegs[0] = PhysicalReg_SCRATCH_3;
279     jumpToExceptionThrown(2/*exception number*/);
280     insertLabel(".unlock_object_done", true);
281     ///////////////////////////
282     rPC += 1;
283     return 0;
284 }
285 #undef P_GPR_1
286 #undef P_GPR_2
287 
288 #define P_GPR_1 PhysicalReg_EBX
289 #define P_GPR_2 PhysicalReg_ECX
290 #define P_GPR_3 PhysicalReg_EDX /*vA*/
291 //! LOWER bytecode ARRAY_LENGTH
292 
293 //! It will use helper function if switch is on
op_array_length()294 int op_array_length() {
295     u2 vA = INST_A(inst);
296     u2 vB = INST_B(inst);
297     ////////////////////
298     //no usage of helper function
299     requestVRFreeDelay(vB,VRDELAY_NULLCHECK); // Request VR delay before transfer to temporary
300     get_virtual_reg(vB, OpndSize_32, 1, false);
301     nullCheck(1, false, 1, vB); //maybe optimized away
302     cancelVRFreeDelayRequest(vB,VRDELAY_NULLCHECK);
303 
304     move_mem_to_reg(OpndSize_32, offArrayObject_length, 1, false, 2, false);
305     set_virtual_reg(vA, OpndSize_32, 2, false);
306     ///////////////////////
307     rPC += 1;
308     return 0;
309 }
310 #undef P_GPR_1
311 #undef P_GPR_2
312 #undef P_GPR_3
313 
314 #define P_GPR_1 PhysicalReg_EBX
315 #define P_GPR_2 PhysicalReg_ECX
316 #define P_GPR_3 PhysicalReg_ESI
317 //! lower bytecode NEW_INSTANCE
318 
319 //! It will use helper function if switch is on
op_new_instance()320 int op_new_instance() {
321     u4 tmp = (u4)FETCH(1);
322     u2 vA = INST_AA(inst);
323     export_pc();
324     /* for trace-based JIT, class is already resolved */
325     ClassObject *classPtr =
326         (currentMethod->clazz->pDvmDex->pResClasses[tmp]);
327     assert(classPtr != NULL);
328     assert(classPtr->status & CLASS_INITIALIZED);
329     /*
330      * If it is going to throw, it should not make to the trace to begin
331      * with.  However, Alloc might throw, so we need to genExportPC()
332      */
333     assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
334     //prepare to call dvmAllocObject, inputs: resolved class & flag ALLOC_DONT_TRACK
335     load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
336     /* 1st argument to dvmAllocObject at -8(%esp) */
337     move_imm_to_mem(OpndSize_32, (int)classPtr, 0, PhysicalReg_ESP, true);
338     move_imm_to_mem(OpndSize_32, ALLOC_DONT_TRACK, 4, PhysicalReg_ESP, true);
339     scratchRegs[0] = PhysicalReg_SCRATCH_3;
340     nextVersionOfHardReg(PhysicalReg_EAX, 3); //next version has 3 refs
341     call_dvmAllocObject();
342     load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
343     //return value of dvmAllocObject is in %eax
344     //if return value is null, throw exception
345     compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
346     conditional_jump(Condition_NE, ".new_instance_done", true);
347     //jump to dvmJitToExceptionThrown
348     scratchRegs[0] = PhysicalReg_SCRATCH_4;
349     jumpToExceptionThrown(3/*exception number*/);
350     insertLabel(".new_instance_done", true);
351     set_virtual_reg(vA, OpndSize_32, PhysicalReg_EAX, true);
352     rPC += 2;
353     return 0;
354 }
355 
356 //! function to initialize a class
357 
358 //!INPUT: %eax (class object) %eax is recovered before return
359 //!OUTPUT: none
360 //!CALL: dvmInitClass
361 //!%eax, %esi, %ebx are live through function new_instance_needinit
new_instance_needinit()362 int new_instance_needinit() {
363     insertLabel(".new_instance_needinit", false);
364     load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
365     move_reg_to_mem(OpndSize_32, PhysicalReg_EAX, true, 0, PhysicalReg_ESP, true);
366     move_reg_to_mem(OpndSize_32, PhysicalReg_EAX, true, 4, PhysicalReg_ESP, true);
367     scratchRegs[0] = PhysicalReg_ECX;
368     call_dvmInitClass();
369     //if return value of dvmInitClass is zero, throw exception
370     compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
371     //recover EAX with the class object
372     move_mem_to_reg(OpndSize_32, 4, PhysicalReg_ESP, true, PhysicalReg_EAX, true);
373     load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
374     conditional_jump(Condition_E, "common_exceptionThrown", false);
375     x86_return();
376     return 0;
377 }
378 #undef P_GPR_1
379 #undef P_GPR_2
380 #undef P_GPR_3
381 
382 #define P_GPR_1 PhysicalReg_EBX //live through C function, must in callee-saved reg
383 #define P_GPR_2 PhysicalReg_ECX
384 #define P_GPR_3 PhysicalReg_EDX
385 //! lower bytecode NEW_ARRAY
386 
387 //! It will use helper function if switch is on
op_new_array()388 int op_new_array() {
389     u4 tmp = (u4)FETCH(1);
390     u2 vA = INST_A(inst); //destination
391     u2 vB = INST_B(inst); //length
392     /////////////////////////
393     //   REGS used: %esi, %eax, P_GPR_1, P_GPR_2
394     //   CALL class_resolve, dvmAllocArrayByClass
395     export_pc(); //use %edx
396     //check size of the array, if negative, throw exception
397     get_virtual_reg(vB, OpndSize_32, 5, false);
398     compare_imm_reg(OpndSize_32, 0, 5, false);
399     handlePotentialException(Condition_S, Condition_NS,
400                              1, "common_errNegArraySize");
401     void *classPtr = (void*)
402         (currentMethod->clazz->pDvmDex->pResClasses[tmp]);
403     assert(classPtr != NULL);
404     //here, class is already resolved, the class object is in %eax
405     //prepare to call dvmAllocArrayByClass with inputs: resolved class, array length, flag ALLOC_DONT_TRACK
406     insertLabel(".new_array_resolved", true);
407     load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
408     /* 1st argument to dvmAllocArrayByClass at 0(%esp) */
409     move_imm_to_mem(OpndSize_32, (int)classPtr, 0, PhysicalReg_ESP, true);
410     move_reg_to_mem(OpndSize_32, 5, false, 4, PhysicalReg_ESP, true);
411     move_imm_to_mem(OpndSize_32, ALLOC_DONT_TRACK, 8, PhysicalReg_ESP, true);
412     scratchRegs[0] = PhysicalReg_SCRATCH_3;
413     nextVersionOfHardReg(PhysicalReg_EAX, 3); //next version has 3 refs
414     call_dvmAllocArrayByClass();
415     load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
416 
417     //the allocated object is in %eax
418     //check whether it is null, throw exception if null
419     compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
420     conditional_jump(Condition_NE, ".new_array_done", true);
421     //jump to dvmJitToExceptionThrown
422     scratchRegs[0] = PhysicalReg_SCRATCH_4;
423     jumpToExceptionThrown(2/*exception number*/);
424     insertLabel(".new_array_done", true);
425     set_virtual_reg(vA, OpndSize_32, PhysicalReg_EAX, true);
426     //////////////////////////////////////
427     rPC += 2;
428     return 0;
429 }
430 #undef P_GPR_1
431 #undef P_GPR_2
432 #undef P_GPR_3
433 
434 #define P_GPR_1 PhysicalReg_EBX
435 #define P_GPR_2 PhysicalReg_ECX
436 #define P_GPR_3 PhysicalReg_ESI
437 //! common code to lower FILLED_NEW_ARRAY
438 
439 //! call: class_resolve call_dvmAllocPrimitiveArray
440 //! exception: filled_new_array_notimpl common_exceptionThrown
common_filled_new_array(u2 length,u4 tmp,bool hasRange)441 int common_filled_new_array(u2 length, u4 tmp, bool hasRange) {
442     ClassObject *classPtr =
443               (currentMethod->clazz->pDvmDex->pResClasses[tmp]);
444     if(classPtr != NULL) ALOGI("FILLED_NEW_ARRAY class %s", classPtr->descriptor);
445     //check whether class is resolved, if yes, jump to resolved
446     //if not, call class_resolve
447     scratchRegs[0] = PhysicalReg_SCRATCH_1; scratchRegs[1] = PhysicalReg_SCRATCH_2;
448     scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
449     get_res_classes(3, false);
450     move_mem_to_reg(OpndSize_32, tmp*4, 3, false, PhysicalReg_EAX, true);
451     export_pc();
452     compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true); //resolved class
453     conditional_jump(Condition_NE, ".filled_new_array_resolved", true);
454     rememberState(1);
455     move_imm_to_reg(OpndSize_32, tmp, PhysicalReg_EAX, true);
456     call_helper_API(".class_resolve");
457     transferToState(1);
458     //here, class is already resolved
459     insertLabel(".filled_new_array_resolved", true);
460     //check descriptor of the class object, if not implemented, throws exception
461     move_mem_to_reg(OpndSize_32, 24, PhysicalReg_EAX, true, 5, false);
462     //load a single byte of the descriptor
463     movez_mem_to_reg(OpndSize_8, 1, 5, false, 6, false);
464     compare_imm_reg(OpndSize_32, 'I', 6, false);
465     conditional_jump(Condition_E, ".filled_new_array_impl", true);
466     compare_imm_reg(OpndSize_32, 'L', 6, false);
467     conditional_jump(Condition_E, ".filled_new_array_impl", true);
468     compare_imm_reg(OpndSize_32, '[', 6, false);
469     conditional_jump(Condition_NE, ".filled_new_array_notimpl", false);
470 
471     insertLabel(".filled_new_array_impl", true);
472     //prepare to call dvmAllocArrayByClass with inputs: classObject, length, flag ALLOC_DONT_TRACK
473     load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
474     move_imm_to_mem(OpndSize_32, (int)classPtr, 0, PhysicalReg_ESP, true);
475     move_imm_to_mem(OpndSize_32, length, 4, PhysicalReg_ESP, true);
476     move_imm_to_mem(OpndSize_32, ALLOC_DONT_TRACK, 8, PhysicalReg_ESP, true);
477     scratchRegs[0] = PhysicalReg_SCRATCH_3; scratchRegs[1] = PhysicalReg_Null;
478     if(hasRange) {
479         nextVersionOfHardReg(PhysicalReg_EAX, 5+(length >= 1 ? LOOP_COUNT : 0)); //next version
480     }
481     else {
482         nextVersionOfHardReg(PhysicalReg_EAX, 5+length); //next version
483     }
484     call_dvmAllocArrayByClass();
485     load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
486     //return value of dvmAllocPrimitiveArray is in %eax
487     //if the return value is null, throw exception
488     compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
489     handlePotentialException(
490                                        Condition_E, Condition_NE,
491                                        3, "common_exceptionThrown");
492 
493     /* we need to mark the card of the new array, if it's not an int */
494     compare_imm_reg(OpndSize_32, 'I', 6, false);
495     conditional_jump(Condition_E, ".dont_mark_filled_new_array", true);
496 
497     // Need to make copy of EAX, because it's used later in op_filled_new_array()
498     move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, 6, false);
499 
500     markCard_filled(6, false, PhysicalReg_SCRATCH_4, false);
501 
502     insertLabel(".dont_mark_filled_new_array", true);
503 
504     //return value of bytecode FILLED_NEW_ARRAY is in GLUE structure
505     scratchRegs[0] = PhysicalReg_SCRATCH_4; scratchRegs[1] = PhysicalReg_Null;
506     set_return_value(OpndSize_32, PhysicalReg_EAX, true);
507     return 0;
508 }
509 //! LOWER bytecode FILLED_NEW_ARRAY
510 
511 //!
op_filled_new_array()512 int op_filled_new_array() {
513     u2 length = INST_B(inst);
514     u4 tmp = (u4)FETCH(1);
515     u2 v5 = INST_A(inst);
516     u2 vv = FETCH(2);
517     u2 v1 = vv & 0xf;
518     u2 v2 = (vv >> 4) & 0xf;
519     u2 v3 = (vv >> 8) & 0xf;
520     u2 v4 = (vv >> 12) & 0xf;
521     common_filled_new_array(length, tmp, false);
522     if(length >= 1) {
523         //move from virtual register to contents of array object
524         get_virtual_reg(v1, OpndSize_32, 7, false);
525         move_reg_to_mem(OpndSize_32, 7, false, offArrayObject_contents, PhysicalReg_EAX, true);
526     }
527     if(length >= 2) {
528         //move from virtual register to contents of array object
529         get_virtual_reg(v2, OpndSize_32, 8, false);
530         move_reg_to_mem(OpndSize_32, 8, false, offArrayObject_contents+4, PhysicalReg_EAX, true);
531     }
532     if(length >= 3) {
533         //move from virtual register to contents of array object
534         get_virtual_reg(v3, OpndSize_32, 9, false);
535         move_reg_to_mem(OpndSize_32, 9, false, offArrayObject_contents+8, PhysicalReg_EAX, true);
536     }
537     if(length >= 4) {
538         //move from virtual register to contents of array object
539         get_virtual_reg(v4, OpndSize_32, 10, false);
540         move_reg_to_mem(OpndSize_32, 10, false, offArrayObject_contents+12, PhysicalReg_EAX, true);
541     }
542     if(length >= 5) {
543         //move from virtual register to contents of array object
544         get_virtual_reg(v5, OpndSize_32, 11, false);
545         move_reg_to_mem(OpndSize_32, 11, false, offArrayObject_contents+16, PhysicalReg_EAX, true);
546     }
547     rPC += 3;
548     return 0;
549 }
550 //! function to handle the error of array not implemented
551 
552 //!
filled_new_array_notimpl()553 int filled_new_array_notimpl() {
554     //two inputs for common_throw:
555     insertLabel(".filled_new_array_notimpl", false);
556     move_imm_to_reg(OpndSize_32, LstrFilledNewArrayNotImpl, PhysicalReg_EAX, true);
557     move_imm_to_reg(OpndSize_32, (int) gDvm.exInternalError, PhysicalReg_ECX, true);
558     unconditional_jump("common_throw", false);
559     return 0;
560 }
561 
562 #define P_SCRATCH_1 PhysicalReg_EDX
563 //! LOWER bytecode FILLED_NEW_ARRAY_RANGE
564 
565 //!
op_filled_new_array_range()566 int op_filled_new_array_range() {
567     u2 length = INST_AA(inst);
568     u4 tmp = (u4)FETCH(1);
569     u4 vC = (u4)FETCH(2);
570     common_filled_new_array(length, tmp, true/*hasRange*/);
571     //here, %eax points to the array object
572     if(length >= 1) {
573         //dump all virtual registers used by this bytecode to stack, for NCG O1
574         int k;
575         for(k = 0; k < length; k++) {
576             spillVirtualReg(vC+k, LowOpndRegType_gp, true); //will update refCount
577         }
578         //address of the first virtual register that will be moved to the array object
579         load_effective_addr(vC*4, PhysicalReg_FP, true, 7, false); //addr
580         //start address for contents of the array object
581         load_effective_addr(offArrayObject_contents, PhysicalReg_EAX, true, 8, false); //addr
582         //loop counter
583         move_imm_to_reg(OpndSize_32, length-1, 9, false); //counter
584         //start of the loop
585         insertLabel(".filled_new_array_range_loop1", true);
586         rememberState(1);
587         move_mem_to_reg(OpndSize_32, 0, 7, false, 10, false);
588         load_effective_addr(4, 7, false, 7, false);
589         move_reg_to_mem(OpndSize_32, 10, false, 0, 8, false);
590         load_effective_addr(4, 8, false, 8, false);
591         alu_binary_imm_reg(OpndSize_32, sub_opc, 1, 9, false);
592         transferToState(1);
593         //jump back to the loop start
594         conditional_jump(Condition_NS, ".filled_new_array_range_loop1", true);
595     }
596     rPC += 3;
597     return 0;
598 }
599 #undef P_GPR_1
600 #undef P_GPR_2
601 #undef P_GPR_3
602 #undef P_SCRATCH_1
603 
604 #define P_GPR_1 PhysicalReg_EBX
605 //! LOWER bytecode FILL_ARRAY_DATA
606 
607 //!use 1 GPR and scratch regs (export_pc dvmInterpHandleFillArrayData)
608 //!CALL: dvmInterpHandleFillArrayData
op_fill_array_data()609 int op_fill_array_data() {
610     u2 vA = INST_AA(inst);
611     u4 tmp = (u4)FETCH(1);
612     tmp |= (u4)FETCH(2) << 16;
613     scratchRegs[0] = PhysicalReg_SCRATCH_1;
614     scratchRegs[1] = PhysicalReg_Null;
615     scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
616     get_virtual_reg(vA, OpndSize_32, 1, false);
617     //prepare to call dvmInterpHandleFillArrayData, input: array object, address of the data
618     load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
619     move_reg_to_mem(OpndSize_32, 1, false, 0, PhysicalReg_ESP, true);
620     /* 2nd argument to dvmInterpHandleFillArrayData at 4(%esp) */
621     move_imm_to_mem(OpndSize_32, (int)(rPC+tmp), 4, PhysicalReg_ESP, true);
622     call_dvmInterpHandleFillArrayData();
623     load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
624 
625     //check return value of dvmInterpHandleFillArrayData, if zero, throw exception
626     compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
627     conditional_jump(Condition_NE, ".fill_array_data_done", true);
628     //jump to dvmJitToExceptionThrown
629     scratchRegs[0] = PhysicalReg_SCRATCH_2;
630     jumpToExceptionThrown(2/*exception number*/);
631     insertLabel(".fill_array_data_done", true);
632     rPC += 3;
633     return 0;
634 }
635 #undef P_GPR_1
636 
637 #define P_GPR_1 PhysicalReg_EBX
638 //! LOWER bytecode THROW
639 
640 //!
op_throw()641 int op_throw() {
642     u2 vA = INST_AA(inst);
643     export_pc();
644     get_virtual_reg(vA, OpndSize_32, 1, false);
645     //null check
646     compare_imm_reg(OpndSize_32, 0, 1, false);
647     conditional_jump(Condition_E, "common_errNullObject", false);
648     //set glue->exception & throw exception
649     scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
650     scratchRegs[0] = PhysicalReg_SCRATCH_1; scratchRegs[1] = PhysicalReg_SCRATCH_2;
651     set_exception(1, false);
652     unconditional_jump("common_exceptionThrown", false);
653     rPC += 1;
654     return 0;
655 }
656 #undef P_GPR_1
657 #define P_GPR_1 PhysicalReg_EBX
658 //! LOWER bytecode THROW_VERIFICATION_ERROR
659 
660 //! op AA, ref@BBBB
op_throw_verification_error()661 int op_throw_verification_error() {
662     u2 vA, vB;
663     vA = INST_AA(inst);
664     vB = FETCH(1);
665 
666     export_pc();
667     scratchRegs[0] = PhysicalReg_SCRATCH_1;
668     get_glue_method(1, false);
669 
670     load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
671     move_imm_to_mem(OpndSize_32, vB, 8, PhysicalReg_ESP, true);
672     move_imm_to_mem(OpndSize_32, vA, 4, PhysicalReg_ESP, true);
673     move_reg_to_mem(OpndSize_32, 1, false, 0, PhysicalReg_ESP, true);
674     scratchRegs[0] = PhysicalReg_SCRATCH_2;
675     call_dvmThrowVerificationError();
676     load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
677 
678     unconditional_jump("common_exceptionThrown", false);
679     rPC += 2;
680     return 0;
681 }
682 #undef P_GPR_1
683