summaryrefslogtreecommitdiffstats
path: root/vm/interp
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:14 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:14 -0800
commitf72d5de56a522ac3be03873bdde26f23a5eeeb3c (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /vm/interp
parent31e30105703263782efd450d356cd67ea01af3b7 (diff)
downloadandroid_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.c718
-rw-r--r--vm/interp/Interp.h37
-rw-r--r--vm/interp/InterpDefs.h148
-rw-r--r--vm/interp/README.txt4
-rw-r--r--vm/interp/Stack.c1233
-rw-r--r--vm/interp/Stack.h277
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*/