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