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); 86fbbcada543302785432e491a3e6c943d1e625eb7You Kim free(table); 8765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden return false; 882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 8965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden 9065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden table[tableIndex].method = method; 9165a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden table[tableIndex].inlineIdx = i; 9265a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden tableIndex++; 932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* mark end of table */ 962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden table[tableIndex].method = NULL; 972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9865a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden gDvm.inlineSubs = table; 9965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden return true; 1002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 1012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 103cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * Release inline sub data structure. 1042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 1051e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid dvmFreeInlineSubsTable() 1062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 10765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden free(gDvm.inlineSubs); 10865a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden gDvm.inlineSubs = NULL; 1092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 1102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 111cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden 1122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 1132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Optimize the specified class. 114fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * 115fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * If "essentialOnly" is true, we only do essential optimizations. For 116fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * example, accesses to volatile 64-bit fields must be replaced with 117fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * "-wide-volatile" instructions or the program could behave incorrectly. 118fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * (Skipping non-essential optimizations makes us a little bit faster, and 119fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * more importantly avoids dirtying DEX pages.) 1202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 121fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFaddenvoid dvmOptimizeClass(ClassObject* clazz, bool essentialOnly) 1222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 1232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden int i; 1242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden for (i = 0; i < clazz->directMethodCount; i++) { 126fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden optimizeMethod(&clazz->directMethods[i], essentialOnly); 1272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 1282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden for (i = 0; i < clazz->virtualMethodCount; i++) { 129fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden optimizeMethod(&clazz->virtualMethods[i], essentialOnly); 1302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 1312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 1322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 1342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Optimize instructions in a method. 1352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 136228a6b01918304f2cd1213c722e028a6e25252bbAndy McFadden * This does a single pass through the code, examining each instruction. 137228a6b01918304f2cd1213c722e028a6e25252bbAndy McFadden * 138fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * This is not expected to fail if the class was successfully verified. 13971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * The only significant failure modes on unverified code occur when an 14071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * "essential" update fails, but we can't generally identify those: if we 14171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * can't look up a field, we can't know if the field access was supposed 14271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * to be handled as volatile. 143fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * 144fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * Instead, we give it our best effort, and hope for the best. For 100% 145fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * reliability, only optimize a class after verification succeeds. 1462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 147fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFaddenstatic void optimizeMethod(Method* method, bool essentialOnly) 1482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 14971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden bool needRetBar, forSmp; 1502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden u4 insnsSize; 1512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden u2* insns; 1522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (dvmIsNativeMethod(method) || dvmIsAbstractMethod(method)) 154fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden return; 1552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 15671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden forSmp = gDvm.dexOptForSmp; 15771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden needRetBar = needsReturnBarrier(method); 1583f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden 1592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden insns = (u2*) method->insns; 1602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert(insns != NULL); 1612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden insnsSize = dvmGetMethodInsnsSize(method); 1622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden while (insnsSize > 0) { 16471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden Opcode opc, quickOpc, volatileOpc; 16571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden size_t width; 16671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden bool matched = true; 16771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden 16871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden opc = dexOpcodeFromCodeUnit(*insns); 16971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden width = dexGetWidthFromInstruction(insns); 17071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden volatileOpc = OP_NOP; 1712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 17271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden /* 17371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Each instruction may have: 17471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * - "volatile" replacement 17571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * - may be essential or essential-on-SMP 17671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * - correctness replacement 17771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * - may be essential or essential-on-SMP 17871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * - performance replacement 17971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * - always non-essential 18071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * 18171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Replacements are considered in the order shown, and the first 18271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * match is applied. For example, iget-wide will convert to 18371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * iget-wide-volatile rather than iget-wide-quick if the target 18471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * field is volatile. 18571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden */ 1862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 18765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden /* 18865a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden * essential substitutions: 189ab35b50311951feea3782151dd5422ee944685c2Elliott Hughes * {iget,iput,sget,sput}-wide --> {op}-wide-volatile 190ab35b50311951feea3782151dd5422ee944685c2Elliott Hughes * invoke-direct[/range] --> invoke-object-init/range 19165a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden * 19265a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden * essential-on-SMP substitutions: 193ab35b50311951feea3782151dd5422ee944685c2Elliott Hughes * {iget,iput,sget,sput}-* --> {op}-volatile 19471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * return-void --> return-void-barrier 19565a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden * 19665a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden * non-essential substitutions: 19771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * {iget,iput}-* --> {op}-quick 19865a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden * 19965a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden * TODO: might be time to merge this with the other two switches 20065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden */ 20171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden switch (opc) { 2022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IGET: 2032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IGET_BOOLEAN: 2042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IGET_BYTE: 2052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IGET_CHAR: 2062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IGET_SHORT: 207fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden quickOpc = OP_IGET_QUICK; 20871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden if (forSmp) 209139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden volatileOpc = OP_IGET_VOLATILE; 210fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden goto rewrite_inst_field; 2112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IGET_WIDE: 212fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden quickOpc = OP_IGET_WIDE_QUICK; 213fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden volatileOpc = OP_IGET_WIDE_VOLATILE; 214fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden goto rewrite_inst_field; 2152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IGET_OBJECT: 216fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden quickOpc = OP_IGET_OBJECT_QUICK; 21771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden if (forSmp) 218139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden volatileOpc = OP_IGET_OBJECT_VOLATILE; 219fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden goto rewrite_inst_field; 2202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IPUT: 2212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IPUT_BOOLEAN: 2222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IPUT_BYTE: 2232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IPUT_CHAR: 2242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IPUT_SHORT: 225fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden quickOpc = OP_IPUT_QUICK; 22671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden if (forSmp) 227139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden volatileOpc = OP_IPUT_VOLATILE; 228fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden goto rewrite_inst_field; 2292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IPUT_WIDE: 230fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden quickOpc = OP_IPUT_WIDE_QUICK; 231fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden volatileOpc = OP_IPUT_WIDE_VOLATILE; 232fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden goto rewrite_inst_field; 2332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IPUT_OBJECT: 234fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden quickOpc = OP_IPUT_OBJECT_QUICK; 23571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden if (forSmp) 236139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden volatileOpc = OP_IPUT_OBJECT_VOLATILE; 23771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden /* fall through */ 238fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFaddenrewrite_inst_field: 239fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden if (essentialOnly) 24071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden quickOpc = OP_NOP; /* if essential-only, no "-quick" sub */ 241139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden if (quickOpc != OP_NOP || volatileOpc != OP_NOP) 242139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden rewriteInstField(method, insns, quickOpc, volatileOpc); 2432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden break; 2442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 24571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden case OP_SGET: 24671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden case OP_SGET_BOOLEAN: 24771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden case OP_SGET_BYTE: 24871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden case OP_SGET_CHAR: 24971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden case OP_SGET_SHORT: 25071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden if (forSmp) 25171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden volatileOpc = OP_SGET_VOLATILE; 25271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden goto rewrite_static_field; 253139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden case OP_SGET_WIDE: 254139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden volatileOpc = OP_SGET_WIDE_VOLATILE; 255139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden goto rewrite_static_field; 25671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden case OP_SGET_OBJECT: 25771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden if (forSmp) 25871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden volatileOpc = OP_SGET_OBJECT_VOLATILE; 25971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden goto rewrite_static_field; 26071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden case OP_SPUT: 26171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden case OP_SPUT_BOOLEAN: 26271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden case OP_SPUT_BYTE: 26371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden case OP_SPUT_CHAR: 26471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden case OP_SPUT_SHORT: 26571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden if (forSmp) 26671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden volatileOpc = OP_SPUT_VOLATILE; 26771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden goto rewrite_static_field; 268139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden case OP_SPUT_WIDE: 269139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden volatileOpc = OP_SPUT_WIDE_VOLATILE; 27071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden goto rewrite_static_field; 27171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden case OP_SPUT_OBJECT: 27271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden if (forSmp) 27371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden volatileOpc = OP_SPUT_OBJECT_VOLATILE; 27471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden /* fall through */ 275fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFaddenrewrite_static_field: 27671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden if (volatileOpc != OP_NOP) 27771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden rewriteStaticField(method, insns, volatileOpc); 27871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden break; 27971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden 28065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden case OP_INVOKE_DIRECT: 28171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden case OP_INVOKE_DIRECT_RANGE: 282d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden if (!rewriteInvokeObjectInit(method, insns)) { 283d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden /* may want to try execute-inline, below */ 28471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden matched = false; 28565a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden } 28665a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden break; 28771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden case OP_RETURN_VOID: 28871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden if (needRetBar) 28971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden rewriteReturnVoid(method, insns); 29071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden break; 2912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden default: 29271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden matched = false; 293c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden break; 294c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden } 295c58b9ef90319c4edad93300151c088434092e9e0Andy McFadden 296fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden 29765a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden /* 29865a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden * non-essential substitutions: 299d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden * invoke-{virtual,direct,static}[/range] --> execute-inline 30065a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden * invoke-{virtual,super}[/range] --> invoke-*-quick 30165a54dc66d2c7b6e16fc24a6ce66e50483620745Andy McFadden */ 30271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden if (!matched && !essentialOnly) { 30371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden switch (opc) { 304fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden case OP_INVOKE_VIRTUAL: 305d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL)) { 306d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden rewriteVirtualInvoke(method, insns, 307d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden OP_INVOKE_VIRTUAL_QUICK); 308d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden } 309fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden break; 310fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden case OP_INVOKE_VIRTUAL_RANGE: 311d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL)) { 312d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden rewriteVirtualInvoke(method, insns, 313d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden OP_INVOKE_VIRTUAL_QUICK_RANGE); 314d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden } 315fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden break; 316fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden case OP_INVOKE_SUPER: 317fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK); 318fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden break; 319fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden case OP_INVOKE_SUPER_RANGE: 320fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK_RANGE); 321fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden break; 322d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden case OP_INVOKE_DIRECT: 323d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden rewriteExecuteInline(method, insns, METHOD_DIRECT); 324d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden break; 325d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden case OP_INVOKE_DIRECT_RANGE: 326d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden rewriteExecuteInlineRange(method, insns, METHOD_DIRECT); 327d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden break; 328d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden case OP_INVOKE_STATIC: 329d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden rewriteExecuteInline(method, insns, METHOD_STATIC); 330d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden break; 331d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden case OP_INVOKE_STATIC_RANGE: 332d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden rewriteExecuteInlineRange(method, insns, METHOD_STATIC); 333d18fcbcee7115ff99673222650fda0f7e982c60aAndy McFadden break; 334fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden default: 335fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden /* nothing to do for this instruction */ 336fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden ; 337fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden } 3382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 3392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 3402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert(width > 0); 34171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden assert(width <= insnsSize); 34271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden assert(width == dexGetWidthFromInstruction(insns)); 3432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 3442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden insns += width; 3452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden insnsSize -= width; 3462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 3472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 3482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert(insnsSize == 0); 3492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 3502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 351fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden/* 35257fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden * Update a 16-bit code unit in "meth". The way in which the DEX data was 35357fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden * loaded determines how we go about the write. 35471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * 35571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * This will be operating on post-byte-swap DEX data, so values will 35671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * be in host order. 357fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden */ 35857fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFaddenvoid dvmUpdateCodeUnit(const Method* meth, u2* ptr, u2 newVal) 359fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden{ 36057fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden DvmDex* pDvmDex = meth->clazz->pDvmDex; 36157fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden 36257fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden if (!pDvmDex->isMappedReadOnly) { 36357fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden /* in-memory DEX (dexopt or byte[]), alter the output directly */ 364fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden *ptr = newVal; 365fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden } else { 36657fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden /* memory-mapped file, toggle the page read/write status */ 36757fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden dvmDexChangeDex2(pDvmDex, ptr, newVal); 368fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden } 369fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden} 3702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 3712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 37271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Update an instruction's opcode. 37371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * 37471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * If "opcode" is an 8-bit op, we just replace that portion. If it's a 37571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * 16-bit op, we convert the opcode from "packed" form (e.g. 0x0108) to 37671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * bytecode form (e.g. 0x08ff). 3773f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden */ 37868e74fda779ca28ecb2b3af10d5193691603b3d0Ben Chengstatic inline void updateOpcode(const Method* meth, u2* ptr, u2 opcode) 3793f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden{ 38071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden if (opcode >= 256) { 38171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden /* opcode low byte becomes high byte, low byte becomes 0xff */ 38271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden assert((ptr[0] & 0xff) == 0xff); 38368e74fda779ca28ecb2b3af10d5193691603b3d0Ben Cheng dvmUpdateCodeUnit(meth, ptr, (opcode << 8) | 0x00ff); 38471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden } else { 38571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden /* 8-bit op, just replace the low byte */ 38671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden assert((ptr[0] & 0xff) != 0xff); 38768e74fda779ca28ecb2b3af10d5193691603b3d0Ben Cheng dvmUpdateCodeUnit(meth, ptr, (ptr[0] & 0xff00) | opcode); 38871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden } 3893f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden} 3903f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden 3913f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden/* 3922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * If "referrer" and "resClass" don't come from the same DEX file, and 3932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * the DEX we're working on is not destined for the bootstrap class path, 3942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * tweak the class loader so package-access checks work correctly. 3952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 3962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Only do this if we're doing pre-verification or optimization. 3972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 3982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void tweakLoader(ClassObject* referrer, ClassObject* resClass) 3992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 4002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!gDvm.optimizing) 4012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return; 4022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert(referrer->classLoader == NULL); 4032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert(resClass->classLoader == NULL); 4042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!gDvm.optimizingBootstrapClass) { 4062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* class loader for an array class comes from element type */ 4072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (dvmIsArrayClass(resClass)) 4082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass = resClass->elementClass; 4092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (referrer->pDvmDex != resClass->pDvmDex) 4102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass->classLoader = (Object*) 0xdead3333; 4112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 4122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 4132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 4152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Undo the effects of tweakLoader. 4162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 4172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void untweakLoader(ClassObject* referrer, ClassObject* resClass) 4182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 4192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!gDvm.optimizing || gDvm.optimizingBootstrapClass) 4202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return; 4212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (dvmIsArrayClass(resClass)) 4232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass = resClass->elementClass; 4242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass->classLoader = NULL; 4252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 4262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 4292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveClass for use with verification and 4302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * optimization. Performs access checks on every resolve, and refuses 4312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * to acknowledge the existence of classes defined in more than one DEX 4322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * file. 4332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 4342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Exceptions caused by failures are cleared before returning. 4352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 4362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL. 4372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 4382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx, 4392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden VerifyError* pFailure) 4402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 4412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden DvmDex* pDvmDex = referrer->pDvmDex; 4422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* resClass; 4432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 4452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Check the table first. If not there, do the lookup by name. 4462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 4472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass = dvmDexGetResolvedClass(pDvmDex, classIdx); 4482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resClass == NULL) { 4492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx); 4502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (className[0] != '\0' && className[1] == '\0') { 4512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* primitive type */ 4522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass = dvmFindPrimitiveClass(className[0]); 4532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } else { 4542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass = dvmFindClassNoInit(className, referrer->classLoader); 4552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 4562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resClass == NULL) { 4572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* not found, exception should be raised */ 45892c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("DexOpt: class %d (%s) not found", 4592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden classIdx, 4602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringByTypeIdx(pDvmDex->pDexFile, classIdx)); 4612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) { 4622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* dig through the wrappers to find the original failure */ 4632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden Object* excep = dvmGetException(dvmThreadSelf()); 4642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden while (true) { 4652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden Object* cause = dvmGetExceptionCause(excep); 4662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (cause == NULL) 4672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden break; 4682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden excep = cause; 4692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 4702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (strcmp(excep->clazz->descriptor, 4712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden "Ljava/lang/IncompatibleClassChangeError;") == 0) 4722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden { 4732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_CLASS_CHANGE; 4742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } else { 4752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_NO_CLASS; 4762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 4772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 4782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dvmClearOptException(dvmThreadSelf()); 4792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 4802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 4812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 4832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Add it to the resolved table so we're faster on the next lookup. 4842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 4852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dvmDexSetResolvedClass(pDvmDex, classIdx, resClass); 4862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 4872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* multiple definitions? */ 4892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) { 4904308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block ALOGI("DexOpt: not resolving ambiguous class '%s'", 4912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass->descriptor); 4922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 4932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_NO_CLASS; 4942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 4952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 4962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* access allowed? */ 4982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden tweakLoader(referrer, resClass); 4992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden bool allowed = dvmCheckClassAccess(referrer, resClass); 5002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden untweakLoader(referrer, resClass); 5012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!allowed) { 502e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("DexOpt: resolve class illegal access: %s -> %s", 5032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden referrer->descriptor, resClass->descriptor); 5042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 5052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_ACCESS_CLASS; 5062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 5072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 5082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return resClass; 5102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 5112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 5132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveInstField(). 5142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 5152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL. 5162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 5172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenInstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx, 5182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden VerifyError* pFailure) 5192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 5202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden DvmDex* pDvmDex = referrer->pDvmDex; 5212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden InstField* resField; 5222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx); 5242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resField == NULL) { 5252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden const DexFieldId* pFieldId; 5262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* resClass; 5272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx); 5292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 5312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Find the field's class. 5322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 5332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure); 5342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resClass == NULL) { 5352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden //dvmClearOptException(dvmThreadSelf()); 5362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert(!dvmCheckException(dvmThreadSelf())); 5372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); } 5382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 5392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 5402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resField = (InstField*)dvmFindFieldHier(resClass, 5422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx), 5432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx)); 5442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resField == NULL) { 545062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block ALOGD("DexOpt: couldn't find field %s.%s", 5462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass->descriptor, 5472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx)); 5482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 5492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_NO_FIELD; 5502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 5512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 552a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro if (dvmIsStaticField(resField)) { 553062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block ALOGD("DexOpt: wanted instance, got static for field %s.%s", 5542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass->descriptor, 5552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx)); 5562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 5572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_CLASS_CHANGE; 5582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 5592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 5602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 5622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Add it to the resolved table so we're faster on the next lookup. 5632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 5642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField); 5652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 5662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* access allowed? */ 568a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro tweakLoader(referrer, resField->clazz); 5692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField); 570a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro untweakLoader(referrer, resField->clazz); 5712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!allowed) { 5724308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block ALOGI("DexOpt: access denied from %s to field %s.%s", 573a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro referrer->descriptor, resField->clazz->descriptor, 574a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro resField->name); 5752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 5762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_ACCESS_FIELD; 5772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 5782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 5792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return resField; 5812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 5822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 5842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveStaticField(). 5852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 5862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Does not force initialization of the resolved field's class. 5872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 5882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL. 5892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 5902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenStaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx, 5912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden VerifyError* pFailure) 5922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 5932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden DvmDex* pDvmDex = referrer->pDvmDex; 5942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden StaticField* resField; 5952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx); 5972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resField == NULL) { 5982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden const DexFieldId* pFieldId; 5992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* resClass; 6002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 6012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx); 6022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 6032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 6042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Find the field's class. 6052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 6062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure); 6072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resClass == NULL) { 6082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden //dvmClearOptException(dvmThreadSelf()); 6092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert(!dvmCheckException(dvmThreadSelf())); 6102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); } 6112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 6122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 6132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 61471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden const char* fieldName = 61571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx); 61671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden 61771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden resField = (StaticField*)dvmFindFieldHier(resClass, fieldName, 6182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx)); 6192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resField == NULL) { 620062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block ALOGD("DexOpt: couldn't find static field %s.%s", 62171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden resClass->descriptor, fieldName); 6222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 6232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_NO_FIELD; 6242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 6252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 626a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro if (!dvmIsStaticField(resField)) { 627062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block ALOGD("DexOpt: wanted static, got instance for field %s.%s", 62871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden resClass->descriptor, fieldName); 6292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 6302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_CLASS_CHANGE; 6312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 6322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 6332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 6342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 6352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Add it to the resolved table so we're faster on the next lookup. 6362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 6372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * We can only do this if we're in "dexopt", because the presence 6382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * of a valid value in the resolution table implies that the class 6392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * containing the static field has been initialized. 6402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 6412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (gDvm.optimizing) 6422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField); 6432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 6442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 6452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* access allowed? */ 646a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro tweakLoader(referrer, resField->clazz); 6472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField); 648a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro untweakLoader(referrer, resField->clazz); 6492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!allowed) { 6504308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block ALOGI("DexOpt: access denied from %s to field %s.%s", 651a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro referrer->descriptor, resField->clazz->descriptor, 652a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro resField->name); 6532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 6542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_ACCESS_FIELD; 6552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 6562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 6572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 6582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return resField; 6592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 6602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 6612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 6622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 66371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Rewrite an iget/iput instruction if appropriate. These all have the form: 6642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * op vA, vB, field@CCCC 6652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 6662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Where vA holds the value, vB holds the object reference, and CCCC is 667fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * the field reference constant pool offset. For a non-volatile field, 668fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * we want to replace the opcode with "quickOpc" and replace CCCC with 669fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * the byte offset from the start of the object. For a volatile field, 670fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * we just want to replace the opcode with "volatileOpc". 6712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 672139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden * If "volatileOpc" is OP_NOP we don't check to see if it's a volatile 673139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden * field. If "quickOpc" is OP_NOP, and this is a non-volatile field, 674139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden * we don't do anything. 675fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * 676fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * "method" is the referring method. 6772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 67871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteInstField(Method* method, u2* insns, Opcode quickOpc, 6799a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein Opcode volatileOpc) 6802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 6812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* clazz = method->clazz; 6822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden u2 fieldIdx = insns[1]; 683fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden InstField* instField; 6842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 685fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden instField = dvmOptResolveInstField(clazz, fieldIdx, NULL); 686fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden if (instField == NULL) { 6874308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block ALOGI("DexOpt: unable to optimize instance field ref " 6886f3c21fb026d9489e5046416bcd5a84fa8e4615bDan Bornstein "0x%04x at 0x%02x in %s.%s", 6892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden fieldIdx, (int) (insns - method->insns), clazz->descriptor, 6902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden method->name); 69171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden return; 692fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden } 693fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden 694a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro if (volatileOpc != OP_NOP && dvmIsVolatileField(instField)) { 6959a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein updateOpcode(method, insns, volatileOpc); 69692c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("DexOpt: rewrote ifield access %s.%s --> volatile", 697a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro instField->clazz->descriptor, instField->name); 69871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden } else if (quickOpc != OP_NOP && instField->byteOffset < 65536) { 6999a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein updateOpcode(method, insns, quickOpc); 70057fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden dvmUpdateCodeUnit(method, insns+1, (u2) instField->byteOffset); 70192c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("DexOpt: rewrote ifield access %s.%s --> %d", 702a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro instField->clazz->descriptor, instField->name, 703fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden instField->byteOffset); 704fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden } else { 70592c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("DexOpt: no rewrite of ifield access %s.%s", 706a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro instField->clazz->descriptor, instField->name); 707fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden } 708fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden 70971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden return; 710fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden} 711fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden 712fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden/* 713ab35b50311951feea3782151dd5422ee944685c2Elliott Hughes * Rewrite a static field access instruction if appropriate. If 71471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * the target field is volatile, we replace the opcode with "volatileOpc". 715fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * 716fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden * "method" is the referring method. 717fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden */ 71871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteStaticField0(Method* method, u2* insns, Opcode volatileOpc, 71971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden u4 fieldIdx) 720fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden{ 721fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden ClassObject* clazz = method->clazz; 722fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden StaticField* staticField; 723fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden 724139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden assert(volatileOpc != OP_NOP); 725139516ee8f527aca18ae658087f28d825bfdf1c9Andy McFadden 726fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden staticField = dvmOptResolveStaticField(clazz, fieldIdx, NULL); 727fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden if (staticField == NULL) { 7284308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block ALOGI("DexOpt: unable to optimize static field ref " 7296f3c21fb026d9489e5046416bcd5a84fa8e4615bDan Bornstein "0x%04x at 0x%02x in %s.%s", 730fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden fieldIdx, (int) (insns - method->insns), clazz->descriptor, 731fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden method->name); 73271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden return; 733fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden } 734fb119e6cf8b47d53f024cae889487a17eacbf19fAndy McFadden 735a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro if (dvmIsVolatileField(staticField)) { 7369a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein updateOpcode(method, insns, volatileOpc); 73792c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("DexOpt: rewrote sfield access %s.%s --> volatile", 738a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro staticField->clazz->descriptor, staticField->name); 7392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 74071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden} 7412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 74271c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteStaticField(Method* method, u2* insns, Opcode volatileOpc) 74371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden{ 74471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden u2 fieldIdx = insns[1]; 74571c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden rewriteStaticField0(method, insns, volatileOpc, fieldIdx); 74671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden} 74771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden 7482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 7492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveMethod(). 7502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 7512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Doesn't throw exceptions, and checks access on every lookup. 7522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 7532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL. 7542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 7552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenMethod* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx, 7562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden MethodType methodType, VerifyError* pFailure) 7572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 7582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden DvmDex* pDvmDex = referrer->pDvmDex; 7592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden Method* resMethod; 7602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 7612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert(methodType == METHOD_DIRECT || 7622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden methodType == METHOD_VIRTUAL || 7632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden methodType == METHOD_STATIC); 7642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 76560fc806b679a3655c228b4093058c59941a49cfeDan Bornstein LOGVV("--- resolving method %u (referrer=%s)", methodIdx, 7662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden referrer->descriptor); 7672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 7682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx); 7692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resMethod == NULL) { 7702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden const DexMethodId* pMethodId; 7712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* resClass; 7722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 7732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx); 7742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 7752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure); 7762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resClass == NULL) { 7772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 7782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Can't find the class that the method is a part of, or don't 7792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * have permission to access the class. 7802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 78192c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("DexOpt: can't find called method's class (?.%s)", 7822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx)); 7832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); } 7842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 7852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 7862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (dvmIsInterfaceClass(resClass)) { 7872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* method is part of an interface; this is wrong method for that */ 788e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("DexOpt: method is in an interface"); 7892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 7902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_GENERIC; 7912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 7922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 7932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 7942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 7952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * We need to chase up the class hierarchy to find methods defined 7962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * in super-classes. (We only want to check the current class 7972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * if we're looking for a constructor.) 7982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 7992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden DexProto proto; 8002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId); 8012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (methodType == METHOD_DIRECT) { 8032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resMethod = dvmFindDirectMethod(resClass, 8042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto); 8052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } else { 8062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* METHOD_STATIC or METHOD_VIRTUAL */ 8072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resMethod = dvmFindMethodHier(resClass, 8082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto); 8092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 8102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resMethod == NULL) { 81292c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("DexOpt: couldn't find method '%s'", 8132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx)); 8142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 8152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_NO_METHOD; 8162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 8172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 8182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (methodType == METHOD_STATIC) { 8192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!dvmIsStaticMethod(resMethod)) { 820062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block ALOGD("DexOpt: wanted static, got instance for method %s.%s", 8212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass->descriptor, resMethod->name); 8222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 8232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_CLASS_CHANGE; 8242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 8252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 8262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } else if (methodType == METHOD_VIRTUAL) { 8272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (dvmIsStaticMethod(resMethod)) { 828062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block ALOGD("DexOpt: wanted instance, got static for method %s.%s", 8292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass->descriptor, resMethod->name); 8302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 8312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_CLASS_CHANGE; 8322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 8332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 8342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 8352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* see if this is a pure-abstract method */ 8372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) { 838e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("DexOpt: pure-abstract method '%s' in %s", 8392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), 8402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass->descriptor); 8412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 8422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_GENERIC; 8432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 8442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 8452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 8472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Add it to the resolved table so we're faster on the next lookup. 8482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 8492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * We can only do this for static methods if we're not in "dexopt", 8502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * because the presence of a valid value in the resolution table 8512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * implies that the class containing the static field has been 8522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * initialized. 8532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 8542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (methodType != METHOD_STATIC || gDvm.optimizing) 8552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod); 8562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 8572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 85860fc806b679a3655c228b4093058c59941a49cfeDan Bornstein LOGVV("--- found method %d (%s.%s)", 8592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden methodIdx, resMethod->clazz->descriptor, resMethod->name); 8602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* access allowed? */ 8622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden tweakLoader(referrer, resMethod->clazz); 8632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden bool allowed = dvmCheckMethodAccess(referrer, resMethod); 8642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden untweakLoader(referrer, resMethod->clazz); 8652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!allowed) { 8664308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block IF_ALOGI() { 8672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype); 8684308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block ALOGI("DexOpt: illegal method access (call %s.%s %s from %s)", 8692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resMethod->clazz->descriptor, resMethod->name, desc, 8702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden referrer->descriptor); 8712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden free(desc); 8722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 8732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 8742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_ACCESS_METHOD; 8752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 8762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 8772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return resMethod; 8792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 8802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 8822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Rewrite invoke-virtual, invoke-virtual/range, invoke-super, and 88371c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * invoke-super/range if appropriate. These all have the form: 8842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * op vAA, meth@BBBB, reg stuff @CCCC 8852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 8862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * We want to replace the method constant pool index BBBB with the 8872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * vtable index. 8882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 88971c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFaddenstatic void rewriteVirtualInvoke(Method* method, u2* insns, Opcode newOpc) 8902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 8912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* clazz = method->clazz; 8922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden Method* baseMethod; 8932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden u2 methodIdx = insns[1]; 8942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL, NULL); 8962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (baseMethod == NULL) { 897062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block ALOGD("DexOpt: unable to optimize virt call 0x%04x at 0x%02x in %s.%s", 8982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden methodIdx, 8992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden (int) (insns - method->insns), clazz->descriptor, 9002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden method->name); 90171c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden return; 9022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 9032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert((insns[0] & 0xff) == OP_INVOKE_VIRTUAL || 9052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE || 9062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden (insns[0] & 0xff) == OP_INVOKE_SUPER || 9072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden (insns[0] & 0xff) == OP_INVOKE_SUPER_RANGE); 9082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 9102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Note: Method->methodIndex is a u2 and is range checked during the 9112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * initial load. 9122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 9139a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein updateOpcode(method, insns, newOpc); 91457fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden dvmUpdateCodeUnit(method, insns+1, baseMethod->methodIndex); 9152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9164308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block //ALOGI("DexOpt: rewrote call to %s.%s --> %s.%s", 9172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden // method->clazz->descriptor, method->name, 9182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden // baseMethod->clazz->descriptor, baseMethod->name); 9192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 92071c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden return; 9212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 9222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 92471c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Rewrite invoke-direct[/range] if the target is Object.<init>. 9252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 9266af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * This is useful as an optimization, because otherwise every object 9276af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * instantiation will cause us to call a method that does nothing. 9286af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * It also allows us to inexpensively mark objects as finalizable at the 9296af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * correct time. 9302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 9316af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * TODO: verifier should ensure Object.<init> contains only return-void, 9326af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden * and issue a warning if not. 9332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 9346af2ddd107842c3737c04c37343cac9be17f4209Andy McFaddenstatic bool rewriteInvokeObjectInit(Method* method, u2* insns) 9352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 9362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* clazz = method->clazz; 9372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden Method* calledMethod; 9382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden u2 methodIdx = insns[1]; 9392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL); 9412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (calledMethod == NULL) { 942062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block ALOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s", 9436af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden methodIdx, (int) (insns - method->insns), 9446af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden clazz->descriptor, method->name); 9452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return false; 9462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 9472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (calledMethod->clazz == gDvm.classJavaLangObject && 9492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0) 9502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden { 9512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 9520346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden * Replace the instruction. If the debugger is attached, the 9530346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden * interpreter will forward execution to the invoke-direct/range 9540346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden * handler. If this was an invoke-direct/range instruction we can 9550346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden * just replace the opcode, but if it was an invoke-direct we 9560346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden * have to set the argument count (high 8 bits of first code unit) 9570346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden * to 1. 9582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 9590346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden u1 origOp = insns[0] & 0xff; 9600346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden if (origOp == OP_INVOKE_DIRECT) { 96157fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden dvmUpdateCodeUnit(method, insns, 96257fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden OP_INVOKE_OBJECT_INIT_RANGE | 0x100); 9630346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden } else { 9640346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden assert(origOp == OP_INVOKE_DIRECT_RANGE); 9650346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden assert((insns[0] >> 8) == 1); 9660346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden updateOpcode(method, insns, OP_INVOKE_OBJECT_INIT_RANGE); 9670346e9dcddccd449c731e42ef83708ff6d8f0976Andy McFadden } 9682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 96960fc806b679a3655c228b4093058c59941a49cfeDan Bornstein LOGVV("DexOpt: replaced Object.<init> in %s.%s", 9706af2ddd107842c3737c04c37343cac9be17f4209Andy McFadden method->clazz->descriptor, method->name); 9712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 9722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return true; 9742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 9752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 9772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Resolve an interface method reference. 9782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 9792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * No method access check here -- interface methods are always public. 9802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 9812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns NULL if the method was not found. Does not throw an exception. 9822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 9832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenMethod* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx) 9842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 9852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden DvmDex* pDvmDex = referrer->pDvmDex; 9862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden Method* resMethod; 9872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 98860fc806b679a3655c228b4093058c59941a49cfeDan Bornstein LOGVV("--- resolving interface method %d (referrer=%s)", 9892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden methodIdx, referrer->descriptor); 9902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx); 9922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resMethod == NULL) { 9932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden const DexMethodId* pMethodId; 9942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* resClass; 9952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx); 9972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, NULL); 9992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resClass == NULL) { 10002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* can't find the class that the method is a part of */ 10012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dvmClearOptException(dvmThreadSelf()); 10022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 10032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 10042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!dvmIsInterfaceClass(resClass)) { 10052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* whoops */ 10064308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block ALOGI("Interface method not part of interface class"); 10072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 10082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 10092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 10102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden const char* methodName = 10112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx); 10122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden DexProto proto; 10132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId); 10142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 101560fc806b679a3655c228b4093058c59941a49cfeDan Bornstein LOGVV("+++ looking for '%s' '%s' in resClass='%s'", 10162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden methodName, methodSig, resClass->descriptor); 1017da7334a4ba1bbffe40d3838f463565af46e716d9Andy McFadden resMethod = dvmFindInterfaceMethodHier(resClass, methodName, &proto); 10182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resMethod == NULL) { 1019da7334a4ba1bbffe40d3838f463565af46e716d9Andy McFadden return NULL; 10202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 10212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 10222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* we're expecting this to be abstract */ 10232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!dvmIsAbstractMethod(resMethod)) { 10242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype); 1025e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block ALOGW("Found non-abstract interface method %s.%s %s", 10262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resMethod->clazz->descriptor, resMethod->name, desc); 10272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden free(desc); 10282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 10292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 10302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 10312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 10322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Add it to the resolved table so we're faster on the next lookup. 10332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 10342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod); 10352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 10362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 103760fc806b679a3655c228b4093058c59941a49cfeDan Bornstein LOGVV("--- found interface method %d (%s.%s)", 10382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden methodIdx, resMethod->clazz->descriptor, resMethod->name); 10392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 10402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* interface methods are always public; no need to check access */ 10412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 10422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return resMethod; 10432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 10442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 10452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 104671c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Replace invoke-virtual, invoke-direct, or invoke-static with an 104771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * execute-inline operation if appropriate. 10482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 10492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" if we replace it. 10502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 10512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInline(Method* method, u2* insns, 1052cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden MethodType methodType) 10532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 1054cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden const InlineSub* inlineSubs = gDvm.inlineSubs; 10552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* clazz = method->clazz; 10562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden Method* calledMethod; 10572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden u2 methodIdx = insns[1]; 10582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 10592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden //return false; 10602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 10612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL); 10622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (calledMethod == NULL) { 106392c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("+++ DexOpt inline: can't find %d", methodIdx); 10642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return false; 10652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 10662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 10672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden while (inlineSubs->method != NULL) { 10682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 10692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (extra) { 10704308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block ALOGI("comparing %p vs %p %s.%s %s", 10712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden inlineSubs->method, calledMethod, 10722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden inlineSubs->method->clazz->descriptor, 10732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden inlineSubs->method->name, 10742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden inlineSubs->method->signature); 10752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 10762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 10772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (inlineSubs->method == calledMethod) { 10782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert((insns[0] & 0xff) == OP_INVOKE_DIRECT || 10792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden (insns[0] & 0xff) == OP_INVOKE_STATIC || 10802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden (insns[0] & 0xff) == OP_INVOKE_VIRTUAL); 10819a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein updateOpcode(method, insns, OP_EXECUTE_INLINE); 108257fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden dvmUpdateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx); 10832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 10844308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block //ALOGI("DexOpt: execute-inline %s.%s --> %s.%s", 10852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden // method->clazz->descriptor, method->name, 10862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden // calledMethod->clazz->descriptor, calledMethod->name); 10872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return true; 10882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 10892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 10902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden inlineSubs++; 10912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 10922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 10932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return false; 10942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 10952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 10962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 109771c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * Replace invoke-virtual/range, invoke-direct/range, or invoke-static/range 109871c1771a0ca30b09653de88f6a9c714dec7a61b7Andy McFadden * with an execute-inline operation if appropriate. 10992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 11002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" if we replace it. 11012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 11022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInlineRange(Method* method, u2* insns, 1103cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden MethodType methodType) 11042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 1105cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden const InlineSub* inlineSubs = gDvm.inlineSubs; 11062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* clazz = method->clazz; 11072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden Method* calledMethod; 11082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden u2 methodIdx = insns[1]; 11092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 11102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL); 11112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (calledMethod == NULL) { 111292c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block ALOGV("+++ DexOpt inline/range: can't find %d", methodIdx); 11132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return false; 11142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 11152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 11162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden while (inlineSubs->method != NULL) { 11172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (inlineSubs->method == calledMethod) { 11182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert((insns[0] & 0xff) == OP_INVOKE_DIRECT_RANGE || 11192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden (insns[0] & 0xff) == OP_INVOKE_STATIC_RANGE || 11202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE); 11219a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein updateOpcode(method, insns, OP_EXECUTE_INLINE_RANGE); 112257fd399d1265ec627d28a15b3d4b98e5f239ac88Andy McFadden dvmUpdateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx); 11232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 11244308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block //ALOGI("DexOpt: execute-inline/range %s.%s --> %s.%s", 11252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden // method->clazz->descriptor, method->name, 11262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden // calledMethod->clazz->descriptor, calledMethod->name); 11272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return true; 11282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 11292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 11302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden inlineSubs++; 11312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 11322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 11332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return false; 11342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 11353f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden 11363f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden/* 11373f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * Returns "true" if the return-void instructions in this method should 11383f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * be converted to return-void-barrier. 11393f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * 11403f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * This is needed to satisfy a Java Memory Model requirement regarding 11413f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * the construction of objects with final fields. (This does not apply 11423f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * to <clinit> or static fields, since appropriate barriers are guaranteed 11433f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * by the class initialization process.) 11443f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden */ 11453f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFaddenstatic bool needsReturnBarrier(Method* method) 11463f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden{ 11473f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden if (!gDvm.dexOptForSmp) 11483f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden return false; 11493f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden if (strcmp(method->name, "<init>") != 0) 11503f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden return false; 11513f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden 11523f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden /* 1153ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden * Check to see if the class is finalizable. The loader sets a flag 1154ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden * if the class or one of its superclasses overrides finalize(). 11553f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden */ 11563f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden const ClassObject* clazz = method->clazz; 1157ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) 1158ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden return true; 11593f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden 11603f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden /* 1161ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden * Check to see if the class has any final fields. If not, we don't 1162ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden * need to generate a barrier instruction. 1163ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden * 11643f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * In theory, we only need to do this if the method actually modifies 11653f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * a final field. In practice, non-constructor methods are allowed 1166ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden * to modify final fields, and there are 3rd-party tools that rely on 1167ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden * this behavior. (The compiler does not allow it, but the VM does.) 11683f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * 11693f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * If we alter the verifier to restrict final-field updates to 11703f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * constructors, we can tighten this up as well. 11713f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden */ 1172ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden int idx = clazz->ifieldCount; 1173ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden while (--idx >= 0) { 1174a7323974309c3b81cfe342db635d0bf30f36ff62Carl Shapiro if (dvmIsFinalField(&clazz->ifields[idx])) 1175ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden return true; 1176ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden } 11773f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden 1178ca02b580a542e97f273e1adfb6d26e7b20cc99a0Andy McFadden return false; 11793f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden} 11803f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden 11813f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden/* 11823f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden * Convert a return-void to a return-void-barrier. 11833f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden */ 11843f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFaddenstatic void rewriteReturnVoid(Method* method, u2* insns) 11853f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden{ 11863f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden assert((insns[0] & 0xff) == OP_RETURN_VOID); 11879a1f81699cc05b58378ffb9aadb4e97677943791Dan Bornstein updateOpcode(method, insns, OP_RETURN_VOID_BARRIER); 11883f4b63f47f50f200538e83fa3fac06947afa08b4Andy McFadden} 1189