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"
231813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro#include "Optimize.h"
242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <zlib.h>
262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <stdlib.h>
282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Virtual/direct calls to "method" are replaced with an execute-inline
312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * instruction with index "idx".
322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
33cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstruct InlineSub {
342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* method;
352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int     inlineIdx;
36cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden};
372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* fwd */
40fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFaddenstatic void optimizeMethod(Method* method, bool essentialOnly);
4171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteInstField(Method* method, u2* insns, Opcode quickOpc,
429a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein    Opcode volatileOpc);
4371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteStaticField(Method* method, u2* insns, Opcode volatileOpc);
4471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteVirtualInvoke(Method* method, u2* insns, Opcode newOpc);
456af2ddd107842c3737c04c37343cac9be17f4209Andy McFaddenstatic bool rewriteInvokeObjectInit(Method* method, u2* insns);
462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInline(Method* method, u2* insns,
47cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    MethodType methodType);
482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInlineRange(Method* method, u2* insns,
49cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    MethodType methodType);
503f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFaddenstatic void rewriteReturnVoid(Method* method, u2* insns);
513f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFaddenstatic bool needsReturnBarrier(Method* method);
522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
5565a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden * Create a table of inline substitutions.  Sets gDvm.inlineSubs.
562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * TODO: this is currently just a linear array.  We will want to put this
582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * into a hash table as the list size increases.
592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
601e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirobool dvmCreateInlineSubsTable()
612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const InlineOperation* ops = dvmGetInlineOpsTable();
632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const int count = dvmGetInlineOpsTableLength();
642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    InlineSub* table;
652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int i, tableIndex;
662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    assert(gDvm.inlineSubs == NULL);
6865a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden
692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
7065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden     * One slot per entry, plus an end-of-list marker.
712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
7265a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    table = (InlineSub*) calloc(count + 1, sizeof(InlineSub));
732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    tableIndex = 0;
752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (i = 0; i < count; i++) {
76fe700260881c8f59ee2f2dc2308aef3b0cc39734Elliott Hughes        Method* method = dvmFindInlinableMethod(ops[i].classDescriptor,
77fe700260881c8f59ee2f2dc2308aef3b0cc39734Elliott Hughes            ops[i].methodName, ops[i].methodSignature);
7865a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        if (method == NULL) {
7965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden            /*
8065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden             * Not expected.  We only use this for key methods in core
8165a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden             * classes, so we should always be able to find them.
8265a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden             */
83c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block            ALOGE("Unable to find method for inlining: %s.%s:%s",
84fe700260881c8f59ee2f2dc2308aef3b0cc39734Elliott Hughes                ops[i].classDescriptor, ops[i].methodName,
85fe700260881c8f59ee2f2dc2308aef3b0cc39734Elliott Hughes                ops[i].methodSignature);
8665a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden            return false;
872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
8865a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden
8965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        table[tableIndex].method = method;
9065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        table[tableIndex].inlineIdx = i;
9165a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        tableIndex++;
922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* mark end of table */
952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    table[tableIndex].method = NULL;
962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    gDvm.inlineSubs = table;
9865a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    return true;
992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
1002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
102cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * Release inline sub data structure.
1032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
1041e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid dvmFreeInlineSubsTable()
1052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
10665a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    free(gDvm.inlineSubs);
10765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    gDvm.inlineSubs = NULL;
1082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
1092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
110cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
1112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
1122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Optimize the specified class.
113fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden *
114fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * If "essentialOnly" is true, we only do essential optimizations.  For
115fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * example, accesses to volatile 64-bit fields must be replaced with
116fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * "-wide-volatile" instructions or the program could behave incorrectly.
117fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * (Skipping non-essential optimizations makes us a little bit faster, and
118fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * more importantly avoids dirtying DEX pages.)
1192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
120fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFaddenvoid dvmOptimizeClass(ClassObject* clazz, bool essentialOnly)
1212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
1222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int i;
1232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (i = 0; i < clazz->directMethodCount; i++) {
125fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        optimizeMethod(&clazz->directMethods[i], essentialOnly);
1262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (i = 0; i < clazz->virtualMethodCount; i++) {
128fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        optimizeMethod(&clazz->virtualMethods[i], essentialOnly);
1292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
1312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
1332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Optimize instructions in a method.
1342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
135228a6b01918304f2cd1213c722e028a6e25252bbAndy McFadden * This does a single pass through the code, examining each instruction.
136228a6b01918304f2cd1213c722e028a6e25252bbAndy McFadden *
137fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * This is not expected to fail if the class was successfully verified.
13871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * The only significant failure modes on unverified code occur when an
13971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * "essential" update fails, but we can't generally identify those: if we
14071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * can't look up a field, we can't know if the field access was supposed
14171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * to be handled as volatile.
142fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden *
143fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * Instead, we give it our best effort, and hope for the best.  For 100%
144fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * reliability, only optimize a class after verification succeeds.
1452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
146fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFaddenstatic void optimizeMethod(Method* method, bool essentialOnly)
1472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
14871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    bool needRetBar, forSmp;
1492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 insnsSize;
1502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2* insns;
1512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (dvmIsNativeMethod(method) || dvmIsAbstractMethod(method))
153fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        return;
1542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
15571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    forSmp = gDvm.dexOptForSmp;
15671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    needRetBar = needsReturnBarrier(method);
1573f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
1582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    insns = (u2*) method->insns;
1592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(insns != NULL);
1602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    insnsSize = dvmGetMethodInsnsSize(method);
1612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    while (insnsSize > 0) {
16371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        Opcode opc, quickOpc, volatileOpc;
16471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        size_t width;
16571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        bool matched = true;
16671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden
16771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        opc = dexOpcodeFromCodeUnit(*insns);
16871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        width = dexGetWidthFromInstruction(insns);
16971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        volatileOpc = OP_NOP;
1702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
17171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        /*
17271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         * Each instruction may have:
17371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         * - "volatile" replacement
17471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         *   - may be essential or essential-on-SMP
17571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         * - correctness replacement
17671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         *   - may be essential or essential-on-SMP
17771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         * - performance replacement
17871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         *   - always non-essential
17971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         *
18071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         * Replacements are considered in the order shown, and the first
18171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         * match is applied.  For example, iget-wide will convert to
18271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         * iget-wide-volatile rather than iget-wide-quick if the target
18371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         * field is volatile.
18471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         */
1852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
18665a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        /*
18765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         * essential substitutions:
188ab35b50311951feea3782151dd5422ee944685c2Elliott Hughes         *  {iget,iput,sget,sput}-wide --> {op}-wide-volatile
189ab35b50311951feea3782151dd5422ee944685c2Elliott Hughes         *  invoke-direct[/range] --> invoke-object-init/range
19065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *
19165a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         * essential-on-SMP substitutions:
192ab35b50311951feea3782151dd5422ee944685c2Elliott Hughes         *  {iget,iput,sget,sput}-* --> {op}-volatile
19371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         *  return-void --> return-void-barrier
19465a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *
19565a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         * non-essential substitutions:
19671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         *  {iget,iput}-* --> {op}-quick
19765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *
19865a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         * TODO: might be time to merge this with the other two switches
19965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         */
20071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        switch (opc) {
2012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET:
2022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_BOOLEAN:
2032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_BYTE:
2042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_CHAR:
2052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_SHORT:
206fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            quickOpc = OP_IGET_QUICK;
20771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
208139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden                volatileOpc = OP_IGET_VOLATILE;
209fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            goto rewrite_inst_field;
2102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_WIDE:
211fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            quickOpc = OP_IGET_WIDE_QUICK;
212fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            volatileOpc = OP_IGET_WIDE_VOLATILE;
213fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            goto rewrite_inst_field;
2142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_OBJECT:
215fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            quickOpc = OP_IGET_OBJECT_QUICK;
21671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
217139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden                volatileOpc = OP_IGET_OBJECT_VOLATILE;
218fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            goto rewrite_inst_field;
2192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT:
2202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_BOOLEAN:
2212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_BYTE:
2222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_CHAR:
2232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_SHORT:
224fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            quickOpc = OP_IPUT_QUICK;
22571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
226139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden                volatileOpc = OP_IPUT_VOLATILE;
227fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            goto rewrite_inst_field;
2282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_WIDE:
229fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            quickOpc = OP_IPUT_WIDE_QUICK;
230fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            volatileOpc = OP_IPUT_WIDE_VOLATILE;
231fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            goto rewrite_inst_field;
2322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_OBJECT:
233fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            quickOpc = OP_IPUT_OBJECT_QUICK;
23471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
235139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden                volatileOpc = OP_IPUT_OBJECT_VOLATILE;
23671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            /* fall through */
237fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFaddenrewrite_inst_field:
238fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            if (essentialOnly)
23971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                quickOpc = OP_NOP;      /* if essential-only, no "-quick" sub */
240139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden            if (quickOpc != OP_NOP || volatileOpc != OP_NOP)
241139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden                rewriteInstField(method, insns, quickOpc, volatileOpc);
2422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
2432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
24471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SGET:
24571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SGET_BOOLEAN:
24671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SGET_BYTE:
24771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SGET_CHAR:
24871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SGET_SHORT:
24971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
25071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                volatileOpc = OP_SGET_VOLATILE;
25171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            goto rewrite_static_field;
252139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden        case OP_SGET_WIDE:
253139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden            volatileOpc = OP_SGET_WIDE_VOLATILE;
254139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden            goto rewrite_static_field;
25571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SGET_OBJECT:
25671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
25771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                volatileOpc = OP_SGET_OBJECT_VOLATILE;
25871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            goto rewrite_static_field;
25971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SPUT:
26071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SPUT_BOOLEAN:
26171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SPUT_BYTE:
26271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SPUT_CHAR:
26371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SPUT_SHORT:
26471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
26571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                volatileOpc = OP_SPUT_VOLATILE;
26671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            goto rewrite_static_field;
267139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden        case OP_SPUT_WIDE:
268139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden            volatileOpc = OP_SPUT_WIDE_VOLATILE;
26971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            goto rewrite_static_field;
27071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SPUT_OBJECT:
27171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
27271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                volatileOpc = OP_SPUT_OBJECT_VOLATILE;
27371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            /* fall through */
274fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFaddenrewrite_static_field:
27571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (volatileOpc != OP_NOP)
27671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                rewriteStaticField(method, insns, volatileOpc);
27771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            break;
27871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden
27965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        case OP_INVOKE_DIRECT:
28071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_INVOKE_DIRECT_RANGE:
281d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden            if (!rewriteInvokeObjectInit(method, insns)) {
282d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                /* may want to try execute-inline, below */
28371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                matched = false;
28465a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden            }
28565a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden            break;
28671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_RETURN_VOID:
28771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (needRetBar)
28871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                rewriteReturnVoid(method, insns);
28971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            break;
2902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        default:
29171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            matched = false;
292c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            break;
293c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden        }
294c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden
295fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
29665a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        /*
29765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         * non-essential substitutions:
298d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden         *  invoke-{virtual,direct,static}[/range] --> execute-inline
29965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *  invoke-{virtual,super}[/range] --> invoke-*-quick
30065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         */
30171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        if (!matched && !essentialOnly) {
30271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            switch (opc) {
303fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            case OP_INVOKE_VIRTUAL:
304d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL)) {
305d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                    rewriteVirtualInvoke(method, insns,
306d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                        OP_INVOKE_VIRTUAL_QUICK);
307d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                }
308fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                break;
309fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            case OP_INVOKE_VIRTUAL_RANGE:
310d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL)) {
311d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                    rewriteVirtualInvoke(method, insns,
312d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                        OP_INVOKE_VIRTUAL_QUICK_RANGE);
313d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                }
314fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                break;
315fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            case OP_INVOKE_SUPER:
316fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK);
317fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                break;
318fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            case OP_INVOKE_SUPER_RANGE:
319fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK_RANGE);
320fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                break;
321d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden            case OP_INVOKE_DIRECT:
322d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                rewriteExecuteInline(method, insns, METHOD_DIRECT);
323d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                break;
324d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden            case OP_INVOKE_DIRECT_RANGE:
325d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                rewriteExecuteInlineRange(method, insns, METHOD_DIRECT);
326d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                break;
327d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden            case OP_INVOKE_STATIC:
328d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                rewriteExecuteInline(method, insns, METHOD_STATIC);
329d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                break;
330d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden            case OP_INVOKE_STATIC_RANGE:
331d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                rewriteExecuteInlineRange(method, insns, METHOD_STATIC);
332d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                break;
333fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            default:
334fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                /* nothing to do for this instruction */
335fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                ;
336fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            }
3372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
3382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        assert(width > 0);
34071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        assert(width <= insnsSize);
34171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        assert(width == dexGetWidthFromInstruction(insns));
3422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        insns += width;
3442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        insnsSize -= width;
3452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
3462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(insnsSize == 0);
3482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
3492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
350fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden/*
35157fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden * Update a 16-bit code unit in "meth".  The way in which the DEX data was
35257fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden * loaded determines how we go about the write.
35371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden *
35471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * This will be operating on post-byte-swap DEX data, so values will
35571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * be in host order.
356fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden */
35757fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFaddenvoid dvmUpdateCodeUnit(const Method* meth, u2* ptr, u2 newVal)
358fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden{
35957fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    DvmDex* pDvmDex = meth->clazz->pDvmDex;
36057fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden
36157fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    if (!pDvmDex->isMappedReadOnly) {
36257fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        /* in-memory DEX (dexopt or byte[]), alter the output directly */
363fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        *ptr = newVal;
364fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    } else {
36557fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        /* memory-mapped file, toggle the page read/write status */
36657fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        dvmDexChangeDex2(pDvmDex, ptr, newVal);
367fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    }
368fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden}
3692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
3702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
37171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Update an instruction's opcode.
37271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden *
37371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * If "opcode" is an 8-bit op, we just replace that portion.  If it's a
37471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * 16-bit op, we convert the opcode from "packed" form (e.g. 0x0108) to
37571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * bytecode form (e.g. 0x08ff).
3763f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden */
3779a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornsteinstatic inline void updateOpcode(const Method* meth, u2* ptr, Opcode opcode)
3783f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden{
37971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    if (opcode >= 256) {
38071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        /* opcode low byte becomes high byte, low byte becomes 0xff */
38171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        assert((ptr[0] & 0xff) == 0xff);
38271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        dvmUpdateCodeUnit(meth, ptr, (u2) (opcode << 8) | 0x00ff);
38371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    } else {
38471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        /* 8-bit op, just replace the low byte */
38571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        assert((ptr[0] & 0xff) != 0xff);
38671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        dvmUpdateCodeUnit(meth, ptr, (ptr[0] & 0xff00) | (u2) opcode);
38771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    }
3883f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden}
3893f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
3903f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden/*
3912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * If "referrer" and "resClass" don't come from the same DEX file, and
3922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * the DEX we're working on is not destined for the bootstrap class path,
3932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * tweak the class loader so package-access checks work correctly.
3942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
3952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Only do this if we're doing pre-verification or optimization.
3962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
3972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void tweakLoader(ClassObject* referrer, ClassObject* resClass)
3982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
3992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!gDvm.optimizing)
4002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return;
4012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(referrer->classLoader == NULL);
4022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(resClass->classLoader == NULL);
4032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!gDvm.optimizingBootstrapClass) {
4052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* class loader for an array class comes from element type */
4062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (dvmIsArrayClass(resClass))
4072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass = resClass->elementClass;
4082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (referrer->pDvmDex != resClass->pDvmDex)
4092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass->classLoader = (Object*) 0xdead3333;
4102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
4112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
4122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
4142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Undo the effects of tweakLoader.
4152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
4162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void untweakLoader(ClassObject* referrer, ClassObject* resClass)
4172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
4182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!gDvm.optimizing || gDvm.optimizingBootstrapClass)
4192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return;
4202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (dvmIsArrayClass(resClass))
4222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = resClass->elementClass;
4232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resClass->classLoader = NULL;
4242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
4252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
4282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveClass for use with verification and
4292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * optimization.  Performs access checks on every resolve, and refuses
4302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * to acknowledge the existence of classes defined in more than one DEX
4312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * file.
4322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
4332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Exceptions caused by failures are cleared before returning.
4342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
4352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
4362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
4372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
4382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    VerifyError* pFailure)
4392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
4402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
4412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* resClass;
4422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
4442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Check the table first.  If not there, do the lookup by name.
4452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
4462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
4472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resClass == NULL) {
4482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
4492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (className[0] != '\0' && className[1] == '\0') {
4502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* primitive type */
4512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass = dvmFindPrimitiveClass(className[0]);
4522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else {
4532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass = dvmFindClassNoInit(className, referrer->classLoader);
4542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
4562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* not found, exception should be raised */
45792c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block            ALOGV("DexOpt: class %d (%s) not found",
4582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                classIdx,
4592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
4602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL) {
4612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                /* dig through the wrappers to find the original failure */
4622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                Object* excep = dvmGetException(dvmThreadSelf());
4632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                while (true) {
4642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    Object* cause = dvmGetExceptionCause(excep);
4652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    if (cause == NULL)
4662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                        break;
4672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    excep = cause;
4682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                }
4692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (strcmp(excep->clazz->descriptor,
4702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    "Ljava/lang/IncompatibleClassChangeError;") == 0)
4712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                {
4722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
4732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                } else {
4742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    *pFailure = VERIFY_ERROR_NO_CLASS;
4752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                }
4762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
4772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmClearOptException(dvmThreadSelf());
4782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
4792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
4822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
4832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
4842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
4852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
4862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* multiple definitions? */
4882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) {
4894308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block        ALOGI("DexOpt: not resolving ambiguous class '%s'",
4902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass->descriptor);
4912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
4922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_NO_CLASS;
4932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
4942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
4952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* access allowed? */
4972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    tweakLoader(referrer, resClass);
4982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool allowed = dvmCheckClassAccess(referrer, resClass);
4992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    untweakLoader(referrer, resClass);
5002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!allowed) {
501e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("DexOpt: resolve class illegal access: %s -> %s",
5022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            referrer->descriptor, resClass->descriptor);
5032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
5042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_ACCESS_CLASS;
5052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
5062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
5072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resClass;
5092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
5102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
5122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveInstField().
5132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
5142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
5152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
5162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenInstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
5172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    VerifyError* pFailure)
5182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
5192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
5202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    InstField* resField;
5212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx);
5232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resField == NULL) {
5242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const DexFieldId* pFieldId;
5252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassObject* resClass;
5262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);
5282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
5302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Find the field's class.
5312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
5322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
5332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
5342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //dvmClearOptException(dvmThreadSelf());
5352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert(!dvmCheckException(dvmThreadSelf()));
5362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
5372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
5382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resField = (InstField*)dvmFindFieldHier(resClass,
5412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
5422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
5432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resField == NULL) {
544062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block            ALOGD("DexOpt: couldn't find field %s.%s",
5452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resClass->descriptor,
5462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
5472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
5482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_NO_FIELD;
5492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
5502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
551a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro        if (dvmIsStaticField(resField)) {
552062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block            ALOGD("DexOpt: wanted instance, got static for field %s.%s",
5532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resClass->descriptor,
5542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
5552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
5562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_CLASS_CHANGE;
5572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
5582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
5612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
5622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
5632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField);
5642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
5652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* access allowed? */
567a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro    tweakLoader(referrer, resField->clazz);
5682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
569a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro    untweakLoader(referrer, resField->clazz);
5702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!allowed) {
5714308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block        ALOGI("DexOpt: access denied from %s to field %s.%s",
572a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro            referrer->descriptor, resField->clazz->descriptor,
573a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro            resField->name);
5742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
5752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_ACCESS_FIELD;
5762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
5772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
5782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resField;
5802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
5812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
5832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveStaticField().
5842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
5852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Does not force initialization of the resolved field's class.
5862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
5872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
5882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
5892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenStaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
5902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    VerifyError* pFailure)
5912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
5922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
5932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    StaticField* resField;
5942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx);
5962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resField == NULL) {
5972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const DexFieldId* pFieldId;
5982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassObject* resClass;
5992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);
6012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
6032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Find the field's class.
6042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
6052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
6062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
6072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //dvmClearOptException(dvmThreadSelf());
6082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert(!dvmCheckException(dvmThreadSelf()));
6092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
6102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
6112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
6122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
61371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        const char* fieldName =
61471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx);
61571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden
61671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        resField = (StaticField*)dvmFindFieldHier(resClass, fieldName,
6172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
6182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resField == NULL) {
619062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block            ALOGD("DexOpt: couldn't find static field %s.%s",
62071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                resClass->descriptor, fieldName);
6212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
6222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_NO_FIELD;
6232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
6242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
625a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro        if (!dvmIsStaticField(resField)) {
626062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block            ALOGD("DexOpt: wanted static, got instance for field %s.%s",
62771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                resClass->descriptor, fieldName);
6282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
6292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_CLASS_CHANGE;
6302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
6312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
6322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
6342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
6352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         *
6362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * We can only do this if we're in "dexopt", because the presence
6372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * of a valid value in the resolution table implies that the class
6382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * containing the static field has been initialized.
6392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
6402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gDvm.optimizing)
6412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
6422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* access allowed? */
645a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro    tweakLoader(referrer, resField->clazz);
6462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
647a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro    untweakLoader(referrer, resField->clazz);
6482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!allowed) {
6494308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block        ALOGI("DexOpt: access denied from %s to field %s.%s",
650a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro            referrer->descriptor, resField->clazz->descriptor,
651a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro            resField->name);
6522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
6532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_ACCESS_FIELD;
6542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
6552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
6562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resField;
6582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
6592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
66271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Rewrite an iget/iput instruction if appropriate.  These all have the form:
6632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *   op vA, vB, field@CCCC
6642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
6652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Where vA holds the value, vB holds the object reference, and CCCC is
666fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * the field reference constant pool offset.  For a non-volatile field,
667fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * we want to replace the opcode with "quickOpc" and replace CCCC with
668fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * the byte offset from the start of the object.  For a volatile field,
669fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * we just want to replace the opcode with "volatileOpc".
6702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
671139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden * If "volatileOpc" is OP_NOP we don't check to see if it's a volatile
672139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden * field.  If "quickOpc" is OP_NOP, and this is a non-volatile field,
673139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden * we don't do anything.
674fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden *
675fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * "method" is the referring method.
6762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
67771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteInstField(Method* method, u2* insns, Opcode quickOpc,
6789a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein    Opcode volatileOpc)
6792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
6802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
6812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 fieldIdx = insns[1];
682fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    InstField* instField;
6832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
684fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    instField = dvmOptResolveInstField(clazz, fieldIdx, NULL);
685fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    if (instField == NULL) {
6864308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block        ALOGI("DexOpt: unable to optimize instance field ref "
6876f3c21fb026d9489e5046416bcd5a84fa8e4615bDan Bornstein             "0x%04x at 0x%02x in %s.%s",
6882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            fieldIdx, (int) (insns - method->insns), clazz->descriptor,
6892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            method->name);
69071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        return;
691fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    }
692fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
693a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro    if (volatileOpc != OP_NOP && dvmIsVolatileField(instField)) {
6949a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein        updateOpcode(method, insns, volatileOpc);
69592c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("DexOpt: rewrote ifield access %s.%s --> volatile",
696a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro            instField->clazz->descriptor, instField->name);
69771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    } else if (quickOpc != OP_NOP && instField->byteOffset < 65536) {
6989a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein        updateOpcode(method, insns, quickOpc);
69957fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        dvmUpdateCodeUnit(method, insns+1, (u2) instField->byteOffset);
70092c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("DexOpt: rewrote ifield access %s.%s --> %d",
701a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro            instField->clazz->descriptor, instField->name,
702fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            instField->byteOffset);
703fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    } else {
70492c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("DexOpt: no rewrite of ifield access %s.%s",
705a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro            instField->clazz->descriptor, instField->name);
706fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    }
707fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
70871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    return;
709fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden}
710fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
711fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden/*
712ab35b50311951feea3782151dd5422ee944685c2Elliott Hughes * Rewrite a static field access instruction if appropriate.  If
71371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * the target field is volatile, we replace the opcode with "volatileOpc".
714fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden *
715fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * "method" is the referring method.
716fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden */
71771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteStaticField0(Method* method, u2* insns, Opcode volatileOpc,
71871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    u4 fieldIdx)
719fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden{
720fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    ClassObject* clazz = method->clazz;
721fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    StaticField* staticField;
722fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
723139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden    assert(volatileOpc != OP_NOP);
724139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden
725fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    staticField = dvmOptResolveStaticField(clazz, fieldIdx, NULL);
726fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    if (staticField == NULL) {
7274308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block        ALOGI("DexOpt: unable to optimize static field ref "
7286f3c21fb026d9489e5046416bcd5a84fa8e4615bDan Bornstein             "0x%04x at 0x%02x in %s.%s",
729fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            fieldIdx, (int) (insns - method->insns), clazz->descriptor,
730fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            method->name);
73171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        return;
732fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    }
733fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
734a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro    if (dvmIsVolatileField(staticField)) {
7359a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein        updateOpcode(method, insns, volatileOpc);
73692c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("DexOpt: rewrote sfield access %s.%s --> volatile",
737a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro            staticField->clazz->descriptor, staticField->name);
7382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
73971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden}
7402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
74171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteStaticField(Method* method, u2* insns, Opcode volatileOpc)
74271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden{
74371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    u2 fieldIdx = insns[1];
74471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    rewriteStaticField0(method, insns, volatileOpc, fieldIdx);
74571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden}
74671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden
7472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
7482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveMethod().
7492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
7502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Doesn't throw exceptions, and checks access on every lookup.
7512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
7522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
7532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
7542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenMethod* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
7552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    MethodType methodType, VerifyError* pFailure)
7562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
7572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
7582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* resMethod;
7592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(methodType == METHOD_DIRECT ||
7612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           methodType == METHOD_VIRTUAL ||
7622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           methodType == METHOD_STATIC);
7632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
76460fc806b679a3655c228b4093058c59941a49cfeDan Bornstein    LOGVV("--- resolving method %u (referrer=%s)", methodIdx,
7652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        referrer->descriptor);
7662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
7682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resMethod == NULL) {
7692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const DexMethodId* pMethodId;
7702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassObject* resClass;
7712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
7732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure);
7752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
7762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /*
7772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * Can't find the class that the method is a part of, or don't
7782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * have permission to access the class.
7792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             */
78092c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block            ALOGV("DexOpt: can't find called method's class (?.%s)",
7812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
7822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
7832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
7842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
7852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (dvmIsInterfaceClass(resClass)) {
7862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* method is part of an interface; this is wrong method for that */
787e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block            ALOGW("DexOpt: method is in an interface");
7882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
7892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_GENERIC;
7902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
7912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
7922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
7942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * We need to chase up the class hierarchy to find methods defined
7952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * in super-classes.  (We only want to check the current class
7962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * if we're looking for a constructor.)
7972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
7982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        DexProto proto;
7992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
8002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (methodType == METHOD_DIRECT) {
8022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resMethod = dvmFindDirectMethod(resClass,
8032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
8042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else {
8052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* METHOD_STATIC or METHOD_VIRTUAL */
8062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resMethod = dvmFindMethodHier(resClass,
8072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
8082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
8092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resMethod == NULL) {
81192c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block            ALOGV("DexOpt: couldn't find method '%s'",
8122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
8132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
8142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_NO_METHOD;
8152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
8162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
8172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (methodType == METHOD_STATIC) {
8182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (!dvmIsStaticMethod(resMethod)) {
819062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block                ALOGD("DexOpt: wanted static, got instance for method %s.%s",
8202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    resClass->descriptor, resMethod->name);
8212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (pFailure != NULL)
8222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
8232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                return NULL;
8242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
8252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else if (methodType == METHOD_VIRTUAL) {
8262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (dvmIsStaticMethod(resMethod)) {
827062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block                ALOGD("DexOpt: wanted instance, got static for method %s.%s",
8282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    resClass->descriptor, resMethod->name);
8292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (pFailure != NULL)
8302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
8312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                return NULL;
8322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
8332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
8342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* see if this is a pure-abstract method */
8362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
837e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block            ALOGW("DexOpt: pure-abstract method '%s' in %s",
8382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx),
8392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resClass->descriptor);
8402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
8412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_GENERIC;
8422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
8432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
8442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
8462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
8472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         *
8482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * We can only do this for static methods if we're not in "dexopt",
8492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * because the presence of a valid value in the resolution table
8502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * implies that the class containing the static field has been
8512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * initialized.
8522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
8532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (methodType != METHOD_STATIC || gDvm.optimizing)
8542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
8552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
8562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
85760fc806b679a3655c228b4093058c59941a49cfeDan Bornstein    LOGVV("--- found method %d (%s.%s)",
8582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        methodIdx, resMethod->clazz->descriptor, resMethod->name);
8592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* access allowed? */
8612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    tweakLoader(referrer, resMethod->clazz);
8622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool allowed = dvmCheckMethodAccess(referrer, resMethod);
8632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    untweakLoader(referrer, resMethod->clazz);
8642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!allowed) {
8654308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block        IF_ALOGI() {
8662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
8674308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block            ALOGI("DexOpt: illegal method access (call %s.%s %s from %s)",
8682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resMethod->clazz->descriptor, resMethod->name, desc,
8692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                referrer->descriptor);
8702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            free(desc);
8712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
8722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
8732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_ACCESS_METHOD;
8742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
8752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
8762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resMethod;
8782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
8792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
8812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Rewrite invoke-virtual, invoke-virtual/range, invoke-super, and
88271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * invoke-super/range if appropriate.  These all have the form:
8832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *   op vAA, meth@BBBB, reg stuff @CCCC
8842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
8852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * We want to replace the method constant pool index BBBB with the
8862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * vtable index.
8872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
88871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteVirtualInvoke(Method* method, u2* insns, Opcode newOpc)
8892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
8902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
8912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* baseMethod;
8922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 methodIdx = insns[1];
8932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL, NULL);
8952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (baseMethod == NULL) {
896062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block        ALOGD("DexOpt: unable to optimize virt call 0x%04x at 0x%02x in %s.%s",
8972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            methodIdx,
8982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (int) (insns - method->insns), clazz->descriptor,
8992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            method->name);
90071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        return;
9012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
9022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert((insns[0] & 0xff) == OP_INVOKE_VIRTUAL ||
9042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE ||
9052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           (insns[0] & 0xff) == OP_INVOKE_SUPER ||
9062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           (insns[0] & 0xff) == OP_INVOKE_SUPER_RANGE);
9072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
9092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Note: Method->methodIndex is a u2 and is range checked during the
9102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * initial load.
9112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
9129a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein    updateOpcode(method, insns, newOpc);
91357fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    dvmUpdateCodeUnit(method, insns+1, baseMethod->methodIndex);
9142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9154308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block    //ALOGI("DexOpt: rewrote call to %s.%s --> %s.%s",
9162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    //    method->clazz->descriptor, method->name,
9172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    //    baseMethod->clazz->descriptor, baseMethod->name);
9182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
91971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    return;
9202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
9212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
92371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Rewrite invoke-direct[/range] if the target is Object.<init>.
9242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
9256af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * This is useful as an optimization, because otherwise every object
9266af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * instantiation will cause us to call a method that does nothing.
9276af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * It also allows us to inexpensively mark objects as finalizable at the
9286af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * correct time.
9292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
9306af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * TODO: verifier should ensure Object.<init> contains only return-void,
9316af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * and issue a warning if not.
9322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
9336af2ddd107842c3737c04c37343cac9be17f4209Andy McFaddenstatic bool rewriteInvokeObjectInit(Method* method, u2* insns)
9342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
9352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
9362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* calledMethod;
9372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 methodIdx = insns[1];
9382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL);
9402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (calledMethod == NULL) {
941062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block        ALOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s",
9426af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden            methodIdx, (int) (insns - method->insns),
9436af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden            clazz->descriptor, method->name);
9442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
9452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
9462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (calledMethod->clazz == gDvm.classJavaLangObject &&
9482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0)
9492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    {
9502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
9510346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden         * Replace the instruction.  If the debugger is attached, the
9520346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden         * interpreter will forward execution to the invoke-direct/range
9530346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden         * handler.  If this was an invoke-direct/range instruction we can
9540346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden         * just replace the opcode, but if it was an invoke-direct we
9550346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden         * have to set the argument count (high 8 bits of first code unit)
9560346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden         * to 1.
9572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
9580346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden        u1 origOp = insns[0] & 0xff;
9590346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden        if (origOp == OP_INVOKE_DIRECT) {
96057fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden            dvmUpdateCodeUnit(method, insns,
96157fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden                OP_INVOKE_OBJECT_INIT_RANGE | 0x100);
9620346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden        } else {
9630346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden            assert(origOp == OP_INVOKE_DIRECT_RANGE);
9640346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden            assert((insns[0] >> 8) == 1);
9650346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden            updateOpcode(method, insns, OP_INVOKE_OBJECT_INIT_RANGE);
9660346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden        }
9672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
96860fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGVV("DexOpt: replaced Object.<init> in %s.%s",
9696af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden            method->clazz->descriptor, method->name);
9702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
9712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return true;
9732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
9742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
9762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Resolve an interface method reference.
9772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
9782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * No method access check here -- interface methods are always public.
9792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
9802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns NULL if the method was not found.  Does not throw an exception.
9812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
9822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenMethod* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx)
9832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
9842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
9852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* resMethod;
9862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
98760fc806b679a3655c228b4093058c59941a49cfeDan Bornstein    LOGVV("--- resolving interface method %d (referrer=%s)",
9882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        methodIdx, referrer->descriptor);
9892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
9912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resMethod == NULL) {
9922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const DexMethodId* pMethodId;
9932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassObject* resClass;
9942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
9962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, NULL);
9982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
9992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* can't find the class that the method is a part of */
10002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmClearOptException(dvmThreadSelf());
10012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
10022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
10032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!dvmIsInterfaceClass(resClass)) {
10042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* whoops */
10054308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block            ALOGI("Interface method not part of interface class");
10062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
10072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
10082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const char* methodName =
10102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
10112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        DexProto proto;
10122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
10132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
101460fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGVV("+++ looking for '%s' '%s' in resClass='%s'",
10152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            methodName, methodSig, resClass->descriptor);
1016da7334a4ba1bbffe40d3838f463565af46e716d9Andy McFadden        resMethod = dvmFindInterfaceMethodHier(resClass, methodName, &proto);
10172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resMethod == NULL) {
1018da7334a4ba1bbffe40d3838f463565af46e716d9Andy McFadden            return NULL;
10192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
10202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* we're expecting this to be abstract */
10222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!dvmIsAbstractMethod(resMethod)) {
10232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1024e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block            ALOGW("Found non-abstract interface method %s.%s %s",
10252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resMethod->clazz->descriptor, resMethod->name, desc);
10262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            free(desc);
10272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
10282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
10292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
10312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
10322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
10332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
10342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
103660fc806b679a3655c228b4093058c59941a49cfeDan Bornstein    LOGVV("--- found interface method %d (%s.%s)",
10372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        methodIdx, resMethod->clazz->descriptor, resMethod->name);
10382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* interface methods are always public; no need to check access */
10402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resMethod;
10422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
10432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
104571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Replace invoke-virtual, invoke-direct, or invoke-static with an
104671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * execute-inline operation if appropriate.
10472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
10482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" if we replace it.
10492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
10502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInline(Method* method, u2* insns,
1051cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    MethodType methodType)
10522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
1053cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    const InlineSub* inlineSubs = gDvm.inlineSubs;
10542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
10552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* calledMethod;
10562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 methodIdx = insns[1];
10572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    //return false;
10592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
10612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (calledMethod == NULL) {
106292c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("+++ DexOpt inline: can't find %d", methodIdx);
10632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
10642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    while (inlineSubs->method != NULL) {
10672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
10682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (extra) {
10694308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block            ALOGI("comparing %p vs %p %s.%s %s",
10702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                inlineSubs->method, calledMethod,
10712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                inlineSubs->method->clazz->descriptor,
10722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                inlineSubs->method->name,
10732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                inlineSubs->method->signature);
10742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
10752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        */
10762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (inlineSubs->method == calledMethod) {
10772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert((insns[0] & 0xff) == OP_INVOKE_DIRECT ||
10782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                   (insns[0] & 0xff) == OP_INVOKE_STATIC ||
10792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                   (insns[0] & 0xff) == OP_INVOKE_VIRTUAL);
10809a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein            updateOpcode(method, insns, OP_EXECUTE_INLINE);
108157fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden            dvmUpdateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx);
10822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10834308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block            //ALOGI("DexOpt: execute-inline %s.%s --> %s.%s",
10842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //    method->clazz->descriptor, method->name,
10852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //    calledMethod->clazz->descriptor, calledMethod->name);
10862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return true;
10872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
10882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        inlineSubs++;
10902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return false;
10932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
10942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
109671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Replace invoke-virtual/range, invoke-direct/range, or invoke-static/range
109771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * with an execute-inline operation if appropriate.
10982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
10992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" if we replace it.
11002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
11012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInlineRange(Method* method, u2* insns,
1102cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    MethodType methodType)
11032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
1104cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    const InlineSub* inlineSubs = gDvm.inlineSubs;
11052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
11062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* calledMethod;
11072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 methodIdx = insns[1];
11082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
11102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (calledMethod == NULL) {
111192c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("+++ DexOpt inline/range: can't find %d", methodIdx);
11122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
11132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    while (inlineSubs->method != NULL) {
11162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (inlineSubs->method == calledMethod) {
11172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert((insns[0] & 0xff) == OP_INVOKE_DIRECT_RANGE ||
11182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                   (insns[0] & 0xff) == OP_INVOKE_STATIC_RANGE ||
11192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                   (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE);
11209a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein            updateOpcode(method, insns, OP_EXECUTE_INLINE_RANGE);
112157fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden            dvmUpdateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx);
11222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11234308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block            //ALOGI("DexOpt: execute-inline/range %s.%s --> %s.%s",
11242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //    method->clazz->descriptor, method->name,
11252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //    calledMethod->clazz->descriptor, calledMethod->name);
11262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return true;
11272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
11282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        inlineSubs++;
11302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return false;
11332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
11343f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
11353f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden/*
11363f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * Returns "true" if the return-void instructions in this method should
11373f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * be converted to return-void-barrier.
11383f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden *
11393f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * This is needed to satisfy a Java Memory Model requirement regarding
11403f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * the construction of objects with final fields.  (This does not apply
11413f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * to <clinit> or static fields, since appropriate barriers are guaranteed
11423f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * by the class initialization process.)
11433f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden */
11443f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFaddenstatic bool needsReturnBarrier(Method* method)
11453f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden{
11463f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    if (!gDvm.dexOptForSmp)
11473f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden        return false;
11483f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    if (strcmp(method->name, "<init>") != 0)
11493f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden        return false;
11503f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
11513f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    /*
1152ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     * Check to see if the class is finalizable.  The loader sets a flag
1153ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     * if the class or one of its superclasses overrides finalize().
11543f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     */
11553f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    const ClassObject* clazz = method->clazz;
1156ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden    if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE))
1157ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden        return true;
11583f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
11593f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    /*
1160ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     * Check to see if the class has any final fields.  If not, we don't
1161ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     * need to generate a barrier instruction.
1162ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     *
11633f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     * In theory, we only need to do this if the method actually modifies
11643f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     * a final field.  In practice, non-constructor methods are allowed
1165ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     * to modify final fields, and there are 3rd-party tools that rely on
1166ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     * this behavior.  (The compiler does not allow it, but the VM does.)
11673f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     *
11683f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     * If we alter the verifier to restrict final-field updates to
11693f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     * constructors, we can tighten this up as well.
11703f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     */
1171ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden    int idx = clazz->ifieldCount;
1172ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden    while (--idx >= 0) {
1173a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro        if (dvmIsFinalField(&clazz->ifields[idx]))
1174ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden            return true;
1175ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden    }
11763f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
1177ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden    return false;
11783f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden}
11793f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
11803f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden/*
11813f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * Convert a return-void to a return-void-barrier.
11823f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden */
11833f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFaddenstatic void rewriteReturnVoid(Method* method, u2* insns)
11843f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden{
11853f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    assert((insns[0] & 0xff) == OP_RETURN_VOID);
11869a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein    updateOpcode(method, insns, OP_RETURN_VOID_BARRIER);
11873f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden}
1188