Stack.cpp revision 3ff838ee3920ef819d207cbf4148cc9c7939ef69
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * Stacks and their uses (e.g. native --> interpreted method calls).
19 *
20 * See the majestic ASCII art in Stack.h.
21 */
22#include "Dalvik.h"
23#include "jni.h"
24
25#include <stdlib.h>
26#include <stdarg.h>
27
28/*
29 * Initialize the interpreter stack in a new thread.
30 *
31 * Currently this doesn't do much, since we don't need to zero out the
32 * stack (and we really don't want to if it was created with mmap).
33 */
34bool dvmInitInterpStack(Thread* thread, int stackSize)
35{
36    assert(thread->interpStackStart != NULL);
37
38    assert(thread->interpSave.curFrame == NULL);
39
40    return true;
41}
42
43/*
44 * We're calling an interpreted method from an internal VM function or
45 * via reflection.
46 *
47 * Push a frame for an interpreted method onto the stack.  This is only
48 * used when calling into interpreted code from native code.  (The
49 * interpreter does its own stack frame manipulation for interp-->interp
50 * calls.)
51 *
52 * The size we need to reserve is the sum of parameters, local variables,
53 * saved goodies, and outbound parameters.
54 *
55 * We start by inserting a "break" frame, which ensures that the interpreter
56 * hands control back to us after the function we call returns or an
57 * uncaught exception is thrown.
58 */
59static bool dvmPushInterpFrame(Thread* self, const Method* method)
60{
61    StackSaveArea* saveBlock;
62    StackSaveArea* breakSaveBlock;
63    int stackReq;
64    u1* stackPtr;
65
66    assert(!dvmIsNativeMethod(method));
67    assert(!dvmIsAbstractMethod(method));
68
69    stackReq = method->registersSize * 4        // params + locals
70                + sizeof(StackSaveArea) * 2     // break frame + regular frame
71                + method->outsSize * 4;         // args to other methods
72
73    if (self->interpSave.curFrame != NULL)
74        stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame);
75    else
76        stackPtr = self->interpStackStart;
77
78    if (stackPtr - stackReq < self->interpStackEnd) {
79        /* not enough space */
80        LOGW("Stack overflow on call to interp "
81             "(req=%d top=%p cur=%p size=%d %s.%s)",
82            stackReq, self->interpStackStart, self->interpSave.curFrame,
83            self->interpStackSize, method->clazz->descriptor, method->name);
84        dvmHandleStackOverflow(self, method);
85        assert(dvmCheckException(self));
86        return false;
87    }
88
89    /*
90     * Shift the stack pointer down, leaving space for the function's
91     * args/registers and save area.
92     */
93    stackPtr -= sizeof(StackSaveArea);
94    breakSaveBlock = (StackSaveArea*)stackPtr;
95    stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea);
96    saveBlock = (StackSaveArea*) stackPtr;
97
98#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
99    /* debug -- memset the new stack, unless we want valgrind's help */
100    memset(stackPtr - (method->outsSize*4), 0xaf, stackReq);
101#endif
102#ifdef EASY_GDB
103    breakSaveBlock->prevSave =
104       (StackSaveArea*)FP_FROM_SAVEAREA(self->interpSave.curFrame);
105    saveBlock->prevSave = breakSaveBlock;
106#endif
107
108    breakSaveBlock->prevFrame = self->interpSave.curFrame;
109    breakSaveBlock->savedPc = NULL;             // not required
110    breakSaveBlock->xtra.localRefCookie = 0;    // not required
111    breakSaveBlock->method = NULL;
112    saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock);
113    saveBlock->savedPc = NULL;                  // not required
114    saveBlock->xtra.currentPc = NULL;           // not required?
115    saveBlock->method = method;
116
117    LOGVV("PUSH frame: old=%p new=%p (size=%d)",
118        self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock),
119        (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
120
121    self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock);
122
123    return true;
124}
125
126/*
127 * We're calling a JNI native method from an internal VM fuction or
128 * via reflection.  This is also used to create the "fake" native-method
129 * frames at the top of the interpreted stack.
130 *
131 * This actually pushes two frames; the first is a "break" frame.
132 *
133 * The top frame has additional space for JNI local reference tracking.
134 */
135bool dvmPushJNIFrame(Thread* self, const Method* method)
136{
137    StackSaveArea* saveBlock;
138    StackSaveArea* breakSaveBlock;
139    int stackReq;
140    u1* stackPtr;
141
142    assert(dvmIsNativeMethod(method));
143
144    stackReq = method->registersSize * 4        // params only
145                + sizeof(StackSaveArea) * 2;    // break frame + regular frame
146
147    if (self->interpSave.curFrame != NULL)
148        stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame);
149    else
150        stackPtr = self->interpStackStart;
151
152    if (stackPtr - stackReq < self->interpStackEnd) {
153        /* not enough space */
154        LOGW("Stack overflow on call to native "
155             "(req=%d top=%p cur=%p size=%d '%s')",
156            stackReq, self->interpStackStart, self->interpSave.curFrame,
157            self->interpStackSize, method->name);
158        dvmHandleStackOverflow(self, method);
159        assert(dvmCheckException(self));
160        return false;
161    }
162
163    /*
164     * Shift the stack pointer down, leaving space for just the stack save
165     * area for the break frame, then shift down farther for the full frame.
166     * We leave space for the method args, which are copied in later.
167     */
168    stackPtr -= sizeof(StackSaveArea);
169    breakSaveBlock = (StackSaveArea*)stackPtr;
170    stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea);
171    saveBlock = (StackSaveArea*) stackPtr;
172
173#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
174    /* debug -- memset the new stack */
175    memset(stackPtr, 0xaf, stackReq);
176#endif
177#ifdef EASY_GDB
178    if (self->interpSave.curFrame == NULL)
179        breakSaveBlock->prevSave = NULL;
180    else {
181        void* fp = FP_FROM_SAVEAREA(self->interpSave.curFrame);
182        breakSaveBlock->prevSave = (StackSaveArea*)fp;
183    }
184    saveBlock->prevSave = breakSaveBlock;
185#endif
186
187    breakSaveBlock->prevFrame = self->interpSave.curFrame;
188    breakSaveBlock->savedPc = NULL;             // not required
189    breakSaveBlock->xtra.localRefCookie = 0;    // not required
190    breakSaveBlock->method = NULL;
191    saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock);
192    saveBlock->savedPc = NULL;                  // not required
193    saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
194    saveBlock->method = method;
195
196    LOGVV("PUSH JNI frame: old=%p new=%p (size=%d)",
197        self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock),
198        (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
199
200    self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock);
201
202    return true;
203}
204
205/*
206 * This is used by the JNI PushLocalFrame call.  We push a new frame onto
207 * the stack that has no ins, outs, or locals, and no break frame above it.
208 * It's strictly used for tracking JNI local refs, and will be popped off
209 * by dvmPopFrame if it's not removed explicitly.
210 */
211bool dvmPushLocalFrame(Thread* self, const Method* method)
212{
213    StackSaveArea* saveBlock;
214    int stackReq;
215    u1* stackPtr;
216
217    assert(dvmIsNativeMethod(method));
218
219    stackReq = sizeof(StackSaveArea);       // regular frame
220
221    assert(self->interpSave.curFrame != NULL);
222    stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame);
223
224    if (stackPtr - stackReq < self->interpStackEnd) {
225        /* not enough space; let JNI throw the exception */
226        LOGW("Stack overflow on PushLocal "
227             "(req=%d top=%p cur=%p size=%d '%s')",
228            stackReq, self->interpStackStart, self->interpSave.curFrame,
229            self->interpStackSize, method->name);
230        dvmHandleStackOverflow(self, method);
231        assert(dvmCheckException(self));
232        return false;
233    }
234
235    /*
236     * Shift the stack pointer down, leaving space for just the stack save
237     * area for the break frame, then shift down farther for the full frame.
238     */
239    stackPtr -= sizeof(StackSaveArea);
240    saveBlock = (StackSaveArea*) stackPtr;
241
242#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
243    /* debug -- memset the new stack */
244    memset(stackPtr, 0xaf, stackReq);
245#endif
246#ifdef EASY_GDB
247    saveBlock->prevSave =
248        (StackSaveArea*)FP_FROM_SAVEAREA(self->interpSave.curFrame);
249#endif
250
251    saveBlock->prevFrame = self->interpSave.curFrame;
252    saveBlock->savedPc = NULL;                  // not required
253    saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
254    saveBlock->method = method;
255
256    LOGVV("PUSH JNI local frame: old=%p new=%p (size=%d)",
257        self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock),
258        (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
259
260    self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock);
261
262    return true;
263}
264
265/*
266 * Pop one frame pushed on by JNI PushLocalFrame.
267 *
268 * If we've gone too far, the previous frame is either a break frame or
269 * an interpreted frame.  Either way, the method pointer won't match.
270 */
271bool dvmPopLocalFrame(Thread* self)
272{
273    StackSaveArea* saveBlock = SAVEAREA_FROM_FP(self->interpSave.curFrame);
274
275    assert(!dvmIsBreakFrame((u4*)self->interpSave.curFrame));
276    if (saveBlock->method != SAVEAREA_FROM_FP(saveBlock->prevFrame)->method) {
277        /*
278         * The previous frame doesn't have the same method pointer -- we've
279         * been asked to pop too much.
280         */
281        assert(dvmIsBreakFrame((u4*)saveBlock->prevFrame) ||
282               !dvmIsNativeMethod(
283                       SAVEAREA_FROM_FP(saveBlock->prevFrame)->method));
284        return false;
285    }
286
287    LOGVV("POP JNI local frame: removing %s, now %s",
288        saveBlock->method->name,
289        SAVEAREA_FROM_FP(saveBlock->prevFrame)->method->name);
290    dvmPopJniLocals(self, saveBlock);
291    self->interpSave.curFrame = saveBlock->prevFrame;
292
293    return true;
294}
295
296/*
297 * Pop a frame we added.  There should be one method frame and one break
298 * frame.
299 *
300 * If JNI Push/PopLocalFrame calls were mismatched, we might end up
301 * popping multiple method frames before we find the break.
302 *
303 * Returns "false" if there was no frame to pop.
304 */
305static bool dvmPopFrame(Thread* self)
306{
307    StackSaveArea* saveBlock;
308
309    if (self->interpSave.curFrame == NULL)
310        return false;
311
312    saveBlock = SAVEAREA_FROM_FP(self->interpSave.curFrame);
313    assert(!dvmIsBreakFrame((u4*)self->interpSave.curFrame));
314
315    /*
316     * Remove everything up to the break frame.  If this was a call into
317     * native code, pop the JNI local references table.
318     */
319    while (saveBlock->prevFrame != NULL && saveBlock->method != NULL) {
320        /* probably a native->native JNI call */
321
322        if (dvmIsNativeMethod(saveBlock->method)) {
323            LOGVV("Popping JNI stack frame for %s.%s%s",
324                saveBlock->method->clazz->descriptor,
325                saveBlock->method->name,
326                (SAVEAREA_FROM_FP(saveBlock->prevFrame)->method == NULL) ?
327                "" : " (JNI local)");
328            dvmPopJniLocals(self, saveBlock);
329        }
330
331        saveBlock = SAVEAREA_FROM_FP(saveBlock->prevFrame);
332    }
333    if (saveBlock->method != NULL) {
334        LOGE("PopFrame missed the break");
335        assert(false);
336        dvmAbort();     // stack trashed -- nowhere to go in this thread
337    }
338
339    LOGVV("POP frame: cur=%p new=%p",
340        self->interpSave.curFrame, saveBlock->prevFrame);
341
342    self->interpSave.curFrame = saveBlock->prevFrame;
343    return true;
344}
345
346/*
347 * Common code for dvmCallMethodV/A and dvmInvokeMethod.
348 *
349 * Pushes a call frame on, advancing self->interpSave.curFrame.
350 */
351static ClassObject* callPrep(Thread* self, const Method* method, Object* obj,
352    bool checkAccess)
353{
354    ClassObject* clazz;
355
356#ifndef NDEBUG
357    if (self->status != THREAD_RUNNING) {
358        LOGW("threadid=%d: status=%d on call to %s.%s -",
359            self->threadId, self->status,
360            method->clazz->descriptor, method->name);
361    }
362#endif
363
364    assert(self != NULL);
365    assert(method != NULL);
366
367    if (obj != NULL)
368        clazz = obj->clazz;
369    else
370        clazz = method->clazz;
371
372    IF_LOGVV() {
373        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
374        LOGVV("thread=%d native code calling %s.%s %s", self->threadId,
375            clazz->descriptor, method->name, desc);
376        free(desc);
377    }
378
379    if (checkAccess) {
380        /* needed for java.lang.reflect.Method.invoke */
381        if (!dvmCheckMethodAccess(dvmGetCaller2Class(self->interpSave.curFrame),
382                method))
383        {
384            /* note this throws IAException, not IAError */
385            dvmThrowIllegalAccessException("access to method denied");
386            return NULL;
387        }
388    }
389
390    /*
391     * Push a call frame on.  If there isn't enough room for ins, locals,
392     * outs, and the saved state, it will throw an exception.
393     *
394     * This updates self->interpSave.curFrame.
395     */
396    if (dvmIsNativeMethod(method)) {
397        /* native code calling native code the hard way */
398        if (!dvmPushJNIFrame(self, method)) {
399            assert(dvmCheckException(self));
400            return NULL;
401        }
402    } else {
403        /* native code calling interpreted code */
404        if (!dvmPushInterpFrame(self, method)) {
405            assert(dvmCheckException(self));
406            return NULL;
407        }
408    }
409
410    return clazz;
411}
412
413/*
414 * Issue a method call.
415 *
416 * Pass in NULL for "obj" on calls to static methods.
417 *
418 * (Note this can't be inlined because it takes a variable number of args.)
419 */
420void dvmCallMethod(Thread* self, const Method* method, Object* obj,
421    JValue* pResult, ...)
422{
423    va_list args;
424    va_start(args, pResult);
425    dvmCallMethodV(self, method, obj, false, pResult, args);
426    va_end(args);
427}
428
429/*
430 * Issue a method call with a variable number of arguments.  We process
431 * the contents of "args" by scanning the method signature.
432 *
433 * Pass in NULL for "obj" on calls to static methods.
434 *
435 * We don't need to take the class as an argument because, in Dalvik,
436 * we don't need to worry about static synchronized methods.
437 */
438void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
439    bool fromJni, JValue* pResult, va_list args)
440{
441    const char* desc = &(method->shorty[1]); // [0] is the return type.
442    int verifyCount = 0;
443    ClassObject* clazz;
444    u4* ins;
445
446    clazz = callPrep(self, method, obj, false);
447    if (clazz == NULL)
448        return;
449
450    /* "ins" for new frame start at frame pointer plus locals */
451    ins = ((u4*)self->interpSave.curFrame) +
452           (method->registersSize - method->insSize);
453
454    //LOGD("  FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);
455
456    /* put "this" pointer into in0 if appropriate */
457    if (!dvmIsStaticMethod(method)) {
458#ifdef WITH_EXTRA_OBJECT_VALIDATION
459        assert(obj != NULL && dvmIsHeapAddress(obj));
460#endif
461        *ins++ = (u4) obj;
462        verifyCount++;
463    }
464
465    JNIEnv* env = self->jniEnv;
466    while (*desc != '\0') {
467        switch (*(desc++)) {
468            case 'D': case 'J': {
469                u8 val = va_arg(args, u8);
470                memcpy(ins, &val, 8);       // EABI prevents direct store
471                ins += 2;
472                verifyCount += 2;
473                break;
474            }
475            case 'F': {
476                /* floats were normalized to doubles; convert back */
477                float f = (float) va_arg(args, double);
478                *ins++ = dvmFloatToU4(f);
479                verifyCount++;
480                break;
481            }
482            case 'L': {     /* 'shorty' descr uses L for all refs, incl array */
483                void* arg = va_arg(args, void*);
484                assert(obj == NULL || dvmIsHeapAddress(obj));
485                jobject argObj = reinterpret_cast<jobject>(arg);
486                if (fromJni)
487                    *ins++ = (u4) dvmDecodeIndirectRef(env, argObj);
488                else
489                    *ins++ = (u4) argObj;
490                verifyCount++;
491                break;
492            }
493            default: {
494                /* Z B C S I -- all passed as 32-bit integers */
495                *ins++ = va_arg(args, u4);
496                verifyCount++;
497                break;
498            }
499        }
500    }
501
502#ifndef NDEBUG
503    if (verifyCount != method->insSize) {
504        LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
505            method->insSize, clazz->descriptor, method->name);
506        assert(false);
507        goto bail;
508    }
509#endif
510
511    //dvmDumpThreadStack(dvmThreadSelf());
512
513    if (dvmIsNativeMethod(method)) {
514        TRACE_METHOD_ENTER(self, method);
515        /*
516         * Because we leave no space for local variables, "curFrame" points
517         * directly at the method arguments.
518         */
519        (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult,
520                              method, self);
521        TRACE_METHOD_EXIT(self, method);
522    } else {
523        dvmInterpret(self, method, pResult);
524    }
525
526#ifndef NDEBUG
527bail:
528#endif
529    dvmPopFrame(self);
530}
531
532/*
533 * Issue a method call with arguments provided in an array.  We process
534 * the contents of "args" by scanning the method signature.
535 *
536 * The values were likely placed into an uninitialized jvalue array using
537 * the field specifiers, which means that sub-32-bit fields (e.g. short,
538 * boolean) may not have 32 or 64 bits of valid data.  This is different
539 * from the varargs invocation where the C compiler does a widening
540 * conversion when calling a function.  As a result, we have to be a
541 * little more precise when pulling stuff out.
542 *
543 * "args" may be NULL if the method has no arguments.
544 */
545void dvmCallMethodA(Thread* self, const Method* method, Object* obj,
546    bool fromJni, JValue* pResult, const jvalue* args)
547{
548    const char* desc = &(method->shorty[1]); // [0] is the return type.
549    int verifyCount = 0;
550    ClassObject* clazz;
551    u4* ins;
552
553    clazz = callPrep(self, method, obj, false);
554    if (clazz == NULL)
555        return;
556
557    /* "ins" for new frame start at frame pointer plus locals */
558    ins = ((u4*)self->interpSave.curFrame) +
559        (method->registersSize - method->insSize);
560
561    /* put "this" pointer into in0 if appropriate */
562    if (!dvmIsStaticMethod(method)) {
563        assert(obj != NULL);
564        *ins++ = (u4) obj;              /* obj is a "real" ref */
565        verifyCount++;
566    }
567
568    JNIEnv* env = self->jniEnv;
569    while (*desc != '\0') {
570        switch (*desc++) {
571        case 'D':                       /* 64-bit quantity; have to use */
572        case 'J':                       /*  memcpy() in case of mis-alignment */
573            memcpy(ins, &args->j, 8);
574            ins += 2;
575            verifyCount++;              /* this needs an extra push */
576            break;
577        case 'L':                       /* includes array refs */
578            if (fromJni)
579                *ins++ = (u4) dvmDecodeIndirectRef(env, args->l);
580            else
581                *ins++ = (u4) args->l;
582            break;
583        case 'F':
584        case 'I':
585            *ins++ = args->i;           /* full 32 bits */
586            break;
587        case 'S':
588            *ins++ = args->s;           /* 16 bits, sign-extended */
589            break;
590        case 'C':
591            *ins++ = args->c;           /* 16 bits, unsigned */
592            break;
593        case 'B':
594            *ins++ = args->b;           /* 8 bits, sign-extended */
595            break;
596        case 'Z':
597            *ins++ = args->z;           /* 8 bits, zero or non-zero */
598            break;
599        default:
600            LOGE("Invalid char %c in short signature of %s.%s",
601                *(desc-1), clazz->descriptor, method->name);
602            assert(false);
603            goto bail;
604        }
605
606        verifyCount++;
607        args++;
608    }
609
610#ifndef NDEBUG
611    if (verifyCount != method->insSize) {
612        LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
613            method->insSize, clazz->descriptor, method->name);
614        assert(false);
615        goto bail;
616    }
617#endif
618
619    if (dvmIsNativeMethod(method)) {
620        TRACE_METHOD_ENTER(self, method);
621        /*
622         * Because we leave no space for local variables, "curFrame" points
623         * directly at the method arguments.
624         */
625        (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult,
626                              method, self);
627        TRACE_METHOD_EXIT(self, method);
628    } else {
629        dvmInterpret(self, method, pResult);
630    }
631
632bail:
633    dvmPopFrame(self);
634}
635
636static void throwArgumentTypeMismatch(int argIndex, ClassObject* expected, DataObject* arg) {
637    std::string expectedClassName(dvmHumanReadableDescriptor(expected->descriptor));
638    std::string actualClassName = dvmHumanReadableType(arg);
639    dvmThrowExceptionFmt(gDvm.exIllegalArgumentException, "argument %d should have type %s, got %s",
640            argIndex + 1, expectedClassName.c_str(), actualClassName.c_str());
641}
642
643/*
644 * Invoke a method, using the specified arguments and return type, through
645 * one of the reflection interfaces.  Could be a virtual or direct method
646 * (including constructors).  Used for reflection.
647 *
648 * Deals with boxing/unboxing primitives and performs widening conversions.
649 *
650 * "invokeObj" will be null for a static method.
651 *
652 * If the invocation returns with an exception raised, we have to wrap it.
653 */
654Object* dvmInvokeMethod(Object* obj, const Method* method,
655    ArrayObject* argList, ArrayObject* params, ClassObject* returnType,
656    bool noAccessCheck)
657{
658    ClassObject* clazz;
659    Object* retObj = NULL;
660    Thread* self = dvmThreadSelf();
661    s4* ins;
662    int verifyCount, argListLength;
663    JValue retval;
664    bool needPop = false;
665
666    /* verify arg count */
667    if (argList != NULL)
668        argListLength = argList->length;
669    else
670        argListLength = 0;
671    if (argListLength != (int) params->length) {
672        dvmThrowExceptionFmt(gDvm.exIllegalArgumentException,
673            "wrong number of arguments; expected %d, got %d",
674            params->length, argListLength);
675        return NULL;
676    }
677
678    clazz = callPrep(self, method, obj, !noAccessCheck);
679    if (clazz == NULL)
680        return NULL;
681    needPop = true;
682
683    /* "ins" for new frame start at frame pointer plus locals */
684    ins = ((s4*)self->interpSave.curFrame) +
685        (method->registersSize - method->insSize);
686    verifyCount = 0;
687
688    //LOGD("  FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);
689
690    /* put "this" pointer into in0 if appropriate */
691    if (!dvmIsStaticMethod(method)) {
692        assert(obj != NULL);
693        *ins++ = (s4) obj;
694        verifyCount++;
695    }
696
697    /*
698     * Copy the args onto the stack.  Primitive types are converted when
699     * necessary, and object types are verified.
700     */
701    DataObject** args = (DataObject**)(void*)argList->contents;
702    ClassObject** types = (ClassObject**)(void*)params->contents;
703    for (int i = 0; i < argListLength; i++) {
704        int width = dvmConvertArgument(*args++, *types++, ins);
705        if (width < 0) {
706            dvmPopFrame(self);      // throw wants to pull PC out of stack
707            needPop = false;
708            throwArgumentTypeMismatch(i, *(types-1), *(args-1));
709            goto bail;
710        }
711
712        ins += width;
713        verifyCount += width;
714    }
715
716#ifndef NDEBUG
717    if (verifyCount != method->insSize) {
718        LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
719            method->insSize, clazz->descriptor, method->name);
720        assert(false);
721        goto bail;
722    }
723#endif
724
725    if (dvmIsNativeMethod(method)) {
726        TRACE_METHOD_ENTER(self, method);
727        /*
728         * Because we leave no space for local variables, "curFrame" points
729         * directly at the method arguments.
730         */
731        (*method->nativeFunc)((u4*)self->interpSave.curFrame, &retval,
732                              method, self);
733        TRACE_METHOD_EXIT(self, method);
734    } else {
735        dvmInterpret(self, method, &retval);
736    }
737
738    /*
739     * Pop the frame immediately.  The "wrap" calls below can cause
740     * allocations, and we don't want the GC to walk the now-dead frame.
741     */
742    dvmPopFrame(self);
743    needPop = false;
744
745    /*
746     * If an exception is raised, wrap and replace.  This is necessary
747     * because the invoked method could have thrown a checked exception
748     * that the caller wasn't prepared for.
749     *
750     * We might be able to do this up in the interpreted code, but that will
751     * leave us with a shortened stack trace in the top-level exception.
752     */
753    if (dvmCheckException(self)) {
754        dvmWrapException("Ljava/lang/reflect/InvocationTargetException;");
755    } else {
756        /*
757         * If this isn't a void method or constructor, convert the return type
758         * to an appropriate object.
759         *
760         * We don't do this when an exception is raised because the value
761         * in "retval" is undefined.
762         */
763        if (returnType != NULL) {
764            retObj = (Object*)dvmBoxPrimitive(retval, returnType);
765            dvmReleaseTrackedAlloc(retObj, NULL);
766        }
767    }
768
769bail:
770    if (needPop) {
771        dvmPopFrame(self);
772    }
773    return retObj;
774}
775
776struct LineNumFromPcContext {
777    u4 address;
778    u4 lineNum;
779};
780
781static int lineNumForPcCb(void *cnxt, u4 address, u4 lineNum)
782{
783    LineNumFromPcContext *pContext = (LineNumFromPcContext *)cnxt;
784
785    // We know that this callback will be called in
786    // ascending address order, so keep going until we find
787    // a match or we've just gone past it.
788
789    if (address > pContext->address) {
790        // The line number from the previous positions callback
791        // wil be the final result.
792        return 1;
793    }
794
795    pContext->lineNum = lineNum;
796
797    return (address == pContext->address) ? 1 : 0;
798}
799
800/*
801 * Determine the source file line number based on the program counter.
802 * "pc" is an offset, in 16-bit units, from the start of the method's code.
803 *
804 * Returns -1 if no match was found (possibly because the source files were
805 * compiled without "-g", so no line number information is present).
806 * Returns -2 for native methods (as expected in exception traces).
807 */
808int dvmLineNumFromPC(const Method* method, u4 relPc)
809{
810    const DexCode* pDexCode = dvmGetMethodCode(method);
811
812    if (pDexCode == NULL) {
813        if (dvmIsNativeMethod(method) && !dvmIsAbstractMethod(method))
814            return -2;
815        return -1;      /* can happen for abstract method stub */
816    }
817
818    LineNumFromPcContext context;
819    memset(&context, 0, sizeof(context));
820    context.address = relPc;
821    // A method with no line number info should return -1
822    context.lineNum = -1;
823
824    dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile, pDexCode,
825            method->clazz->descriptor,
826            method->prototype.protoIdx,
827            method->accessFlags,
828            lineNumForPcCb, NULL, &context);
829
830    return context.lineNum;
831}
832
833/*
834 * Compute the frame depth.
835 *
836 * Excludes "break" frames.
837 */
838int dvmComputeExactFrameDepth(const void* fp)
839{
840    int count = 0;
841
842    for ( ; fp != NULL; fp = SAVEAREA_FROM_FP(fp)->prevFrame) {
843        if (!dvmIsBreakFrame((u4*)fp))
844            count++;
845    }
846
847    return count;
848}
849
850/*
851 * Compute the "vague" frame depth, which is just a pointer subtraction.
852 * The result is NOT an overly generous assessment of the number of
853 * frames; the only meaningful use is to compare against the result of
854 * an earlier invocation.
855 *
856 * Useful for implementing single-step debugger modes, which may need to
857 * call this for every instruction.
858 */
859int dvmComputeVagueFrameDepth(Thread* thread, const void* fp)
860{
861    const u1* interpStackStart = thread->interpStackStart;
862
863    assert((u1*) fp >= interpStackStart - thread->interpStackSize);
864    assert((u1*) fp < interpStackStart);
865    return interpStackStart - (u1*) fp;
866}
867
868/*
869 * Get the calling frame.  Pass in the current fp.
870 *
871 * Skip "break" frames and reflection invoke frames.
872 */
873void* dvmGetCallerFP(const void* curFrame)
874{
875    void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
876    StackSaveArea* saveArea;
877
878retry:
879    if (dvmIsBreakFrame((u4*)caller)) {
880        /* pop up one more */
881        caller = SAVEAREA_FROM_FP(caller)->prevFrame;
882        if (caller == NULL)
883            return NULL;        /* hit the top */
884
885        /*
886         * If we got here by java.lang.reflect.Method.invoke(), we don't
887         * want to return Method's class loader.  Shift up one and try
888         * again.
889         */
890        saveArea = SAVEAREA_FROM_FP(caller);
891        if (dvmIsReflectionMethod(saveArea->method)) {
892            caller = saveArea->prevFrame;
893            assert(caller != NULL);
894            goto retry;
895        }
896    }
897
898    return caller;
899}
900
901/*
902 * Get the caller's class.  Pass in the current fp.
903 *
904 * This is used by e.g. java.lang.Class.
905 */
906ClassObject* dvmGetCallerClass(const void* curFrame)
907{
908    void* caller;
909
910    caller = dvmGetCallerFP(curFrame);
911    if (caller == NULL)
912        return NULL;
913
914    return SAVEAREA_FROM_FP(caller)->method->clazz;
915}
916
917/*
918 * Get the caller's caller's class.  Pass in the current fp.
919 *
920 * This is used by e.g. java.lang.Class, which wants to know about the
921 * class loader of the method that called it.
922 */
923ClassObject* dvmGetCaller2Class(const void* curFrame)
924{
925    void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
926    void* callerCaller;
927
928    /* at the top? */
929    if (dvmIsBreakFrame((u4*)caller) &&
930        SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
931        return NULL;
932
933    /* go one more */
934    callerCaller = dvmGetCallerFP(caller);
935    if (callerCaller == NULL)
936        return NULL;
937
938    return SAVEAREA_FROM_FP(callerCaller)->method->clazz;
939}
940
941/*
942 * Get the caller's caller's caller's class.  Pass in the current fp.
943 *
944 * This is used by e.g. java.lang.Class, which wants to know about the
945 * class loader of the method that called it.
946 */
947ClassObject* dvmGetCaller3Class(const void* curFrame)
948{
949    void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
950    int i;
951
952    /* at the top? */
953    if (dvmIsBreakFrame((u4*)caller) &&
954        SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
955        return NULL;
956
957    /* Walk up two frames if possible. */
958    for (i = 0; i < 2; i++) {
959        caller = dvmGetCallerFP(caller);
960        if (caller == NULL)
961            return NULL;
962    }
963
964    return SAVEAREA_FROM_FP(caller)->method->clazz;
965}
966
967/*
968 * Fill a flat array of methods that comprise the current interpreter
969 * stack trace.  Pass in the current frame ptr.  Break frames are
970 * skipped, but reflection invocations are not.
971 *
972 * The current frame will be in element 0.
973 */
974void dvmFillStackTraceArray(const void* fp, const Method** array, size_t length)
975{
976    assert(fp != NULL);
977    assert(array != NULL);
978    size_t i = 0;
979    while (fp != NULL) {
980        if (!dvmIsBreakFrame((u4*)fp)) {
981            assert(i < length);
982            array[i++] = SAVEAREA_FROM_FP(fp)->method;
983        }
984        fp = SAVEAREA_FROM_FP(fp)->prevFrame;
985    }
986}
987
988/*
989 * Open up the reserved area and throw an exception.  The reserved area
990 * should only be needed to create and initialize the exception itself.
991 *
992 * If we already opened it and we're continuing to overflow, abort the VM.
993 *
994 * We have to leave the "reserved" area open until the "catch" handler has
995 * finished doing its processing.  This is because the catch handler may
996 * need to resolve classes, which requires calling into the class loader if
997 * the classes aren't already in the "initiating loader" list.
998 */
999void dvmHandleStackOverflow(Thread* self, const Method* method)
1000{
1001    /*
1002     * Can we make the reserved area available?
1003     */
1004    if (self->stackOverflowed) {
1005        /*
1006         * Already did, nothing to do but bail.
1007         */
1008        LOGE("DalvikVM: double-overflow of stack in threadid=%d; aborting",
1009            self->threadId);
1010        dvmDumpThread(self, false);
1011        dvmAbort();
1012    }
1013
1014    /* open it up to the full range */
1015    LOGI("threadid=%d: stack overflow on call to %s.%s:%s",
1016        self->threadId,
1017        method->clazz->descriptor, method->name, method->shorty);
1018    StackSaveArea* saveArea = SAVEAREA_FROM_FP(self->interpSave.curFrame);
1019    LOGI("  method requires %d+%d+%d=%d bytes, fp is %p (%d left)",
1020        method->registersSize * 4, sizeof(StackSaveArea), method->outsSize * 4,
1021        (method->registersSize + method->outsSize) * 4 + sizeof(StackSaveArea),
1022        saveArea, (u1*) saveArea - self->interpStackEnd);
1023    LOGI("  expanding stack end (%p to %p)", self->interpStackEnd,
1024        self->interpStackStart - self->interpStackSize);
1025    //dvmDumpThread(self, false);
1026    self->interpStackEnd = self->interpStackStart - self->interpStackSize;
1027    self->stackOverflowed = true;
1028
1029    /*
1030     * If we were trying to throw an exception when the stack overflowed,
1031     * we will blow up when doing the class lookup on StackOverflowError
1032     * because of the pending exception.  So, we clear it and make it
1033     * the cause of the SOE.
1034     */
1035    Object* excep = dvmGetException(self);
1036    if (excep != NULL) {
1037        LOGW("Stack overflow while throwing exception");
1038        dvmClearException(self);
1039    }
1040    dvmThrowChainedException(gDvm.exStackOverflowError, NULL, excep);
1041}
1042
1043/*
1044 * Reduce the available stack size.  By this point we should have finished
1045 * our overflow processing.
1046 */
1047void dvmCleanupStackOverflow(Thread* self, const Object* exception)
1048{
1049    const u1* newStackEnd;
1050
1051    assert(self->stackOverflowed);
1052
1053    if (exception->clazz != gDvm.exStackOverflowError) {
1054        /* exception caused during SOE, not the SOE itself */
1055        return;
1056    }
1057
1058    newStackEnd = (self->interpStackStart - self->interpStackSize)
1059        + STACK_OVERFLOW_RESERVE;
1060    if ((u1*)self->interpSave.curFrame <= newStackEnd) {
1061        LOGE("Can't shrink stack: curFrame is in reserved area (%p %p)",
1062            self->interpStackEnd, self->interpSave.curFrame);
1063        dvmDumpThread(self, false);
1064        dvmAbort();
1065    }
1066
1067    self->interpStackEnd = newStackEnd;
1068    self->stackOverflowed = false;
1069
1070    LOGI("Shrank stack (to %p, curFrame is %p)", self->interpStackEnd,
1071        self->interpSave.curFrame);
1072}
1073
1074
1075/*
1076 * Extract the object that is the target of a monitor-enter instruction
1077 * in the top stack frame of "thread".
1078 *
1079 * The other thread might be alive, so this has to work carefully.
1080 *
1081 * The thread list lock must be held.
1082 *
1083 * Returns "true" if we successfully recover the object.  "*pOwner" will
1084 * be NULL if we can't determine the owner for some reason (e.g. race
1085 * condition on ownership transfer).
1086 */
1087static bool extractMonitorEnterObject(Thread* thread, Object** pLockObj,
1088    Thread** pOwner)
1089{
1090    void* framePtr = thread->interpSave.curFrame;
1091
1092    if (framePtr == NULL || dvmIsBreakFrame((u4*)framePtr))
1093        return false;
1094
1095    const StackSaveArea* saveArea = SAVEAREA_FROM_FP(framePtr);
1096    const Method* method = saveArea->method;
1097    const u2* currentPc = saveArea->xtra.currentPc;
1098
1099    /* check Method* */
1100    if (!dvmLinearAllocContains(method, sizeof(Method))) {
1101        LOGD("ExtrMon: method %p not valid", method);
1102        return false;
1103    }
1104
1105    /* check currentPc */
1106    u4 insnsSize = dvmGetMethodInsnsSize(method);
1107    if (currentPc < method->insns ||
1108        currentPc >= method->insns + insnsSize)
1109    {
1110        LOGD("ExtrMon: insns %p not valid (%p - %p)",
1111            currentPc, method->insns, method->insns + insnsSize);
1112        return false;
1113    }
1114
1115    /* check the instruction */
1116    if ((*currentPc & 0xff) != OP_MONITOR_ENTER) {
1117        LOGD("ExtrMon: insn at %p is not monitor-enter (0x%02x)",
1118            currentPc, *currentPc & 0xff);
1119        return false;
1120    }
1121
1122    /* get and check the register index */
1123    unsigned int reg = *currentPc >> 8;
1124    if (reg >= method->registersSize) {
1125        LOGD("ExtrMon: invalid register %d (max %d)",
1126            reg, method->registersSize);
1127        return false;
1128    }
1129
1130    /* get and check the object in that register */
1131    u4* fp = (u4*) framePtr;
1132    Object* obj = (Object*) fp[reg];
1133    if (obj != NULL && !dvmIsHeapAddress(obj)) {
1134        LOGD("ExtrMon: invalid object %p at %p[%d]", obj, fp, reg);
1135        return false;
1136    }
1137    *pLockObj = obj;
1138
1139    /*
1140     * Try to determine the object's lock holder; it's okay if this fails.
1141     *
1142     * We're assuming the thread list lock is already held by this thread.
1143     * If it's not, we may be living dangerously if we have to scan through
1144     * the thread list to find a match.  (The VM will generally be in a
1145     * suspended state when executing here, so this is a minor concern
1146     * unless we're dumping while threads are running, in which case there's
1147     * a good chance of stuff blowing up anyway.)
1148     */
1149    *pOwner = dvmGetObjectLockHolder(obj);
1150
1151    return true;
1152}
1153
1154static void printWaitMessage(const DebugOutputTarget* target, const char* detail, Object* obj,
1155        Thread* thread)
1156{
1157    std::string msg(StringPrintf("  - waiting %s <%p> ", detail, obj));
1158
1159    if (obj->clazz != gDvm.classJavaLangClass) {
1160        // I(16573)   - waiting on <0xf5feda38> (a java.util.LinkedList)
1161        // I(16573)   - waiting on <0xf5ed54f8> (a java.lang.Class<java.lang.ref.ReferenceQueue>)
1162        msg += "(a " + dvmHumanReadableType(obj) + ")";
1163    }
1164
1165    if (thread != NULL) {
1166        std::string threadName(dvmGetThreadName(thread));
1167        StringAppendF(&msg, " held by tid=%d (%s)", thread->threadId, threadName.c_str());
1168    }
1169
1170    dvmPrintDebugMessage(target, "%s\n", msg.c_str());
1171}
1172
1173/*
1174 * Dump stack frames, starting from the specified frame and moving down.
1175 *
1176 * Each frame holds a pointer to the currently executing method, and the
1177 * saved program counter from the caller ("previous" frame).  This means
1178 * we don't have the PC for the current method on the stack, which is
1179 * pretty reasonable since it's in the "PC register" for the VM.  Because
1180 * exceptions need to show the correct line number we actually *do* have
1181 * an updated version in the fame's "xtra.currentPc", but it's unreliable.
1182 *
1183 * Note "framePtr" could be NULL in rare circumstances.
1184 */
1185static void dumpFrames(const DebugOutputTarget* target, void* framePtr,
1186    Thread* thread)
1187{
1188    const StackSaveArea* saveArea;
1189    const Method* method;
1190    int checkCount = 0;
1191    const u2* currentPc = NULL;
1192    bool first = true;
1193
1194    /*
1195     * We call functions that require us to be holding the thread list lock.
1196     * It's probable that the caller has already done so, but it's not
1197     * guaranteed.  If it's not locked, lock it now.
1198     */
1199    bool needThreadUnlock = dvmTryLockThreadList();
1200
1201    /*
1202     * The "currentPc" is updated whenever we execute an instruction that
1203     * might throw an exception.  Show it here.
1204     */
1205    if (framePtr != NULL && !dvmIsBreakFrame((u4*)framePtr)) {
1206        saveArea = SAVEAREA_FROM_FP(framePtr);
1207
1208        if (saveArea->xtra.currentPc != NULL)
1209            currentPc = saveArea->xtra.currentPc;
1210    }
1211
1212    while (framePtr != NULL) {
1213        saveArea = SAVEAREA_FROM_FP(framePtr);
1214        method = saveArea->method;
1215
1216        if (dvmIsBreakFrame((u4*)framePtr)) {
1217            //dvmPrintDebugMessage(target, "  (break frame)\n");
1218        } else {
1219            int relPc;
1220
1221            if (currentPc != NULL)
1222                relPc = currentPc - saveArea->method->insns;
1223            else
1224                relPc = -1;
1225
1226            std::string methodName(dvmHumanReadableMethod(method, false));
1227            if (dvmIsNativeMethod(method)) {
1228                dvmPrintDebugMessage(target, "  at %s(Native Method)\n",
1229                        methodName.c_str());
1230            } else {
1231                dvmPrintDebugMessage(target, "  at %s(%s:%s%d)\n",
1232                        methodName.c_str(), dvmGetMethodSourceFile(method),
1233                        (relPc >= 0 && first) ? "~" : "",
1234                        relPc < 0 ? -1 : dvmLineNumFromPC(method, relPc));
1235            }
1236
1237            if (first) {
1238                /*
1239                 * Decorate WAIT and MONITOR threads with some detail on
1240                 * the first frame.
1241                 *
1242                 * warning: wait status not stable, even in suspend
1243                 */
1244                if (thread->status == THREAD_WAIT ||
1245                    thread->status == THREAD_TIMED_WAIT)
1246                {
1247                    Monitor* mon = thread->waitMonitor;
1248                    Object* obj = dvmGetMonitorObject(mon);
1249                    if (obj != NULL) {
1250                        Thread* joinThread = NULL;
1251                        if (obj->clazz == gDvm.classJavaLangVMThread) {
1252                            joinThread = dvmGetThreadFromThreadObject(obj);
1253                        }
1254                        printWaitMessage(target, "on", obj, joinThread);
1255                    }
1256                } else if (thread->status == THREAD_MONITOR) {
1257                    Object* obj;
1258                    Thread* owner;
1259                    if (extractMonitorEnterObject(thread, &obj, &owner)) {
1260                        printWaitMessage(target, "to lock", obj, owner);
1261                    }
1262                }
1263            }
1264        }
1265
1266        /*
1267         * Get saved PC for previous frame.  There's no savedPc in a "break"
1268         * frame, because that represents native or interpreted code
1269         * invoked by the VM.  The saved PC is sitting in the "PC register",
1270         * a local variable on the native stack.
1271         */
1272        currentPc = saveArea->savedPc;
1273
1274        first = false;
1275
1276        if (saveArea->prevFrame != NULL && saveArea->prevFrame <= framePtr) {
1277            LOGW("Warning: loop in stack trace at frame %d (%p -> %p)",
1278                checkCount, framePtr, saveArea->prevFrame);
1279            break;
1280        }
1281        framePtr = saveArea->prevFrame;
1282
1283        checkCount++;
1284        if (checkCount > 300) {
1285            dvmPrintDebugMessage(target,
1286                "  ***** printed %d frames, not showing any more\n",
1287                checkCount);
1288            break;
1289        }
1290    }
1291    dvmPrintDebugMessage(target, "\n");
1292
1293    if (needThreadUnlock) {
1294        dvmUnlockThreadList();
1295    }
1296}
1297
1298
1299/*
1300 * Dump the stack for the specified thread.
1301 */
1302void dvmDumpThreadStack(const DebugOutputTarget* target, Thread* thread)
1303{
1304    dumpFrames(target, thread->interpSave.curFrame, thread);
1305}
1306
1307/*
1308 * Dump the stack for the specified thread, which is still running.
1309 *
1310 * This is very dangerous, because stack frames are being pushed on and
1311 * popped off, and if the thread exits we'll be looking at freed memory.
1312 * The plan here is to take a snapshot of the stack and then dump that
1313 * to try to minimize the chances of catching it mid-update.  This should
1314 * work reasonably well on a single-CPU system.
1315 *
1316 * There is a small chance that calling here will crash the VM.
1317 */
1318void dvmDumpRunningThreadStack(const DebugOutputTarget* target, Thread* thread)
1319{
1320    StackSaveArea* saveArea;
1321    const u1* origStack;
1322    u1* stackCopy = NULL;
1323    int origSize, fpOffset;
1324    void* fp;
1325    int depthLimit = 200;
1326
1327    if (thread == NULL || thread->interpSave.curFrame == NULL) {
1328        dvmPrintDebugMessage(target,
1329            "DumpRunning: Thread at %p has no curFrame (threadid=%d)\n",
1330            thread, (thread != NULL) ? thread->threadId : 0);
1331        return;
1332    }
1333
1334    /* wait for a full quantum */
1335    sched_yield();
1336
1337    /* copy the info we need, then the stack itself */
1338    origSize = thread->interpStackSize;
1339    origStack = (const u1*) thread->interpStackStart - origSize;
1340    stackCopy = (u1*) malloc(origSize);
1341    fpOffset = (u1*) thread->interpSave.curFrame - origStack;
1342    memcpy(stackCopy, origStack, origSize);
1343
1344    /*
1345     * Run through the stack and rewrite the "prev" pointers.
1346     */
1347    //LOGI("DR: fpOff=%d (from %p %p)",fpOffset, origStack,
1348    //     thread->interpSave.curFrame);
1349    fp = stackCopy + fpOffset;
1350    while (true) {
1351        int prevOffset;
1352
1353        if (depthLimit-- < 0) {
1354            /* we're probably screwed */
1355            dvmPrintDebugMessage(target, "DumpRunning: depth limit hit\n");
1356            dvmAbort();
1357        }
1358        saveArea = SAVEAREA_FROM_FP(fp);
1359        if (saveArea->prevFrame == NULL)
1360            break;
1361
1362        prevOffset = (u1*) saveArea->prevFrame - origStack;
1363        if (prevOffset < 0 || prevOffset > origSize) {
1364            dvmPrintDebugMessage(target,
1365                "DumpRunning: bad offset found: %d (from %p %p)\n",
1366                prevOffset, origStack, saveArea->prevFrame);
1367            saveArea->prevFrame = NULL;
1368            break;
1369        }
1370
1371        saveArea->prevFrame = (u4*)(stackCopy + prevOffset);
1372        fp = saveArea->prevFrame;
1373    }
1374
1375    /*
1376     * We still need to pass the Thread for some monitor wait stuff.
1377     */
1378    dumpFrames(target, stackCopy + fpOffset, thread);
1379    free(stackCopy);
1380}
1381