Stack.cpp revision 6f3c21fb026d9489e5046416bcd5a84fa8e4615b
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 && dvmIsValidObject(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 || dvmIsValidObject(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,
637    DataObject* arg)
638{
639    char* expectedClassName = dvmHumanReadableDescriptor(expected->descriptor);
640    char* actualClassName = (arg != NULL)
641        ? dvmHumanReadableDescriptor(arg->clazz->descriptor)
642        : strdup("null");
643    dvmThrowExceptionFmt(gDvm.exIllegalArgumentException,
644        "argument %d should have type %s, got %s",
645        argIndex + 1, expectedClassName, actualClassName);
646    free(expectedClassName);
647    free(actualClassName);
648}
649
650/*
651 * Invoke a method, using the specified arguments and return type, through
652 * one of the reflection interfaces.  Could be a virtual or direct method
653 * (including constructors).  Used for reflection.
654 *
655 * Deals with boxing/unboxing primitives and performs widening conversions.
656 *
657 * "invokeObj" will be null for a static method.
658 *
659 * If the invocation returns with an exception raised, we have to wrap it.
660 */
661Object* dvmInvokeMethod(Object* obj, const Method* method,
662    ArrayObject* argList, ArrayObject* params, ClassObject* returnType,
663    bool noAccessCheck)
664{
665    ClassObject* clazz;
666    Object* retObj = NULL;
667    Thread* self = dvmThreadSelf();
668    s4* ins;
669    int verifyCount, argListLength;
670    JValue retval;
671    bool needPop = false;
672
673    /* verify arg count */
674    if (argList != NULL)
675        argListLength = argList->length;
676    else
677        argListLength = 0;
678    if (argListLength != (int) params->length) {
679        dvmThrowExceptionFmt(gDvm.exIllegalArgumentException,
680            "wrong number of arguments; expected %d, got %d",
681            params->length, argListLength);
682        return NULL;
683    }
684
685    clazz = callPrep(self, method, obj, !noAccessCheck);
686    if (clazz == NULL)
687        return NULL;
688    needPop = true;
689
690    /* "ins" for new frame start at frame pointer plus locals */
691    ins = ((s4*)self->interpSave.curFrame) +
692        (method->registersSize - method->insSize);
693    verifyCount = 0;
694
695    //LOGD("  FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);
696
697    /* put "this" pointer into in0 if appropriate */
698    if (!dvmIsStaticMethod(method)) {
699        assert(obj != NULL);
700        *ins++ = (s4) obj;
701        verifyCount++;
702    }
703
704    /*
705     * Copy the args onto the stack.  Primitive types are converted when
706     * necessary, and object types are verified.
707     */
708    DataObject** args = (DataObject**)(void*)argList->contents;
709    ClassObject** types = (ClassObject**)(void*)params->contents;
710    for (int i = 0; i < argListLength; i++) {
711        int width = dvmConvertArgument(*args++, *types++, ins);
712        if (width < 0) {
713            dvmPopFrame(self);      // throw wants to pull PC out of stack
714            needPop = false;
715            throwArgumentTypeMismatch(i, *(types-1), *(args-1));
716            goto bail;
717        }
718
719        ins += width;
720        verifyCount += width;
721    }
722
723#ifndef NDEBUG
724    if (verifyCount != method->insSize) {
725        LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
726            method->insSize, clazz->descriptor, method->name);
727        assert(false);
728        goto bail;
729    }
730#endif
731
732    if (dvmIsNativeMethod(method)) {
733        TRACE_METHOD_ENTER(self, method);
734        /*
735         * Because we leave no space for local variables, "curFrame" points
736         * directly at the method arguments.
737         */
738        (*method->nativeFunc)((u4*)self->interpSave.curFrame, &retval,
739                              method, self);
740        TRACE_METHOD_EXIT(self, method);
741    } else {
742        dvmInterpret(self, method, &retval);
743    }
744
745    /*
746     * Pop the frame immediately.  The "wrap" calls below can cause
747     * allocations, and we don't want the GC to walk the now-dead frame.
748     */
749    dvmPopFrame(self);
750    needPop = false;
751
752    /*
753     * If an exception is raised, wrap and replace.  This is necessary
754     * because the invoked method could have thrown a checked exception
755     * that the caller wasn't prepared for.
756     *
757     * We might be able to do this up in the interpreted code, but that will
758     * leave us with a shortened stack trace in the top-level exception.
759     */
760    if (dvmCheckException(self)) {
761        dvmWrapException("Ljava/lang/reflect/InvocationTargetException;");
762    } else {
763        /*
764         * If this isn't a void method or constructor, convert the return type
765         * to an appropriate object.
766         *
767         * We don't do this when an exception is raised because the value
768         * in "retval" is undefined.
769         */
770        if (returnType != NULL) {
771            retObj = (Object*)dvmBoxPrimitive(retval, returnType);
772            dvmReleaseTrackedAlloc(retObj, NULL);
773        }
774    }
775
776bail:
777    if (needPop) {
778        dvmPopFrame(self);
779    }
780    return retObj;
781}
782
783struct LineNumFromPcContext {
784    u4 address;
785    u4 lineNum;
786};
787
788static int lineNumForPcCb(void *cnxt, u4 address, u4 lineNum)
789{
790    LineNumFromPcContext *pContext = (LineNumFromPcContext *)cnxt;
791
792    // We know that this callback will be called in
793    // ascending address order, so keep going until we find
794    // a match or we've just gone past it.
795
796    if (address > pContext->address) {
797        // The line number from the previous positions callback
798        // wil be the final result.
799        return 1;
800    }
801
802    pContext->lineNum = lineNum;
803
804    return (address == pContext->address) ? 1 : 0;
805}
806
807/*
808 * Determine the source file line number based on the program counter.
809 * "pc" is an offset, in 16-bit units, from the start of the method's code.
810 *
811 * Returns -1 if no match was found (possibly because the source files were
812 * compiled without "-g", so no line number information is present).
813 * Returns -2 for native methods (as expected in exception traces).
814 */
815int dvmLineNumFromPC(const Method* method, u4 relPc)
816{
817    const DexCode* pDexCode = dvmGetMethodCode(method);
818
819    if (pDexCode == NULL) {
820        if (dvmIsNativeMethod(method) && !dvmIsAbstractMethod(method))
821            return -2;
822        return -1;      /* can happen for abstract method stub */
823    }
824
825    LineNumFromPcContext context;
826    memset(&context, 0, sizeof(context));
827    context.address = relPc;
828    // A method with no line number info should return -1
829    context.lineNum = -1;
830
831    dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile, pDexCode,
832            method->clazz->descriptor,
833            method->prototype.protoIdx,
834            method->accessFlags,
835            lineNumForPcCb, NULL, &context);
836
837    return context.lineNum;
838}
839
840/*
841 * Compute the frame depth.
842 *
843 * Excludes "break" frames.
844 */
845int dvmComputeExactFrameDepth(const void* fp)
846{
847    int count = 0;
848
849    for ( ; fp != NULL; fp = SAVEAREA_FROM_FP(fp)->prevFrame) {
850        if (!dvmIsBreakFrame((u4*)fp))
851            count++;
852    }
853
854    return count;
855}
856
857/*
858 * Compute the "vague" frame depth, which is just a pointer subtraction.
859 * The result is NOT an overly generous assessment of the number of
860 * frames; the only meaningful use is to compare against the result of
861 * an earlier invocation.
862 *
863 * Useful for implementing single-step debugger modes, which may need to
864 * call this for every instruction.
865 */
866int dvmComputeVagueFrameDepth(Thread* thread, const void* fp)
867{
868    const u1* interpStackStart = thread->interpStackStart;
869
870    assert((u1*) fp >= interpStackStart - thread->interpStackSize);
871    assert((u1*) fp < interpStackStart);
872    return interpStackStart - (u1*) fp;
873}
874
875/*
876 * Get the calling frame.  Pass in the current fp.
877 *
878 * Skip "break" frames and reflection invoke frames.
879 */
880void* dvmGetCallerFP(const void* curFrame)
881{
882    void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
883    StackSaveArea* saveArea;
884
885retry:
886    if (dvmIsBreakFrame((u4*)caller)) {
887        /* pop up one more */
888        caller = SAVEAREA_FROM_FP(caller)->prevFrame;
889        if (caller == NULL)
890            return NULL;        /* hit the top */
891
892        /*
893         * If we got here by java.lang.reflect.Method.invoke(), we don't
894         * want to return Method's class loader.  Shift up one and try
895         * again.
896         */
897        saveArea = SAVEAREA_FROM_FP(caller);
898        if (dvmIsReflectionMethod(saveArea->method)) {
899            caller = saveArea->prevFrame;
900            assert(caller != NULL);
901            goto retry;
902        }
903    }
904
905    return caller;
906}
907
908/*
909 * Get the caller's class.  Pass in the current fp.
910 *
911 * This is used by e.g. java.lang.Class.
912 */
913ClassObject* dvmGetCallerClass(const void* curFrame)
914{
915    void* caller;
916
917    caller = dvmGetCallerFP(curFrame);
918    if (caller == NULL)
919        return NULL;
920
921    return SAVEAREA_FROM_FP(caller)->method->clazz;
922}
923
924/*
925 * Get the caller's caller's class.  Pass in the current fp.
926 *
927 * This is used by e.g. java.lang.Class, which wants to know about the
928 * class loader of the method that called it.
929 */
930ClassObject* dvmGetCaller2Class(const void* curFrame)
931{
932    void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
933    void* callerCaller;
934
935    /* at the top? */
936    if (dvmIsBreakFrame((u4*)caller) &&
937        SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
938        return NULL;
939
940    /* go one more */
941    callerCaller = dvmGetCallerFP(caller);
942    if (callerCaller == NULL)
943        return NULL;
944
945    return SAVEAREA_FROM_FP(callerCaller)->method->clazz;
946}
947
948/*
949 * Get the caller's caller's caller's class.  Pass in the current fp.
950 *
951 * This is used by e.g. java.lang.Class, which wants to know about the
952 * class loader of the method that called it.
953 */
954ClassObject* dvmGetCaller3Class(const void* curFrame)
955{
956    void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
957    int i;
958
959    /* at the top? */
960    if (dvmIsBreakFrame((u4*)caller) &&
961        SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
962        return NULL;
963
964    /* Walk up two frames if possible. */
965    for (i = 0; i < 2; i++) {
966        caller = dvmGetCallerFP(caller);
967        if (caller == NULL)
968            return NULL;
969    }
970
971    return SAVEAREA_FROM_FP(caller)->method->clazz;
972}
973
974/*
975 * Fill a flat array of methods that comprise the current interpreter
976 * stack trace.  Pass in the current frame ptr.  Break frames are
977 * skipped, but reflection invocations are not.
978 *
979 * The current frame will be in element 0.
980 */
981void dvmFillStackTraceArray(const void* fp, const Method** array, size_t length)
982{
983    assert(fp != NULL);
984    assert(array != NULL);
985    size_t i = 0;
986    while (fp != NULL) {
987        if (!dvmIsBreakFrame((u4*)fp)) {
988            assert(i < length);
989            array[i++] = SAVEAREA_FROM_FP(fp)->method;
990        }
991        fp = SAVEAREA_FROM_FP(fp)->prevFrame;
992    }
993}
994
995/*
996 * Open up the reserved area and throw an exception.  The reserved area
997 * should only be needed to create and initialize the exception itself.
998 *
999 * If we already opened it and we're continuing to overflow, abort the VM.
1000 *
1001 * We have to leave the "reserved" area open until the "catch" handler has
1002 * finished doing its processing.  This is because the catch handler may
1003 * need to resolve classes, which requires calling into the class loader if
1004 * the classes aren't already in the "initiating loader" list.
1005 */
1006void dvmHandleStackOverflow(Thread* self, const Method* method)
1007{
1008    /*
1009     * Can we make the reserved area available?
1010     */
1011    if (self->stackOverflowed) {
1012        /*
1013         * Already did, nothing to do but bail.
1014         */
1015        LOGE("DalvikVM: double-overflow of stack in threadid=%d; aborting",
1016            self->threadId);
1017        dvmDumpThread(self, false);
1018        dvmAbort();
1019    }
1020
1021    /* open it up to the full range */
1022    LOGI("threadid=%d: stack overflow on call to %s.%s:%s",
1023        self->threadId,
1024        method->clazz->descriptor, method->name, method->shorty);
1025    StackSaveArea* saveArea = SAVEAREA_FROM_FP(self->interpSave.curFrame);
1026    LOGI("  method requires %d+%d+%d=%d bytes, fp is %p (%d left)",
1027        method->registersSize * 4, sizeof(StackSaveArea), method->outsSize * 4,
1028        (method->registersSize + method->outsSize) * 4 + sizeof(StackSaveArea),
1029        saveArea, (u1*) saveArea - self->interpStackEnd);
1030    LOGI("  expanding stack end (%p to %p)", self->interpStackEnd,
1031        self->interpStackStart - self->interpStackSize);
1032    //dvmDumpThread(self, false);
1033    self->interpStackEnd = self->interpStackStart - self->interpStackSize;
1034    self->stackOverflowed = true;
1035
1036    /*
1037     * If we were trying to throw an exception when the stack overflowed,
1038     * we will blow up when doing the class lookup on StackOverflowError
1039     * because of the pending exception.  So, we clear it and make it
1040     * the cause of the SOE.
1041     */
1042    Object* excep = dvmGetException(self);
1043    if (excep != NULL) {
1044        LOGW("Stack overflow while throwing exception");
1045        dvmClearException(self);
1046    }
1047    dvmThrowChainedException(gDvm.exStackOverflowError, NULL, excep);
1048}
1049
1050/*
1051 * Reduce the available stack size.  By this point we should have finished
1052 * our overflow processing.
1053 */
1054void dvmCleanupStackOverflow(Thread* self, const Object* exception)
1055{
1056    const u1* newStackEnd;
1057
1058    assert(self->stackOverflowed);
1059
1060    if (exception->clazz != gDvm.exStackOverflowError) {
1061        /* exception caused during SOE, not the SOE itself */
1062        return;
1063    }
1064
1065    newStackEnd = (self->interpStackStart - self->interpStackSize)
1066        + STACK_OVERFLOW_RESERVE;
1067    if ((u1*)self->interpSave.curFrame <= newStackEnd) {
1068        LOGE("Can't shrink stack: curFrame is in reserved area (%p %p)",
1069            self->interpStackEnd, self->interpSave.curFrame);
1070        dvmDumpThread(self, false);
1071        dvmAbort();
1072    }
1073
1074    self->interpStackEnd = newStackEnd;
1075    self->stackOverflowed = false;
1076
1077    LOGI("Shrank stack (to %p, curFrame is %p)", self->interpStackEnd,
1078        self->interpSave.curFrame);
1079}
1080
1081
1082/*
1083 * Extract the object that is the target of a monitor-enter instruction
1084 * in the top stack frame of "thread".
1085 *
1086 * The other thread might be alive, so this has to work carefully.
1087 *
1088 * The thread list lock must be held.
1089 *
1090 * Returns "true" if we successfully recover the object.  "*pOwner" will
1091 * be NULL if we can't determine the owner for some reason (e.g. race
1092 * condition on ownership transfer).
1093 */
1094static bool extractMonitorEnterObject(Thread* thread, Object** pLockObj,
1095    Thread** pOwner)
1096{
1097    void* framePtr = thread->interpSave.curFrame;
1098
1099    if (framePtr == NULL || dvmIsBreakFrame((u4*)framePtr))
1100        return false;
1101
1102    const StackSaveArea* saveArea = SAVEAREA_FROM_FP(framePtr);
1103    const Method* method = saveArea->method;
1104    const u2* currentPc = saveArea->xtra.currentPc;
1105
1106    /* check Method* */
1107    if (!dvmLinearAllocContains(method, sizeof(Method))) {
1108        LOGD("ExtrMon: method %p not valid", method);
1109        return false;
1110    }
1111
1112    /* check currentPc */
1113    u4 insnsSize = dvmGetMethodInsnsSize(method);
1114    if (currentPc < method->insns ||
1115        currentPc >= method->insns + insnsSize)
1116    {
1117        LOGD("ExtrMon: insns %p not valid (%p - %p)",
1118            currentPc, method->insns, method->insns + insnsSize);
1119        return false;
1120    }
1121
1122    /* check the instruction */
1123    if ((*currentPc & 0xff) != OP_MONITOR_ENTER) {
1124        LOGD("ExtrMon: insn at %p is not monitor-enter (0x%02x)",
1125            currentPc, *currentPc & 0xff);
1126        return false;
1127    }
1128
1129    /* get and check the register index */
1130    unsigned int reg = *currentPc >> 8;
1131    if (reg >= method->registersSize) {
1132        LOGD("ExtrMon: invalid register %d (max %d)",
1133            reg, method->registersSize);
1134        return false;
1135    }
1136
1137    /* get and check the object in that register */
1138    u4* fp = (u4*) framePtr;
1139    Object* obj = (Object*) fp[reg];
1140    if (!dvmIsValidObject(obj)) {
1141        LOGD("ExtrMon: invalid object %p at %p[%d]", obj, fp, reg);
1142        return false;
1143    }
1144    *pLockObj = obj;
1145
1146    /*
1147     * Try to determine the object's lock holder; it's okay if this fails.
1148     *
1149     * We're assuming the thread list lock is already held by this thread.
1150     * If it's not, we may be living dangerously if we have to scan through
1151     * the thread list to find a match.  (The VM will generally be in a
1152     * suspended state when executing here, so this is a minor concern
1153     * unless we're dumping while threads are running, in which case there's
1154     * a good chance of stuff blowing up anyway.)
1155     */
1156    *pOwner = dvmGetObjectLockHolder(obj);
1157
1158    return true;
1159}
1160
1161/*
1162 * Dump stack frames, starting from the specified frame and moving down.
1163 *
1164 * Each frame holds a pointer to the currently executing method, and the
1165 * saved program counter from the caller ("previous" frame).  This means
1166 * we don't have the PC for the current method on the stack, which is
1167 * pretty reasonable since it's in the "PC register" for the VM.  Because
1168 * exceptions need to show the correct line number we actually *do* have
1169 * an updated version in the fame's "xtra.currentPc", but it's unreliable.
1170 *
1171 * Note "framePtr" could be NULL in rare circumstances.
1172 */
1173static void dumpFrames(const DebugOutputTarget* target, void* framePtr,
1174    Thread* thread)
1175{
1176    const StackSaveArea* saveArea;
1177    const Method* method;
1178    int checkCount = 0;
1179    const u2* currentPc = NULL;
1180    bool first = true;
1181
1182    /*
1183     * We call functions that require us to be holding the thread list lock.
1184     * It's probable that the caller has already done so, but it's not
1185     * guaranteed.  If it's not locked, lock it now.
1186     */
1187    bool needThreadUnlock = dvmTryLockThreadList();
1188
1189    /*
1190     * The "currentPc" is updated whenever we execute an instruction that
1191     * might throw an exception.  Show it here.
1192     */
1193    if (framePtr != NULL && !dvmIsBreakFrame((u4*)framePtr)) {
1194        saveArea = SAVEAREA_FROM_FP(framePtr);
1195
1196        if (saveArea->xtra.currentPc != NULL)
1197            currentPc = saveArea->xtra.currentPc;
1198    }
1199
1200    while (framePtr != NULL) {
1201        saveArea = SAVEAREA_FROM_FP(framePtr);
1202        method = saveArea->method;
1203
1204        if (dvmIsBreakFrame((u4*)framePtr)) {
1205            //dvmPrintDebugMessage(target, "  (break frame)\n");
1206        } else {
1207            int relPc;
1208
1209            if (currentPc != NULL)
1210                relPc = currentPc - saveArea->method->insns;
1211            else
1212                relPc = -1;
1213
1214            char* className =
1215                dvmHumanReadableDescriptor(method->clazz->descriptor);
1216            if (dvmIsNativeMethod(method))
1217                dvmPrintDebugMessage(target,
1218                    "  at %s.%s(Native Method)\n", className, method->name);
1219            else {
1220                dvmPrintDebugMessage(target,
1221                    "  at %s.%s(%s:%s%d)\n",
1222                    className, method->name, dvmGetMethodSourceFile(method),
1223                    (relPc >= 0 && first) ? "~" : "",
1224                    relPc < 0 ? -1 : dvmLineNumFromPC(method, relPc));
1225            }
1226            free(className);
1227
1228            if (first) {
1229                /*
1230                 * Decorate WAIT and MONITOR threads with some detail on
1231                 * the first frame.
1232                 *
1233                 * warning: wait status not stable, even in suspend
1234                 */
1235                if (thread->status == THREAD_WAIT ||
1236                    thread->status == THREAD_TIMED_WAIT)
1237                {
1238                    Monitor* mon = thread->waitMonitor;
1239                    Object* obj = dvmGetMonitorObject(mon);
1240                    if (obj != NULL) {
1241                        Thread* joinThread = NULL;
1242                        className =
1243                            dvmHumanReadableDescriptor(obj->clazz->descriptor);
1244                        if (strcmp(className, "java.lang.VMThread") == 0) {
1245                            joinThread = dvmGetThreadFromThreadObject(obj);
1246                        }
1247                        if (joinThread == NULL) {
1248                            dvmPrintDebugMessage(target,
1249                                "  - waiting on <%p> (a %s)\n", obj, className);
1250                        } else {
1251                            dvmPrintDebugMessage(target,
1252                                "  - waiting on <%p> (a %s) tid=%d\n",
1253                                obj, className, joinThread->threadId);
1254                        }
1255                        free(className);
1256                    }
1257                } else if (thread->status == THREAD_MONITOR) {
1258                    Object* obj;
1259                    Thread* owner;
1260                    if (extractMonitorEnterObject(thread, &obj, &owner)) {
1261                        className =
1262                            dvmHumanReadableDescriptor(obj->clazz->descriptor);
1263                        if (owner != NULL) {
1264                            char* threadName = dvmGetThreadName(owner);
1265                            dvmPrintDebugMessage(target,
1266                                "  - waiting to lock <%p> (a %s) held by threadid=%d (%s)\n",
1267                                obj, className, owner->threadId, threadName);
1268                            free(threadName);
1269                        } else {
1270                            dvmPrintDebugMessage(target,
1271                                "  - waiting to lock <%p> (a %s) held by ???\n",
1272                                obj, className);
1273                        }
1274                        free(className);
1275                    }
1276                }
1277            }
1278        }
1279
1280        /*
1281         * Get saved PC for previous frame.  There's no savedPc in a "break"
1282         * frame, because that represents native or interpreted code
1283         * invoked by the VM.  The saved PC is sitting in the "PC register",
1284         * a local variable on the native stack.
1285         */
1286        currentPc = saveArea->savedPc;
1287
1288        first = false;
1289
1290        if (saveArea->prevFrame != NULL && saveArea->prevFrame <= framePtr) {
1291            LOGW("Warning: loop in stack trace at frame %d (%p -> %p)",
1292                checkCount, framePtr, saveArea->prevFrame);
1293            break;
1294        }
1295        framePtr = saveArea->prevFrame;
1296
1297        checkCount++;
1298        if (checkCount > 300) {
1299            dvmPrintDebugMessage(target,
1300                "  ***** printed %d frames, not showing any more\n",
1301                checkCount);
1302            break;
1303        }
1304    }
1305    dvmPrintDebugMessage(target, "\n");
1306
1307    if (needThreadUnlock) {
1308        dvmUnlockThreadList();
1309    }
1310}
1311
1312
1313/*
1314 * Dump the stack for the specified thread.
1315 */
1316void dvmDumpThreadStack(const DebugOutputTarget* target, Thread* thread)
1317{
1318    dumpFrames(target, thread->interpSave.curFrame, thread);
1319}
1320
1321/*
1322 * Dump the stack for the specified thread, which is still running.
1323 *
1324 * This is very dangerous, because stack frames are being pushed on and
1325 * popped off, and if the thread exits we'll be looking at freed memory.
1326 * The plan here is to take a snapshot of the stack and then dump that
1327 * to try to minimize the chances of catching it mid-update.  This should
1328 * work reasonably well on a single-CPU system.
1329 *
1330 * There is a small chance that calling here will crash the VM.
1331 */
1332void dvmDumpRunningThreadStack(const DebugOutputTarget* target, Thread* thread)
1333{
1334    StackSaveArea* saveArea;
1335    const u1* origStack;
1336    u1* stackCopy = NULL;
1337    int origSize, fpOffset;
1338    void* fp;
1339    int depthLimit = 200;
1340
1341    if (thread == NULL || thread->interpSave.curFrame == NULL) {
1342        dvmPrintDebugMessage(target,
1343            "DumpRunning: Thread at %p has no curFrame (threadid=%d)\n",
1344            thread, (thread != NULL) ? thread->threadId : 0);
1345        return;
1346    }
1347
1348    /* wait for a full quantum */
1349    sched_yield();
1350
1351    /* copy the info we need, then the stack itself */
1352    origSize = thread->interpStackSize;
1353    origStack = (const u1*) thread->interpStackStart - origSize;
1354    stackCopy = (u1*) malloc(origSize);
1355    fpOffset = (u1*) thread->interpSave.curFrame - origStack;
1356    memcpy(stackCopy, origStack, origSize);
1357
1358    /*
1359     * Run through the stack and rewrite the "prev" pointers.
1360     */
1361    //LOGI("DR: fpOff=%d (from %p %p)",fpOffset, origStack,
1362    //     thread->interpSave.curFrame);
1363    fp = stackCopy + fpOffset;
1364    while (true) {
1365        int prevOffset;
1366
1367        if (depthLimit-- < 0) {
1368            /* we're probably screwed */
1369            dvmPrintDebugMessage(target, "DumpRunning: depth limit hit\n");
1370            dvmAbort();
1371        }
1372        saveArea = SAVEAREA_FROM_FP(fp);
1373        if (saveArea->prevFrame == NULL)
1374            break;
1375
1376        prevOffset = (u1*) saveArea->prevFrame - origStack;
1377        if (prevOffset < 0 || prevOffset > origSize) {
1378            dvmPrintDebugMessage(target,
1379                "DumpRunning: bad offset found: %d (from %p %p)\n",
1380                prevOffset, origStack, saveArea->prevFrame);
1381            saveArea->prevFrame = NULL;
1382            break;
1383        }
1384
1385        saveArea->prevFrame = (u4*)(stackCopy + prevOffset);
1386        fp = saveArea->prevFrame;
1387    }
1388
1389    /*
1390     * We still need to pass the Thread for some monitor wait stuff.
1391     */
1392    dumpFrames(target, stackCopy + fpOffset, thread);
1393    free(stackCopy);
1394}
1395