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