📄 frame.c
字号:
/* * Copyright (c) 1998-2002 Sun Microsystems, Inc. All Rights Reserved. * * This software is the confidential and proprietary information of Sun * Microsystems, Inc. ("Confidential Information"). You shall not * disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into * with Sun. * * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING * THIS SOFTWARE OR ITS DERIVATIVES. * * Use is subject to license terms. *//*========================================================================= * SYSTEM: KVM * SUBSYSTEM: Interpreter stack frames * FILE: frame.c * OVERVIEW: This file defines the internal operations for * manipulating stack frames & performing exception * handling. * AUTHOR: Antero Taivalsaari, Sun Labs, 1998 * Edited by Doug Simon 11/1998 (simplified exception handling) * Sheng Liang (chunky stacks), Frank Yellin *=======================================================================*//*========================================================================= * Include files *=======================================================================*/#include "global.h"/*========================================================================= * Global variables and definitions *=======================================================================*//* Shortcuts to the errors/exceptions that the VM may throw */const char NullPointerException[] = "java/lang/NullPointerException";const char IndexOutOfBoundsException[] = "java/lang/IndexOutOfBoundsException";const char ArrayIndexOutOfBoundsException[] = "java/lang/ArrayIndexOutOfBoundsException";const char ArrayStoreException[] = "java/lang/ArrayStoreException";const char ArithmeticException[] = "java/lang/ArithmeticException";const char ClassCastException[] = "java/lang/ClassCastException";const char NegativeArraySizeException[] = "java/lang/NegativeArraySizeException";const char JavaLangError_name[] /* JavaLangError is name of class */ = "java/lang/Error";/*========================================================================= * Static function prototypes (for functions used only in this file) *=======================================================================*/#if INCLUDEDEBUGCODEstatic void exceptionThrownTracing(INSTANCE_HANDLE exceptionH);static void exceptionCaughtTracing(THROWABLE_INSTANCE_HANDLE exceptionH, HANDLER handler);#else#define exceptionThrownTracing(exception)#define exceptionCaughtTracing(exception, handler)#endif /* INCLUDEDEBUGCODE *//*========================================================================= * Operations on stack frames *=======================================================================*//*========================================================================= * FUNCTION: pushFrame() * TYPE: constructor (kind of) * OVERVIEW: Creates a new execution stack frame for the currently * executing thread. The operation is used for invoking * methods upon message sending to objects. Allocates * new stack chunks as necessary ("chunky stacks"). * This allows the KVM to support a large number of * Java threads in a limited heap space. * INTERFACE: * parameters: method pointer * returns: TRUE if pushFrame succeeds; * FALSE on stack overflow (it will have raised the exception) * throws: OutOfMemoryError if the system runs out of memory * * COMMENTS: Note: this function operates in the context of * currently executing thread. All VM registers must * be initialized correctly before allocating frames. * * Remember that the zeroeth local variable '*lp' * must contain the 'this' (self) pointer * in virtual/special/interface method calls. * * Also remember that unlike most other Java VMs, * KVM does not create stack frames for native * function calls (see native.c and kni.h/c for * more information on native function calls) *=======================================================================*/bool_t pushFrame(METHOD thisMethod){ int thisFrameSize = thisMethod->frameSize; int thisArgCount = thisMethod->argCount; int thisLocalCount = thisFrameSize - thisArgCount; STACK stack = getFP() ? getFP()->stack : CurrentThread->stack; int thisMethodHeight = thisLocalCount + thisMethod->u.java.maxStack + SIZEOF_FRAME + RESERVEDFORNATIVE; FRAME newFrame; int i; cell* prev_sp = getSP() - thisArgCount; /* Very volatile! */ /* Check if there is enough space in the current stack chunk */ if (getSP() - stack->cells + thisMethodHeight >= stack->size) { /* Not enough space in the current stack chunk. */ /* We need to create a new one or reuse an existing one */ STACK newstack; thisMethodHeight += thisArgCount; /* Check if we can reuse an existing stack chunk */ if (stack->next && thisMethodHeight > stack->next->size) { stack->next = NULL; } /* If next is NULL, we need to create a new stack chunk */ if (stack->next == NULL) { int size = thisMethodHeight > STACKCHUNKSIZE ? thisMethodHeight : STACKCHUNKSIZE; int stacksize = sizeof(struct stackStruct) / CELL + (size - STACKCHUNKSIZE); START_TEMPORARY_ROOTS DECLARE_TEMPORARY_ROOT(STACK, stackX, stack); newstack = (STACK)mallocHeapObject(stacksize, GCT_EXECSTACK); stack = stackX; prev_sp = getSP() - thisArgCount; END_TEMPORARY_ROOTS if (newstack == NULL) { throwException(&StackOverflowObject); return FALSE; }#if INCLUDEDEBUGCODE /* In debug mode, initialize the new stack chunk to zeros */ memset(newstack, 0, stacksize << log2CELL);#endif newstack->next = NULL; newstack->size = size; stack->next = newstack;#if INCLUDEDEBUGCODE if (traceframes || tracestackchunks) { fprintf(stdout, "Created a new stack chunk (thread: %lx, new chunk: %lx, prev: %lx, stack depth: %ld)\n", (long)CurrentThread, (long)newstack, (long)stack, (long)frameDepth()); }#endif } else { /* Can reuse an existing, unused stack chunk */ newstack = stack->next; } /* The actual pushFrame operation for a new stack chunk happens here */ for (i = 0; i < thisArgCount; i++) { newstack->cells[i] = prev_sp[i + 1]; } setLP(newstack->cells); newFrame = (FRAME)(getLP() + thisFrameSize); newFrame->stack = newstack; } else { /* This is the more common case; pushing a frame without */ /* having to create or reuse another stack chunk */ ASSERTING_NO_ALLOCATION /* Set the local variable pointer to point to the start */ /* of the local variables in the execution stack */ setLP(prev_sp + 1); /* Add space for local variables, and */ /* initialize the new frame pointer */ newFrame = (FRAME)(getSP() + thisLocalCount + 1); newFrame->stack = stack; END_ASSERTING_NO_ALLOCATION }#if ENABLE_JAVA_DEBUGGER /* * Although the GC doesn't need to zero out the locations, the debugger * code needs to have unallocated objects zeroed out on the stack, else * it will try to dereference them when the debugger asks for the local * variables. */ if (vmDebugReady) memset(getLP() + thisArgCount, 0, thisLocalCount << log2CELL);#endif /* Fill out the remaining fields in the stack frame */ ASSERTING_NO_ALLOCATION /* Initialize info needed for popping the stack frame later on */ newFrame->previousSp = prev_sp; newFrame->previousIp = getIP(); newFrame->previousFp = getFP(); /* Initialize the frame to execute the given method */ newFrame->thisMethod = thisMethod; newFrame->syncObject = NIL; /* Initialized later if necessary */ /* Change virtual machine registers to execute the new method */ setFP(newFrame); setSP((cell*)(newFrame + 1) - 1); setIP(thisMethod->u.java.code); setCP(thisMethod->ofClass->constPool);#if INCLUDEDEBUGCODE if (tracemethodcalls || tracemethodcallsverbose) { frameTracing(thisMethod, "=>", 0); } if (traceframes) { fprintf(stdout, "Pushed a stack frame (thread: %lx, fp: %lx, sp: %lx, depth: %ld, stack: %lx)\n", (long)CurrentThread, (long)getFP(), (long)getSP(), (long)frameDepth(), (long)stack); }#endif /* INCLUDEDEBUGCODE */ END_ASSERTING_NO_ALLOCATION return TRUE;}/*========================================================================= * FUNCTION: popFrame() * TYPE: destructor (kind of) * OVERVIEW: Deletes an execution stack frame and resumes the * execution of the method that called the currently * executing method. * INTERFACE: * parameters: <none> * returns: Nothing directly, but field 'previousIp' holds * information about what to do after the frame has * been popped (whether to continue interpreter execution, * to kill the thread, or to return to C/C++ code). * Also, the field 'syncObject' holds a monitor object * to be released in case this was a synchronized method * call (see the RETURN bytecodes in Interpret.cpp) *=======================================================================*/void popFrame(){ /* Unallocate a stack frame and restore virtual */ /* machine registers to continue the execution */ /* of the previous method. */#if INCLUDEDEBUGCODE if (tracemethodcalls || tracemethodcallsverbose) { frameTracing(getFP()->thisMethod, "<=", 0); }#endif /* INCLUDEDEBUGCODE */ /* See frame.h */ POPFRAMEMACRO#if INCLUDEDEBUGCODE if (traceframes) { fprintf(stdout, "Popped a stack frame (thread: %lx, fp: %lx, sp: %lx, depth: %ld, stack: %lx)\n", (long)CurrentThread, (long)getFP(), (long)getSP(), (long)frameDepth(), (long)getFP()->stack); }#endif /* INCLUDEDEBUGCODE */#if ENABLE_JAVA_DEBUGGER if (vmDebugReady) setEvent_FramePop();#endif}/*========================================================================= * Exception handling operations *=======================================================================*//*========================================================================= * FUNCTION: findHandler() * TYPE: exception handler table lookup operation * OVERVIEW: Find a possible handler in the given exception handler * table that catches the given exception in given * code location. * INTERFACE: * parameters: handler table, exception object, instruction pointer offset * returns: handler or NIL if no matching handler is found *=======================================================================*/static HANDLERfindHandler(INSTANCE_CLASS thisClass, HANDLERTABLE handlerTable, THROWABLE_INSTANCE_HANDLE exceptionH, unsigned short ipOffset){ HANDLER result = NULL; ASSERTING_NO_ALLOCATION FOR_EACH_HANDLER(thisHandler, handlerTable) if (ipOffset < thisHandler->startPC) { continue; } else if (ipOffset >= thisHandler->endPC) { continue; } else { if (thisHandler->exception == 0) { result = thisHandler; break; } else { unsigned short thisException = (unsigned short)thisHandler->exception; CLASS handlerClass = resolveClassReference(thisClass->constPool, thisException, thisClass); if (isAssignableTo((CLASS)(unhand(exceptionH)->ofClass), (CLASS)handlerClass)) { /* Matching exception handler has been found */ result = thisHandler; break; } } } END_FOR_EACH_HANDLER END_ASSERTING_NO_ALLOCATION return result;}/*========================================================================= * FUNCTION: throwException() * TYPE: internal exception handling operation * OVERVIEW: Throw an exception (to be handled by a matching * stack frame exception handler. This operation may be * called both from bytecode (by primitive ATHROW) or * internally from the VM whenever an exceptional * situation occurs (e.g., an array range exception). * * Handle a runtime exception by inspecting exception * handlers in execution stack frames, and unwinding the * execution stack if necessary in order to try to find * a matching handler. If we find a matching handler * set the interpreter to execute its code. * INTERFACE: * parameters: pointer to an exception object * returns: <nothing> * NOTE: When invoking this operation from inside the VM, * keep in mind that the exception handler is not * executed until the VM returns back to the interpreter. * Thus, you should not put any C/C++ code after calls * to 'throwException' because that code would be called * "too early" (without having executed any of the * the exception handler bytecode. *=======================================================================*/void throwException(THROWABLE_INSTANCE_HANDLE exceptionH) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -