Optimize.cpp revision 228a6b01918304f2cd1213c722e028a6e25252bb
12e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
22e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Copyright (C) 2008 The Android Open Source Project
32e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
42e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Licensed under the Apache License, Version 2.0 (the "License");
52e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * you may not use this file except in compliance with the License.
62e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * You may obtain a copy of the License at
72e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
82e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *      http://www.apache.org/licenses/LICENSE-2.0
92e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Unless required by applicable law or agreed to in writing, software
112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * distributed under the License is distributed on an "AS IS" BASIS,
122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * See the License for the specific language governing permissions and
142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * limitations under the License.
152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Perform some simple bytecode optimizations, chiefly "quickening" of
192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * opcodes.
202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include "Dalvik.h"
222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include "libdex/InstrUtils.h"
232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <zlib.h>
252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <stdlib.h>
272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Virtual/direct calls to "method" are replaced with an execute-inline
302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * instruction with index "idx".
312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
32cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstruct InlineSub {
332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* method;
342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int     inlineIdx;
35cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden};
362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* fwd */
39cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstatic bool optimizeMethod(Method* method);
402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void rewriteInstField(Method* method, u2* insns, OpCode newOpc);
412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteVirtualInvoke(Method* method, u2* insns, OpCode newOpc);
422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteEmptyDirectInvoke(Method* method, u2* insns);
432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInline(Method* method, u2* insns,
44cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    MethodType methodType);
452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInlineRange(Method* method, u2* insns,
46cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    MethodType methodType);
472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Create a table of inline substitutions.
512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * TODO: this is currently just a linear array.  We will want to put this
532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * into a hash table as the list size increases.
542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
55cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenInlineSub* dvmCreateInlineSubsTable(void)
562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const InlineOperation* ops = dvmGetInlineOpsTable();
582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const int count = dvmGetInlineOpsTableLength();
592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    InlineSub* table;
602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* method;
612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz;
622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int i, tableIndex;
632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Allocate for optimism: one slot per entry, plus an end-of-list marker.
662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    table = malloc(sizeof(InlineSub) * (count+1));
682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    tableIndex = 0;
702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (i = 0; i < count; i++) {
712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        clazz = dvmFindClassNoInit(ops[i].classDescriptor, NULL);
722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (clazz == NULL) {
732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGV("DexOpt: can't inline for class '%s': not found\n",
742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                ops[i].classDescriptor);
752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmClearOptException(dvmThreadSelf());
762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else {
772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /*
782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * Method could be virtual or direct.  Try both.  Don't use
792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * the "hier" versions.
802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             */
812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            method = dvmFindDirectMethodByDescriptor(clazz, ops[i].methodName,
822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                        ops[i].methodSignature);
832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (method == NULL)
842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                method = dvmFindVirtualMethodByDescriptor(clazz, ops[i].methodName,
852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                        ops[i].methodSignature);
862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (method == NULL) {
872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                LOGW("DexOpt: can't inline %s.%s %s: method not found\n",
882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    ops[i].classDescriptor, ops[i].methodName,
892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    ops[i].methodSignature);
902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            } else {
912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (!dvmIsFinalClass(clazz) && !dvmIsFinalMethod(method)) {
922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    LOGW("DexOpt: WARNING: inline op on non-final class/method "
932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                         "%s.%s\n",
942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                        clazz->descriptor, method->name);
952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    /* fail? */
962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                }
972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (dvmIsSynchronizedMethod(method) ||
982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    dvmIsDeclaredSynchronizedMethod(method))
992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                {
1002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    LOGW("DexOpt: WARNING: inline op on synchronized method "
1012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                         "%s.%s\n",
1022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                        clazz->descriptor, method->name);
1032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    /* fail? */
1042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                }
1052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                table[tableIndex].method = method;
1072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                table[tableIndex].inlineIdx = i;
1082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                tableIndex++;
1092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                LOGV("DexOpt: will inline %d: %s.%s %s\n", i,
1112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    ops[i].classDescriptor, ops[i].methodName,
1122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    ops[i].methodSignature);
1132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
1142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
1152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* mark end of table */
1182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    table[tableIndex].method = NULL;
1192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGV("DexOpt: inline table has %d entries\n", tableIndex);
1202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return table;
1222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
1232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
125cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * Release inline sub data structure.
1262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
127cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenvoid dvmFreeInlineSubsTable(InlineSub* inlineSubs)
1282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
1292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    free(inlineSubs);
1302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
1312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
132cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
1332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
1342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Optimize the specified class.
1352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
136cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenvoid dvmOptimizeClass(ClassObject* clazz)
1372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
1382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int i;
1392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (i = 0; i < clazz->directMethodCount; i++) {
141cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        if (!optimizeMethod(&clazz->directMethods[i] ))
1422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto fail;
1432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (i = 0; i < clazz->virtualMethodCount; i++) {
145cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden        if (!optimizeMethod(&clazz->virtualMethods[i]))
1462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            goto fail;
1472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return;
1502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenfail:
152cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    // TODO: show when in "verbose" mode
1532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGV("DexOpt: ceasing optimization attempts on %s\n", clazz->descriptor);
1542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
1552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
1572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Optimize instructions in a method.
1582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
159228a6b01918304f2cd1213c722e028a6e25252bbAndy McFadden * This does a single pass through the code, examining each instruction.
160228a6b01918304f2cd1213c722e028a6e25252bbAndy McFadden *
1612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" if all went well, "false" if we bailed out early when
1622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * something failed.
1632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
164cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstatic bool optimizeMethod(Method* method)
1652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
1662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 insnsSize;
1672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2* insns;
1682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 inst;
1692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (dvmIsNativeMethod(method) || dvmIsAbstractMethod(method))
1712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return true;
1722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    insns = (u2*) method->insns;
1742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(insns != NULL);
1752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    insnsSize = dvmGetMethodInsnsSize(method);
1762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    while (insnsSize > 0) {
1782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int width;
1792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        inst = *insns & 0xff;
1812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        switch (inst) {
183cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden#ifndef PROFILE_FIELD_ACCESS    /* quickened instructions not instrumented */
1842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET:
1852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_BOOLEAN:
1862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_BYTE:
1872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_CHAR:
1882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_SHORT:
1892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            rewriteInstField(method, insns, OP_IGET_QUICK);
1902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
1912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_WIDE:
1922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            rewriteInstField(method, insns, OP_IGET_WIDE_QUICK);
1932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
1942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_OBJECT:
1952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            rewriteInstField(method, insns, OP_IGET_OBJECT_QUICK);
1962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
1972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT:
1982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_BOOLEAN:
1992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_BYTE:
2002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_CHAR:
2012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_SHORT:
2022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            rewriteInstField(method, insns, OP_IPUT_QUICK);
2032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
2042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_WIDE:
2052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            rewriteInstField(method, insns, OP_IPUT_WIDE_QUICK);
2062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
2072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_OBJECT:
2082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            rewriteInstField(method, insns, OP_IPUT_OBJECT_QUICK);
2092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
210cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden#endif
2112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_INVOKE_VIRTUAL:
213cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL)) {
2142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (!rewriteVirtualInvoke(method, insns, OP_INVOKE_VIRTUAL_QUICK))
2152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    return false;
2162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
2172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
2182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_INVOKE_VIRTUAL_RANGE:
219cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL)) {
2202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (!rewriteVirtualInvoke(method, insns,
2212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                        OP_INVOKE_VIRTUAL_QUICK_RANGE))
2222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                {
2232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    return false;
2242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                }
2252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
2262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
2272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_INVOKE_SUPER:
2282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (!rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK))
2292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                return false;
2302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
2312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_INVOKE_SUPER_RANGE:
2322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (!rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK_RANGE))
2332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                return false;
2342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
2352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_INVOKE_DIRECT:
237cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            if (!rewriteExecuteInline(method, insns, METHOD_DIRECT)) {
2382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (!rewriteEmptyDirectInvoke(method, insns))
2392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    return false;
2402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
2412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
2422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_INVOKE_DIRECT_RANGE:
243cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            rewriteExecuteInlineRange(method, insns, METHOD_DIRECT);
2442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
2452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_INVOKE_STATIC:
247cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            rewriteExecuteInline(method, insns, METHOD_STATIC);
2482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
2492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_INVOKE_STATIC_RANGE:
250cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden            rewriteExecuteInlineRange(method, insns, METHOD_STATIC);
2512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
2522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        default:
2542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            // ignore this instruction
2552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            ;
2562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
2572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
258228a6b01918304f2cd1213c722e028a6e25252bbAndy McFadden        width = dexGetInstrOrTableWidthAbs(gDvm.instrWidth, insns);
2592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        assert(width > 0);
2602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        insns += width;
2622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        insnsSize -= width;
2632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
2642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(insnsSize == 0);
2662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return true;
2672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
2682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
2712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * If "referrer" and "resClass" don't come from the same DEX file, and
2722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * the DEX we're working on is not destined for the bootstrap class path,
2732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * tweak the class loader so package-access checks work correctly.
2742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
2752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Only do this if we're doing pre-verification or optimization.
2762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
2772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void tweakLoader(ClassObject* referrer, ClassObject* resClass)
2782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
2792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!gDvm.optimizing)
2802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return;
2812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(referrer->classLoader == NULL);
2822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(resClass->classLoader == NULL);
2832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!gDvm.optimizingBootstrapClass) {
2852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* class loader for an array class comes from element type */
2862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (dvmIsArrayClass(resClass))
2872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass = resClass->elementClass;
2882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (referrer->pDvmDex != resClass->pDvmDex)
2892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass->classLoader = (Object*) 0xdead3333;
2902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
2912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
2922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
2932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
2942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Undo the effects of tweakLoader.
2952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
2962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void untweakLoader(ClassObject* referrer, ClassObject* resClass)
2972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
2982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!gDvm.optimizing || gDvm.optimizingBootstrapClass)
2992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return;
3002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (dvmIsArrayClass(resClass))
3022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = resClass->elementClass;
3032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resClass->classLoader = NULL;
3042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
3052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
3082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveClass for use with verification and
3092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * optimization.  Performs access checks on every resolve, and refuses
3102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * to acknowledge the existence of classes defined in more than one DEX
3112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * file.
3122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
3132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Exceptions caused by failures are cleared before returning.
3142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
3152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
3162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
3172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
3182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    VerifyError* pFailure)
3192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
3202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
3212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* resClass;
3222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
3242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Check the table first.  If not there, do the lookup by name.
3252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
3262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
3272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resClass == NULL) {
3282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
3292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (className[0] != '\0' && className[1] == '\0') {
3302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* primitive type */
3312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass = dvmFindPrimitiveClass(className[0]);
3322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else {
3332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass = dvmFindClassNoInit(className, referrer->classLoader);
3342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
3352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
3362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* not found, exception should be raised */
3372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGV("DexOpt: class %d (%s) not found\n",
3382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                classIdx,
3392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
3402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL) {
3412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                /* dig through the wrappers to find the original failure */
3422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                Object* excep = dvmGetException(dvmThreadSelf());
3432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                while (true) {
3442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    Object* cause = dvmGetExceptionCause(excep);
3452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    if (cause == NULL)
3462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                        break;
3472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    excep = cause;
3482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                }
3492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (strcmp(excep->clazz->descriptor,
3502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    "Ljava/lang/IncompatibleClassChangeError;") == 0)
3512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                {
3522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
3532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                } else {
3542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    *pFailure = VERIFY_ERROR_NO_CLASS;
3552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                }
3562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
3572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmClearOptException(dvmThreadSelf());
3582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
3592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
3602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
3622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
3632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
3642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
3652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
3662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* multiple definitions? */
3682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) {
3692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGI("DexOpt: not resolving ambiguous class '%s'\n",
3702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass->descriptor);
3712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
3722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_NO_CLASS;
3732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
3742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
3752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* access allowed? */
3772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    tweakLoader(referrer, resClass);
3782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool allowed = dvmCheckClassAccess(referrer, resClass);
3792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    untweakLoader(referrer, resClass);
3802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!allowed) {
3812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("DexOpt: resolve class illegal access: %s -> %s\n",
3822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            referrer->descriptor, resClass->descriptor);
3832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
3842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_ACCESS_CLASS;
3852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
3862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
3872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resClass;
3892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
3902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
3922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveInstField().
3932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
3942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
3952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
3962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenInstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
3972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    VerifyError* pFailure)
3982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
3992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
4002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    InstField* resField;
4012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx);
4032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resField == NULL) {
4042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const DexFieldId* pFieldId;
4052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassObject* resClass;
4062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);
4082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
4102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Find the field's class.
4112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
4122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
4132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
4142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //dvmClearOptException(dvmThreadSelf());
4152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert(!dvmCheckException(dvmThreadSelf()));
4162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
4172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
4182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resField = (InstField*)dvmFindFieldHier(resClass,
4212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
4222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
4232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resField == NULL) {
4242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGD("DexOpt: couldn't find field %s.%s\n",
4252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resClass->descriptor,
4262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
4272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
4282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_NO_FIELD;
4292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
4302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (dvmIsStaticField(&resField->field)) {
4322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGD("DexOpt: wanted instance, got static for field %s.%s\n",
4332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resClass->descriptor,
4342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
4352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
4362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_CLASS_CHANGE;
4372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
4382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
4412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
4422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
4432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField);
4442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
4452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* access allowed? */
4472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    tweakLoader(referrer, resField->field.clazz);
4482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
4492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    untweakLoader(referrer, resField->field.clazz);
4502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!allowed) {
4512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGI("DexOpt: access denied from %s to field %s.%s\n",
4522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            referrer->descriptor, resField->field.clazz->descriptor,
4532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resField->field.name);
4542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
4552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_ACCESS_FIELD;
4562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
4572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
4582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resField;
4602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
4612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
4632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveStaticField().
4642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
4652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Does not force initialization of the resolved field's class.
4662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
4672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
4682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
4692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenStaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
4702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    VerifyError* pFailure)
4712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
4722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
4732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    StaticField* resField;
4742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx);
4762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resField == NULL) {
4772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const DexFieldId* pFieldId;
4782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassObject* resClass;
4792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);
4812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
4832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Find the field's class.
4842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
4852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
4862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
4872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //dvmClearOptException(dvmThreadSelf());
4882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert(!dvmCheckException(dvmThreadSelf()));
4892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
4902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
4912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resField = (StaticField*)dvmFindFieldHier(resClass,
4942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
4952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
4962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resField == NULL) {
4972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGD("DexOpt: couldn't find static field\n");
4982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
4992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_NO_FIELD;
5002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
5012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!dvmIsStaticField(&resField->field)) {
5032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGD("DexOpt: wanted static, got instance for field %s.%s\n",
5042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resClass->descriptor,
5052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
5062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
5072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_CLASS_CHANGE;
5082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
5092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
5122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
5132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         *
5142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * We can only do this if we're in "dexopt", because the presence
5152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * of a valid value in the resolution table implies that the class
5162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * containing the static field has been initialized.
5172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
5182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gDvm.optimizing)
5192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
5202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
5212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* access allowed? */
5232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    tweakLoader(referrer, resField->field.clazz);
5242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
5252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    untweakLoader(referrer, resField->field.clazz);
5262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!allowed) {
5272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGI("DexOpt: access denied from %s to field %s.%s\n",
5282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            referrer->descriptor, resField->field.clazz->descriptor,
5292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resField->field.name);
5302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
5312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_ACCESS_FIELD;
5322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
5332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
5342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resField;
5362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
5372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
5402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Rewrite an iget/iput instruction.  These all have the form:
5412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *   op vA, vB, field@CCCC
5422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
5432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Where vA holds the value, vB holds the object reference, and CCCC is
5442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * the field reference constant pool offset.  We want to replace CCCC
5452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * with the byte offset from the start of the object.
5462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
5472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * "clazz" is the referring class.  We need this because we verify
5482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * access rights here.
5492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
5502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void rewriteInstField(Method* method, u2* insns, OpCode newOpc)
5512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
5522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
5532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 fieldIdx = insns[1];
5542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    InstField* field;
5552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    field = dvmOptResolveInstField(clazz, fieldIdx, NULL);
5572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (field == NULL) {
5582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGI("DexOpt: unable to optimize field ref 0x%04x at 0x%02x in %s.%s\n",
5592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            fieldIdx, (int) (insns - method->insns), clazz->descriptor,
5602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            method->name);
5612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return;
5622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
5632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (field->byteOffset >= 65536) {
5652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGI("DexOpt: field offset exceeds 64K (%d)\n", field->byteOffset);
5662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return;
5672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
5682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    insns[0] = (insns[0] & 0xff00) | (u2) newOpc;
5702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    insns[1] = (u2) field->byteOffset;
5712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGVV("DexOpt: rewrote access to %s.%s --> %d\n",
5722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        field->field.clazz->descriptor, field->field.name,
5732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        field->byteOffset);
5742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
5752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
5772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveMethod().
5782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
5792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Doesn't throw exceptions, and checks access on every lookup.
5802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
5812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
5822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
5832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenMethod* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
5842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    MethodType methodType, VerifyError* pFailure)
5852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
5862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
5872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* resMethod;
5882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(methodType == METHOD_DIRECT ||
5902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           methodType == METHOD_VIRTUAL ||
5912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           methodType == METHOD_STATIC);
5922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGVV("--- resolving method %u (referrer=%s)\n", methodIdx,
5942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        referrer->descriptor);
5952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
5972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resMethod == NULL) {
5982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const DexMethodId* pMethodId;
5992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassObject* resClass;
6002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
6022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure);
6042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
6052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /*
6062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * Can't find the class that the method is a part of, or don't
6072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * have permission to access the class.
6082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             */
6092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGV("DexOpt: can't find called method's class (?.%s)\n",
6102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
6112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
6122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
6132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
6142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (dvmIsInterfaceClass(resClass)) {
6152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* method is part of an interface; this is wrong method for that */
6162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGW("DexOpt: method is in an interface\n");
6172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
6182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_GENERIC;
6192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
6202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
6212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
6232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * We need to chase up the class hierarchy to find methods defined
6242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * in super-classes.  (We only want to check the current class
6252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * if we're looking for a constructor.)
6262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
6272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        DexProto proto;
6282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
6292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (methodType == METHOD_DIRECT) {
6312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resMethod = dvmFindDirectMethod(resClass,
6322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
6332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else {
6342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* METHOD_STATIC or METHOD_VIRTUAL */
6352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resMethod = dvmFindMethodHier(resClass,
6362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
6372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
6382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resMethod == NULL) {
6402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGV("DexOpt: couldn't find method '%s'\n",
6412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
6422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
6432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_NO_METHOD;
6442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
6452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
6462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (methodType == METHOD_STATIC) {
6472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (!dvmIsStaticMethod(resMethod)) {
6482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                LOGD("DexOpt: wanted static, got instance for method %s.%s\n",
6492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    resClass->descriptor, resMethod->name);
6502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (pFailure != NULL)
6512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
6522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                return NULL;
6532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
6542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else if (methodType == METHOD_VIRTUAL) {
6552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (dvmIsStaticMethod(resMethod)) {
6562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                LOGD("DexOpt: wanted instance, got static for method %s.%s\n",
6572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    resClass->descriptor, resMethod->name);
6582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (pFailure != NULL)
6592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
6602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                return NULL;
6612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
6622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
6632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* see if this is a pure-abstract method */
6652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
6662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGW("DexOpt: pure-abstract method '%s' in %s\n",
6672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx),
6682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resClass->descriptor);
6692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
6702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_GENERIC;
6712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
6722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
6732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
6752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
6762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         *
6772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * We can only do this for static methods if we're not in "dexopt",
6782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * because the presence of a valid value in the resolution table
6792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * implies that the class containing the static field has been
6802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * initialized.
6812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
6822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (methodType != METHOD_STATIC || gDvm.optimizing)
6832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
6842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGVV("--- found method %d (%s.%s)\n",
6872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        methodIdx, resMethod->clazz->descriptor, resMethod->name);
6882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* access allowed? */
6902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    tweakLoader(referrer, resMethod->clazz);
6912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool allowed = dvmCheckMethodAccess(referrer, resMethod);
6922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    untweakLoader(referrer, resMethod->clazz);
6932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!allowed) {
6942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        IF_LOGI() {
6952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
6962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGI("DexOpt: illegal method access (call %s.%s %s from %s)\n",
6972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resMethod->clazz->descriptor, resMethod->name, desc,
6982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                referrer->descriptor);
6992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            free(desc);
7002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
7012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
7022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_ACCESS_METHOD;
7032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
7042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
7052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resMethod;
7072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
7082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
7102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Rewrite invoke-virtual, invoke-virtual/range, invoke-super, and
7112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * invoke-super/range.  These all have the form:
7122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *   op vAA, meth@BBBB, reg stuff @CCCC
7132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
7142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * We want to replace the method constant pool index BBBB with the
7152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * vtable index.
7162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
7172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteVirtualInvoke(Method* method, u2* insns, OpCode newOpc)
7182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
7192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
7202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* baseMethod;
7212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 methodIdx = insns[1];
7222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL, NULL);
7242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (baseMethod == NULL) {
7252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGD("DexOpt: unable to optimize virt call 0x%04x at 0x%02x in %s.%s\n",
7262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            methodIdx,
7272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (int) (insns - method->insns), clazz->descriptor,
7282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            method->name);
7292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
7302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
7312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert((insns[0] & 0xff) == OP_INVOKE_VIRTUAL ||
7332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE ||
7342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           (insns[0] & 0xff) == OP_INVOKE_SUPER ||
7352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           (insns[0] & 0xff) == OP_INVOKE_SUPER_RANGE);
7362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
7382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Note: Method->methodIndex is a u2 and is range checked during the
7392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * initial load.
7402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
7412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    insns[0] = (insns[0] & 0xff00) | (u2) newOpc;
7422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    insns[1] = baseMethod->methodIndex;
7432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    //LOGI("DexOpt: rewrote call to %s.%s --> %s.%s\n",
7452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    //    method->clazz->descriptor, method->name,
7462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    //    baseMethod->clazz->descriptor, baseMethod->name);
7472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return true;
7492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
7502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
7522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Rewrite invoke-direct, which has the form:
7532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *   op vAA, meth@BBBB, reg stuff @CCCC
7542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
7552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * There isn't a lot we can do to make this faster, but in some situations
7562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * we can make it go away entirely.
7572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
7582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * This must only be used when the invoked method does nothing and has
7592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * no return value (the latter being very important for verification).
7602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
7612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteEmptyDirectInvoke(Method* method, u2* insns)
7622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
7632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
7642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* calledMethod;
7652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 methodIdx = insns[1];
7662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL);
7682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (calledMethod == NULL) {
7692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s\n",
7702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            methodIdx,
7712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (int) (insns - method->insns), clazz->descriptor,
7722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            method->name);
7732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
7742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
7752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* TODO: verify that java.lang.Object() is actually empty! */
7772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (calledMethod->clazz == gDvm.classJavaLangObject &&
7782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0)
7792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    {
7802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
7812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Replace with "empty" instruction.  DO NOT disturb anything
7822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * else about it, as we want it to function the same as
7832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * OP_INVOKE_DIRECT when debugging is enabled.
7842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
7852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        assert((insns[0] & 0xff) == OP_INVOKE_DIRECT);
7862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        insns[0] = (insns[0] & 0xff00) | (u2) OP_INVOKE_DIRECT_EMPTY;
7872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        //LOGI("DexOpt: marked-empty call to %s.%s --> %s.%s\n",
7892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        //    method->clazz->descriptor, method->name,
7902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        //    calledMethod->clazz->descriptor, calledMethod->name);
7912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
7922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return true;
7942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
7952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
7972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Resolve an interface method reference.
7982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
7992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * No method access check here -- interface methods are always public.
8002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
8012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns NULL if the method was not found.  Does not throw an exception.
8022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
8032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenMethod* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx)
8042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
8052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
8062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* resMethod;
8072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int i;
8082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGVV("--- resolving interface method %d (referrer=%s)\n",
8102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        methodIdx, referrer->descriptor);
8112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
8132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resMethod == NULL) {
8142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const DexMethodId* pMethodId;
8152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassObject* resClass;
8162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
8182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, NULL);
8202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
8212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* can't find the class that the method is a part of */
8222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmClearOptException(dvmThreadSelf());
8232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
8242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
8252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!dvmIsInterfaceClass(resClass)) {
8262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* whoops */
8272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGI("Interface method not part of interface class\n");
8282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
8292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
8302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const char* methodName =
8322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
8332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        DexProto proto;
8342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
8352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGVV("+++ looking for '%s' '%s' in resClass='%s'\n",
8372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            methodName, methodSig, resClass->descriptor);
8382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resMethod = dvmFindVirtualMethod(resClass, methodName, &proto);
8392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resMethod == NULL) {
8402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* scan superinterfaces and superclass interfaces */
8412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGVV("+++ did not resolve immediately\n");
8422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            for (i = 0; i < resClass->iftableCount; i++) {
8432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resMethod = dvmFindVirtualMethod(resClass->iftable[i].clazz,
8442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                                methodName, &proto);
8452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (resMethod != NULL)
8462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    break;
8472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
8482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (resMethod == NULL) {
8502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                LOGVV("+++ unable to resolve method %s\n", methodName);
8512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                return NULL;
8522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
8532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else {
8542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGVV("+++ resolved immediately: %s (%s %d)\n", resMethod->name,
8552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resMethod->clazz->descriptor, (u4) resMethod->methodIndex);
8562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
8572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* we're expecting this to be abstract */
8592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!dvmIsAbstractMethod(resMethod)) {
8602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
8612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGW("Found non-abstract interface method %s.%s %s\n",
8622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resMethod->clazz->descriptor, resMethod->name, desc);
8632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            free(desc);
8642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
8652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
8662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
8682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
8692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
8702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
8712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
8722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGVV("--- found interface method %d (%s.%s)\n",
8742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        methodIdx, resMethod->clazz->descriptor, resMethod->name);
8752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* interface methods are always public; no need to check access */
8772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resMethod;
8792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
8802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
8822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * See if the method being called can be rewritten as an inline operation.
8832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Works for invoke-virtual, invoke-direct, and invoke-static.
8842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
8852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" if we replace it.
8862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
8872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInline(Method* method, u2* insns,
888cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    MethodType methodType)
8892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
890cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    const InlineSub* inlineSubs = gDvm.inlineSubs;
8912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
8922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* calledMethod;
8932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 methodIdx = insns[1];
8942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    //return false;
8962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
8982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (calledMethod == NULL) {
8992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("+++ DexOpt inline: can't find %d\n", methodIdx);
9002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
9012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
9022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    while (inlineSubs->method != NULL) {
9042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
9052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (extra) {
9062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGI("comparing %p vs %p %s.%s %s\n",
9072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                inlineSubs->method, calledMethod,
9082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                inlineSubs->method->clazz->descriptor,
9092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                inlineSubs->method->name,
9102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                inlineSubs->method->signature);
9112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
9122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        */
9132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (inlineSubs->method == calledMethod) {
9142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert((insns[0] & 0xff) == OP_INVOKE_DIRECT ||
9152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                   (insns[0] & 0xff) == OP_INVOKE_STATIC ||
9162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                   (insns[0] & 0xff) == OP_INVOKE_VIRTUAL);
9172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            insns[0] = (insns[0] & 0xff00) | (u2) OP_EXECUTE_INLINE;
9182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            insns[1] = (u2) inlineSubs->inlineIdx;
9192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //LOGI("DexOpt: execute-inline %s.%s --> %s.%s\n",
9212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //    method->clazz->descriptor, method->name,
9222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //    calledMethod->clazz->descriptor, calledMethod->name);
9232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return true;
9242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
9252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        inlineSubs++;
9272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
9282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return false;
9302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
9312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
9332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * See if the method being called can be rewritten as an inline operation.
9342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Works for invoke-virtual/range, invoke-direct/range, and invoke-static/range.
9352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
9362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" if we replace it.
9372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
9382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInlineRange(Method* method, u2* insns,
939cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    MethodType methodType)
9402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
941cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    const InlineSub* inlineSubs = gDvm.inlineSubs;
9422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
9432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* calledMethod;
9442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 methodIdx = insns[1];
9452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
9472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (calledMethod == NULL) {
9482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("+++ DexOpt inline/range: can't find %d\n", methodIdx);
9492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
9502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
9512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    while (inlineSubs->method != NULL) {
9532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (inlineSubs->method == calledMethod) {
9542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert((insns[0] & 0xff) == OP_INVOKE_DIRECT_RANGE ||
9552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                   (insns[0] & 0xff) == OP_INVOKE_STATIC_RANGE ||
9562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                   (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE);
9572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            insns[0] = (insns[0] & 0xff00) | (u2) OP_EXECUTE_INLINE_RANGE;
9582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            insns[1] = (u2) inlineSubs->inlineIdx;
9592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //LOGI("DexOpt: execute-inline/range %s.%s --> %s.%s\n",
9612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //    method->clazz->descriptor, method->name,
9622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //    calledMethod->clazz->descriptor, calledMethod->name);
9632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return true;
9642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
9652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        inlineSubs++;
9672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
9682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return false;
9702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
971