📄 class.c
字号:
/* * Copyright (c) 1998-2001 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: Internal runtime structures * FILE: class.c * OVERVIEW: Internal runtime class structures (see Class.h). * AUTHOR: Antero Taivalsaari, Sun Labs * Edited by Doug Simon 11/1998 (added the string pool) * Added access checks by Sheng Liang for VM-spec compliance * Frank Yellin (more checks for JLS compliance) *=======================================================================*//*========================================================================= * Include files *=======================================================================*/#include "global.h"#include "stddef.h"/*========================================================================= * Global variables and definitions *=======================================================================*//* Pointers to the most important Java classes needed by the VM *//* If Romizing, these are defined and initialized in ROMjava.c */#if ROMIZING# define EXTERN_IF_ROMIZING extern#else# define EXTERN_IF_ROMIZING#endifEXTERN_IF_ROMIZINGINSTANCE_CLASS JavaLangObject; /* Pointer to class 'java.lang.Object' */EXTERN_IF_ROMIZINGINSTANCE_CLASS JavaLangClass; /* Pointer to class 'java.lang.Class' */EXTERN_IF_ROMIZINGINSTANCE_CLASS JavaLangSystem; /* Pointer to class 'java.lang.System' */EXTERN_IF_ROMIZINGINSTANCE_CLASS JavaLangString; /* Pointer to class 'java.lang.String' */EXTERN_IF_ROMIZINGINSTANCE_CLASS JavaLangThread; /* Pointer to class 'java.lang.Thread' */EXTERN_IF_ROMIZINGINSTANCE_CLASS JavaLangThrowable; /* Pointer to class 'java.lang.Throwable' */EXTERN_IF_ROMIZINGINSTANCE_CLASS JavaLangError; /* Pointer to class 'java.lang.Throwable' */EXTERN_IF_ROMIZING METHOD RunCustomCodeMethod;EXTERN_IF_ROMIZING NameTypeKey initNameAndType; /* void <init>() */EXTERN_IF_ROMIZING NameTypeKey clinitNameAndType; /* void <clinit>() */EXTERN_IF_ROMIZING NameTypeKey runNameAndType; /* void run() */EXTERN_IF_ROMIZING NameTypeKey mainNameAndType; /* void main(String[]) */EXTERN_IF_ROMIZING ARRAY_CLASS PrimitiveArrayClasses[T_LASTPRIMITIVETYPE + 1];INSTANCE_CLASS JavaLangOutOfMemoryError;THROWABLE_INSTANCE OutOfMemoryObject;THROWABLE_INSTANCE StackOverflowObject;/*========================================================================= * Static methods (only used in this file) *=======================================================================*/static void runClinit(FRAME_HANDLE);static void runClinitException(FRAME_HANDLE);/*========================================================================= * Constructors *=======================================================================*//*========================================================================= * FUNCTION: initializeClass() * TYPE: constructor * OVERVIEW: After loading a class, it must be initialized * by executing the possible internal static * constructor '<clinit>'. This will initialize the * necessary static structures. * * This function sets up the necessary Class.runClinit * frame and returns to the interpreter. * INTERFACE: * parameters: class pointer * returns: <nothing> *=======================================================================*/void initializeClass(INSTANCE_CLASS thisClass){ if (thisClass->status == CLASS_ERROR) { return; } else if (thisClass->status < CLASS_VERIFIED) { if (thisClass->superClass != NULL && thisClass->superClass->clazz.accessFlags == ACC_FINAL) { START_TEMPORARY_ROOTS DECLARE_TEMPORARY_ROOT(char *, thisClassName, getClassName((CLASS)thisClass)); DECLARE_TEMPORARY_ROOT(char *, superClassName, getClassName((CLASS)(thisClass->superClass))); sprintf(str_buffer, KVM_MSG_CLASS_EXTENDS_FINAL_CLASS_2STRPARAMS, thisClassName, superClassName); fatalError(str_buffer); END_TEMPORARY_ROOTS } if ( (thisClass->clazz.accessFlags & ACC_INTERFACE) && thisClass->superClass != JavaLangObject) { sprintf(str_buffer, KVM_MSG_INTERFACE_DOES_NOT_EXTEND_JAVALANGOBJECT_1STRPARAM, getClassName((CLASS)thisClass)); fatalError(str_buffer); } if (verifyClass(thisClass)) { sprintf(str_buffer, KVM_MSG_ERROR_VERIFYING_CLASS_1STRPARAM, getClassName((CLASS)thisClass)); fatalError(str_buffer); } } if (pushFrame(RunCustomCodeMethod)) { pushStackAsType(CustomCodeCallbackFunction, runClinit); pushStackAsType(INSTANCE_CLASS, thisClass); pushStackAsType(long, 1); } else { /* Stack overflow */ setClassStatus(thisClass, CLASS_ERROR); }}/*========================================================================= * FUNCTION: runClinit() * TYPE: private initialization of a class * OVERVIEW: Initialize a class. The Class.runCustomCode frame has * already been pushed. * * This function follows the exact steps as documented in * the Java virtual machine spec (2ed) 2.17.5, except that * Error is used instead of ExceptionInInitializerError * because the latter is not defined in CLDC. *=======================================================================*/static voidrunClinit(FRAME_HANDLE exceptionFrameH){ INSTANCE_CLASS thisClass; int state; bool_t haveMonitor = FALSE; if (exceptionFrameH) { runClinitException(exceptionFrameH); return; } state = topStackAsType(cell); thisClass = secondStackAsType(INSTANCE_CLASS); /* The 11 steps as documented in page 53 of the virtual machine spec. */ switch (state) { case 1: /* A short cut that'll probably happen 99% of the time. This class * has no monitor, and no one is in the middle of initializing this * class. Since our scheduler is non preemptive, we can just * mark the class, without worrying about the monitor or other threads. */ if (!OBJECT_HAS_MONITOR(&thisClass->clazz) && thisClass->initThread == NULL) { goto markClass; } /* Step 1: Grab the class monitor so we have exclusive access. */ if (monitorEnter((OBJECT)thisClass) != MonitorStatusOwn) { /* We've been forced to wait. When we're awoken, we'll have * the lock */ topStack = 2; return; } else { /* FALL THROUGH. We have the lock */ } case 2: haveMonitor = TRUE; if (thisClass->initThread && thisClass->initThread != CurrentThread) { /* Step 2: * Someone else is initializing this class. Just wait until * a notification. Of course, we'll have to recheck, since the * class could also be notified for other reasons. */ long64 timeout; ll_setZero(timeout); monitorWait((OBJECT)thisClass, timeout); topStack = 2; return; } markClass: if (thisClass->initThread == CurrentThread || thisClass->status == CLASS_READY) { /* step 4 */ /* Step 3, Step 4: * This thread is already initializing the class, or the class * has somehow already become initialized. We're done. */ if (haveMonitor) { char *junk; monitorExit((OBJECT)thisClass, &junk); } popFrame(); return; } if (thisClass->status == CLASS_ERROR) { /* Step 5: * What can we do? */ popFrame(); return; } /* Step 6: * Mark that we're about to initialize this class */ setClassInitialThread(thisClass, CurrentThread); if (haveMonitor) { char *junk; monitorExit((OBJECT)thisClass, &junk); haveMonitor = FALSE; } /* FALL THROUGH */ case 3: /* Step 7: * Initialize the superclass, if necessary */ if ((thisClass->clazz.accessFlags & ACC_INTERFACE) == 0) { INSTANCE_CLASS superClass = thisClass->superClass; if (superClass && superClass->status != CLASS_READY) { topStack = 4; initializeClass(superClass); return; } } /* FALL THROUGH */ case 4: { /* Step 8: * Run the <clinit> method, if the class has one */ METHOD thisMethod = getSpecialMethod(thisClass, clinitNameAndType); if (thisMethod) {#if INCLUDEDEBUGCODE if (traceclassloading || traceclassloadingverbose) { START_TEMPORARY_ROOTS fprintf(stdout, "Initializing class: '%s'\n", getClassName((CLASS)thisClass)); END_TEMPORARY_ROOTS }#endif /* INCLUDEDEBUGCODE */ topStack = 5; if (!pushFrame(thisMethod)) { /* Stack overflow while pushing the frame */ setClassStatus(thisClass, CLASS_ERROR); popFrame(); } return; } else { /* No <clinit> method. */ /* FALL THROUGH */ } } case 5: /* Step 9: * Grab the monitor so we can change the flags, and wake up any * other thread waiting on us. * * SHORTCUT: 99% of the time, there is no contention for the class. * Since our scheduler is non-preemptive, if there is no contention * for this class, we just go ahead and unmark the class, without * bothering with the monitor. */ if (!OBJECT_HAS_MONITOR(&thisClass->clazz)) { goto unmarkClass; } if (monitorEnter((OBJECT)thisClass) != MonitorStatusOwn) { /* When we wake up, we'll have the monitor */ topStack = 6; return; } else { /* FALL THROUGH */ } case 6: haveMonitor = TRUE; /* Step 9, cont. * Mark the class as initialized. Wake up anyone waiting for the * class to be initialized. Return the monitor. */ unmarkClass: setClassInitialThread(thisClass, NULL); setClassStatus(thisClass, CLASS_READY);#if ENABLE_JAVA_DEBUGGER if (vmDebugReady) { CEModPtr cep = GetCEModifier(); cep->loc.classID = GET_CLASS_DEBUGGERID(&thisClass->clazz); cep->threadID = getObjectID((OBJECT)CurrentThread->javaThread); cep->eventKind = JDWP_EventKind_CLASS_PREPARE; insertDebugEvent(cep); }#endif if (haveMonitor) { char *junk; monitorNotify((OBJECT)thisClass, TRUE); /* wakeup everyone */ monitorExit((OBJECT)thisClass, &junk); } popFrame(); return; /* Step 10, 11: * These handle error conditions that cannot currently be * implemented in the KVM. */ default: fatalVMError(KVM_MSG_STATIC_INITIALIZER_FAILED); }}static void runClinitException(FRAME_HANDLE frameH){ INSTANCE_CLASS thisClass; START_TEMPORARY_ROOTS void **bottomStack = (void **)(unhand(frameH) + 1); /* transient */ DECLARE_TEMPORARY_ROOT(THROWABLE_INSTANCE, exception, bottomStack[0]); thisClass = bottomStack[1]; setClassStatus(thisClass, CLASS_ERROR); setClassInitialThread(thisClass, NULL); /* Handle exception during clinit */ if (!isAssignableTo((CLASS)(exception->ofClass), (CLASS)JavaLangError)) { /* Replace exception with Error, then continue the throwing */ DECLARE_TEMPORARY_ROOT(THROWABLE_INSTANCE, error, (THROWABLE_INSTANCE)instantiate(JavaLangError)); DECLARE_TEMPORARY_ROOT(STRING_INSTANCE, messageString, exception->message); char *p = str_buffer; /* Create the new message: * Static initializer: <className of throwable> <message> */ strcpy(p, "Static initializer: "); p += strlen(p); getClassName_inBuffer(&exception->ofClass->clazz, p); p += strlen(p); if (messageString != NULL) { strcpy(p, ": "); p += strlen(p); getStringContentsSafely(messageString, p, STRINGBUFFERSIZE - (p - str_buffer)); p += strlen(p); } error->message = instantiateString(str_buffer, p - str_buffer); /* Replace the exception with our new Error, continue throwing */ *(THROWABLE_INSTANCE *)(unhand(frameH) + 1) = error; } END_TEMPORARY_ROOTS /* If any other thread is waiting for this, we should try to wake them * up if we can. */ if (OBJECT_HAS_REAL_MONITOR(&thisClass->clazz)) { MONITOR monitor = OBJECT_MHC_MONITOR(&thisClass->clazz); if (monitor->owner == NULL || monitor->owner == CurrentThread) { char *junk; monitorEnter((OBJECT)thisClass); monitorNotify((OBJECT)thisClass, TRUE); /* wakeup everyone */ monitorExit((OBJECT)thisClass, &junk); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -