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