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