1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 18 /*! \file LowerInvoke.cpp 19 \brief This file lowers the following bytecodes: INVOKE_XXX 20 */ 21 #include "libdex/DexOpcodes.h" 22 #include "libdex/DexFile.h" 23 #include "mterp/Mterp.h" 24 #include "Lower.h" 25 #include "NcgAot.h" 26 #include "enc_wrapper.h" 27 28 char* streamMisPred = NULL; 29 30 /* according to callee, decide the ArgsDoneType*/ 31 ArgsDoneType convertCalleeToType(const Method* calleeMethod) { 32 if(calleeMethod == NULL) 33 return ArgsDone_Full; 34 if(dvmIsNativeMethod(calleeMethod)) 35 return ArgsDone_Native; 36 return ArgsDone_Normal; 37 } 38 int common_invokeMethodRange(ArgsDoneType); 39 int common_invokeMethodNoRange(ArgsDoneType); 40 void gen_predicted_chain(bool isRange, u2 tmp, int IMMC, bool isInterface, int inputReg); 41 42 //inputs to common_invokeMethodRange: %ecx 43 // common_errNoSuchMethod: %edx 44 #define P_GPR_1 PhysicalReg_ESI 45 #define P_GPR_2 PhysicalReg_EBX 46 #define P_GPR_3 PhysicalReg_ECX 47 #define P_SCRATCH_1 PhysicalReg_EDX 48 #define PP_GPR_1 PhysicalReg_EBX 49 #define PP_GPR_2 PhysicalReg_ESI 50 #define PP_GPR_3 PhysicalReg_EAX 51 #define PP_GPR_4 PhysicalReg_EDX 52 53 #ifdef WITH_JIT_INLINING 54 /* 55 * The function here takes care the 56 * branch over if prediction is correct and the misprediction target for misPredBranchOver. 57 */ 58 static void genLandingPadForMispredictedCallee(MIR* mir) { 59 BasicBlock *fallThrough = traceCurrentBB->fallThrough; 60 /* Bypass the move-result block if there is one */ 61 if (fallThrough->firstMIRInsn) { 62 assert(fallThrough->firstMIRInsn->OptimizationFlags & MIR_INLINED_PRED); 63 fallThrough = fallThrough->fallThrough; 64 } 65 /* Generate a branch over if the predicted inlining is correct */ 66 jumpToBasicBlock(stream, fallThrough->id); 67 /* Hook up the target to the verification branch */ 68 int relativeNCG = stream - streamMisPred; 69 unsigned instSize = encoder_get_inst_size(streamMisPred); 70 relativeNCG -= instSize; //size of the instruction 71 updateJumpInst(streamMisPred, OpndSize_8, relativeNCG); 72 } 73 #endif 74 75 //! LOWER bytecode INVOKE_VIRTUAL without usage of helper function 76 77 //! 78 int common_invoke_virtual_nohelper(bool isRange, u2 tmp, u2 vD) { 79 #ifdef WITH_JIT_INLINING 80 /* 81 * If the invoke has non-null misPredBranchOver, we need to generate 82 * the non-inlined version of the invoke here to handle the 83 * mispredicted case. 84 */ 85 if (traceCurrentMIR->meta.callsiteInfo->misPredBranchOver) { 86 genLandingPadForMispredictedCallee(); //cUnit, mir, bb, labelList); 87 } 88 #endif 89 scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null; 90 export_pc(); 91 constVREndOfBB(); 92 beforeCall("exception"); //dump GG, GL VRs 93 94 get_virtual_reg(vD, OpndSize_32, 5, false); 95 simpleNullCheck(5, false, vD); 96 #ifndef PREDICTED_CHAINING 97 move_mem_to_reg(OpndSize_32, offObject_clazz, 5, false, 6, false); //clazz of "this" 98 move_mem_to_reg(OpndSize_32, offClassObject_vtable, 6, false, 7, false); //vtable 99 /* method is already resolved in trace-based JIT */ 100 int methodIndex = 101 currentMethod->clazz->pDvmDex->pResMethods[tmp]->methodIndex; 102 move_mem_to_reg(OpndSize_32, methodIndex*4, 7, false, PhysicalReg_ECX, true); 103 if(isRange) { 104 common_invokeMethodRange(ArgsDone_Full); 105 } 106 else { 107 common_invokeMethodNoRange(ArgsDone_Full); 108 } 109 #else 110 int methodIndex = 111 currentMethod->clazz->pDvmDex->pResMethods[tmp]->methodIndex; 112 gen_predicted_chain(isRange, tmp, methodIndex*4, false, 5/*tmp5*/); 113 #endif 114 /////////////////////////////////// 115 return 0; 116 } 117 //! wrapper to call either common_invoke_virtual_helper or common_invoke_virtual_nohelper 118 119 //! 120 int common_invoke_virtual(bool isRange, u2 tmp, u2 vD) { 121 return common_invoke_virtual_nohelper(isRange, tmp, vD); 122 } 123 #undef P_GPR_1 124 #undef P_GPR_2 125 #undef P_GPR_3 126 #undef P_SCRATCH_1 127 #undef PP_GPR_1 128 #undef PP_GPR_2 129 #undef PP_GPR_3 130 #undef PP_GPR_4 131 132 #define P_GPR_1 PhysicalReg_ESI 133 #define P_GPR_2 PhysicalReg_EBX 134 #define P_GPR_3 PhysicalReg_EDX 135 #define PP_GPR_1 PhysicalReg_EBX 136 #define PP_GPR_2 PhysicalReg_ESI 137 #define PP_GPR_3 PhysicalReg_EAX 138 #define PP_GPR_4 PhysicalReg_EDX 139 //! common section to lower INVOKE_SUPER 140 141 //! It will use helper function if the switch is on 142 int common_invoke_super(bool isRange, u2 tmp) { 143 export_pc(); 144 constVREndOfBB(); 145 beforeCall("exception"); //dump GG, GL VRs 146 /////////////////////// 147 scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null; 148 /* method is already resolved in trace-based JIT */ 149 int mIndex = currentMethod->clazz->pDvmDex->pResMethods[tmp]->methodIndex; 150 const Method *calleeMethod = 151 currentMethod->clazz->super->vtable[mIndex]; 152 move_imm_to_reg(OpndSize_32, (int) calleeMethod, PhysicalReg_ECX, true); 153 if(isRange) { 154 common_invokeMethodRange(convertCalleeToType(calleeMethod)); 155 } 156 else { 157 common_invokeMethodNoRange(convertCalleeToType(calleeMethod)); 158 } 159 /////////////////////////////// 160 return 0; 161 } 162 #undef PP_GPR_1 163 #undef PP_GPR_2 164 #undef PP_GPR_3 165 #undef PP_GPR_4 166 167 //! helper function to handle no such method error 168 169 //! 170 int invoke_super_nsm() { 171 insertLabel(".invoke_super_nsm", false); 172 //NOTE: it seems that the name in %edx is not used in common_errNoSuchMethod 173 move_mem_to_reg(OpndSize_32, offMethod_name, PhysicalReg_EAX, true, PhysicalReg_EDX, true); //method name 174 unconditional_jump("common_errNoSuchMethod", false); 175 return 0; 176 } 177 #undef P_GPR_1 178 #undef P_GPR_2 179 #undef P_GPR_3 180 181 #define P_GPR_1 PhysicalReg_EBX 182 #define P_GPR_2 PhysicalReg_ESI 183 #define P_GPR_3 PhysicalReg_ECX 184 #define PP_GPR_1 PhysicalReg_EBX 185 #define PP_GPR_2 PhysicalReg_ESI 186 #define PP_GPR_3 PhysicalReg_EAX 187 #define PP_GPR_4 PhysicalReg_EDX 188 //! common section to lower INVOKE_DIRECT 189 190 //! It will use helper function if the switch is on 191 int common_invoke_direct(bool isRange, u2 tmp, u2 vD) { 192 //%ecx can be used as scratch when calling export_pc, get_res_methods and resolve_method 193 export_pc(); 194 constVREndOfBB(); 195 beforeCall("exception"); //dump GG, GL VRs 196 //////////////////////////////////// 197 get_virtual_reg(vD, OpndSize_32, 5, false); 198 simpleNullCheck(5, false, vD); 199 /* method is already resolved in trace-based JIT */ 200 const Method *calleeMethod = 201 currentMethod->clazz->pDvmDex->pResMethods[tmp]; 202 move_imm_to_reg(OpndSize_32, (int) calleeMethod, PhysicalReg_ECX, true); 203 //%ecx passed to common_invokeMethod... 204 if(isRange) { 205 common_invokeMethodRange(convertCalleeToType(calleeMethod)); 206 } 207 else { 208 common_invokeMethodNoRange(convertCalleeToType(calleeMethod)); 209 } 210 //////////////////////////// 211 return 0; 212 } 213 #undef P_GPR_1 214 #undef P_GPR_2 215 #undef P_GPR_3 216 #undef PP_GPR_1 217 #undef PP_GPR_2 218 #undef PP_GPR_3 219 #undef PP_GPR_4 220 221 #define P_GPR_1 PhysicalReg_EBX 222 #define P_GPR_3 PhysicalReg_ECX 223 #define PP_GPR_1 PhysicalReg_EBX 224 #define PP_GPR_2 PhysicalReg_ESI 225 #define PP_GPR_3 PhysicalReg_EAX 226 #define PP_GPR_4 PhysicalReg_EDX 227 //! common section to lower INVOKE_STATIC 228 229 //! It will use helper function if the switch is on 230 int common_invoke_static(bool isRange, u2 tmp) { 231 //%ecx can be used as scratch when calling export_pc, get_res_methods and resolve_method 232 export_pc(); 233 constVREndOfBB(); 234 beforeCall("exception"); //dump GG, GL VRs 235 //////////////////////////// 236 /* method is already resolved in trace-based JIT */ 237 const Method *calleeMethod = 238 currentMethod->clazz->pDvmDex->pResMethods[tmp]; 239 move_imm_to_reg(OpndSize_32, (int) calleeMethod, PhysicalReg_ECX, true); 240 //%ecx passed to common_invokeMethod... 241 if(isRange) { 242 common_invokeMethodRange(convertCalleeToType(calleeMethod)); 243 } 244 else { 245 common_invokeMethodNoRange(convertCalleeToType(calleeMethod)); 246 } 247 //////////////////////// 248 return 0; 249 } 250 #undef P_GPR_1 251 #undef PP_GPR_1 252 #undef PP_GPR_2 253 #undef PP_GPR_3 254 #undef PP_GPR_4 255 256 #define P_GPR_1 PhysicalReg_EBX 257 #define P_GPR_2 PhysicalReg_EAX //scratch 258 #define P_GPR_3 PhysicalReg_ECX 259 #define P_SCRATCH_1 PhysicalReg_ESI //clazz of object 260 #define PP_GPR_1 PhysicalReg_EBX 261 #define PP_GPR_2 PhysicalReg_ESI 262 #define PP_GPR_3 PhysicalReg_EAX 263 #define PP_GPR_4 PhysicalReg_EDX 264 //! common section to lower INVOKE_INTERFACE 265 266 //! It will use helper function if the switch is on 267 int common_invoke_interface(bool isRange, u2 tmp, u2 vD) { 268 #ifdef WITH_JIT_INLINING 269 /* 270 * If the invoke has non-null misPredBranchOver, we need to generate 271 * the non-inlined version of the invoke here to handle the 272 * mispredicted case. 273 */ 274 if (traceCurrentMIR->meta.callsiteInfo->misPredBranchOver) { 275 genLandingPadForMispredictedCallee(); //cUnit, mir, bb, labelList); 276 } 277 #endif 278 export_pc(); //use %edx 279 constVREndOfBB(); 280 beforeCall("exception"); //dump GG, GL VRs 281 /////////////////////// 282 scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null; 283 get_virtual_reg(vD, OpndSize_32, 1, false); 284 simpleNullCheck(1, false, vD); 285 286 #ifndef PREDICTED_CHAINING 287 load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 288 move_imm_to_mem(OpndSize_32, tmp, 4, PhysicalReg_ESP, true); 289 /* for trace-based JIT, pDvmDex is a constant at JIT time 290 4th argument to dvmFindInterfaceMethodInCache at -4(%esp) */ 291 move_imm_to_mem(OpndSize_32, (int) currentMethod->clazz->pDvmDex, 12, PhysicalReg_ESP, true); 292 move_mem_to_reg(OpndSize_32, offObject_clazz, 1, false, 5, false); 293 /* for trace-based JIT, method is a constant at JIT time 294 3rd argument to dvmFindInterfaceMethodInCache at 8(%esp) */ 295 move_imm_to_mem(OpndSize_32, (int) currentMethod, 8, PhysicalReg_ESP, true); 296 move_reg_to_mem(OpndSize_32, 5, false, 0, PhysicalReg_ESP, true); 297 scratchRegs[0] = PhysicalReg_SCRATCH_3; scratchRegs[1] = PhysicalReg_Null; 298 call_dvmFindInterfaceMethodInCache(); 299 load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 300 compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true); 301 302 conditional_jump_global_API(Condition_E, "common_exceptionThrown", false); 303 move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, PhysicalReg_ECX, true); 304 if(isRange) { 305 common_invokeMethodRange(ArgsDone_Full); 306 } 307 else { 308 common_invokeMethodNoRange(ArgsDone_Full); 309 } 310 #else 311 gen_predicted_chain(isRange, tmp, -1, true /*interface*/, 1/*tmp1*/); 312 #endif 313 /////////////////////// 314 return 0; 315 } 316 #undef PP_GPR_1 317 #undef PP_GPR_2 318 #undef PP_GPR_3 319 #undef PP_GPR_4 320 #undef P_GPR_1 321 #undef P_GPR_2 322 #undef P_GPR_3 323 #undef P_SCRATCH_1 324 //! lower bytecode INVOKE_VIRTUAL by calling common_invoke_virtual 325 326 //! 327 int op_invoke_virtual() { 328 #ifdef WITH_JIT_INLINING 329 /* An invoke with the MIR_INLINED is effectively a no-op */ 330 if (traceCurrentMIR->OptimizationFlags & MIR_INLINED) 331 return false; 332 #endif 333 //B|A|op CCCC G|F|E|D 334 //D: the first argument, which is the "this" pointer 335 //B: argument count 336 //D,E,F,G,A: arguments 337 u2 vD = FETCH(2) & 0xf; 338 u2 tmp = FETCH(1); //method index 339 int retval = common_invoke_virtual(false/*not range*/, tmp, vD); 340 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2) 341 insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on 342 #endif 343 rPC += 3; 344 return retval; 345 } 346 //! lower bytecode INVOKE_SUPER by calling common_invoke_super 347 348 //! 349 int op_invoke_super() { 350 #ifdef WITH_JIT_INLINING 351 /* An invoke with the MIR_INLINED is effectively a no-op */ 352 if (traceCurrentMIR->OptimizationFlags & MIR_INLINED) 353 return false; 354 #endif 355 //B|A|op CCCC G|F|E|D 356 //D: the first argument 357 //B: argument count 358 //D,E,F,G,A: arguments 359 u2 tmp = FETCH(1); //method index 360 int retval = common_invoke_super(false/*not range*/, tmp); 361 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2) 362 insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on 363 #endif 364 rPC += 3; 365 return retval; 366 } 367 //! lower bytecode INVOKE_DIRECT by calling common_invoke_direct 368 369 //! 370 int op_invoke_direct() { 371 #ifdef WITH_JIT_INLINING 372 /* An invoke with the MIR_INLINED is effectively a no-op */ 373 if (traceCurrentMIR->OptimizationFlags & MIR_INLINED) 374 return false; 375 #endif 376 //B|A|op CCCC G|F|E|D 377 //D: the first argument, which is the "this" pointer 378 //B: argument count 379 //D,E,F,G,A: arguments 380 u2 vD = FETCH(2) & 0xf; 381 u2 tmp = FETCH(1); //method index 382 int retval = common_invoke_direct(false/*not range*/, tmp, vD); 383 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2) 384 insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on 385 #endif 386 rPC += 3; 387 return retval; 388 } 389 //! lower bytecode INVOKE_STATIC by calling common_invoke_static 390 391 //! 392 int op_invoke_static() { 393 #ifdef WITH_JIT_INLINING 394 /* An invoke with the MIR_INLINED is effectively a no-op */ 395 if (traceCurrentMIR->OptimizationFlags & MIR_INLINED) 396 return false; 397 #endif 398 //B|A|op CCCC G|F|E|D 399 //D: the first argument 400 //B: argument count 401 //D,E,F,G,A: arguments 402 u2 tmp = FETCH(1); //method index 403 int retval = common_invoke_static(false/*not range*/, tmp); 404 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2) 405 insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on 406 #endif 407 rPC += 3; 408 return retval; 409 } 410 //! lower bytecode INVOKE_INTERFACE by calling common_invoke_interface 411 412 //! 413 int op_invoke_interface() { 414 #ifdef WITH_JIT_INLINING 415 /* An invoke with the MIR_INLINED is effectively a no-op */ 416 if (traceCurrentMIR->OptimizationFlags & MIR_INLINED) 417 return false; 418 #endif 419 //B|A|op CCCC G|F|E|D 420 //D: the first argument, which is the "this" pointer 421 //B: argument count 422 //D,E,F,G,A: arguments 423 u2 vD = FETCH(2) & 0xf; 424 u2 tmp = FETCH(1); //method index 425 int retval = common_invoke_interface(false/*not range*/, tmp, vD); 426 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2) 427 insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on 428 #endif 429 rPC += 3; 430 return retval; 431 } 432 //! lower bytecode INVOKE_VIRTUAL_RANGE by calling common_invoke_virtual 433 434 //! 435 int op_invoke_virtual_range() { 436 #ifdef WITH_JIT_INLINING 437 /* An invoke with the MIR_INLINED is effectively a no-op */ 438 if (traceCurrentMIR->OptimizationFlags & MIR_INLINED) 439 return false; 440 #endif 441 //AA|op BBBB CCCC 442 //CCCC: the first argument, which is the "this" pointer 443 //AA: argument count 444 u2 tmp = FETCH(1); //BBBB, method index 445 u2 vD = FETCH(2); //the first argument 446 int retval = common_invoke_virtual(true/*range*/, tmp, vD); 447 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2) 448 insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on 449 #endif 450 rPC += 3; 451 return retval; 452 } 453 //! lower bytecode INVOKE_SUPER_RANGE by calling common_invoke_super 454 455 //! 456 int op_invoke_super_range() { 457 #ifdef WITH_JIT_INLINING 458 /* An invoke with the MIR_INLINED is effectively a no-op */ 459 if (traceCurrentMIR->OptimizationFlags & MIR_INLINED) 460 return false; 461 #endif 462 u2 tmp = FETCH(1); //BBBB, method index 463 int retval = common_invoke_super(true/*range*/, tmp); 464 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2) 465 insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on 466 #endif 467 rPC += 3; 468 return retval; 469 } 470 //! lower bytecode INVOKE_DIRECT_RANGE by calling common_invoke_direct 471 472 //! 473 int op_invoke_direct_range() { 474 #ifdef WITH_JIT_INLINING 475 /* An invoke with the MIR_INLINED is effectively a no-op */ 476 if (traceCurrentMIR->OptimizationFlags & MIR_INLINED) 477 return false; 478 #endif 479 u2 tmp = FETCH(1); //BBBB, method index 480 u2 vD = FETCH(2); //the first argument 481 int retval = common_invoke_direct(true/*range*/, tmp, vD); 482 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2) 483 insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on 484 #endif 485 rPC += 3; 486 return retval; 487 } 488 //! lower bytecode INVOKE_STATIC_RANGE by calling common_invoke_static 489 490 //! 491 int op_invoke_static_range() { 492 #ifdef WITH_JIT_INLINING 493 /* An invoke with the MIR_INLINED is effectively a no-op */ 494 if (traceCurrentMIR->OptimizationFlags & MIR_INLINED) 495 return false; 496 #endif 497 u2 tmp = FETCH(1); //BBBB, method index 498 int retval = common_invoke_static(true/*range*/, tmp); 499 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2) 500 insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on 501 #endif 502 rPC += 3; 503 return retval; 504 } 505 //! lower bytecode INVOKE_INTERFACE_RANGE by calling common_invoke_interface 506 507 //! 508 int op_invoke_interface_range() { 509 #ifdef WITH_JIT_INLINING 510 /* An invoke with the MIR_INLINED is effectively a no-op */ 511 if (traceCurrentMIR->OptimizationFlags & MIR_INLINED) 512 return false; 513 #endif 514 u2 tmp = FETCH(1); //BBBB, method index 515 u2 vD = FETCH(2); //the first argument 516 int retval = common_invoke_interface(true/*range*/, tmp, vD); 517 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2) 518 insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on 519 #endif 520 rPC += 3; 521 return retval; 522 } 523 524 //used %ecx, %edi, %esp %ebp 525 #define P_GPR_1 PhysicalReg_EBX 526 #define P_SCRATCH_1 PhysicalReg_ESI 527 #define P_SCRATCH_2 PhysicalReg_EAX 528 #define P_SCRATCH_3 PhysicalReg_EDX 529 #define P_SCRATCH_4 PhysicalReg_ESI 530 #define P_SCRATCH_5 PhysicalReg_EAX 531 //! pass the arguments for invoking method without range 532 533 //! 534 int common_invokeMethodNoRange_noJmp() { 535 u2 count = INST_B(inst); 536 u2 vD = FETCH(2) & 0xf; 537 u2 vE = (FETCH(2) >> 4) & 0xf; 538 u2 vF = (FETCH(2) >> 8) & 0xf; 539 u2 vG = (FETCH(2) >> 12) & 0xf; 540 u2 vA = INST_A(inst); //5th argument 541 int offsetFromSaveArea = -4; 542 if(count == 5) { 543 get_virtual_reg(vA, OpndSize_32, 22, false); 544 move_reg_to_mem(OpndSize_32, 22, false, offsetFromSaveArea-sizeofStackSaveArea, PhysicalReg_FP, true); 545 offsetFromSaveArea -= 4; 546 } 547 if(count >= 4) { 548 get_virtual_reg(vG, OpndSize_32, 23, false); 549 move_reg_to_mem(OpndSize_32, 23, false, offsetFromSaveArea-sizeofStackSaveArea, PhysicalReg_FP, true); 550 offsetFromSaveArea -= 4; 551 } 552 if(count >= 3) { 553 get_virtual_reg(vF, OpndSize_32, 24, false); 554 move_reg_to_mem(OpndSize_32, 24, false, offsetFromSaveArea-sizeofStackSaveArea, PhysicalReg_FP, true); 555 offsetFromSaveArea -= 4; 556 } 557 if(count >= 2) { 558 get_virtual_reg(vE, OpndSize_32, 25, false); 559 move_reg_to_mem(OpndSize_32, 25, false, offsetFromSaveArea-sizeofStackSaveArea, PhysicalReg_FP, true); 560 offsetFromSaveArea -= 4; 561 } 562 if(count >= 1) { 563 get_virtual_reg(vD, OpndSize_32, 26, false); 564 move_reg_to_mem(OpndSize_32, 26, false, offsetFromSaveArea-sizeofStackSaveArea, PhysicalReg_FP, true); 565 } 566 return 0; 567 } 568 569 int common_invokeMethod_Jmp(ArgsDoneType form) { 570 nextVersionOfHardReg(PhysicalReg_EDX, 1); 571 move_imm_to_reg(OpndSize_32, (int)rPC, PhysicalReg_EDX, true); 572 //arguments needed in ArgsDone: 573 // start of HotChainingCell for next bytecode: -4(%esp) 574 // start of InvokeSingletonChainingCell for callee: -8(%esp) 575 load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 576 insertChainingWorklist(traceCurrentBB->fallThrough->id, stream); 577 move_chain_to_mem(OpndSize_32, traceCurrentBB->fallThrough->id, 4, PhysicalReg_ESP, true); 578 // for honeycomb: JNI call doesn't need a chaining cell, so the taken branch is null 579 if(traceCurrentBB->taken) 580 insertChainingWorklist(traceCurrentBB->taken->id, stream); 581 int takenId = traceCurrentBB->taken ? traceCurrentBB->taken->id : 0; 582 move_chain_to_mem(OpndSize_32, takenId, 0, PhysicalReg_ESP, true); 583 if(form == ArgsDone_Full) 584 unconditional_jump_global_API(".invokeArgsDone_jit", false); 585 else if(form == ArgsDone_Native) 586 unconditional_jump_global_API(".invokeArgsDone_native", false); 587 else 588 unconditional_jump_global_API(".invokeArgsDone_normal", false); 589 return 0; 590 } 591 592 int common_invokeMethodNoRange(ArgsDoneType form) { 593 common_invokeMethodNoRange_noJmp(); 594 common_invokeMethod_Jmp(form); 595 return 0; 596 } 597 598 #undef P_GPR_1 599 #undef P_SCRATCH_1 600 #undef P_SCRATCH_2 601 #undef P_SCRATCH_3 602 #undef P_SCRATCH_4 603 #undef P_SCRATCH_5 604 605 //input: %ecx (method to call) 606 #define P_GPR_1 PhysicalReg_EBX 607 #define P_GPR_2 PhysicalReg_ESI 608 #define P_GPR_3 PhysicalReg_EDX //not used with P_SCRATCH_2 609 #define P_SCRATCH_1 PhysicalReg_EAX 610 #define P_SCRATCH_2 PhysicalReg_EDX 611 #define P_SCRATCH_3 PhysicalReg_EAX 612 #define P_SCRATCH_4 PhysicalReg_EDX 613 #define P_SCRATCH_5 PhysicalReg_EAX 614 #define P_SCRATCH_6 PhysicalReg_EDX 615 #define P_SCRATCH_7 PhysicalReg_EAX 616 #define P_SCRATCH_8 PhysicalReg_EDX 617 #define P_SCRATCH_9 PhysicalReg_EAX 618 #define P_SCRATCH_10 PhysicalReg_EDX 619 //! pass the arguments for invoking method with range 620 621 //! loop is unrolled when count <= 10 622 int common_invokeMethodRange_noJmp() { 623 u2 count = INST_AA(inst); 624 u2 vD = FETCH(2); //the first argument 625 savearea_from_fp(21, false); 626 //vD to rFP-4*count-20 627 //vD+1 to rFP-4*count-20+4 = rFP-20-4*(count-1) 628 if(count >= 1 && count <= 10) { 629 get_virtual_reg(vD, OpndSize_32, 22, false); 630 move_reg_to_mem(OpndSize_32, 22, false, -4*count, 21, false); 631 } 632 if(count >= 2 && count <= 10) { 633 get_virtual_reg(vD+1, OpndSize_32, 23, false); 634 move_reg_to_mem(OpndSize_32, 23, false, -4*(count-1), 21, false); 635 } 636 if(count >= 3 && count <= 10) { 637 get_virtual_reg(vD+2, OpndSize_32, 24, false); 638 move_reg_to_mem(OpndSize_32, 24, false, -4*(count-2), 21, false); 639 } 640 if(count >= 4 && count <= 10) { 641 get_virtual_reg(vD+3, OpndSize_32, 25, false); 642 move_reg_to_mem(OpndSize_32, 25, false, -4*(count-3), 21, false); 643 } 644 if(count >= 5 && count <= 10) { 645 get_virtual_reg(vD+4, OpndSize_32, 26, false); 646 move_reg_to_mem(OpndSize_32, 26, false, -4*(count-4), 21, false); 647 } 648 if(count >= 6 && count <= 10) { 649 get_virtual_reg(vD+5, OpndSize_32, 27, false); 650 move_reg_to_mem(OpndSize_32, 27, false, -4*(count-5), 21, false); 651 } 652 if(count >= 7 && count <= 10) { 653 get_virtual_reg(vD+6, OpndSize_32, 28, false); 654 move_reg_to_mem(OpndSize_32, 28, false, -4*(count-6), 21, false); 655 } 656 if(count >= 8 && count <= 10) { 657 get_virtual_reg(vD+7, OpndSize_32, 29, false); 658 move_reg_to_mem(OpndSize_32, 29, false, -4*(count-7), 21, false); 659 } 660 if(count >= 9 && count <= 10) { 661 get_virtual_reg(vD+8, OpndSize_32, 30, false); 662 move_reg_to_mem(OpndSize_32, 30, false, -4*(count-8), 21, false); 663 } 664 if(count == 10) { 665 get_virtual_reg(vD+9, OpndSize_32, 31, false); 666 move_reg_to_mem(OpndSize_32, 31, false, -4*(count-9), 21, false); 667 } 668 if(count > 10) { 669 //dump to memory first, should we set physicalReg to Null? 670 //this bytecodes uses a set of virtual registers (update getVirtualInfo) 671 //this is necessary to correctly insert transfer points 672 int k; 673 for(k = 0; k < count; k++) { 674 spillVirtualReg(vD+k, LowOpndRegType_gp, true); //will update refCount 675 } 676 load_effective_addr(4*vD, PhysicalReg_FP, true, 12, false); 677 alu_binary_imm_reg(OpndSize_32, sub_opc, 4*count, 21, false); 678 move_imm_to_reg(OpndSize_32, count, 13, false); 679 insertLabel(".invokeMethod_1", true); //if checkDup: will perform work from ShortWorklist 680 rememberState(1); 681 move_mem_to_reg(OpndSize_32, 0, 12, false, 14, false); 682 move_reg_to_mem(OpndSize_32, 14, false, 0, 21, false); 683 load_effective_addr(4, 12, false, 12, false); 684 alu_binary_imm_reg(OpndSize_32, sub_opc, 1, 13, false); 685 load_effective_addr(4, 21, false, 21, false); 686 transferToState(1); 687 conditional_jump(Condition_NE, ".invokeMethod_1", true); //backward branch 688 } 689 return 0; 690 } 691 692 int common_invokeMethodRange(ArgsDoneType form) { 693 common_invokeMethodRange_noJmp(); 694 common_invokeMethod_Jmp(form); 695 return 0; 696 } 697 #undef P_GPR_1 698 #undef P_GPR_2 699 #undef P_GPR_3 700 #undef P_SCRATCH_1 701 #undef P_SCRATCH_2 702 #undef P_SCRATCH_3 703 #undef P_SCRATCH_4 704 #undef P_SCRATCH_5 705 #undef P_SCRATCH_6 706 #undef P_SCRATCH_7 707 #undef P_SCRATCH_8 708 #undef P_SCRATCH_9 709 #undef P_SCRATCH_10 710 711 #define P_GPR_1 PhysicalReg_EBX 712 #define P_GPR_3 PhysicalReg_ESI 713 #define P_SCRATCH_1 PhysicalReg_EAX 714 #define P_SCRATCH_2 PhysicalReg_EDX 715 #define P_SCRATCH_3 PhysicalReg_EAX 716 #define P_SCRATCH_4 PhysicalReg_EDX 717 #define P_SCRATCH_5 PhysicalReg_EAX 718 #define P_SCRATCH_6 PhysicalReg_EDX 719 720 //! spill a register to native stack 721 722 //! decrease %esp by 4, then store a register at 0(%esp) 723 int spill_reg(int reg, bool isPhysical) { 724 load_effective_addr(-4, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 725 move_reg_to_mem(OpndSize_32, reg, isPhysical, 0, PhysicalReg_ESP, true); 726 return 0; 727 } 728 //! get a register from native stack 729 730 //! load a register from 0(%esp), then increase %esp by 4 731 int unspill_reg(int reg, bool isPhysical) { 732 move_mem_to_reg(OpndSize_32, 0, PhysicalReg_ESP, true, reg, isPhysical); 733 load_effective_addr(4, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 734 return 0; 735 } 736 737 void generate_invokeNative(bool generateForNcg); //forward declaration 738 void generate_stackOverflow(); //forward declaration 739 740 //! common code to invoke a method after all arguments are handled 741 742 //! 743 //takes one argument to generate code 744 // for invokeNativeSingle (form == ArgsDone_Native) 745 // or invokeNonNativeSingle (form == ArgsDone_Normal) when WITH_JIT is true 746 // to dynamically determine which one to choose (form == ArgsDone_Full) 747 /* common_invokeArgsDone is called at NCG time and 748 at execution time during relocation 749 generate invokeArgsDone for NCG if isJitFull is false && form == Full */ 750 int common_invokeArgsDone(ArgsDoneType form, bool isJitFull) { 751 bool generateForNcg = false; 752 if(form == ArgsDone_Full) { 753 if(isJitFull) 754 insertLabel(".invokeArgsDone_jit", false); 755 else { 756 insertLabel(".invokeArgsDone", false); 757 generateForNcg = true; 758 } 759 } 760 else if(form == ArgsDone_Normal) 761 insertLabel(".invokeArgsDone_normal", false); 762 else if(form == ArgsDone_Native) 763 insertLabel(".invokeArgsDone_native", false); 764 //%ecx: methodToCall 765 movez_mem_to_reg(OpndSize_16, offMethod_registersSize, PhysicalReg_ECX, true, P_SCRATCH_1, true); //regSize 766 scratchRegs[0] = PhysicalReg_EBX; scratchRegs[1] = PhysicalReg_ESI; 767 scratchRegs[2] = PhysicalReg_EDX; scratchRegs[3] = PhysicalReg_Null; 768 savearea_from_fp(P_GPR_3, true); 769 alu_binary_imm_reg(OpndSize_32, shl_opc, 2, P_SCRATCH_1, true); 770 alu_binary_reg_reg(OpndSize_32, sub_opc, P_SCRATCH_1, true, P_GPR_3, true); 771 //update newSaveArea->savedPc, here P_GPR_3 is new FP 772 move_reg_to_mem(OpndSize_32, PhysicalReg_EDX, true, offStackSaveArea_savedPc-sizeofStackSaveArea, P_GPR_3, true); 773 movez_mem_to_reg(OpndSize_16, offMethod_outsSize, PhysicalReg_ECX, true, P_SCRATCH_2, true); //outsSize 774 move_reg_to_reg(OpndSize_32, P_GPR_3, true, P_GPR_1, true); //new FP 775 alu_binary_imm_reg(OpndSize_32, sub_opc, sizeofStackSaveArea, P_GPR_3, true); 776 777 alu_binary_imm_reg(OpndSize_32, shl_opc, 2, P_SCRATCH_2, true); 778 alu_binary_reg_reg(OpndSize_32, sub_opc, P_SCRATCH_2, true, P_GPR_3, true); 779 get_self_pointer(P_SCRATCH_3, true); 780 move_reg_to_mem(OpndSize_32, PhysicalReg_FP, true, offStackSaveArea_prevFrame-sizeofStackSaveArea, P_GPR_1, true); //set stack->prevFrame 781 compare_mem_reg(OpndSize_32, offsetof(Thread, interpStackEnd), P_SCRATCH_3, true, P_GPR_3, true); 782 conditional_jump(Condition_L, ".stackOverflow", true); 783 784 if(form == ArgsDone_Full) { 785 test_imm_mem(OpndSize_32, ACC_NATIVE, offMethod_accessFlags, PhysicalReg_ECX, true); 786 } 787 move_reg_to_mem(OpndSize_32, PhysicalReg_ECX, true, offStackSaveArea_method-sizeofStackSaveArea, P_GPR_1, true); //set stack->method 788 789 if(form == ArgsDone_Native || form == ArgsDone_Full) { 790 /* to correctly handle code cache reset: 791 update returnAddr and check returnAddr after done with the native method 792 if returnAddr is set to NULL during code cache reset, 793 the execution will correctly continue with interpreter */ 794 //get returnAddr from 4(%esp) and update stack 795 move_mem_to_reg(OpndSize_32, 4, PhysicalReg_ESP, true, 796 PhysicalReg_EDX, true); 797 move_reg_to_mem(OpndSize_32, PhysicalReg_EDX, true, 798 offStackSaveArea_returnAddr-sizeofStackSaveArea, P_GPR_1, true); 799 } 800 if(form == ArgsDone_Native) { 801 generate_invokeNative(generateForNcg); 802 return 0; 803 } 804 if(form == ArgsDone_Full) { 805 conditional_jump(Condition_NE, ".invokeNative", true); 806 } 807 move_mem_to_reg(OpndSize_32, offMethod_clazz, PhysicalReg_ECX, true, P_SCRATCH_4, true); //get method->claz 808 move_mem_to_reg(OpndSize_32, offClassObject_pDvmDex, P_SCRATCH_4, true, P_SCRATCH_4, true); //get method->clazz->pDvmDex 809 move_reg_to_reg(OpndSize_32, P_GPR_1, true, PhysicalReg_FP, true); //update rFP 810 get_self_pointer(P_GPR_1, true); 811 move_reg_to_mem(OpndSize_32, PhysicalReg_ECX, true, offsetof(Thread, interpSave.method), P_GPR_1, true); //glue->method 812 move_reg_to_mem(OpndSize_32, P_SCRATCH_4, true, offsetof(Thread, interpSave.methodClassDex), P_GPR_1, true); //set_glue_dvmdex 813 move_reg_to_mem(OpndSize_32, PhysicalReg_FP, true, offThread_curFrame, P_GPR_1, true); //set glue->self->frame 814 if(!generateForNcg) { 815 /* returnAddr updated already for Full */ 816 //get returnAddr from 4(%esp) and update stack 817 if(form == ArgsDone_Normal) 818 move_mem_to_reg(OpndSize_32, 4, PhysicalReg_ESP, true, 819 PhysicalReg_EDX, true); 820 //for JIT: starting bytecode in %ebx to invoke JitToInterp 821 move_mem_to_reg(OpndSize_32, offMethod_insns, PhysicalReg_ECX, true, PhysicalReg_EBX, true); 822 if(form == ArgsDone_Normal) 823 move_reg_to_mem(OpndSize_32, PhysicalReg_EDX, true, 824 offStackSaveArea_returnAddr-sizeofStackSaveArea, PhysicalReg_FP, true); 825 } 826 827 insertLabel(".invokeInterp", true); 828 if(!generateForNcg) { 829 bool callNoChain = false; 830 #ifdef PREDICTED_CHAINING 831 if(form == ArgsDone_Full) callNoChain = true; 832 #endif 833 if(callNoChain) { 834 scratchRegs[0] = PhysicalReg_EAX; 835 load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 836 #if defined(WITH_JIT_TUNING) 837 /* Predicted chaining failed. Fall back to interpreter and indicate 838 * inline cache miss. 839 */ 840 move_imm_to_reg(OpndSize_32, kInlineCacheMiss, PhysicalReg_EDX, true); 841 #endif 842 call_dvmJitToInterpTraceSelectNoChain(); //input: rPC in %ebx 843 } else { 844 //jump to the stub at (%esp) 845 move_mem_to_reg(OpndSize_32, 0, PhysicalReg_ESP, true, 846 PhysicalReg_EDX, true); 847 load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 848 unconditional_jump_reg(PhysicalReg_EDX, true); 849 } 850 } 851 852 if(form == ArgsDone_Full) generate_invokeNative(generateForNcg); 853 generate_stackOverflow(); 854 return 0; 855 } 856 857 /* when WITH_JIT is true, 858 JIT'ed code invokes native method, after invoke, execution will continue 859 with the interpreter or with JIT'ed code if chained 860 */ 861 void generate_invokeNative(bool generateForNcg) { 862 insertLabel(".invokeNative", true); 863 //if(!generateForNcg) 864 // load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 865 load_effective_addr(-28, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 866 move_reg_to_mem(OpndSize_32, P_GPR_1, true, 0, PhysicalReg_ESP, true); 867 move_reg_to_mem(OpndSize_32, P_GPR_1, true, 20, PhysicalReg_ESP, true); 868 scratchRegs[0] = PhysicalReg_EDX; 869 get_self_pointer(P_SCRATCH_1, true); //glue->self 870 move_reg_to_mem(OpndSize_32, PhysicalReg_ECX, true, 8, PhysicalReg_ESP, true); 871 move_reg_to_mem(OpndSize_32, P_SCRATCH_1, true, 12, PhysicalReg_ESP, true); 872 move_reg_to_mem(OpndSize_32, P_SCRATCH_1, true, 24, PhysicalReg_ESP, true); 873 move_mem_to_reg(OpndSize_32, offThread_jniLocal_nextEntry, P_SCRATCH_1, true, P_SCRATCH_2, true); //get self->local_next 874 scratchRegs[1] = PhysicalReg_EAX; 875 move_reg_to_mem(OpndSize_32, P_SCRATCH_2, true, offStackSaveArea_localRefTop-sizeofStackSaveArea, P_GPR_1, true); //update jniLocalRef of stack 876 move_reg_to_mem(OpndSize_32, P_GPR_1, true, offThread_curFrame, P_SCRATCH_1, true); //set self->curFrame 877 move_imm_to_mem(OpndSize_32, 0, offThread_inJitCodeCache, P_SCRATCH_1, true); //clear self->inJitCodeCache 878 load_effective_addr(offsetof(Thread, interpSave.retval), P_SCRATCH_1, true, P_SCRATCH_3, true); //self->retval 879 move_reg_to_mem(OpndSize_32, P_SCRATCH_3, true, 4, PhysicalReg_ESP, true); 880 //NOTE: native method checks the interpreted stack for arguments 881 // The immediate arguments on native stack: address of return value, new FP, self 882 call_mem(40, PhysicalReg_ECX, true);//*40(%ecx) 883 //we can't assume the argument stack is unmodified after the function call 884 //duplicate newFP & glue->self on stack: newFP (-28 & -8) glue->self (-16 & -4) 885 move_mem_to_reg(OpndSize_32, 20, PhysicalReg_ESP, true, P_GPR_3, true); //new FP 886 move_mem_to_reg(OpndSize_32, 24, PhysicalReg_ESP, true, P_GPR_1, true); //glue->self 887 load_effective_addr(28, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 888 move_mem_to_reg(OpndSize_32, offStackSaveArea_localRefTop-sizeofStackSaveArea, P_GPR_3, true, P_SCRATCH_1, true); //newSaveArea->jniLocal 889 compare_imm_mem(OpndSize_32, 0, offThread_exception, P_GPR_1, true); //self->exception 890 if(!generateForNcg) 891 load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 892 //NOTE: PhysicalReg_FP should be callee-saved register 893 move_reg_to_mem(OpndSize_32, PhysicalReg_FP, true, offThread_curFrame, P_GPR_1, true); //set self->curFrame 894 move_reg_to_mem(OpndSize_32, P_SCRATCH_1, true, offThread_jniLocal_nextEntry, P_GPR_1, true); //set self->jniLocal 895 conditional_jump(Condition_NE, "common_exceptionThrown", false); 896 if(!generateForNcg) { 897 //get returnAddr, if it is not NULL, 898 // return to JIT'ed returnAddr after executing the native method 899 /* to correctly handle code cache reset: 900 update returnAddr and check returnAddr after done with the native method 901 if returnAddr is set to NULL during code cache reset, 902 the execution will correctly continue with interpreter */ 903 move_mem_to_reg(OpndSize_32, offStackSaveArea_returnAddr-sizeofStackSaveArea, P_GPR_3, true, P_SCRATCH_2, true); 904 //set self->inJitCodeCache to returnAddr (P_GPR_1 is in %ebx) 905 move_reg_to_mem(OpndSize_32, P_SCRATCH_2, true, offThread_inJitCodeCache, P_GPR_1, true); 906 move_mem_to_reg(OpndSize_32, offStackSaveArea_savedPc-sizeofStackSaveArea, P_GPR_3, true, PhysicalReg_EBX, true); //savedPc 907 compare_imm_reg(OpndSize_32, 0, P_SCRATCH_2, true); 908 conditional_jump(Condition_E, ".nativeToInterp", true); 909 unconditional_jump_reg(P_SCRATCH_2, true); 910 //if returnAddr is NULL, return to interpreter after executing the native method 911 insertLabel(".nativeToInterp", true); 912 //move rPC by 6 (3 bytecode units for INVOKE) 913 alu_binary_imm_reg(OpndSize_32, add_opc, 6, PhysicalReg_EBX, true); 914 scratchRegs[0] = PhysicalReg_EAX; 915 #if defined(WITH_JIT_TUNING) 916 /* Return address not in code cache. Indicate that continuing with interpreter 917 */ 918 move_imm_to_reg(OpndSize_32, kCallsiteInterpreted, PhysicalReg_EDX, true); 919 #endif 920 call_dvmJitToInterpTraceSelectNoChain(); //rPC in %ebx 921 } 922 return; 923 } 924 void generate_stackOverflow() { 925 insertLabel(".stackOverflow", true); 926 //load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 927 move_reg_to_mem(OpndSize_32, PhysicalReg_ECX, true, 4, PhysicalReg_ESP, true); 928 get_self_pointer(P_GPR_1, true); //glue->self 929 move_reg_to_mem(OpndSize_32, P_GPR_1, true, 0, PhysicalReg_ESP, true); 930 call_dvmHandleStackOverflow(); 931 load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 932 unconditional_jump("common_exceptionThrown", false); 933 } 934 #undef P_GPR_1 935 #undef P_GPR_2 936 #undef P_GPR_3 937 #undef P_SCRATCH_1 938 #undef P_SCRATCH_2 939 #undef P_SCRATCH_3 940 #undef P_SCRATCH_4 941 #undef P_SCRATCH_5 942 #undef P_SCRATCH_6 943 944 ///////////////////////////////////////////// 945 #define P_GPR_1 PhysicalReg_EBX 946 #define P_GPR_2 PhysicalReg_ECX 947 #define P_SCRATCH_1 PhysicalReg_ESI 948 #define P_SCRATCH_2 PhysicalReg_EDX 949 #define P_SCRATCH_3 PhysicalReg_ESI 950 #define P_SCRATCH_4 PhysicalReg_EDX 951 //! lower bytecode EXECUTE_INLINE 952 953 //! 954 int op_execute_inline(bool isRange) { 955 //tmp, vC, vD, vE, vF 956 int num; 957 if(!isRange) num = INST_B(inst); 958 else num = INST_AA(inst); 959 u2 tmp = FETCH(1); 960 u2 vC, vD, vE, vF; 961 if(!isRange) { 962 vC = FETCH(2) & 0xf; 963 vD = (FETCH(2) >> 4) & 0xf; 964 vE = (FETCH(2) >> 8) & 0xf; 965 vF = FETCH(2) >> 12; 966 } else { 967 vC = FETCH(2); 968 vD = vC + 1; 969 vE = vC + 2; 970 vF = vC + 3; 971 } 972 export_pc(); 973 switch (tmp) { 974 case INLINE_EMPTYINLINEMETHOD: 975 return 0; /* Nop */ 976 case INLINE_STRING_LENGTH: 977 get_virtual_reg(vC, OpndSize_32, 1, false); 978 compare_imm_reg(OpndSize_32, 0, 1, false); 979 conditional_jump(Condition_NE, ".do_inlined_string_length", true); 980 scratchRegs[0] = PhysicalReg_SCRATCH_1; 981 jumpToExceptionThrown(1/*exception number*/); 982 insertLabel(".do_inlined_string_length", true); 983 move_mem_to_reg(OpndSize_32, 0x14, 1, false, 2, false); 984 get_self_pointer(3, false); 985 move_reg_to_mem(OpndSize_32, 2, false, offsetof(Thread, interpSave.retval), 3, false); 986 return 0; 987 case INLINE_STRING_IS_EMPTY: 988 get_virtual_reg(vC, OpndSize_32, 1, false); 989 compare_imm_reg(OpndSize_32, 0, 1, false); 990 conditional_jump(Condition_NE, ".do_inlined_string_length", true); 991 scratchRegs[0] = PhysicalReg_SCRATCH_1; 992 jumpToExceptionThrown(1/*exception number*/); 993 insertLabel(".do_inlined_string_length", true); 994 compare_imm_mem(OpndSize_32, 0, 0x14, 1, false); 995 conditional_jump(Condition_E, ".inlined_string_length_return_true", 996 true); 997 get_self_pointer(2, false); 998 move_imm_to_mem(OpndSize_32, 0, offsetof(Thread, interpSave.retval), 2, false); 999 unconditional_jump(".inlined_string_length_done", true); 1000 insertLabel(".inlined_string_length_return_true", true); 1001 get_self_pointer(2, false); 1002 move_imm_to_mem(OpndSize_32, 1, offsetof(Thread, interpSave.retval), 2, false); 1003 insertLabel(".inlined_string_length_done", true); 1004 return 0; 1005 case INLINE_MATH_ABS_INT: 1006 get_virtual_reg(vC, OpndSize_32, 1, false); 1007 move_reg_to_reg(OpndSize_32, 1, false, 2, false); 1008 alu_binary_imm_reg(OpndSize_32, sar_opc, 0x1f, 2, false); 1009 alu_binary_reg_reg(OpndSize_32, xor_opc, 2, false, 1, false); 1010 alu_binary_reg_reg(OpndSize_32, sub_opc, 2, false, 1, false); 1011 get_self_pointer(3, false); 1012 move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 3, false); 1013 return 0; 1014 case INLINE_MATH_ABS_LONG: 1015 get_virtual_reg(vD, OpndSize_32, 1, false); 1016 move_reg_to_reg(OpndSize_32, 1, false, 2, false); 1017 alu_binary_imm_reg(OpndSize_32, sar_opc, 0x1f, 1, false); 1018 move_reg_to_reg(OpndSize_32, 1, false, 3, false); 1019 move_reg_to_reg(OpndSize_32, 1, false, 4, false); 1020 get_virtual_reg(vC, OpndSize_32, 5, false); 1021 alu_binary_reg_reg(OpndSize_32, xor_opc, 5, false, 1, false); 1022 get_self_pointer(6, false); 1023 move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 6, false); 1024 alu_binary_reg_reg(OpndSize_32, xor_opc, 2, false, 3, false); 1025 move_reg_to_mem(OpndSize_32, 3, false, 4 + offsetof(Thread, interpSave.retval), 6, false); 1026 alu_binary_reg_mem(OpndSize_32, sub_opc, 4, false, offsetof(Thread, interpSave.retval), 6, false); 1027 alu_binary_reg_mem(OpndSize_32, sbb_opc, 4, false, 4 + offsetof(Thread, interpSave.retval), 6, false); 1028 return 0; 1029 case INLINE_MATH_MAX_INT: 1030 get_virtual_reg(vC, OpndSize_32, 1, false); 1031 get_virtual_reg(vD, OpndSize_32, 2, false); 1032 compare_reg_reg(1, false, 2, false); 1033 conditional_move_reg_to_reg(OpndSize_32, Condition_GE, 2, 1034 false/*src*/, 1, false/*dst*/); 1035 get_self_pointer(3, false); 1036 move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 3, false); 1037 return 0; 1038 case INLINE_MATH_ABS_FLOAT: 1039 get_virtual_reg(vC, OpndSize_32, 1, false); 1040 alu_binary_imm_reg(OpndSize_32, and_opc, 0x7fffffff, 1, false); 1041 get_self_pointer(2, false); 1042 move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 2, false); 1043 return 0; 1044 case INLINE_MATH_ABS_DOUBLE: 1045 get_virtual_reg(vC, OpndSize_32, 1, false); 1046 get_virtual_reg(vD, OpndSize_32, 2, false); 1047 alu_binary_imm_reg(OpndSize_32, and_opc, 0x7fffffff, 2, false); 1048 get_self_pointer(3, false); 1049 move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 3, false); 1050 move_reg_to_mem(OpndSize_32, 2, false, 4 + offsetof(Thread, interpSave.retval), 3, false); 1051 return 0; 1052 case INLINE_STRING_FASTINDEXOF_II: 1053 #if defined(USE_GLOBAL_STRING_DEFS) 1054 break; 1055 #else 1056 get_virtual_reg(vC, OpndSize_32, 1, false); 1057 compare_imm_reg(OpndSize_32, 0, 1, false); 1058 get_virtual_reg(vD, OpndSize_32, 2, false); 1059 get_virtual_reg(vE, OpndSize_32, 3, false); 1060 conditional_jump(Condition_NE, ".do_inlined_string_fastIndexof", 1061 true); 1062 scratchRegs[0] = PhysicalReg_SCRATCH_1; 1063 jumpToExceptionThrown(1/*exception number*/); 1064 insertLabel(".do_inlined_string_fastIndexof", true); 1065 move_mem_to_reg(OpndSize_32, 0x14, 1, false, 4, false); 1066 move_mem_to_reg(OpndSize_32, 0x8, 1, false, 5, false); 1067 move_mem_to_reg(OpndSize_32, 0x10, 1, false, 6, false); 1068 alu_binary_reg_reg(OpndSize_32, xor_opc, 1, false, 1, false); 1069 compare_imm_reg(OpndSize_32, 0, 3, false); 1070 conditional_move_reg_to_reg(OpndSize_32, Condition_NS, 3, false, 1, 1071 false); 1072 compare_reg_reg(4, false, 1, false); 1073 conditional_jump(Condition_GE, 1074 ".do_inlined_string_fastIndexof_exitfalse", true); 1075 dump_mem_scale_reg(Mnemonic_LEA, OpndSize_32, 5, false, 0xc/*disp*/, 1076 6, false, 2, 5, false, LowOpndRegType_gp); 1077 movez_mem_disp_scale_to_reg(OpndSize_16, 5, false, 0, 1, false, 2, 1078 3, false); 1079 compare_reg_reg(3, false, 2, false); 1080 conditional_jump(Condition_E, ".do_inlined_string_fastIndexof_exit", 1081 true); 1082 load_effective_addr(0x1, 1, false, 3, false); 1083 load_effective_addr_scale(5, false, 3, false, 2, 5, false); 1084 unconditional_jump(".do_inlined_string_fastIndexof_iter", true); 1085 insertLabel(".do_inlined_string_fastIndexof_ch_cmp", true); 1086 if(gDvm.executionMode == kExecutionModeNcgO1) { 1087 rememberState(1); 1088 } 1089 movez_mem_to_reg(OpndSize_16, 0, 5, false, 6, false); 1090 load_effective_addr(0x2, 5, false, 5, false); 1091 compare_reg_reg(6, false, 2, false); 1092 conditional_jump(Condition_E, ".do_inlined_string_fastIndexof_exit", 1093 true); 1094 load_effective_addr(0x1, 3, false, 3, false); 1095 insertLabel(".do_inlined_string_fastIndexof_iter", true); 1096 compare_reg_reg(4, false, 3, false); 1097 move_reg_to_reg(OpndSize_32, 3, false, 1, false); 1098 if(gDvm.executionMode == kExecutionModeNcgO1) { 1099 transferToState(1); 1100 } 1101 conditional_jump(Condition_NE, 1102 ".do_inlined_string_fastIndexof_ch_cmp", true); 1103 insertLabel(".do_inlined_string_fastIndexof_exitfalse", true); 1104 move_imm_to_reg(OpndSize_32, 0xffffffff, 1, false); 1105 insertLabel(".do_inlined_string_fastIndexof_exit", true); 1106 get_self_pointer(7, false); 1107 move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 7, false); 1108 return 0; 1109 case INLINE_FLOAT_TO_RAW_INT_BITS: 1110 get_virtual_reg(vC, OpndSize_32, 1, false); 1111 get_self_pointer(2, false); 1112 move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 2, false); 1113 return 0; 1114 case INLINE_INT_BITS_TO_FLOAT: 1115 get_virtual_reg(vC, OpndSize_32, 1, false); 1116 get_self_pointer(2, false); 1117 move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 2, false); 1118 return 0; 1119 case INLINE_DOUBLE_TO_RAW_LONG_BITS: 1120 get_virtual_reg(vC, OpndSize_32, 1, false); 1121 get_self_pointer(3, false); 1122 move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 3, false); 1123 get_virtual_reg(vD, OpndSize_32, 2, false); 1124 move_reg_to_mem(OpndSize_32, 2, false, 4 + offsetof(Thread, interpSave.retval), 3, false); 1125 return 0; 1126 case INLINE_LONG_BITS_TO_DOUBLE: 1127 get_virtual_reg(vC, OpndSize_32, 1, false); 1128 get_virtual_reg(vD, OpndSize_32, 2, false); 1129 get_self_pointer(3, false); 1130 move_reg_to_mem(OpndSize_32, 2, false, 4 + offsetof(Thread, interpSave.retval), 3, false); 1131 move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 3, false); 1132 return 0; 1133 default: 1134 break; 1135 } 1136 #endif 1137 get_self_pointer(PhysicalReg_SCRATCH_1, false); 1138 load_effective_addr(offsetof(Thread, interpSave.retval), PhysicalReg_SCRATCH_1, false, 1, false); 1139 load_effective_addr(-24, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 1140 move_reg_to_mem(OpndSize_32, 1, false, 16, PhysicalReg_ESP, true); 1141 if(num >= 1) { 1142 get_virtual_reg(vC, OpndSize_32, 2, false); 1143 move_reg_to_mem(OpndSize_32, 2, false, 0, PhysicalReg_ESP, true); 1144 } 1145 if(num >= 2) { 1146 get_virtual_reg(vD, OpndSize_32, 3, false); 1147 move_reg_to_mem(OpndSize_32, 3, false, 4, PhysicalReg_ESP, true); 1148 } 1149 if(num >= 3) { 1150 get_virtual_reg(vE, OpndSize_32, 4, false); 1151 move_reg_to_mem(OpndSize_32, 4, false, 8, PhysicalReg_ESP, true); 1152 } 1153 if(num >= 4) { 1154 get_virtual_reg(vF, OpndSize_32, 5, false); 1155 move_reg_to_mem(OpndSize_32, 5, false, 12, PhysicalReg_ESP, true); 1156 } 1157 beforeCall("execute_inline"); 1158 load_imm_global_data_API("gDvmInlineOpsTable", OpndSize_32, 6, false); 1159 call_mem(16*tmp, 6, false);// 1160 afterCall("execute_inline"); 1161 compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true); 1162 1163 load_effective_addr(24, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 1164 conditional_jump(Condition_NE, ".execute_inline_done", true); 1165 //jump to dvmJitToExceptionThrown 1166 scratchRegs[0] = PhysicalReg_SCRATCH_1; 1167 jumpToExceptionThrown(1/*exception number*/); 1168 insertLabel(".execute_inline_done", true); 1169 rPC += 3; 1170 return 0; 1171 } 1172 #undef P_GPR_1 1173 #undef P_GPR_2 1174 #undef P_SCRATCH_1 1175 #undef P_SCRATCH_2 1176 #undef P_SCRATCH_3 1177 #undef P_SCRATCH_4 1178 1179 //! lower bytecode INVOKE_OBJECT_INIT_RANGE 1180 1181 //! 1182 int op_invoke_object_init_range() { 1183 return -1; 1184 } 1185 1186 #define P_GPR_1 PhysicalReg_EBX 1187 #define P_SCRATCH_1 PhysicalReg_ESI 1188 #define P_SCRATCH_2 PhysicalReg_EDX 1189 #define PP_GPR_1 PhysicalReg_EBX 1190 #define PP_GPR_2 PhysicalReg_ESI 1191 #define PP_GPR_3 PhysicalReg_EAX 1192 #define PP_GPR_4 PhysicalReg_EDX 1193 //! common code for INVOKE_VIRTUAL_QUICK 1194 1195 //! It uses helper function if the switch is on 1196 int common_invoke_virtual_quick(bool hasRange, u2 vD, u2 IMMC) { 1197 #ifdef WITH_JIT_INLINING 1198 /* An invoke with the MIR_INLINED is effectively a no-op */ 1199 if (traceCurrentMIR->OptimizationFlags & MIR_INLINED) 1200 return false; 1201 /* 1202 * If the invoke has non-null misPredBranchOver, we need to generate 1203 * the non-inlined version of the invoke here to handle the 1204 * mispredicted case. 1205 */ 1206 if (traceCurrentMIR->meta.callsiteInfo->misPredBranchOver) { 1207 genLandingPadForMispredictedCallee(); //cUnit, mir, bb, labelList); 1208 } 1209 #endif 1210 export_pc(); 1211 constVREndOfBB(); 1212 beforeCall("exception"); //dump GG, GL VRs 1213 ///////////////////////////////////////////////// 1214 get_virtual_reg(vD, OpndSize_32, 1, false); 1215 simpleNullCheck(1, false, vD); 1216 #ifndef PREDICTED_CHAINING 1217 move_mem_to_reg(OpndSize_32, 0, 1, false, 2, false); 1218 move_mem_to_reg(OpndSize_32, offClassObject_vtable, 2, false, 3, false); 1219 move_mem_to_reg(OpndSize_32, IMMC, 3, false, PhysicalReg_ECX, true); 1220 1221 if(hasRange) { 1222 common_invokeMethodRange(ArgsDone_Full); 1223 } 1224 else { 1225 common_invokeMethodNoRange(ArgsDone_Full); 1226 } 1227 #else 1228 gen_predicted_chain(hasRange, -1, IMMC, false, 1/*tmp1*/); 1229 #endif 1230 //////////////////////// 1231 return 0; 1232 } 1233 #undef P_GPR_1 1234 #undef P_SCRATCH_1 1235 #undef P_SCRATCH_2 1236 #undef PP_GPR_1 1237 #undef PP_GPR_2 1238 #undef PP_GPR_3 1239 #undef PP_GPR_4 1240 //! lower bytecode INVOKE_VIRTUAL_QUICK by calling common_invoke_virtual_quick 1241 1242 //! 1243 int op_invoke_virtual_quick() { 1244 u2 vD = FETCH(2) & 0xf; 1245 u2 IMMC = 4*FETCH(1); 1246 int retval = common_invoke_virtual_quick(false, vD, IMMC); 1247 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2) 1248 insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on 1249 #endif 1250 rPC += 3; 1251 return retval; 1252 } 1253 //! lower bytecode INVOKE_VIRTUAL_QUICK_RANGE by calling common_invoke_virtual_quick 1254 1255 //! 1256 int op_invoke_virtual_quick_range() { 1257 u2 vD = FETCH(2); 1258 u2 IMMC = 4*FETCH(1); 1259 int retval = common_invoke_virtual_quick(true, vD, IMMC); 1260 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2) 1261 insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on 1262 #endif 1263 rPC += 3; 1264 return retval; 1265 } 1266 #define P_GPR_1 PhysicalReg_EBX 1267 #define P_GPR_2 PhysicalReg_ESI 1268 #define P_SCRATCH_1 PhysicalReg_EDX 1269 //! common code to lower INVOKE_SUPER_QUICK 1270 1271 //! 1272 int common_invoke_super_quick(bool hasRange, u2 vD, u2 IMMC) { 1273 export_pc(); 1274 constVREndOfBB(); 1275 beforeCall("exception"); //dump GG, GL VRs 1276 compare_imm_VR(OpndSize_32, 0, vD); 1277 1278 conditional_jump_global_API(Condition_E, "common_errNullObject", false); 1279 /* for trace-based JIT, callee is already resolved */ 1280 int mIndex = IMMC/4; 1281 const Method *calleeMethod = currentMethod->clazz->super->vtable[mIndex]; 1282 move_imm_to_reg(OpndSize_32, (int) calleeMethod, PhysicalReg_ECX, true); 1283 if(hasRange) { 1284 common_invokeMethodRange(convertCalleeToType(calleeMethod)); 1285 } 1286 else { 1287 common_invokeMethodNoRange(convertCalleeToType(calleeMethod)); 1288 } 1289 return 0; 1290 } 1291 #undef P_GPR_1 1292 #undef P_GPR_2 1293 #undef P_SCRATCH_1 1294 //! lower bytecode INVOKE_SUPER_QUICK by calling common_invoke_super_quick 1295 1296 //! 1297 int op_invoke_super_quick() { 1298 u2 vD = FETCH(2) & 0xf; 1299 u2 IMMC = 4*FETCH(1); 1300 int retval = common_invoke_super_quick(false, vD, IMMC); 1301 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2) 1302 insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on 1303 #endif 1304 rPC += 3; 1305 return retval; 1306 } 1307 //! lower bytecode INVOKE_SUPER_QUICK_RANGE by calling common_invoke_super_quick 1308 1309 //! 1310 int op_invoke_super_quick_range() { 1311 u2 vD = FETCH(2); 1312 u2 IMMC = 4*FETCH(1); 1313 int retval = common_invoke_super_quick(true, vD, IMMC); 1314 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2) 1315 insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on 1316 #endif 1317 rPC += 3; 1318 return retval; 1319 } 1320 /////// code to predict the callee method for invoke_virtual & invoke_interface 1321 #define offChainingCell_clazz 8 1322 #define offChainingCell_method 12 1323 #define offChainingCell_counter 16 1324 #define P_GPR_1 PhysicalReg_EBX 1325 #define P_GPR_2 PhysicalReg_EAX 1326 #define P_GPR_3 PhysicalReg_ESI 1327 #define P_SCRATCH_2 PhysicalReg_EDX 1328 /* TODO gingerbread: implemented for O1, but not for O0: 1329 valid input to JitToPatch & use icRechainCount */ 1330 /* update predicted method for invoke interface */ 1331 // 2 inputs: ChainingCell in P_GPR_1, current class object in P_GPR_3 1332 void predicted_chain_interface_O0(u2 tmp) { 1333 ALOGI("TODO chain_interface_O0"); 1334 1335 /* set up arguments to dvmFindInterfaceMethodInCache */ 1336 load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 1337 move_imm_to_mem(OpndSize_32, tmp, 4, PhysicalReg_ESP, true); 1338 move_imm_to_mem(OpndSize_32, (int) currentMethod->clazz->pDvmDex, 12, PhysicalReg_ESP, true); 1339 move_imm_to_mem(OpndSize_32, (int) currentMethod, 8, PhysicalReg_ESP, true); 1340 move_reg_to_mem(OpndSize_32, P_GPR_3, true, 0, PhysicalReg_ESP, true); 1341 scratchRegs[0] = PhysicalReg_EDX; 1342 call_dvmFindInterfaceMethodInCache(); 1343 load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 1344 1345 /* if dvmFindInterfaceMethodInCache returns NULL, throw exception 1346 otherwise, jump to .find_interface_done */ 1347 compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true); 1348 conditional_jump(Condition_NE, ".find_interface_done", true); 1349 scratchRegs[0] = PhysicalReg_EAX; 1350 jumpToExceptionThrown(1/*exception number*/); 1351 1352 /* the interface method is found */ 1353 insertLabel(".find_interface_done", true); 1354 /* reduce counter in chaining cell by 1 */ 1355 move_mem_to_reg(OpndSize_32, offChainingCell_counter, P_GPR_1, true, P_SCRATCH_2, true); //counter 1356 alu_binary_imm_reg(OpndSize_32, sub_opc, 0x1, P_SCRATCH_2, true); 1357 move_reg_to_mem(OpndSize_32, P_SCRATCH_2, true, offChainingCell_counter, P_GPR_1, true); 1358 1359 /* if counter is still greater than zero, skip prediction 1360 if it is zero, update predicted method */ 1361 compare_imm_reg(OpndSize_32, 0, P_SCRATCH_2, true); 1362 conditional_jump(Condition_G, ".skipPrediction", true); 1363 1364 /* call dvmJitToPatchPredictedChain to update predicted method */ 1365 //%ecx has callee method for virtual, %eax has callee for interface 1366 /* set up arguments for dvmJitToPatchPredictedChain */ 1367 load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 1368 move_reg_to_mem(OpndSize_32, PhysicalReg_EAX, true, 0, PhysicalReg_ESP, true); 1369 insertChainingWorklist(traceCurrentBB->taken->id, stream); 1370 move_chain_to_mem(OpndSize_32, traceCurrentBB->taken->id, 8, PhysicalReg_ESP, true); //predictedChainCell 1371 move_reg_to_mem(OpndSize_32, P_GPR_3, true, 12, PhysicalReg_ESP, true); 1372 scratchRegs[0] = PhysicalReg_EAX; 1373 call_dvmJitToPatchPredictedChain(); //inputs: method, unused, predictedChainCell, clazz 1374 load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 1375 insertLabel(".skipPrediction", true); 1376 move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, PhysicalReg_ECX, true); 1377 } 1378 1379 // 2 inputs: ChainingCell in temp 41, current class object in temp 40 1380 void predicted_chain_interface_O1(u2 tmp) { 1381 1382 /* set up arguments to dvmFindInterfaceMethodInCache */ 1383 load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 1384 move_imm_to_mem(OpndSize_32, tmp, 4, PhysicalReg_ESP, true); 1385 move_imm_to_mem(OpndSize_32, (int) currentMethod->clazz->pDvmDex, 12, PhysicalReg_ESP, true); 1386 move_imm_to_mem(OpndSize_32, (int) currentMethod, 8, PhysicalReg_ESP, true); 1387 move_reg_to_mem(OpndSize_32, 40, false, 0, PhysicalReg_ESP, true); 1388 scratchRegs[0] = PhysicalReg_SCRATCH_10; 1389 call_dvmFindInterfaceMethodInCache(); 1390 load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 1391 1392 /* if dvmFindInterfaceMethodInCache returns NULL, throw exception 1393 otherwise, jump to .find_interface_done */ 1394 compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true); 1395 conditional_jump(Condition_NE, ".find_interface_done", true); 1396 rememberState(3); 1397 scratchRegs[0] = PhysicalReg_SCRATCH_9; 1398 jumpToExceptionThrown(1/*exception number*/); 1399 1400 goToState(3); 1401 /* the interface method is found */ 1402 insertLabel(".find_interface_done", true); 1403 #if 1 // 1404 /* for gingerbread, counter is stored in glue structure 1405 if clazz is not initialized, set icRechainCount to 0, otherwise, reduce it by 1 */ 1406 /* for gingerbread: t43 = 0 t44 = t33 t33-- cmov_ne t43 = t33 cmov_ne t44 = t33 */ 1407 move_mem_to_reg(OpndSize_32, offChainingCell_clazz, 41, false, 45, false); 1408 move_imm_to_reg(OpndSize_32, 0, 43, false); 1409 get_self_pointer(PhysicalReg_SCRATCH_7, isScratchPhysical); 1410 move_mem_to_reg(OpndSize_32, offsetof(Thread, icRechainCount), PhysicalReg_SCRATCH_7, isScratchPhysical, 33, false); //counter 1411 move_reg_to_reg(OpndSize_32, 33, false, 44, false); 1412 alu_binary_imm_reg(OpndSize_32, sub_opc, 0x1, 33, false); 1413 /* sub_opc will update control flags, so compare_imm_reg must happen after */ 1414 compare_imm_reg(OpndSize_32, 0, 45, false); 1415 conditional_move_reg_to_reg(OpndSize_32, Condition_NZ, 33, false/*src*/, 43, false/*dst*/); 1416 conditional_move_reg_to_reg(OpndSize_32, Condition_NZ, 33, false/*src*/, 44, false/*dst*/); 1417 move_reg_to_mem(OpndSize_32, 44, false, offsetof(Thread, icRechainCount), PhysicalReg_SCRATCH_7, isScratchPhysical); 1418 #else 1419 /* reduce counter in chaining cell by 1 */ 1420 move_mem_to_reg(OpndSize_32, offChainingCell_counter, 41, false, 33, false); //counter 1421 alu_binary_imm_reg(OpndSize_32, sub_opc, 0x1, 33, false); 1422 move_reg_to_mem(OpndSize_32, 33, false, offChainingCell_counter, 41, false); 1423 #endif 1424 1425 /* if counter is still greater than zero, skip prediction 1426 if it is zero, update predicted method */ 1427 compare_imm_reg(OpndSize_32, 0, 43, false); 1428 conditional_jump(Condition_G, ".skipPrediction", true); 1429 1430 rememberState(4); 1431 /* call dvmJitToPatchPredictedChain to update predicted method */ 1432 //%ecx has callee method for virtual, %eax has callee for interface 1433 /* set up arguments for dvmJitToPatchPredictedChain */ 1434 load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 1435 move_reg_to_mem(OpndSize_32, PhysicalReg_EAX, true, 0, PhysicalReg_ESP, true); 1436 move_reg_to_mem(OpndSize_32, PhysicalReg_SCRATCH_7, isScratchPhysical, 4, PhysicalReg_ESP, true); 1437 insertChainingWorklist(traceCurrentBB->taken->id, stream); 1438 move_chain_to_mem(OpndSize_32, traceCurrentBB->taken->id, 8, PhysicalReg_ESP, true); //predictedChainCell 1439 move_reg_to_mem(OpndSize_32, 40, false, 12, PhysicalReg_ESP, true); 1440 scratchRegs[0] = PhysicalReg_SCRATCH_8; 1441 call_dvmJitToPatchPredictedChain(); //inputs: method, unused, predictedChainCell, clazz 1442 load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 1443 transferToState(4); 1444 1445 insertLabel(".skipPrediction", true); 1446 move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, PhysicalReg_ECX, true); 1447 } 1448 1449 /* update predicted method for invoke virtual */ 1450 // 2 inputs: ChainingCell in P_GPR_1, current class object in P_GPR_3 1451 void predicted_chain_virtual_O0(u2 IMMC) { 1452 ALOGI("TODO chain_virtual_O0"); 1453 1454 /* reduce counter in chaining cell by 1 */ 1455 move_mem_to_reg(OpndSize_32, offChainingCell_counter, P_GPR_1, true, P_GPR_2, true); //counter 1456 move_mem_to_reg(OpndSize_32, offClassObject_vtable, P_GPR_3, true, P_SCRATCH_2, true); 1457 alu_binary_imm_reg(OpndSize_32, sub_opc, 0x1, P_GPR_2, true); 1458 move_mem_to_reg(OpndSize_32, IMMC, P_SCRATCH_2, true, PhysicalReg_ECX, true); 1459 move_reg_to_mem(OpndSize_32, P_GPR_2, true, offChainingCell_counter, P_GPR_1, true); 1460 1461 /* if counter is still greater than zero, skip prediction 1462 if it is zero, update predicted method */ 1463 compare_imm_reg(OpndSize_32, 0, P_GPR_2, true); 1464 conditional_jump(Condition_G, ".skipPrediction", true); 1465 1466 /* call dvmJitToPatchPredictedChain to update predicted method */ 1467 //%ecx has callee method for virtual, %eax has callee for interface 1468 /* set up arguments for dvmJitToPatchPredictedChain */ 1469 load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 1470 move_reg_to_mem(OpndSize_32, PhysicalReg_ECX, true, 0, PhysicalReg_ESP, true); 1471 insertChainingWorklist(traceCurrentBB->taken->id, stream); 1472 move_chain_to_mem(OpndSize_32, traceCurrentBB->taken->id, 8, PhysicalReg_ESP, true); //predictedChainCell 1473 move_reg_to_mem(OpndSize_32, P_GPR_3, true, 12, PhysicalReg_ESP, true); 1474 scratchRegs[0] = PhysicalReg_EAX; 1475 call_dvmJitToPatchPredictedChain(); //inputs: method, unused, predictedChainCell, clazz 1476 load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 1477 1478 //callee method in %ecx for invoke virtual 1479 move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, PhysicalReg_ECX, true); 1480 insertLabel(".skipPrediction", true); 1481 } 1482 1483 // 2 inputs: ChainingCell in temp 41, current class object in temp 40 1484 // extra input: predicted clazz in temp 32 1485 void predicted_chain_virtual_O1(u2 IMMC) { 1486 1487 /* reduce counter in chaining cell by 1 */ 1488 /* for gingerbread: t43 = 0 t44 = t33 t33-- cmov_ne t43 = t33 cmov_ne t44 = t33 */ 1489 get_self_pointer(PhysicalReg_SCRATCH_7, isScratchPhysical); 1490 move_imm_to_reg(OpndSize_32, 0, 43, false); 1491 move_mem_to_reg(OpndSize_32, offsetof(Thread, icRechainCount), PhysicalReg_SCRATCH_7, isScratchPhysical, 33, false); //counter 1492 move_mem_to_reg(OpndSize_32, offClassObject_vtable, 40, false, 34, false); 1493 move_reg_to_reg(OpndSize_32, 33, false, 44, false); 1494 alu_binary_imm_reg(OpndSize_32, sub_opc, 0x1, 33, false); 1495 compare_imm_reg(OpndSize_32, 0, 32, false); // after sub_opc 1496 move_mem_to_reg(OpndSize_32, IMMC, 34, false, PhysicalReg_ECX, true); 1497 conditional_move_reg_to_reg(OpndSize_32, Condition_NZ, 33, false/*src*/, 43, false/*dst*/); 1498 conditional_move_reg_to_reg(OpndSize_32, Condition_NZ, 33, false/*src*/, 44, false/*dst*/); 1499 move_reg_to_mem(OpndSize_32, 44, false, offsetof(Thread, icRechainCount), PhysicalReg_SCRATCH_7, isScratchPhysical); 1500 1501 /* if counter is still greater than zero, skip prediction 1502 if it is zero, update predicted method */ 1503 compare_imm_reg(OpndSize_32, 0, 43, false); 1504 conditional_jump(Condition_G, ".skipPrediction", true); 1505 1506 rememberState(2); 1507 /* call dvmJitToPatchPredictedChain to update predicted method */ 1508 //%ecx has callee method for virtual, %eax has callee for interface 1509 /* set up arguments for dvmJitToPatchPredictedChain */ 1510 load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 1511 move_reg_to_mem(OpndSize_32, PhysicalReg_ECX, true, 0, PhysicalReg_ESP, true); 1512 move_reg_to_mem(OpndSize_32, PhysicalReg_SCRATCH_7, isScratchPhysical, 4, PhysicalReg_ESP, true); 1513 if(traceCurrentBB->taken) 1514 insertChainingWorklist(traceCurrentBB->taken->id, stream); 1515 int traceTakenId = traceCurrentBB->taken ? traceCurrentBB->taken->id : 0; 1516 move_chain_to_mem(OpndSize_32, traceTakenId, 8, PhysicalReg_ESP, true); //predictedChainCell 1517 move_reg_to_mem(OpndSize_32, 40, false, 12, PhysicalReg_ESP, true); 1518 scratchRegs[0] = PhysicalReg_SCRATCH_10; 1519 call_dvmJitToPatchPredictedChain(); //inputs: method, unused, predictedChainCell, clazz 1520 load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 1521 1522 //callee method in %ecx for invoke virtual 1523 move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, PhysicalReg_ECX, true); 1524 transferToState(2); 1525 1526 insertLabel(".skipPrediction", true); 1527 } 1528 1529 static int invokeChain_inst = 0; 1530 /* object "this" is in %ebx */ 1531 void gen_predicted_chain_O0(bool isRange, u2 tmp, int IMMC, bool isInterface, int inputReg) { 1532 ALOGI("TODO predicted_chain_O0"); 1533 1534 /* get current class object */ 1535 move_mem_to_reg(OpndSize_32, offObject_clazz, PhysicalReg_EBX, true, 1536 P_GPR_3, true); 1537 #ifdef DEBUG_CALL_STACK3 1538 scratchRegs[0] = PhysicalReg_EAX; 1539 call_debug_dumpSwitch(); //%ebx, %eax, %edx 1540 move_imm_to_reg(OpndSize_32, 0xdd11, PhysicalReg_EBX, true); 1541 call_debug_dumpSwitch(); 1542 #endif 1543 1544 /* get predicted clazz 1545 get predicted method 1546 */ 1547 insertChainingWorklist(traceCurrentBB->taken->id, stream); 1548 move_chain_to_reg(OpndSize_32, traceCurrentBB->taken->id, P_GPR_1, true); //predictedChainCell 1549 move_mem_to_reg(OpndSize_32, offChainingCell_clazz, P_GPR_1, true, P_SCRATCH_2, true);//predicted clazz 1550 move_mem_to_reg(OpndSize_32, offChainingCell_method, P_GPR_1, true, PhysicalReg_ECX, true);//predicted method 1551 1552 #ifdef DEBUG_CALL_STACK3 1553 load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 1554 move_reg_to_mem(OpndSize_32, P_GPR_1, true, 8, PhysicalReg_ESP, true); 1555 move_reg_to_mem(OpndSize_32, P_SCRATCH_2, true, 4, PhysicalReg_ESP, true); 1556 move_reg_to_mem(OpndSize_32, P_GPR_3, true, 0, PhysicalReg_ESP, true); 1557 1558 move_reg_to_reg(OpndSize_32, P_SCRATCH_2, true, PhysicalReg_EBX, true); 1559 call_debug_dumpSwitch(); 1560 move_imm_to_reg(OpndSize_32, 0xdd22, PhysicalReg_EBX, true); 1561 scratchRegs[0] = PhysicalReg_EAX; 1562 call_debug_dumpSwitch(); //%ebx, %eax, %edx 1563 move_reg_to_reg(OpndSize_32, P_GPR_3, true, PhysicalReg_EBX, true); 1564 call_debug_dumpSwitch(); 1565 move_reg_to_reg(OpndSize_32, PhysicalReg_ECX, true, PhysicalReg_EBX, true); 1566 call_debug_dumpSwitch(); 1567 1568 move_mem_to_reg(OpndSize_32, 8, PhysicalReg_ESP, true, P_GPR_1, true); 1569 move_mem_to_reg(OpndSize_32, 4, PhysicalReg_ESP, true, P_SCRATCH_2, true); 1570 move_mem_to_reg(OpndSize_32, 0, PhysicalReg_ESP, true, P_GPR_3, true); 1571 load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true); 1572 #endif 1573 1574 /* compare current class object against predicted clazz 1575 if equal, prediction is still valid, jump to .invokeChain */ 1576 //live registers: P_GPR_1, P_GPR_3, P_SCRATCH_2 1577 compare_reg_reg(P_GPR_3, true, P_SCRATCH_2, true); 1578 conditional_jump(Condition_E, ".invokeChain", true); 1579 invokeChain_inst++; 1580 1581 //get callee method and update predicted method if necessary 1582 if(isInterface) { 1583 predicted_chain_interface_O0(tmp); 1584 } else { 1585 predicted_chain_virtual_O0(IMMC); 1586 } 1587 1588 #ifdef DEBUG_CALL_STACK3 1589 move_imm_to_reg(OpndSize_32, 0xeeee, PhysicalReg_EBX, true); 1590 scratchRegs[0] = PhysicalReg_EAX; 1591 call_debug_dumpSwitch(); //%ebx, %eax, %edx 1592 insertChainingWorklist(traceCurrentBB->taken->id, stream); 1593 move_chain_to_reg(OpndSize_32, traceCurrentBB->taken->id, PhysicalReg_EBX, true); 1594 call_debug_dumpSwitch(); 1595 #endif 1596 1597 if(isRange) { 1598 common_invokeMethodRange(ArgsDone_Full); 1599 } 1600 else { 1601 common_invokeMethodNoRange(ArgsDone_Full); 1602 } 1603 1604 insertLabel(".invokeChain", true); 1605 #ifdef DEBUG_CALL_STACK3 1606 move_imm_to_reg(OpndSize_32, 0xdddd, PhysicalReg_EBX, true); 1607 scratchRegs[0] = PhysicalReg_EAX; 1608 call_debug_dumpSwitch(); //%ebx, %eax, %edx 1609 insertChainingWorklist(traceCurrentBB->taken->id, stream); 1610 move_chain_to_reg(OpndSize_32, traceCurrentBB->taken->id, PhysicalReg_EBX, true); 1611 call_debug_dumpSwitch(); 1612 move_reg_to_reg(OpndSize_32, PhysicalReg_ECX, true, PhysicalReg_EBX, true); 1613 call_debug_dumpSwitch(); 1614 #endif 1615 1616 if(isRange) { 1617 common_invokeMethodRange(ArgsDone_Normal); 1618 } 1619 else { 1620 common_invokeMethodNoRange(ArgsDone_Normal); 1621 } 1622 } 1623 1624 /* object "this" is in inputReg: 5 for virtual, 1 for interface, 1 for virtual_quick */ 1625 void gen_predicted_chain_O1(bool isRange, u2 tmp, int IMMC, bool isInterface, int inputReg) { 1626 1627 /* get current class object */ 1628 move_mem_to_reg(OpndSize_32, offObject_clazz, inputReg, false, 1629 40, false); 1630 1631 /* get predicted clazz 1632 get predicted method 1633 */ 1634 if(traceCurrentBB->taken) 1635 insertChainingWorklist(traceCurrentBB->taken->id, stream); 1636 int traceTakenId = traceCurrentBB->taken ? traceCurrentBB->taken->id : 0; 1637 move_chain_to_reg(OpndSize_32, traceTakenId, 41, false); //predictedChainCell 1638 move_mem_to_reg(OpndSize_32, offChainingCell_clazz, 41, false, 32, false);//predicted clazz 1639 move_mem_to_reg(OpndSize_32, offChainingCell_method, 41, false, PhysicalReg_ECX, true);//predicted method 1640 1641 /* update stack with parameters first, then decide the callee */ 1642 if(isRange) common_invokeMethodRange_noJmp(); 1643 else common_invokeMethodNoRange_noJmp(); 1644 1645 /* compare current class object against predicted clazz 1646 if equal, prediction is still valid, jump to .invokeChain */ 1647 compare_reg_reg(40, false, 32, false); 1648 conditional_jump(Condition_E, ".invokeChain", true); 1649 rememberState(1); 1650 invokeChain_inst++; 1651 1652 //get callee method and update predicted method if necessary 1653 if(isInterface) { 1654 predicted_chain_interface_O1(tmp); 1655 } else { 1656 predicted_chain_virtual_O1(IMMC); 1657 } 1658 1659 common_invokeMethod_Jmp(ArgsDone_Full); //will touch %ecx 1660 1661 insertLabel(".invokeChain", true); 1662 goToState(1); 1663 common_invokeMethod_Jmp(ArgsDone_Normal); 1664 } 1665 1666 void gen_predicted_chain(bool isRange, u2 tmp, int IMMC, bool isInterface, int inputReg) { 1667 return gen_predicted_chain_O1(isRange, tmp, IMMC, isInterface, inputReg); 1668 } 1669 #undef P_GPR_1 1670 #undef P_GPR_2 1671 #undef P_GPR_3 1672 #undef P_SCRATCH_2 1673