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