Home | History | Annotate | Download | only in x86
      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
     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 //!
    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 //!
    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 //!
    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
    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
    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
    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
    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
    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
    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
    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
    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 //!
    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 //!
    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 //!
    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
    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 //!
    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
    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