diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:14 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:14 -0800 |
commit | f72d5de56a522ac3be03873bdde26f23a5eeeb3c (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /vm/interp | |
parent | 31e30105703263782efd450d356cd67ea01af3b7 (diff) | |
download | android_dalvik-f72d5de56a522ac3be03873bdde26f23a5eeeb3c.tar.gz android_dalvik-f72d5de56a522ac3be03873bdde26f23a5eeeb3c.tar.bz2 android_dalvik-f72d5de56a522ac3be03873bdde26f23a5eeeb3c.zip |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'vm/interp')
-rw-r--r-- | vm/interp/Interp.c | 718 | ||||
-rw-r--r-- | vm/interp/Interp.h | 37 | ||||
-rw-r--r-- | vm/interp/InterpDefs.h | 148 | ||||
-rw-r--r-- | vm/interp/README.txt | 4 | ||||
-rw-r--r-- | vm/interp/Stack.c | 1233 | ||||
-rw-r--r-- | vm/interp/Stack.h | 277 |
6 files changed, 0 insertions, 2417 deletions
diff --git a/vm/interp/Interp.c b/vm/interp/Interp.c deleted file mode 100644 index 27b9582ab..000000000 --- a/vm/interp/Interp.c +++ /dev/null @@ -1,718 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Main interpreter entry point and support functions. - * - * The entry point selects the "standard" or "debug" interpreter and - * facilitates switching between them. The standard interpreter may - * use the "fast" or "portable" implementation. - * - * Some debugger support functions are included here. Ideally their - * entire existence would be "#ifdef WITH_DEBUGGER", but we're not that - * aggressive in other parts of the code yet. - */ -#include "Dalvik.h" -#include "interp/InterpDefs.h" - - -/* - * =========================================================================== - * Debugger support - * =========================================================================== - */ - -/* - * Initialize the breakpoint address lookup table when the debugger attaches. - * - * This shouldn't be necessary -- the global area is initially zeroed out, - * and the events should be cleaning up after themselves. - */ -void dvmInitBreakpoints(void) -{ -#ifdef WITH_DEBUGGER - memset(gDvm.debugBreakAddr, 0, sizeof(gDvm.debugBreakAddr)); -#else - assert(false); -#endif -} - -/* - * Add an address to the list, putting it in the first non-empty slot. - * - * Sometimes the debugger likes to add two entries for one breakpoint. - * We add two entries here, so that we get the right behavior when it's - * removed twice. - * - * This will only be run from the JDWP thread, and it will happen while - * we are updating the event list, which is synchronized. We're guaranteed - * to be the only one adding entries, and the lock ensures that nobody - * will be trying to remove them while we're in here. - * - * "addr" is the absolute address of the breakpoint bytecode. - */ -void dvmAddBreakAddr(Method* method, int instrOffset) -{ -#ifdef WITH_DEBUGGER - const u2* addr = method->insns + instrOffset; - const u2** ptr = gDvm.debugBreakAddr; - int i; - - LOGV("BKP: add %p %s.%s (%s:%d)\n", - addr, method->clazz->descriptor, method->name, - dvmGetMethodSourceFile(method), dvmLineNumFromPC(method, instrOffset)); - - method->debugBreakpointCount++; - for (i = 0; i < MAX_BREAKPOINTS; i++, ptr++) { - if (*ptr == NULL) { - *ptr = addr; - break; - } - } - if (i == MAX_BREAKPOINTS) { - /* no room; size is too small or we're not cleaning up properly */ - LOGE("ERROR: max breakpoints exceeded\n"); - assert(false); - } -#else - assert(false); -#endif -} - -/* - * Remove an address from the list by setting the entry to NULL. - * - * This can be called from the JDWP thread (because the debugger has - * cancelled the breakpoint) or from an event thread (because it's a - * single-shot breakpoint, e.g. "run to line"). We only get here as - * the result of removing an entry from the event list, which is - * synchronized, so it should not be possible for two threads to be - * updating breakpoints at the same time. - */ -void dvmClearBreakAddr(Method* method, int instrOffset) -{ -#ifdef WITH_DEBUGGER - const u2* addr = method->insns + instrOffset; - const u2** ptr = gDvm.debugBreakAddr; - int i; - - LOGV("BKP: clear %p %s.%s (%s:%d)\n", - addr, method->clazz->descriptor, method->name, - dvmGetMethodSourceFile(method), dvmLineNumFromPC(method, instrOffset)); - - method->debugBreakpointCount--; - assert(method->debugBreakpointCount >= 0); - for (i = 0; i < MAX_BREAKPOINTS; i++, ptr++) { - if (*ptr == addr) { - *ptr = NULL; - break; - } - } - if (i == MAX_BREAKPOINTS) { - /* didn't find it */ - LOGE("ERROR: breakpoint on %p not found\n", addr); - assert(false); - } -#else - assert(false); -#endif -} - -/* - * Add a single step event. Currently this is a global item. - * - * We set up some initial values based on the thread's current state. This - * won't work well if the thread is running, so it's up to the caller to - * verify that it's suspended. - * - * This is only called from the JDWP thread. - */ -bool dvmAddSingleStep(Thread* thread, int size, int depth) -{ -#ifdef WITH_DEBUGGER - StepControl* pCtrl = &gDvm.stepControl; - - if (pCtrl->active && thread != pCtrl->thread) { - LOGW("WARNING: single-step active for %p; adding %p\n", - pCtrl->thread, thread); - - /* - * Keep going, overwriting previous. This can happen if you - * suspend a thread in Object.wait, hit the single-step key, then - * switch to another thread and do the same thing again. - * The first thread's step is still pending. - * - * TODO: consider making single-step per-thread. Adds to the - * overhead, but could be useful in rare situations. - */ - } - - pCtrl->size = size; - pCtrl->depth = depth; - pCtrl->thread = thread; - - /* - * We may be stepping into or over method calls, or running until we - * return from the current method. To make this work we need to track - * the current line, current method, and current stack depth. We need - * to be checking these after most instructions, notably those that - * call methods, return from methods, or are on a different line from the - * previous instruction. - * - * We have to start with a snapshot of the current state. If we're in - * an interpreted method, everything we need is in the current frame. If - * we're in a native method, possibly with some extra JNI frames pushed - * on by PushLocalFrame, we want to use the topmost native method. - */ - const StackSaveArea* saveArea; - void* fp; - void* prevFp = NULL; - - for (fp = thread->curFrame; fp != NULL; fp = saveArea->prevFrame) { - const Method* method; - - saveArea = SAVEAREA_FROM_FP(fp); - method = saveArea->method; - - if (!dvmIsBreakFrame(fp) && !dvmIsNativeMethod(method)) - break; - prevFp = fp; - } - if (fp == NULL) { - LOGW("Unexpected: step req in native-only threadid=%d\n", - thread->threadId); - return false; - } - if (prevFp != NULL) { - /* - * First interpreted frame wasn't the one at the bottom. Break - * frames are only inserted when calling from native->interp, so we - * don't need to worry about one being here. - */ - LOGV("##### init step while in native method\n"); - fp = prevFp; - assert(!dvmIsBreakFrame(fp)); - assert(dvmIsNativeMethod(SAVEAREA_FROM_FP(fp)->method)); - saveArea = SAVEAREA_FROM_FP(fp); - } - - /* - * Pull the goodies out. "xtra.currentPc" should be accurate since - * we update it on every instruction while the debugger is connected. - */ - pCtrl->method = saveArea->method; - // Clear out any old address set - if (pCtrl->pAddressSet != NULL) { - // (discard const) - free((void *)pCtrl->pAddressSet); - pCtrl->pAddressSet = NULL; - } - if (dvmIsNativeMethod(pCtrl->method)) { - pCtrl->line = -1; - } else { - pCtrl->line = dvmLineNumFromPC(saveArea->method, - saveArea->xtra.currentPc - saveArea->method->insns); - pCtrl->pAddressSet - = dvmAddressSetForLine(saveArea->method, pCtrl->line); - } - pCtrl->frameDepth = dvmComputeVagueFrameDepth(thread, thread->curFrame); - pCtrl->active = true; - - LOGV("##### step init: thread=%p meth=%p '%s' line=%d frameDepth=%d depth=%s size=%s\n", - pCtrl->thread, pCtrl->method, pCtrl->method->name, - pCtrl->line, pCtrl->frameDepth, - dvmJdwpStepDepthStr(pCtrl->depth), - dvmJdwpStepSizeStr(pCtrl->size)); - - return true; -#else - assert(false); - return false; -#endif -} - -/* - * Disable a single step event. - */ -void dvmClearSingleStep(Thread* thread) -{ -#ifdef WITH_DEBUGGER - UNUSED_PARAMETER(thread); - - gDvm.stepControl.active = false; -#else - assert(false); -#endif -} - - -/* - * Recover the "this" pointer from the current interpreted method. "this" - * is always in "in0" for non-static methods. - * - * The "ins" start at (#of registers - #of ins). Note in0 != v0. - * - * This works because "dx" guarantees that it will work. It's probably - * fairly common to have a virtual method that doesn't use its "this" - * pointer, in which case we're potentially wasting a register. However, - * the debugger doesn't treat "this" as just another argument. For - * example, events (such as breakpoints) can be enabled for specific - * values of "this". There is also a separate StackFrame.ThisObject call - * in JDWP that is expected to work for any non-native non-static method. - * - * Because we need it when setting up debugger event filters, we want to - * be able to do this quickly. - */ -Object* dvmGetThisPtr(const Method* method, const u4* fp) -{ - if (dvmIsStaticMethod(method)) - return NULL; - return (Object*)fp[method->registersSize - method->insSize]; -} - - -#if defined(WITH_TRACKREF_CHECKS) -/* - * Verify that all internally-tracked references have been released. If - * they haven't, print them and abort the VM. - * - * "debugTrackedRefStart" indicates how many refs were on the list when - * we were first invoked. - */ -void dvmInterpCheckTrackedRefs(Thread* self, const Method* method, - int debugTrackedRefStart) -{ - if (dvmReferenceTableEntries(&self->internalLocalRefTable) - != (size_t) debugTrackedRefStart) - { - char* desc; - Object** top; - int count; - - count = dvmReferenceTableEntries(&self->internalLocalRefTable); - - LOGE("TRACK: unreleased internal reference (prev=%d total=%d)\n", - debugTrackedRefStart, count); - desc = dexProtoCopyMethodDescriptor(&method->prototype); - LOGE(" current method is %s.%s %s\n", method->clazz->descriptor, - method->name, desc); - free(desc); - top = self->internalLocalRefTable.table + debugTrackedRefStart; - while (top < self->internalLocalRefTable.nextEntry) { - LOGE(" %p (%s)\n", - *top, - ((*top)->clazz != NULL) ? (*top)->clazz->descriptor : ""); - top++; - } - dvmDumpThread(self, false); - - dvmAbort(); - } - //LOGI("TRACK OK\n"); -} -#endif - - -#ifdef LOG_INSTR -/* - * Dump the v-registers. Sent to the ILOG log tag. - */ -void dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly) -{ - int i, localCount; - - localCount = method->registersSize - method->insSize; - - LOG(LOG_VERBOSE, LOG_TAG"i", "Registers (fp=%p):\n", framePtr); - for (i = method->registersSize-1; i >= 0; i--) { - if (i >= localCount) { - LOG(LOG_VERBOSE, LOG_TAG"i", " v%-2d in%-2d : 0x%08x\n", - i, i-localCount, framePtr[i]); - } else { - if (inOnly) { - LOG(LOG_VERBOSE, LOG_TAG"i", " [...]\n"); - break; - } - const char* name = ""; - int j; -#if 0 // "locals" structure has changed -- need to rewrite this - DexFile* pDexFile = method->clazz->pDexFile; - const DexCode* pDexCode = dvmGetMethodCode(method); - int localsSize = dexGetLocalsSize(pDexFile, pDexCode); - const DexLocal* locals = dvmDexGetLocals(pDexFile, pDexCode); - for (j = 0; j < localsSize, j++) { - if (locals[j].registerNum == (u4) i) { - name = dvmDexStringStr(locals[j].pName); - break; - } - } -#endif - LOG(LOG_VERBOSE, LOG_TAG"i", " v%-2d : 0x%08x %s\n", - i, framePtr[i], name); - } - } -} -#endif - - -/* - * =========================================================================== - * Entry point and general support functions - * =========================================================================== - */ - -/* - * Construct an s4 from two consecutive half-words of switch data. - * This needs to check endianness because the DEX optimizer only swaps - * half-words in instruction stream. - * - * "switchData" must be 32-bit aligned. - */ -#if __BYTE_ORDER == __LITTLE_ENDIAN -static inline s4 s4FromSwitchData(const void* switchData) { - return *(s4*) switchData; -} -#else -static inline s4 s4FromSwitchData(const void* switchData) { - u2* data = switchData; - return data[0] | (((s4) data[1]) << 16); -#endif - -/* - * Find the matching case. Returns the offset to the handler instructions. - * - * Returns 3 if we don't find a match (it's the size of the packed-switch - * instruction). - */ -s4 dvmInterpHandlePackedSwitch(const u2* switchData, s4 testVal) -{ - const int kInstrLen = 3; - u2 size; - s4 firstKey; - const s4* entries; - - /* - * Packed switch data format: - * ushort ident = 0x0100 magic value - * ushort size number of entries in the table - * int first_key first (and lowest) switch case value - * int targets[size] branch targets, relative to switch opcode - * - * Total size is (4+size*2) 16-bit code units. - */ - if (*switchData++ != kPackedSwitchSignature) { - /* should have been caught by verifier */ - dvmThrowException("Ljava/lang/InternalError;", - "bad packed switch magic"); - return kInstrLen; - } - - size = *switchData++; - assert(size > 0); - - firstKey = *switchData++; - firstKey |= (*switchData++) << 16; - - if (testVal < firstKey || testVal >= firstKey + size) { - LOGVV("Value %d not found in switch (%d-%d)\n", - testVal, firstKey, firstKey+size-1); - return kInstrLen; - } - - /* The entries are guaranteed to be aligned on a 32-bit boundary; - * we can treat them as a native int array. - */ - entries = (const s4*) switchData; - assert(((u4)entries & 0x3) == 0); - - assert(testVal - firstKey >= 0 && testVal - firstKey < size); - LOGVV("Value %d found in slot %d (goto 0x%02x)\n", - testVal, testVal - firstKey, - s4FromSwitchData(&entries[testVal - firstKey])); - return s4FromSwitchData(&entries[testVal - firstKey]); -} - -/* - * Find the matching case. Returns the offset to the handler instructions. - * - * Returns 3 if we don't find a match (it's the size of the sparse-switch - * instruction). - */ -s4 dvmInterpHandleSparseSwitch(const u2* switchData, s4 testVal) -{ - const int kInstrLen = 3; - u2 ident, size; - const s4* keys; - const s4* entries; - int i; - - /* - * Sparse switch data format: - * ushort ident = 0x0200 magic value - * ushort size number of entries in the table; > 0 - * int keys[size] keys, sorted low-to-high; 32-bit aligned - * int targets[size] branch targets, relative to switch opcode - * - * Total size is (2+size*4) 16-bit code units. - */ - - if (*switchData++ != kSparseSwitchSignature) { - /* should have been caught by verifier */ - dvmThrowException("Ljava/lang/InternalError;", - "bad sparse switch magic"); - return kInstrLen; - } - - size = *switchData++; - assert(size > 0); - - /* The keys are guaranteed to be aligned on a 32-bit boundary; - * we can treat them as a native int array. - */ - keys = (const s4*) switchData; - assert(((u4)keys & 0x3) == 0); - - /* The entries are guaranteed to be aligned on a 32-bit boundary; - * we can treat them as a native int array. - */ - entries = keys + size; - assert(((u4)entries & 0x3) == 0); - - /* - * Run through the list of keys, which are guaranteed to - * be sorted low-to-high. - * - * Most tables have 3-4 entries. Few have more than 10. A binary - * search here is probably not useful. - */ - for (i = 0; i < size; i++) { - s4 k = s4FromSwitchData(&keys[i]); - if (k == testVal) { - LOGVV("Value %d found in entry %d (goto 0x%02x)\n", - testVal, i, s4FromSwitchData(&entries[i])); - return s4FromSwitchData(&entries[i]); - } else if (k > testVal) { - break; - } - } - - LOGVV("Value %d not found in switch\n", testVal); - return kInstrLen; -} - -/* - * Fill the array with predefined constant values. - * - * Returns true if job is completed, otherwise false to indicate that - * an exception has been thrown. - */ -bool dvmInterpHandleFillArrayData(ArrayObject* arrayObj, const u2* arrayData) -{ - u2 width; - u4 size; - - if (arrayObj == NULL) { - dvmThrowException("Ljava/lang/NullPointerException;", NULL); - return false; - } - - /* - * Array data table format: - * ushort ident = 0x0300 magic value - * ushort width width of each element in the table - * uint size number of elements in the table - * ubyte data[size*width] table of data values (may contain a single-byte - * padding at the end) - * - * Total size is 4+(width * size + 1)/2 16-bit code units. - */ - if (arrayData[0] != kArrayDataSignature) { - dvmThrowException("Ljava/lang/InternalError;", "bad array data magic"); - return false; - } - - width = arrayData[1]; - size = arrayData[2] | (((u4)arrayData[3]) << 16); - - if (size > arrayObj->length) { - dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", NULL); - return false; - } - memcpy(arrayObj->contents, &arrayData[4], size*width); - return true; -} - -/* - * Find the concrete method that corresponds to "methodIdx". The code in - * "method" is executing invoke-method with "thisClass" as its first argument. - * - * Returns NULL with an exception raised on failure. - */ -Method* dvmInterpFindInterfaceMethod(ClassObject* thisClass, u4 methodIdx, - const Method* method, DvmDex* methodClassDex) -{ - Method* absMethod; - Method* methodToCall; - int i, vtableIndex; - - /* - * Resolve the method. This gives us the abstract method from the - * interface class declaration. - */ - absMethod = dvmDexGetResolvedMethod(methodClassDex, methodIdx); - if (absMethod == NULL) { - absMethod = dvmResolveInterfaceMethod(method->clazz, methodIdx); - if (absMethod == NULL) { - LOGV("+ unknown method\n"); - return NULL; - } - } - - /* make sure absMethod->methodIndex means what we think it means */ - assert(dvmIsAbstractMethod(absMethod)); - - /* - * Run through the "this" object's iftable. Find the entry for - * absMethod's class, then use absMethod->methodIndex to find - * the method's entry. The value there is the offset into our - * vtable of the actual method to execute. - * - * The verifier does not guarantee that objects stored into - * interface references actually implement the interface, so this - * check cannot be eliminated. - */ - for (i = 0; i < thisClass->iftableCount; i++) { - if (thisClass->iftable[i].clazz == absMethod->clazz) - break; - } - if (i == thisClass->iftableCount) { - /* impossible in verified DEX, need to check for it in unverified */ - dvmThrowException("Ljava/lang/IncompatibleClassChangeError;", - "interface not implemented"); - return NULL; - } - - assert(absMethod->methodIndex < - thisClass->iftable[i].clazz->virtualMethodCount); - - vtableIndex = - thisClass->iftable[i].methodIndexArray[absMethod->methodIndex]; - assert(vtableIndex >= 0 && vtableIndex < thisClass->vtableCount); - methodToCall = thisClass->vtable[vtableIndex]; - -#if 0 - /* this can happen when there's a stale class file */ - if (dvmIsAbstractMethod(methodToCall)) { - dvmThrowException("Ljava/lang/AbstractMethodError;", - "interface method not implemented"); - return NULL; - } -#else - assert(!dvmIsAbstractMethod(methodToCall) || - methodToCall->nativeFunc != NULL); -#endif - - LOGVV("+++ interface=%s.%s concrete=%s.%s\n", - absMethod->clazz->descriptor, absMethod->name, - methodToCall->clazz->descriptor, methodToCall->name); - assert(methodToCall != NULL); - - return methodToCall; -} - - -/* - * Main interpreter loop entry point. Select "standard" or "debug" - * interpreter and switch between them as required. - * - * This begins executing code at the start of "method". On exit, "pResult" - * holds the return value of the method (or, if "method" returns NULL, it - * holds an undefined value). - * - * The interpreted stack frame, which holds the method arguments, has - * already been set up. - */ -void dvmInterpret(Thread* self, const Method* method, JValue* pResult) -{ - InterpState interpState; - bool change; - -#if defined(WITH_TRACKREF_CHECKS) - interpState.debugTrackedRefStart = - dvmReferenceTableEntries(&self->internalLocalRefTable); -#endif -#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER) - interpState.debugIsMethodEntry = true; -#endif - - /* - * Initialize working state. - * - * No need to initialize "retval". - */ - interpState.method = method; - interpState.fp = (u4*) self->curFrame; - interpState.pc = method->insns; - interpState.entryPoint = kInterpEntryInstr; - - if (dvmDebuggerOrProfilerActive()) - interpState.nextMode = INTERP_DBG; - else - interpState.nextMode = INTERP_STD; - - assert(!dvmIsNativeMethod(method)); - - /* - * Make sure the class is ready to go. Shouldn't be possible to get - * here otherwise. - */ - if (method->clazz->status < CLASS_INITIALIZING || - method->clazz->status == CLASS_ERROR) - { - LOGE("ERROR: tried to execute code in unprepared class '%s' (%d)\n", - method->clazz->descriptor, method->clazz->status); - dvmDumpThread(self, false); - dvmAbort(); - } - - typedef bool (*Interpreter)(Thread*, InterpState*); - Interpreter stdInterp; - if (gDvm.executionMode == kExecutionModeInterpFast) - stdInterp = dvmMterpStd; - else - stdInterp = dvmInterpretStd; - - change = true; - while (change) { - switch (interpState.nextMode) { - case INTERP_STD: - LOGVV("threadid=%d: interp STD\n", self->threadId); - change = (*stdInterp)(self, &interpState); - break; -#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER) - case INTERP_DBG: - LOGVV("threadid=%d: interp DBG\n", self->threadId); - change = dvmInterpretDbg(self, &interpState); - break; -#endif - default: - dvmAbort(); - } - } - - *pResult = interpState.retval; -} - diff --git a/vm/interp/Interp.h b/vm/interp/Interp.h deleted file mode 100644 index eb36b9f50..000000000 --- a/vm/interp/Interp.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * Dalvik interpreter public definitions. - */ -#ifndef _DALVIK_INTERP_INTERP -#define _DALVIK_INTERP_INTERP - -/* - * Interpreter entry point. Call here after setting up the interpreted - * stack (most code will want to get here via dvmCallMethod().) - */ -void dvmInterpret(Thread* thread, const Method* method, JValue* pResult); - -/* - * Breakpoint optimization table. - */ -void dvmInitBreakpoints(); -void dvmAddBreakAddr(Method* method, int instrOffset); -void dvmClearBreakAddr(Method* method, int instrOffset); -bool dvmAddSingleStep(Thread* thread, int size, int depth); -void dvmClearSingleStep(Thread* thread); - -#endif /*_DALVIK_INTERP_INTERP*/ diff --git a/vm/interp/InterpDefs.h b/vm/interp/InterpDefs.h deleted file mode 100644 index 856c2f586..000000000 --- a/vm/interp/InterpDefs.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * Dalvik interpreter definitions. These are internal to the interpreter. - * - * This includes defines, types, function declarations, and inline functions - * that are common to all interpreter implementations. - * - * Functions and globals declared here are defined in Interp.c. - */ -#ifndef _DALVIK_INTERP_DEFS -#define _DALVIK_INTERP_DEFS - - -/* - * Specify the starting point when switching between interpreters. - */ -typedef enum InterpEntry { - kInterpEntryInstr = 0, // continue to next instruction - kInterpEntryReturn = 1, // jump to method return - kInterpEntryThrow = 2, // jump to exception throw -} InterpEntry; - -/* - * Interpreter context, used when switching from one interpreter to - * another. We also tuck "mterp" state in here. - */ -typedef struct InterpState { - /* - * To make some mterp state updates easier, "pc" and "fp" MUST come - * first and MUST appear in this order. - */ - const u2* pc; // program counter - u4* fp; // frame pointer - - JValue retval; // return value -- "out" only - const Method* method; // method being executed - - - /* ---------------------------------------------------------------------- - * Mterp-only state - */ - DvmDex* methodClassDex; - Thread* self; - - /* housekeeping */ - void* bailPtr; - - /* - * These are available globally, from gDvm, or from another glue field - * (self/method). They're copied in here for speed. - */ - const u1* interpStackEnd; - volatile int* pSelfSuspendCount; -#if defined(WITH_DEBUGGER) - volatile bool* pDebuggerActive; -#endif -#if defined(WITH_PROFILER) - volatile int* pActiveProfilers; -#endif - /* ---------------------------------------------------------------------- - */ - - /* - * Interpreter switching. - */ - InterpEntry entryPoint; // what to do when we start - int nextMode; // INTERP_STD or INTERP_DBG - - -#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER) - bool debugIsMethodEntry; // used for method entry event triggers -#endif -#if defined(WITH_TRACKREF_CHECKS) - int debugTrackedRefStart; // tracked refs from prior invocations -#endif - -} InterpState; - -/* - * These are generated from InterpCore.h. - */ -extern bool dvmInterpretDbg(Thread* self, InterpState* interpState); -extern bool dvmInterpretStd(Thread* self, InterpState* interpState); -#define INTERP_STD 0 -#define INTERP_DBG 1 - -/* - * "mterp" interpreter. - */ -extern bool dvmMterpStd(Thread* self, InterpState* interpState); - -/* - * Get the "this" pointer from the current frame. - */ -Object* dvmGetThisPtr(const Method* method, const u4* fp); - -/* - * Verify that our tracked local references are valid. - */ -void dvmInterpCheckTrackedRefs(Thread* self, const Method* method, - int debugTrackedRefStart); - -/* - * Process switch statement. - */ -s4 dvmInterpHandlePackedSwitch(const u2* switchData, s4 testVal); -s4 dvmInterpHandleSparseSwitch(const u2* switchData, s4 testVal); - -/* - * Process fill-array-data. - */ -bool dvmInterpHandleFillArrayData(ArrayObject* arrayObject, - const u2* arrayData); - -/* - * Find an interface method. - */ -Method* dvmInterpFindInterfaceMethod(ClassObject* thisClass, u4 methodIdx, - const Method* method, DvmDex* methodClassDex); - -/* - * Determine if the debugger or profiler is currently active. Used when - * selecting which interpreter to start or switch to. - */ -static inline bool dvmDebuggerOrProfilerActive(void) -{ - return gDvm.debuggerActive -#if defined(WITH_PROFILER) - || gDvm.activeProfilers != 0 -#endif - ; -} - -#endif /*_DALVIK_INTERP_DEFS*/ diff --git a/vm/interp/README.txt b/vm/interp/README.txt deleted file mode 100644 index 76d47a787..000000000 --- a/vm/interp/README.txt +++ /dev/null @@ -1,4 +0,0 @@ -Dalvik interpreter entry point. - -The "mterp" directory now holds the interpreter implementation. - diff --git a/vm/interp/Stack.c b/vm/interp/Stack.c deleted file mode 100644 index 103d2b4d9..000000000 --- a/vm/interp/Stack.c +++ /dev/null @@ -1,1233 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * Stacks and their uses (e.g. native --> interpreted method calls). - * - * See the majestic ASCII art in Stack.h. - */ -#include "Dalvik.h" -#include "jni.h" - -#include <stdlib.h> -#include <stdarg.h> - -/* - * Initialize the interpreter stack in a new thread. - * - * Currently this doesn't do much, since we don't need to zero out the - * stack (and we really don't want to if it was created with mmap). - */ -bool dvmInitInterpStack(Thread* thread, int stackSize) -{ - assert(thread->interpStackStart != NULL); - - assert(thread->curFrame == NULL); - - return true; -} - -/* - * We're calling an interpreted method from an internal VM function or - * via reflection. - * - * Push a frame for an interpreted method onto the stack. This is only - * used when calling into interpreted code from native code. (The - * interpreter does its own stack frame manipulation for interp-->interp - * calls.) - * - * The size we need to reserve is the sum of parameters, local variables, - * saved goodies, and outbound parameters. - * - * We start by inserting a "break" frame, which ensures that the interpreter - * hands control back to us after the function we call returns or an - * uncaught exception is thrown. - */ -static bool dvmPushInterpFrame(Thread* self, const Method* method) -{ - StackSaveArea* saveBlock; - StackSaveArea* breakSaveBlock; - int stackReq; - u1* stackPtr; - - assert(!dvmIsNativeMethod(method)); - assert(!dvmIsAbstractMethod(method)); - - stackReq = method->registersSize * 4 // params + locals - + sizeof(StackSaveArea) * 2 // break frame + regular frame - + method->outsSize * 4; // args to other methods - - if (self->curFrame != NULL) - stackPtr = (u1*) SAVEAREA_FROM_FP(self->curFrame); - else - stackPtr = self->interpStackStart; - - if (stackPtr - stackReq < self->interpStackEnd) { - /* not enough space */ - LOGW("Stack overflow on call to interp (top=%p cur=%p size=%d %s.%s)\n", - self->interpStackStart, self->curFrame, self->interpStackSize, - method->clazz->descriptor, method->name); - dvmHandleStackOverflow(self); - assert(dvmCheckException(self)); - return false; - } - - /* - * Shift the stack pointer down, leaving space for the function's - * args/registers and save area. - */ - stackPtr -= sizeof(StackSaveArea); - breakSaveBlock = (StackSaveArea*)stackPtr; - stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea); - saveBlock = (StackSaveArea*) stackPtr; - -#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA) - /* debug -- memset the new stack, unless we want valgrind's help */ - memset(stackPtr - (method->outsSize*4), 0xaf, stackReq); -#endif -#ifdef EASY_GDB - breakSaveBlock->prevSave = FP_FROM_SAVEAREA(self->curFrame); - saveBlock->prevSave = breakSaveBlock; -#endif - - breakSaveBlock->prevFrame = self->curFrame; - breakSaveBlock->savedPc = NULL; // not required - breakSaveBlock->xtra.localRefTop = NULL; // not required - breakSaveBlock->method = NULL; - saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock); - saveBlock->savedPc = NULL; // not required - saveBlock->xtra.currentPc = NULL; // not required? - saveBlock->method = method; - - LOGVV("PUSH frame: old=%p new=%p (size=%d)\n", - self->curFrame, FP_FROM_SAVEAREA(saveBlock), - (u1*)self->curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock)); - - self->curFrame = FP_FROM_SAVEAREA(saveBlock); - - return true; -} - -/* - * We're calling a JNI native method from an internal VM fuction or - * via reflection. This is also used to create the "fake" native-method - * frames at the top of the interpreted stack. - * - * This actually pushes two frames; the first is a "break" frame. - * - * The top frame has additional space for JNI local reference tracking. - */ -bool dvmPushJNIFrame(Thread* self, const Method* method) -{ - StackSaveArea* saveBlock; - StackSaveArea* breakSaveBlock; - int stackReq; - u1* stackPtr; - - assert(dvmIsNativeMethod(method)); - - stackReq = method->registersSize * 4 // params only - + sizeof(StackSaveArea) * 2; // break frame + regular frame - - if (self->curFrame != NULL) - stackPtr = (u1*) SAVEAREA_FROM_FP(self->curFrame); - else - stackPtr = self->interpStackStart; - - if (stackPtr - stackReq < self->interpStackEnd) { - /* not enough space */ - LOGW("Stack overflow on call to native (top=%p cur=%p size=%d '%s')\n", - self->interpStackStart, self->curFrame, self->interpStackSize, - method->name); - dvmHandleStackOverflow(self); - assert(dvmCheckException(self)); - return false; - } - - /* - * Shift the stack pointer down, leaving space for just the stack save - * area for the break frame, then shift down farther for the full frame. - * We leave space for the method args, which are copied in later. - */ - stackPtr -= sizeof(StackSaveArea); - breakSaveBlock = (StackSaveArea*)stackPtr; - stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea); - saveBlock = (StackSaveArea*) stackPtr; - -#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA) - /* debug -- memset the new stack */ - memset(stackPtr, 0xaf, stackReq); -#endif -#ifdef EASY_GDB - if (self->curFrame == NULL) - breakSaveBlock->prevSave = NULL; - else - breakSaveBlock->prevSave = FP_FROM_SAVEAREA(self->curFrame); - saveBlock->prevSave = breakSaveBlock; -#endif - - breakSaveBlock->prevFrame = self->curFrame; - breakSaveBlock->savedPc = NULL; // not required - breakSaveBlock->xtra.localRefTop = NULL; // not required - breakSaveBlock->method = NULL; - saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock); - saveBlock->savedPc = NULL; // not required - saveBlock->xtra.localRefTop = self->jniLocalRefTable.nextEntry; - saveBlock->method = method; - - LOGVV("PUSH JNI frame: old=%p new=%p (size=%d)\n", - self->curFrame, FP_FROM_SAVEAREA(saveBlock), - (u1*)self->curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock)); - - self->curFrame = FP_FROM_SAVEAREA(saveBlock); - - return true; -} - -/* - * This is used by the JNI PushLocalFrame call. We push a new frame onto - * the stack that has no ins, outs, or locals, and no break frame above it. - * It's strictly used for tracking JNI local refs, and will be popped off - * by dvmPopFrame if it's not removed explicitly. - */ -bool dvmPushLocalFrame(Thread* self, const Method* method) -{ - StackSaveArea* saveBlock; - int stackReq; - u1* stackPtr; - - assert(dvmIsNativeMethod(method)); - - stackReq = sizeof(StackSaveArea); // regular frame - - assert(self->curFrame != NULL); - stackPtr = (u1*) SAVEAREA_FROM_FP(self->curFrame); - - if (stackPtr - stackReq < self->interpStackEnd) { - /* not enough space; let JNI throw the exception */ - LOGW("Stack overflow on PushLocal (top=%p cur=%p size=%d '%s')\n", - self->interpStackStart, self->curFrame, self->interpStackSize, - method->name); - dvmHandleStackOverflow(self); - assert(dvmCheckException(self)); - return false; - } - - /* - * Shift the stack pointer down, leaving space for just the stack save - * area for the break frame, then shift down farther for the full frame. - */ - stackPtr -= sizeof(StackSaveArea); - saveBlock = (StackSaveArea*) stackPtr; - -#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA) - /* debug -- memset the new stack */ - memset(stackPtr, 0xaf, stackReq); -#endif -#ifdef EASY_GDB - saveBlock->prevSave = FP_FROM_SAVEAREA(self->curFrame); -#endif - - saveBlock->prevFrame = self->curFrame; - saveBlock->savedPc = NULL; // not required - saveBlock->xtra.localRefTop = self->jniLocalRefTable.nextEntry; - saveBlock->method = method; - - LOGVV("PUSH JNI local frame: old=%p new=%p (size=%d)\n", - self->curFrame, FP_FROM_SAVEAREA(saveBlock), - (u1*)self->curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock)); - - self->curFrame = FP_FROM_SAVEAREA(saveBlock); - - return true; -} - -/* - * Pop one frame pushed on by JNI PushLocalFrame. - * - * If we've gone too far, the previous frame is either a break frame or - * an interpreted frame. Either way, the method pointer won't match. - */ -bool dvmPopLocalFrame(Thread* self) -{ - StackSaveArea* saveBlock = SAVEAREA_FROM_FP(self->curFrame); - - assert(!dvmIsBreakFrame(self->curFrame)); - if (saveBlock->method != SAVEAREA_FROM_FP(saveBlock->prevFrame)->method) { - /* - * The previous frame doesn't have the same method pointer -- we've - * been asked to pop too much. - */ - assert(dvmIsBreakFrame(saveBlock->prevFrame) || - !dvmIsNativeMethod( - SAVEAREA_FROM_FP(saveBlock->prevFrame)->method)); - return false; - } - - LOGVV("POP JNI local frame: removing %s, now %s\n", - saveBlock->method->name, - SAVEAREA_FROM_FP(saveBlock->prevFrame)->method->name); - dvmPopJniLocals(self, saveBlock); - self->curFrame = saveBlock->prevFrame; - - return true; -} - -/* - * Pop a frame we added. There should be one method frame and one break - * frame. - * - * If JNI Push/PopLocalFrame calls were mismatched, we might end up - * popping multiple method frames before we find the break. - * - * Returns "false" if there was no frame to pop. - */ -static bool dvmPopFrame(Thread* self) -{ - StackSaveArea* saveBlock; - - if (self->curFrame == NULL) - return false; - - saveBlock = SAVEAREA_FROM_FP(self->curFrame); - assert(!dvmIsBreakFrame(self->curFrame)); - - /* - * Remove everything up to the break frame. If this was a call into - * native code, pop the JNI local references table. - */ - while (saveBlock->prevFrame != NULL && saveBlock->method != NULL) { - /* probably a native->native JNI call */ - - if (dvmIsNativeMethod(saveBlock->method)) { - LOGVV("Popping JNI stack frame for %s.%s%s\n", - saveBlock->method->clazz->descriptor, - saveBlock->method->name, - (SAVEAREA_FROM_FP(saveBlock->prevFrame)->method == NULL) ? - "" : " (JNI local)"); - assert(saveBlock->xtra.localRefTop != NULL); - assert(saveBlock->xtra.localRefTop >=self->jniLocalRefTable.table && - saveBlock->xtra.localRefTop <=self->jniLocalRefTable.nextEntry); - - dvmPopJniLocals(self, saveBlock); - } - - saveBlock = SAVEAREA_FROM_FP(saveBlock->prevFrame); - } - if (saveBlock->method != NULL) { - LOGE("PopFrame missed the break\n"); - assert(false); - dvmAbort(); // stack trashed -- nowhere to go in this thread - } - - LOGVV("POP frame: cur=%p new=%p\n", - self->curFrame, saveBlock->prevFrame); - - self->curFrame = saveBlock->prevFrame; - return true; -} - -/* - * Common code for dvmCallMethodV/A and dvmInvokeMethod. - * - * Pushes a call frame on, advancing self->curFrame. - */ -static ClassObject* callPrep(Thread* self, const Method* method, Object* obj, - bool checkAccess) -{ - ClassObject* clazz; - -#ifndef NDEBUG - if (self->status != THREAD_RUNNING) { - LOGW("Status=%d on call to %s.%s -\n", self->status, - method->clazz->descriptor, method->name); - } -#endif - - assert(self != NULL); - assert(method != NULL); - - if (obj != NULL) - clazz = obj->clazz; - else - clazz = method->clazz; - - IF_LOGVV() { - char* desc = dexProtoCopyMethodDescriptor(&method->prototype); - LOGVV("thread=%d native code calling %s.%s %s\n", self->threadId, - clazz->descriptor, method->name, desc); - free(desc); - } - - if (checkAccess) { - /* needed for java.lang.reflect.Method.invoke */ - if (!dvmCheckMethodAccess(dvmGetCaller2Class(self->curFrame), - method)) - { - /* note this throws IAException, not IAError */ - dvmThrowException("Ljava/lang/IllegalAccessException;", - "access to method denied"); - return NULL; - } - } - - /* - * Push a call frame on. If there isn't enough room for ins, locals, - * outs, and the saved state, it will throw an exception. - * - * This updates self->curFrame. - */ - if (dvmIsNativeMethod(method)) { - /* native code calling native code the hard way */ - if (!dvmPushJNIFrame(self, method)) { - assert(dvmCheckException(self)); - return NULL; - } - } else { - /* native code calling interpreted code */ - if (!dvmPushInterpFrame(self, method)) { - assert(dvmCheckException(self)); - return NULL; - } - } - - return clazz; -} - -/* - * Issue a method call. - * - * Pass in NULL for "obj" on calls to static methods. - * - * (Note this can't be inlined because it takes a variable number of args.) - */ -void dvmCallMethod(Thread* self, const Method* method, Object* obj, - JValue* pResult, ...) -{ - JValue result; - - va_list args; - va_start(args, pResult); - dvmCallMethodV(self, method, obj, pResult, args); - va_end(args); -} - -/* - * Issue a method call with a variable number of arguments. We process - * the contents of "args" by scanning the method signature. - * - * Pass in NULL for "obj" on calls to static methods. - * - * We don't need to take the class as an argument because, in Dalvik, - * we don't need to worry about static synchronized methods. - */ -void dvmCallMethodV(Thread* self, const Method* method, Object* obj, - JValue* pResult, va_list args) -{ - const char* desc = &(method->shorty[1]); // [0] is the return type. - int verifyCount = 0; - ClassObject* clazz; - u4* ins; - - clazz = callPrep(self, method, obj, false); - if (clazz == NULL) - return; - - /* "ins" for new frame start at frame pointer plus locals */ - ins = ((u4*)self->curFrame) + (method->registersSize - method->insSize); - - //LOGD(" FP is %p, INs live at >= %p\n", self->curFrame, ins); - - /* put "this" pointer into in0 if appropriate */ - if (!dvmIsStaticMethod(method)) { -#ifdef WITH_EXTRA_OBJECT_VALIDATION - assert(obj != NULL && dvmIsValidObject(obj)); -#endif - *ins++ = (u4) obj; - verifyCount++; - } - - while (*desc != '\0') { - switch (*(desc++)) { - case 'D': case 'J': { - u8 val = va_arg(args, u8); - memcpy(ins, &val, 8); // EABI prevents direct store - ins += 2; - verifyCount += 2; - break; - } - case 'F': { - /* floats were normalized to doubles; convert back */ - float f = (float) va_arg(args, double); - *ins++ = dvmFloatToU4(f); - verifyCount++; - break; - } -#ifdef WITH_EXTRA_OBJECT_VALIDATION - case 'L': { /* 'shorty' descr uses L for all refs, incl array */ - Object* argObj = (Object*) va_arg(args, u4); - assert(obj == NULL || dvmIsValidObject(obj)); - *ins++ = (u4) argObj; - verifyCount++; - break; - } -#endif - default: { - *ins++ = va_arg(args, u4); - verifyCount++; - break; - } - } - } - -#ifndef NDEBUG - if (verifyCount != method->insSize) { - LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount, - method->insSize, clazz->descriptor, method->name); - assert(false); - goto bail; - } -#endif - - //dvmDumpThreadStack(dvmThreadSelf()); - - if (dvmIsNativeMethod(method)) { - /* - * Because we leave no space for local variables, "curFrame" points - * directly at the method arguments. - */ - (*method->nativeFunc)(self->curFrame, pResult, method, self); - } else { - dvmInterpret(self, method, pResult); - } - -bail: - dvmPopFrame(self); -} - -/* - * Issue a method call with arguments provided in an array. We process - * the contents of "args" by scanning the method signature. - * - * The values were likely placed into an uninitialized jvalue array using - * the field specifiers, which means that sub-32-bit fields (e.g. short, - * boolean) may not have 32 or 64 bits of valid data. This is different - * from the varargs invocation where the C compiler does a widening - * conversion when calling a function. As a result, we have to be a - * little more precise when pulling stuff out. - */ -void dvmCallMethodA(Thread* self, const Method* method, Object* obj, - JValue* pResult, const jvalue* args) -{ - const char* desc = &(method->shorty[1]); // [0] is the return type. - int verifyCount = 0; - ClassObject* clazz; - u4* ins; - - clazz = callPrep(self, method, obj, false); - if (clazz == NULL) - return; - - /* "ins" for new frame start at frame pointer plus locals */ - ins = ((u4*)self->curFrame) + (method->registersSize - method->insSize); - - /* put "this" pointer into in0 if appropriate */ - if (!dvmIsStaticMethod(method)) { - assert(obj != NULL); - *ins++ = (u4) obj; - verifyCount++; - } - - while (*desc != '\0') { - switch (*(desc++)) { - case 'D': case 'J': { - memcpy(ins, &args->j, 8); /* EABI prevents direct store */ - ins += 2; - verifyCount += 2; - args++; - break; - } - case 'F': case 'I': case 'L': { /* (no '[' in short signatures) */ - *ins++ = args->i; /* get all 32 bits */ - verifyCount++; - args++; - break; - } - case 'S': { - *ins++ = args->s; /* 16 bits, sign-extended */ - verifyCount++; - args++; - break; - } - case 'C': { - *ins++ = args->c; /* 16 bits, unsigned */ - verifyCount++; - args++; - break; - } - case 'B': { - *ins++ = args->b; /* 8 bits, sign-extended */ - verifyCount++; - args++; - break; - } - case 'Z': { - *ins++ = args->z; /* 8 bits, zero or non-zero */ - verifyCount++; - args++; - break; - } - default: { - LOGE("Invalid char %c in short signature of %s.%s\n", - *(desc-1), clazz->descriptor, method->name); - assert(false); - goto bail; - } - } - } - -#ifndef NDEBUG - if (verifyCount != method->insSize) { - LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount, - method->insSize, clazz->descriptor, method->name); - assert(false); - goto bail; - } -#endif - - if (dvmIsNativeMethod(method)) { - /* - * Because we leave no space for local variables, "curFrame" points - * directly at the method arguments. - */ - (*method->nativeFunc)(self->curFrame, pResult, method, self); - } else { - dvmInterpret(self, method, pResult); - } - -bail: - dvmPopFrame(self); -} - -/* - * Invoke a method, using the specified arguments and return type, through - * one of the reflection interfaces. Could be a virtual or direct method - * (including constructors). Used for reflection. - * - * Deals with boxing/unboxing primitives and performs widening conversions. - * - * "invokeObj" will be null for a static method. - * - * If the invocation returns with an exception raised, we have to wrap it. - */ -Object* dvmInvokeMethod(Object* obj, const Method* method, - ArrayObject* argList, ArrayObject* params, ClassObject* returnType, - bool noAccessCheck) -{ - ClassObject* clazz; - Object* retObj = NULL; - Thread* self = dvmThreadSelf(); - s4* ins; - int verifyCount, argListLength; - JValue retval; - - /* verify arg count */ - if (argList != NULL) - argListLength = argList->length; - else - argListLength = 0; - if (argListLength != (int) params->length) { - LOGI("invoke: expected %d args, received %d args\n", - params->length, argListLength); - dvmThrowException("Ljava/lang/IllegalArgumentException;", - "wrong number of arguments"); - return NULL; - } - - clazz = callPrep(self, method, obj, !noAccessCheck); - if (clazz == NULL) - return NULL; - - /* "ins" for new frame start at frame pointer plus locals */ - ins = ((s4*)self->curFrame) + (method->registersSize - method->insSize); - verifyCount = 0; - - //LOGD(" FP is %p, INs live at >= %p\n", self->curFrame, ins); - - /* put "this" pointer into in0 if appropriate */ - if (!dvmIsStaticMethod(method)) { - assert(obj != NULL); - *ins++ = (s4) obj; - verifyCount++; - } - - /* - * Copy the args onto the stack. Primitive types are converted when - * necessary, and object types are verified. - */ - DataObject** args; - ClassObject** types; - int i; - - args = (DataObject**) argList->contents; - types = (ClassObject**) params->contents; - for (i = 0; i < argListLength; i++) { - int width; - - width = dvmConvertArgument(*args++, *types++, ins); - if (width < 0) { - if (*(args-1) != NULL) { - LOGV("invoke: type mismatch on arg %d ('%s' '%s')\n", - i, (*(args-1))->obj.clazz->descriptor, - (*(types-1))->descriptor); - } - dvmPopFrame(self); // throw wants to pull PC out of stack - dvmThrowException("Ljava/lang/IllegalArgumentException;", - "argument type mismatch"); - goto bail_popped; - } - - ins += width; - verifyCount += width; - } - - if (verifyCount != method->insSize) { - LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount, - method->insSize, clazz->descriptor, method->name); - assert(false); - goto bail; - } - //dvmDumpThreadStack(dvmThreadSelf()); - - if (dvmIsNativeMethod(method)) { - /* - * Because we leave no space for local variables, "curFrame" points - * directly at the method arguments. - */ - (*method->nativeFunc)(self->curFrame, &retval, method, self); - } else { - dvmInterpret(self, method, &retval); - } - - /* - * If an exception is raised, wrap and replace. This is necessary - * because the invoked method could have thrown a checked exception - * that the caller wasn't prepared for. - * - * We might be able to do this up in the interpreted code, but that will - * leave us with a shortened stack trace in the top-level exception. - */ - if (dvmCheckException(self)) { - dvmWrapException("Ljava/lang/reflect/InvocationTargetException;"); - } else { - /* - * If this isn't a void method or constructor, convert the return type - * to an appropriate object. - * - * We don't do this when an exception is raised because the value - * in "retval" is undefined. - */ - if (returnType != NULL) { - retObj = (Object*)dvmWrapPrimitive(retval, returnType); - dvmReleaseTrackedAlloc(retObj, NULL); - } - } - -bail: - dvmPopFrame(self); -bail_popped: - return retObj; -} - -typedef struct LineNumFromPcContext { - u4 address; - u4 lineNum; -} LineNumFromPcContext; - -static int lineNumForPcCb(void *cnxt, u4 address, u4 lineNum) -{ - LineNumFromPcContext *pContext = (LineNumFromPcContext *)cnxt; - - // We know that this callback will be called in - // ascending address order, so keep going until we find - // a match or we've just gone past it. - - if (address > pContext->address) { - // The line number from the previous positions callback - // wil be the final result. - return 1; - } - - pContext->lineNum = lineNum; - - return (address == pContext->address) ? 1 : 0; -} - -/* - * Determine the source file line number based on the program counter. - * "pc" is an offset, in 16-bit units, from the start of the method's code. - * - * Returns -1 if no match was found (possibly because the source files were - * compiled without "-g", so no line number information is present). - * Returns -2 for native methods (as expected in exception traces). - */ -int dvmLineNumFromPC(const Method* method, u4 relPc) -{ - const DexCode* pDexCode = dvmGetMethodCode(method); - - if (pDexCode == NULL) { - if (dvmIsNativeMethod(method) && !dvmIsAbstractMethod(method)) - return -2; - return -1; /* can happen for abstract method stub */ - } - - LineNumFromPcContext context; - memset(&context, 0, sizeof(context)); - context.address = relPc; - // A method with no line number info should return -1 - context.lineNum = -1; - - dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile, pDexCode, - method->clazz->descriptor, - method->prototype.protoIdx, - method->accessFlags, - lineNumForPcCb, NULL, &context); - - return context.lineNum; -} - -/* - * Compute the frame depth. - * - * Excludes "break" frames. - */ -int dvmComputeExactFrameDepth(const void* fp) -{ - int count = 0; - - for ( ; fp != NULL; fp = SAVEAREA_FROM_FP(fp)->prevFrame) { - if (!dvmIsBreakFrame(fp)) - count++; - } - - return count; -} - -/* - * Compute the "vague" frame depth, which is just a pointer subtraction. - * The result is NOT an overly generous assessment of the number of - * frames; the only meaningful use is to compare against the result of - * an earlier invocation. - * - * Useful for implementing single-step debugger modes, which may need to - * call this for every instruction. - */ -int dvmComputeVagueFrameDepth(Thread* thread, const void* fp) -{ - const u1* interpStackStart = thread->interpStackStart; - const u1* interpStackBottom = interpStackStart - thread->interpStackSize; - - assert((u1*) fp >= interpStackBottom && (u1*) fp < interpStackStart); - return interpStackStart - (u1*) fp; -} - -/* - * Get the calling frame. Pass in the current fp. - * - * Skip "break" frames and reflection invoke frames. - */ -void* dvmGetCallerFP(const void* curFrame) -{ - void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame; - StackSaveArea* saveArea; - -retry: - if (dvmIsBreakFrame(caller)) { - /* pop up one more */ - caller = SAVEAREA_FROM_FP(caller)->prevFrame; - if (caller == NULL) - return NULL; /* hit the top */ - - /* - * If we got here by java.lang.reflect.Method.invoke(), we don't - * want to return Method's class loader. Shift up one and try - * again. - */ - saveArea = SAVEAREA_FROM_FP(caller); - if (dvmIsReflectionMethod(saveArea->method)) { - caller = saveArea->prevFrame; - assert(caller != NULL); - goto retry; - } - } - - return caller; -} - -/* - * Get the caller's class. Pass in the current fp. - * - * This is used by e.g. java.lang.Class. - */ -ClassObject* dvmGetCallerClass(const void* curFrame) -{ - void* caller; - - caller = dvmGetCallerFP(curFrame); - if (caller == NULL) - return NULL; - - return SAVEAREA_FROM_FP(caller)->method->clazz; -} - -/* - * Get the caller's caller's class. Pass in the current fp. - * - * This is used by e.g. java.lang.Class, which wants to know about the - * class loader of the method that called it. - */ -ClassObject* dvmGetCaller2Class(const void* curFrame) -{ - void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame; - void* callerCaller; - - /* at the top? */ - if (dvmIsBreakFrame(caller) && SAVEAREA_FROM_FP(caller)->prevFrame == NULL) - return NULL; - - /* go one more */ - callerCaller = dvmGetCallerFP(caller); - if (callerCaller == NULL) - return NULL; - - return SAVEAREA_FROM_FP(callerCaller)->method->clazz; -} - -/* - * Get the caller's caller's caller's class. Pass in the current fp. - * - * This is used by e.g. java.lang.Class, which wants to know about the - * class loader of the method that called it. - */ -ClassObject* dvmGetCaller3Class(const void* curFrame) -{ - void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame; - int i; - - /* at the top? */ - if (dvmIsBreakFrame(caller) && SAVEAREA_FROM_FP(caller)->prevFrame == NULL) - return NULL; - - /* Walk up two frames if possible. */ - for (i = 0; i < 2; i++) { - caller = dvmGetCallerFP(caller); - if (caller == NULL) - return NULL; - } - - return SAVEAREA_FROM_FP(caller)->method->clazz; -} - -/* - * Create a flat array of methods that comprise the current interpreter - * stack trace. Pass in the current frame ptr. - * - * Allocates a new array and fills it with method pointers. Break frames - * are skipped, but reflection invocations are not. The caller must free - * "*pArray". - * - * The current frame will be in element 0. - * - * Returns "true" on success, "false" on failure (e.g. malloc failed). - */ -bool dvmCreateStackTraceArray(const void* fp, const Method*** pArray, - int* pLength) -{ - const Method** array; - int idx, depth; - - depth = dvmComputeExactFrameDepth(fp); - array = (const Method**) malloc(depth * sizeof(Method*)); - if (array == NULL) - return false; - - for (idx = 0; fp != NULL; fp = SAVEAREA_FROM_FP(fp)->prevFrame) { - if (!dvmIsBreakFrame(fp)) - array[idx++] = SAVEAREA_FROM_FP(fp)->method; - } - assert(idx == depth); - - *pArray = array; - *pLength = depth; - return true; -} - -/* - * Open up the reserved area and throw an exception. The reserved area - * should only be needed to create and initialize the exception itself. - * - * If we already opened it and we're continuing to overflow, abort the VM. - * - * We have to leave the "reserved" area open until the "catch" handler has - * finished doing its processing. This is because the catch handler may - * need to resolve classes, which requires calling into the class loader if - * the classes aren't already in the "initiating loader" list. - */ -void dvmHandleStackOverflow(Thread* self) -{ - /* - * Can we make the reserved area available? - */ - if (self->stackOverflowed) { - /* - * Already did, nothing to do but bail. - */ - LOGE("DalvikVM: double-overflow of stack in threadid=%d; aborting\n", - self->threadId); - dvmDumpThread(self, false); - dvmAbort(); - } - - /* open it up to the full range */ - LOGI("Stack overflow, expanding (%p to %p)\n", self->interpStackEnd, - self->interpStackStart - self->interpStackSize); - //dvmDumpThread(self, false); - self->interpStackEnd = self->interpStackStart - self->interpStackSize; - self->stackOverflowed = true; - - /* - * If we were trying to throw an exception when the stack overflowed, - * we will blow up when doing the class lookup on StackOverflowError - * because of the pending exception. So, we clear it and make it - * the cause of the SOE. - */ - Object* excep = dvmGetException(self); - if (excep != NULL) { - LOGW("Stack overflow while throwing exception\n"); - dvmClearException(self); - } - dvmThrowChainedException("Ljava/lang/StackOverflowError;", NULL, excep); -} - -/* - * Reduce the available stack size. By this point we should have finished - * our overflow processing. - */ -void dvmCleanupStackOverflow(Thread* self) -{ - const u1* newStackEnd; - - assert(self->stackOverflowed); - - newStackEnd = (self->interpStackStart - self->interpStackSize) - + STACK_OVERFLOW_RESERVE; - if ((u1*)self->curFrame <= newStackEnd) { - LOGE("Can't shrink stack: curFrame is in reserved area (%p %p)\n", - self->interpStackEnd, self->curFrame); - dvmDumpThread(self, false); - dvmAbort(); - } - - self->interpStackEnd = newStackEnd; - self->stackOverflowed = false; - - LOGI("Shrank stack (to %p, curFrame is %p)\n", self->interpStackEnd, - self->curFrame); -} - - -/* - * Dump stack frames, starting from the specified frame and moving down. - * - * Each frame holds a pointer to the currently executing method, and the - * saved program counter from the caller ("previous" frame). This means - * we don't have the PC for the current method on the stack, which is - * pretty reasonable since it's in the "PC register" for the VM. Because - * exceptions need to show the correct line number we actually *do* have - * an updated version in the fame's "xtra.currentPc", but it's unreliable. - * - * Note "framePtr" could be NULL in rare circumstances. - */ -static void dumpFrames(const DebugOutputTarget* target, void* framePtr, - Thread* thread) -{ - const StackSaveArea* saveArea; - const Method* method; - int checkCount = 0; - const u2* currentPc = NULL; - bool first = true; - - /* - * The "currentPc" is updated whenever we execute an instruction that - * might throw an exception. Show it here. - */ - if (framePtr != NULL && !dvmIsBreakFrame(framePtr)) { - saveArea = SAVEAREA_FROM_FP(framePtr); - - if (saveArea->xtra.currentPc != NULL) - currentPc = saveArea->xtra.currentPc; - } - - while (framePtr != NULL) { - saveArea = SAVEAREA_FROM_FP(framePtr); - method = saveArea->method; - - if (dvmIsBreakFrame(framePtr)) { - //dvmPrintDebugMessage(target, " (break frame)\n"); - } else { - int relPc; - - if (currentPc != NULL) - relPc = currentPc - saveArea->method->insns; - else - relPc = -1; - - char* className = dvmDescriptorToDot(method->clazz->descriptor); - if (dvmIsNativeMethod(method)) - dvmPrintDebugMessage(target, - " at %s.%s(Native Method)\n", className, method->name); - else { - dvmPrintDebugMessage(target, - " at %s.%s(%s:%s%d)\n", - className, method->name, dvmGetMethodSourceFile(method), - (relPc >= 0 && first) ? "~" : "", - relPc < 0 ? -1 : dvmLineNumFromPC(method, relPc)); - } - free(className); - - if (first && - (thread->status == THREAD_WAIT || - thread->status == THREAD_TIMED_WAIT)) - { - /* warning: wait status not stable, even in suspend */ - Monitor* mon = thread->waitMonitor; - Object* obj = dvmGetMonitorObject(mon); - if (obj != NULL) { - className = dvmDescriptorToDot(obj->clazz->descriptor); - dvmPrintDebugMessage(target, - " - waiting on <%p> (a %s)\n", mon, className); - free(className); - } - } - - } - - /* - * Get saved PC for previous frame. There's no savedPc in a "break" - * frame, because that represents native or interpreted code - * invoked by the VM. The saved PC is sitting in the "PC register", - * a local variable on the native stack. - */ - currentPc = saveArea->savedPc; - - first = false; - - assert(framePtr != saveArea->prevFrame); - framePtr = saveArea->prevFrame; - - checkCount++; - if (checkCount > 200) { - dvmPrintDebugMessage(target, - " ***** printed %d frames, not showing any more\n", - checkCount); - break; - } - } - dvmPrintDebugMessage(target, "\n"); -} - - -/* - * Dump the stack for the specified thread. - */ -void dvmDumpThreadStack(const DebugOutputTarget* target, Thread* thread) -{ - dumpFrames(target, thread->curFrame, thread); -} - -/* - * Dump the stack for the specified thread, which is still running. - * - * This is very dangerous, because stack frames are being pushed on and - * popped off, and if the thread exits we'll be looking at freed memory. - * The plan here is to take a snapshot of the stack and then dump that - * to try to minimize the chances of catching it mid-update. This should - * work reasonably well on a single-CPU system. - * - * There is a small chance that calling here will crash the VM. - */ -void dvmDumpRunningThreadStack(const DebugOutputTarget* target, Thread* thread) -{ - StackSaveArea* saveArea; - const u1* origStack; - u1* stackCopy = NULL; - int origSize, fpOffset; - void* fp; - int depthLimit = 200; - - if (thread == NULL || thread->curFrame == NULL) { - dvmPrintDebugMessage(target, - "DumpRunning: Thread at %p has no curFrame (threadid=%d)\n", - thread, (thread != NULL) ? thread->threadId : 0); - return; - } - - /* wait for a full quantum */ - sched_yield(); - - /* copy the info we need, then the stack itself */ - origSize = thread->interpStackSize; - origStack = (const u1*) thread->interpStackStart - origSize; - stackCopy = (u1*) malloc(origSize); - fpOffset = (u1*) thread->curFrame - origStack; - memcpy(stackCopy, origStack, origSize); - - /* - * Run through the stack and rewrite the "prev" pointers. - */ - //LOGI("DR: fpOff=%d (from %p %p)\n",fpOffset, origStack, thread->curFrame); - fp = stackCopy + fpOffset; - while (true) { - int prevOffset; - - if (depthLimit-- < 0) { - /* we're probably screwed */ - dvmPrintDebugMessage(target, "DumpRunning: depth limit hit\n"); - dvmAbort(); - } - saveArea = SAVEAREA_FROM_FP(fp); - if (saveArea->prevFrame == NULL) - break; - - prevOffset = (u1*) saveArea->prevFrame - origStack; - if (prevOffset < 0 || prevOffset > origSize) { - dvmPrintDebugMessage(target, - "DumpRunning: bad offset found: %d (from %p %p)\n", - prevOffset, origStack, saveArea->prevFrame); - saveArea->prevFrame = NULL; - break; - } - - saveArea->prevFrame = stackCopy + prevOffset; - fp = saveArea->prevFrame; - } - - /* - * We still need to pass the Thread for some monitor wait stuff. - */ - dumpFrames(target, stackCopy + fpOffset, thread); - free(stackCopy); -} - diff --git a/vm/interp/Stack.h b/vm/interp/Stack.h deleted file mode 100644 index 1b28d49d2..000000000 --- a/vm/interp/Stack.h +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * Stack frames, and uses thereof. - */ -#ifndef _DALVIK_INTERP_STACK -#define _DALVIK_INTERP_STACK - -#include "jni.h" -#include <stdarg.h> - - -/* -Stack layout - -In what follows, the "top" of the stack is at a low position in memory, -and the "bottom" of the stack is in a high position (put more simply, -they grow downward). They may be merged with the native stack at a -later date. The interpreter assumes that they have a fixed size, -determined when the thread is created. - -Dalvik's registers (of which there can be up to 64K) map to the "ins" -(method arguments) and "locals" (local variables). The "outs" (arguments -to called methods) are specified by the "invoke" operand. The return -value, which is passed through the interpreter rather than on the stack, -is retrieved with a "move-result" instruction. - - Low addresses (0x00000000) - - +- - - - - - - - -+ - - out0 - - +-----------------+ <-- stack ptr (top of stack) - + VM-specific + - + internal goop + - +-----------------+ <-- curFrame: FP for cur function - + v0 == local0 + -+-----------------+ +-----------------+ -+ out0 + + v1 == in0 + -+-----------------+ +-----------------+ -+ out1 + + v2 == in1 + -+-----------------+ +-----------------+ -+ VM-specific + -+ internal goop + -+-----------------+ <-- frame ptr (FP) for previous function -+ v0 == local0 + -+-----------------+ -+ v1 == local1 + -+-----------------+ -+ v2 == in0 + -+-----------------+ -+ v3 == in1 + -+-----------------+ -+ v4 == in2 + -+-----------------+ -- - -- - -- - -+-----------------+ <-- interpStackStart - - High addresses (0xffffffff) - -Note the "ins" and "outs" overlap -- values pushed into the "outs" area -become the parameters to the called method. The VM guarantees that there -will be enough room for all possible "outs" on the stack before calling -into a method. - -All "V registers" are 32 bits, and all stack entries are 32-bit aligned. -Registers are accessed as a positive offset from the frame pointer, -e.g. register v2 is fp[2]. 64-bit quantities are stored in two adjacent -registers, addressed by the lower-numbered register, and are in host order. -64-bit quantities do not need to start in an even-numbered register. - -We push two stack frames on when calling an interpreted or native method -directly from the VM (e.g. invoking <clinit> or via reflection "invoke()"). -The first is a "break" frame, which allows us to tell when a call return or -exception unroll has reached the VM call site. Without the break frame the -stack might look like an uninterrupted series of interpreted method calls. -The second frame is for the method itself. - -The "break" frame is used as an alternative to adding additional fields -to the StackSaveArea struct itself. They are recognized by having a -NULL method pointer. - -When calling a native method from interpreted code, the stack setup is -essentially identical to calling an interpreted method. Because it's a -native method, though, there are never any "locals" or "outs". - -For native calls into JNI, we want to store a table of local references -on the stack. The GC needs to scan them while the native code is running, -and we want to trivially discard them when the method returns. See JNI.c -for a discussion of how this is managed. In particular note that it is -possible to push additional call frames on without calling a method. -*/ - - -struct StackSaveArea; -typedef struct StackSaveArea StackSaveArea; - -//#define PAD_SAVE_AREA /* help debug stack trampling */ - -/* - * The VM-specific internal goop. - * - * The idea is to mimic a typical native stack frame, with copies of the - * saved PC and FP. At some point we'd like to have interpreted and - * native code share the same stack, though this makes portability harder. - */ -struct StackSaveArea { -#ifdef PAD_SAVE_AREA - u4 pad0, pad1, pad2; -#endif - -#ifdef EASY_GDB - /* make it easier to trek through stack frames in GDB */ - StackSaveArea* prevSave; -#endif - - /* saved frame pointer for previous frame, or NULL if this is at bottom */ - void* prevFrame; - - /* saved program counter (from method in caller's frame) */ - const u2* savedPc; - - /* pointer to method we're *currently* executing; handy for exceptions */ - const Method* method; - - union { - /* for JNI native methods: top of local reference storage */ - Object** localRefTop; - - /* for interpreted methods: saved current PC, for exception stack - * traces and debugger traces */ - const u2* currentPc; - } xtra; - -#ifdef PAD_SAVE_AREA - u4 pad3, pad4, pad5; -#endif -}; - -/* move between the stack save area and the frame pointer */ -#define SAVEAREA_FROM_FP(_fp) ((StackSaveArea*)(_fp) -1) -#define FP_FROM_SAVEAREA(_save) ((void*) ((StackSaveArea*)(_save) +1)) - -/* when calling a function, get a pointer to outs[0] */ -#define OUTS_FROM_FP(_fp, _argCount) \ - ((u4*) ((u1*)SAVEAREA_FROM_FP(_fp) - sizeof(u4) * (_argCount))) - -/* reserve this many bytes for handling StackOverflowError */ -#define STACK_OVERFLOW_RESERVE 512 - -/* - * Determine if the frame pointer points to a "break frame". - */ -INLINE bool dvmIsBreakFrame(const u4* fp) -{ - return SAVEAREA_FROM_FP(fp)->method == NULL; -} - -/* - * Initialize the interp stack (call this after allocating storage and - * setting thread->interpStackStart). - */ -bool dvmInitInterpStack(Thread* thread, int stackSize); - -/* - * Push a native method frame directly onto the stack. Used to push the - * "fake" native frames at the top of each thread stack. - */ -bool dvmPushJNIFrame(Thread* thread, const Method* method); - -/* - * JNI local frame management. - */ -bool dvmPushLocalFrame(Thread* thread, const Method* method); -bool dvmPopLocalFrame(Thread* thread); - -/* - * Call an interpreted method from native code. - * - * "obj" should be NULL for "direct" methods. - */ -void dvmCallMethodV(Thread* self, const Method* method, Object* obj, - JValue* pResult, va_list args); -void dvmCallMethodA(Thread* self, const Method* method, Object* obj, - JValue* pResult, const jvalue* args); -void dvmCallMethod(Thread* self, const Method* method, Object* obj, - JValue* pResult, ...); - -/* - * Invoke a method, using the specified arguments and return type, through - * a reflection interface. - * - * Deals with boxing/unboxing primitives and performs widening conversions. - * - * "obj" should be null for a static method. - * - * "params" and "returnType" come from the Method object, so we don't have - * to re-generate them from the method signature. "returnType" should be - * NULL if we're invoking a constructor. - */ -Object* dvmInvokeMethod(Object* invokeObj, const Method* meth, - ArrayObject* argList, ArrayObject* params, ClassObject* returnType, - bool noAccessCheck); - -/* - * Determine the source file line number, given the program counter offset - * into the specified method. Returns -2 for native methods, -1 if no - * match was found. - */ -int dvmLineNumFromPC(const Method* method, u4 relPc); - -/* - * Given a frame pointer, compute the current call depth. The value can be - * "exact" (a count of non-break frames) or "vague" (just subtracting - * pointers to give relative values). - */ -int dvmComputeExactFrameDepth(const void* fp); -int dvmComputeVagueFrameDepth(Thread* thread, const void* fp); - -/* - * Get the frame pointer for the caller's stack frame. - */ -void* dvmGetCallerFP(const void* curFrame); - -/* - * Get the class of the method that called us. - */ -ClassObject* dvmGetCallerClass(const void* curFrame); - -/* - * Get the caller's caller's class. Pass in the current fp. - * - * This is used by e.g. java.lang.Class, which wants to know about the - * class loader of the method that called it. - */ -ClassObject* dvmGetCaller2Class(const void* curFrame); - -/* - * Get the caller's caller's caller's class. Pass in the current fp. - * - * This is used by e.g. java.lang.Class, which wants to know about the - * class loader of the method that called it. - */ -ClassObject* dvmGetCaller3Class(const void* curFrame); - -/* - * Allocate and fill an array of method pointers representing the current - * stack trace (element 0 is current frame). - */ -bool dvmCreateStackTraceArray(const void* fp, const Method*** pArray, - int* pLength); - -/* - * Common handling for stack overflow. - */ -void dvmHandleStackOverflow(Thread* self); -void dvmCleanupStackOverflow(Thread* self); - -/* debugging; dvmDumpThread() is probably a better starting point */ -void dvmDumpThreadStack(const DebugOutputTarget* target, Thread* thread); -void dvmDumpRunningThreadStack(const DebugOutputTarget* target, Thread* thread); - -#endif /*_DALVIK_INTERP_STACK*/ |