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