Interp.c revision 7a0bcd0de6c4da6499a088a18d1750e51204c2a6
12ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
22ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
32ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
42ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
52ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * you may not use this file except in compliance with the License.
62ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * You may obtain a copy of the License at
72ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
82ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
92ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * See the License for the specific language governing permissions and
142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * limitations under the License.
152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
1689c1feb0a69a7707b271086e749975b3f7acacf7The Android Open Source Project
172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Main interpreter entry point and support functions.
192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * The entry point selects the "standard" or "debug" interpreter and
212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * facilitates switching between them.  The standard interpreter may
222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * use the "fast" or "portable" implementation.
232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Some debugger support functions are included here.  Ideally their
252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * entire existence would be "#ifdef WITH_DEBUGGER", but we're not that
262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * aggressive in other parts of the code yet.
272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#include "Dalvik.h"
292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#include "interp/InterpDefs.h"
302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * ===========================================================================
342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *      Debugger support
352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * ===========================================================================
362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
3896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden// fwd
3996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic BreakpointSet* dvmBreakpointSetAlloc(void);
4096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic void dvmBreakpointSetFree(BreakpointSet* pSet);
4196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
4396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Initialize global breakpoint structures.
4496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
4596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenbool dvmBreakpointStartup(void)
4696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
4796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden#ifdef WITH_DEBUGGER
4896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    gDvm.breakpointSet = dvmBreakpointSetAlloc();
4996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return (gDvm.breakpointSet != NULL);
5096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden#else
5196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return true;
5296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden#endif
5396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
5496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
5596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
5696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Free resources.
5796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
5896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenvoid dvmBreakpointShutdown(void)
5996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
6096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden#ifdef WITH_DEBUGGER
6196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetFree(gDvm.breakpointSet);
6296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden#endif
6396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
6496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
6596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
6696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden#ifdef WITH_DEBUGGER
6796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
6896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * This represents a breakpoint inserted in the instruction stream.
692ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
7096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The debugger may ask us to create the same breakpoint multiple times.
7196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * We only remove the breakpoint when the last instance is cleared.
7296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
7396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddentypedef struct {
7496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    u2*         addr;                   /* absolute memory address */
7596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    u1          originalOpCode;         /* original 8-bit opcode value */
7696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int         setCount;               /* #of times this breakpoint was set */
7796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden} Breakpoint;
7896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
7996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
8096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Set of breakpoints.
8196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
8296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstruct BreakpointSet {
8396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    /* grab lock before reading or writing anything else in here */
8496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    pthread_mutex_t lock;
8596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
8696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    /* vector of breakpoint structures */
8796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int         alloc;
8896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int         count;
8996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    Breakpoint* breakpoints;
9096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden};
9196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
9296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
9396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Initialize a BreakpointSet.  Initially empty.
9496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
9596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic BreakpointSet* dvmBreakpointSetAlloc(void)
9696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
9796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    BreakpointSet* pSet = (BreakpointSet*) calloc(1, sizeof(*pSet));
9896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
9996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmInitMutex(&pSet->lock);
10096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    /* leave the rest zeroed -- will alloc on first use */
10196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
10296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return pSet;
10396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
10496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
10596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
10696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Free storage associated with a BreakpointSet.
10796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
10896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic void dvmBreakpointSetFree(BreakpointSet* pSet)
10996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
11096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (pSet == NULL)
11196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        return;
11296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
11396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    free(pSet->breakpoints);
11496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    free(pSet);
11596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
11696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
11796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
11896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Lock the breakpoint set.
11996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
12096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic void dvmBreakpointSetLock(BreakpointSet* pSet)
12196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
12296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmLockMutex(&pSet->lock);
12396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
12496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
12596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
12696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Unlock the breakpoint set.
12796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
12896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic void dvmBreakpointSetUnlock(BreakpointSet* pSet)
12996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
13096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmUnlockMutex(&pSet->lock);
13196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
13296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
13396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
13496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Return the #of breakpoints.
13596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
13696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic int dvmBreakpointSetCount(const BreakpointSet* pSet)
13796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
13896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return pSet->count;
13996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
14096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
14196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
14296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * See if we already have an entry for this address.
14396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
14496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The BreakpointSet's lock must be acquired before calling here.
14596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
14696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Returns the index of the breakpoint entry, or -1 if not found.
14796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
14896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic int dvmBreakpointSetFind(const BreakpointSet* pSet, const u2* addr)
14996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
15096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int i;
15196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
15296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    for (i = 0; i < pSet->count; i++) {
15396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        Breakpoint* pBreak = &pSet->breakpoints[i];
15496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        if (pBreak->addr == addr)
15596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            return i;
15696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
15796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
15896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return -1;
15996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
16096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
16196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
16296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Retrieve the opcode that was originally at the specified location.
16396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
16496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The BreakpointSet's lock must be acquired before calling here.
16596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
16696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Returns "true" with the opcode in *pOrig on success.
16796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
16896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic bool dvmBreakpointSetOriginalOpCode(const BreakpointSet* pSet,
16996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    const u2* addr, u1* pOrig)
17096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
17196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int idx = dvmBreakpointSetFind(pSet, addr);
17296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (idx < 0)
17396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        return false;
17496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
17596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    *pOrig = pSet->breakpoints[idx].originalOpCode;
17696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return true;
17796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
17896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
17996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
18096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Add a breakpoint at a specific address.  If the address is already
18196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * present in the table, this just increments the count.
18296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
18396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * For a new entry, this will extract and preserve the current opcode from
18496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * the instruction stream, and replace it with a breakpoint opcode.
18596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
18696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The BreakpointSet's lock must be acquired before calling here.
18796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
18896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Returns "true" on success.
18996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
19096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic bool dvmBreakpointSetAdd(BreakpointSet* pSet, Method* method,
19196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    unsigned int instrOffset)
19296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
19396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    const int kBreakpointGrowth = 10;
19496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    const u2* addr = method->insns + instrOffset;
19596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int idx = dvmBreakpointSetFind(pSet, addr);
19696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    Breakpoint* pBreak;
19796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
19896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (idx < 0) {
19996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        if (pSet->count == pSet->alloc) {
20096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            int newSize = pSet->alloc + kBreakpointGrowth;
20196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            Breakpoint* newVec;
20296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
20396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            LOGV("+++ increasing breakpoint set size to %d\n", newSize);
20496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
20596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            /* pSet->breakpoints will be NULL on first entry */
20696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            newVec = realloc(pSet->breakpoints, newSize * sizeof(Breakpoint));
20796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            if (newVec == NULL)
20896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                return false;
20996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
21096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            pSet->breakpoints = newVec;
21196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            pSet->alloc = newSize;
21296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        }
21396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
21496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        pBreak = &pSet->breakpoints[pSet->count++];
21596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        pBreak->addr = (u2*)addr;
21696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        pBreak->originalOpCode = *(u1*)addr;
21796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        pBreak->setCount = 1;
21896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
21996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        /*
22096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden         * Change the opcode.  We must ensure that the BreakpointSet
22196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden         * updates happen before we change the opcode.
22296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden         */
22396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        MEM_BARRIER();
22496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        assert(*(u1*)addr != OP_BREAKPOINT);
22596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr, OP_BREAKPOINT);
22696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    } else {
22796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        pBreak = &pSet->breakpoints[idx];
22896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        pBreak->setCount++;
22996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
23096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        /* verify instruction stream has break op */
23196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        assert(*(u1*)addr == OP_BREAKPOINT);
23296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
23396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
23496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return true;
23596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
23696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
23796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
23896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Remove one instance of the specified breakpoint.  When the count
23996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * reaches zero, the entry is removed from the table, and the original
24096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * opcode is restored.
24196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
24296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The BreakpointSet's lock must be acquired before calling here.
24396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
24496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic void dvmBreakpointSetRemove(BreakpointSet* pSet, Method* method,
24596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    unsigned int instrOffset)
24696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
24796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    const u2* addr = method->insns + instrOffset;
24896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int idx = dvmBreakpointSetFind(pSet, addr);
24996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
25096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (idx < 0) {
25196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        /* breakpoint not found in set -- unexpected */
25296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        if (*(u1*)addr == OP_BREAKPOINT) {
25396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            LOGE("Unable to restore breakpoint opcode (%s.%s +%u)\n",
25496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                method->clazz->descriptor, method->name, instrOffset);
25596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            dvmAbort();
25696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        } else {
25796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            LOGW("Breakpoint was already restored? (%s.%s +%u)\n",
25896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                method->clazz->descriptor, method->name, instrOffset);
25996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        }
26096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    } else {
26196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        Breakpoint* pBreak = &pSet->breakpoints[idx];
26296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        if (pBreak->setCount == 1) {
26396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            /*
26496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden             * Must restore opcode before removing set entry.
26596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden             */
26696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr,
26796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                pBreak->originalOpCode);
26896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            MEM_BARRIER();
26996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
27096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            if (idx != pSet->count-1) {
27196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                /* shift down */
27296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                memmove(&pSet->breakpoints[idx], &pSet->breakpoints[idx+1],
27396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                    (pSet->count-1 - idx) * sizeof(pSet->breakpoints[0]));
27496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            }
27596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            pSet->count--;
27696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            pSet->breakpoints[pSet->count].addr = (u2*) 0xdecadead; // debug
27796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        } else {
27896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            pBreak->setCount--;
27996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            assert(pBreak->setCount > 0);
28096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        }
28196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
28296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
28396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
28496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
28596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Restore the original opcode on any breakpoints that are in the specified
28696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * method.  The breakpoints are NOT removed from the set.
28796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
28896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The BreakpointSet's lock must be acquired before calling here.
28996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
29096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic void dvmBreakpointSetUndo(BreakpointSet* pSet, Method* method)
29196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
29296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    const u2* start = method->insns;
29396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    const u2* end = method->insns + dvmGetMethodInsnsSize(method);
29496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
29596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int i;
29696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    for (i = 0; i < pSet->count; i++) {
29796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        Breakpoint* pBreak = &pSet->breakpoints[i];
29896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        if (pBreak->addr >= start && pBreak->addr < end) {
29996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            LOGV("UNDO %s.%s [%d]\n",
30096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                method->clazz->descriptor, method->name, i);
30196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)pBreak->addr,
30296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                pBreak->originalOpCode);
30396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        }
30496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
30596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
30696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
30796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
30896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Put the breakpoint opcode back into the instruction stream, and check
30996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * to see if the original opcode has changed.
31096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
31196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * The BreakpointSet's lock must be acquired before calling here.
31296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
31396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenstatic void dvmBreakpointSetRedo(BreakpointSet* pSet, Method* method)
31496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
31596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    const u2* start = method->insns;
31696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    const u2* end = method->insns + dvmGetMethodInsnsSize(method);
31796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
31896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    int i;
31996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    for (i = 0; i < pSet->count; i++) {
32096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        Breakpoint* pBreak = &pSet->breakpoints[i];
32196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        if (pBreak->addr >= start && pBreak->addr < end) {
32296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            LOGV("REDO %s.%s [%d]\n",
32396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                method->clazz->descriptor, method->name, i);
32496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            u1 currentOpCode = *(u1*)pBreak->addr;
32596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            if (pBreak->originalOpCode != currentOpCode) {
32696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                /* verifier can drop in a throw-verification-error */
32796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                LOGD("NOTE: updating originalOpCode from 0x%02x to 0x%02x\n",
32896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                    pBreak->originalOpCode, currentOpCode);
32996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                pBreak->originalOpCode = currentOpCode;
33096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            }
33196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)pBreak->addr,
33296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden                OP_BREAKPOINT);
33396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        }
33496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
33596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
33696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
33796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden#endif /*WITH_DEBUGGER*/
33896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
33996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
34096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
34196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Do any debugger-attach-time initialization.
3422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
3432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectvoid dvmInitBreakpoints(void)
3442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
3452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#ifdef WITH_DEBUGGER
34696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    /* quick sanity check */
34796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    BreakpointSet* pSet = gDvm.breakpointSet;
34896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetLock(pSet);
34996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (dvmBreakpointSetCount(pSet) != 0) {
35096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        LOGW("WARNING: %d leftover breakpoints\n", dvmBreakpointSetCount(pSet));
35196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        /* generally not good, but we can keep going */
35296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
35396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetUnlock(pSet);
3542ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#else
3552ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(false);
3562ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
3572ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
3582ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
3592ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
3602ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Add an address to the list, putting it in the first non-empty slot.
3612ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
3622ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Sometimes the debugger likes to add two entries for one breakpoint.
3632ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * We add two entries here, so that we get the right behavior when it's
3642ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * removed twice.
3652ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
3662ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * This will only be run from the JDWP thread, and it will happen while
3672ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * we are updating the event list, which is synchronized.  We're guaranteed
3682ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * to be the only one adding entries, and the lock ensures that nobody
3692ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * will be trying to remove them while we're in here.
3702ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
3712ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * "addr" is the absolute address of the breakpoint bytecode.
3722ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
37396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenvoid dvmAddBreakAddr(Method* method, unsigned int instrOffset)
3742ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
3752ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#ifdef WITH_DEBUGGER
37696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    BreakpointSet* pSet = gDvm.breakpointSet;
37796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetLock(pSet);
37896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetAdd(pSet, method, instrOffset);
37996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetUnlock(pSet);
3802ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#else
3812ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(false);
3822ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
3832ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
3842ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
3852ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
3862ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Remove an address from the list by setting the entry to NULL.
3872ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
3882ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * This can be called from the JDWP thread (because the debugger has
3892ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * cancelled the breakpoint) or from an event thread (because it's a
3902ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * single-shot breakpoint, e.g. "run to line").  We only get here as
3912ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * the result of removing an entry from the event list, which is
3922ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * synchronized, so it should not be possible for two threads to be
3932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * updating breakpoints at the same time.
3942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
39596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenvoid dvmClearBreakAddr(Method* method, unsigned int instrOffset)
3962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
3972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#ifdef WITH_DEBUGGER
39896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    BreakpointSet* pSet = gDvm.breakpointSet;
39996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetLock(pSet);
40096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetRemove(pSet, method, instrOffset);
40196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetUnlock(pSet);
4022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
4032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#else
4042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(false);
4052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
4062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
4072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
40896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden#ifdef WITH_DEBUGGER
40996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
41096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Get the original opcode from under a breakpoint.
41196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
41296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenu1 dvmGetOriginalOpCode(const u2* addr)
41396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
41496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    BreakpointSet* pSet = gDvm.breakpointSet;
41596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    u1 orig = 0;
41696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
41796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetLock(pSet);
41896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    if (!dvmBreakpointSetOriginalOpCode(pSet, addr, &orig)) {
41996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        orig = *(u1*)addr;
42096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        if (orig == OP_BREAKPOINT) {
42196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            LOGE("GLITCH: can't find breakpoint, opcode is still set\n");
42296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden            dvmAbort();
42396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden        }
42496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    }
42596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetUnlock(pSet);
42696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
42796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    return orig;
42896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
42996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
43096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
43196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Temporarily "undo" any breakpoints set in a specific method.  Used
43296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * during verification.
43396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
43496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Locks the breakpoint set, and leaves it locked.
43596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
43696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenvoid dvmUndoBreakpoints(Method* method)
43796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
43896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    BreakpointSet* pSet = gDvm.breakpointSet;
43996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
44096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetLock(pSet);
44196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetUndo(pSet, method);
44296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    /* lock remains held */
44396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
44496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
44596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden/*
44696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * "Redo" the breakpoints cleared by a previous "undo", re-inserting the
44796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * breakpoint opcodes and updating the "original opcode" values.
44896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden *
44996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden * Unlocks the breakpoint set, which must be held by a previous "undo".
45096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden */
45196516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFaddenvoid dvmRedoBreakpoints(Method* method)
45296516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden{
45396516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    BreakpointSet* pSet = gDvm.breakpointSet;
45496516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
45596516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    /* lock already held */
45696516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetRedo(pSet, method);
45796516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    dvmBreakpointSetUnlock(pSet);
45896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden}
45996516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden#endif
46096516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden
4612ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
4622ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Add a single step event.  Currently this is a global item.
4632ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
4642ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * We set up some initial values based on the thread's current state.  This
4652ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * won't work well if the thread is running, so it's up to the caller to
4662ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * verify that it's suspended.
4672ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
4682ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * This is only called from the JDWP thread.
4692ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
4702ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectbool dvmAddSingleStep(Thread* thread, int size, int depth)
4712ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
4722ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#ifdef WITH_DEBUGGER
4732ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    StepControl* pCtrl = &gDvm.stepControl;
4742ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
4752ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (pCtrl->active && thread != pCtrl->thread) {
4762ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        LOGW("WARNING: single-step active for %p; adding %p\n",
4772ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            pCtrl->thread, thread);
4782ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
4792ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        /*
4802ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         * Keep going, overwriting previous.  This can happen if you
4812ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         * suspend a thread in Object.wait, hit the single-step key, then
4822ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         * switch to another thread and do the same thing again.
4832ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         * The first thread's step is still pending.
4842ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         *
4852ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         * TODO: consider making single-step per-thread.  Adds to the
4862ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         * overhead, but could be useful in rare situations.
4872ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         */
4882ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
4892ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
4902ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    pCtrl->size = size;
4912ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    pCtrl->depth = depth;
4922ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    pCtrl->thread = thread;
4932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
4942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
4952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * We may be stepping into or over method calls, or running until we
4962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * return from the current method.  To make this work we need to track
4972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * the current line, current method, and current stack depth.  We need
4982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * to be checking these after most instructions, notably those that
4992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * call methods, return from methods, or are on a different line from the
5002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * previous instruction.
5012ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *
5022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * We have to start with a snapshot of the current state.  If we're in
5032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * an interpreted method, everything we need is in the current frame.  If
5042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * we're in a native method, possibly with some extra JNI frames pushed
5052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * on by PushLocalFrame, we want to use the topmost native method.
5062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
5072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    const StackSaveArea* saveArea;
5082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    void* fp;
5092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    void* prevFp = NULL;
51038329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng
5112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    for (fp = thread->curFrame; fp != NULL; fp = saveArea->prevFrame) {
5122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        const Method* method;
5132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        saveArea = SAVEAREA_FROM_FP(fp);
5152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        method = saveArea->method;
5162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        if (!dvmIsBreakFrame(fp) && !dvmIsNativeMethod(method))
5182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            break;
5192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        prevFp = fp;
5202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
5212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (fp == NULL) {
5222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        LOGW("Unexpected: step req in native-only threadid=%d\n",
5232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            thread->threadId);
5242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return false;
5252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
5262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (prevFp != NULL) {
5272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        /*
5282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         * First interpreted frame wasn't the one at the bottom.  Break
5292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         * frames are only inserted when calling from native->interp, so we
5302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         * don't need to worry about one being here.
5312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project         */
5322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        LOGV("##### init step while in native method\n");
5332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        fp = prevFp;
5342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        assert(!dvmIsBreakFrame(fp));
5352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        assert(dvmIsNativeMethod(SAVEAREA_FROM_FP(fp)->method));
5362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        saveArea = SAVEAREA_FROM_FP(fp);
5372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
5382ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
5402ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Pull the goodies out.  "xtra.currentPc" should be accurate since
5412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * we update it on every instruction while the debugger is connected.
5422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
5432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    pCtrl->method = saveArea->method;
5442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    // Clear out any old address set
5452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (pCtrl->pAddressSet != NULL) {
5462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        // (discard const)
5472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        free((void *)pCtrl->pAddressSet);
5482ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        pCtrl->pAddressSet = NULL;
5492ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
5502ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (dvmIsNativeMethod(pCtrl->method)) {
5512ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        pCtrl->line = -1;
5522ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    } else {
5532ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        pCtrl->line = dvmLineNumFromPC(saveArea->method,
5542ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                        saveArea->xtra.currentPc - saveArea->method->insns);
55538329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng        pCtrl->pAddressSet
5562ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                = dvmAddressSetForLine(saveArea->method, pCtrl->line);
5572ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
5582ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    pCtrl->frameDepth = dvmComputeVagueFrameDepth(thread, thread->curFrame);
5592ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    pCtrl->active = true;
5602ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5612ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    LOGV("##### step init: thread=%p meth=%p '%s' line=%d frameDepth=%d depth=%s size=%s\n",
5622ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        pCtrl->thread, pCtrl->method, pCtrl->method->name,
5632ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        pCtrl->line, pCtrl->frameDepth,
5642ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmJdwpStepDepthStr(pCtrl->depth),
5652ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmJdwpStepSizeStr(pCtrl->size));
5662ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5672ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    return true;
5682ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#else
5692ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(false);
5702ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    return false;
5712ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
5722ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
5732ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5742ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
5752ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Disable a single step event.
5762ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
5772ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectvoid dvmClearSingleStep(Thread* thread)
5782ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
5792ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#ifdef WITH_DEBUGGER
5802ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    UNUSED_PARAMETER(thread);
5812ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5822ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    gDvm.stepControl.active = false;
5832ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#else
5842ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(false);
5852ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
5862ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
5872ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5882ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
5892ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
5902ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Recover the "this" pointer from the current interpreted method.  "this"
5912ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * is always in "in0" for non-static methods.
5922ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
5932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * The "ins" start at (#of registers - #of ins).  Note in0 != v0.
5942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
5952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * This works because "dx" guarantees that it will work.  It's probably
5962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * fairly common to have a virtual method that doesn't use its "this"
5972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * pointer, in which case we're potentially wasting a register.  However,
5982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * the debugger doesn't treat "this" as just another argument.  For
5992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * example, events (such as breakpoints) can be enabled for specific
6002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * values of "this".  There is also a separate StackFrame.ThisObject call
6012ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * in JDWP that is expected to work for any non-native non-static method.
6022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
6032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Because we need it when setting up debugger event filters, we want to
6042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * be able to do this quickly.
6052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
6062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source ProjectObject* dvmGetThisPtr(const Method* method, const u4* fp)
6072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
6082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (dvmIsStaticMethod(method))
6092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return NULL;
6102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    return (Object*)fp[method->registersSize - method->insSize];
6112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
6122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#if defined(WITH_TRACKREF_CHECKS)
6152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
6162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Verify that all internally-tracked references have been released.  If
6172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * they haven't, print them and abort the VM.
6182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
6192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * "debugTrackedRefStart" indicates how many refs were on the list when
6202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * we were first invoked.
6212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
6222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectvoid dvmInterpCheckTrackedRefs(Thread* self, const Method* method,
6232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    int debugTrackedRefStart)
6242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
6252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (dvmReferenceTableEntries(&self->internalLocalRefTable)
6262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        != (size_t) debugTrackedRefStart)
6272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    {
6282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        char* desc;
6292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        Object** top;
6302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        int count;
6312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        count = dvmReferenceTableEntries(&self->internalLocalRefTable);
6332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        LOGE("TRACK: unreleased internal reference (prev=%d total=%d)\n",
6352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            debugTrackedRefStart, count);
6362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        desc = dexProtoCopyMethodDescriptor(&method->prototype);
6372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        LOGE("       current method is %s.%s %s\n", method->clazz->descriptor,
6382ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            method->name, desc);
6392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        free(desc);
6402ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        top = self->internalLocalRefTable.table + debugTrackedRefStart;
6412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        while (top < self->internalLocalRefTable.nextEntry) {
6422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            LOGE("  %p (%s)\n",
6432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                 *top,
6442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                 ((*top)->clazz != NULL) ? (*top)->clazz->descriptor : "");
6452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            top++;
6462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        }
6472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmDumpThread(self, false);
6482ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6492ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmAbort();
6502ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
6512ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    //LOGI("TRACK OK\n");
6522ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
6532ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
6542ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6552ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6562ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#ifdef LOG_INSTR
6572ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
6582ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Dump the v-registers.  Sent to the ILOG log tag.
6592ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
6602ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectvoid dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly)
6612ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
6622ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    int i, localCount;
6632ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6642ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    localCount = method->registersSize - method->insSize;
6652ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6662ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    LOG(LOG_VERBOSE, LOG_TAG"i", "Registers (fp=%p):\n", framePtr);
6672ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    for (i = method->registersSize-1; i >= 0; i--) {
6682ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        if (i >= localCount) {
6692ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            LOG(LOG_VERBOSE, LOG_TAG"i", "  v%-2d in%-2d : 0x%08x\n",
6702ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                i, i-localCount, framePtr[i]);
6712ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        } else {
6722ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            if (inOnly) {
6732ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                LOG(LOG_VERBOSE, LOG_TAG"i", "  [...]\n");
6742ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                break;
6752ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            }
6762ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            const char* name = "";
6772ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            int j;
6782ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#if 0   // "locals" structure has changed -- need to rewrite this
6792ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            DexFile* pDexFile = method->clazz->pDexFile;
6802ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            const DexCode* pDexCode = dvmGetMethodCode(method);
6812ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            int localsSize = dexGetLocalsSize(pDexFile, pDexCode);
6822ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            const DexLocal* locals = dvmDexGetLocals(pDexFile, pDexCode);
6832ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            for (j = 0; j < localsSize, j++) {
6842ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                if (locals[j].registerNum == (u4) i) {
6852ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                    name = dvmDexStringStr(locals[j].pName);
6862ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                    break;
6872ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                }
6882ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            }
6892ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
6902ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            LOG(LOG_VERBOSE, LOG_TAG"i", "  v%-2d      : 0x%08x %s\n",
6912ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project                i, framePtr[i], name);
6922ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        }
6932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
6942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
6952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
6962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
6982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
6992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * ===========================================================================
7002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *      Entry point and general support functions
7012ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * ===========================================================================
7022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
7032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
70438329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng/*
7052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Construct an s4 from two consecutive half-words of switch data.
7062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * This needs to check endianness because the DEX optimizer only swaps
7072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * half-words in instruction stream.
7082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
7092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * "switchData" must be 32-bit aligned.
7102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
7112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#if __BYTE_ORDER == __LITTLE_ENDIAN
7122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectstatic inline s4 s4FromSwitchData(const void* switchData) {
7132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    return *(s4*) switchData;
7142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
7152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#else
7162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectstatic inline s4 s4FromSwitchData(const void* switchData) {
7172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    u2* data = switchData;
7182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    return data[0] | (((s4) data[1]) << 16);
719ffa5c29a95ee5cb32c5bb4c46eccb5a57f5f493bJay Freeman (saurik)}
7202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
7212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
7232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Find the matching case.  Returns the offset to the handler instructions.
7242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
7252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Returns 3 if we don't find a match (it's the size of the packed-switch
7262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * instruction).
7272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
7282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projects4 dvmInterpHandlePackedSwitch(const u2* switchData, s4 testVal)
7292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
7302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    const int kInstrLen = 3;
7312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    u2 size;
7322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    s4 firstKey;
7332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    const s4* entries;
7342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
7362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Packed switch data format:
7372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  ushort ident = 0x0100   magic value
7382ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  ushort size             number of entries in the table
7392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  int first_key           first (and lowest) switch case value
7402ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  int targets[size]       branch targets, relative to switch opcode
7412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *
7422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Total size is (4+size*2) 16-bit code units.
7432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
7442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (*switchData++ != kPackedSwitchSignature) {
7452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        /* should have been caught by verifier */
7462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmThrowException("Ljava/lang/InternalError;",
7472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            "bad packed switch magic");
7482ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return kInstrLen;
7492ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
7502ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7512ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    size = *switchData++;
7522ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(size > 0);
7532ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7542ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    firstKey = *switchData++;
7552ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    firstKey |= (*switchData++) << 16;
7562ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7572ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (testVal < firstKey || testVal >= firstKey + size) {
7582ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        LOGVV("Value %d not found in switch (%d-%d)\n",
7592ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            testVal, firstKey, firstKey+size-1);
7602ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return kInstrLen;
7612ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
7622ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7632ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /* The entries are guaranteed to be aligned on a 32-bit boundary;
7642ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * we can treat them as a native int array.
7652ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
7662ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    entries = (const s4*) switchData;
7672ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(((u4)entries & 0x3) == 0);
7682ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7692ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(testVal - firstKey >= 0 && testVal - firstKey < size);
7702ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    LOGVV("Value %d found in slot %d (goto 0x%02x)\n",
7712ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        testVal, testVal - firstKey,
7722ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        s4FromSwitchData(&entries[testVal - firstKey]));
7732ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    return s4FromSwitchData(&entries[testVal - firstKey]);
7742ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
7752ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7762ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
7772ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Find the matching case.  Returns the offset to the handler instructions.
7782ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
7792ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Returns 3 if we don't find a match (it's the size of the sparse-switch
7802ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * instruction).
7812ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
7822ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projects4 dvmInterpHandleSparseSwitch(const u2* switchData, s4 testVal)
7832ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
7842ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    const int kInstrLen = 3;
7852ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    u2 ident, size;
7862ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    const s4* keys;
7872ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    const s4* entries;
7882ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7892ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
7902ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Sparse switch data format:
7912ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  ushort ident = 0x0200   magic value
7922ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  ushort size             number of entries in the table; > 0
7932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  int keys[size]          keys, sorted low-to-high; 32-bit aligned
7942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  int targets[size]       branch targets, relative to switch opcode
7952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *
7962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Total size is (2+size*4) 16-bit code units.
7972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
7982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
7992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (*switchData++ != kSparseSwitchSignature) {
8002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        /* should have been caught by verifier */
8012ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmThrowException("Ljava/lang/InternalError;",
8022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            "bad sparse switch magic");
8032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return kInstrLen;
8042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
8052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
8062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    size = *switchData++;
8072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(size > 0);
80838329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng
8092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /* The keys are guaranteed to be aligned on a 32-bit boundary;
8102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * we can treat them as a native int array.
8112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
8122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    keys = (const s4*) switchData;
8132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(((u4)keys & 0x3) == 0);
8142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
8152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /* The entries 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    entries = keys + size;
8192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(((u4)entries & 0x3) == 0);
8202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
8212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
82262f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden     * Binary-search through the array of keys, which are guaranteed to
8232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * be sorted low-to-high.
8242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
82562f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden    int lo = 0;
82662f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden    int hi = size - 1;
82762f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden    while (lo <= hi) {
82862f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden        int mid = (lo + hi) >> 1;
82962f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden
83062f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden        s4 foundVal = s4FromSwitchData(&keys[mid]);
83162f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden        if (testVal < foundVal) {
83262f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden            hi = mid - 1;
83362f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden        } else if (testVal > foundVal) {
83462f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden            lo = mid + 1;
83562f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden        } else {
8362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            LOGVV("Value %d found in entry %d (goto 0x%02x)\n",
83762f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden                testVal, mid, s4FromSwitchData(&entries[mid]));
83862f19157a87ed8a5f97b919b92728d9029cc3861Andy McFadden            return s4FromSwitchData(&entries[mid]);
8392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        }
8402ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
8412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
8422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    LOGVV("Value %d not found in switch\n", testVal);
8432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    return kInstrLen;
8442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
8452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
8462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
8476f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * Copy data for a fill-array-data instruction.  On a little-endian machine
8486f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * we can just do a memcpy(), on a big-endian system we have work to do.
8496f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden *
8506f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * The trick here is that dexopt has byte-swapped each code unit, which is
8516f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * exactly what we want for short/char data.  For byte data we need to undo
8526f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * the swap, and for 4- or 8-byte values we need to swap pieces within
8536f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden * each word.
8546f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden */
8556f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFaddenstatic void copySwappedArrayData(void* dest, const u2* src, u4 size, u2 width)
8566f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden{
8576f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden#if __BYTE_ORDER == __LITTLE_ENDIAN
8586f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    memcpy(dest, src, size*width);
8596f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden#else
8606f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    int i;
8616f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden
8626f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    switch (width) {
8636f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    case 1:
8646f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        /* un-swap pairs of bytes as we go */
8656f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        for (i = (size-1) & ~1; i >= 0; i -= 2) {
8666f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden            ((u1*)dest)[i] = ((u1*)src)[i+1];
8676f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden            ((u1*)dest)[i+1] = ((u1*)src)[i];
8686f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        }
8696f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        /*
8706f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden         * "src" is padded to end on a two-byte boundary, but we don't want to
8716f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden         * assume "dest" is, so we handle odd length specially.
8726f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden         */
8736f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        if ((size & 1) != 0) {
8746f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden            ((u1*)dest)[size-1] = ((u1*)src)[size];
8756f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        }
8766f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        break;
8776f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    case 2:
8786f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        /* already swapped correctly */
8796f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        memcpy(dest, src, size*width);
8806f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        break;
8816f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    case 4:
8826f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        /* swap word halves */
8836f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        for (i = 0; i < (int) size; i++) {
8846f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden            ((u4*)dest)[i] = (src[(i << 1) + 1] << 16) | src[i << 1];
8856f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        }
8866f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        break;
8876f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    case 8:
8886f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        /* swap word halves and words */
8896f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        for (i = 0; i < (int) (size << 1); i += 2) {
8906f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden            ((int*)dest)[i] = (src[(i << 1) + 3] << 16) | src[(i << 1) + 2];
8916f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden            ((int*)dest)[i+1] = (src[(i << 1) + 1] << 16) | src[i << 1];
8926f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        }
8936f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        break;
8946f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    default:
8956f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        LOGE("Unexpected width %d in copySwappedArrayData\n", width);
8966f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        dvmAbort();
8976f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden        break;
8986f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    }
8996f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden#endif
9006f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden}
9016f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden
9026f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden/*
9032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Fill the array with predefined constant values.
9042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
9052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Returns true if job is completed, otherwise false to indicate that
9062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * an exception has been thrown.
9072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
90889c1feb0a69a7707b271086e749975b3f7acacf7The Android Open Source Projectbool dvmInterpHandleFillArrayData(ArrayObject* arrayObj, const u2* arrayData)
9092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
9102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    u2 width;
9112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    u4 size;
9122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
91389c1feb0a69a7707b271086e749975b3f7acacf7The Android Open Source Project    if (arrayObj == NULL) {
91489c1feb0a69a7707b271086e749975b3f7acacf7The Android Open Source Project        dvmThrowException("Ljava/lang/NullPointerException;", NULL);
9152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return false;
9162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
91789c1feb0a69a7707b271086e749975b3f7acacf7The Android Open Source Project
9182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
9192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Array data table format:
9202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  ushort ident = 0x0300   magic value
9212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  ushort width            width of each element in the table
9222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  uint   size             number of elements in the table
9232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *  ubyte  data[size*width] table of data values (may contain a single-byte
9242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *                          padding at the end)
9252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *
9262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Total size is 4+(width * size + 1)/2 16-bit code units.
9272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
9282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (arrayData[0] != kArrayDataSignature) {
9292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmThrowException("Ljava/lang/InternalError;", "bad array data magic");
9302ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return false;
9312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
9322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
9332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    width = arrayData[1];
9342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    size = arrayData[2] | (((u4)arrayData[3]) << 16);
9352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
936f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (size > arrayObj->length) {
9372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", NULL);
9382ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return false;
9392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
9406f21450e1e5d43b7c210a989ac24bb445e7e29deAndy McFadden    copySwappedArrayData(arrayObj->contents, &arrayData[4], size, width);
9412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    return true;
9422ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
9432ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
9442ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
9452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Find the concrete method that corresponds to "methodIdx".  The code in
9462ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * "method" is executing invoke-method with "thisClass" as its first argument.
9472ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
9482ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Returns NULL with an exception raised on failure.
9492ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
9502ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source ProjectMethod* dvmInterpFindInterfaceMethod(ClassObject* thisClass, u4 methodIdx,
9512ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    const Method* method, DvmDex* methodClassDex)
9522ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
9532ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    Method* absMethod;
9542ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    Method* methodToCall;
9552ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    int i, vtableIndex;
9562ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
9572ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
9582ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Resolve the method.  This gives us the abstract method from the
9592ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * interface class declaration.
9602ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
9612ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    absMethod = dvmDexGetResolvedMethod(methodClassDex, methodIdx);
9622ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (absMethod == NULL) {
9632ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        absMethod = dvmResolveInterfaceMethod(method->clazz, methodIdx);
9642ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        if (absMethod == NULL) {
9652ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            LOGV("+ unknown method\n");
9662ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            return NULL;
9672ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        }
9682ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
9692ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
9702ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /* make sure absMethod->methodIndex means what we think it means */
9712ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(dvmIsAbstractMethod(absMethod));
9722ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
9732ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
9742ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Run through the "this" object's iftable.  Find the entry for
9752ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * absMethod's class, then use absMethod->methodIndex to find
9762ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * the method's entry.  The value there is the offset into our
9772ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * vtable of the actual method to execute.
9782ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *
9792ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * The verifier does not guarantee that objects stored into
9802ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * interface references actually implement the interface, so this
9812ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * check cannot be eliminated.
9822ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
9832ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    for (i = 0; i < thisClass->iftableCount; i++) {
9842ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        if (thisClass->iftable[i].clazz == absMethod->clazz)
9852ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            break;
9862ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
9872ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (i == thisClass->iftableCount) {
9882ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        /* impossible in verified DEX, need to check for it in unverified */
9892ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmThrowException("Ljava/lang/IncompatibleClassChangeError;",
9902ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            "interface not implemented");
9912ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return NULL;
9922ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
9932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
9942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(absMethod->methodIndex <
9952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        thisClass->iftable[i].clazz->virtualMethodCount);
9962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
9972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    vtableIndex =
9982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        thisClass->iftable[i].methodIndexArray[absMethod->methodIndex];
9992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(vtableIndex >= 0 && vtableIndex < thisClass->vtableCount);
10002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    methodToCall = thisClass->vtable[vtableIndex];
10012ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
10022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#if 0
10032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /* this can happen when there's a stale class file */
10042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (dvmIsAbstractMethod(methodToCall)) {
10052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmThrowException("Ljava/lang/AbstractMethodError;",
10062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            "interface method not implemented");
10072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        return NULL;
10082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
10092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#else
10102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(!dvmIsAbstractMethod(methodToCall) ||
10112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        methodToCall->nativeFunc != NULL);
10122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
10132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
10142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    LOGVV("+++ interface=%s.%s concrete=%s.%s\n",
10152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        absMethod->clazz->descriptor, absMethod->name,
10162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        methodToCall->clazz->descriptor, methodToCall->name);
10172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(methodToCall != NULL);
10182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
10192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    return methodToCall;
10202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
10212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
10222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
1023b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1024b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden/*
1025b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden * Helpers for dvmThrowVerificationError().
1026b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden *
1027b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden * Each returns a newly-allocated string.
1028b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden */
1029b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden#define kThrowShow_accessFromClass     1
1030af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFaddenstatic char* classNameFromIndex(const Method* method, int ref,
1031af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    VerifyErrorRefType refType, int flags)
1032b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden{
1033b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    static const int kBufLen = 256;
1034b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const DvmDex* pDvmDex = method->clazz->pDvmDex;
1035af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden
1036af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    if (refType == VERIFY_ERROR_REF_FIELD) {
1037af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        /* get class ID from field ID */
1038af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        const DexFieldId* pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref);
1039af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        ref = pFieldId->classIdx;
1040af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    } else if (refType == VERIFY_ERROR_REF_METHOD) {
1041af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        /* get class ID from method ID */
1042af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        const DexMethodId* pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref);
1043af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        ref = pMethodId->classIdx;
1044af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    }
1045af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden
1046b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, ref);
1047b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    char* dotClassName = dvmDescriptorToDot(className);
1048b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    if (flags == 0)
1049b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        return dotClassName;
1050b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1051b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    char* result = (char*) malloc(kBufLen);
1052b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1053b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    if ((flags & kThrowShow_accessFromClass) != 0) {
1054b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor);
1055b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        snprintf(result, kBufLen, "tried to access class %s from class %s",
1056b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden            dotClassName, dotFromName);
1057b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        free(dotFromName);
1058b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    } else {
1059b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        assert(false);      // should've been caught above
1060b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        result[0] = '\0';
1061b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    }
1062b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1063b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    free(dotClassName);
1064b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    return result;
1065b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden}
1066af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFaddenstatic char* fieldNameFromIndex(const Method* method, int ref,
1067af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    VerifyErrorRefType refType, int flags)
1068b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden{
1069b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    static const int kBufLen = 256;
1070b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const DvmDex* pDvmDex = method->clazz->pDvmDex;
1071b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const DexFieldId* pFieldId;
1072b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const char* className;
1073b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const char* fieldName;
1074b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1075af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    if (refType != VERIFY_ERROR_REF_FIELD) {
1076af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        LOGW("Expected ref type %d, got %d\n", VERIFY_ERROR_REF_FIELD, refType);
1077af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        return NULL;    /* no message */
1078af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    }
1079af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden
1080b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref);
1081b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    className = dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->classIdx);
1082b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    fieldName = dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx);
1083b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1084b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    char* dotName = dvmDescriptorToDot(className);
1085b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    char* result = (char*) malloc(kBufLen);
1086b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1087b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    if ((flags & kThrowShow_accessFromClass) != 0) {
1088b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor);
1089b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        snprintf(result, kBufLen, "tried to access field %s.%s from class %s",
1090b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden            dotName, fieldName, dotFromName);
1091b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        free(dotFromName);
1092b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    } else {
1093b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        snprintf(result, kBufLen, "%s.%s", dotName, fieldName);
1094b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    }
1095b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1096b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    free(dotName);
1097b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    return result;
1098b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden}
1099af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFaddenstatic char* methodNameFromIndex(const Method* method, int ref,
1100af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    VerifyErrorRefType refType, int flags)
1101b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden{
1102b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    static const int kBufLen = 384;
1103b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const DvmDex* pDvmDex = method->clazz->pDvmDex;
1104b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const DexMethodId* pMethodId;
1105b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const char* className;
1106b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const char* methodName;
1107b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1108af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    if (refType != VERIFY_ERROR_REF_METHOD) {
1109af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        LOGW("Expected ref type %d, got %d\n", VERIFY_ERROR_REF_METHOD,refType);
1110af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        return NULL;    /* no message */
1111af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    }
1112af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden
1113b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref);
1114b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    className = dexStringByTypeIdx(pDvmDex->pDexFile, pMethodId->classIdx);
1115b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    methodName = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
1116b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1117b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    char* dotName = dvmDescriptorToDot(className);
1118b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    char* result = (char*) malloc(kBufLen);
1119b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1120b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    if ((flags & kThrowShow_accessFromClass) != 0) {
1121b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor);
1122b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
1123b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        snprintf(result, kBufLen,
1124b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden            "tried to access method %s.%s:%s from class %s",
1125b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden            dotName, methodName, desc, dotFromName);
1126b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        free(dotFromName);
1127b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        free(desc);
1128b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    } else {
1129b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        snprintf(result, kBufLen, "%s.%s", dotName, methodName);
1130b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    }
1131b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1132b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    free(dotName);
1133b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    return result;
1134b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden}
1135b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
11362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project/*
11373a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden * Throw an exception for a problem identified by the verifier.
11383a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden *
11393a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden * This is used by the invoke-verification-error instruction.  It always
11403a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden * throws an exception.
11413a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden *
1142af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden * "kind" indicates the kind of failure encountered by the verifier.  It
1143af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden * has two parts, an error code and an indication of the reference type.
11443a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden */
1145b51ea11c70602918c42764bfafe92a997d3b1803Andy McFaddenvoid dvmThrowVerificationError(const Method* method, int kind, int ref)
11463a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden{
1147af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    const int typeMask = 0xff << kVerifyErrorRefTypeShift;
1148af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    VerifyError errorKind = kind & ~typeMask;
1149af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    VerifyErrorRefType refType = kind >> kVerifyErrorRefTypeShift;
1150b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    const char* exceptionName = "Ljava/lang/VerifyError;";
1151b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    char* msg = NULL;
1152b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1153af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden    switch ((VerifyError) errorKind) {
1154b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_NO_CLASS:
1155b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        exceptionName = "Ljava/lang/NoClassDefFoundError;";
1156af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        msg = classNameFromIndex(method, ref, refType, 0);
1157b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1158b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_NO_FIELD:
1159b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        exceptionName = "Ljava/lang/NoSuchFieldError;";
1160af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        msg = fieldNameFromIndex(method, ref, refType, 0);
1161b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1162b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_NO_METHOD:
1163b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        exceptionName = "Ljava/lang/NoSuchMethodError;";
1164af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        msg = methodNameFromIndex(method, ref, refType, 0);
1165b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1166b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_ACCESS_CLASS:
1167b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        exceptionName = "Ljava/lang/IllegalAccessError;";
1168af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        msg = classNameFromIndex(method, ref, refType,
1169af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden            kThrowShow_accessFromClass);
1170b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1171b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_ACCESS_FIELD:
1172b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        exceptionName = "Ljava/lang/IllegalAccessError;";
1173af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        msg = fieldNameFromIndex(method, ref, refType,
1174af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden            kThrowShow_accessFromClass);
1175b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1176b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_ACCESS_METHOD:
1177b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        exceptionName = "Ljava/lang/IllegalAccessError;";
1178af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        msg = methodNameFromIndex(method, ref, refType,
1179af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden            kThrowShow_accessFromClass);
1180b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1181b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_CLASS_CHANGE:
1182b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        exceptionName = "Ljava/lang/IncompatibleClassChangeError;";
1183af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        msg = classNameFromIndex(method, ref, refType, 0);
1184b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1185b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_INSTANTIATION:
1186b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        exceptionName = "Ljava/lang/InstantiationError;";
1187af0e838887d3a2fa76e0d2716e39adf2bb0c01a1Andy McFadden        msg = classNameFromIndex(method, ref, refType, 0);
1188b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1189b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1190b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_GENERIC:
1191b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        /* generic VerifyError; use default exception, no message */
1192b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1193b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    case VERIFY_ERROR_NONE:
1194b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        /* should never happen; use default exception */
1195b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        assert(false);
1196b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        msg = strdup("weird - no error specified");
1197b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden        break;
1198b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1199b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    /* no default clause -- want warning if enum updated */
1200b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    }
1201b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden
1202b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    dvmThrowException(exceptionName, msg);
1203b51ea11c70602918c42764bfafe92a997d3b1803Andy McFadden    free(msg);
12043a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden}
12053a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden
12063a1aedbc9777eab6275a360b93b81b079464238eAndy McFadden/*
12072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * Main interpreter loop entry point.  Select "standard" or "debug"
12082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * interpreter and switch between them as required.
12092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
12102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * This begins executing code at the start of "method".  On exit, "pResult"
12112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * holds the return value of the method (or, if "method" returns NULL, it
12122ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * holds an undefined value).
12132ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project *
12142ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * The interpreted stack frame, which holds the method arguments, has
12152ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project * already been set up.
12162ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project */
12172ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Projectvoid dvmInterpret(Thread* self, const Method* method, JValue* pResult)
12182ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project{
12192ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    InterpState interpState;
12202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    bool change;
1221ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#if defined(WITH_JIT)
1222342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee    /* Target-specific save/restore */
1223342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee    extern void dvmJitCalleeSave(double *saveArea);
1224342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee    extern void dvmJitCalleeRestore(double *saveArea);
1225ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    /* Interpreter entry points from compiled code */
1226ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    extern void dvmJitToInterpNormal();
1227ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    extern void dvmJitToInterpNoChain();
1228ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    extern void dvmJitToInterpPunt();
1229ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    extern void dvmJitToInterpSingleStep();
1230ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    extern void dvmJitToTraceSelect();
123138329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng    extern void dvmJitToPatchPredictedChain();
123297319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#if defined(WITH_SELF_VERIFICATION)
123397319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao    extern void dvmJitToBackwardBranch();
123497319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#endif
1235ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
123638329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng    /*
1237ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng     * Reserve a static entity here to quickly setup runtime contents as
1238ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng     * gcc will issue block copy instructions.
1239ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng     */
1240ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    static struct JitToInterpEntries jitToInterpEntries = {
1241ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        dvmJitToInterpNormal,
1242ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        dvmJitToInterpNoChain,
1243ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        dvmJitToInterpPunt,
1244ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        dvmJitToInterpSingleStep,
1245ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        dvmJitToTraceSelect,
124638329f5678fd7a4879528b02a0ab60322d38a897Ben Cheng        dvmJitToPatchPredictedChain,
124797319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#if defined(WITH_SELF_VERIFICATION)
124897319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao        dvmJitToBackwardBranch,
124997319a8a234e9fe1cf90ca39aa6eca37d729afd5Jeff Hao#endif
1250ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    };
12517a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng
12527a0bcd0de6c4da6499a088a18d1750e51204c2a6Ben Cheng    assert(self->inJitCodeCache == NULL);
1253ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#endif
1254ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
12552ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
12562ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#if defined(WITH_TRACKREF_CHECKS)
12572ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    interpState.debugTrackedRefStart =
12582ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmReferenceTableEntries(&self->internalLocalRefTable);
12592ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
12602ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
12612ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    interpState.debugIsMethodEntry = true;
12622ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
1263ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#if defined(WITH_JIT)
1264342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee    dvmJitCalleeSave(interpState.calleeSave);
1265ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    interpState.jitState = gDvmJit.pJitEntryTable ? kJitNormal : kJitOff;
1266ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng
1267ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    /* Setup the Jit-to-interpreter entry points */
1268ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    interpState.jitToInterpEntries = jitToInterpEntries;
126948f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee
127048f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee    /*
127148f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee     * Initialize the threshold filter [don't bother to zero out the
127248f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee     * actual table.  We're looking for matches, and an occasional
127348f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee     * false positive is acceptible.
127448f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee     */
127548f1824fd36241067e7bed2302cc00b2d880be7fBill Buzbee    interpState.lastThreshFilter = 0;
1276ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#endif
12772ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
12782ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
12792ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Initialize working state.
12802ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     *
12812ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * No need to initialize "retval".
12822ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
12832ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    interpState.method = method;
12842ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    interpState.fp = (u4*) self->curFrame;
12852ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    interpState.pc = method->insns;
12862ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    interpState.entryPoint = kInterpEntryInstr;
12872ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
12882ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (dvmDebuggerOrProfilerActive())
12892ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        interpState.nextMode = INTERP_DBG;
12902ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    else
12912ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        interpState.nextMode = INTERP_STD;
12922ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
12932ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    assert(!dvmIsNativeMethod(method));
12942ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
12952ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    /*
12962ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * Make sure the class is ready to go.  Shouldn't be possible to get
12972ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     * here otherwise.
12982ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project     */
12992ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (method->clazz->status < CLASS_INITIALIZING ||
13002ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        method->clazz->status == CLASS_ERROR)
13012ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    {
13022ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        LOGE("ERROR: tried to execute code in unprepared class '%s' (%d)\n",
13032ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            method->clazz->descriptor, method->clazz->status);
13042ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmDumpThread(self, false);
13052ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        dvmAbort();
13062ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
13072ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
13082ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    typedef bool (*Interpreter)(Thread*, InterpState*);
13092ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    Interpreter stdInterp;
13102ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    if (gDvm.executionMode == kExecutionModeInterpFast)
13112ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        stdInterp = dvmMterpStd;
1312ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#if defined(WITH_JIT)
1313ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng    else if (gDvm.executionMode == kExecutionModeJit)
1314ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng/* If profiling overhead can be kept low enough, we can use a profiling
1315ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * mterp fast for both Jit and "fast" modes.  If overhead is too high,
1316ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng * create a specialized profiling interpreter.
1317ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng */
1318ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng        stdInterp = dvmMterpStd;
1319ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#endif
13202ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    else
13212ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        stdInterp = dvmInterpretStd;
13222ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
13232ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    change = true;
13242ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    while (change) {
13252ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        switch (interpState.nextMode) {
13262ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        case INTERP_STD:
13272ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            LOGVV("threadid=%d: interp STD\n", self->threadId);
13282ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            change = (*stdInterp)(self, &interpState);
13292ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            break;
1330ba4fc8bfc1bccae048403bd1cea3b869dca61dd7Ben Cheng#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER) || defined(WITH_JIT)
13312ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        case INTERP_DBG:
13322ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            LOGVV("threadid=%d: interp DBG\n", self->threadId);
13332ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            change = dvmInterpretDbg(self, &interpState);
13342ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            break;
13352ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project#endif
13362ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        default:
13372ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project            dvmAbort();
13382ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project        }
13392ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    }
13402ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project
13412ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project    *pResult = interpState.retval;
1342342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee#if defined(WITH_JIT)
1343342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee    dvmJitCalleeRestore(interpState.calleeSave);
1344342806dae77556290dfe0760e6fe3117d812c7baBill Buzbee#endif
13452ad60cfc28e14ee8f0bb038720836a4696c478aThe Android Open Source Project}
1346