Home | History | Annotate | Download | only in analysis
      1 /*
      2  * Copyright (C) 2008 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  * Perform some simple bytecode optimizations, chiefly "quickening" of
     19  * opcodes.
     20  */
     21 #include "Dalvik.h"
     22 #include "libdex/InstrUtils.h"
     23 #include "Optimize.h"
     24 
     25 #include <zlib.h>
     26 
     27 #include <stdlib.h>
     28 
     29 /*
     30  * Virtual/direct calls to "method" are replaced with an execute-inline
     31  * instruction with index "idx".
     32  */
     33 struct InlineSub {
     34     Method* method;
     35     int     inlineIdx;
     36 };
     37 
     38 
     39 /* fwd */
     40 static void optimizeMethod(Method* method, bool essentialOnly);
     41 static void rewriteInstField(Method* method, u2* insns, Opcode quickOpc,
     42     Opcode volatileOpc);
     43 static void rewriteStaticField(Method* method, u2* insns, Opcode volatileOpc);
     44 static void rewriteVirtualInvoke(Method* method, u2* insns, Opcode newOpc);
     45 static bool rewriteInvokeObjectInit(Method* method, u2* insns);
     46 static bool rewriteExecuteInline(Method* method, u2* insns,
     47     MethodType methodType);
     48 static bool rewriteExecuteInlineRange(Method* method, u2* insns,
     49     MethodType methodType);
     50 static void rewriteReturnVoid(Method* method, u2* insns);
     51 static bool needsReturnBarrier(Method* method);
     52 
     53 
     54 /*
     55  * Create a table of inline substitutions.  Sets gDvm.inlineSubs.
     56  *
     57  * TODO: this is currently just a linear array.  We will want to put this
     58  * into a hash table as the list size increases.
     59  */
     60 bool dvmCreateInlineSubsTable()
     61 {
     62     const InlineOperation* ops = dvmGetInlineOpsTable();
     63     const int count = dvmGetInlineOpsTableLength();
     64     InlineSub* table;
     65     int i, tableIndex;
     66 
     67     assert(gDvm.inlineSubs == NULL);
     68 
     69     /*
     70      * One slot per entry, plus an end-of-list marker.
     71      */
     72     table = (InlineSub*) calloc(count + 1, sizeof(InlineSub));
     73 
     74     tableIndex = 0;
     75     for (i = 0; i < count; i++) {
     76         Method* method = dvmFindInlinableMethod(ops[i].classDescriptor,
     77             ops[i].methodName, ops[i].methodSignature);
     78         if (method == NULL) {
     79             /*
     80              * Not expected.  We only use this for key methods in core
     81              * classes, so we should always be able to find them.
     82              */
     83             ALOGE("Unable to find method for inlining: %s.%s:%s",
     84                 ops[i].classDescriptor, ops[i].methodName,
     85                 ops[i].methodSignature);
     86             return false;
     87         }
     88 
     89         table[tableIndex].method = method;
     90         table[tableIndex].inlineIdx = i;
     91         tableIndex++;
     92     }
     93 
     94     /* mark end of table */
     95     table[tableIndex].method = NULL;
     96 
     97     gDvm.inlineSubs = table;
     98     return true;
     99 }
    100 
    101 /*
    102  * Release inline sub data structure.
    103  */
    104 void dvmFreeInlineSubsTable()
    105 {
    106     free(gDvm.inlineSubs);
    107     gDvm.inlineSubs = NULL;
    108 }
    109 
    110 
    111 /*
    112  * Optimize the specified class.
    113  *
    114  * If "essentialOnly" is true, we only do essential optimizations.  For
    115  * example, accesses to volatile 64-bit fields must be replaced with
    116  * "-wide-volatile" instructions or the program could behave incorrectly.
    117  * (Skipping non-essential optimizations makes us a little bit faster, and
    118  * more importantly avoids dirtying DEX pages.)
    119  */
    120 void dvmOptimizeClass(ClassObject* clazz, bool essentialOnly)
    121 {
    122     int i;
    123 
    124     for (i = 0; i < clazz->directMethodCount; i++) {
    125         optimizeMethod(&clazz->directMethods[i], essentialOnly);
    126     }
    127     for (i = 0; i < clazz->virtualMethodCount; i++) {
    128         optimizeMethod(&clazz->virtualMethods[i], essentialOnly);
    129     }
    130 }
    131 
    132 /*
    133  * Optimize instructions in a method.
    134  *
    135  * This does a single pass through the code, examining each instruction.
    136  *
    137  * This is not expected to fail if the class was successfully verified.
    138  * The only significant failure modes on unverified code occur when an
    139  * "essential" update fails, but we can't generally identify those: if we
    140  * can't look up a field, we can't know if the field access was supposed
    141  * to be handled as volatile.
    142  *
    143  * Instead, we give it our best effort, and hope for the best.  For 100%
    144  * reliability, only optimize a class after verification succeeds.
    145  */
    146 static void optimizeMethod(Method* method, bool essentialOnly)
    147 {
    148     bool needRetBar, forSmp;
    149     u4 insnsSize;
    150     u2* insns;
    151 
    152     if (dvmIsNativeMethod(method) || dvmIsAbstractMethod(method))
    153         return;
    154 
    155     forSmp = gDvm.dexOptForSmp;
    156     needRetBar = needsReturnBarrier(method);
    157 
    158     insns = (u2*) method->insns;
    159     assert(insns != NULL);
    160     insnsSize = dvmGetMethodInsnsSize(method);
    161 
    162     while (insnsSize > 0) {
    163         Opcode opc, quickOpc, volatileOpc;
    164         size_t width;
    165         bool matched = true;
    166 
    167         opc = dexOpcodeFromCodeUnit(*insns);
    168         width = dexGetWidthFromInstruction(insns);
    169         volatileOpc = OP_NOP;
    170 
    171         /*
    172          * Each instruction may have:
    173          * - "volatile" replacement
    174          *   - may be essential or essential-on-SMP
    175          * - correctness replacement
    176          *   - may be essential or essential-on-SMP
    177          * - performance replacement
    178          *   - always non-essential
    179          *
    180          * Replacements are considered in the order shown, and the first
    181          * match is applied.  For example, iget-wide will convert to
    182          * iget-wide-volatile rather than iget-wide-quick if the target
    183          * field is volatile.
    184          */
    185 
    186         /*
    187          * essential substitutions:
    188          *  {iget,iput,sget,sput}-wide --> {op}-wide-volatile
    189          *  invoke-direct[/range] --> invoke-object-init/range
    190          *
    191          * essential-on-SMP substitutions:
    192          *  {iget,iput,sget,sput}-* --> {op}-volatile
    193          *  return-void --> return-void-barrier
    194          *
    195          * non-essential substitutions:
    196          *  {iget,iput}-* --> {op}-quick
    197          *
    198          * TODO: might be time to merge this with the other two switches
    199          */
    200         switch (opc) {
    201         case OP_IGET:
    202         case OP_IGET_BOOLEAN:
    203         case OP_IGET_BYTE:
    204         case OP_IGET_CHAR:
    205         case OP_IGET_SHORT:
    206             quickOpc = OP_IGET_QUICK;
    207             if (forSmp)
    208                 volatileOpc = OP_IGET_VOLATILE;
    209             goto rewrite_inst_field;
    210         case OP_IGET_WIDE:
    211             quickOpc = OP_IGET_WIDE_QUICK;
    212             volatileOpc = OP_IGET_WIDE_VOLATILE;
    213             goto rewrite_inst_field;
    214         case OP_IGET_OBJECT:
    215             quickOpc = OP_IGET_OBJECT_QUICK;
    216             if (forSmp)
    217                 volatileOpc = OP_IGET_OBJECT_VOLATILE;
    218             goto rewrite_inst_field;
    219         case OP_IPUT:
    220         case OP_IPUT_BOOLEAN:
    221         case OP_IPUT_BYTE:
    222         case OP_IPUT_CHAR:
    223         case OP_IPUT_SHORT:
    224             quickOpc = OP_IPUT_QUICK;
    225             if (forSmp)
    226                 volatileOpc = OP_IPUT_VOLATILE;
    227             goto rewrite_inst_field;
    228         case OP_IPUT_WIDE:
    229             quickOpc = OP_IPUT_WIDE_QUICK;
    230             volatileOpc = OP_IPUT_WIDE_VOLATILE;
    231             goto rewrite_inst_field;
    232         case OP_IPUT_OBJECT:
    233             quickOpc = OP_IPUT_OBJECT_QUICK;
    234             if (forSmp)
    235                 volatileOpc = OP_IPUT_OBJECT_VOLATILE;
    236             /* fall through */
    237 rewrite_inst_field:
    238             if (essentialOnly)
    239                 quickOpc = OP_NOP;      /* if essential-only, no "-quick" sub */
    240             if (quickOpc != OP_NOP || volatileOpc != OP_NOP)
    241                 rewriteInstField(method, insns, quickOpc, volatileOpc);
    242             break;
    243 
    244         case OP_SGET:
    245         case OP_SGET_BOOLEAN:
    246         case OP_SGET_BYTE:
    247         case OP_SGET_CHAR:
    248         case OP_SGET_SHORT:
    249             if (forSmp)
    250                 volatileOpc = OP_SGET_VOLATILE;
    251             goto rewrite_static_field;
    252         case OP_SGET_WIDE:
    253             volatileOpc = OP_SGET_WIDE_VOLATILE;
    254             goto rewrite_static_field;
    255         case OP_SGET_OBJECT:
    256             if (forSmp)
    257                 volatileOpc = OP_SGET_OBJECT_VOLATILE;
    258             goto rewrite_static_field;
    259         case OP_SPUT:
    260         case OP_SPUT_BOOLEAN:
    261         case OP_SPUT_BYTE:
    262         case OP_SPUT_CHAR:
    263         case OP_SPUT_SHORT:
    264             if (forSmp)
    265                 volatileOpc = OP_SPUT_VOLATILE;
    266             goto rewrite_static_field;
    267         case OP_SPUT_WIDE:
    268             volatileOpc = OP_SPUT_WIDE_VOLATILE;
    269             goto rewrite_static_field;
    270         case OP_SPUT_OBJECT:
    271             if (forSmp)
    272                 volatileOpc = OP_SPUT_OBJECT_VOLATILE;
    273             /* fall through */
    274 rewrite_static_field:
    275             if (volatileOpc != OP_NOP)
    276                 rewriteStaticField(method, insns, volatileOpc);
    277             break;
    278 
    279         case OP_INVOKE_DIRECT:
    280         case OP_INVOKE_DIRECT_RANGE:
    281             if (!rewriteInvokeObjectInit(method, insns)) {
    282                 /* may want to try execute-inline, below */
    283                 matched = false;
    284             }
    285             break;
    286         case OP_RETURN_VOID:
    287             if (needRetBar)
    288                 rewriteReturnVoid(method, insns);
    289             break;
    290         default:
    291             matched = false;
    292             break;
    293         }
    294 
    295 
    296         /*
    297          * non-essential substitutions:
    298          *  invoke-{virtual,direct,static}[/range] --> execute-inline
    299          *  invoke-{virtual,super}[/range] --> invoke-*-quick
    300          */
    301         if (!matched && !essentialOnly) {
    302             switch (opc) {
    303             case OP_INVOKE_VIRTUAL:
    304                 if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL)) {
    305                     rewriteVirtualInvoke(method, insns,
    306                         OP_INVOKE_VIRTUAL_QUICK);
    307                 }
    308                 break;
    309             case OP_INVOKE_VIRTUAL_RANGE:
    310                 if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL)) {
    311                     rewriteVirtualInvoke(method, insns,
    312                         OP_INVOKE_VIRTUAL_QUICK_RANGE);
    313                 }
    314                 break;
    315             case OP_INVOKE_SUPER:
    316                 rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK);
    317                 break;
    318             case OP_INVOKE_SUPER_RANGE:
    319                 rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK_RANGE);
    320                 break;
    321             case OP_INVOKE_DIRECT:
    322                 rewriteExecuteInline(method, insns, METHOD_DIRECT);
    323                 break;
    324             case OP_INVOKE_DIRECT_RANGE:
    325                 rewriteExecuteInlineRange(method, insns, METHOD_DIRECT);
    326                 break;
    327             case OP_INVOKE_STATIC:
    328                 rewriteExecuteInline(method, insns, METHOD_STATIC);
    329                 break;
    330             case OP_INVOKE_STATIC_RANGE:
    331                 rewriteExecuteInlineRange(method, insns, METHOD_STATIC);
    332                 break;
    333             default:
    334                 /* nothing to do for this instruction */
    335                 ;
    336             }
    337         }
    338 
    339         assert(width > 0);
    340         assert(width <= insnsSize);
    341         assert(width == dexGetWidthFromInstruction(insns));
    342 
    343         insns += width;
    344         insnsSize -= width;
    345     }
    346 
    347     assert(insnsSize == 0);
    348 }
    349 
    350 /*
    351  * Update a 16-bit code unit in "meth".  The way in which the DEX data was
    352  * loaded determines how we go about the write.
    353  *
    354  * This will be operating on post-byte-swap DEX data, so values will
    355  * be in host order.
    356  */
    357 void dvmUpdateCodeUnit(const Method* meth, u2* ptr, u2 newVal)
    358 {
    359     DvmDex* pDvmDex = meth->clazz->pDvmDex;
    360 
    361     if (!pDvmDex->isMappedReadOnly) {
    362         /* in-memory DEX (dexopt or byte[]), alter the output directly */
    363         *ptr = newVal;
    364     } else {
    365         /* memory-mapped file, toggle the page read/write status */
    366         dvmDexChangeDex2(pDvmDex, ptr, newVal);
    367     }
    368 }
    369 
    370 /*
    371  * Update an instruction's opcode.
    372  *
    373  * If "opcode" is an 8-bit op, we just replace that portion.  If it's a
    374  * 16-bit op, we convert the opcode from "packed" form (e.g. 0x0108) to
    375  * bytecode form (e.g. 0x08ff).
    376  */
    377 static inline void updateOpcode(const Method* meth, u2* ptr, Opcode opcode)
    378 {
    379     if (opcode >= 256) {
    380         /* opcode low byte becomes high byte, low byte becomes 0xff */
    381         assert((ptr[0] & 0xff) == 0xff);
    382         dvmUpdateCodeUnit(meth, ptr, (u2) (opcode << 8) | 0x00ff);
    383     } else {
    384         /* 8-bit op, just replace the low byte */
    385         assert((ptr[0] & 0xff) != 0xff);
    386         dvmUpdateCodeUnit(meth, ptr, (ptr[0] & 0xff00) | (u2) opcode);
    387     }
    388 }
    389 
    390 /*
    391  * If "referrer" and "resClass" don't come from the same DEX file, and
    392  * the DEX we're working on is not destined for the bootstrap class path,
    393  * tweak the class loader so package-access checks work correctly.
    394  *
    395  * Only do this if we're doing pre-verification or optimization.
    396  */
    397 static void tweakLoader(ClassObject* referrer, ClassObject* resClass)
    398 {
    399     if (!gDvm.optimizing)
    400         return;
    401     assert(referrer->classLoader == NULL);
    402     assert(resClass->classLoader == NULL);
    403 
    404     if (!gDvm.optimizingBootstrapClass) {
    405         /* class loader for an array class comes from element type */
    406         if (dvmIsArrayClass(resClass))
    407             resClass = resClass->elementClass;
    408         if (referrer->pDvmDex != resClass->pDvmDex)
    409             resClass->classLoader = (Object*) 0xdead3333;
    410     }
    411 }
    412 
    413 /*
    414  * Undo the effects of tweakLoader.
    415  */
    416 static void untweakLoader(ClassObject* referrer, ClassObject* resClass)
    417 {
    418     if (!gDvm.optimizing || gDvm.optimizingBootstrapClass)
    419         return;
    420 
    421     if (dvmIsArrayClass(resClass))
    422         resClass = resClass->elementClass;
    423     resClass->classLoader = NULL;
    424 }
    425 
    426 
    427 /*
    428  * Alternate version of dvmResolveClass for use with verification and
    429  * optimization.  Performs access checks on every resolve, and refuses
    430  * to acknowledge the existence of classes defined in more than one DEX
    431  * file.
    432  *
    433  * Exceptions caused by failures are cleared before returning.
    434  *
    435  * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
    436  */
    437 ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
    438     VerifyError* pFailure)
    439 {
    440     DvmDex* pDvmDex = referrer->pDvmDex;
    441     ClassObject* resClass;
    442 
    443     /*
    444      * Check the table first.  If not there, do the lookup by name.
    445      */
    446     resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
    447     if (resClass == NULL) {
    448         const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
    449         if (className[0] != '\0' && className[1] == '\0') {
    450             /* primitive type */
    451             resClass = dvmFindPrimitiveClass(className[0]);
    452         } else {
    453             resClass = dvmFindClassNoInit(className, referrer->classLoader);
    454         }
    455         if (resClass == NULL) {
    456             /* not found, exception should be raised */
    457             ALOGV("DexOpt: class %d (%s) not found",
    458                 classIdx,
    459                 dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
    460             if (pFailure != NULL) {
    461                 /* dig through the wrappers to find the original failure */
    462                 Object* excep = dvmGetException(dvmThreadSelf());
    463                 while (true) {
    464                     Object* cause = dvmGetExceptionCause(excep);
    465                     if (cause == NULL)
    466                         break;
    467                     excep = cause;
    468                 }
    469                 if (strcmp(excep->clazz->descriptor,
    470                     "Ljava/lang/IncompatibleClassChangeError;") == 0)
    471                 {
    472                     *pFailure = VERIFY_ERROR_CLASS_CHANGE;
    473                 } else {
    474                     *pFailure = VERIFY_ERROR_NO_CLASS;
    475                 }
    476             }
    477             dvmClearOptException(dvmThreadSelf());
    478             return NULL;
    479         }
    480 
    481         /*
    482          * Add it to the resolved table so we're faster on the next lookup.
    483          */
    484         dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
    485     }
    486 
    487     /* multiple definitions? */
    488     if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) {
    489         ALOGI("DexOpt: not resolving ambiguous class '%s'",
    490             resClass->descriptor);
    491         if (pFailure != NULL)
    492             *pFailure = VERIFY_ERROR_NO_CLASS;
    493         return NULL;
    494     }
    495 
    496     /* access allowed? */
    497     tweakLoader(referrer, resClass);
    498     bool allowed = dvmCheckClassAccess(referrer, resClass);
    499     untweakLoader(referrer, resClass);
    500     if (!allowed) {
    501         ALOGW("DexOpt: resolve class illegal access: %s -> %s",
    502             referrer->descriptor, resClass->descriptor);
    503         if (pFailure != NULL)
    504             *pFailure = VERIFY_ERROR_ACCESS_CLASS;
    505         return NULL;
    506     }
    507 
    508     return resClass;
    509 }
    510 
    511 /*
    512  * Alternate version of dvmResolveInstField().
    513  *
    514  * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
    515  */
    516 InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
    517     VerifyError* pFailure)
    518 {
    519     DvmDex* pDvmDex = referrer->pDvmDex;
    520     InstField* resField;
    521 
    522     resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx);
    523     if (resField == NULL) {
    524         const DexFieldId* pFieldId;
    525         ClassObject* resClass;
    526 
    527         pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);
    528 
    529         /*
    530          * Find the field's class.
    531          */
    532         resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
    533         if (resClass == NULL) {
    534             //dvmClearOptException(dvmThreadSelf());
    535             assert(!dvmCheckException(dvmThreadSelf()));
    536             if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
    537             return NULL;
    538         }
    539 
    540         resField = (InstField*)dvmFindFieldHier(resClass,
    541             dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
    542             dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
    543         if (resField == NULL) {
    544             ALOGD("DexOpt: couldn't find field %s.%s",
    545                 resClass->descriptor,
    546                 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
    547             if (pFailure != NULL)
    548                 *pFailure = VERIFY_ERROR_NO_FIELD;
    549             return NULL;
    550         }
    551         if (dvmIsStaticField(resField)) {
    552             ALOGD("DexOpt: wanted instance, got static for field %s.%s",
    553                 resClass->descriptor,
    554                 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
    555             if (pFailure != NULL)
    556                 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
    557             return NULL;
    558         }
    559 
    560         /*
    561          * Add it to the resolved table so we're faster on the next lookup.
    562          */
    563         dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField);
    564     }
    565 
    566     /* access allowed? */
    567     tweakLoader(referrer, resField->clazz);
    568     bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
    569     untweakLoader(referrer, resField->clazz);
    570     if (!allowed) {
    571         ALOGI("DexOpt: access denied from %s to field %s.%s",
    572             referrer->descriptor, resField->clazz->descriptor,
    573             resField->name);
    574         if (pFailure != NULL)
    575             *pFailure = VERIFY_ERROR_ACCESS_FIELD;
    576         return NULL;
    577     }
    578 
    579     return resField;
    580 }
    581 
    582 /*
    583  * Alternate version of dvmResolveStaticField().
    584  *
    585  * Does not force initialization of the resolved field's class.
    586  *
    587  * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
    588  */
    589 StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
    590     VerifyError* pFailure)
    591 {
    592     DvmDex* pDvmDex = referrer->pDvmDex;
    593     StaticField* resField;
    594 
    595     resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx);
    596     if (resField == NULL) {
    597         const DexFieldId* pFieldId;
    598         ClassObject* resClass;
    599 
    600         pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);
    601 
    602         /*
    603          * Find the field's class.
    604          */
    605         resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
    606         if (resClass == NULL) {
    607             //dvmClearOptException(dvmThreadSelf());
    608             assert(!dvmCheckException(dvmThreadSelf()));
    609             if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
    610             return NULL;
    611         }
    612 
    613         const char* fieldName =
    614             dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx);
    615 
    616         resField = (StaticField*)dvmFindFieldHier(resClass, fieldName,
    617                     dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
    618         if (resField == NULL) {
    619             ALOGD("DexOpt: couldn't find static field %s.%s",
    620                 resClass->descriptor, fieldName);
    621             if (pFailure != NULL)
    622                 *pFailure = VERIFY_ERROR_NO_FIELD;
    623             return NULL;
    624         }
    625         if (!dvmIsStaticField(resField)) {
    626             ALOGD("DexOpt: wanted static, got instance for field %s.%s",
    627                 resClass->descriptor, fieldName);
    628             if (pFailure != NULL)
    629                 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
    630             return NULL;
    631         }
    632 
    633         /*
    634          * Add it to the resolved table so we're faster on the next lookup.
    635          *
    636          * We can only do this if we're in "dexopt", because the presence
    637          * of a valid value in the resolution table implies that the class
    638          * containing the static field has been initialized.
    639          */
    640         if (gDvm.optimizing)
    641             dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
    642     }
    643 
    644     /* access allowed? */
    645     tweakLoader(referrer, resField->clazz);
    646     bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
    647     untweakLoader(referrer, resField->clazz);
    648     if (!allowed) {
    649         ALOGI("DexOpt: access denied from %s to field %s.%s",
    650             referrer->descriptor, resField->clazz->descriptor,
    651             resField->name);
    652         if (pFailure != NULL)
    653             *pFailure = VERIFY_ERROR_ACCESS_FIELD;
    654         return NULL;
    655     }
    656 
    657     return resField;
    658 }
    659 
    660 
    661 /*
    662  * Rewrite an iget/iput instruction if appropriate.  These all have the form:
    663  *   op vA, vB, field@CCCC
    664  *
    665  * Where vA holds the value, vB holds the object reference, and CCCC is
    666  * the field reference constant pool offset.  For a non-volatile field,
    667  * we want to replace the opcode with "quickOpc" and replace CCCC with
    668  * the byte offset from the start of the object.  For a volatile field,
    669  * we just want to replace the opcode with "volatileOpc".
    670  *
    671  * If "volatileOpc" is OP_NOP we don't check to see if it's a volatile
    672  * field.  If "quickOpc" is OP_NOP, and this is a non-volatile field,
    673  * we don't do anything.
    674  *
    675  * "method" is the referring method.
    676  */
    677 static void rewriteInstField(Method* method, u2* insns, Opcode quickOpc,
    678     Opcode volatileOpc)
    679 {
    680     ClassObject* clazz = method->clazz;
    681     u2 fieldIdx = insns[1];
    682     InstField* instField;
    683 
    684     instField = dvmOptResolveInstField(clazz, fieldIdx, NULL);
    685     if (instField == NULL) {
    686         ALOGI("DexOpt: unable to optimize instance field ref "
    687              "0x%04x at 0x%02x in %s.%s",
    688             fieldIdx, (int) (insns - method->insns), clazz->descriptor,
    689             method->name);
    690         return;
    691     }
    692 
    693     if (volatileOpc != OP_NOP && dvmIsVolatileField(instField)) {
    694         updateOpcode(method, insns, volatileOpc);
    695         ALOGV("DexOpt: rewrote ifield access %s.%s --> volatile",
    696             instField->clazz->descriptor, instField->name);
    697     } else if (quickOpc != OP_NOP && instField->byteOffset < 65536) {
    698         updateOpcode(method, insns, quickOpc);
    699         dvmUpdateCodeUnit(method, insns+1, (u2) instField->byteOffset);
    700         ALOGV("DexOpt: rewrote ifield access %s.%s --> %d",
    701             instField->clazz->descriptor, instField->name,
    702             instField->byteOffset);
    703     } else {
    704         ALOGV("DexOpt: no rewrite of ifield access %s.%s",
    705             instField->clazz->descriptor, instField->name);
    706     }
    707 
    708     return;
    709 }
    710 
    711 /*
    712  * Rewrite a static field access instruction if appropriate.  If
    713  * the target field is volatile, we replace the opcode with "volatileOpc".
    714  *
    715  * "method" is the referring method.
    716  */
    717 static void rewriteStaticField0(Method* method, u2* insns, Opcode volatileOpc,
    718     u4 fieldIdx)
    719 {
    720     ClassObject* clazz = method->clazz;
    721     StaticField* staticField;
    722 
    723     assert(volatileOpc != OP_NOP);
    724 
    725     staticField = dvmOptResolveStaticField(clazz, fieldIdx, NULL);
    726     if (staticField == NULL) {
    727         ALOGI("DexOpt: unable to optimize static field ref "
    728              "0x%04x at 0x%02x in %s.%s",
    729             fieldIdx, (int) (insns - method->insns), clazz->descriptor,
    730             method->name);
    731         return;
    732     }
    733 
    734     if (dvmIsVolatileField(staticField)) {
    735         updateOpcode(method, insns, volatileOpc);
    736         ALOGV("DexOpt: rewrote sfield access %s.%s --> volatile",
    737             staticField->clazz->descriptor, staticField->name);
    738     }
    739 }
    740 
    741 static void rewriteStaticField(Method* method, u2* insns, Opcode volatileOpc)
    742 {
    743     u2 fieldIdx = insns[1];
    744     rewriteStaticField0(method, insns, volatileOpc, fieldIdx);
    745 }
    746 
    747 /*
    748  * Alternate version of dvmResolveMethod().
    749  *
    750  * Doesn't throw exceptions, and checks access on every lookup.
    751  *
    752  * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
    753  */
    754 Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
    755     MethodType methodType, VerifyError* pFailure)
    756 {
    757     DvmDex* pDvmDex = referrer->pDvmDex;
    758     Method* resMethod;
    759 
    760     assert(methodType == METHOD_DIRECT ||
    761            methodType == METHOD_VIRTUAL ||
    762            methodType == METHOD_STATIC);
    763 
    764     LOGVV("--- resolving method %u (referrer=%s)", methodIdx,
    765         referrer->descriptor);
    766 
    767     resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
    768     if (resMethod == NULL) {
    769         const DexMethodId* pMethodId;
    770         ClassObject* resClass;
    771 
    772         pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
    773 
    774         resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure);
    775         if (resClass == NULL) {
    776             /*
    777              * Can't find the class that the method is a part of, or don't
    778              * have permission to access the class.
    779              */
    780             ALOGV("DexOpt: can't find called method's class (?.%s)",
    781                 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
    782             if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
    783             return NULL;
    784         }
    785         if (dvmIsInterfaceClass(resClass)) {
    786             /* method is part of an interface; this is wrong method for that */
    787             ALOGW("DexOpt: method is in an interface");
    788             if (pFailure != NULL)
    789                 *pFailure = VERIFY_ERROR_GENERIC;
    790             return NULL;
    791         }
    792 
    793         /*
    794          * We need to chase up the class hierarchy to find methods defined
    795          * in super-classes.  (We only want to check the current class
    796          * if we're looking for a constructor.)
    797          */
    798         DexProto proto;
    799         dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
    800 
    801         if (methodType == METHOD_DIRECT) {
    802             resMethod = dvmFindDirectMethod(resClass,
    803                 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
    804         } else {
    805             /* METHOD_STATIC or METHOD_VIRTUAL */
    806             resMethod = dvmFindMethodHier(resClass,
    807                 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
    808         }
    809 
    810         if (resMethod == NULL) {
    811             ALOGV("DexOpt: couldn't find method '%s'",
    812                 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
    813             if (pFailure != NULL)
    814                 *pFailure = VERIFY_ERROR_NO_METHOD;
    815             return NULL;
    816         }
    817         if (methodType == METHOD_STATIC) {
    818             if (!dvmIsStaticMethod(resMethod)) {
    819                 ALOGD("DexOpt: wanted static, got instance for method %s.%s",
    820                     resClass->descriptor, resMethod->name);
    821                 if (pFailure != NULL)
    822                     *pFailure = VERIFY_ERROR_CLASS_CHANGE;
    823                 return NULL;
    824             }
    825         } else if (methodType == METHOD_VIRTUAL) {
    826             if (dvmIsStaticMethod(resMethod)) {
    827                 ALOGD("DexOpt: wanted instance, got static for method %s.%s",
    828                     resClass->descriptor, resMethod->name);
    829                 if (pFailure != NULL)
    830                     *pFailure = VERIFY_ERROR_CLASS_CHANGE;
    831                 return NULL;
    832             }
    833         }
    834 
    835         /* see if this is a pure-abstract method */
    836         if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
    837             ALOGW("DexOpt: pure-abstract method '%s' in %s",
    838                 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx),
    839                 resClass->descriptor);
    840             if (pFailure != NULL)
    841                 *pFailure = VERIFY_ERROR_GENERIC;
    842             return NULL;
    843         }
    844 
    845         /*
    846          * Add it to the resolved table so we're faster on the next lookup.
    847          *
    848          * We can only do this for static methods if we're not in "dexopt",
    849          * because the presence of a valid value in the resolution table
    850          * implies that the class containing the static field has been
    851          * initialized.
    852          */
    853         if (methodType != METHOD_STATIC || gDvm.optimizing)
    854             dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
    855     }
    856 
    857     LOGVV("--- found method %d (%s.%s)",
    858         methodIdx, resMethod->clazz->descriptor, resMethod->name);
    859 
    860     /* access allowed? */
    861     tweakLoader(referrer, resMethod->clazz);
    862     bool allowed = dvmCheckMethodAccess(referrer, resMethod);
    863     untweakLoader(referrer, resMethod->clazz);
    864     if (!allowed) {
    865         IF_ALOGI() {
    866             char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
    867             ALOGI("DexOpt: illegal method access (call %s.%s %s from %s)",
    868                 resMethod->clazz->descriptor, resMethod->name, desc,
    869                 referrer->descriptor);
    870             free(desc);
    871         }
    872         if (pFailure != NULL)
    873             *pFailure = VERIFY_ERROR_ACCESS_METHOD;
    874         return NULL;
    875     }
    876 
    877     return resMethod;
    878 }
    879 
    880 /*
    881  * Rewrite invoke-virtual, invoke-virtual/range, invoke-super, and
    882  * invoke-super/range if appropriate.  These all have the form:
    883  *   op vAA, meth@BBBB, reg stuff @CCCC
    884  *
    885  * We want to replace the method constant pool index BBBB with the
    886  * vtable index.
    887  */
    888 static void rewriteVirtualInvoke(Method* method, u2* insns, Opcode newOpc)
    889 {
    890     ClassObject* clazz = method->clazz;
    891     Method* baseMethod;
    892     u2 methodIdx = insns[1];
    893 
    894     baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL, NULL);
    895     if (baseMethod == NULL) {
    896         ALOGD("DexOpt: unable to optimize virt call 0x%04x at 0x%02x in %s.%s",
    897             methodIdx,
    898             (int) (insns - method->insns), clazz->descriptor,
    899             method->name);
    900         return;
    901     }
    902 
    903     assert((insns[0] & 0xff) == OP_INVOKE_VIRTUAL ||
    904            (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE ||
    905            (insns[0] & 0xff) == OP_INVOKE_SUPER ||
    906            (insns[0] & 0xff) == OP_INVOKE_SUPER_RANGE);
    907 
    908     /*
    909      * Note: Method->methodIndex is a u2 and is range checked during the
    910      * initial load.
    911      */
    912     updateOpcode(method, insns, newOpc);
    913     dvmUpdateCodeUnit(method, insns+1, baseMethod->methodIndex);
    914 
    915     //ALOGI("DexOpt: rewrote call to %s.%s --> %s.%s",
    916     //    method->clazz->descriptor, method->name,
    917     //    baseMethod->clazz->descriptor, baseMethod->name);
    918 
    919     return;
    920 }
    921 
    922 /*
    923  * Rewrite invoke-direct[/range] if the target is Object.<init>.
    924  *
    925  * This is useful as an optimization, because otherwise every object
    926  * instantiation will cause us to call a method that does nothing.
    927  * It also allows us to inexpensively mark objects as finalizable at the
    928  * correct time.
    929  *
    930  * TODO: verifier should ensure Object.<init> contains only return-void,
    931  * and issue a warning if not.
    932  */
    933 static bool rewriteInvokeObjectInit(Method* method, u2* insns)
    934 {
    935     ClassObject* clazz = method->clazz;
    936     Method* calledMethod;
    937     u2 methodIdx = insns[1];
    938 
    939     calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL);
    940     if (calledMethod == NULL) {
    941         ALOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s",
    942             methodIdx, (int) (insns - method->insns),
    943             clazz->descriptor, method->name);
    944         return false;
    945     }
    946 
    947     if (calledMethod->clazz == gDvm.classJavaLangObject &&
    948         dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0)
    949     {
    950         /*
    951          * Replace the instruction.  If the debugger is attached, the
    952          * interpreter will forward execution to the invoke-direct/range
    953          * handler.  If this was an invoke-direct/range instruction we can
    954          * just replace the opcode, but if it was an invoke-direct we
    955          * have to set the argument count (high 8 bits of first code unit)
    956          * to 1.
    957          */
    958         u1 origOp = insns[0] & 0xff;
    959         if (origOp == OP_INVOKE_DIRECT) {
    960             dvmUpdateCodeUnit(method, insns,
    961                 OP_INVOKE_OBJECT_INIT_RANGE | 0x100);
    962         } else {
    963             assert(origOp == OP_INVOKE_DIRECT_RANGE);
    964             assert((insns[0] >> 8) == 1);
    965             updateOpcode(method, insns, OP_INVOKE_OBJECT_INIT_RANGE);
    966         }
    967 
    968         LOGVV("DexOpt: replaced Object.<init> in %s.%s",
    969             method->clazz->descriptor, method->name);
    970     }
    971 
    972     return true;
    973 }
    974 
    975 /*
    976  * Resolve an interface method reference.
    977  *
    978  * No method access check here -- interface methods are always public.
    979  *
    980  * Returns NULL if the method was not found.  Does not throw an exception.
    981  */
    982 Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx)
    983 {
    984     DvmDex* pDvmDex = referrer->pDvmDex;
    985     Method* resMethod;
    986 
    987     LOGVV("--- resolving interface method %d (referrer=%s)",
    988         methodIdx, referrer->descriptor);
    989 
    990     resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
    991     if (resMethod == NULL) {
    992         const DexMethodId* pMethodId;
    993         ClassObject* resClass;
    994 
    995         pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
    996 
    997         resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, NULL);
    998         if (resClass == NULL) {
    999             /* can't find the class that the method is a part of */
   1000             dvmClearOptException(dvmThreadSelf());
   1001             return NULL;
   1002         }
   1003         if (!dvmIsInterfaceClass(resClass)) {
   1004             /* whoops */
   1005             ALOGI("Interface method not part of interface class");
   1006             return NULL;
   1007         }
   1008 
   1009         const char* methodName =
   1010             dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
   1011         DexProto proto;
   1012         dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
   1013 
   1014         LOGVV("+++ looking for '%s' '%s' in resClass='%s'",
   1015             methodName, methodSig, resClass->descriptor);
   1016         resMethod = dvmFindInterfaceMethodHier(resClass, methodName, &proto);
   1017         if (resMethod == NULL) {
   1018             return NULL;
   1019         }
   1020 
   1021         /* we're expecting this to be abstract */
   1022         if (!dvmIsAbstractMethod(resMethod)) {
   1023             char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
   1024             ALOGW("Found non-abstract interface method %s.%s %s",
   1025                 resMethod->clazz->descriptor, resMethod->name, desc);
   1026             free(desc);
   1027             return NULL;
   1028         }
   1029 
   1030         /*
   1031          * Add it to the resolved table so we're faster on the next lookup.
   1032          */
   1033         dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
   1034     }
   1035 
   1036     LOGVV("--- found interface method %d (%s.%s)",
   1037         methodIdx, resMethod->clazz->descriptor, resMethod->name);
   1038 
   1039     /* interface methods are always public; no need to check access */
   1040 
   1041     return resMethod;
   1042 }
   1043 
   1044 /*
   1045  * Replace invoke-virtual, invoke-direct, or invoke-static with an
   1046  * execute-inline operation if appropriate.
   1047  *
   1048  * Returns "true" if we replace it.
   1049  */
   1050 static bool rewriteExecuteInline(Method* method, u2* insns,
   1051     MethodType methodType)
   1052 {
   1053     const InlineSub* inlineSubs = gDvm.inlineSubs;
   1054     ClassObject* clazz = method->clazz;
   1055     Method* calledMethod;
   1056     u2 methodIdx = insns[1];
   1057 
   1058     //return false;
   1059 
   1060     calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
   1061     if (calledMethod == NULL) {
   1062         ALOGV("+++ DexOpt inline: can't find %d", methodIdx);
   1063         return false;
   1064     }
   1065 
   1066     while (inlineSubs->method != NULL) {
   1067         /*
   1068         if (extra) {
   1069             ALOGI("comparing %p vs %p %s.%s %s",
   1070                 inlineSubs->method, calledMethod,
   1071                 inlineSubs->method->clazz->descriptor,
   1072                 inlineSubs->method->name,
   1073                 inlineSubs->method->signature);
   1074         }
   1075         */
   1076         if (inlineSubs->method == calledMethod) {
   1077             assert((insns[0] & 0xff) == OP_INVOKE_DIRECT ||
   1078                    (insns[0] & 0xff) == OP_INVOKE_STATIC ||
   1079                    (insns[0] & 0xff) == OP_INVOKE_VIRTUAL);
   1080             updateOpcode(method, insns, OP_EXECUTE_INLINE);
   1081             dvmUpdateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx);
   1082 
   1083             //ALOGI("DexOpt: execute-inline %s.%s --> %s.%s",
   1084             //    method->clazz->descriptor, method->name,
   1085             //    calledMethod->clazz->descriptor, calledMethod->name);
   1086             return true;
   1087         }
   1088 
   1089         inlineSubs++;
   1090     }
   1091 
   1092     return false;
   1093 }
   1094 
   1095 /*
   1096  * Replace invoke-virtual/range, invoke-direct/range, or invoke-static/range
   1097  * with an execute-inline operation if appropriate.
   1098  *
   1099  * Returns "true" if we replace it.
   1100  */
   1101 static bool rewriteExecuteInlineRange(Method* method, u2* insns,
   1102     MethodType methodType)
   1103 {
   1104     const InlineSub* inlineSubs = gDvm.inlineSubs;
   1105     ClassObject* clazz = method->clazz;
   1106     Method* calledMethod;
   1107     u2 methodIdx = insns[1];
   1108 
   1109     calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
   1110     if (calledMethod == NULL) {
   1111         ALOGV("+++ DexOpt inline/range: can't find %d", methodIdx);
   1112         return false;
   1113     }
   1114 
   1115     while (inlineSubs->method != NULL) {
   1116         if (inlineSubs->method == calledMethod) {
   1117             assert((insns[0] & 0xff) == OP_INVOKE_DIRECT_RANGE ||
   1118                    (insns[0] & 0xff) == OP_INVOKE_STATIC_RANGE ||
   1119                    (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE);
   1120             updateOpcode(method, insns, OP_EXECUTE_INLINE_RANGE);
   1121             dvmUpdateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx);
   1122 
   1123             //ALOGI("DexOpt: execute-inline/range %s.%s --> %s.%s",
   1124             //    method->clazz->descriptor, method->name,
   1125             //    calledMethod->clazz->descriptor, calledMethod->name);
   1126             return true;
   1127         }
   1128 
   1129         inlineSubs++;
   1130     }
   1131 
   1132     return false;
   1133 }
   1134 
   1135 /*
   1136  * Returns "true" if the return-void instructions in this method should
   1137  * be converted to return-void-barrier.
   1138  *
   1139  * This is needed to satisfy a Java Memory Model requirement regarding
   1140  * the construction of objects with final fields.  (This does not apply
   1141  * to <clinit> or static fields, since appropriate barriers are guaranteed
   1142  * by the class initialization process.)
   1143  */
   1144 static bool needsReturnBarrier(Method* method)
   1145 {
   1146     if (!gDvm.dexOptForSmp)
   1147         return false;
   1148     if (strcmp(method->name, "<init>") != 0)
   1149         return false;
   1150 
   1151     /*
   1152      * Check to see if the class is finalizable.  The loader sets a flag
   1153      * if the class or one of its superclasses overrides finalize().
   1154      */
   1155     const ClassObject* clazz = method->clazz;
   1156     if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE))
   1157         return true;
   1158 
   1159     /*
   1160      * Check to see if the class has any final fields.  If not, we don't
   1161      * need to generate a barrier instruction.
   1162      *
   1163      * In theory, we only need to do this if the method actually modifies
   1164      * a final field.  In practice, non-constructor methods are allowed
   1165      * to modify final fields, and there are 3rd-party tools that rely on
   1166      * this behavior.  (The compiler does not allow it, but the VM does.)
   1167      *
   1168      * If we alter the verifier to restrict final-field updates to
   1169      * constructors, we can tighten this up as well.
   1170      */
   1171     int idx = clazz->ifieldCount;
   1172     while (--idx >= 0) {
   1173         if (dvmIsFinalField(&clazz->ifields[idx]))
   1174             return true;
   1175     }
   1176 
   1177     return false;
   1178 }
   1179 
   1180 /*
   1181  * Convert a return-void to a return-void-barrier.
   1182  */
   1183 static void rewriteReturnVoid(Method* method, u2* insns)
   1184 {
   1185     assert((insns[0] & 0xff) == OP_RETURN_VOID);
   1186     updateOpcode(method, insns, OP_RETURN_VOID_BARRIER);
   1187 }
   1188