/* * This is used by the JNI PushLocalFrame call. We push a new frame onto * the stack that has no ins, outs, or locals, and no break frame above it. * It's strictly used for tracking JNI local refs, and will be popped off * by dvmPopFrame if it's not removed explicitly. */ bool dvmPushLocalFrame(Thread* self, const Method* method) { StackSaveArea* saveBlock; int stackReq; u1* stackPtr; assert(dvmIsNativeMethod(method)); stackReq = sizeof(StackSaveArea); // regular frame assert(self->curFrame != NULL); stackPtr = (u1*) SAVEAREA_FROM_FP(self->curFrame); if (stackPtr - stackReq < self->interpStackEnd) { /* not enough space; let JNI throw the exception */ LOGW("Stack overflow on PushLocal " "(req=%d top=%p cur=%p size=%d '%s')\n", stackReq, self->interpStackStart, self->curFrame, self->interpStackSize, method->name); dvmHandleStackOverflow(self, method); assert(dvmCheckException(self)); return false; } /* * Shift the stack pointer down, leaving space for just the stack save * area for the break frame, then shift down farther for the full frame. */ stackPtr -= sizeof(StackSaveArea); saveBlock = (StackSaveArea*) stackPtr; #if !defined(NDEBUG) && !defined(PAD_SAVE_AREA) /* debug -- memset the new stack */ memset(stackPtr, 0xaf, stackReq); #endif #ifdef EASY_GDB saveBlock->prevSave = FP_FROM_SAVEAREA(self->curFrame); #endif saveBlock->prevFrame = self->curFrame; saveBlock->savedPc = NULL; // not required #ifdef USE_INDIRECT_REF saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all; #else saveBlock->xtra.localRefCookie = self->jniLocalRefTable.nextEntry; #endif saveBlock->method = method; LOGVV("PUSH JNI local frame: old=%p new=%p (size=%d)\n", self->curFrame, FP_FROM_SAVEAREA(saveBlock), (u1*)self->curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock)); self->curFrame = FP_FROM_SAVEAREA(saveBlock); return true; }
/* * We're calling an interpreted method from an internal VM function or * via reflection. * * Push a frame for an interpreted method onto the stack. This is only * used when calling into interpreted code from native code. (The * interpreter does its own stack frame manipulation for interp-->interp * calls.) * * The size we need to reserve is the sum of parameters, local variables, * saved goodies, and outbound parameters. * * We start by inserting a "break" frame, which ensures that the interpreter * hands control back to us after the function we call returns or an * uncaught exception is thrown. */ static bool dvmPushInterpFrame(Thread* self, const Method* method) { StackSaveArea* saveBlock; StackSaveArea* breakSaveBlock; int stackReq; u1* stackPtr; assert(!dvmIsNativeMethod(method)); assert(!dvmIsAbstractMethod(method)); stackReq = method->registersSize * 4 // params + locals + sizeof(StackSaveArea) * 2 // break frame + regular frame + method->outsSize * 4; // args to other methods if (self->interpSave.curFrame != NULL) stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame); else stackPtr = self->interpStackStart; if (stackPtr - stackReq < self->interpStackEnd) { /* not enough space */ ALOGW("Stack overflow on call to interp " "(req=%d top=%p cur=%p size=%d %s.%s)", stackReq, self->interpStackStart, self->interpSave.curFrame, self->interpStackSize, method->clazz->descriptor, method->name); dvmHandleStackOverflow(self, method); assert(dvmCheckException(self)); return false; } /* * Shift the stack pointer down, leaving space for the function's * args/registers and save area. */ stackPtr -= sizeof(StackSaveArea); breakSaveBlock = (StackSaveArea*)stackPtr; stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea); saveBlock = (StackSaveArea*) stackPtr; #if !defined(NDEBUG) && !defined(PAD_SAVE_AREA) /* debug -- memset the new stack, unless we want valgrind's help */ memset(stackPtr - (method->outsSize*4), 0xaf, stackReq); #endif #ifdef EASY_GDB breakSaveBlock->prevSave = (StackSaveArea*)FP_FROM_SAVEAREA(self->interpSave.curFrame); saveBlock->prevSave = breakSaveBlock; #endif breakSaveBlock->prevFrame = self->interpSave.curFrame; breakSaveBlock->savedPc = NULL; // not required breakSaveBlock->xtra.localRefCookie = 0; // not required breakSaveBlock->method = NULL; saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock); saveBlock->savedPc = NULL; // not required saveBlock->xtra.currentPc = NULL; // not required? saveBlock->method = method; LOGVV("PUSH frame: old=%p new=%p (size=%d)", self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock), (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock)); self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock); return true; }
/* * We're calling a JNI native method from an internal VM fuction or * via reflection. This is also used to create the "fake" native-method * frames at the top of the interpreted stack. * * This actually pushes two frames; the first is a "break" frame. * * The top frame has additional space for JNI local reference tracking. */ bool dvmPushJNIFrame(Thread* self, const Method* method) { StackSaveArea* saveBlock; StackSaveArea* breakSaveBlock; int stackReq; u1* stackPtr; assert(dvmIsNativeMethod(method)); stackReq = method->registersSize * 4 // params only + sizeof(StackSaveArea) * 2; // break frame + regular frame if (self->interpSave.curFrame != NULL) stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame); else stackPtr = self->interpStackStart; if (stackPtr - stackReq < self->interpStackEnd) { /* not enough space */ ALOGW("Stack overflow on call to native " "(req=%d top=%p cur=%p size=%d '%s')", stackReq, self->interpStackStart, self->interpSave.curFrame, self->interpStackSize, method->name); dvmHandleStackOverflow(self, method); assert(dvmCheckException(self)); return false; } /* * Shift the stack pointer down, leaving space for just the stack save * area for the break frame, then shift down farther for the full frame. * We leave space for the method args, which are copied in later. */ stackPtr -= sizeof(StackSaveArea); breakSaveBlock = (StackSaveArea*)stackPtr; stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea); saveBlock = (StackSaveArea*) stackPtr; #if !defined(NDEBUG) && !defined(PAD_SAVE_AREA) /* debug -- memset the new stack */ memset(stackPtr, 0xaf, stackReq); #endif #ifdef EASY_GDB if (self->interpSave.curFrame == NULL) breakSaveBlock->prevSave = NULL; else { void* fp = FP_FROM_SAVEAREA(self->interpSave.curFrame); breakSaveBlock->prevSave = (StackSaveArea*)fp; } saveBlock->prevSave = breakSaveBlock; #endif breakSaveBlock->prevFrame = self->interpSave.curFrame; breakSaveBlock->savedPc = NULL; // not required breakSaveBlock->xtra.localRefCookie = 0; // not required breakSaveBlock->method = NULL; saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock); saveBlock->savedPc = NULL; // not required saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all; saveBlock->method = method; LOGVV("PUSH JNI frame: old=%p new=%p (size=%d)", self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock), (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock)); self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock); return true; }