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