Interp.c revision e3c01dac83e6eea7f82fe81ed89cfbdd9791dbc9
12ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/* 22ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 32ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 42ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 52ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * you may not use this file except in compliance with the License. 62ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * You may obtain a copy of the License at 72ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 82ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 92ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * See the License for the specific language governing permissions and 142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * limitations under the License. 152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 1689c1feb0a69a7707b271086e749975b3f7acacf7The Android Open Source Project 172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/* 182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Main interpreter entry point and support functions. 192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * The entry point selects the "standard" or "debug" interpreter and 212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * facilitates switching between them. The standard interpreter may 222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * use the "fast" or "portable" implementation. 232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Some debugger support functions are included here. Ideally their 252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * entire existence would be "#ifdef WITH_DEBUGGER", but we're not that 262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * aggressive in other parts of the code yet. 272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#include "Dalvik.h" 292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#include "interp/InterpDefs.h" 302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/* 332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * =========================================================================== 342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Debugger support 352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * =========================================================================== 362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 3896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden// fwd 3996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic BreakpointSet* dvmBreakpointSetAlloc(void); 4096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic void dvmBreakpointSetFree(BreakpointSet* pSet); 4196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/* 4396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Initialize global breakpoint structures. 4496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 4596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenbool dvmBreakpointStartup(void) 4696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{ 4796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden#ifdef WITH_DEBUGGER 4896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden gDvm.breakpointSet = dvmBreakpointSetAlloc(); 4996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden return (gDvm.breakpointSet != NULL); 5096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden#else 5196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden return true; 5296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden#endif 5396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden} 5496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 5596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/* 5696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Free resources. 5796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 5896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenvoid dvmBreakpointShutdown(void) 5996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{ 6096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden#ifdef WITH_DEBUGGER 6196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden dvmBreakpointSetFree(gDvm.breakpointSet); 6296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden#endif 6396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden} 6496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 6596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 6696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden#ifdef WITH_DEBUGGER 6796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/* 6896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * This represents a breakpoint inserted in the instruction stream. 692ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 7096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The debugger may ask us to create the same breakpoint multiple times. 7196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * We only remove the breakpoint when the last instance is cleared. 7296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 7396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddentypedef struct { 74d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden Method* method; /* method we're associated with */ 7596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden u2* addr; /* absolute memory address */ 7696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden u1 originalOpCode; /* original 8-bit opcode value */ 7796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden int setCount; /* #of times this breakpoint was set */ 7896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden} Breakpoint; 7996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 8096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/* 8196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Set of breakpoints. 8296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 8396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstruct BreakpointSet { 8496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden /* grab lock before reading or writing anything else in here */ 8596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden pthread_mutex_t lock; 8696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 8796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden /* vector of breakpoint structures */ 8896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden int alloc; 8996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden int count; 9096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden Breakpoint* breakpoints; 9196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}; 9296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 9396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/* 9496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Initialize a BreakpointSet. Initially empty. 9596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 9696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic BreakpointSet* dvmBreakpointSetAlloc(void) 9796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{ 9896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden BreakpointSet* pSet = (BreakpointSet*) calloc(1, sizeof(*pSet)); 9996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 10096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden dvmInitMutex(&pSet->lock); 10196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden /* leave the rest zeroed -- will alloc on first use */ 10296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 10396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden return pSet; 10496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden} 10596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 10696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/* 10796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Free storage associated with a BreakpointSet. 10896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 10996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic void dvmBreakpointSetFree(BreakpointSet* pSet) 11096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{ 11196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden if (pSet == NULL) 11296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden return; 11396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 11496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden free(pSet->breakpoints); 11596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden free(pSet); 11696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden} 11796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 11896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/* 11996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Lock the breakpoint set. 120d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * 121d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * It's not currently necessary to switch to VMWAIT in the event of 122d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * contention, because nothing in here can block. However, it's possible 123d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * that the bytecode-updater code could become fancier in the future, so 124d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * we do the trylock dance as a bit of future-proofing. 12596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 12696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic void dvmBreakpointSetLock(BreakpointSet* pSet) 12796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{ 128d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden if (dvmTryLockMutex(&pSet->lock) != 0) { 129d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden Thread* self = dvmThreadSelf(); 130d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden int oldStatus = dvmChangeStatus(self, THREAD_VMWAIT); 131d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden dvmLockMutex(&pSet->lock); 132d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden dvmChangeStatus(self, oldStatus); 133d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden } 13496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden} 13596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 13696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/* 13796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Unlock the breakpoint set. 13896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 13996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic void dvmBreakpointSetUnlock(BreakpointSet* pSet) 14096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{ 14196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden dvmUnlockMutex(&pSet->lock); 14296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden} 14396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 14496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/* 14596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Return the #of breakpoints. 14696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 14796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic int dvmBreakpointSetCount(const BreakpointSet* pSet) 14896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{ 14996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden return pSet->count; 15096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden} 15196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 15296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/* 15396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * See if we already have an entry for this address. 15496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * 15596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The BreakpointSet's lock must be acquired before calling here. 15696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * 15796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Returns the index of the breakpoint entry, or -1 if not found. 15896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 15996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic int dvmBreakpointSetFind(const BreakpointSet* pSet, const u2* addr) 16096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{ 16196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden int i; 16296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 16396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden for (i = 0; i < pSet->count; i++) { 16496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden Breakpoint* pBreak = &pSet->breakpoints[i]; 16596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden if (pBreak->addr == addr) 16696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden return i; 16796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } 16896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 16996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden return -1; 17096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden} 17196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 17296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/* 17396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Retrieve the opcode that was originally at the specified location. 17496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * 17596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The BreakpointSet's lock must be acquired before calling here. 17696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * 17796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Returns "true" with the opcode in *pOrig on success. 17896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 17996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic bool dvmBreakpointSetOriginalOpCode(const BreakpointSet* pSet, 18096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden const u2* addr, u1* pOrig) 18196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{ 18296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden int idx = dvmBreakpointSetFind(pSet, addr); 18396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden if (idx < 0) 18496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden return false; 18596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 18696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *pOrig = pSet->breakpoints[idx].originalOpCode; 18796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden return true; 18896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden} 18996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 19096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/* 191da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * Check the opcode. If it's a "magic" NOP, indicating the start of 192da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * switch or array data in the instruction stream, we don't want to set 193da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * a breakpoint. 194da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * 195da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * This can happen because the line number information dx generates 196da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * associates the switch data with the switch statement's line number, 197da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * and some debuggers put breakpoints at every address associated with 198da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * a given line. The result is that the breakpoint stomps on the NOP 199da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * instruction that doubles as a data table magic number, and an explicit 200da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * check in the interpreter results in an exception being thrown. 201da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * 202da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * We don't want to simply refuse to add the breakpoint to the table, 203da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * because that confuses the housekeeping. We don't want to reject the 204da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * debugger's event request, and we want to be sure that there's exactly 205da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * one un-set operation for every set op. 206da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden */ 207da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFaddenstatic bool instructionIsMagicNop(const u2* addr) 208da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden{ 209da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden u2 curVal = *addr; 210da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden return ((curVal & 0xff) == OP_NOP && (curVal >> 8) != 0); 211da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden} 212da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden 213da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden/* 21496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Add a breakpoint at a specific address. If the address is already 21596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * present in the table, this just increments the count. 21696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * 21796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * For a new entry, this will extract and preserve the current opcode from 21896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * the instruction stream, and replace it with a breakpoint opcode. 21996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * 22096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The BreakpointSet's lock must be acquired before calling here. 22196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * 22296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Returns "true" on success. 22396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 22496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic bool dvmBreakpointSetAdd(BreakpointSet* pSet, Method* method, 22596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden unsigned int instrOffset) 22696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{ 22796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden const int kBreakpointGrowth = 10; 22896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden const u2* addr = method->insns + instrOffset; 22996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden int idx = dvmBreakpointSetFind(pSet, addr); 23096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden Breakpoint* pBreak; 23196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 23296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden if (idx < 0) { 23396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden if (pSet->count == pSet->alloc) { 23496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden int newSize = pSet->alloc + kBreakpointGrowth; 23596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden Breakpoint* newVec; 23696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 23796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden LOGV("+++ increasing breakpoint set size to %d\n", newSize); 23896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 23996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden /* pSet->breakpoints will be NULL on first entry */ 24096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden newVec = realloc(pSet->breakpoints, newSize * sizeof(Breakpoint)); 24196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden if (newVec == NULL) 24296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden return false; 24396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 24496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden pSet->breakpoints = newVec; 24596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden pSet->alloc = newSize; 24696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } 24796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 24896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden pBreak = &pSet->breakpoints[pSet->count++]; 249d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden pBreak->method = method; 25096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden pBreak->addr = (u2*)addr; 25196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden pBreak->originalOpCode = *(u1*)addr; 25296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden pBreak->setCount = 1; 25396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 25496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden /* 25596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Change the opcode. We must ensure that the BreakpointSet 25696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * updates happen before we change the opcode. 257d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * 258d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * If the method has not been verified, we do NOT insert the 259d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * breakpoint yet, since that will screw up the verifier. The 260d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * debugger is allowed to insert breakpoints in unverified code, 261d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * but since we don't execute unverified code we don't need to 262d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * alter the bytecode yet. 263d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * 264c7a12b2fc8270722c7de8d24fd8fa943e5ef1818Andy McFadden * The class init code will "flush" all pending opcode writes 265c7a12b2fc8270722c7de8d24fd8fa943e5ef1818Andy McFadden * before verification completes. 26696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 26796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden assert(*(u1*)addr != OP_BREAKPOINT); 268d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden if (dvmIsClassVerified(method->clazz)) { 269d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden LOGV("Class %s verified, adding breakpoint at %p\n", 270d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden method->clazz->descriptor, addr); 271da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden if (instructionIsMagicNop(addr)) { 272da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden LOGV("Refusing to set breakpoint on %04x at %s.%s + 0x%x\n", 273da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden *addr, method->clazz->descriptor, method->name, 274da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden instrOffset); 275da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden } else { 276da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden MEM_BARRIER(); 277da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr, 278da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden OP_BREAKPOINT); 279da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden } 280d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden } else { 281d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden LOGV("Class %s NOT verified, deferring breakpoint at %p\n", 282d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden method->clazz->descriptor, addr); 283d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden } 28496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } else { 285d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden /* 286c7a12b2fc8270722c7de8d24fd8fa943e5ef1818Andy McFadden * Breakpoint already exists, just increase the count. 287d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden */ 288c7a12b2fc8270722c7de8d24fd8fa943e5ef1818Andy McFadden pBreak = &pSet->breakpoints[idx]; 289c7a12b2fc8270722c7de8d24fd8fa943e5ef1818Andy McFadden pBreak->setCount++; 29096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } 29196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 29296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden return true; 29396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden} 29496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 29596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/* 29696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Remove one instance of the specified breakpoint. When the count 29796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * reaches zero, the entry is removed from the table, and the original 29896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * opcode is restored. 29996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * 30096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The BreakpointSet's lock must be acquired before calling here. 30196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 30296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic void dvmBreakpointSetRemove(BreakpointSet* pSet, Method* method, 30396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden unsigned int instrOffset) 30496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{ 30596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden const u2* addr = method->insns + instrOffset; 30696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden int idx = dvmBreakpointSetFind(pSet, addr); 30796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 30896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden if (idx < 0) { 30996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden /* breakpoint not found in set -- unexpected */ 31096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden if (*(u1*)addr == OP_BREAKPOINT) { 311da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden LOGE("Unable to restore breakpoint opcode (%s.%s +0x%x)\n", 31296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden method->clazz->descriptor, method->name, instrOffset); 31396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden dvmAbort(); 31496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } else { 315da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden LOGW("Breakpoint was already restored? (%s.%s +0x%x)\n", 31696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden method->clazz->descriptor, method->name, instrOffset); 31796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } 31896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } else { 31996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden Breakpoint* pBreak = &pSet->breakpoints[idx]; 32096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden if (pBreak->setCount == 1) { 32196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden /* 32296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Must restore opcode before removing set entry. 323d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * 324d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * If the breakpoint was never flushed, we could be ovewriting 325d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * a value with the same value. Not a problem, though we 326d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * could end up causing a copy-on-write here when we didn't 327d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * need to. (Not worth worrying about.) 32896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 32996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr, 33096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden pBreak->originalOpCode); 33196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden MEM_BARRIER(); 33296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 33396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden if (idx != pSet->count-1) { 33496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden /* shift down */ 33596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden memmove(&pSet->breakpoints[idx], &pSet->breakpoints[idx+1], 33696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden (pSet->count-1 - idx) * sizeof(pSet->breakpoints[0])); 33796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } 33896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden pSet->count--; 33996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden pSet->breakpoints[pSet->count].addr = (u2*) 0xdecadead; // debug 34096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } else { 34196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden pBreak->setCount--; 34296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden assert(pBreak->setCount > 0); 34396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } 34496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } 34596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden} 34696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 34796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/* 348d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * Flush any breakpoints associated with methods in "clazz". We want to 349d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * change the opcode, which might not have happened when the breakpoint 350d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * was initially set because the class was in the process of being 351d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * verified. 35296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * 35396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The BreakpointSet's lock must be acquired before calling here. 35496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 355d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFaddenstatic void dvmBreakpointSetFlush(BreakpointSet* pSet, ClassObject* clazz) 35696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{ 35796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden int i; 35896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden for (i = 0; i < pSet->count; i++) { 35996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden Breakpoint* pBreak = &pSet->breakpoints[i]; 360d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden if (pBreak->method->clazz == clazz) { 361d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden /* 362d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * The breakpoint is associated with a method in this class. 363d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * It might already be there or it might not; either way, 364d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * flush it out. 365d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden */ 366d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden LOGV("Flushing breakpoint at %p for %s\n", 367d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden pBreak->addr, clazz->descriptor); 368da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden if (instructionIsMagicNop(pBreak->addr)) { 369da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden LOGV("Refusing to flush breakpoint on %04x at %s.%s + 0x%x\n", 370e3c01dac83e6eea7f82fe81ed89cfbdd9791dbc9Carl Shapiro *pBreak->addr, pBreak->method->clazz->descriptor, 371e3c01dac83e6eea7f82fe81ed89cfbdd9791dbc9Carl Shapiro pBreak->method->name, pBreak->addr - pBreak->method->insns); 372da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden } else { 373da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden dvmDexChangeDex1(clazz->pDvmDex, (u1*)pBreak->addr, 374da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden OP_BREAKPOINT); 375da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden } 37696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } 37796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } 37896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden} 37996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden#endif /*WITH_DEBUGGER*/ 38096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 38196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 38296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/* 38396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Do any debugger-attach-time initialization. 3842ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 3852ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectvoid dvmInitBreakpoints(void) 3862ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{ 3872ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#ifdef WITH_DEBUGGER 38896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden /* quick sanity check */ 38996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden BreakpointSet* pSet = gDvm.breakpointSet; 39096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden dvmBreakpointSetLock(pSet); 39196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden if (dvmBreakpointSetCount(pSet) != 0) { 39296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden LOGW("WARNING: %d leftover breakpoints\n", dvmBreakpointSetCount(pSet)); 39396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden /* generally not good, but we can keep going */ 39496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } 39596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden dvmBreakpointSetUnlock(pSet); 3962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#else 3972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(false); 3982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif 3992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project} 4002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 4012ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/* 4022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Add an address to the list, putting it in the first non-empty slot. 4032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 4042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Sometimes the debugger likes to add two entries for one breakpoint. 4052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * We add two entries here, so that we get the right behavior when it's 4062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * removed twice. 4072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 4082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * This will only be run from the JDWP thread, and it will happen while 4092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * we are updating the event list, which is synchronized. We're guaranteed 4102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * to be the only one adding entries, and the lock ensures that nobody 4112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * will be trying to remove them while we're in here. 4122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 4132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * "addr" is the absolute address of the breakpoint bytecode. 4142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 41596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenvoid dvmAddBreakAddr(Method* method, unsigned int instrOffset) 4162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{ 4172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#ifdef WITH_DEBUGGER 41896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden BreakpointSet* pSet = gDvm.breakpointSet; 41996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden dvmBreakpointSetLock(pSet); 42096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden dvmBreakpointSetAdd(pSet, method, instrOffset); 42196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden dvmBreakpointSetUnlock(pSet); 4222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#else 4232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(false); 4242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif 4252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project} 4262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 4272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/* 4282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Remove an address from the list by setting the entry to NULL. 4292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 4302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * This can be called from the JDWP thread (because the debugger has 4312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * cancelled the breakpoint) or from an event thread (because it's a 4322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * single-shot breakpoint, e.g. "run to line"). We only get here as 4332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * the result of removing an entry from the event list, which is 4342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * synchronized, so it should not be possible for two threads to be 4352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * updating breakpoints at the same time. 4362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 43796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenvoid dvmClearBreakAddr(Method* method, unsigned int instrOffset) 4382ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{ 4392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#ifdef WITH_DEBUGGER 44096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden BreakpointSet* pSet = gDvm.breakpointSet; 44196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden dvmBreakpointSetLock(pSet); 44296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden dvmBreakpointSetRemove(pSet, method, instrOffset); 44396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden dvmBreakpointSetUnlock(pSet); 4442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 4452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#else 4462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(false); 4472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif 4482ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project} 4492ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 45096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden#ifdef WITH_DEBUGGER 45196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/* 45296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Get the original opcode from under a breakpoint. 45396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 45496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenu1 dvmGetOriginalOpCode(const u2* addr) 45596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{ 45696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden BreakpointSet* pSet = gDvm.breakpointSet; 45796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden u1 orig = 0; 45896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 45996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden dvmBreakpointSetLock(pSet); 46096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden if (!dvmBreakpointSetOriginalOpCode(pSet, addr, &orig)) { 46196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden orig = *(u1*)addr; 46296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden if (orig == OP_BREAKPOINT) { 46396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden LOGE("GLITCH: can't find breakpoint, opcode is still set\n"); 46496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden dvmAbort(); 46596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } 46696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden } 46796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden dvmBreakpointSetUnlock(pSet); 46896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 46996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden return orig; 47096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden} 47196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 47296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/* 473d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * Flush any breakpoints associated with methods in "clazz". 47496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * 475d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * We don't want to modify the bytecode of a method before the verifier 476d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * gets a chance to look at it, so we postpone opcode replacement until 477d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * after verification completes. 47896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */ 479d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFaddenvoid dvmFlushBreakpoints(ClassObject* clazz) 48096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{ 48196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden BreakpointSet* pSet = gDvm.breakpointSet; 48296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 483d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden if (pSet == NULL) 484d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden return; 48596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 486d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden assert(dvmIsClassVerified(clazz)); 487d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden dvmBreakpointSetLock(pSet); 488d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden dvmBreakpointSetFlush(pSet, clazz); 48996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden dvmBreakpointSetUnlock(pSet); 49096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden} 49196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden#endif 49296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden 4932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/* 4942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Add a single step event. Currently this is a global item. 4952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 4962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * We set up some initial values based on the thread's current state. This 4972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * won't work well if the thread is running, so it's up to the caller to 4982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * verify that it's suspended. 4992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 5002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * This is only called from the JDWP thread. 5012ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 5022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectbool dvmAddSingleStep(Thread* thread, int size, int depth) 5032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{ 5042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#ifdef WITH_DEBUGGER 5052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project StepControl* pCtrl = &gDvm.stepControl; 5062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 5072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (pCtrl->active && thread != pCtrl->thread) { 5082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOGW("WARNING: single-step active for %p; adding %p\n", 5092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project pCtrl->thread, thread); 5102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 5112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* 5122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Keep going, overwriting previous. This can happen if you 5132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * suspend a thread in Object.wait, hit the single-step key, then 5142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * switch to another thread and do the same thing again. 5152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * The first thread's step is still pending. 5162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 5172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * TODO: consider making single-step per-thread. Adds to the 5182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * overhead, but could be useful in rare situations. 5192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 5202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 5212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 5222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project pCtrl->size = size; 5232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project pCtrl->depth = depth; 5242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project pCtrl->thread = thread; 5252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 5262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* 5272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * We may be stepping into or over method calls, or running until we 5282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * return from the current method. To make this work we need to track 5292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * the current line, current method, and current stack depth. We need 5302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * to be checking these after most instructions, notably those that 5312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * call methods, return from methods, or are on a different line from the 5322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * previous instruction. 5332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 5342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * We have to start with a snapshot of the current state. If we're in 5352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * an interpreted method, everything we need is in the current frame. If 5362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * we're in a native method, possibly with some extra JNI frames pushed 5372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * on by PushLocalFrame, we want to use the topmost native method. 5382ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 5392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project const StackSaveArea* saveArea; 5402ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project void* fp; 5412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project void* prevFp = NULL; 54238329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng 5432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project for (fp = thread->curFrame; fp != NULL; fp = saveArea->prevFrame) { 5442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project const Method* method; 5452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 5462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project saveArea = SAVEAREA_FROM_FP(fp); 5472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project method = saveArea->method; 5482ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 5492ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (!dvmIsBreakFrame(fp) && !dvmIsNativeMethod(method)) 5502ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project break; 5512ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project prevFp = fp; 5522ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 5532ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (fp == NULL) { 5542ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOGW("Unexpected: step req in native-only threadid=%d\n", 5552ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project thread->threadId); 5562ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return false; 5572ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 5582ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (prevFp != NULL) { 5592ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* 5602ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * First interpreted frame wasn't the one at the bottom. Break 5612ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * frames are only inserted when calling from native->interp, so we 5622ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * don't need to worry about one being here. 5632ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 5642ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOGV("##### init step while in native method\n"); 5652ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project fp = prevFp; 5662ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(!dvmIsBreakFrame(fp)); 5672ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(dvmIsNativeMethod(SAVEAREA_FROM_FP(fp)->method)); 5682ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project saveArea = SAVEAREA_FROM_FP(fp); 5692ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 5702ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 5712ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* 5722ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Pull the goodies out. "xtra.currentPc" should be accurate since 5732ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * we update it on every instruction while the debugger is connected. 5742ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 5752ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project pCtrl->method = saveArea->method; 5762ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project // Clear out any old address set 5772ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (pCtrl->pAddressSet != NULL) { 5782ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project // (discard const) 5792ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project free((void *)pCtrl->pAddressSet); 5802ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project pCtrl->pAddressSet = NULL; 5812ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 5822ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (dvmIsNativeMethod(pCtrl->method)) { 5832ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project pCtrl->line = -1; 5842ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } else { 5852ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project pCtrl->line = dvmLineNumFromPC(saveArea->method, 5862ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project saveArea->xtra.currentPc - saveArea->method->insns); 58738329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng pCtrl->pAddressSet 5882ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project = dvmAddressSetForLine(saveArea->method, pCtrl->line); 5892ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 5902ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project pCtrl->frameDepth = dvmComputeVagueFrameDepth(thread, thread->curFrame); 5912ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project pCtrl->active = true; 5922ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 5932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOGV("##### step init: thread=%p meth=%p '%s' line=%d frameDepth=%d depth=%s size=%s\n", 5942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project pCtrl->thread, pCtrl->method, pCtrl->method->name, 5952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project pCtrl->line, pCtrl->frameDepth, 5962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project dvmJdwpStepDepthStr(pCtrl->depth), 5972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project dvmJdwpStepSizeStr(pCtrl->size)); 5982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 5992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return true; 6002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#else 6012ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(false); 6022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return false; 6032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif 6042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project} 6052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 6062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/* 6072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Disable a single step event. 6082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 6092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectvoid dvmClearSingleStep(Thread* thread) 6102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{ 6112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#ifdef WITH_DEBUGGER 6122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project UNUSED_PARAMETER(thread); 6132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 6142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project gDvm.stepControl.active = false; 6152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#else 6162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(false); 6172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif 6182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project} 6192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 6202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 6212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/* 6222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Recover the "this" pointer from the current interpreted method. "this" 6232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * is always in "in0" for non-static methods. 6242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 6252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * The "ins" start at (#of registers - #of ins). Note in0 != v0. 6262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 6272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * This works because "dx" guarantees that it will work. It's probably 6282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * fairly common to have a virtual method that doesn't use its "this" 6292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * pointer, in which case we're potentially wasting a register. However, 6302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * the debugger doesn't treat "this" as just another argument. For 6312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * example, events (such as breakpoints) can be enabled for specific 6322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * values of "this". There is also a separate StackFrame.ThisObject call 6332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * in JDWP that is expected to work for any non-native non-static method. 6342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 6352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Because we need it when setting up debugger event filters, we want to 6362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * be able to do this quickly. 6372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 6382ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source ProjectObject* dvmGetThisPtr(const Method* method, const u4* fp) 6392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{ 6402ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (dvmIsStaticMethod(method)) 6412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return NULL; 6422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return (Object*)fp[method->registersSize - method->insSize]; 6432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project} 6442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 6452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 6462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#if defined(WITH_TRACKREF_CHECKS) 6472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/* 6482ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Verify that all internally-tracked references have been released. If 6492ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * they haven't, print them and abort the VM. 6502ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 6512ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * "debugTrackedRefStart" indicates how many refs were on the list when 6522ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * we were first invoked. 6532ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 6542ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectvoid dvmInterpCheckTrackedRefs(Thread* self, const Method* method, 6552ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project int debugTrackedRefStart) 6562ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{ 6572ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (dvmReferenceTableEntries(&self->internalLocalRefTable) 6582ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project != (size_t) debugTrackedRefStart) 6592ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project { 6602ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project char* desc; 6612ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project Object** top; 6622ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project int count; 6632ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 6642ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project count = dvmReferenceTableEntries(&self->internalLocalRefTable); 6652ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 6662ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOGE("TRACK: unreleased internal reference (prev=%d total=%d)\n", 6672ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project debugTrackedRefStart, count); 6682ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project desc = dexProtoCopyMethodDescriptor(&method->prototype); 6692ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOGE(" current method is %s.%s %s\n", method->clazz->descriptor, 6702ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project method->name, desc); 6712ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project free(desc); 6722ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project top = self->internalLocalRefTable.table + debugTrackedRefStart; 6732ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project while (top < self->internalLocalRefTable.nextEntry) { 6742ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOGE(" %p (%s)\n", 6752ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *top, 6762ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project ((*top)->clazz != NULL) ? (*top)->clazz->descriptor : ""); 6772ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project top++; 6782ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 6792ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project dvmDumpThread(self, false); 6802ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 6812ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project dvmAbort(); 6822ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 6832ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project //LOGI("TRACK OK\n"); 6842ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project} 6852ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif 6862ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 6872ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 6882ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#ifdef LOG_INSTR 6892ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/* 6902ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Dump the v-registers. Sent to the ILOG log tag. 6912ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 6922ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectvoid dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly) 6932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{ 6942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project int i, localCount; 6952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 6962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project localCount = method->registersSize - method->insSize; 6972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 6982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOG(LOG_VERBOSE, LOG_TAG"i", "Registers (fp=%p):\n", framePtr); 6992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project for (i = method->registersSize-1; i >= 0; i--) { 7002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (i >= localCount) { 7012ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOG(LOG_VERBOSE, LOG_TAG"i", " v%-2d in%-2d : 0x%08x\n", 7022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project i, i-localCount, framePtr[i]); 7032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } else { 7042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (inOnly) { 7052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOG(LOG_VERBOSE, LOG_TAG"i", " [...]\n"); 7062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project break; 7072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 7082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project const char* name = ""; 7092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project int j; 7102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#if 0 // "locals" structure has changed -- need to rewrite this 7112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project DexFile* pDexFile = method->clazz->pDexFile; 7122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project const DexCode* pDexCode = dvmGetMethodCode(method); 7132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project int localsSize = dexGetLocalsSize(pDexFile, pDexCode); 7142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project const DexLocal* locals = dvmDexGetLocals(pDexFile, pDexCode); 7152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project for (j = 0; j < localsSize, j++) { 7162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (locals[j].registerNum == (u4) i) { 7172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project name = dvmDexStringStr(locals[j].pName); 7182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project break; 7192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 7202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 7212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif 7222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOG(LOG_VERBOSE, LOG_TAG"i", " v%-2d : 0x%08x %s\n", 7232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project i, framePtr[i], name); 7242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 7252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 7262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project} 7272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif 7282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 7292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 7302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/* 7312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * =========================================================================== 7322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Entry point and general support functions 7332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * =========================================================================== 7342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 7352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 73638329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng/* 7372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Construct an s4 from two consecutive half-words of switch data. 7382ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * This needs to check endianness because the DEX optimizer only swaps 7392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * half-words in instruction stream. 7402ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 7412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * "switchData" must be 32-bit aligned. 7422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 7432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#if __BYTE_ORDER == __LITTLE_ENDIAN 7442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectstatic inline s4 s4FromSwitchData(const void* switchData) { 7452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return *(s4*) switchData; 7462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project} 7472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#else 7482ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectstatic inline s4 s4FromSwitchData(const void* switchData) { 7492ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project u2* data = switchData; 7502ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return data[0] | (((s4) data[1]) << 16); 751ffa5c29a95ee5cb32c5bb4c46eccb5a57f5f493bJay Freeman (saurik)} 7522ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif 7532ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 7542ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/* 7552ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Find the matching case. Returns the offset to the handler instructions. 7562ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 7572ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Returns 3 if we don't find a match (it's the size of the packed-switch 7582ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * instruction). 7592ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 7602ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projects4 dvmInterpHandlePackedSwitch(const u2* switchData, s4 testVal) 7612ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{ 7622ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project const int kInstrLen = 3; 7632ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project u2 size; 7642ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project s4 firstKey; 7652ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project const s4* entries; 7662ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 7672ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* 7682ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Packed switch data format: 7692ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * ushort ident = 0x0100 magic value 7702ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * ushort size number of entries in the table 7712ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * int first_key first (and lowest) switch case value 7722ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * int targets[size] branch targets, relative to switch opcode 7732ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 7742ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Total size is (4+size*2) 16-bit code units. 7752ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 7762ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (*switchData++ != kPackedSwitchSignature) { 7772ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* should have been caught by verifier */ 7782ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project dvmThrowException("Ljava/lang/InternalError;", 7792ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project "bad packed switch magic"); 7802ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return kInstrLen; 7812ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 7822ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 7832ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project size = *switchData++; 7842ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(size > 0); 7852ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 7862ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project firstKey = *switchData++; 7872ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project firstKey |= (*switchData++) << 16; 7882ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 7892ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (testVal < firstKey || testVal >= firstKey + size) { 7902ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOGVV("Value %d not found in switch (%d-%d)\n", 7912ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project testVal, firstKey, firstKey+size-1); 7922ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return kInstrLen; 7932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 7942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 7952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* The entries are guaranteed to be aligned on a 32-bit boundary; 7962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * we can treat them as a native int array. 7972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 7982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project entries = (const s4*) switchData; 7992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(((u4)entries & 0x3) == 0); 8002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 8012ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(testVal - firstKey >= 0 && testVal - firstKey < size); 8022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOGVV("Value %d found in slot %d (goto 0x%02x)\n", 8032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project testVal, testVal - firstKey, 8042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project s4FromSwitchData(&entries[testVal - firstKey])); 8052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return s4FromSwitchData(&entries[testVal - firstKey]); 8062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project} 8072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 8082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/* 8092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Find the matching case. Returns the offset to the handler instructions. 8102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 8112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Returns 3 if we don't find a match (it's the size of the sparse-switch 8122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * instruction). 8132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 8142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projects4 dvmInterpHandleSparseSwitch(const u2* switchData, s4 testVal) 8152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{ 8162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project const int kInstrLen = 3; 817e3c01dac83e6eea7f82fe81ed89cfbdd9791dbc9Carl Shapiro u2 size; 8182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project const s4* keys; 8192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project const s4* entries; 8202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 8212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* 8222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Sparse switch data format: 8232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * ushort ident = 0x0200 magic value 8242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * ushort size number of entries in the table; > 0 8252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * int keys[size] keys, sorted low-to-high; 32-bit aligned 8262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * int targets[size] branch targets, relative to switch opcode 8272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 8282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Total size is (2+size*4) 16-bit code units. 8292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 8302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 8312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (*switchData++ != kSparseSwitchSignature) { 8322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* should have been caught by verifier */ 8332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project dvmThrowException("Ljava/lang/InternalError;", 8342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project "bad sparse switch magic"); 8352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return kInstrLen; 8362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 8372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 8382ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project size = *switchData++; 8392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(size > 0); 84038329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng 8412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* The keys are guaranteed to be aligned on a 32-bit boundary; 8422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * we can treat them as a native int array. 8432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 8442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project keys = (const s4*) switchData; 8452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(((u4)keys & 0x3) == 0); 8462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 8472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* The entries are guaranteed to be aligned on a 32-bit boundary; 8482ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * we can treat them as a native int array. 8492ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 8502ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project entries = keys + size; 8512ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(((u4)entries & 0x3) == 0); 8522ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 8532ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* 85462f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden * Binary-search through the array of keys, which are guaranteed to 8552ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * be sorted low-to-high. 8562ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 85762f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden int lo = 0; 85862f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden int hi = size - 1; 85962f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden while (lo <= hi) { 86062f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden int mid = (lo + hi) >> 1; 86162f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden 86262f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden s4 foundVal = s4FromSwitchData(&keys[mid]); 86362f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden if (testVal < foundVal) { 86462f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden hi = mid - 1; 86562f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden } else if (testVal > foundVal) { 86662f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden lo = mid + 1; 86762f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden } else { 8682ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOGVV("Value %d found in entry %d (goto 0x%02x)\n", 86962f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden testVal, mid, s4FromSwitchData(&entries[mid])); 87062f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden return s4FromSwitchData(&entries[mid]); 8712ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 8722ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 8732ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 8742ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOGVV("Value %d not found in switch\n", testVal); 8752ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return kInstrLen; 8762ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project} 8772ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 8782ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/* 8796f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * Copy data for a fill-array-data instruction. On a little-endian machine 8806f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * we can just do a memcpy(), on a big-endian system we have work to do. 8816f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * 8826f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * The trick here is that dexopt has byte-swapped each code unit, which is 8836f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * exactly what we want for short/char data. For byte data we need to undo 8846f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * the swap, and for 4- or 8-byte values we need to swap pieces within 8856f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * each word. 8866f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden */ 8876f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFaddenstatic void copySwappedArrayData(void* dest, const u2* src, u4 size, u2 width) 8886f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden{ 8896f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden#if __BYTE_ORDER == __LITTLE_ENDIAN 8906f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden memcpy(dest, src, size*width); 8916f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden#else 8926f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden int i; 8936f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden 8946f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden switch (width) { 8956f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden case 1: 8966f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden /* un-swap pairs of bytes as we go */ 8976f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden for (i = (size-1) & ~1; i >= 0; i -= 2) { 8986f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden ((u1*)dest)[i] = ((u1*)src)[i+1]; 8996f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden ((u1*)dest)[i+1] = ((u1*)src)[i]; 9006f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden } 9016f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden /* 9026f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * "src" is padded to end on a two-byte boundary, but we don't want to 9036f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * assume "dest" is, so we handle odd length specially. 9046f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden */ 9056f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden if ((size & 1) != 0) { 9066f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden ((u1*)dest)[size-1] = ((u1*)src)[size]; 9076f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden } 9086f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden break; 9096f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden case 2: 9106f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden /* already swapped correctly */ 9116f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden memcpy(dest, src, size*width); 9126f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden break; 9136f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden case 4: 9146f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden /* swap word halves */ 9156f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden for (i = 0; i < (int) size; i++) { 9166f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden ((u4*)dest)[i] = (src[(i << 1) + 1] << 16) | src[i << 1]; 9176f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden } 9186f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden break; 9196f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden case 8: 9206f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden /* swap word halves and words */ 9216f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden for (i = 0; i < (int) (size << 1); i += 2) { 9226f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden ((int*)dest)[i] = (src[(i << 1) + 3] << 16) | src[(i << 1) + 2]; 9236f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden ((int*)dest)[i+1] = (src[(i << 1) + 1] << 16) | src[i << 1]; 9246f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden } 9256f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden break; 9266f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden default: 9276f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden LOGE("Unexpected width %d in copySwappedArrayData\n", width); 9286f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden dvmAbort(); 9296f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden break; 9306f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden } 9316f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden#endif 9326f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden} 9336f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden 9346f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden/* 9352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Fill the array with predefined constant values. 9362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 9372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Returns true if job is completed, otherwise false to indicate that 9382ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * an exception has been thrown. 9392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 94089c1feb0a69a7707b271086e749975b3f7acacf7The Android Open Source Projectbool dvmInterpHandleFillArrayData(ArrayObject* arrayObj, const u2* arrayData) 9412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{ 9422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project u2 width; 9432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project u4 size; 9442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 94589c1feb0a69a7707b271086e749975b3f7acacf7The Android Open Source Project if (arrayObj == NULL) { 94689c1feb0a69a7707b271086e749975b3f7acacf7The Android Open Source Project dvmThrowException("Ljava/lang/NullPointerException;", NULL); 9472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return false; 9482ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 9497dc966014df20fea6a4643ce2736922d0a7ee2c8Barry Hayes assert (!IS_CLASS_FLAG_SET(((Object *)arrayObj)->clazz, 9507dc966014df20fea6a4643ce2736922d0a7ee2c8Barry Hayes CLASS_ISOBJECTARRAY)); 95189c1feb0a69a7707b271086e749975b3f7acacf7The Android Open Source Project 9522ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* 9532ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Array data table format: 9542ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * ushort ident = 0x0300 magic value 9552ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * ushort width width of each element in the table 9562ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * uint size number of elements in the table 9572ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * ubyte data[size*width] table of data values (may contain a single-byte 9582ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * padding at the end) 9592ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 9602ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Total size is 4+(width * size + 1)/2 16-bit code units. 9612ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 9622ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (arrayData[0] != kArrayDataSignature) { 9632ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project dvmThrowException("Ljava/lang/InternalError;", "bad array data magic"); 9642ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return false; 9652ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 9662ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 9672ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project width = arrayData[1]; 9682ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project size = arrayData[2] | (((u4)arrayData[3]) << 16); 9692ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 970f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (size > arrayObj->length) { 9712ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", NULL); 9722ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return false; 9732ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 9746f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden copySwappedArrayData(arrayObj->contents, &arrayData[4], size, width); 9752ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return true; 9762ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project} 9772ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 9782ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/* 9792ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Find the concrete method that corresponds to "methodIdx". The code in 9802ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * "method" is executing invoke-method with "thisClass" as its first argument. 9812ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 9822ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Returns NULL with an exception raised on failure. 9832ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 9842ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source ProjectMethod* dvmInterpFindInterfaceMethod(ClassObject* thisClass, u4 methodIdx, 9852ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project const Method* method, DvmDex* methodClassDex) 9862ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{ 9872ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project Method* absMethod; 9882ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project Method* methodToCall; 9892ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project int i, vtableIndex; 9902ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 9912ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* 9922ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Resolve the method. This gives us the abstract method from the 9932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * interface class declaration. 9942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 9952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project absMethod = dvmDexGetResolvedMethod(methodClassDex, methodIdx); 9962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (absMethod == NULL) { 9972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project absMethod = dvmResolveInterfaceMethod(method->clazz, methodIdx); 9982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (absMethod == NULL) { 9992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOGV("+ unknown method\n"); 10002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return NULL; 10012ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 10022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 10032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 10042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* make sure absMethod->methodIndex means what we think it means */ 10052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(dvmIsAbstractMethod(absMethod)); 10062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 10072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* 10082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Run through the "this" object's iftable. Find the entry for 10092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * absMethod's class, then use absMethod->methodIndex to find 10102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * the method's entry. The value there is the offset into our 10112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * vtable of the actual method to execute. 10122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 10132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * The verifier does not guarantee that objects stored into 10142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * interface references actually implement the interface, so this 10152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * check cannot be eliminated. 10162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 10172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project for (i = 0; i < thisClass->iftableCount; i++) { 10182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (thisClass->iftable[i].clazz == absMethod->clazz) 10192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project break; 10202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 10212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (i == thisClass->iftableCount) { 10222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* impossible in verified DEX, need to check for it in unverified */ 10232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project dvmThrowException("Ljava/lang/IncompatibleClassChangeError;", 10242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project "interface not implemented"); 10252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return NULL; 10262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 10272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 10282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(absMethod->methodIndex < 10292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project thisClass->iftable[i].clazz->virtualMethodCount); 10302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 10312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project vtableIndex = 10322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project thisClass->iftable[i].methodIndexArray[absMethod->methodIndex]; 10332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(vtableIndex >= 0 && vtableIndex < thisClass->vtableCount); 10342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project methodToCall = thisClass->vtable[vtableIndex]; 10352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 10362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#if 0 10372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* this can happen when there's a stale class file */ 10382ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (dvmIsAbstractMethod(methodToCall)) { 10392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project dvmThrowException("Ljava/lang/AbstractMethodError;", 10402ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project "interface method not implemented"); 10412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return NULL; 10422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 10432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#else 10442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(!dvmIsAbstractMethod(methodToCall) || 10452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project methodToCall->nativeFunc != NULL); 10462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif 10472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 10482ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOGVV("+++ interface=%s.%s concrete=%s.%s\n", 10492ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project absMethod->clazz->descriptor, absMethod->name, 10502ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project methodToCall->clazz->descriptor, methodToCall->name); 10512ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(methodToCall != NULL); 10522ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 10532ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project return methodToCall; 10542ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project} 10552ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 10562ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 1057b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden 1058b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden/* 1059b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden * Helpers for dvmThrowVerificationError(). 1060b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden * 1061b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden * Each returns a newly-allocated string. 1062b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden */ 1063b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden#define kThrowShow_accessFromClass 1 1064af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFaddenstatic char* classNameFromIndex(const Method* method, int ref, 1065af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden VerifyErrorRefType refType, int flags) 1066b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden{ 1067b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden static const int kBufLen = 256; 1068b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden const DvmDex* pDvmDex = method->clazz->pDvmDex; 1069af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden 1070af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden if (refType == VERIFY_ERROR_REF_FIELD) { 1071af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden /* get class ID from field ID */ 1072af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden const DexFieldId* pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref); 1073af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden ref = pFieldId->classIdx; 1074af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden } else if (refType == VERIFY_ERROR_REF_METHOD) { 1075af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden /* get class ID from method ID */ 1076af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden const DexMethodId* pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref); 1077af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden ref = pMethodId->classIdx; 1078af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden } 1079af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden 1080b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, ref); 1081b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden char* dotClassName = dvmDescriptorToDot(className); 1082b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden if (flags == 0) 1083b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden return dotClassName; 1084b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden 1085b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden char* result = (char*) malloc(kBufLen); 1086b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden 1087b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden if ((flags & kThrowShow_accessFromClass) != 0) { 1088b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor); 1089b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden snprintf(result, kBufLen, "tried to access class %s from class %s", 1090b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden dotClassName, dotFromName); 1091b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden free(dotFromName); 1092b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden } else { 1093b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden assert(false); // should've been caught above 1094b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden result[0] = '\0'; 1095b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden } 1096b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden 1097b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden free(dotClassName); 1098b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden return result; 1099b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden} 1100af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFaddenstatic char* fieldNameFromIndex(const Method* method, int ref, 1101af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden VerifyErrorRefType refType, int flags) 1102b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden{ 1103b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden static const int kBufLen = 256; 1104b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden const DvmDex* pDvmDex = method->clazz->pDvmDex; 1105b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden const DexFieldId* pFieldId; 1106b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden const char* className; 1107b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden const char* fieldName; 1108b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden 1109af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden if (refType != VERIFY_ERROR_REF_FIELD) { 1110af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden LOGW("Expected ref type %d, got %d\n", VERIFY_ERROR_REF_FIELD, refType); 1111af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden return NULL; /* no message */ 1112af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden } 1113af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden 1114b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref); 1115b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden className = dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->classIdx); 1116b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden fieldName = dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx); 1117b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden 1118b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden char* dotName = dvmDescriptorToDot(className); 1119b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden char* result = (char*) malloc(kBufLen); 1120b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden 1121b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden if ((flags & kThrowShow_accessFromClass) != 0) { 1122b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor); 1123b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden snprintf(result, kBufLen, "tried to access field %s.%s from class %s", 1124b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden dotName, fieldName, dotFromName); 1125b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden free(dotFromName); 1126b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden } else { 1127b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden snprintf(result, kBufLen, "%s.%s", dotName, fieldName); 1128b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden } 1129b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden 1130b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden free(dotName); 1131b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden return result; 1132b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden} 1133af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFaddenstatic char* methodNameFromIndex(const Method* method, int ref, 1134af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden VerifyErrorRefType refType, int flags) 1135b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden{ 1136b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden static const int kBufLen = 384; 1137b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden const DvmDex* pDvmDex = method->clazz->pDvmDex; 1138b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden const DexMethodId* pMethodId; 1139b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden const char* className; 1140b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden const char* methodName; 1141b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden 1142af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden if (refType != VERIFY_ERROR_REF_METHOD) { 1143af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden LOGW("Expected ref type %d, got %d\n", VERIFY_ERROR_REF_METHOD,refType); 1144af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden return NULL; /* no message */ 1145af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden } 1146af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden 1147b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref); 1148b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden className = dexStringByTypeIdx(pDvmDex->pDexFile, pMethodId->classIdx); 1149b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden methodName = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx); 1150b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden 1151b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden char* dotName = dvmDescriptorToDot(className); 1152b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden char* result = (char*) malloc(kBufLen); 1153b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden 1154b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden if ((flags & kThrowShow_accessFromClass) != 0) { 1155b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor); 1156b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden char* desc = dexProtoCopyMethodDescriptor(&method->prototype); 1157b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden snprintf(result, kBufLen, 1158b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden "tried to access method %s.%s:%s from class %s", 1159b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden dotName, methodName, desc, dotFromName); 1160b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden free(dotFromName); 1161b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden free(desc); 1162b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden } else { 1163b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden snprintf(result, kBufLen, "%s.%s", dotName, methodName); 1164b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden } 1165b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden 1166b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden free(dotName); 1167b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden return result; 1168b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden} 1169b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden 11702ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/* 11713a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden * Throw an exception for a problem identified by the verifier. 11723a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden * 11733a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden * This is used by the invoke-verification-error instruction. It always 11743a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden * throws an exception. 11753a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden * 1176af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden * "kind" indicates the kind of failure encountered by the verifier. It 1177af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden * has two parts, an error code and an indication of the reference type. 11783a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden */ 1179b51ea11c70602918c42764bfafe92a997d3b1803Andy McFaddenvoid dvmThrowVerificationError(const Method* method, int kind, int ref) 11803a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden{ 1181af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden const int typeMask = 0xff << kVerifyErrorRefTypeShift; 1182af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden VerifyError errorKind = kind & ~typeMask; 1183af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden VerifyErrorRefType refType = kind >> kVerifyErrorRefTypeShift; 1184b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden const char* exceptionName = "Ljava/lang/VerifyError;"; 1185b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden char* msg = NULL; 1186b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden 1187af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden switch ((VerifyError) errorKind) { 1188b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden case VERIFY_ERROR_NO_CLASS: 1189b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden exceptionName = "Ljava/lang/NoClassDefFoundError;"; 1190af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden msg = classNameFromIndex(method, ref, refType, 0); 1191b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden break; 1192b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden case VERIFY_ERROR_NO_FIELD: 1193b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden exceptionName = "Ljava/lang/NoSuchFieldError;"; 1194af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden msg = fieldNameFromIndex(method, ref, refType, 0); 1195b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden break; 1196b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden case VERIFY_ERROR_NO_METHOD: 1197b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden exceptionName = "Ljava/lang/NoSuchMethodError;"; 1198af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden msg = methodNameFromIndex(method, ref, refType, 0); 1199b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden break; 1200b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden case VERIFY_ERROR_ACCESS_CLASS: 1201b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden exceptionName = "Ljava/lang/IllegalAccessError;"; 1202af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden msg = classNameFromIndex(method, ref, refType, 1203af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden kThrowShow_accessFromClass); 1204b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden break; 1205b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden case VERIFY_ERROR_ACCESS_FIELD: 1206b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden exceptionName = "Ljava/lang/IllegalAccessError;"; 1207af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden msg = fieldNameFromIndex(method, ref, refType, 1208af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden kThrowShow_accessFromClass); 1209b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden break; 1210b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden case VERIFY_ERROR_ACCESS_METHOD: 1211b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden exceptionName = "Ljava/lang/IllegalAccessError;"; 1212af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden msg = methodNameFromIndex(method, ref, refType, 1213af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden kThrowShow_accessFromClass); 1214b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden break; 1215b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden case VERIFY_ERROR_CLASS_CHANGE: 1216b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden exceptionName = "Ljava/lang/IncompatibleClassChangeError;"; 1217af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden msg = classNameFromIndex(method, ref, refType, 0); 1218b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden break; 1219b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden case VERIFY_ERROR_INSTANTIATION: 1220b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden exceptionName = "Ljava/lang/InstantiationError;"; 1221af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden msg = classNameFromIndex(method, ref, refType, 0); 1222b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden break; 1223b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden 1224b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden case VERIFY_ERROR_GENERIC: 1225b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden /* generic VerifyError; use default exception, no message */ 1226b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden break; 1227b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden case VERIFY_ERROR_NONE: 1228b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden /* should never happen; use default exception */ 1229b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden assert(false); 1230b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden msg = strdup("weird - no error specified"); 1231b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden break; 1232b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden 1233b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden /* no default clause -- want warning if enum updated */ 1234b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden } 1235b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden 1236b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden dvmThrowException(exceptionName, msg); 1237b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden free(msg); 12383a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden} 12393a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden 12403a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden/* 12412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Main interpreter loop entry point. Select "standard" or "debug" 12422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * interpreter and switch between them as required. 12432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 12442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * This begins executing code at the start of "method". On exit, "pResult" 12452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * holds the return value of the method (or, if "method" returns NULL, it 12462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * holds an undefined value). 12472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 12482ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * The interpreted stack frame, which holds the method arguments, has 12492ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * already been set up. 12502ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 12512ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectvoid dvmInterpret(Thread* self, const Method* method, JValue* pResult) 12522ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{ 12532ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project InterpState interpState; 12542ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project bool change; 1255ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#if defined(WITH_JIT) 1256342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee /* Target-specific save/restore */ 1257342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee extern void dvmJitCalleeSave(double *saveArea); 1258342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee extern void dvmJitCalleeRestore(double *saveArea); 1259ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng /* Interpreter entry points from compiled code */ 1260ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng extern void dvmJitToInterpNormal(); 1261ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng extern void dvmJitToInterpNoChain(); 1262ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng extern void dvmJitToInterpPunt(); 1263ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng extern void dvmJitToInterpSingleStep(); 126440094c16d9727cc1e047a7d4bddffe04dd566211Ben Cheng extern void dvmJitToInterpTraceSelectNoChain(); 126540094c16d9727cc1e047a7d4bddffe04dd566211Ben Cheng extern void dvmJitToInterpTraceSelect(); 126638329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng extern void dvmJitToPatchPredictedChain(); 126797319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#if defined(WITH_SELF_VERIFICATION) 126840094c16d9727cc1e047a7d4bddffe04dd566211Ben Cheng extern void dvmJitToInterpBackwardBranch(); 126997319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#endif 1270ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng 127138329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng /* 1272ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * Reserve a static entity here to quickly setup runtime contents as 1273ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * gcc will issue block copy instructions. 1274ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng */ 1275ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng static struct JitToInterpEntries jitToInterpEntries = { 1276ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng dvmJitToInterpNormal, 1277ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng dvmJitToInterpNoChain, 1278ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng dvmJitToInterpPunt, 1279ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng dvmJitToInterpSingleStep, 128040094c16d9727cc1e047a7d4bddffe04dd566211Ben Cheng dvmJitToInterpTraceSelectNoChain, 128140094c16d9727cc1e047a7d4bddffe04dd566211Ben Cheng dvmJitToInterpTraceSelect, 128238329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng dvmJitToPatchPredictedChain, 128397319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#if defined(WITH_SELF_VERIFICATION) 128440094c16d9727cc1e047a7d4bddffe04dd566211Ben Cheng dvmJitToInterpBackwardBranch, 128597319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#endif 1286ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng }; 12877a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng 12887a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng assert(self->inJitCodeCache == NULL); 1289ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#endif 1290ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng 12912ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 12922ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#if defined(WITH_TRACKREF_CHECKS) 12932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project interpState.debugTrackedRefStart = 12942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project dvmReferenceTableEntries(&self->internalLocalRefTable); 12952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif 12962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER) 12972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project interpState.debugIsMethodEntry = true; 12982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif 1299ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#if defined(WITH_JIT) 1300342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee dvmJitCalleeSave(interpState.calleeSave); 1301a497359afa1abe4c5780c8799c6fe0edab551c2dBen Cheng /* Initialize the state to kJitNot */ 1302a497359afa1abe4c5780c8799c6fe0edab551c2dBen Cheng interpState.jitState = kJitNot; 1303ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng 1304ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng /* Setup the Jit-to-interpreter entry points */ 1305ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng interpState.jitToInterpEntries = jitToInterpEntries; 130648f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee 130748f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee /* 130848f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee * Initialize the threshold filter [don't bother to zero out the 130948f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee * actual table. We're looking for matches, and an occasional 131048f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee * false positive is acceptible. 131148f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee */ 131248f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee interpState.lastThreshFilter = 0; 1313ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#endif 13142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 13152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* 13162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Initialize working state. 13172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * 13182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * No need to initialize "retval". 13192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 13202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project interpState.method = method; 13212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project interpState.fp = (u4*) self->curFrame; 13222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project interpState.pc = method->insns; 13232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project interpState.entryPoint = kInterpEntryInstr; 13242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 13252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (dvmDebuggerOrProfilerActive()) 13262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project interpState.nextMode = INTERP_DBG; 13272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project else 13282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project interpState.nextMode = INTERP_STD; 13292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 13302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project assert(!dvmIsNativeMethod(method)); 13312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 13322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project /* 13332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Make sure the class is ready to go. Shouldn't be possible to get 13342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * here otherwise. 13352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */ 13362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (method->clazz->status < CLASS_INITIALIZING || 13372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project method->clazz->status == CLASS_ERROR) 13382ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project { 13392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOGE("ERROR: tried to execute code in unprepared class '%s' (%d)\n", 13402ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project method->clazz->descriptor, method->clazz->status); 13412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project dvmDumpThread(self, false); 13422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project dvmAbort(); 13432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 13442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 13452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project typedef bool (*Interpreter)(Thread*, InterpState*); 13462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project Interpreter stdInterp; 13472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project if (gDvm.executionMode == kExecutionModeInterpFast) 13482ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project stdInterp = dvmMterpStd; 1349ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#if defined(WITH_JIT) 1350ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng else if (gDvm.executionMode == kExecutionModeJit) 1351ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng/* If profiling overhead can be kept low enough, we can use a profiling 1352ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * mterp fast for both Jit and "fast" modes. If overhead is too high, 1353ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * create a specialized profiling interpreter. 1354ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng */ 1355ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng stdInterp = dvmMterpStd; 1356ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#endif 13572ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project else 13582ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project stdInterp = dvmInterpretStd; 13592ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 13602ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project change = true; 13612ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project while (change) { 13622ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project switch (interpState.nextMode) { 13632ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project case INTERP_STD: 13642ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOGVV("threadid=%d: interp STD\n", self->threadId); 13652ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project change = (*stdInterp)(self, &interpState); 13662ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project break; 1367ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER) || defined(WITH_JIT) 13682ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project case INTERP_DBG: 13692ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project LOGVV("threadid=%d: interp DBG\n", self->threadId); 13702ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project change = dvmInterpretDbg(self, &interpState); 13712ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project break; 13722ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif 13732ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project default: 13742ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project dvmAbort(); 13752ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 13762ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project } 13772ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project 13782ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *pResult = interpState.retval; 1379342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee#if defined(WITH_JIT) 1380342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee dvmJitCalleeRestore(interpState.calleeSave); 1381342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee#endif 13822ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project} 1383