Optimize.cpp revision d18fcbcee7115ff99673222650fda0f7e982c60a
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 */
39fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFaddenstatic void optimizeMethod(Method* method, bool essentialOnly);
409a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornsteinstatic bool rewriteInstField(Method* method, u2* insns, Opcode quickOpc,
419a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein    Opcode volatileOpc);
429a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornsteinstatic bool rewriteStaticField(Method* method, u2* insns, Opcode volatileOpc);
439a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornsteinstatic bool rewriteVirtualInvoke(Method* method, u2* insns, Opcode newOpc);
446af2ddd107842c3737c04c37343cac9be17f4209Andy McFaddenstatic bool rewriteInvokeObjectInit(Method* method, u2* insns);
452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInline(Method* method, u2* insns,
46cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    MethodType methodType);
472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInlineRange(Method* method, u2* insns,
48cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    MethodType methodType);
493f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFaddenstatic void rewriteReturnVoid(Method* method, u2* insns);
503f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFaddenstatic bool needsReturnBarrier(Method* method);
512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
5465a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden * Create a table of inline substitutions.  Sets gDvm.inlineSubs.
552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * TODO: this is currently just a linear array.  We will want to put this
572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * into a hash table as the list size increases.
582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
5965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFaddenbool dvmCreateInlineSubsTable(void)
602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const InlineOperation* ops = dvmGetInlineOpsTable();
622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const int count = dvmGetInlineOpsTableLength();
632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    InlineSub* table;
642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int i, tableIndex;
652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6665a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    assert(gDvm.inlineSubs == NULL);
6765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden
682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
6965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden     * One slot per entry, plus an end-of-list marker.
702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
7165a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    table = (InlineSub*) calloc(count + 1, sizeof(InlineSub));
722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    tableIndex = 0;
742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (i = 0; i < count; i++) {
75fe700260881c8f59ee2f2dc2308aef3b0cc39734Elliott Hughes        Method* method = dvmFindInlinableMethod(ops[i].classDescriptor,
76fe700260881c8f59ee2f2dc2308aef3b0cc39734Elliott Hughes            ops[i].methodName, ops[i].methodSignature);
7765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        if (method == NULL) {
7865a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden            /*
7965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden             * Not expected.  We only use this for key methods in core
8065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden             * classes, so we should always be able to find them.
8165a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden             */
8265a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden            LOGE("Unable to find method for inlining: %s.%s:%s\n",
83fe700260881c8f59ee2f2dc2308aef3b0cc39734Elliott Hughes                ops[i].classDescriptor, ops[i].methodName,
84fe700260881c8f59ee2f2dc2308aef3b0cc39734Elliott Hughes                ops[i].methodSignature);
8565a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden            return false;
862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
8765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden
8865a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        table[tableIndex].method = method;
8965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        table[tableIndex].inlineIdx = i;
9065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        tableIndex++;
912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* mark end of table */
942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    table[tableIndex].method = NULL;
952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9665a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    gDvm.inlineSubs = table;
9765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    return true;
982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
101cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * Release inline sub data structure.
1022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
10365a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFaddenvoid dvmFreeInlineSubsTable(void)
1042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
10565a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    free(gDvm.inlineSubs);
10665a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    gDvm.inlineSubs = NULL;
1072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
1082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
109cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
1102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
1112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Optimize the specified class.
112fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden *
113fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * If "essentialOnly" is true, we only do essential optimizations.  For
114fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * example, accesses to volatile 64-bit fields must be replaced with
115fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * "-wide-volatile" instructions or the program could behave incorrectly.
116fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * (Skipping non-essential optimizations makes us a little bit faster, and
117fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * more importantly avoids dirtying DEX pages.)
1182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
119fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFaddenvoid dvmOptimizeClass(ClassObject* clazz, bool essentialOnly)
1202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
1212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int i;
1222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (i = 0; i < clazz->directMethodCount; i++) {
124fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        optimizeMethod(&clazz->directMethods[i], essentialOnly);
1252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (i = 0; i < clazz->virtualMethodCount; i++) {
127fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        optimizeMethod(&clazz->virtualMethods[i], essentialOnly);
1282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
1302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
1322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Optimize instructions in a method.
1332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
134228a6b01918304f2cd1213c722e028a6e25252bbAndy McFadden * This does a single pass through the code, examining each instruction.
135228a6b01918304f2cd1213c722e028a6e25252bbAndy McFadden *
136fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * This is not expected to fail if the class was successfully verified.
137fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * The only significant failure modes occur when an "essential" update fails,
138fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * but we can't generally identify those: if we can't look up a field,
139fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * we can't know if the field access was supposed to be handled as volatile.
140fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden *
141fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * Instead, we give it our best effort, and hope for the best.  For 100%
142fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * reliability, only optimize a class after verification succeeds.
1432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
144fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFaddenstatic void optimizeMethod(Method* method, bool essentialOnly)
1452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
1462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 insnsSize;
1472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2* insns;
1482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 inst;
1492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (dvmIsNativeMethod(method) || dvmIsAbstractMethod(method))
151fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        return;
1522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1533f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    /* compute this once per method */
1543f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    bool needRetBar = needsReturnBarrier(method);
1553f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
1562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    insns = (u2*) method->insns;
1572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(insns != NULL);
1582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    insnsSize = dvmGetMethodInsnsSize(method);
1592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    while (insnsSize > 0) {
1619a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein        Opcode quickOpc, volatileOpc = OP_NOP;
1622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        int width;
163139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden        bool notMatched = false;
1642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        inst = *insns & 0xff;
1662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
16765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        /*
16865a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         * essential substitutions:
16965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *  {iget,iput,sget,sput}-wide --> *-wide-volatile
170750d110b62cef538e193b6f91f5239b0c4b63ef1Andy McFadden         *  invoke-direct --> invoke-object-init
17165a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *
17265a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         * essential-on-SMP substitutions:
17365a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *  iget-* --> iget-*-volatile
17465a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *  iput-* --> iput-*-volatile
17565a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *
17665a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         * non-essential substitutions:
17765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *  iget-* --> iget-*-quick
17865a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *  iput-* --> iput-*-quick
17965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *
18065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         * TODO: might be time to merge this with the other two switches
18165a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         */
1822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        switch (inst) {
1832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET:
1842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_BOOLEAN:
1852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_BYTE:
1862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_CHAR:
1872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_SHORT:
188fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            quickOpc = OP_IGET_QUICK;
189c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            if (gDvm.dexOptForSmp)
190139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden                volatileOpc = OP_IGET_VOLATILE;
191fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            goto rewrite_inst_field;
1922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_WIDE:
193fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            quickOpc = OP_IGET_WIDE_QUICK;
194fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            volatileOpc = OP_IGET_WIDE_VOLATILE;
195fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            goto rewrite_inst_field;
1962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_OBJECT:
197fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            quickOpc = OP_IGET_OBJECT_QUICK;
198c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            if (gDvm.dexOptForSmp)
199139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden                volatileOpc = OP_IGET_OBJECT_VOLATILE;
200fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            goto rewrite_inst_field;
2012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT:
2022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_BOOLEAN:
2032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_BYTE:
2042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_CHAR:
2052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_SHORT:
206fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            quickOpc = OP_IPUT_QUICK;
207c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            if (gDvm.dexOptForSmp)
208139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden                volatileOpc = OP_IPUT_VOLATILE;
209fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            goto rewrite_inst_field;
2102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_WIDE:
211fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            quickOpc = OP_IPUT_WIDE_QUICK;
212fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            volatileOpc = OP_IPUT_WIDE_VOLATILE;
213fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            goto rewrite_inst_field;
2142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_OBJECT:
215fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            quickOpc = OP_IPUT_OBJECT_QUICK;
216c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            if (gDvm.dexOptForSmp)
217139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden                volatileOpc = OP_IPUT_OBJECT_VOLATILE;
218fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFaddenrewrite_inst_field:
219fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            if (essentialOnly)
22065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden                quickOpc = OP_NOP;      /* if not essential, no "-quick" sub */
221139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden            if (quickOpc != OP_NOP || volatileOpc != OP_NOP)
222139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden                rewriteInstField(method, insns, quickOpc, volatileOpc);
2232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
2242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
225139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden        case OP_SGET_WIDE:
226139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden            volatileOpc = OP_SGET_WIDE_VOLATILE;
227139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden            goto rewrite_static_field;
228139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden        case OP_SPUT_WIDE:
229139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden            volatileOpc = OP_SPUT_WIDE_VOLATILE;
230fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFaddenrewrite_static_field:
231fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            rewriteStaticField(method, insns, volatileOpc);
2322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
23365a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden
23465a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        case OP_INVOKE_DIRECT:
235d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden            /* TODO: also handle invoke-direct/range */
236d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden            if (!rewriteInvokeObjectInit(method, insns)) {
237d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                /* may want to try execute-inline, below */
238d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                notMatched = true;
23965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden            }
24065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden            break;
2412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        default:
242fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            notMatched = true;
243c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            break;
244c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden        }
245c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden
24665a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        /*
24765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         * essential-on-SMP substitutions:
24865a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *  {sget,sput}-* --> {sget,sput}-*-volatile
24965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *  return-void --> return-void-barrier
25065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         */
251c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden        if (notMatched && gDvm.dexOptForSmp) {
252c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            switch (inst) {
253c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            case OP_SGET:
254c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            case OP_SGET_BOOLEAN:
255c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            case OP_SGET_BYTE:
256c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            case OP_SGET_CHAR:
257c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            case OP_SGET_SHORT:
258c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden                volatileOpc = OP_SGET_VOLATILE;
259c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden                goto rewrite_static_field2;
260c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            case OP_SGET_OBJECT:
261c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden                volatileOpc = OP_SGET_OBJECT_VOLATILE;
262c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden                goto rewrite_static_field2;
263c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            case OP_SPUT:
264c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            case OP_SPUT_BOOLEAN:
265c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            case OP_SPUT_BYTE:
266c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            case OP_SPUT_CHAR:
267c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            case OP_SPUT_SHORT:
268c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden                volatileOpc = OP_SPUT_VOLATILE;
269c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden                goto rewrite_static_field2;
270c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            case OP_SPUT_OBJECT:
271c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden                volatileOpc = OP_SPUT_OBJECT_VOLATILE;
272c58b9ef90319c4edad93300151c088434092e9e0Andy McFaddenrewrite_static_field2:
273c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden                rewriteStaticField(method, insns, volatileOpc);
274c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden                notMatched = false;
275c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden                break;
2763f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden            case OP_RETURN_VOID:
2773f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden                if (needRetBar)
2783f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden                    rewriteReturnVoid(method, insns);
2793f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden                notMatched = false;
2803f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden                break;
281c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            default:
282c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden                assert(notMatched);
283c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden                break;
284c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            }
285fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        }
286fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
28765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        /*
28865a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         * non-essential substitutions:
289d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden         *  invoke-{virtual,direct,static}[/range] --> execute-inline
29065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *  invoke-{virtual,super}[/range] --> invoke-*-quick
29165a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         */
292fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        if (notMatched && !essentialOnly) {
293fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            switch (inst) {
294fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            case OP_INVOKE_VIRTUAL:
295d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL)) {
296d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                    rewriteVirtualInvoke(method, insns,
297d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                        OP_INVOKE_VIRTUAL_QUICK);
298d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                }
299fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                break;
300fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            case OP_INVOKE_VIRTUAL_RANGE:
301d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL)) {
302d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                    rewriteVirtualInvoke(method, insns,
303d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                        OP_INVOKE_VIRTUAL_QUICK_RANGE);
304d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                }
305fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                break;
306fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            case OP_INVOKE_SUPER:
307fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK);
308fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                break;
309fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            case OP_INVOKE_SUPER_RANGE:
310fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK_RANGE);
311fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                break;
312d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden            case OP_INVOKE_DIRECT:
313d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                rewriteExecuteInline(method, insns, METHOD_DIRECT);
314d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                break;
315d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden            case OP_INVOKE_DIRECT_RANGE:
316d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                rewriteExecuteInlineRange(method, insns, METHOD_DIRECT);
317d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                break;
318d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden            case OP_INVOKE_STATIC:
319d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                rewriteExecuteInline(method, insns, METHOD_STATIC);
320d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                break;
321d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden            case OP_INVOKE_STATIC_RANGE:
322d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                rewriteExecuteInlineRange(method, insns, METHOD_STATIC);
323d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                break;
324fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            default:
325fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                /* nothing to do for this instruction */
326fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                ;
327fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            }
3282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
3292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
330e485276c6ba778cafa373b3b5c867f84e91b0bfdDan Bornstein        width = dexGetWidthFromInstruction(insns);
3312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        assert(width > 0);
3322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        insns += width;
3342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        insnsSize -= width;
3352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
3362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(insnsSize == 0);
3382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
3392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
340fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden/*
341fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * Update a 16-bit code unit in "meth".
342fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden */
3433f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFaddenstatic inline void updateCodeUnit(const Method* meth, u2* ptr, u2 newVal)
344fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden{
345fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    if (gDvm.optimizing) {
346fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        /* dexopt time, alter the output directly */
347fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        *ptr = newVal;
348fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    } else {
349fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        /* runtime, toggle the page read/write status */
350fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        dvmDexChangeDex2(meth->clazz->pDvmDex, ptr, newVal);
351fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    }
352fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden}
3532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
3553f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * Update the 8-bit opcode portion of a 16-bit code unit in "meth".
3563f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden */
3579a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornsteinstatic inline void updateOpcode(const Method* meth, u2* ptr, Opcode opcode)
3583f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden{
3599a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein    updateCodeUnit(meth, ptr, (ptr[0] & 0xff00) | (u2) opcode);
3603f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden}
3613f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
3623f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden/*
3632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * If "referrer" and "resClass" don't come from the same DEX file, and
3642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * the DEX we're working on is not destined for the bootstrap class path,
3652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * tweak the class loader so package-access checks work correctly.
3662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
3672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Only do this if we're doing pre-verification or optimization.
3682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
3692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void tweakLoader(ClassObject* referrer, ClassObject* resClass)
3702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
3712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!gDvm.optimizing)
3722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return;
3732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(referrer->classLoader == NULL);
3742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(resClass->classLoader == NULL);
3752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!gDvm.optimizingBootstrapClass) {
3772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* class loader for an array class comes from element type */
3782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (dvmIsArrayClass(resClass))
3792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass = resClass->elementClass;
3802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (referrer->pDvmDex != resClass->pDvmDex)
3812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass->classLoader = (Object*) 0xdead3333;
3822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
3832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
3842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
3862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Undo the effects of tweakLoader.
3872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
3882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void untweakLoader(ClassObject* referrer, ClassObject* resClass)
3892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
3902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!gDvm.optimizing || gDvm.optimizingBootstrapClass)
3912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return;
3922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (dvmIsArrayClass(resClass))
3942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = resClass->elementClass;
3952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resClass->classLoader = NULL;
3962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
3972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
4002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveClass for use with verification and
4012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * optimization.  Performs access checks on every resolve, and refuses
4022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * to acknowledge the existence of classes defined in more than one DEX
4032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * file.
4042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
4052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Exceptions caused by failures are cleared before returning.
4062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
4072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
4082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
4092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
4102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    VerifyError* pFailure)
4112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
4122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
4132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* resClass;
4142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
4162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Check the table first.  If not there, do the lookup by name.
4172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
4182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
4192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resClass == NULL) {
4202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
4212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (className[0] != '\0' && className[1] == '\0') {
4222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* primitive type */
4232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass = dvmFindPrimitiveClass(className[0]);
4242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else {
4252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass = dvmFindClassNoInit(className, referrer->classLoader);
4262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
4282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* not found, exception should be raised */
4292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGV("DexOpt: class %d (%s) not found\n",
4302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                classIdx,
4312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
4322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL) {
4332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                /* dig through the wrappers to find the original failure */
4342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                Object* excep = dvmGetException(dvmThreadSelf());
4352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                while (true) {
4362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    Object* cause = dvmGetExceptionCause(excep);
4372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    if (cause == NULL)
4382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                        break;
4392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    excep = cause;
4402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                }
4412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (strcmp(excep->clazz->descriptor,
4422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    "Ljava/lang/IncompatibleClassChangeError;") == 0)
4432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                {
4442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
4452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                } else {
4462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    *pFailure = VERIFY_ERROR_NO_CLASS;
4472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                }
4482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
4492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmClearOptException(dvmThreadSelf());
4502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
4512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
4542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
4552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
4562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
4572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
4582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* multiple definitions? */
4602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) {
4612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGI("DexOpt: not resolving ambiguous class '%s'\n",
4622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass->descriptor);
4632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
4642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_NO_CLASS;
4652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
4662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
4672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* access allowed? */
4692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    tweakLoader(referrer, resClass);
4702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool allowed = dvmCheckClassAccess(referrer, resClass);
4712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    untweakLoader(referrer, resClass);
4722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!allowed) {
4732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGW("DexOpt: resolve class illegal access: %s -> %s\n",
4742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            referrer->descriptor, resClass->descriptor);
4752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
4762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_ACCESS_CLASS;
4772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
4782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
4792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resClass;
4812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
4822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
4842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveInstField().
4852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
4862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
4872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
4882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenInstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
4892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    VerifyError* pFailure)
4902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
4912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
4922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    InstField* resField;
4932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx);
4952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resField == NULL) {
4962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const DexFieldId* pFieldId;
4972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassObject* resClass;
4982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);
5002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
5022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Find the field's class.
5032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
5042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
5052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
5062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //dvmClearOptException(dvmThreadSelf());
5072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert(!dvmCheckException(dvmThreadSelf()));
5082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
5092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
5102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resField = (InstField*)dvmFindFieldHier(resClass,
5132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
5142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
5152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resField == NULL) {
5162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGD("DexOpt: couldn't find field %s.%s\n",
5172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resClass->descriptor,
5182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
5192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
5202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_NO_FIELD;
5212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
5222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (dvmIsStaticField(&resField->field)) {
5242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGD("DexOpt: wanted instance, got static for field %s.%s\n",
5252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resClass->descriptor,
5262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
5272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
5282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_CLASS_CHANGE;
5292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
5302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
5332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
5342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
5352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField);
5362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
5372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* access allowed? */
5392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    tweakLoader(referrer, resField->field.clazz);
5402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
5412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    untweakLoader(referrer, resField->field.clazz);
5422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!allowed) {
5432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGI("DexOpt: access denied from %s to field %s.%s\n",
5442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            referrer->descriptor, resField->field.clazz->descriptor,
5452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resField->field.name);
5462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
5472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_ACCESS_FIELD;
5482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
5492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
5502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resField;
5522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
5532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
5552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveStaticField().
5562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
5572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Does not force initialization of the resolved field's class.
5582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
5592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
5602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
5612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenStaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
5622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    VerifyError* pFailure)
5632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
5642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
5652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    StaticField* resField;
5662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx);
5682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resField == NULL) {
5692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const DexFieldId* pFieldId;
5702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassObject* resClass;
5712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);
5732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
5752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Find the field's class.
5762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
5772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
5782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
5792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //dvmClearOptException(dvmThreadSelf());
5802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert(!dvmCheckException(dvmThreadSelf()));
5812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
5822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
5832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resField = (StaticField*)dvmFindFieldHier(resClass,
5862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
5872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
5882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resField == NULL) {
5892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGD("DexOpt: couldn't find static field\n");
5902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
5912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_NO_FIELD;
5922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
5932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!dvmIsStaticField(&resField->field)) {
5952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGD("DexOpt: wanted static, got instance for field %s.%s\n",
5962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resClass->descriptor,
5972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
5982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
5992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_CLASS_CHANGE;
6002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
6012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
6022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
6042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
6052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         *
6062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * We can only do this if we're in "dexopt", because the presence
6072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * of a valid value in the resolution table implies that the class
6082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * containing the static field has been initialized.
6092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
6102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gDvm.optimizing)
6112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
6122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* access allowed? */
6152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    tweakLoader(referrer, resField->field.clazz);
6162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
6172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    untweakLoader(referrer, resField->field.clazz);
6182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!allowed) {
6192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGI("DexOpt: access denied from %s to field %s.%s\n",
6202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            referrer->descriptor, resField->field.clazz->descriptor,
6212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resField->field.name);
6222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
6232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_ACCESS_FIELD;
6242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
6252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resField;
6282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
6292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
6322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Rewrite an iget/iput instruction.  These all have the form:
6332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *   op vA, vB, field@CCCC
6342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
6352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Where vA holds the value, vB holds the object reference, and CCCC is
636fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * the field reference constant pool offset.  For a non-volatile field,
637fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * we want to replace the opcode with "quickOpc" and replace CCCC with
638fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * the byte offset from the start of the object.  For a volatile field,
639fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * we just want to replace the opcode with "volatileOpc".
6402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
641139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden * If "volatileOpc" is OP_NOP we don't check to see if it's a volatile
642139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden * field.  If "quickOpc" is OP_NOP, and this is a non-volatile field,
643139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden * we don't do anything.
644fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden *
645fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * "method" is the referring method.
6462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
6479a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornsteinstatic bool rewriteInstField(Method* method, u2* insns, Opcode quickOpc,
6489a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein    Opcode volatileOpc)
6492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
6502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
6512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 fieldIdx = insns[1];
652fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    InstField* instField;
6532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
654fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    instField = dvmOptResolveInstField(clazz, fieldIdx, NULL);
655fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    if (instField == NULL) {
656fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        LOGI("DexOpt: unable to optimize instance field ref "
657fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden             "0x%04x at 0x%02x in %s.%s\n",
6582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            fieldIdx, (int) (insns - method->insns), clazz->descriptor,
6592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            method->name);
660fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        return false;
6612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
663fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    if (instField->byteOffset >= 65536) {
664fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        LOGI("DexOpt: field offset exceeds 64K (%d)\n", instField->byteOffset);
665fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        return false;
666fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    }
667fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
668139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden    if (volatileOpc != OP_NOP && dvmIsVolatileField(&instField->field)) {
6699a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein        updateOpcode(method, insns, volatileOpc);
670fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        LOGV("DexOpt: rewrote ifield access %s.%s --> volatile\n",
671fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            instField->field.clazz->descriptor, instField->field.name);
672fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    } else if (quickOpc != OP_NOP) {
6739a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein        updateOpcode(method, insns, quickOpc);
6743f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden        updateCodeUnit(method, insns+1, (u2) instField->byteOffset);
675fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        LOGV("DexOpt: rewrote ifield access %s.%s --> %d\n",
676fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            instField->field.clazz->descriptor, instField->field.name,
677fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            instField->byteOffset);
678fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    } else {
679fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        LOGV("DexOpt: no rewrite of ifield access %s.%s\n",
680fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            instField->field.clazz->descriptor, instField->field.name);
681fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    }
682fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
683fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    return true;
684fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden}
685fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
686fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden/*
687fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * Rewrite an sget/sput instruction.  These all have the form:
688fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden *   op vAA, field@BBBB
689fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden *
690fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * Where vAA holds the value, and BBBB is the field reference constant
691fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * pool offset.  There is no "quick" form of static field accesses, so
692fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * this is only useful for volatile fields.
693fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden *
694fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * "method" is the referring method.
695fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden */
6969a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornsteinstatic bool rewriteStaticField(Method* method, u2* insns, Opcode volatileOpc)
697fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden{
698fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    ClassObject* clazz = method->clazz;
699fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    u2 fieldIdx = insns[1];
700fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    StaticField* staticField;
701fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
702139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden    assert(volatileOpc != OP_NOP);
703139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden
704fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    staticField = dvmOptResolveStaticField(clazz, fieldIdx, NULL);
705fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    if (staticField == NULL) {
706fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        LOGI("DexOpt: unable to optimize static field ref "
707fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden             "0x%04x at 0x%02x in %s.%s\n",
708fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            fieldIdx, (int) (insns - method->insns), clazz->descriptor,
709fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            method->name);
710fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        return false;
711fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    }
712fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
713fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    if (dvmIsVolatileField(&staticField->field)) {
7149a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein        updateOpcode(method, insns, volatileOpc);
715fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        LOGV("DexOpt: rewrote sfield access %s.%s --> volatile\n",
716fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            staticField->field.clazz->descriptor, staticField->field.name);
7172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
7182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
719fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    return true;
7202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
7212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
7232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveMethod().
7242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
7252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Doesn't throw exceptions, and checks access on every lookup.
7262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
7272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
7282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
7292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenMethod* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
7302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    MethodType methodType, VerifyError* pFailure)
7312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
7322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
7332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* resMethod;
7342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(methodType == METHOD_DIRECT ||
7362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           methodType == METHOD_VIRTUAL ||
7372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           methodType == METHOD_STATIC);
7382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGVV("--- resolving method %u (referrer=%s)\n", methodIdx,
7402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        referrer->descriptor);
7412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
7432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resMethod == NULL) {
7442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const DexMethodId* pMethodId;
7452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassObject* resClass;
7462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
7482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure);
7502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
7512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /*
7522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * Can't find the class that the method is a part of, or don't
7532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * have permission to access the class.
7542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             */
7552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGV("DexOpt: can't find called method's class (?.%s)\n",
7562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
7572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
7582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
7592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
7602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (dvmIsInterfaceClass(resClass)) {
7612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* method is part of an interface; this is wrong method for that */
7622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGW("DexOpt: method is in an interface\n");
7632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
7642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_GENERIC;
7652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
7662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
7672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
7692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * We need to chase up the class hierarchy to find methods defined
7702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * in super-classes.  (We only want to check the current class
7712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * if we're looking for a constructor.)
7722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
7732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        DexProto proto;
7742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
7752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (methodType == METHOD_DIRECT) {
7772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resMethod = dvmFindDirectMethod(resClass,
7782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
7792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else {
7802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* METHOD_STATIC or METHOD_VIRTUAL */
7812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resMethod = dvmFindMethodHier(resClass,
7822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
7832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
7842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resMethod == NULL) {
7862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGV("DexOpt: couldn't find method '%s'\n",
7872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
7882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
7892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_NO_METHOD;
7902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
7912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
7922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (methodType == METHOD_STATIC) {
7932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (!dvmIsStaticMethod(resMethod)) {
7942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                LOGD("DexOpt: wanted static, got instance for method %s.%s\n",
7952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    resClass->descriptor, resMethod->name);
7962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (pFailure != NULL)
7972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
7982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                return NULL;
7992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
8002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else if (methodType == METHOD_VIRTUAL) {
8012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (dvmIsStaticMethod(resMethod)) {
8022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                LOGD("DexOpt: wanted instance, got static for method %s.%s\n",
8032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    resClass->descriptor, resMethod->name);
8042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (pFailure != NULL)
8052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
8062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                return NULL;
8072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
8082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
8092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* see if this is a pure-abstract method */
8112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
8122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGW("DexOpt: pure-abstract method '%s' in %s\n",
8132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx),
8142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resClass->descriptor);
8152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
8162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_GENERIC;
8172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
8182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
8192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
8212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
8222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         *
8232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * We can only do this for static methods if we're not in "dexopt",
8242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * because the presence of a valid value in the resolution table
8252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * implies that the class containing the static field has been
8262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * initialized.
8272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
8282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (methodType != METHOD_STATIC || gDvm.optimizing)
8292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
8302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
8312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGVV("--- found method %d (%s.%s)\n",
8332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        methodIdx, resMethod->clazz->descriptor, resMethod->name);
8342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* access allowed? */
8362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    tweakLoader(referrer, resMethod->clazz);
8372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool allowed = dvmCheckMethodAccess(referrer, resMethod);
8382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    untweakLoader(referrer, resMethod->clazz);
8392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!allowed) {
8402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        IF_LOGI() {
8412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
8422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGI("DexOpt: illegal method access (call %s.%s %s from %s)\n",
8432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resMethod->clazz->descriptor, resMethod->name, desc,
8442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                referrer->descriptor);
8452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            free(desc);
8462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
8472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
8482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_ACCESS_METHOD;
8492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
8502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
8512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resMethod;
8532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
8542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
8562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Rewrite invoke-virtual, invoke-virtual/range, invoke-super, and
8572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * invoke-super/range.  These all have the form:
8582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *   op vAA, meth@BBBB, reg stuff @CCCC
8592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
8602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * We want to replace the method constant pool index BBBB with the
8612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * vtable index.
8622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
8639a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornsteinstatic bool rewriteVirtualInvoke(Method* method, u2* insns, Opcode newOpc)
8642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
8652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
8662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* baseMethod;
8672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 methodIdx = insns[1];
8682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL, NULL);
8702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (baseMethod == NULL) {
8712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGD("DexOpt: unable to optimize virt call 0x%04x at 0x%02x in %s.%s\n",
8722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            methodIdx,
8732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (int) (insns - method->insns), clazz->descriptor,
8742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            method->name);
8752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
8762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
8772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert((insns[0] & 0xff) == OP_INVOKE_VIRTUAL ||
8792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE ||
8802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           (insns[0] & 0xff) == OP_INVOKE_SUPER ||
8812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           (insns[0] & 0xff) == OP_INVOKE_SUPER_RANGE);
8822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
8842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Note: Method->methodIndex is a u2 and is range checked during the
8852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * initial load.
8862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
8879a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein    updateOpcode(method, insns, newOpc);
8883f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    updateCodeUnit(method, insns+1, baseMethod->methodIndex);
8892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    //LOGI("DexOpt: rewrote call to %s.%s --> %s.%s\n",
8912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    //    method->clazz->descriptor, method->name,
8922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    //    baseMethod->clazz->descriptor, baseMethod->name);
8932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return true;
8952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
8962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
8986af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * Rewrite invoke-direct of Object.<init>, which has the form:
8992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *   op vAA, meth@BBBB, reg stuff @CCCC
9002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
9016af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * This is useful as an optimization, because otherwise every object
9026af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * instantiation will cause us to call a method that does nothing.
9036af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * It also allows us to inexpensively mark objects as finalizable at the
9046af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * correct time.
9052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
9066af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * TODO: verifier should ensure Object.<init> contains only return-void,
9076af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * and issue a warning if not.
9082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
9096af2ddd107842c3737c04c37343cac9be17f4209Andy McFaddenstatic bool rewriteInvokeObjectInit(Method* method, u2* insns)
9102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
9112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
9122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* calledMethod;
9132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 methodIdx = insns[1];
9142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL);
9162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (calledMethod == NULL) {
9172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s\n",
9186af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden            methodIdx, (int) (insns - method->insns),
9196af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden            clazz->descriptor, method->name);
9202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
9212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
9222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (calledMethod->clazz == gDvm.classJavaLangObject &&
9242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0)
9252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    {
9262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
9276af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden         * Replace the instruction.  We want to modify as little as possible
9286af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden         * because, if the debugger is attached, the interpreter will
9296af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden         * forward execution to the invoke-direct handler.
9302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
9312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        assert((insns[0] & 0xff) == OP_INVOKE_DIRECT);
932750d110b62cef538e193b6f91f5239b0c4b63ef1Andy McFadden        updateOpcode(method, insns, OP_INVOKE_OBJECT_INIT);
9332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9346af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden        LOGVV("DexOpt: replaced Object.<init> in %s.%s\n",
9356af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden            method->clazz->descriptor, method->name);
9362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
9372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return true;
9392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
9402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
9422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Resolve an interface method reference.
9432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
9442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * No method access check here -- interface methods are always public.
9452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
9462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns NULL if the method was not found.  Does not throw an exception.
9472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
9482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenMethod* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx)
9492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
9502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
9512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* resMethod;
9522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGVV("--- resolving interface method %d (referrer=%s)\n",
9542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        methodIdx, referrer->descriptor);
9552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
9572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resMethod == NULL) {
9582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const DexMethodId* pMethodId;
9592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassObject* resClass;
9602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
9622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, NULL);
9642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
9652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* can't find the class that the method is a part of */
9662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmClearOptException(dvmThreadSelf());
9672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
9682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
9692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!dvmIsInterfaceClass(resClass)) {
9702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* whoops */
9712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGI("Interface method not part of interface class\n");
9722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
9732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
9742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const char* methodName =
9762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
9772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        DexProto proto;
9782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
9792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGVV("+++ looking for '%s' '%s' in resClass='%s'\n",
9812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            methodName, methodSig, resClass->descriptor);
982da7334a4ba1bbffe40d3838f463565af46e716d9Andy McFadden        resMethod = dvmFindInterfaceMethodHier(resClass, methodName, &proto);
9832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resMethod == NULL) {
984da7334a4ba1bbffe40d3838f463565af46e716d9Andy McFadden            return NULL;
9852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
9862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* we're expecting this to be abstract */
9882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!dvmIsAbstractMethod(resMethod)) {
9892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
9902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGW("Found non-abstract interface method %s.%s %s\n",
9912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resMethod->clazz->descriptor, resMethod->name, desc);
9922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            free(desc);
9932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
9942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
9952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
9972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
9982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
9992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
10002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    LOGVV("--- found interface method %d (%s.%s)\n",
10032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        methodIdx, resMethod->clazz->descriptor, resMethod->name);
10042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* interface methods are always public; no need to check access */
10062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resMethod;
10082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
10092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
10112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * See if the method being called can be rewritten as an inline operation.
10122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Works for invoke-virtual, invoke-direct, and invoke-static.
10132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
10142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" if we replace it.
10152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
10162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInline(Method* method, u2* insns,
1017cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    MethodType methodType)
10182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
1019cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    const InlineSub* inlineSubs = gDvm.inlineSubs;
10202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
10212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* calledMethod;
10222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 methodIdx = insns[1];
10232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    //return false;
10252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
10272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (calledMethod == NULL) {
10282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("+++ DexOpt inline: can't find %d\n", methodIdx);
10292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
10302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    while (inlineSubs->method != NULL) {
10332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
10342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (extra) {
10352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            LOGI("comparing %p vs %p %s.%s %s\n",
10362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                inlineSubs->method, calledMethod,
10372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                inlineSubs->method->clazz->descriptor,
10382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                inlineSubs->method->name,
10392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                inlineSubs->method->signature);
10402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
10412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        */
10422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (inlineSubs->method == calledMethod) {
10432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert((insns[0] & 0xff) == OP_INVOKE_DIRECT ||
10442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                   (insns[0] & 0xff) == OP_INVOKE_STATIC ||
10452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                   (insns[0] & 0xff) == OP_INVOKE_VIRTUAL);
10469a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein            updateOpcode(method, insns, OP_EXECUTE_INLINE);
10473f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden            updateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx);
10482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //LOGI("DexOpt: execute-inline %s.%s --> %s.%s\n",
10502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //    method->clazz->descriptor, method->name,
10512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //    calledMethod->clazz->descriptor, calledMethod->name);
10522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return true;
10532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
10542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        inlineSubs++;
10562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return false;
10592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
10602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
10622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * See if the method being called can be rewritten as an inline operation.
10632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Works for invoke-virtual/range, invoke-direct/range, and invoke-static/range.
10642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
10652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" if we replace it.
10662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
10672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInlineRange(Method* method, u2* insns,
1068cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    MethodType methodType)
10692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
1070cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    const InlineSub* inlineSubs = gDvm.inlineSubs;
10712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
10722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* calledMethod;
10732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 methodIdx = insns[1];
10742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
10762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (calledMethod == NULL) {
10772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        LOGV("+++ DexOpt inline/range: can't find %d\n", methodIdx);
10782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
10792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    while (inlineSubs->method != NULL) {
10822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (inlineSubs->method == calledMethod) {
10832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert((insns[0] & 0xff) == OP_INVOKE_DIRECT_RANGE ||
10842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                   (insns[0] & 0xff) == OP_INVOKE_STATIC_RANGE ||
10852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                   (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE);
10869a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein            updateOpcode(method, insns, OP_EXECUTE_INLINE_RANGE);
10873f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden            updateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx);
10882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //LOGI("DexOpt: execute-inline/range %s.%s --> %s.%s\n",
10902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //    method->clazz->descriptor, method->name,
10912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //    calledMethod->clazz->descriptor, calledMethod->name);
10922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return true;
10932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
10942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        inlineSubs++;
10962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return false;
10992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
11003f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
11013f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden/*
11023f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * Returns "true" if the return-void instructions in this method should
11033f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * be converted to return-void-barrier.
11043f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden *
11053f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * This is needed to satisfy a Java Memory Model requirement regarding
11063f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * the construction of objects with final fields.  (This does not apply
11073f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * to <clinit> or static fields, since appropriate barriers are guaranteed
11083f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * by the class initialization process.)
11093f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden */
11103f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFaddenstatic bool needsReturnBarrier(Method* method)
11113f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden{
11123f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    if (!gDvm.dexOptForSmp)
11133f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden        return false;
11143f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    if (strcmp(method->name, "<init>") != 0)
11153f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden        return false;
11163f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
11173f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    /*
1118ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     * Check to see if the class is finalizable.  The loader sets a flag
1119ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     * if the class or one of its superclasses overrides finalize().
11203f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     */
11213f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    const ClassObject* clazz = method->clazz;
1122ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden    if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE))
1123ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden        return true;
11243f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
11253f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    /*
1126ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     * Check to see if the class has any final fields.  If not, we don't
1127ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     * need to generate a barrier instruction.
1128ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     *
11293f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     * In theory, we only need to do this if the method actually modifies
11303f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     * a final field.  In practice, non-constructor methods are allowed
1131ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     * to modify final fields, and there are 3rd-party tools that rely on
1132ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     * this behavior.  (The compiler does not allow it, but the VM does.)
11333f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     *
11343f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     * If we alter the verifier to restrict final-field updates to
11353f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     * constructors, we can tighten this up as well.
11363f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     */
1137ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden    int idx = clazz->ifieldCount;
1138ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden    while (--idx >= 0) {
1139ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden        if (dvmIsFinalField(&clazz->ifields[idx].field))
1140ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden            return true;
1141ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden    }
11423f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
1143ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden    return false;
11443f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden}
11453f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
11463f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden/*
11473f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * Convert a return-void to a return-void-barrier.
11483f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden */
11493f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFaddenstatic void rewriteReturnVoid(Method* method, u2* insns)
11503f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden{
11513f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    assert((insns[0] & 0xff) == OP_RETURN_VOID);
11529a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein    updateOpcode(method, insns, OP_RETURN_VOID_BARRIER);
11533f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden}
1154