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 *
240d615c3ce5bf97ae65b9347ee77968f38620d5e8Andy McFadden * Some debugger support functions are included here.
252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#include "Dalvik.h"
272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#include "interp/InterpDefs.h"
282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * ===========================================================================
322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *      Debugger support
332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * ===========================================================================
342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
3696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden// fwd
3796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic BreakpointSet* dvmBreakpointSetAlloc(void);
3896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic void dvmBreakpointSetFree(BreakpointSet* pSet);
3996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
402ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
4196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Initialize global breakpoint structures.
4296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
4396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenbool dvmBreakpointStartup(void)
4496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
4596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    gDvm.breakpointSet = dvmBreakpointSetAlloc();
4696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return (gDvm.breakpointSet != NULL);
4796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
4896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
4996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
5096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Free resources.
5196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
5296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenvoid dvmBreakpointShutdown(void)
5396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
5496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetFree(gDvm.breakpointSet);
5596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
5696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
5796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
5896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
5996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * This represents a breakpoint inserted in the instruction stream.
602ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
6196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The debugger may ask us to create the same breakpoint multiple times.
6296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * We only remove the breakpoint when the last instance is cleared.
6396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
6496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddentypedef struct {
65d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden    Method*     method;                 /* method we're associated with */
6696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    u2*         addr;                   /* absolute memory address */
6796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    u1          originalOpCode;         /* original 8-bit opcode value */
6896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int         setCount;               /* #of times this breakpoint was set */
6996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden} Breakpoint;
7096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
7196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
7296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Set of breakpoints.
7396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
7496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstruct BreakpointSet {
7596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    /* grab lock before reading or writing anything else in here */
7696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    pthread_mutex_t lock;
7796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
7896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    /* vector of breakpoint structures */
7996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int         alloc;
8096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int         count;
8196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    Breakpoint* breakpoints;
8296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden};
8396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
8496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
8596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Initialize a BreakpointSet.  Initially empty.
8696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
8796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic BreakpointSet* dvmBreakpointSetAlloc(void)
8896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
8996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    BreakpointSet* pSet = (BreakpointSet*) calloc(1, sizeof(*pSet));
9096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
9196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmInitMutex(&pSet->lock);
9296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    /* leave the rest zeroed -- will alloc on first use */
9396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
9496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return pSet;
9596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
9696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
9796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
9896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Free storage associated with a BreakpointSet.
9996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
10096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic void dvmBreakpointSetFree(BreakpointSet* pSet)
10196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
10296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (pSet == NULL)
10396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        return;
10496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
10596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    free(pSet->breakpoints);
10696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    free(pSet);
10796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
10896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
10996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
11096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Lock the breakpoint set.
111d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden *
112d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * It's not currently necessary to switch to VMWAIT in the event of
113d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * contention, because nothing in here can block.  However, it's possible
114d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * that the bytecode-updater code could become fancier in the future, so
115d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * we do the trylock dance as a bit of future-proofing.
11696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
11796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic void dvmBreakpointSetLock(BreakpointSet* pSet)
11896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
119d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden    if (dvmTryLockMutex(&pSet->lock) != 0) {
120d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden        Thread* self = dvmThreadSelf();
1215617ad30c611f373e16bf10c0feec114faef54efCarl Shapiro        ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
122d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden        dvmLockMutex(&pSet->lock);
123d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden        dvmChangeStatus(self, oldStatus);
124d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden    }
12596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
12696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
12796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
12896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Unlock the breakpoint set.
12996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
13096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic void dvmBreakpointSetUnlock(BreakpointSet* pSet)
13196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
13296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmUnlockMutex(&pSet->lock);
13396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
13496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
13596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
13696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Return the #of breakpoints.
13796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
13896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic int dvmBreakpointSetCount(const BreakpointSet* pSet)
13996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
14096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return pSet->count;
14196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
14296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
14396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
14496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * See if we already have an entry for this address.
14596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
14696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The BreakpointSet's lock must be acquired before calling here.
14796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
14896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Returns the index of the breakpoint entry, or -1 if not found.
14996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
15096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic int dvmBreakpointSetFind(const BreakpointSet* pSet, const u2* addr)
15196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
15296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int i;
15396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
15496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    for (i = 0; i < pSet->count; i++) {
15596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        Breakpoint* pBreak = &pSet->breakpoints[i];
15696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        if (pBreak->addr == addr)
15796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            return i;
15896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
15996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
16096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return -1;
16196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
16296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
16396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
16496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Retrieve the opcode that was originally at the specified location.
16596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
16696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The BreakpointSet's lock must be acquired before calling here.
16796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
16896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Returns "true" with the opcode in *pOrig on success.
16996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
17096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic bool dvmBreakpointSetOriginalOpCode(const BreakpointSet* pSet,
17196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    const u2* addr, u1* pOrig)
17296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
17396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int idx = dvmBreakpointSetFind(pSet, addr);
17496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (idx < 0)
17596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        return false;
17696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
17796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    *pOrig = pSet->breakpoints[idx].originalOpCode;
17896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return true;
17996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
18096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
18196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
182da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * Check the opcode.  If it's a "magic" NOP, indicating the start of
183da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * switch or array data in the instruction stream, we don't want to set
184da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * a breakpoint.
185da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden *
186da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * This can happen because the line number information dx generates
187da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * associates the switch data with the switch statement's line number,
188da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * and some debuggers put breakpoints at every address associated with
189da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * a given line.  The result is that the breakpoint stomps on the NOP
190da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * instruction that doubles as a data table magic number, and an explicit
191da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * check in the interpreter results in an exception being thrown.
192da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden *
193da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * We don't want to simply refuse to add the breakpoint to the table,
194da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * because that confuses the housekeeping.  We don't want to reject the
195da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * debugger's event request, and we want to be sure that there's exactly
196da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden * one un-set operation for every set op.
197da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden */
198da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFaddenstatic bool instructionIsMagicNop(const u2* addr)
199da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden{
200da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden    u2 curVal = *addr;
201da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden    return ((curVal & 0xff) == OP_NOP && (curVal >> 8) != 0);
202da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden}
203da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden
204da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden/*
20596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Add a breakpoint at a specific address.  If the address is already
20696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * present in the table, this just increments the count.
20796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
20896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * For a new entry, this will extract and preserve the current opcode from
20996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * the instruction stream, and replace it with a breakpoint opcode.
21096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
21196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The BreakpointSet's lock must be acquired before calling here.
21296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
21396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Returns "true" on success.
21496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
21596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic bool dvmBreakpointSetAdd(BreakpointSet* pSet, Method* method,
21696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    unsigned int instrOffset)
21796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
21896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    const int kBreakpointGrowth = 10;
21996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    const u2* addr = method->insns + instrOffset;
22096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int idx = dvmBreakpointSetFind(pSet, addr);
22196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    Breakpoint* pBreak;
22296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
22396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (idx < 0) {
22496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        if (pSet->count == pSet->alloc) {
22596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            int newSize = pSet->alloc + kBreakpointGrowth;
22696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            Breakpoint* newVec;
22796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
22896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            LOGV("+++ increasing breakpoint set size to %d\n", newSize);
22996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
23096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            /* pSet->breakpoints will be NULL on first entry */
23196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            newVec = realloc(pSet->breakpoints, newSize * sizeof(Breakpoint));
23296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            if (newVec == NULL)
23396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                return false;
23496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
23596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            pSet->breakpoints = newVec;
23696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            pSet->alloc = newSize;
23796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        }
23896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
23996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        pBreak = &pSet->breakpoints[pSet->count++];
240d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden        pBreak->method = method;
24196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        pBreak->addr = (u2*)addr;
24296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        pBreak->originalOpCode = *(u1*)addr;
24396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        pBreak->setCount = 1;
24496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
24596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        /*
24696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden         * Change the opcode.  We must ensure that the BreakpointSet
24796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden         * updates happen before we change the opcode.
248d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden         *
249d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden         * If the method has not been verified, we do NOT insert the
250d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden         * breakpoint yet, since that will screw up the verifier.  The
251d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden         * debugger is allowed to insert breakpoints in unverified code,
252d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden         * but since we don't execute unverified code we don't need to
253d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden         * alter the bytecode yet.
254d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden         *
255c7a12b2fc8270722c7de8d24fd8fa943e5ef1818Andy McFadden         * The class init code will "flush" all pending opcode writes
256c7a12b2fc8270722c7de8d24fd8fa943e5ef1818Andy McFadden         * before verification completes.
25796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden         */
25896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        assert(*(u1*)addr != OP_BREAKPOINT);
259d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden        if (dvmIsClassVerified(method->clazz)) {
260d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden            LOGV("Class %s verified, adding breakpoint at %p\n",
261d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden                method->clazz->descriptor, addr);
262da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden            if (instructionIsMagicNop(addr)) {
263da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden                LOGV("Refusing to set breakpoint on %04x at %s.%s + 0x%x\n",
264da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden                    *addr, method->clazz->descriptor, method->name,
265da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden                    instrOffset);
266da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden            } else {
2676e10b9aaa72425a4825a25f0043533d0c6fdbba4Andy McFadden                ANDROID_MEMBAR_FULL();
268da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden                dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr,
269da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden                    OP_BREAKPOINT);
270da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden            }
271d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden        } else {
272d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden            LOGV("Class %s NOT verified, deferring breakpoint at %p\n",
273d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden                method->clazz->descriptor, addr);
274d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden        }
27596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    } else {
276d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden        /*
277c7a12b2fc8270722c7de8d24fd8fa943e5ef1818Andy McFadden         * Breakpoint already exists, just increase the count.
278d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden         */
279c7a12b2fc8270722c7de8d24fd8fa943e5ef1818Andy McFadden        pBreak = &pSet->breakpoints[idx];
280c7a12b2fc8270722c7de8d24fd8fa943e5ef1818Andy McFadden        pBreak->setCount++;
28196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
28296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
28396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return true;
28496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
28596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
28696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
28796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Remove one instance of the specified breakpoint.  When the count
28896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * reaches zero, the entry is removed from the table, and the original
28996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * opcode is restored.
29096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
29196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The BreakpointSet's lock must be acquired before calling here.
29296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
29396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic void dvmBreakpointSetRemove(BreakpointSet* pSet, Method* method,
29496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    unsigned int instrOffset)
29596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
29696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    const u2* addr = method->insns + instrOffset;
29796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int idx = dvmBreakpointSetFind(pSet, addr);
29896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
29996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (idx < 0) {
30096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        /* breakpoint not found in set -- unexpected */
30196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        if (*(u1*)addr == OP_BREAKPOINT) {
302da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden            LOGE("Unable to restore breakpoint opcode (%s.%s +0x%x)\n",
30396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                method->clazz->descriptor, method->name, instrOffset);
30496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            dvmAbort();
30596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        } else {
306da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden            LOGW("Breakpoint was already restored? (%s.%s +0x%x)\n",
30796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                method->clazz->descriptor, method->name, instrOffset);
30896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        }
30996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    } else {
31096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        Breakpoint* pBreak = &pSet->breakpoints[idx];
31196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        if (pBreak->setCount == 1) {
31296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            /*
31396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden             * Must restore opcode before removing set entry.
314d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden             *
315d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden             * If the breakpoint was never flushed, we could be ovewriting
316d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden             * a value with the same value.  Not a problem, though we
317d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden             * could end up causing a copy-on-write here when we didn't
318d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden             * need to.  (Not worth worrying about.)
31996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden             */
32096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr,
32196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                pBreak->originalOpCode);
3226e10b9aaa72425a4825a25f0043533d0c6fdbba4Andy McFadden            ANDROID_MEMBAR_FULL();
32396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
32496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            if (idx != pSet->count-1) {
32596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                /* shift down */
32696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                memmove(&pSet->breakpoints[idx], &pSet->breakpoints[idx+1],
32796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                    (pSet->count-1 - idx) * sizeof(pSet->breakpoints[0]));
32896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            }
32996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            pSet->count--;
33096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            pSet->breakpoints[pSet->count].addr = (u2*) 0xdecadead; // debug
33196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        } else {
33296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            pBreak->setCount--;
33396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            assert(pBreak->setCount > 0);
33496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        }
33596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
33696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
33796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
33896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
339d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * Flush any breakpoints associated with methods in "clazz".  We want to
340d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * change the opcode, which might not have happened when the breakpoint
341d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * was initially set because the class was in the process of being
342d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * verified.
34396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
34496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The BreakpointSet's lock must be acquired before calling here.
34596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
346d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFaddenstatic void dvmBreakpointSetFlush(BreakpointSet* pSet, ClassObject* clazz)
34796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
34896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int i;
34996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    for (i = 0; i < pSet->count; i++) {
35096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        Breakpoint* pBreak = &pSet->breakpoints[i];
351d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden        if (pBreak->method->clazz == clazz) {
352d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden            /*
353d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden             * The breakpoint is associated with a method in this class.
354d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden             * It might already be there or it might not; either way,
355d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden             * flush it out.
356d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden             */
357d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden            LOGV("Flushing breakpoint at %p for %s\n",
358d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden                pBreak->addr, clazz->descriptor);
359da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden            if (instructionIsMagicNop(pBreak->addr)) {
360da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden                LOGV("Refusing to flush breakpoint on %04x at %s.%s + 0x%x\n",
361e3c01dac83e6eea7f82fe81ed89cfbdd9791dbc9Carl Shapiro                    *pBreak->addr, pBreak->method->clazz->descriptor,
362e3c01dac83e6eea7f82fe81ed89cfbdd9791dbc9Carl Shapiro                    pBreak->method->name, pBreak->addr - pBreak->method->insns);
363da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden            } else {
364da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden                dvmDexChangeDex1(clazz->pDvmDex, (u1*)pBreak->addr,
365da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden                    OP_BREAKPOINT);
366da9dc84a1296a11efce0b656cbc87c7112994d0bAndy McFadden            }
36796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        }
36896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
36996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
37096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
37196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
37296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
37396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Do any debugger-attach-time initialization.
3742ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
3752ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectvoid dvmInitBreakpoints(void)
3762ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
37796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    /* quick sanity check */
37896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    BreakpointSet* pSet = gDvm.breakpointSet;
37996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetLock(pSet);
38096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (dvmBreakpointSetCount(pSet) != 0) {
38196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        LOGW("WARNING: %d leftover breakpoints\n", dvmBreakpointSetCount(pSet));
38296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        /* generally not good, but we can keep going */
38396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
38496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetUnlock(pSet);
3852ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
3862ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
3872ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
3882ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Add an address to the list, putting it in the first non-empty slot.
3892ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
3902ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Sometimes the debugger likes to add two entries for one breakpoint.
3912ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * We add two entries here, so that we get the right behavior when it's
3922ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * removed twice.
3932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
3942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * This will only be run from the JDWP thread, and it will happen while
3952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * we are updating the event list, which is synchronized.  We're guaranteed
3962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * to be the only one adding entries, and the lock ensures that nobody
3972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * will be trying to remove them while we're in here.
3982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
3992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * "addr" is the absolute address of the breakpoint bytecode.
4002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
40196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenvoid dvmAddBreakAddr(Method* method, unsigned int instrOffset)
4022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
40396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    BreakpointSet* pSet = gDvm.breakpointSet;
40496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetLock(pSet);
40596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetAdd(pSet, method, instrOffset);
40696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetUnlock(pSet);
4072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
4082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
4092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
4102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Remove an address from the list by setting the entry to NULL.
4112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
4122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * This can be called from the JDWP thread (because the debugger has
4132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * cancelled the breakpoint) or from an event thread (because it's a
4142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * single-shot breakpoint, e.g. "run to line").  We only get here as
4152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * the result of removing an entry from the event list, which is
4162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * synchronized, so it should not be possible for two threads to be
4172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * updating breakpoints at the same time.
4182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
41996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenvoid dvmClearBreakAddr(Method* method, unsigned int instrOffset)
4202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
42196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    BreakpointSet* pSet = gDvm.breakpointSet;
42296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetLock(pSet);
42396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetRemove(pSet, method, instrOffset);
42496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetUnlock(pSet);
4252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
4262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
42796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
42896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Get the original opcode from under a breakpoint.
429fc3d31683a0120ba005f45f98dcbe1001064dafbAndy McFadden *
430fc3d31683a0120ba005f45f98dcbe1001064dafbAndy McFadden * On SMP hardware it's possible one core might try to execute a breakpoint
431fc3d31683a0120ba005f45f98dcbe1001064dafbAndy McFadden * after another core has cleared it.  We need to handle the case where
432fc3d31683a0120ba005f45f98dcbe1001064dafbAndy McFadden * there's no entry in the breakpoint set.  (The memory barriers in the
433fc3d31683a0120ba005f45f98dcbe1001064dafbAndy McFadden * locks and in the breakpoint update code should ensure that, once we've
434fc3d31683a0120ba005f45f98dcbe1001064dafbAndy McFadden * observed the absence of a breakpoint entry, we will also now observe
435fc3d31683a0120ba005f45f98dcbe1001064dafbAndy McFadden * the restoration of the original opcode.  The fact that we're holding
436fc3d31683a0120ba005f45f98dcbe1001064dafbAndy McFadden * the lock prevents other threads from confusing things further.)
43796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
43896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenu1 dvmGetOriginalOpCode(const u2* addr)
43996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
44096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    BreakpointSet* pSet = gDvm.breakpointSet;
44196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    u1 orig = 0;
44296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
44396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetLock(pSet);
44496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (!dvmBreakpointSetOriginalOpCode(pSet, addr, &orig)) {
44596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        orig = *(u1*)addr;
44696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        if (orig == OP_BREAKPOINT) {
44796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            LOGE("GLITCH: can't find breakpoint, opcode is still set\n");
44896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            dvmAbort();
44996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        }
45096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
45196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetUnlock(pSet);
45296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
45396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return orig;
45496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
45596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
45696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
457d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * Flush any breakpoints associated with methods in "clazz".
45896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
459d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * We don't want to modify the bytecode of a method before the verifier
460d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * gets a chance to look at it, so we postpone opcode replacement until
461d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden * after verification completes.
46296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
463d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFaddenvoid dvmFlushBreakpoints(ClassObject* clazz)
46496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
46596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    BreakpointSet* pSet = gDvm.breakpointSet;
46696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
467d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden    if (pSet == NULL)
468d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden        return;
46996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
470d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden    assert(dvmIsClassVerified(clazz));
471d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden    dvmBreakpointSetLock(pSet);
472d22748a8ddc8f6a7d2e82868b46e9a7739f2e8e5Andy McFadden    dvmBreakpointSetFlush(pSet, clazz);
47396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetUnlock(pSet);
47496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
47596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
4762ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
4772ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Add a single step event.  Currently this is a global item.
4782ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
4792ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * We set up some initial values based on the thread's current state.  This
4802ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * won't work well if the thread is running, so it's up to the caller to
4812ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * verify that it's suspended.
4822ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
4832ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * This is only called from the JDWP thread.
4842ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
4852ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectbool dvmAddSingleStep(Thread* thread, int size, int depth)
4862ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
4872ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    StepControl* pCtrl = &gDvm.stepControl;
4882ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
4892ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (pCtrl->active && thread != pCtrl->thread) {
4902ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        LOGW("WARNING: single-step active for %p; adding %p\n",
4912ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            pCtrl->thread, thread);
4922ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
4932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        /*
4942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         * Keep going, overwriting previous.  This can happen if you
4952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         * suspend a thread in Object.wait, hit the single-step key, then
4962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         * switch to another thread and do the same thing again.
4972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         * The first thread's step is still pending.
4982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         *
4992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         * TODO: consider making single-step per-thread.  Adds to the
5002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         * overhead, but could be useful in rare situations.
5012ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         */
5022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
5032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    pCtrl->size = size;
5052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    pCtrl->depth = depth;
5062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    pCtrl->thread = thread;
5072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
5092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * We may be stepping into or over method calls, or running until we
5102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * return from the current method.  To make this work we need to track
5112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * the current line, current method, and current stack depth.  We need
5122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * to be checking these after most instructions, notably those that
5132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * call methods, return from methods, or are on a different line from the
5142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * previous instruction.
5152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *
5162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * We have to start with a snapshot of the current state.  If we're in
5172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * an interpreted method, everything we need is in the current frame.  If
5182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * we're in a native method, possibly with some extra JNI frames pushed
5192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * on by PushLocalFrame, we want to use the topmost native method.
5202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
5212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    const StackSaveArea* saveArea;
5222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    void* fp;
5232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    void* prevFp = NULL;
52438329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng
5252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    for (fp = thread->curFrame; fp != NULL; fp = saveArea->prevFrame) {
5262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        const Method* method;
5272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        saveArea = SAVEAREA_FROM_FP(fp);
5292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        method = saveArea->method;
5302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        if (!dvmIsBreakFrame(fp) && !dvmIsNativeMethod(method))
5322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            break;
5332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        prevFp = fp;
5342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
5352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (fp == NULL) {
5362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        LOGW("Unexpected: step req in native-only threadid=%d\n",
5372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            thread->threadId);
5382ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return false;
5392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
5402ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (prevFp != NULL) {
5412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        /*
5422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         * First interpreted frame wasn't the one at the bottom.  Break
5432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         * frames are only inserted when calling from native->interp, so we
5442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         * don't need to worry about one being here.
5452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         */
5462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        LOGV("##### init step while in native method\n");
5472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        fp = prevFp;
5482ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        assert(!dvmIsBreakFrame(fp));
5492ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        assert(dvmIsNativeMethod(SAVEAREA_FROM_FP(fp)->method));
5502ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        saveArea = SAVEAREA_FROM_FP(fp);
5512ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
5522ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5532ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
5542ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Pull the goodies out.  "xtra.currentPc" should be accurate since
5552ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * we update it on every instruction while the debugger is connected.
5562ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
5572ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    pCtrl->method = saveArea->method;
5582ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    // Clear out any old address set
5592ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (pCtrl->pAddressSet != NULL) {
5602ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        // (discard const)
5612ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        free((void *)pCtrl->pAddressSet);
5622ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        pCtrl->pAddressSet = NULL;
5632ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
5642ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (dvmIsNativeMethod(pCtrl->method)) {
5652ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        pCtrl->line = -1;
5662ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    } else {
5672ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        pCtrl->line = dvmLineNumFromPC(saveArea->method,
5682ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                        saveArea->xtra.currentPc - saveArea->method->insns);
56938329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng        pCtrl->pAddressSet
5702ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                = dvmAddressSetForLine(saveArea->method, pCtrl->line);
5712ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
5722ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    pCtrl->frameDepth = dvmComputeVagueFrameDepth(thread, thread->curFrame);
5732ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    pCtrl->active = true;
5742ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5752ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    LOGV("##### step init: thread=%p meth=%p '%s' line=%d frameDepth=%d depth=%s size=%s\n",
5762ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        pCtrl->thread, pCtrl->method, pCtrl->method->name,
5772ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        pCtrl->line, pCtrl->frameDepth,
5782ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmJdwpStepDepthStr(pCtrl->depth),
5792ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmJdwpStepSizeStr(pCtrl->size));
5802ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5812ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    return true;
5822ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
5832ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5842ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
5852ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Disable a single step event.
5862ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
5872ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectvoid dvmClearSingleStep(Thread* thread)
5882ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
5892ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    UNUSED_PARAMETER(thread);
5902ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5912ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    gDvm.stepControl.active = false;
5922ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
5932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
5962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Recover the "this" pointer from the current interpreted method.  "this"
5972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * is always in "in0" for non-static methods.
5982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
5992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * The "ins" start at (#of registers - #of ins).  Note in0 != v0.
6002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
6012ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * This works because "dx" guarantees that it will work.  It's probably
6022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * fairly common to have a virtual method that doesn't use its "this"
6032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * pointer, in which case we're potentially wasting a register.  However,
6042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * the debugger doesn't treat "this" as just another argument.  For
6052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * example, events (such as breakpoints) can be enabled for specific
6062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * values of "this".  There is also a separate StackFrame.ThisObject call
6072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * in JDWP that is expected to work for any non-native non-static method.
6082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
6092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Because we need it when setting up debugger event filters, we want to
6102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * be able to do this quickly.
6112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
6122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source ProjectObject* dvmGetThisPtr(const Method* method, const u4* fp)
6132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
6142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (dvmIsStaticMethod(method))
6152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return NULL;
6162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    return (Object*)fp[method->registersSize - method->insSize];
6172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
6182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#if defined(WITH_TRACKREF_CHECKS)
6212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
6222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Verify that all internally-tracked references have been released.  If
6232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * they haven't, print them and abort the VM.
6242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
6252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * "debugTrackedRefStart" indicates how many refs were on the list when
6262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * we were first invoked.
6272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
6282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectvoid dvmInterpCheckTrackedRefs(Thread* self, const Method* method,
6292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    int debugTrackedRefStart)
6302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
6312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (dvmReferenceTableEntries(&self->internalLocalRefTable)
6322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        != (size_t) debugTrackedRefStart)
6332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    {
6342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        char* desc;
6352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        Object** top;
6362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        int count;
6372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6382ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        count = dvmReferenceTableEntries(&self->internalLocalRefTable);
6392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6402ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        LOGE("TRACK: unreleased internal reference (prev=%d total=%d)\n",
6412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            debugTrackedRefStart, count);
6422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        desc = dexProtoCopyMethodDescriptor(&method->prototype);
6432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        LOGE("       current method is %s.%s %s\n", method->clazz->descriptor,
6442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            method->name, desc);
6452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        free(desc);
6462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        top = self->internalLocalRefTable.table + debugTrackedRefStart;
6472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        while (top < self->internalLocalRefTable.nextEntry) {
6482ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            LOGE("  %p (%s)\n",
6492ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                 *top,
6502ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                 ((*top)->clazz != NULL) ? (*top)->clazz->descriptor : "");
6512ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            top++;
6522ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        }
6532ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmDumpThread(self, false);
6542ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6552ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmAbort();
6562ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
6572ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    //LOGI("TRACK OK\n");
6582ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
6592ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
6602ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6612ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6622ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#ifdef LOG_INSTR
6632ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
6642ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Dump the v-registers.  Sent to the ILOG log tag.
6652ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
6662ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectvoid dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly)
6672ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
6682ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    int i, localCount;
6692ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6702ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    localCount = method->registersSize - method->insSize;
6712ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6722ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    LOG(LOG_VERBOSE, LOG_TAG"i", "Registers (fp=%p):\n", framePtr);
6732ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    for (i = method->registersSize-1; i >= 0; i--) {
6742ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        if (i >= localCount) {
6752ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            LOG(LOG_VERBOSE, LOG_TAG"i", "  v%-2d in%-2d : 0x%08x\n",
6762ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                i, i-localCount, framePtr[i]);
6772ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        } else {
6782ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            if (inOnly) {
6792ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                LOG(LOG_VERBOSE, LOG_TAG"i", "  [...]\n");
6802ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                break;
6812ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            }
6822ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            const char* name = "";
6832ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#if 0   // "locals" structure has changed -- need to rewrite this
6848afa9dfe04354e5b3917e31e3e2772885f507580Elliott Hughes            int j;
6852ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            DexFile* pDexFile = method->clazz->pDexFile;
6862ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            const DexCode* pDexCode = dvmGetMethodCode(method);
6872ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            int localsSize = dexGetLocalsSize(pDexFile, pDexCode);
6882ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            const DexLocal* locals = dvmDexGetLocals(pDexFile, pDexCode);
6892ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            for (j = 0; j < localsSize, j++) {
6902ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                if (locals[j].registerNum == (u4) i) {
6912ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                    name = dvmDexStringStr(locals[j].pName);
6922ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                    break;
6932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                }
6942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            }
6952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
6962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            LOG(LOG_VERBOSE, LOG_TAG"i", "  v%-2d      : 0x%08x %s\n",
6972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                i, framePtr[i], name);
6982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        }
6992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
7002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
7012ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
7022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
7052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * ===========================================================================
7062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *      Entry point and general support functions
7072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * ===========================================================================
7082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
7092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
71038329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng/*
7112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Construct an s4 from two consecutive half-words of switch data.
7122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * This needs to check endianness because the DEX optimizer only swaps
7132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * half-words in instruction stream.
7142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
7152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * "switchData" must be 32-bit aligned.
7162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
7172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#if __BYTE_ORDER == __LITTLE_ENDIAN
7182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectstatic inline s4 s4FromSwitchData(const void* switchData) {
7192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    return *(s4*) switchData;
7202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
7212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#else
7222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectstatic inline s4 s4FromSwitchData(const void* switchData) {
7232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    u2* data = switchData;
7242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    return data[0] | (((s4) data[1]) << 16);
725ffa5c29a95ee5cb32c5bb4c46eccb5a57f5f493bJay Freeman (saurik)}
7262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
7272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
7292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Find the matching case.  Returns the offset to the handler instructions.
7302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
7312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Returns 3 if we don't find a match (it's the size of the packed-switch
7322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * instruction).
7332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
7342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projects4 dvmInterpHandlePackedSwitch(const u2* switchData, s4 testVal)
7352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
7362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    const int kInstrLen = 3;
7372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    u2 size;
7382ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    s4 firstKey;
7392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    const s4* entries;
7402ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
7422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Packed switch data format:
7432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  ushort ident = 0x0100   magic value
7442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  ushort size             number of entries in the table
7452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  int first_key           first (and lowest) switch case value
7462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  int targets[size]       branch targets, relative to switch opcode
7472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *
7482ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Total size is (4+size*2) 16-bit code units.
7492ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
7502ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (*switchData++ != kPackedSwitchSignature) {
7512ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        /* should have been caught by verifier */
7522ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmThrowException("Ljava/lang/InternalError;",
7532ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            "bad packed switch magic");
7542ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return kInstrLen;
7552ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
7562ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7572ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    size = *switchData++;
7582ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(size > 0);
7592ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7602ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    firstKey = *switchData++;
7612ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    firstKey |= (*switchData++) << 16;
7622ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7632ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (testVal < firstKey || testVal >= firstKey + size) {
7642ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        LOGVV("Value %d not found in switch (%d-%d)\n",
7652ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            testVal, firstKey, firstKey+size-1);
7662ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return kInstrLen;
7672ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
7682ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7692ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /* The entries are guaranteed to be aligned on a 32-bit boundary;
7702ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * we can treat them as a native int array.
7712ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
7722ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    entries = (const s4*) switchData;
7732ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(((u4)entries & 0x3) == 0);
7742ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7752ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(testVal - firstKey >= 0 && testVal - firstKey < size);
7762ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    LOGVV("Value %d found in slot %d (goto 0x%02x)\n",
7772ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        testVal, testVal - firstKey,
7782ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        s4FromSwitchData(&entries[testVal - firstKey]));
7792ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    return s4FromSwitchData(&entries[testVal - firstKey]);
7802ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
7812ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7822ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
7832ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Find the matching case.  Returns the offset to the handler instructions.
7842ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
7852ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Returns 3 if we don't find a match (it's the size of the sparse-switch
7862ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * instruction).
7872ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
7882ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projects4 dvmInterpHandleSparseSwitch(const u2* switchData, s4 testVal)
7892ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
7902ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    const int kInstrLen = 3;
791e3c01dac83e6eea7f82fe81ed89cfbdd9791dbc9Carl Shapiro    u2 size;
7922ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    const s4* keys;
7932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    const s4* entries;
7942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
7962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Sparse switch data format:
7972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  ushort ident = 0x0200   magic value
7982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  ushort size             number of entries in the table; > 0
7992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  int keys[size]          keys, sorted low-to-high; 32-bit aligned
8002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  int targets[size]       branch targets, relative to switch opcode
8012ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *
8022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Total size is (2+size*4) 16-bit code units.
8032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
8042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
8052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (*switchData++ != kSparseSwitchSignature) {
8062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        /* should have been caught by verifier */
8072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmThrowException("Ljava/lang/InternalError;",
8082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            "bad sparse switch magic");
8092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return kInstrLen;
8102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
8112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
8122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    size = *switchData++;
8132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(size > 0);
81438329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng
8152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /* The keys are guaranteed to be aligned on a 32-bit boundary;
8162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * we can treat them as a native int array.
8172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
8182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    keys = (const s4*) switchData;
8192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(((u4)keys & 0x3) == 0);
8202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
8212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /* The entries are guaranteed to be aligned on a 32-bit boundary;
8222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * we can treat them as a native int array.
8232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
8242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    entries = keys + size;
8252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(((u4)entries & 0x3) == 0);
8262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
8272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
82862f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden     * Binary-search through the array of keys, which are guaranteed to
8292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * be sorted low-to-high.
8302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
83162f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden    int lo = 0;
83262f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden    int hi = size - 1;
83362f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden    while (lo <= hi) {
83462f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden        int mid = (lo + hi) >> 1;
83562f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden
83662f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden        s4 foundVal = s4FromSwitchData(&keys[mid]);
83762f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden        if (testVal < foundVal) {
83862f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden            hi = mid - 1;
83962f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden        } else if (testVal > foundVal) {
84062f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden            lo = mid + 1;
84162f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden        } else {
8422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            LOGVV("Value %d found in entry %d (goto 0x%02x)\n",
84362f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden                testVal, mid, s4FromSwitchData(&entries[mid]));
84462f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden            return s4FromSwitchData(&entries[mid]);
8452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        }
8462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
8472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
8482ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    LOGVV("Value %d not found in switch\n", testVal);
8492ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    return kInstrLen;
8502ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
8512ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
8522ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
8536f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * Copy data for a fill-array-data instruction.  On a little-endian machine
8546f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * we can just do a memcpy(), on a big-endian system we have work to do.
8556f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden *
8566f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * The trick here is that dexopt has byte-swapped each code unit, which is
8576f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * exactly what we want for short/char data.  For byte data we need to undo
8586f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * the swap, and for 4- or 8-byte values we need to swap pieces within
8596f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * each word.
8606f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden */
8616f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFaddenstatic void copySwappedArrayData(void* dest, const u2* src, u4 size, u2 width)
8626f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden{
8636f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden#if __BYTE_ORDER == __LITTLE_ENDIAN
8646f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    memcpy(dest, src, size*width);
8656f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden#else
8666f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    int i;
8676f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden
8686f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    switch (width) {
8696f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    case 1:
8706f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        /* un-swap pairs of bytes as we go */
8716f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        for (i = (size-1) & ~1; i >= 0; i -= 2) {
8726f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden            ((u1*)dest)[i] = ((u1*)src)[i+1];
8736f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden            ((u1*)dest)[i+1] = ((u1*)src)[i];
8746f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        }
8756f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        /*
8766f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden         * "src" is padded to end on a two-byte boundary, but we don't want to
8776f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden         * assume "dest" is, so we handle odd length specially.
8786f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden         */
8796f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        if ((size & 1) != 0) {
8806f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden            ((u1*)dest)[size-1] = ((u1*)src)[size];
8816f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        }
8826f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        break;
8836f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    case 2:
8846f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        /* already swapped correctly */
8856f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        memcpy(dest, src, size*width);
8866f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        break;
8876f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    case 4:
8886f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        /* swap word halves */
8896f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        for (i = 0; i < (int) size; i++) {
8906f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden            ((u4*)dest)[i] = (src[(i << 1) + 1] << 16) | src[i << 1];
8916f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        }
8926f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        break;
8936f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    case 8:
8946f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        /* swap word halves and words */
8956f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        for (i = 0; i < (int) (size << 1); i += 2) {
8966f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden            ((int*)dest)[i] = (src[(i << 1) + 3] << 16) | src[(i << 1) + 2];
8976f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden            ((int*)dest)[i+1] = (src[(i << 1) + 1] << 16) | src[i << 1];
8986f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        }
8996f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        break;
9006f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    default:
9016f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        LOGE("Unexpected width %d in copySwappedArrayData\n", width);
9026f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        dvmAbort();
9036f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        break;
9046f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    }
9056f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden#endif
9066f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden}
9076f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden
9086f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden/*
9092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Fill the array with predefined constant values.
9102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
9112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Returns true if job is completed, otherwise false to indicate that
9122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * an exception has been thrown.
9132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
91489c1feb0a69a7707b271086e749975b3f7acacf7The Android Open Source Projectbool dvmInterpHandleFillArrayData(ArrayObject* arrayObj, const u2* arrayData)
9152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
9162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    u2 width;
9172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    u4 size;
9182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
91989c1feb0a69a7707b271086e749975b3f7acacf7The Android Open Source Project    if (arrayObj == NULL) {
92089c1feb0a69a7707b271086e749975b3f7acacf7The Android Open Source Project        dvmThrowException("Ljava/lang/NullPointerException;", NULL);
9212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return false;
9222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
9237dc966014df20fea6a4643ce2736922d0a7ee2c8Barry Hayes    assert (!IS_CLASS_FLAG_SET(((Object *)arrayObj)->clazz,
9247dc966014df20fea6a4643ce2736922d0a7ee2c8Barry Hayes                               CLASS_ISOBJECTARRAY));
92589c1feb0a69a7707b271086e749975b3f7acacf7The Android Open Source Project
9262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
9272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Array data table format:
9282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  ushort ident = 0x0300   magic value
9292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  ushort width            width of each element in the table
9302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  uint   size             number of elements in the table
9312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  ubyte  data[size*width] table of data values (may contain a single-byte
9322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *                          padding at the end)
9332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *
9342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Total size is 4+(width * size + 1)/2 16-bit code units.
9352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
9362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (arrayData[0] != kArrayDataSignature) {
9372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmThrowException("Ljava/lang/InternalError;", "bad array data magic");
9382ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return false;
9392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
9402ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
9412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    width = arrayData[1];
9422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    size = arrayData[2] | (((u4)arrayData[3]) << 16);
9432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
944f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (size > arrayObj->length) {
9452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", NULL);
9462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return false;
9472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
9486f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    copySwappedArrayData(arrayObj->contents, &arrayData[4], size, width);
9492ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    return true;
9502ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
9512ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
9522ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
9532ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Find the concrete method that corresponds to "methodIdx".  The code in
9542ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * "method" is executing invoke-method with "thisClass" as its first argument.
9552ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
9562ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Returns NULL with an exception raised on failure.
9572ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
9582ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source ProjectMethod* dvmInterpFindInterfaceMethod(ClassObject* thisClass, u4 methodIdx,
9592ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    const Method* method, DvmDex* methodClassDex)
9602ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
9612ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    Method* absMethod;
9622ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    Method* methodToCall;
9632ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    int i, vtableIndex;
9642ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
9652ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
9662ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Resolve the method.  This gives us the abstract method from the
9672ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * interface class declaration.
9682ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
9692ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    absMethod = dvmDexGetResolvedMethod(methodClassDex, methodIdx);
9702ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (absMethod == NULL) {
9712ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        absMethod = dvmResolveInterfaceMethod(method->clazz, methodIdx);
9722ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        if (absMethod == NULL) {
9732ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            LOGV("+ unknown method\n");
9742ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            return NULL;
9752ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        }
9762ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
9772ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
9782ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /* make sure absMethod->methodIndex means what we think it means */
9792ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(dvmIsAbstractMethod(absMethod));
9802ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
9812ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
9822ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Run through the "this" object's iftable.  Find the entry for
9832ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * absMethod's class, then use absMethod->methodIndex to find
9842ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * the method's entry.  The value there is the offset into our
9852ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * vtable of the actual method to execute.
9862ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *
9872ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * The verifier does not guarantee that objects stored into
9882ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * interface references actually implement the interface, so this
9892ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * check cannot be eliminated.
9902ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
9912ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    for (i = 0; i < thisClass->iftableCount; i++) {
9922ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        if (thisClass->iftable[i].clazz == absMethod->clazz)
9932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            break;
9942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
9952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (i == thisClass->iftableCount) {
9962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        /* impossible in verified DEX, need to check for it in unverified */
9972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmThrowException("Ljava/lang/IncompatibleClassChangeError;",
9982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            "interface not implemented");
9992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return NULL;
10002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
10012ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
10022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(absMethod->methodIndex <
10032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        thisClass->iftable[i].clazz->virtualMethodCount);
10042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
10052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    vtableIndex =
10062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        thisClass->iftable[i].methodIndexArray[absMethod->methodIndex];
10072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(vtableIndex >= 0 && vtableIndex < thisClass->vtableCount);
10082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    methodToCall = thisClass->vtable[vtableIndex];
10092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
10102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#if 0
10112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /* this can happen when there's a stale class file */
10122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (dvmIsAbstractMethod(methodToCall)) {
10132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmThrowException("Ljava/lang/AbstractMethodError;",
10142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            "interface method not implemented");
10152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return NULL;
10162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
10172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#else
10182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(!dvmIsAbstractMethod(methodToCall) ||
10192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        methodToCall->nativeFunc != NULL);
10202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
10212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
10222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    LOGVV("+++ interface=%s.%s concrete=%s.%s\n",
10232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        absMethod->clazz->descriptor, absMethod->name,
10242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        methodToCall->clazz->descriptor, methodToCall->name);
10252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(methodToCall != NULL);
10262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
10272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    return methodToCall;
10282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
10292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
10302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
1031b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1032b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden/*
1033b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden * Helpers for dvmThrowVerificationError().
1034b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden *
1035b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden * Each returns a newly-allocated string.
1036b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden */
1037b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden#define kThrowShow_accessFromClass     1
1038af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFaddenstatic char* classNameFromIndex(const Method* method, int ref,
1039af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    VerifyErrorRefType refType, int flags)
1040b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden{
1041b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    static const int kBufLen = 256;
1042b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const DvmDex* pDvmDex = method->clazz->pDvmDex;
1043af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden
1044af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    if (refType == VERIFY_ERROR_REF_FIELD) {
1045af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        /* get class ID from field ID */
1046af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        const DexFieldId* pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref);
1047af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        ref = pFieldId->classIdx;
1048af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    } else if (refType == VERIFY_ERROR_REF_METHOD) {
1049af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        /* get class ID from method ID */
1050af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        const DexMethodId* pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref);
1051af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        ref = pMethodId->classIdx;
1052af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    }
1053af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden
1054b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, ref);
1055b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    char* dotClassName = dvmDescriptorToDot(className);
1056b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    if (flags == 0)
1057b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        return dotClassName;
1058b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1059b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    char* result = (char*) malloc(kBufLen);
1060b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1061b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    if ((flags & kThrowShow_accessFromClass) != 0) {
1062b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor);
1063b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        snprintf(result, kBufLen, "tried to access class %s from class %s",
1064b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden            dotClassName, dotFromName);
1065b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        free(dotFromName);
1066b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    } else {
1067b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        assert(false);      // should've been caught above
1068b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        result[0] = '\0';
1069b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    }
1070b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1071b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    free(dotClassName);
1072b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    return result;
1073b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden}
1074af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFaddenstatic char* fieldNameFromIndex(const Method* method, int ref,
1075af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    VerifyErrorRefType refType, int flags)
1076b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden{
1077b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    static const int kBufLen = 256;
1078b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const DvmDex* pDvmDex = method->clazz->pDvmDex;
1079b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const DexFieldId* pFieldId;
1080b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const char* className;
1081b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const char* fieldName;
1082b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1083af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    if (refType != VERIFY_ERROR_REF_FIELD) {
1084af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        LOGW("Expected ref type %d, got %d\n", VERIFY_ERROR_REF_FIELD, refType);
1085af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        return NULL;    /* no message */
1086af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    }
1087af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden
1088b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref);
1089b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    className = dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->classIdx);
1090b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    fieldName = dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx);
1091b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1092b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    char* dotName = dvmDescriptorToDot(className);
1093b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    char* result = (char*) malloc(kBufLen);
1094b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1095b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    if ((flags & kThrowShow_accessFromClass) != 0) {
1096b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor);
1097b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        snprintf(result, kBufLen, "tried to access field %s.%s from class %s",
1098b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden            dotName, fieldName, dotFromName);
1099b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        free(dotFromName);
1100b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    } else {
1101b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        snprintf(result, kBufLen, "%s.%s", dotName, fieldName);
1102b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    }
1103b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1104b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    free(dotName);
1105b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    return result;
1106b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden}
1107af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFaddenstatic char* methodNameFromIndex(const Method* method, int ref,
1108af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    VerifyErrorRefType refType, int flags)
1109b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden{
1110b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    static const int kBufLen = 384;
1111b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const DvmDex* pDvmDex = method->clazz->pDvmDex;
1112b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const DexMethodId* pMethodId;
1113b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const char* className;
1114b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const char* methodName;
1115b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1116af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    if (refType != VERIFY_ERROR_REF_METHOD) {
1117af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        LOGW("Expected ref type %d, got %d\n", VERIFY_ERROR_REF_METHOD,refType);
1118af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        return NULL;    /* no message */
1119af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    }
1120af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden
1121b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref);
1122b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    className = dexStringByTypeIdx(pDvmDex->pDexFile, pMethodId->classIdx);
1123b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    methodName = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
1124b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1125b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    char* dotName = dvmDescriptorToDot(className);
1126b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    char* result = (char*) malloc(kBufLen);
1127b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1128b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    if ((flags & kThrowShow_accessFromClass) != 0) {
1129b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor);
1130b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
1131b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        snprintf(result, kBufLen,
1132b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden            "tried to access method %s.%s:%s from class %s",
1133b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden            dotName, methodName, desc, dotFromName);
1134b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        free(dotFromName);
1135b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        free(desc);
1136b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    } else {
1137b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        snprintf(result, kBufLen, "%s.%s", dotName, methodName);
1138b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    }
1139b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1140b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    free(dotName);
1141b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    return result;
1142b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden}
1143b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
11442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
11453a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden * Throw an exception for a problem identified by the verifier.
11463a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden *
11473a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden * This is used by the invoke-verification-error instruction.  It always
11483a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden * throws an exception.
11493a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden *
1150af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden * "kind" indicates the kind of failure encountered by the verifier.  It
1151af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden * has two parts, an error code and an indication of the reference type.
11523a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden */
1153b51ea11c70602918c42764bfafe92a997d3b1803Andy McFaddenvoid dvmThrowVerificationError(const Method* method, int kind, int ref)
11543a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden{
1155af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    const int typeMask = 0xff << kVerifyErrorRefTypeShift;
1156af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    VerifyError errorKind = kind & ~typeMask;
1157af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    VerifyErrorRefType refType = kind >> kVerifyErrorRefTypeShift;
1158b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const char* exceptionName = "Ljava/lang/VerifyError;";
1159b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    char* msg = NULL;
1160b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1161af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    switch ((VerifyError) errorKind) {
1162b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_NO_CLASS:
1163b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        exceptionName = "Ljava/lang/NoClassDefFoundError;";
1164af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        msg = classNameFromIndex(method, ref, refType, 0);
1165b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1166b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_NO_FIELD:
1167b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        exceptionName = "Ljava/lang/NoSuchFieldError;";
1168af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        msg = fieldNameFromIndex(method, ref, refType, 0);
1169b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1170b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_NO_METHOD:
1171b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        exceptionName = "Ljava/lang/NoSuchMethodError;";
1172af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        msg = methodNameFromIndex(method, ref, refType, 0);
1173b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1174b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_ACCESS_CLASS:
1175b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        exceptionName = "Ljava/lang/IllegalAccessError;";
1176af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        msg = classNameFromIndex(method, ref, refType,
1177af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden            kThrowShow_accessFromClass);
1178b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1179b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_ACCESS_FIELD:
1180b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        exceptionName = "Ljava/lang/IllegalAccessError;";
1181af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        msg = fieldNameFromIndex(method, ref, refType,
1182af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden            kThrowShow_accessFromClass);
1183b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1184b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_ACCESS_METHOD:
1185b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        exceptionName = "Ljava/lang/IllegalAccessError;";
1186af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        msg = methodNameFromIndex(method, ref, refType,
1187af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden            kThrowShow_accessFromClass);
1188b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1189b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_CLASS_CHANGE:
1190b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        exceptionName = "Ljava/lang/IncompatibleClassChangeError;";
1191af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        msg = classNameFromIndex(method, ref, refType, 0);
1192b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1193b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_INSTANTIATION:
1194b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        exceptionName = "Ljava/lang/InstantiationError;";
1195af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        msg = classNameFromIndex(method, ref, refType, 0);
1196b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1197b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1198b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_GENERIC:
1199b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        /* generic VerifyError; use default exception, no message */
1200b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1201b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_NONE:
1202b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        /* should never happen; use default exception */
1203b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        assert(false);
1204b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        msg = strdup("weird - no error specified");
1205b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1206b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1207b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    /* no default clause -- want warning if enum updated */
1208b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    }
1209b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1210b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    dvmThrowException(exceptionName, msg);
1211b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    free(msg);
12123a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden}
12133a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden
12143a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden/*
12152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Main interpreter loop entry point.  Select "standard" or "debug"
12162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * interpreter and switch between them as required.
12172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
12182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * This begins executing code at the start of "method".  On exit, "pResult"
12192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * holds the return value of the method (or, if "method" returns NULL, it
12202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * holds an undefined value).
12212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
12222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * The interpreted stack frame, which holds the method arguments, has
12232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * already been set up.
12242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
12252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectvoid dvmInterpret(Thread* self, const Method* method, JValue* pResult)
12262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
12272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    InterpState interpState;
12282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    bool change;
1229ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#if defined(WITH_JIT)
1230342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee    /* Target-specific save/restore */
1231342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee    extern void dvmJitCalleeSave(double *saveArea);
1232342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee    extern void dvmJitCalleeRestore(double *saveArea);
1233ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    /* Interpreter entry points from compiled code */
1234ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    extern void dvmJitToInterpNormal();
1235ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    extern void dvmJitToInterpNoChain();
1236ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    extern void dvmJitToInterpPunt();
1237ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    extern void dvmJitToInterpSingleStep();
123840094c16d9727cc1e047a7d4bddffe04dd566211Ben Cheng    extern void dvmJitToInterpTraceSelectNoChain();
123940094c16d9727cc1e047a7d4bddffe04dd566211Ben Cheng    extern void dvmJitToInterpTraceSelect();
124038329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng    extern void dvmJitToPatchPredictedChain();
124197319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#if defined(WITH_SELF_VERIFICATION)
124240094c16d9727cc1e047a7d4bddffe04dd566211Ben Cheng    extern void dvmJitToInterpBackwardBranch();
124397319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#endif
1244ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
124538329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng    /*
1246ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng     * Reserve a static entity here to quickly setup runtime contents as
1247ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng     * gcc will issue block copy instructions.
1248ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng     */
1249ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    static struct JitToInterpEntries jitToInterpEntries = {
1250ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        dvmJitToInterpNormal,
1251ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        dvmJitToInterpNoChain,
1252ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        dvmJitToInterpPunt,
1253ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        dvmJitToInterpSingleStep,
125440094c16d9727cc1e047a7d4bddffe04dd566211Ben Cheng        dvmJitToInterpTraceSelectNoChain,
125540094c16d9727cc1e047a7d4bddffe04dd566211Ben Cheng        dvmJitToInterpTraceSelect,
125638329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng        dvmJitToPatchPredictedChain,
125797319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#if defined(WITH_SELF_VERIFICATION)
125840094c16d9727cc1e047a7d4bddffe04dd566211Ben Cheng        dvmJitToInterpBackwardBranch,
125997319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#endif
1260ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    };
12617a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng
12627a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng    /*
12637a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng     * If the previous VM left the code cache through single-stepping the
12647a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng     * inJitCodeCache flag will be set when the VM is re-entered (for example,
12657a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng     * in self-verification mode we single-step NEW_INSTANCE which may re-enter
12667a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng     * the VM through findClassFromLoaderNoInit). Because of that, we cannot
12677a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng     * assert that self->inJitCodeCache is NULL here.
12687a2697d327936e20ef5484f7819e2e4bf91c891fBen Cheng     */
1269ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#endif
1270ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
12712ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
12722ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#if defined(WITH_TRACKREF_CHECKS)
12732ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    interpState.debugTrackedRefStart =
12742ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmReferenceTableEntries(&self->internalLocalRefTable);
12752ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
12762ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    interpState.debugIsMethodEntry = true;
1277ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#if defined(WITH_JIT)
1278342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee    dvmJitCalleeSave(interpState.calleeSave);
1279a497359afa1abe4c5780c8799c6fe0edab551c2dBen Cheng    /* Initialize the state to kJitNot */
1280a497359afa1abe4c5780c8799c6fe0edab551c2dBen Cheng    interpState.jitState = kJitNot;
1281ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
1282ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    /* Setup the Jit-to-interpreter entry points */
1283ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    interpState.jitToInterpEntries = jitToInterpEntries;
128448f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee
128548f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee    /*
128648f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee     * Initialize the threshold filter [don't bother to zero out the
128748f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee     * actual table.  We're looking for matches, and an occasional
128848f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee     * false positive is acceptible.
128948f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee     */
129048f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee    interpState.lastThreshFilter = 0;
1291b88ec3cbb419b5eac23508dc6b73de2620d7521aBen Cheng
1292b88ec3cbb419b5eac23508dc6b73de2620d7521aBen Cheng    interpState.icRechainCount = PREDICTED_CHAIN_COUNTER_RECHAIN;
1293ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#endif
12942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
12952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
12962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Initialize working state.
12972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *
12982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * No need to initialize "retval".
12992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
13002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    interpState.method = method;
13012ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    interpState.fp = (u4*) self->curFrame;
13022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    interpState.pc = method->insns;
13032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    interpState.entryPoint = kInterpEntryInstr;
13042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
13052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (dvmDebuggerOrProfilerActive())
13062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        interpState.nextMode = INTERP_DBG;
13072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    else
13082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        interpState.nextMode = INTERP_STD;
13092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
13102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(!dvmIsNativeMethod(method));
13112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
13122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
13132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Make sure the class is ready to go.  Shouldn't be possible to get
13142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * here otherwise.
13152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
13162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (method->clazz->status < CLASS_INITIALIZING ||
13172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        method->clazz->status == CLASS_ERROR)
13182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    {
13192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        LOGE("ERROR: tried to execute code in unprepared class '%s' (%d)\n",
13202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            method->clazz->descriptor, method->clazz->status);
13212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmDumpThread(self, false);
13222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmAbort();
13232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
13242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
13252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    typedef bool (*Interpreter)(Thread*, InterpState*);
13262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    Interpreter stdInterp;
13272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (gDvm.executionMode == kExecutionModeInterpFast)
13282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        stdInterp = dvmMterpStd;
1329ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#if defined(WITH_JIT)
1330ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    else if (gDvm.executionMode == kExecutionModeJit)
1331ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng/* If profiling overhead can be kept low enough, we can use a profiling
1332ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * mterp fast for both Jit and "fast" modes.  If overhead is too high,
1333ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * create a specialized profiling interpreter.
1334ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng */
1335ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        stdInterp = dvmMterpStd;
1336ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#endif
13372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    else
13382ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        stdInterp = dvmInterpretStd;
13392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
13402ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    change = true;
13412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    while (change) {
13422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        switch (interpState.nextMode) {
13432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        case INTERP_STD:
13442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            LOGVV("threadid=%d: interp STD\n", self->threadId);
13452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            change = (*stdInterp)(self, &interpState);
13462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            break;
13472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        case INTERP_DBG:
13482ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            LOGVV("threadid=%d: interp DBG\n", self->threadId);
13492ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            change = dvmInterpretDbg(self, &interpState);
13502ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            break;
13512ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        default:
13522ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            dvmAbort();
13532ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        }
13542ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
13552ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
13562ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    *pResult = interpState.retval;
1357342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee#if defined(WITH_JIT)
1358342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee    dvmJitCalleeRestore(interpState.calleeSave);
1359342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee#endif
13602ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
1361