Optimize.cpp revision 228a6b01918304f2cd1213c722e028a6e25252bb
12e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 22e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Copyright (C) 2008 The Android Open Source Project 32e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 42e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Licensed under the Apache License, Version 2.0 (the "License"); 52e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * you may not use this file except in compliance with the License. 62e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * You may obtain a copy of the License at 72e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 82e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * http://www.apache.org/licenses/LICENSE-2.0 92e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Unless required by applicable law or agreed to in writing, software 112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * distributed under the License is distributed on an "AS IS" BASIS, 122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * See the License for the specific language governing permissions and 142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * limitations under the License. 152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Perform some simple bytecode optimizations, chiefly "quickening" of 192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * opcodes. 202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include "Dalvik.h" 222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include "libdex/InstrUtils.h" 232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <zlib.h> 252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden#include <stdlib.h> 272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Virtual/direct calls to "method" are replaced with an execute-inline 302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * instruction with index "idx". 312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 32cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstruct InlineSub { 332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden Method* method; 342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden int inlineIdx; 35cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden}; 362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* fwd */ 39cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstatic bool optimizeMethod(Method* method); 402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void rewriteInstField(Method* method, u2* insns, OpCode newOpc); 412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteVirtualInvoke(Method* method, u2* insns, OpCode newOpc); 422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteEmptyDirectInvoke(Method* method, u2* insns); 432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInline(Method* method, u2* insns, 44cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden MethodType methodType); 452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInlineRange(Method* method, u2* insns, 46cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden MethodType methodType); 472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Create a table of inline substitutions. 512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * TODO: this is currently just a linear array. We will want to put this 532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * into a hash table as the list size increases. 542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 55cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenInlineSub* dvmCreateInlineSubsTable(void) 562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden const InlineOperation* ops = dvmGetInlineOpsTable(); 582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden const int count = dvmGetInlineOpsTableLength(); 592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden InlineSub* table; 602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden Method* method; 612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* clazz; 622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden int i, tableIndex; 632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Allocate for optimism: one slot per entry, plus an end-of-list marker. 662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden table = malloc(sizeof(InlineSub) * (count+1)); 682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden tableIndex = 0; 702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden for (i = 0; i < count; i++) { 712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden clazz = dvmFindClassNoInit(ops[i].classDescriptor, NULL); 722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (clazz == NULL) { 732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGV("DexOpt: can't inline for class '%s': not found\n", 742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ops[i].classDescriptor); 752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dvmClearOptException(dvmThreadSelf()); 762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } else { 772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Method could be virtual or direct. Try both. Don't use 792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * the "hier" versions. 802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden method = dvmFindDirectMethodByDescriptor(clazz, ops[i].methodName, 822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ops[i].methodSignature); 832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (method == NULL) 842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden method = dvmFindVirtualMethodByDescriptor(clazz, ops[i].methodName, 852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ops[i].methodSignature); 862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (method == NULL) { 872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGW("DexOpt: can't inline %s.%s %s: method not found\n", 882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ops[i].classDescriptor, ops[i].methodName, 892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ops[i].methodSignature); 902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } else { 912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!dvmIsFinalClass(clazz) && !dvmIsFinalMethod(method)) { 922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGW("DexOpt: WARNING: inline op on non-final class/method " 932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden "%s.%s\n", 942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden clazz->descriptor, method->name); 952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* fail? */ 962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (dvmIsSynchronizedMethod(method) || 982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dvmIsDeclaredSynchronizedMethod(method)) 992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden { 1002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGW("DexOpt: WARNING: inline op on synchronized method " 1012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden "%s.%s\n", 1022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden clazz->descriptor, method->name); 1032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* fail? */ 1042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 1052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden table[tableIndex].method = method; 1072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden table[tableIndex].inlineIdx = i; 1082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden tableIndex++; 1092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGV("DexOpt: will inline %d: %s.%s %s\n", i, 1112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ops[i].classDescriptor, ops[i].methodName, 1122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ops[i].methodSignature); 1132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 1142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 1152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 1162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* mark end of table */ 1182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden table[tableIndex].method = NULL; 1192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGV("DexOpt: inline table has %d entries\n", tableIndex); 1202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return table; 1222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 1232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 125cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden * Release inline sub data structure. 1262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 127cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenvoid dvmFreeInlineSubsTable(InlineSub* inlineSubs) 1282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 1292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden free(inlineSubs); 1302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 1312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 132cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden 1332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 1342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Optimize the specified class. 1352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 136cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenvoid dvmOptimizeClass(ClassObject* clazz) 1372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 1382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden int i; 1392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden for (i = 0; i < clazz->directMethodCount; i++) { 141cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden if (!optimizeMethod(&clazz->directMethods[i] )) 1422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden goto fail; 1432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 1442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden for (i = 0; i < clazz->virtualMethodCount; i++) { 145cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden if (!optimizeMethod(&clazz->virtualMethods[i])) 1462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden goto fail; 1472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 1482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return; 1502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenfail: 152cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden // TODO: show when in "verbose" mode 1532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGV("DexOpt: ceasing optimization attempts on %s\n", clazz->descriptor); 1542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 1552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 1572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Optimize instructions in a method. 1582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 159228a6b01918304f2cd1213c722e028a6e25252bbAndy McFadden * This does a single pass through the code, examining each instruction. 160228a6b01918304f2cd1213c722e028a6e25252bbAndy McFadden * 1612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" if all went well, "false" if we bailed out early when 1622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * something failed. 1632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 164cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFaddenstatic bool optimizeMethod(Method* method) 1652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 1662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden u4 insnsSize; 1672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden u2* insns; 1682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden u2 inst; 1692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (dvmIsNativeMethod(method) || dvmIsAbstractMethod(method)) 1712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return true; 1722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden insns = (u2*) method->insns; 1742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert(insns != NULL); 1752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden insnsSize = dvmGetMethodInsnsSize(method); 1762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden while (insnsSize > 0) { 1782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden int width; 1792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden inst = *insns & 0xff; 1812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 1822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden switch (inst) { 183cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden#ifndef PROFILE_FIELD_ACCESS /* quickened instructions not instrumented */ 1842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IGET: 1852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IGET_BOOLEAN: 1862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IGET_BYTE: 1872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IGET_CHAR: 1882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IGET_SHORT: 1892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden rewriteInstField(method, insns, OP_IGET_QUICK); 1902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden break; 1912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IGET_WIDE: 1922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden rewriteInstField(method, insns, OP_IGET_WIDE_QUICK); 1932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden break; 1942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IGET_OBJECT: 1952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden rewriteInstField(method, insns, OP_IGET_OBJECT_QUICK); 1962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden break; 1972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IPUT: 1982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IPUT_BOOLEAN: 1992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IPUT_BYTE: 2002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IPUT_CHAR: 2012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IPUT_SHORT: 2022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden rewriteInstField(method, insns, OP_IPUT_QUICK); 2032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden break; 2042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IPUT_WIDE: 2052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden rewriteInstField(method, insns, OP_IPUT_WIDE_QUICK); 2062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden break; 2072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_IPUT_OBJECT: 2082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden rewriteInstField(method, insns, OP_IPUT_OBJECT_QUICK); 2092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden break; 210cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden#endif 2112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 2122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_INVOKE_VIRTUAL: 213cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL)) { 2142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!rewriteVirtualInvoke(method, insns, OP_INVOKE_VIRTUAL_QUICK)) 2152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return false; 2162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 2172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden break; 2182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_INVOKE_VIRTUAL_RANGE: 219cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL)) { 2202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!rewriteVirtualInvoke(method, insns, 2212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden OP_INVOKE_VIRTUAL_QUICK_RANGE)) 2222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden { 2232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return false; 2242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 2252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 2262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden break; 2272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_INVOKE_SUPER: 2282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK)) 2292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return false; 2302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden break; 2312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_INVOKE_SUPER_RANGE: 2322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK_RANGE)) 2332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return false; 2342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden break; 2352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 2362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_INVOKE_DIRECT: 237cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden if (!rewriteExecuteInline(method, insns, METHOD_DIRECT)) { 2382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!rewriteEmptyDirectInvoke(method, insns)) 2392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return false; 2402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 2412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden break; 2422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_INVOKE_DIRECT_RANGE: 243cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden rewriteExecuteInlineRange(method, insns, METHOD_DIRECT); 2442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden break; 2452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 2462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_INVOKE_STATIC: 247cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden rewriteExecuteInline(method, insns, METHOD_STATIC); 2482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden break; 2492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden case OP_INVOKE_STATIC_RANGE: 250cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden rewriteExecuteInlineRange(method, insns, METHOD_STATIC); 2512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden break; 2522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 2532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden default: 2542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden // ignore this instruction 2552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ; 2562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 2572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 258228a6b01918304f2cd1213c722e028a6e25252bbAndy McFadden width = dexGetInstrOrTableWidthAbs(gDvm.instrWidth, insns); 2592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert(width > 0); 2602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 2612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden insns += width; 2622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden insnsSize -= width; 2632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 2642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 2652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert(insnsSize == 0); 2662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return true; 2672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 2682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 2692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 2702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 2712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * If "referrer" and "resClass" don't come from the same DEX file, and 2722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * the DEX we're working on is not destined for the bootstrap class path, 2732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * tweak the class loader so package-access checks work correctly. 2742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 2752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Only do this if we're doing pre-verification or optimization. 2762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 2772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void tweakLoader(ClassObject* referrer, ClassObject* resClass) 2782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 2792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!gDvm.optimizing) 2802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return; 2812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert(referrer->classLoader == NULL); 2822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert(resClass->classLoader == NULL); 2832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 2842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!gDvm.optimizingBootstrapClass) { 2852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* class loader for an array class comes from element type */ 2862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (dvmIsArrayClass(resClass)) 2872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass = resClass->elementClass; 2882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (referrer->pDvmDex != resClass->pDvmDex) 2892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass->classLoader = (Object*) 0xdead3333; 2902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 2912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 2922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 2932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 2942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Undo the effects of tweakLoader. 2952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 2962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void untweakLoader(ClassObject* referrer, ClassObject* resClass) 2972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 2982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!gDvm.optimizing || gDvm.optimizingBootstrapClass) 2992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return; 3002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 3012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (dvmIsArrayClass(resClass)) 3022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass = resClass->elementClass; 3032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass->classLoader = NULL; 3042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 3052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 3062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 3072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 3082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveClass for use with verification and 3092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * optimization. Performs access checks on every resolve, and refuses 3102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * to acknowledge the existence of classes defined in more than one DEX 3112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * file. 3122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 3132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Exceptions caused by failures are cleared before returning. 3142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 3152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL. 3162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 3172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx, 3182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden VerifyError* pFailure) 3192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 3202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden DvmDex* pDvmDex = referrer->pDvmDex; 3212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* resClass; 3222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 3232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 3242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Check the table first. If not there, do the lookup by name. 3252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 3262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass = dvmDexGetResolvedClass(pDvmDex, classIdx); 3272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resClass == NULL) { 3282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx); 3292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (className[0] != '\0' && className[1] == '\0') { 3302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* primitive type */ 3312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass = dvmFindPrimitiveClass(className[0]); 3322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } else { 3332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass = dvmFindClassNoInit(className, referrer->classLoader); 3342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 3352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resClass == NULL) { 3362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* not found, exception should be raised */ 3372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGV("DexOpt: class %d (%s) not found\n", 3382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden classIdx, 3392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringByTypeIdx(pDvmDex->pDexFile, classIdx)); 3402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) { 3412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* dig through the wrappers to find the original failure */ 3422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden Object* excep = dvmGetException(dvmThreadSelf()); 3432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden while (true) { 3442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden Object* cause = dvmGetExceptionCause(excep); 3452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (cause == NULL) 3462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden break; 3472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden excep = cause; 3482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 3492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (strcmp(excep->clazz->descriptor, 3502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden "Ljava/lang/IncompatibleClassChangeError;") == 0) 3512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden { 3522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_CLASS_CHANGE; 3532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } else { 3542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_NO_CLASS; 3552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 3562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 3572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dvmClearOptException(dvmThreadSelf()); 3582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 3592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 3602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 3612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 3622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Add it to the resolved table so we're faster on the next lookup. 3632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 3642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dvmDexSetResolvedClass(pDvmDex, classIdx, resClass); 3652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 3662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 3672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* multiple definitions? */ 3682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) { 3692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGI("DexOpt: not resolving ambiguous class '%s'\n", 3702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass->descriptor); 3712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 3722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_NO_CLASS; 3732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 3742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 3752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 3762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* access allowed? */ 3772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden tweakLoader(referrer, resClass); 3782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden bool allowed = dvmCheckClassAccess(referrer, resClass); 3792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden untweakLoader(referrer, resClass); 3802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!allowed) { 3812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGW("DexOpt: resolve class illegal access: %s -> %s\n", 3822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden referrer->descriptor, resClass->descriptor); 3832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 3842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_ACCESS_CLASS; 3852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 3862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 3872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 3882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return resClass; 3892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 3902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 3912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 3922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveInstField(). 3932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 3942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL. 3952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 3962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenInstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx, 3972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden VerifyError* pFailure) 3982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 3992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden DvmDex* pDvmDex = referrer->pDvmDex; 4002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden InstField* resField; 4012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx); 4032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resField == NULL) { 4042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden const DexFieldId* pFieldId; 4052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* resClass; 4062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx); 4082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 4102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Find the field's class. 4112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 4122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure); 4132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resClass == NULL) { 4142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden //dvmClearOptException(dvmThreadSelf()); 4152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert(!dvmCheckException(dvmThreadSelf())); 4162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); } 4172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 4182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 4192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resField = (InstField*)dvmFindFieldHier(resClass, 4212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx), 4222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx)); 4232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resField == NULL) { 4242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGD("DexOpt: couldn't find field %s.%s\n", 4252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass->descriptor, 4262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx)); 4272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 4282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_NO_FIELD; 4292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 4302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 4312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (dvmIsStaticField(&resField->field)) { 4322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGD("DexOpt: wanted instance, got static for field %s.%s\n", 4332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass->descriptor, 4342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx)); 4352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 4362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_CLASS_CHANGE; 4372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 4382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 4392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 4412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Add it to the resolved table so we're faster on the next lookup. 4422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 4432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField); 4442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 4452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* access allowed? */ 4472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden tweakLoader(referrer, resField->field.clazz); 4482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField); 4492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden untweakLoader(referrer, resField->field.clazz); 4502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!allowed) { 4512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGI("DexOpt: access denied from %s to field %s.%s\n", 4522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden referrer->descriptor, resField->field.clazz->descriptor, 4532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resField->field.name); 4542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 4552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_ACCESS_FIELD; 4562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 4572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 4582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return resField; 4602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 4612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 4632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveStaticField(). 4642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 4652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Does not force initialization of the resolved field's class. 4662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 4672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL. 4682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 4692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenStaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx, 4702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden VerifyError* pFailure) 4712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 4722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden DvmDex* pDvmDex = referrer->pDvmDex; 4732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden StaticField* resField; 4742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx); 4762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resField == NULL) { 4772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden const DexFieldId* pFieldId; 4782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* resClass; 4792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx); 4812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 4832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Find the field's class. 4842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 4852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure); 4862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resClass == NULL) { 4872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden //dvmClearOptException(dvmThreadSelf()); 4882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert(!dvmCheckException(dvmThreadSelf())); 4892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); } 4902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 4912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 4922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 4932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resField = (StaticField*)dvmFindFieldHier(resClass, 4942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx), 4952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx)); 4962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resField == NULL) { 4972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGD("DexOpt: couldn't find static field\n"); 4982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 4992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_NO_FIELD; 5002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 5012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 5022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!dvmIsStaticField(&resField->field)) { 5032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGD("DexOpt: wanted static, got instance for field %s.%s\n", 5042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass->descriptor, 5052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx)); 5062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 5072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_CLASS_CHANGE; 5082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 5092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 5102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 5122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Add it to the resolved table so we're faster on the next lookup. 5132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 5142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * We can only do this if we're in "dexopt", because the presence 5152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * of a valid value in the resolution table implies that the class 5162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * containing the static field has been initialized. 5172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 5182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (gDvm.optimizing) 5192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField); 5202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 5212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* access allowed? */ 5232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden tweakLoader(referrer, resField->field.clazz); 5242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField); 5252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden untweakLoader(referrer, resField->field.clazz); 5262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!allowed) { 5272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGI("DexOpt: access denied from %s to field %s.%s\n", 5282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden referrer->descriptor, resField->field.clazz->descriptor, 5292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resField->field.name); 5302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 5312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_ACCESS_FIELD; 5322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 5332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 5342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return resField; 5362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 5372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 5402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Rewrite an iget/iput instruction. These all have the form: 5412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * op vA, vB, field@CCCC 5422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 5432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Where vA holds the value, vB holds the object reference, and CCCC is 5442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * the field reference constant pool offset. We want to replace CCCC 5452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * with the byte offset from the start of the object. 5462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 5472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * "clazz" is the referring class. We need this because we verify 5482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * access rights here. 5492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 5502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic void rewriteInstField(Method* method, u2* insns, OpCode newOpc) 5512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 5522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* clazz = method->clazz; 5532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden u2 fieldIdx = insns[1]; 5542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden InstField* field; 5552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden field = dvmOptResolveInstField(clazz, fieldIdx, NULL); 5572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (field == NULL) { 5582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGI("DexOpt: unable to optimize field ref 0x%04x at 0x%02x in %s.%s\n", 5592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden fieldIdx, (int) (insns - method->insns), clazz->descriptor, 5602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden method->name); 5612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return; 5622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 5632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (field->byteOffset >= 65536) { 5652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGI("DexOpt: field offset exceeds 64K (%d)\n", field->byteOffset); 5662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return; 5672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 5682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden insns[0] = (insns[0] & 0xff00) | (u2) newOpc; 5702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden insns[1] = (u2) field->byteOffset; 5712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGVV("DexOpt: rewrote access to %s.%s --> %d\n", 5722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden field->field.clazz->descriptor, field->field.name, 5732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden field->byteOffset); 5742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 5752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 5772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Alternate version of dvmResolveMethod(). 5782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 5792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Doesn't throw exceptions, and checks access on every lookup. 5802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 5812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * On failure, returns NULL, and sets *pFailure if pFailure is not NULL. 5822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 5832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenMethod* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx, 5842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden MethodType methodType, VerifyError* pFailure) 5852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 5862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden DvmDex* pDvmDex = referrer->pDvmDex; 5872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden Method* resMethod; 5882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert(methodType == METHOD_DIRECT || 5902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden methodType == METHOD_VIRTUAL || 5912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden methodType == METHOD_STATIC); 5922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGVV("--- resolving method %u (referrer=%s)\n", methodIdx, 5942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden referrer->descriptor); 5952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 5962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx); 5972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resMethod == NULL) { 5982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden const DexMethodId* pMethodId; 5992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* resClass; 6002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 6012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx); 6022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 6032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure); 6042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resClass == NULL) { 6052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 6062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Can't find the class that the method is a part of, or don't 6072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * have permission to access the class. 6082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 6092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGV("DexOpt: can't find called method's class (?.%s)\n", 6102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx)); 6112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); } 6122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 6132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 6142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (dvmIsInterfaceClass(resClass)) { 6152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* method is part of an interface; this is wrong method for that */ 6162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGW("DexOpt: method is in an interface\n"); 6172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 6182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_GENERIC; 6192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 6202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 6212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 6222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 6232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * We need to chase up the class hierarchy to find methods defined 6242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * in super-classes. (We only want to check the current class 6252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * if we're looking for a constructor.) 6262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 6272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden DexProto proto; 6282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId); 6292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 6302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (methodType == METHOD_DIRECT) { 6312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resMethod = dvmFindDirectMethod(resClass, 6322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto); 6332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } else { 6342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* METHOD_STATIC or METHOD_VIRTUAL */ 6352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resMethod = dvmFindMethodHier(resClass, 6362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto); 6372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 6382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 6392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resMethod == NULL) { 6402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGV("DexOpt: couldn't find method '%s'\n", 6412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx)); 6422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 6432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_NO_METHOD; 6442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 6452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 6462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (methodType == METHOD_STATIC) { 6472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!dvmIsStaticMethod(resMethod)) { 6482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGD("DexOpt: wanted static, got instance for method %s.%s\n", 6492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass->descriptor, resMethod->name); 6502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 6512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_CLASS_CHANGE; 6522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 6532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 6542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } else if (methodType == METHOD_VIRTUAL) { 6552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (dvmIsStaticMethod(resMethod)) { 6562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGD("DexOpt: wanted instance, got static for method %s.%s\n", 6572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass->descriptor, resMethod->name); 6582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 6592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_CLASS_CHANGE; 6602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 6612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 6622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 6632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 6642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* see if this is a pure-abstract method */ 6652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) { 6662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGW("DexOpt: pure-abstract method '%s' in %s\n", 6672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), 6682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass->descriptor); 6692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 6702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_GENERIC; 6712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 6722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 6732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 6742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 6752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Add it to the resolved table so we're faster on the next lookup. 6762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 6772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * We can only do this for static methods if we're not in "dexopt", 6782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * because the presence of a valid value in the resolution table 6792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * implies that the class containing the static field has been 6802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * initialized. 6812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 6822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (methodType != METHOD_STATIC || gDvm.optimizing) 6832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod); 6842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 6852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 6862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGVV("--- found method %d (%s.%s)\n", 6872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden methodIdx, resMethod->clazz->descriptor, resMethod->name); 6882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 6892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* access allowed? */ 6902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden tweakLoader(referrer, resMethod->clazz); 6912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden bool allowed = dvmCheckMethodAccess(referrer, resMethod); 6922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden untweakLoader(referrer, resMethod->clazz); 6932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!allowed) { 6942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden IF_LOGI() { 6952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype); 6962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGI("DexOpt: illegal method access (call %s.%s %s from %s)\n", 6972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resMethod->clazz->descriptor, resMethod->name, desc, 6982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden referrer->descriptor); 6992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden free(desc); 7002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 7012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (pFailure != NULL) 7022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden *pFailure = VERIFY_ERROR_ACCESS_METHOD; 7032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 7042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 7052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 7062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return resMethod; 7072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 7082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 7092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 7102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Rewrite invoke-virtual, invoke-virtual/range, invoke-super, and 7112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * invoke-super/range. These all have the form: 7122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * op vAA, meth@BBBB, reg stuff @CCCC 7132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 7142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * We want to replace the method constant pool index BBBB with the 7152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * vtable index. 7162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 7172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteVirtualInvoke(Method* method, u2* insns, OpCode newOpc) 7182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 7192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* clazz = method->clazz; 7202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden Method* baseMethod; 7212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden u2 methodIdx = insns[1]; 7222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 7232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL, NULL); 7242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (baseMethod == NULL) { 7252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGD("DexOpt: unable to optimize virt call 0x%04x at 0x%02x in %s.%s\n", 7262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden methodIdx, 7272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden (int) (insns - method->insns), clazz->descriptor, 7282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden method->name); 7292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return false; 7302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 7312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 7322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert((insns[0] & 0xff) == OP_INVOKE_VIRTUAL || 7332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE || 7342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden (insns[0] & 0xff) == OP_INVOKE_SUPER || 7352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden (insns[0] & 0xff) == OP_INVOKE_SUPER_RANGE); 7362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 7372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 7382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Note: Method->methodIndex is a u2 and is range checked during the 7392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * initial load. 7402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 7412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden insns[0] = (insns[0] & 0xff00) | (u2) newOpc; 7422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden insns[1] = baseMethod->methodIndex; 7432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 7442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden //LOGI("DexOpt: rewrote call to %s.%s --> %s.%s\n", 7452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden // method->clazz->descriptor, method->name, 7462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden // baseMethod->clazz->descriptor, baseMethod->name); 7472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 7482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return true; 7492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 7502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 7512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 7522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Rewrite invoke-direct, which has the form: 7532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * op vAA, meth@BBBB, reg stuff @CCCC 7542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 7552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * There isn't a lot we can do to make this faster, but in some situations 7562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * we can make it go away entirely. 7572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 7582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * This must only be used when the invoked method does nothing and has 7592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * no return value (the latter being very important for verification). 7602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 7612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteEmptyDirectInvoke(Method* method, u2* insns) 7622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 7632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* clazz = method->clazz; 7642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden Method* calledMethod; 7652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden u2 methodIdx = insns[1]; 7662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 7672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL); 7682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (calledMethod == NULL) { 7692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s\n", 7702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden methodIdx, 7712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden (int) (insns - method->insns), clazz->descriptor, 7722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden method->name); 7732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return false; 7742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 7752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 7762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* TODO: verify that java.lang.Object() is actually empty! */ 7772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (calledMethod->clazz == gDvm.classJavaLangObject && 7782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0) 7792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden { 7802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 7812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Replace with "empty" instruction. DO NOT disturb anything 7822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * else about it, as we want it to function the same as 7832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * OP_INVOKE_DIRECT when debugging is enabled. 7842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 7852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert((insns[0] & 0xff) == OP_INVOKE_DIRECT); 7862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden insns[0] = (insns[0] & 0xff00) | (u2) OP_INVOKE_DIRECT_EMPTY; 7872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 7882e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden //LOGI("DexOpt: marked-empty call to %s.%s --> %s.%s\n", 7892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden // method->clazz->descriptor, method->name, 7902e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden // calledMethod->clazz->descriptor, calledMethod->name); 7912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 7922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 7932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return true; 7942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 7952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 7962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 7972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Resolve an interface method reference. 7982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 7992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * No method access check here -- interface methods are always public. 8002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 8012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns NULL if the method was not found. Does not throw an exception. 8022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 8032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenMethod* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx) 8042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 8052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden DvmDex* pDvmDex = referrer->pDvmDex; 8062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden Method* resMethod; 8072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden int i; 8082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGVV("--- resolving interface method %d (referrer=%s)\n", 8102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden methodIdx, referrer->descriptor); 8112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx); 8132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resMethod == NULL) { 8142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden const DexMethodId* pMethodId; 8152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* resClass; 8162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx); 8182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, NULL); 8202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resClass == NULL) { 8212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* can't find the class that the method is a part of */ 8222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dvmClearOptException(dvmThreadSelf()); 8232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 8242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 8252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!dvmIsInterfaceClass(resClass)) { 8262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* whoops */ 8272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGI("Interface method not part of interface class\n"); 8282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 8292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 8302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden const char* methodName = 8322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx); 8332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden DexProto proto; 8342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId); 8352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGVV("+++ looking for '%s' '%s' in resClass='%s'\n", 8372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden methodName, methodSig, resClass->descriptor); 8382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resMethod = dvmFindVirtualMethod(resClass, methodName, &proto); 8392e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resMethod == NULL) { 8402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* scan superinterfaces and superclass interfaces */ 8412e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGVV("+++ did not resolve immediately\n"); 8422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden for (i = 0; i < resClass->iftableCount; i++) { 8432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resMethod = dvmFindVirtualMethod(resClass->iftable[i].clazz, 8442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden methodName, &proto); 8452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resMethod != NULL) 8462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden break; 8472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 8482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (resMethod == NULL) { 8502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGVV("+++ unable to resolve method %s\n", methodName); 8512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 8522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 8532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } else { 8542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGVV("+++ resolved immediately: %s (%s %d)\n", resMethod->name, 8552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resMethod->clazz->descriptor, (u4) resMethod->methodIndex); 8562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 8572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* we're expecting this to be abstract */ 8592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (!dvmIsAbstractMethod(resMethod)) { 8602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype); 8612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGW("Found non-abstract interface method %s.%s %s\n", 8622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden resMethod->clazz->descriptor, resMethod->name, desc); 8632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden free(desc); 8642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return NULL; 8652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 8662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 8682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Add it to the resolved table so we're faster on the next lookup. 8692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 8702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod); 8712e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 8722e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8732e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGVV("--- found interface method %d (%s.%s)\n", 8742e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden methodIdx, resMethod->clazz->descriptor, resMethod->name); 8752e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8762e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* interface methods are always public; no need to check access */ 8772e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8782e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return resMethod; 8792e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 8802e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8812e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 8822e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * See if the method being called can be rewritten as an inline operation. 8832e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Works for invoke-virtual, invoke-direct, and invoke-static. 8842e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 8852e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" if we replace it. 8862e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 8872e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInline(Method* method, u2* insns, 888cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden MethodType methodType) 8892e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 890cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden const InlineSub* inlineSubs = gDvm.inlineSubs; 8912e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* clazz = method->clazz; 8922e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden Method* calledMethod; 8932e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden u2 methodIdx = insns[1]; 8942e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8952e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden //return false; 8962e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 8972e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL); 8982e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (calledMethod == NULL) { 8992e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGV("+++ DexOpt inline: can't find %d\n", methodIdx); 9002e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return false; 9012e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 9022e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9032e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden while (inlineSubs->method != NULL) { 9042e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden /* 9052e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (extra) { 9062e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGI("comparing %p vs %p %s.%s %s\n", 9072e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden inlineSubs->method, calledMethod, 9082e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden inlineSubs->method->clazz->descriptor, 9092e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden inlineSubs->method->name, 9102e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden inlineSubs->method->signature); 9112e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 9122e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 9132e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (inlineSubs->method == calledMethod) { 9142e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert((insns[0] & 0xff) == OP_INVOKE_DIRECT || 9152e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden (insns[0] & 0xff) == OP_INVOKE_STATIC || 9162e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden (insns[0] & 0xff) == OP_INVOKE_VIRTUAL); 9172e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden insns[0] = (insns[0] & 0xff00) | (u2) OP_EXECUTE_INLINE; 9182e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden insns[1] = (u2) inlineSubs->inlineIdx; 9192e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9202e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden //LOGI("DexOpt: execute-inline %s.%s --> %s.%s\n", 9212e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden // method->clazz->descriptor, method->name, 9222e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden // calledMethod->clazz->descriptor, calledMethod->name); 9232e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return true; 9242e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 9252e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9262e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden inlineSubs++; 9272e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 9282e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9292e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return false; 9302e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 9312e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9322e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden/* 9332e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * See if the method being called can be rewritten as an inline operation. 9342e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Works for invoke-virtual/range, invoke-direct/range, and invoke-static/range. 9352e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * 9362e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden * Returns "true" if we replace it. 9372e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden */ 9382e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFaddenstatic bool rewriteExecuteInlineRange(Method* method, u2* insns, 939cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden MethodType methodType) 9402e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden{ 941cb3c542b8712b7ef005aabc4b8139c667afc7a9dAndy McFadden const InlineSub* inlineSubs = gDvm.inlineSubs; 9422e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden ClassObject* clazz = method->clazz; 9432e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden Method* calledMethod; 9442e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden u2 methodIdx = insns[1]; 9452e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9462e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL); 9472e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (calledMethod == NULL) { 9482e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden LOGV("+++ DexOpt inline/range: can't find %d\n", methodIdx); 9492e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return false; 9502e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 9512e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9522e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden while (inlineSubs->method != NULL) { 9532e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden if (inlineSubs->method == calledMethod) { 9542e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden assert((insns[0] & 0xff) == OP_INVOKE_DIRECT_RANGE || 9552e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden (insns[0] & 0xff) == OP_INVOKE_STATIC_RANGE || 9562e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE); 9572e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden insns[0] = (insns[0] & 0xff00) | (u2) OP_EXECUTE_INLINE_RANGE; 9582e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden insns[1] = (u2) inlineSubs->inlineIdx; 9592e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9602e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden //LOGI("DexOpt: execute-inline/range %s.%s --> %s.%s\n", 9612e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden // method->clazz->descriptor, method->name, 9622e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden // calledMethod->clazz->descriptor, calledMethod->name); 9632e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return true; 9642e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 9652e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9662e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden inlineSubs++; 9672e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden } 9682e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden 9692e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden return false; 9702e1ee50a08cc3dd07ce4e956b925c1f0f28cf329Andy McFadden} 971