Optimize.cpp revision 60fc806b679a3655c228b4093058c59941a49cfe
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 rewriteJumboInstField(Method* method, u2* insns,
4471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    Opcode volatileOpc);
4571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteStaticField(Method* method, u2* insns, Opcode volatileOpc);
4671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteJumboStaticField(Method* method, u2* insns,
4771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    Opcode volatileOpc);
4871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteVirtualInvoke(Method* method, u2* insns, Opcode newOpc);
496af2ddd107842c3737c04c37343cac9be17f4209Andy McFaddenstatic bool rewriteInvokeObjectInit(Method* method, u2* insns);
5071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic bool rewriteJumboInvokeObjectInit(Method* method, u2* insns);
512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInline(Method* method, u2* insns,
52cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    MethodType methodType);
532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInlineRange(Method* method, u2* insns,
54cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    MethodType methodType);
553f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFaddenstatic void rewriteReturnVoid(Method* method, u2* insns);
563f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFaddenstatic bool needsReturnBarrier(Method* method);
572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
6065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden * Create a table of inline substitutions.  Sets gDvm.inlineSubs.
612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * TODO: this is currently just a linear array.  We will want to put this
632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * into a hash table as the list size increases.
642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
651e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirobool dvmCreateInlineSubsTable()
662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const InlineOperation* ops = dvmGetInlineOpsTable();
682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    const int count = dvmGetInlineOpsTableLength();
692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    InlineSub* table;
702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int i, tableIndex;
712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7265a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    assert(gDvm.inlineSubs == NULL);
7365a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden
742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
7565a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden     * One slot per entry, plus an end-of-list marker.
762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
7765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    table = (InlineSub*) calloc(count + 1, sizeof(InlineSub));
782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    tableIndex = 0;
802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (i = 0; i < count; i++) {
81fe700260881c8f59ee2f2dc2308aef3b0cc39734Elliott Hughes        Method* method = dvmFindInlinableMethod(ops[i].classDescriptor,
82fe700260881c8f59ee2f2dc2308aef3b0cc39734Elliott Hughes            ops[i].methodName, ops[i].methodSignature);
8365a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        if (method == NULL) {
8465a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden            /*
8565a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden             * Not expected.  We only use this for key methods in core
8665a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden             * classes, so we should always be able to find them.
8765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden             */
8860fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            LOGE("Unable to find method for inlining: %s.%s:%s",
89fe700260881c8f59ee2f2dc2308aef3b0cc39734Elliott Hughes                ops[i].classDescriptor, ops[i].methodName,
90fe700260881c8f59ee2f2dc2308aef3b0cc39734Elliott Hughes                ops[i].methodSignature);
9165a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden            return false;
922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
9365a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden
9465a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        table[tableIndex].method = method;
9565a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        table[tableIndex].inlineIdx = i;
9665a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        tableIndex++;
972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* mark end of table */
1002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    table[tableIndex].method = NULL;
1012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10265a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    gDvm.inlineSubs = table;
10365a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    return true;
1042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
1052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
107cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * Release inline sub data structure.
1082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
1091e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid dvmFreeInlineSubsTable()
1102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
11165a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    free(gDvm.inlineSubs);
11265a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden    gDvm.inlineSubs = NULL;
1132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
1142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
115cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden
1162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
1172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Optimize the specified class.
118fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden *
119fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * If "essentialOnly" is true, we only do essential optimizations.  For
120fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * example, accesses to volatile 64-bit fields must be replaced with
121fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * "-wide-volatile" instructions or the program could behave incorrectly.
122fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * (Skipping non-essential optimizations makes us a little bit faster, and
123fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * more importantly avoids dirtying DEX pages.)
1242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
125fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFaddenvoid dvmOptimizeClass(ClassObject* clazz, bool essentialOnly)
1262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
1272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    int i;
1282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (i = 0; i < clazz->directMethodCount; i++) {
130fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        optimizeMethod(&clazz->directMethods[i], essentialOnly);
1312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    for (i = 0; i < clazz->virtualMethodCount; i++) {
133fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        optimizeMethod(&clazz->virtualMethods[i], essentialOnly);
1342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
1352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
1362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
1382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Optimize instructions in a method.
1392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
140228a6b01918304f2cd1213c722e028a6e25252bbAndy McFadden * This does a single pass through the code, examining each instruction.
141228a6b01918304f2cd1213c722e028a6e25252bbAndy McFadden *
142fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * This is not expected to fail if the class was successfully verified.
14371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * The only significant failure modes on unverified code occur when an
14471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * "essential" update fails, but we can't generally identify those: if we
14571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * can't look up a field, we can't know if the field access was supposed
14671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * to be handled as volatile.
147fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden *
148fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * Instead, we give it our best effort, and hope for the best.  For 100%
149fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * reliability, only optimize a class after verification succeeds.
1502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
151fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFaddenstatic void optimizeMethod(Method* method, bool essentialOnly)
1522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
15371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    bool needRetBar, forSmp;
1542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u4 insnsSize;
1552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2* insns;
1562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (dvmIsNativeMethod(method) || dvmIsAbstractMethod(method))
158fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        return;
1592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
16071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    forSmp = gDvm.dexOptForSmp;
16171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    needRetBar = needsReturnBarrier(method);
1623f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
1632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    insns = (u2*) method->insns;
1642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(insns != NULL);
1652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    insnsSize = dvmGetMethodInsnsSize(method);
1662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
1672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    while (insnsSize > 0) {
16871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        Opcode opc, quickOpc, volatileOpc;
16971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        size_t width;
17071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        bool matched = true;
17171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden
17271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        opc = dexOpcodeFromCodeUnit(*insns);
17371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        width = dexGetWidthFromInstruction(insns);
17471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        volatileOpc = OP_NOP;
1752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
17671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        /*
17771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         * Each instruction may have:
17871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         * - "volatile" replacement
17971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         *   - may be essential or essential-on-SMP
18071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         * - correctness replacement
18171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         *   - may be essential or essential-on-SMP
18271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         * - performance replacement
18371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         *   - always non-essential
18471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         *
18571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         * Replacements are considered in the order shown, and the first
18671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         * match is applied.  For example, iget-wide will convert to
18771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         * iget-wide-volatile rather than iget-wide-quick if the target
18871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         * field is volatile.
18971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         */
1902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
19165a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        /*
19265a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         * essential substitutions:
19371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         *  {iget,iput,sget,sput}-wide[/jumbo] --> {op}-wide-volatile
19471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         *  invoke-direct[/jumbo][/range] --> invoke-object-init/range
19565a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *
19665a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         * essential-on-SMP substitutions:
19771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         *  {iget,iput,sget,sput}-*[/jumbo] --> {op}-volatile
19871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         *  return-void --> return-void-barrier
19965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *
20065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         * non-essential substitutions:
20171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden         *  {iget,iput}-* --> {op}-quick
20265a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *
20365a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         * TODO: might be time to merge this with the other two switches
20465a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         */
20571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        switch (opc) {
2062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET:
2072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_BOOLEAN:
2082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_BYTE:
2092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_CHAR:
2102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_SHORT:
211fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            quickOpc = OP_IGET_QUICK;
21271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
213139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden                volatileOpc = OP_IGET_VOLATILE;
214fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            goto rewrite_inst_field;
2152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_WIDE:
216fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            quickOpc = OP_IGET_WIDE_QUICK;
217fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            volatileOpc = OP_IGET_WIDE_VOLATILE;
218fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            goto rewrite_inst_field;
2192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IGET_OBJECT:
220fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            quickOpc = OP_IGET_OBJECT_QUICK;
22171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
222139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden                volatileOpc = OP_IGET_OBJECT_VOLATILE;
223fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            goto rewrite_inst_field;
2242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT:
2252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_BOOLEAN:
2262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_BYTE:
2272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_CHAR:
2282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_SHORT:
229fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            quickOpc = OP_IPUT_QUICK;
23071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
231139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden                volatileOpc = OP_IPUT_VOLATILE;
232fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            goto rewrite_inst_field;
2332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_WIDE:
234fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            quickOpc = OP_IPUT_WIDE_QUICK;
235fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            volatileOpc = OP_IPUT_WIDE_VOLATILE;
236fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            goto rewrite_inst_field;
2372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        case OP_IPUT_OBJECT:
238fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            quickOpc = OP_IPUT_OBJECT_QUICK;
23971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
240139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden                volatileOpc = OP_IPUT_OBJECT_VOLATILE;
24171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            /* fall through */
242fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFaddenrewrite_inst_field:
243fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            if (essentialOnly)
24471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                quickOpc = OP_NOP;      /* if essential-only, no "-quick" sub */
245139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden            if (quickOpc != OP_NOP || volatileOpc != OP_NOP)
246139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden                rewriteInstField(method, insns, quickOpc, volatileOpc);
2472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
2482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
24971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_IGET_JUMBO:
25062fe4c1e9fc28254d357e9755cf4bd2138753c17buzbee        case OP_IGET_BOOLEAN_JUMBO:
25162fe4c1e9fc28254d357e9755cf4bd2138753c17buzbee        case OP_IGET_BYTE_JUMBO:
25262fe4c1e9fc28254d357e9755cf4bd2138753c17buzbee        case OP_IGET_CHAR_JUMBO:
25362fe4c1e9fc28254d357e9755cf4bd2138753c17buzbee        case OP_IGET_SHORT_JUMBO:
25471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
25571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                volatileOpc = OP_IGET_VOLATILE_JUMBO;
25671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            goto rewrite_jumbo_inst_field;
25771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_IGET_WIDE_JUMBO:
25871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            volatileOpc = OP_IGET_WIDE_VOLATILE_JUMBO;
25971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            goto rewrite_jumbo_inst_field;
26071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_IGET_OBJECT_JUMBO:
26171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
26271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                volatileOpc = OP_IGET_OBJECT_VOLATILE_JUMBO;
26371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            goto rewrite_jumbo_inst_field;
26471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_IPUT_JUMBO:
26562fe4c1e9fc28254d357e9755cf4bd2138753c17buzbee        case OP_IPUT_BOOLEAN_JUMBO:
26662fe4c1e9fc28254d357e9755cf4bd2138753c17buzbee        case OP_IPUT_BYTE_JUMBO:
26762fe4c1e9fc28254d357e9755cf4bd2138753c17buzbee        case OP_IPUT_CHAR_JUMBO:
26862fe4c1e9fc28254d357e9755cf4bd2138753c17buzbee        case OP_IPUT_SHORT_JUMBO:
26971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
27071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                volatileOpc = OP_IPUT_VOLATILE_JUMBO;
27171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            goto rewrite_jumbo_inst_field;
27271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_IPUT_WIDE_JUMBO:
27371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            volatileOpc = OP_IPUT_WIDE_VOLATILE_JUMBO;
27471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            goto rewrite_jumbo_inst_field;
27571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_IPUT_OBJECT_JUMBO:
27671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
27771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                volatileOpc = OP_IPUT_OBJECT_VOLATILE_JUMBO;
27871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            /* fall through */
27971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenrewrite_jumbo_inst_field:
28071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (volatileOpc != OP_NOP)
28171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                rewriteJumboInstField(method, insns, volatileOpc);
28271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            break;
28371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden
28471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SGET:
28571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SGET_BOOLEAN:
28671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SGET_BYTE:
28771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SGET_CHAR:
28871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SGET_SHORT:
28971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
29071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                volatileOpc = OP_SGET_VOLATILE;
29171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            goto rewrite_static_field;
292139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden        case OP_SGET_WIDE:
293139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden            volatileOpc = OP_SGET_WIDE_VOLATILE;
294139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden            goto rewrite_static_field;
29571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SGET_OBJECT:
29671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
29771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                volatileOpc = OP_SGET_OBJECT_VOLATILE;
29871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            goto rewrite_static_field;
29971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SPUT:
30071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SPUT_BOOLEAN:
30171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SPUT_BYTE:
30271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SPUT_CHAR:
30371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SPUT_SHORT:
30471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
30571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                volatileOpc = OP_SPUT_VOLATILE;
30671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            goto rewrite_static_field;
307139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden        case OP_SPUT_WIDE:
308139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden            volatileOpc = OP_SPUT_WIDE_VOLATILE;
30971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            goto rewrite_static_field;
31071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SPUT_OBJECT:
31171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
31271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                volatileOpc = OP_SPUT_OBJECT_VOLATILE;
31371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            /* fall through */
314fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFaddenrewrite_static_field:
31571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (volatileOpc != OP_NOP)
31671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                rewriteStaticField(method, insns, volatileOpc);
31771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            break;
31871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden
31971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SGET_JUMBO:
32062fe4c1e9fc28254d357e9755cf4bd2138753c17buzbee        case OP_SGET_BOOLEAN_JUMBO:
32162fe4c1e9fc28254d357e9755cf4bd2138753c17buzbee        case OP_SGET_BYTE_JUMBO:
32262fe4c1e9fc28254d357e9755cf4bd2138753c17buzbee        case OP_SGET_CHAR_JUMBO:
32362fe4c1e9fc28254d357e9755cf4bd2138753c17buzbee        case OP_SGET_SHORT_JUMBO:
32471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
32571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                volatileOpc = OP_SGET_VOLATILE_JUMBO;
32671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            goto rewrite_jumbo_static_field;
32771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SGET_WIDE_JUMBO:
32871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            volatileOpc = OP_SGET_WIDE_VOLATILE_JUMBO;
32971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            goto rewrite_jumbo_static_field;
33071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SGET_OBJECT_JUMBO:
33171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
33271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                volatileOpc = OP_SGET_OBJECT_VOLATILE_JUMBO;
33371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            goto rewrite_jumbo_static_field;
33471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SPUT_JUMBO:
33562fe4c1e9fc28254d357e9755cf4bd2138753c17buzbee        case OP_SPUT_BOOLEAN_JUMBO:
33662fe4c1e9fc28254d357e9755cf4bd2138753c17buzbee        case OP_SPUT_BYTE_JUMBO:
33762fe4c1e9fc28254d357e9755cf4bd2138753c17buzbee        case OP_SPUT_CHAR_JUMBO:
33862fe4c1e9fc28254d357e9755cf4bd2138753c17buzbee        case OP_SPUT_SHORT_JUMBO:
33971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
34071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                volatileOpc = OP_SPUT_VOLATILE_JUMBO;
34171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            goto rewrite_jumbo_static_field;
34271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SPUT_WIDE_JUMBO:
34371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            volatileOpc = OP_SPUT_WIDE_VOLATILE_JUMBO;
34471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            goto rewrite_jumbo_static_field;
34571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_SPUT_OBJECT_JUMBO:
34671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (forSmp)
34771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                volatileOpc = OP_SPUT_OBJECT_VOLATILE_JUMBO;
34871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            /* fall through */
34971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenrewrite_jumbo_static_field:
35071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (volatileOpc != OP_NOP)
35171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                rewriteJumboStaticField(method, insns, volatileOpc);
3522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            break;
35365a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden
35465a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        case OP_INVOKE_DIRECT:
35571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_INVOKE_DIRECT_RANGE:
356d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden            if (!rewriteInvokeObjectInit(method, insns)) {
357d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                /* may want to try execute-inline, below */
35871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                matched = false;
35965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden            }
36065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden            break;
36171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_INVOKE_DIRECT_JUMBO:
36271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            rewriteJumboInvokeObjectInit(method, insns);
36371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            break;
36471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        case OP_RETURN_VOID:
36571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            if (needRetBar)
36671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                rewriteReturnVoid(method, insns);
36771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            break;
3682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        default:
36971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            matched = false;
370c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden            break;
371c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden        }
372c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden
373fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
37465a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden        /*
37565a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         * non-essential substitutions:
376d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden         *  invoke-{virtual,direct,static}[/range] --> execute-inline
37765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         *  invoke-{virtual,super}[/range] --> invoke-*-quick
37865a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden         */
37971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        if (!matched && !essentialOnly) {
38071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            switch (opc) {
381fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            case OP_INVOKE_VIRTUAL:
382d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL)) {
383d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                    rewriteVirtualInvoke(method, insns,
384d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                        OP_INVOKE_VIRTUAL_QUICK);
385d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                }
386fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                break;
387fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            case OP_INVOKE_VIRTUAL_RANGE:
388d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL)) {
389d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                    rewriteVirtualInvoke(method, insns,
390d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                        OP_INVOKE_VIRTUAL_QUICK_RANGE);
391d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                }
392fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                break;
393fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            case OP_INVOKE_SUPER:
394fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK);
395fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                break;
396fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            case OP_INVOKE_SUPER_RANGE:
397fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK_RANGE);
398fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                break;
399d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden            case OP_INVOKE_DIRECT:
400d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                rewriteExecuteInline(method, insns, METHOD_DIRECT);
401d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                break;
402d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden            case OP_INVOKE_DIRECT_RANGE:
403d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                rewriteExecuteInlineRange(method, insns, METHOD_DIRECT);
404d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                break;
405d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden            case OP_INVOKE_STATIC:
406d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                rewriteExecuteInline(method, insns, METHOD_STATIC);
407d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                break;
408d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden            case OP_INVOKE_STATIC_RANGE:
409d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                rewriteExecuteInlineRange(method, insns, METHOD_STATIC);
410d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden                break;
411fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            default:
412fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                /* nothing to do for this instruction */
413fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden                ;
414fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            }
4152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
4162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        assert(width > 0);
41871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        assert(width <= insnsSize);
41971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        assert(width == dexGetWidthFromInstruction(insns));
4202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        insns += width;
4222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        insnsSize -= width;
4232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
4242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(insnsSize == 0);
4262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
4272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
428fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden/*
42957fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden * Update a 16-bit code unit in "meth".  The way in which the DEX data was
43057fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden * loaded determines how we go about the write.
43171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden *
43271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * This will be operating on post-byte-swap DEX data, so values will
43371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * be in host order.
434fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden */
43557fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFaddenvoid dvmUpdateCodeUnit(const Method* meth, u2* ptr, u2 newVal)
436fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden{
43757fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    DvmDex* pDvmDex = meth->clazz->pDvmDex;
43857fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden
43957fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    if (!pDvmDex->isMappedReadOnly) {
44057fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        /* in-memory DEX (dexopt or byte[]), alter the output directly */
441fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        *ptr = newVal;
442fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    } else {
44357fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        /* memory-mapped file, toggle the page read/write status */
44457fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        dvmDexChangeDex2(pDvmDex, ptr, newVal);
445fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    }
446fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden}
4472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
44971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Update an instruction's opcode.
45071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden *
45171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * If "opcode" is an 8-bit op, we just replace that portion.  If it's a
45271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * 16-bit op, we convert the opcode from "packed" form (e.g. 0x0108) to
45371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * bytecode form (e.g. 0x08ff).
4543f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden */
4559a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornsteinstatic inline void updateOpcode(const Method* meth, u2* ptr, Opcode opcode)
4563f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden{
45771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    if (opcode >= 256) {
45871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        /* opcode low byte becomes high byte, low byte becomes 0xff */
45971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        assert((ptr[0] & 0xff) == 0xff);
46071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        dvmUpdateCodeUnit(meth, ptr, (u2) (opcode << 8) | 0x00ff);
46171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    } else {
46271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        /* 8-bit op, just replace the low byte */
46371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        assert((ptr[0] & 0xff) != 0xff);
46471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        dvmUpdateCodeUnit(meth, ptr, (ptr[0] & 0xff00) | (u2) opcode);
46571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    }
4663f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden}
4673f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
4683f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden/*
4692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * If "referrer" and "resClass" don't come from the same DEX file, and
4702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * the DEX we're working on is not destined for the bootstrap class path,
4712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * tweak the class loader so package-access checks work correctly.
4722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
4732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Only do this if we're doing pre-verification or optimization.
4742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
4752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void tweakLoader(ClassObject* referrer, ClassObject* resClass)
4762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
4772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!gDvm.optimizing)
4782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return;
4792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(referrer->classLoader == NULL);
4802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(resClass->classLoader == NULL);
4812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!gDvm.optimizingBootstrapClass) {
4832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* class loader for an array class comes from element type */
4842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (dvmIsArrayClass(resClass))
4852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass = resClass->elementClass;
4862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (referrer->pDvmDex != resClass->pDvmDex)
4872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass->classLoader = (Object*) 0xdead3333;
4882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
4892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
4902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
4922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Undo the effects of tweakLoader.
4932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
4942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void untweakLoader(ClassObject* referrer, ClassObject* resClass)
4952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
4962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!gDvm.optimizing || gDvm.optimizingBootstrapClass)
4972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return;
4982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
4992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (dvmIsArrayClass(resClass))
5002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = resClass->elementClass;
5012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resClass->classLoader = NULL;
5022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
5032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
5062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveClass for use with verification and
5072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * optimization.  Performs access checks on every resolve, and refuses
5082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * to acknowledge the existence of classes defined in more than one DEX
5092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * file.
5102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
5112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Exceptions caused by failures are cleared before returning.
5122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
5132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
5142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
5152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
5162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    VerifyError* pFailure)
5172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
5182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
5192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* resClass;
5202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
5222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Check the table first.  If not there, do the lookup by name.
5232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
5242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
5252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resClass == NULL) {
5262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
5272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (className[0] != '\0' && className[1] == '\0') {
5282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* primitive type */
5292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass = dvmFindPrimitiveClass(className[0]);
5302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else {
5312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass = dvmFindClassNoInit(className, referrer->classLoader);
5322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
5342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* not found, exception should be raised */
53560fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            LOGV("DexOpt: class %d (%s) not found",
5362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                classIdx,
5372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
5382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL) {
5392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                /* dig through the wrappers to find the original failure */
5402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                Object* excep = dvmGetException(dvmThreadSelf());
5412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                while (true) {
5422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    Object* cause = dvmGetExceptionCause(excep);
5432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    if (cause == NULL)
5442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                        break;
5452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    excep = cause;
5462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                }
5472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (strcmp(excep->clazz->descriptor,
5482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    "Ljava/lang/IncompatibleClassChangeError;") == 0)
5492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                {
5502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
5512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                } else {
5522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    *pFailure = VERIFY_ERROR_NO_CLASS;
5532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                }
5542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
5552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmClearOptException(dvmThreadSelf());
5562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
5572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
5582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
5602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
5612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
5622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
5632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
5642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* multiple definitions? */
5662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) {
56760fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGI("DexOpt: not resolving ambiguous class '%s'",
5682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resClass->descriptor);
5692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
5702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_NO_CLASS;
5712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
5722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
5732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* access allowed? */
5752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    tweakLoader(referrer, resClass);
5762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool allowed = dvmCheckClassAccess(referrer, resClass);
5772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    untweakLoader(referrer, resClass);
5782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!allowed) {
57960fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGW("DexOpt: resolve class illegal access: %s -> %s",
5802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            referrer->descriptor, resClass->descriptor);
5812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
5822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_ACCESS_CLASS;
5832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
5842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
5852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resClass;
5872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
5882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
5892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
5902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveInstField().
5912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
5922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
5932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
5942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenInstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
5952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    VerifyError* pFailure)
5962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
5972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
5982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    InstField* resField;
5992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx);
6012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resField == NULL) {
6022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const DexFieldId* pFieldId;
6032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassObject* resClass;
6042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);
6062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
6082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Find the field's class.
6092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
6102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
6112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
6122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //dvmClearOptException(dvmThreadSelf());
6132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert(!dvmCheckException(dvmThreadSelf()));
6142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
6152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
6162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
6172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resField = (InstField*)dvmFindFieldHier(resClass,
6192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
6202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
6212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resField == NULL) {
62260fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            LOGD("DexOpt: couldn't find field %s.%s",
6232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resClass->descriptor,
6242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
6252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
6262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_NO_FIELD;
6272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
6282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
629a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro        if (dvmIsStaticField(resField)) {
63060fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            LOGD("DexOpt: wanted instance, got static for field %s.%s",
6312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resClass->descriptor,
6322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
6332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
6342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_CLASS_CHANGE;
6352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
6362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
6372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
6392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
6402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
6412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmDexSetResolvedField(pDvmDex, ifieldIdx, (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) {
64960fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGI("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 * Alternate version of dvmResolveStaticField().
6622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
6632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Does not force initialization of the resolved field's class.
6642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
6652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
6662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
6672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenStaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
6682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    VerifyError* pFailure)
6692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
6702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
6712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    StaticField* resField;
6722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx);
6742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resField == NULL) {
6752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const DexFieldId* pFieldId;
6762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassObject* resClass;
6772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);
6792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
6802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
6812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Find the field's class.
6822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
6832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
6842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
6852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //dvmClearOptException(dvmThreadSelf());
6862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert(!dvmCheckException(dvmThreadSelf()));
6872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
6882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
6892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
6902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
69171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        const char* fieldName =
69271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx);
69371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden
69471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        resField = (StaticField*)dvmFindFieldHier(resClass, fieldName,
6952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
6962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resField == NULL) {
69760fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            LOGD("DexOpt: couldn't find static field %s.%s",
69871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                resClass->descriptor, fieldName);
6992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
7002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_NO_FIELD;
7012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
7022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
703a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro        if (!dvmIsStaticField(resField)) {
70460fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            LOGD("DexOpt: wanted static, got instance for field %s.%s",
70571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden                resClass->descriptor, fieldName);
7062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
7072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_CLASS_CHANGE;
7082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
7092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
7102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
7122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
7132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         *
7142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * We can only do this if we're in "dexopt", because the presence
7152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * of a valid value in the resolution table implies that the class
7162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * containing the static field has been initialized.
7172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
7182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (gDvm.optimizing)
7192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
7202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
7212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* access allowed? */
723a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro    tweakLoader(referrer, resField->clazz);
7242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
725a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro    untweakLoader(referrer, resField->clazz);
7262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!allowed) {
72760fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGI("DexOpt: access denied from %s to field %s.%s",
728a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro            referrer->descriptor, resField->clazz->descriptor,
729a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro            resField->name);
7302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
7312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_ACCESS_FIELD;
7322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
7332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
7342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resField;
7362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
7372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
7392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
74071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Rewrite an iget/iput instruction if appropriate.  These all have the form:
7412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *   op vA, vB, field@CCCC
7422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
7432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Where vA holds the value, vB holds the object reference, and CCCC is
744fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * the field reference constant pool offset.  For a non-volatile field,
745fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * we want to replace the opcode with "quickOpc" and replace CCCC with
746fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * the byte offset from the start of the object.  For a volatile field,
747fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * we just want to replace the opcode with "volatileOpc".
7482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
749139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden * If "volatileOpc" is OP_NOP we don't check to see if it's a volatile
750139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden * field.  If "quickOpc" is OP_NOP, and this is a non-volatile field,
751139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden * we don't do anything.
752fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden *
753fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * "method" is the referring method.
7542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
75571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteInstField(Method* method, u2* insns, Opcode quickOpc,
7569a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein    Opcode volatileOpc)
7572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
7582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
7592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 fieldIdx = insns[1];
760fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    InstField* instField;
7612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
762fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    instField = dvmOptResolveInstField(clazz, fieldIdx, NULL);
763fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    if (instField == NULL) {
764fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        LOGI("DexOpt: unable to optimize instance field ref "
765fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden             "0x%04x at 0x%02x in %s.%s\n",
7662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            fieldIdx, (int) (insns - method->insns), clazz->descriptor,
7672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            method->name);
76871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        return;
769fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    }
770fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
771a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro    if (volatileOpc != OP_NOP && dvmIsVolatileField(instField)) {
7729a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein        updateOpcode(method, insns, volatileOpc);
77360fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGV("DexOpt: rewrote ifield access %s.%s --> volatile",
774a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro            instField->clazz->descriptor, instField->name);
77571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    } else if (quickOpc != OP_NOP && instField->byteOffset < 65536) {
7769a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein        updateOpcode(method, insns, quickOpc);
77757fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden        dvmUpdateCodeUnit(method, insns+1, (u2) instField->byteOffset);
77860fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGV("DexOpt: rewrote ifield access %s.%s --> %d",
779a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro            instField->clazz->descriptor, instField->name,
780fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            instField->byteOffset);
781fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    } else {
78260fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGV("DexOpt: no rewrite of ifield access %s.%s",
783a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro            instField->clazz->descriptor, instField->name);
784fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    }
785fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
78671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    return;
787fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden}
788fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
789fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden/*
79071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Rewrite a jumbo instance field access instruction if appropriate.  If
79171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * the target field is volatile, we replace the opcode with "volatileOpc".
792fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden *
79371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * "method" is the referring method.
79471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden */
79571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteJumboInstField(Method* method, u2* insns, Opcode volatileOpc)
79671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden{
79771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    ClassObject* clazz = method->clazz;
79871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    u4 fieldIdx = insns[1] | (u4) insns[2] << 16;
79971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    InstField* instField;
80071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden
80171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    assert(volatileOpc != OP_NOP);
80271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden
80371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    instField = dvmOptResolveInstField(clazz, fieldIdx, NULL);
80471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    if (instField == NULL) {
80571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        LOGI("DexOpt: unable to optimize instance field ref "
80671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden             "0x%04x at 0x%02x in %s.%s\n",
80771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            fieldIdx, (int) (insns - method->insns), clazz->descriptor,
80871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            method->name);
80971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        return;
81071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    }
81171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden
812a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro    if (dvmIsVolatileField(instField)) {
81371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        updateOpcode(method, insns, volatileOpc);
81460fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGV("DexOpt: rewrote jumbo ifield access %s.%s --> volatile",
815a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro            instField->clazz->descriptor, instField->name);
81671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    } else {
81760fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGV("DexOpt: no rewrite of jumbo ifield access %s.%s",
818a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro            instField->clazz->descriptor, instField->name);
81971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    }
82071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden}
82171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden
82271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden/*
82371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Rewrite a static [jumbo] field access instruction if appropriate.  If
82471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * the target field is volatile, we replace the opcode with "volatileOpc".
825fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden *
826fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * "method" is the referring method.
827fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden */
82871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteStaticField0(Method* method, u2* insns, Opcode volatileOpc,
82971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    u4 fieldIdx)
830fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden{
831fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    ClassObject* clazz = method->clazz;
832fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    StaticField* staticField;
833fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
834139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden    assert(volatileOpc != OP_NOP);
835139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden
836fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    staticField = dvmOptResolveStaticField(clazz, fieldIdx, NULL);
837fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    if (staticField == NULL) {
838fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden        LOGI("DexOpt: unable to optimize static field ref "
839fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden             "0x%04x at 0x%02x in %s.%s\n",
840fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            fieldIdx, (int) (insns - method->insns), clazz->descriptor,
841fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden            method->name);
84271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        return;
843fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden    }
844fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden
845a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro    if (dvmIsVolatileField(staticField)) {
8469a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein        updateOpcode(method, insns, volatileOpc);
84760fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGV("DexOpt: rewrote sfield access %s.%s --> volatile",
848a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro            staticField->clazz->descriptor, staticField->name);
8492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
85071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden}
8512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
85271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteStaticField(Method* method, u2* insns, Opcode volatileOpc)
85371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden{
85471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    u2 fieldIdx = insns[1];
85571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    rewriteStaticField0(method, insns, volatileOpc, fieldIdx);
85671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden}
85771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteJumboStaticField(Method* method, u2* insns,
85871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    Opcode volatileOpc)
85971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden{
86071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    u4 fieldIdx = insns[1] | (u4) insns[2] << 16;
86171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    rewriteStaticField0(method, insns, volatileOpc, fieldIdx);
8622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
8632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
86471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden
8652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
8662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveMethod().
8672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
8682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Doesn't throw exceptions, and checks access on every lookup.
8692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
8702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
8712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
8722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenMethod* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
8732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    MethodType methodType, VerifyError* pFailure)
8742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
8752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
8762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* resMethod;
8772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert(methodType == METHOD_DIRECT ||
8792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           methodType == METHOD_VIRTUAL ||
8802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           methodType == METHOD_STATIC);
8812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
88260fc806b679a3655c228b4093058c59941a49cfeDan Bornstein    LOGVV("--- resolving method %u (referrer=%s)", methodIdx,
8832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        referrer->descriptor);
8842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
8862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resMethod == NULL) {
8872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const DexMethodId* pMethodId;
8882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassObject* resClass;
8892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
8912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
8922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure);
8932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
8942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /*
8952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * Can't find the class that the method is a part of, or don't
8962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             * have permission to access the class.
8972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden             */
89860fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            LOGV("DexOpt: can't find called method's class (?.%s)",
8992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
9002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
9012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
9022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
9032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (dvmIsInterfaceClass(resClass)) {
9042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* method is part of an interface; this is wrong method for that */
90560fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            LOGW("DexOpt: method is in an interface");
9062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
9072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_GENERIC;
9082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
9092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
9102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
9122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * We need to chase up the class hierarchy to find methods defined
9132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * in super-classes.  (We only want to check the current class
9142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * if we're looking for a constructor.)
9152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
9162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        DexProto proto;
9172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
9182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (methodType == METHOD_DIRECT) {
9202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resMethod = dvmFindDirectMethod(resClass,
9212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
9222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else {
9232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* METHOD_STATIC or METHOD_VIRTUAL */
9242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            resMethod = dvmFindMethodHier(resClass,
9252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
9262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
9272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resMethod == NULL) {
92960fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            LOGV("DexOpt: couldn't find method '%s'",
9302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
9312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
9322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_NO_METHOD;
9332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
9342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
9352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (methodType == METHOD_STATIC) {
9362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (!dvmIsStaticMethod(resMethod)) {
93760fc806b679a3655c228b4093058c59941a49cfeDan Bornstein                LOGD("DexOpt: wanted static, got instance for method %s.%s",
9382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    resClass->descriptor, resMethod->name);
9392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (pFailure != NULL)
9402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
9412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                return NULL;
9422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
9432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        } else if (methodType == METHOD_VIRTUAL) {
9442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (dvmIsStaticMethod(resMethod)) {
94560fc806b679a3655c228b4093058c59941a49cfeDan Bornstein                LOGD("DexOpt: wanted instance, got static for method %s.%s",
9462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    resClass->descriptor, resMethod->name);
9472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                if (pFailure != NULL)
9482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                    *pFailure = VERIFY_ERROR_CLASS_CHANGE;
9492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                return NULL;
9502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            }
9512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
9522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* see if this is a pure-abstract method */
9542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
95560fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            LOGW("DexOpt: pure-abstract method '%s' in %s",
9562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx),
9572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resClass->descriptor);
9582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            if (pFailure != NULL)
9592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                *pFailure = VERIFY_ERROR_GENERIC;
9602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
9612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
9622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
9642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
9652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         *
9662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * We can only do this for static methods if we're not in "dexopt",
9672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * because the presence of a valid value in the resolution table
9682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * implies that the class containing the static field has been
9692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * initialized.
9702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
9712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (methodType != METHOD_STATIC || gDvm.optimizing)
9722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
9732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
9742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
97560fc806b679a3655c228b4093058c59941a49cfeDan Bornstein    LOGVV("--- found method %d (%s.%s)",
9762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        methodIdx, resMethod->clazz->descriptor, resMethod->name);
9772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* access allowed? */
9792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    tweakLoader(referrer, resMethod->clazz);
9802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    bool allowed = dvmCheckMethodAccess(referrer, resMethod);
9812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    untweakLoader(referrer, resMethod->clazz);
9822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (!allowed) {
9832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        IF_LOGI() {
9842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
98560fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            LOGI("DexOpt: illegal method access (call %s.%s %s from %s)",
9862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resMethod->clazz->descriptor, resMethod->name, desc,
9872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                referrer->descriptor);
9882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            free(desc);
9892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
9902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (pFailure != NULL)
9912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            *pFailure = VERIFY_ERROR_ACCESS_METHOD;
9922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return NULL;
9932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
9942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resMethod;
9962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
9972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
9982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
9992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Rewrite invoke-virtual, invoke-virtual/range, invoke-super, and
100071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * invoke-super/range if appropriate.  These all have the form:
10012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *   op vAA, meth@BBBB, reg stuff @CCCC
10022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
10032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * We want to replace the method constant pool index BBBB with the
10042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * vtable index.
10052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
100671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteVirtualInvoke(Method* method, u2* insns, Opcode newOpc)
10072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
10082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
10092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* baseMethod;
10102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 methodIdx = insns[1];
10112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL, NULL);
10132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (baseMethod == NULL) {
101460fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGD("DexOpt: unable to optimize virt call 0x%04x at 0x%02x in %s.%s",
10152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            methodIdx,
10162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            (int) (insns - method->insns), clazz->descriptor,
10172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            method->name);
101871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        return;
10192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    assert((insns[0] & 0xff) == OP_INVOKE_VIRTUAL ||
10222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE ||
10232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           (insns[0] & 0xff) == OP_INVOKE_SUPER ||
10242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden           (insns[0] & 0xff) == OP_INVOKE_SUPER_RANGE);
10252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /*
10272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * Note: Method->methodIndex is a u2 and is range checked during the
10282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     * initial load.
10292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden     */
10309a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein    updateOpcode(method, insns, newOpc);
103157fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden    dvmUpdateCodeUnit(method, insns+1, baseMethod->methodIndex);
10322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
103360fc806b679a3655c228b4093058c59941a49cfeDan Bornstein    //LOGI("DexOpt: rewrote call to %s.%s --> %s.%s",
10342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    //    method->clazz->descriptor, method->name,
10352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    //    baseMethod->clazz->descriptor, baseMethod->name);
10362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
103771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    return;
10382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
10392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
104171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Rewrite invoke-direct[/range] if the target is Object.<init>.
10422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
10436af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * This is useful as an optimization, because otherwise every object
10446af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * instantiation will cause us to call a method that does nothing.
10456af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * It also allows us to inexpensively mark objects as finalizable at the
10466af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * correct time.
10472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
10486af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * TODO: verifier should ensure Object.<init> contains only return-void,
10496af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * and issue a warning if not.
10502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
10516af2ddd107842c3737c04c37343cac9be17f4209Andy McFaddenstatic bool rewriteInvokeObjectInit(Method* method, u2* insns)
10522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
10532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
10542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* calledMethod;
10552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 methodIdx = insns[1];
10562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL);
10582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (calledMethod == NULL) {
105960fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s",
10606af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden            methodIdx, (int) (insns - method->insns),
10616af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden            clazz->descriptor, method->name);
10622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
10632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (calledMethod->clazz == gDvm.classJavaLangObject &&
10662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0)
10672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    {
10682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
10690346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden         * Replace the instruction.  If the debugger is attached, the
10700346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden         * interpreter will forward execution to the invoke-direct/range
10710346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden         * handler.  If this was an invoke-direct/range instruction we can
10720346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden         * just replace the opcode, but if it was an invoke-direct we
10730346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden         * have to set the argument count (high 8 bits of first code unit)
10740346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden         * to 1.
10752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
10760346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden        u1 origOp = insns[0] & 0xff;
10770346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden        if (origOp == OP_INVOKE_DIRECT) {
107857fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden            dvmUpdateCodeUnit(method, insns,
107957fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden                OP_INVOKE_OBJECT_INIT_RANGE | 0x100);
10800346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden        } else {
10810346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden            assert(origOp == OP_INVOKE_DIRECT_RANGE);
10820346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden            assert((insns[0] >> 8) == 1);
10830346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden            updateOpcode(method, insns, OP_INVOKE_OBJECT_INIT_RANGE);
10840346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden        }
10852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
108660fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGVV("DexOpt: replaced Object.<init> in %s.%s",
10876af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden            method->clazz->descriptor, method->name);
10882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
10892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return true;
10912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
10922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
10932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
109471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Rewrite invoke-direct/jumbo if the target is Object.<init>.
109571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden */
109671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic bool rewriteJumboInvokeObjectInit(Method* method, u2* insns)
109771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden{
109871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    ClassObject* clazz = method->clazz;
109971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    Method* calledMethod;
110071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    u4 methodIdx = insns[1] | (u4) insns[2] << 16;
110171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden
110271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL);
110371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    if (calledMethod == NULL) {
110460fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s",
110571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            methodIdx, (int) (insns - method->insns),
110671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            clazz->descriptor, method->name);
110771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        return false;
110871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    }
110971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden
111071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    if (calledMethod->clazz == gDvm.classJavaLangObject &&
111171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0)
111271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    {
111371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        assert(insns[0] == ((u2) (OP_INVOKE_DIRECT_JUMBO << 8) | 0xff));
111471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden        updateOpcode(method, insns, OP_INVOKE_OBJECT_INIT_JUMBO);
111571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden
111660fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGVV("DexOpt: replaced jumbo Object.<init> in %s.%s",
111771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden            method->clazz->descriptor, method->name);
111871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    }
111971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden
112071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden    return true;
112171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden}
112271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden
112371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden/*
11242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Resolve an interface method reference.
11252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
11262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * No method access check here -- interface methods are always public.
11272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
11282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns NULL if the method was not found.  Does not throw an exception.
11292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
11302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenMethod* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx)
11312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
11322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    DvmDex* pDvmDex = referrer->pDvmDex;
11332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* resMethod;
11342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
113560fc806b679a3655c228b4093058c59941a49cfeDan Bornstein    LOGVV("--- resolving interface method %d (referrer=%s)",
11362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        methodIdx, referrer->descriptor);
11372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
11392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (resMethod == NULL) {
11402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const DexMethodId* pMethodId;
11412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        ClassObject* resClass;
11422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
11442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, NULL);
11462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resClass == NULL) {
11472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* can't find the class that the method is a part of */
11482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dvmClearOptException(dvmThreadSelf());
11492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
11502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
11512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!dvmIsInterfaceClass(resClass)) {
11522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            /* whoops */
115360fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            LOGI("Interface method not part of interface class");
11542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
11552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
11562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        const char* methodName =
11582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
11592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        DexProto proto;
11602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
11612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
116260fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGVV("+++ looking for '%s' '%s' in resClass='%s'",
11632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            methodName, methodSig, resClass->descriptor);
1164da7334a4ba1bbffe40d3838f463565af46e716d9Andy McFadden        resMethod = dvmFindInterfaceMethodHier(resClass, methodName, &proto);
11652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (resMethod == NULL) {
1166da7334a4ba1bbffe40d3838f463565af46e716d9Andy McFadden            return NULL;
11672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
11682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /* we're expecting this to be abstract */
11702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (!dvmIsAbstractMethod(resMethod)) {
11712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
117260fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            LOGW("Found non-abstract interface method %s.%s %s",
11732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                resMethod->clazz->descriptor, resMethod->name, desc);
11742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            free(desc);
11752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return NULL;
11762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
11772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
11792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         * Add it to the resolved table so we're faster on the next lookup.
11802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden         */
11812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
11822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
11832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
118460fc806b679a3655c228b4093058c59941a49cfeDan Bornstein    LOGVV("--- found interface method %d (%s.%s)",
11852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        methodIdx, resMethod->clazz->descriptor, resMethod->name);
11862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    /* interface methods are always public; no need to check access */
11882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return resMethod;
11902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
11912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
11922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
119371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Replace invoke-virtual, invoke-direct, or invoke-static with an
119471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * execute-inline operation if appropriate.
11952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
11962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" if we replace it.
11972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
11982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInline(Method* method, u2* insns,
1199cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    MethodType methodType)
12002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
1201cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    const InlineSub* inlineSubs = gDvm.inlineSubs;
12022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
12032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* calledMethod;
12042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 methodIdx = insns[1];
12052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    //return false;
12072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
12092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (calledMethod == NULL) {
121060fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGV("+++ DexOpt inline: can't find %d", methodIdx);
12112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
12122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    while (inlineSubs->method != NULL) {
12152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        /*
12162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (extra) {
121760fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            LOGI("comparing %p vs %p %s.%s %s",
12182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                inlineSubs->method, calledMethod,
12192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                inlineSubs->method->clazz->descriptor,
12202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                inlineSubs->method->name,
12212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                inlineSubs->method->signature);
12222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
12232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        */
12242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (inlineSubs->method == calledMethod) {
12252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert((insns[0] & 0xff) == OP_INVOKE_DIRECT ||
12262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                   (insns[0] & 0xff) == OP_INVOKE_STATIC ||
12272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                   (insns[0] & 0xff) == OP_INVOKE_VIRTUAL);
12289a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein            updateOpcode(method, insns, OP_EXECUTE_INLINE);
122957fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden            dvmUpdateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx);
12302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
123160fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            //LOGI("DexOpt: execute-inline %s.%s --> %s.%s",
12322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //    method->clazz->descriptor, method->name,
12332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //    calledMethod->clazz->descriptor, calledMethod->name);
12342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return true;
12352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
12362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        inlineSubs++;
12382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return false;
12412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
12422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/*
124471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Replace invoke-virtual/range, invoke-direct/range, or invoke-static/range
124571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * with an execute-inline operation if appropriate.
12462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *
12472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" if we replace it.
12482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */
12492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInlineRange(Method* method, u2* insns,
1250cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    MethodType methodType)
12512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{
1252cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden    const InlineSub* inlineSubs = gDvm.inlineSubs;
12532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    ClassObject* clazz = method->clazz;
12542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    Method* calledMethod;
12552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    u2 methodIdx = insns[1];
12562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
12582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    if (calledMethod == NULL) {
125960fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGV("+++ DexOpt inline/range: can't find %d", methodIdx);
12602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        return false;
12612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    while (inlineSubs->method != NULL) {
12642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        if (inlineSubs->method == calledMethod) {
12652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            assert((insns[0] & 0xff) == OP_INVOKE_DIRECT_RANGE ||
12662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                   (insns[0] & 0xff) == OP_INVOKE_STATIC_RANGE ||
12672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden                   (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE);
12689a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein            updateOpcode(method, insns, OP_EXECUTE_INLINE_RANGE);
126957fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden            dvmUpdateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx);
12702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
127160fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            //LOGI("DexOpt: execute-inline/range %s.%s --> %s.%s",
12722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //    method->clazz->descriptor, method->name,
12732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            //    calledMethod->clazz->descriptor, calledMethod->name);
12742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden            return true;
12752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        }
12762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden        inlineSubs++;
12782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    }
12792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden
12802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden    return false;
12812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden}
12823f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
12833f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden/*
12843f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * Returns "true" if the return-void instructions in this method should
12853f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * be converted to return-void-barrier.
12863f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden *
12873f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * This is needed to satisfy a Java Memory Model requirement regarding
12883f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * the construction of objects with final fields.  (This does not apply
12893f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * to <clinit> or static fields, since appropriate barriers are guaranteed
12903f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * by the class initialization process.)
12913f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden */
12923f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFaddenstatic bool needsReturnBarrier(Method* method)
12933f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden{
12943f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    if (!gDvm.dexOptForSmp)
12953f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden        return false;
12963f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    if (strcmp(method->name, "<init>") != 0)
12973f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden        return false;
12983f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
12993f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    /*
1300ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     * Check to see if the class is finalizable.  The loader sets a flag
1301ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     * if the class or one of its superclasses overrides finalize().
13023f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     */
13033f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    const ClassObject* clazz = method->clazz;
1304ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden    if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE))
1305ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden        return true;
13063f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
13073f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    /*
1308ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     * Check to see if the class has any final fields.  If not, we don't
1309ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     * need to generate a barrier instruction.
1310ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     *
13113f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     * In theory, we only need to do this if the method actually modifies
13123f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     * a final field.  In practice, non-constructor methods are allowed
1313ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     * to modify final fields, and there are 3rd-party tools that rely on
1314ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden     * this behavior.  (The compiler does not allow it, but the VM does.)
13153f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     *
13163f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     * If we alter the verifier to restrict final-field updates to
13173f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     * constructors, we can tighten this up as well.
13183f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden     */
1319ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden    int idx = clazz->ifieldCount;
1320ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden    while (--idx >= 0) {
1321a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro        if (dvmIsFinalField(&clazz->ifields[idx]))
1322ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden            return true;
1323ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden    }
13243f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
1325ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden    return false;
13263f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden}
13273f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden
13283f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden/*
13293f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * Convert a return-void to a return-void-barrier.
13303f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden */
13313f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFaddenstatic void rewriteReturnVoid(Method* method, u2* insns)
13323f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden{
13333f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden    assert((insns[0] & 0xff) == OP_RETURN_VOID);
13349a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein    updateOpcode(method, insns, OP_RETURN_VOID_BARRIER);
13353f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden}
1336