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