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