LowerObject.cpp revision 0c2dc522d0e120f346cf0a40c8cf0c93346131c2
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
26extern 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
35int 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//!
169int 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//!
179int 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//!
189int 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
203int 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
240int 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
255int 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
294int 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
320int 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
362int 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
388int 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
441int 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//!
512int 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//!
553int 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//!
566int 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
609int 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//!
641int 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
661int 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