From b54d653dce301da5ec1c6a8d43d457dc1598cc0e Mon Sep 17 00:00:00 2001 From: Pavel Afremov Date: Thu, 30 Aug 2007 20:11:00 +0400 Subject: [PATCH] First version of class unloading support in lazy stack creation. This version prevents class unloading if there is any stored exception. In Throwable class implementation array of java.lang.Class was added. This array contains classes of each method on the stack. --- .../javasrc/java/lang/Throwable.java | 50 ++++++++++++++------ .../javasrc/org/apache/harmony/vm/VMStack.java | 26 +++++++++- .../native/org_apache_harmony_vm_VMStack.cpp | 47 ++++++++++++++++++- .../native/org_apache_harmony_vm_VMStack.h | 7 +++ 4 files changed, 111 insertions(+), 19 deletions(-) diff --git a/vm/vmcore/src/kernel_classes/javasrc/java/lang/Throwable.java b/vm/vmcore/src/kernel_classes/javasrc/java/lang/Throwable.java index fd418c5..35a982c 100644 --- a/vm/vmcore/src/kernel_classes/javasrc/java/lang/Throwable.java +++ b/vm/vmcore/src/kernel_classes/javasrc/java/lang/Throwable.java @@ -41,8 +41,10 @@ public class Throwable implements Serializable { private final String detailMessage; private StackTraceElement[] stackTrace; - - private transient Object state; + + private transient Class [] stackClasses; + + private transient Object state; /** * @com.intel.drl.spec_ref @@ -80,6 +82,7 @@ public class Throwable implements Serializable { */ public Throwable fillInStackTrace() { state = VMStack.getStackState(); + stackClasses = VMStack.getStackClasses(state); return this; } @@ -107,14 +110,9 @@ public class Throwable implements Serializable { /** * @com.intel.drl.spec_ref */ - public StackTraceElement[] getStackTrace() { - if (stackTrace == null) { - stackTrace = VMStack.getStackTrace(state); - } - StackTraceElement[] st = new StackTraceElement[stackTrace.length]; - System.arraycopy(stackTrace, 0, st, 0, stackTrace.length); - return st; - } + public StackTraceElement[] getStackTrace() { + return getStackTrace(true); + } /** * @com.intel.drl.spec_ref @@ -149,15 +147,37 @@ public class Throwable implements Serializable { /** * @com.intel.drl.spec_ref */ - public void printStackTrace(PrintWriter pw) { + public void printStackTrace(PrintWriter pw) { pw.println(makeThrowableString()); - } + } + + private void initStackTrace() { + if (stackTrace == null) { + stackTrace = VMStack.getStackTrace(state); + state = null; + stackClasses = null; + } + } + + private StackTraceElement[] getStackTrace(boolean copyArray) + { + StackTraceElement[] st; + initStackTrace(); + + if (copyArray) { + st = new StackTraceElement[stackTrace.length]; + System.arraycopy(stackTrace, 0, st, 0, stackTrace.length); + } else { + st = stackTrace; + } + return st; + } private String makeThrowableString() { StringBuffer sb = new StringBuffer(); sb.append(toString()); if (stackTrace == null) { - stackTrace = VMStack.getStackTrace(state); + initStackTrace(); } // FIXME stackTrace should never be null here if (stackTrace != null) { @@ -173,7 +193,7 @@ public class Throwable implements Serializable { StackTraceElement[] parentStackTrace = wCause.stackTrace; wCause = wCause.getCause(); if (wCause.stackTrace == null) { - wCause.stackTrace = VMStack.getStackTrace(wCause.state); + wCause.initStackTrace(); } sb.append("\nCaused by: ").append(wCause.toString()); // FIXME wCause.stackTrace should never be null here @@ -242,7 +262,7 @@ public class Throwable implements Serializable { private void writeObject(ObjectOutputStream s) throws IOException { if (stackTrace == null) { - stackTrace = VMStack.getStackTrace(state); + initStackTrace(); } s.defaultWriteObject(); } diff --git a/vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/vm/VMStack.java b/vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/vm/VMStack.java index 141f220..ce95066 100644 --- a/vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/vm/VMStack.java +++ b/vm/vmcore/src/kernel_classes/javasrc/org/apache/harmony/vm/VMStack.java @@ -78,7 +78,7 @@ public final class VMStack { * @api2vm */ public static native Class[] getClasses(int maxSize, boolean considerPrivileged); - + /** * Saves stack information of currently executing thread. Returned object * can be used as a handler to obtain an array of @@ -88,7 +88,27 @@ public final class VMStack { * @return handler of the current stack. */ public static native Object getStackState(); - + + /** + * Collects and returns the classes of invoked methods as an array of the + * {@link Class} objects. This method may be used by + * java.lang.Throwable class implementation. + *

+ * Resulting stack should contain native stack frames as well as reflection + * stack frames. + *

+ * Note, that it returns classes for all stack, without any checks. + * It's fast, simple version of {@link VMStack#getClasses() VMStack.getClasses()} + * method, and used from Throwable class implementation. + * + * @param state handler returned by the + * {@link VMStack#getStackState() VMStack.getStackState()} method. + * @return array of Class elements. If stack is + * empty then null should be returned. + * @api2vm + */ + public static native Class[] getStackClasses(Object state); + /** * Collects and returns the stack of invoked methods as an array of the * {@link StackTraceElement} objects. This method may be used by @@ -108,6 +128,6 @@ public final class VMStack { * @api2vm */ public static native StackTraceElement[] getStackTrace(Object state); - + public static native StackTraceElement[] getThreadStackTrace(Thread t); } diff --git a/vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.cpp b/vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.cpp index ec9b756..b64077f 100644 --- a/vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.cpp +++ b/vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.cpp @@ -241,7 +241,6 @@ Java_java_security_AccessController_getStackDomains(JNIEnv *jenv, jclass UNREF) return arr; } - /* * Class: org_apache_harmony_vm_VMStack * Method: getStackState @@ -277,6 +276,52 @@ JNIEXPORT jobject JNICALL Java_org_apache_harmony_vm_VMStack_getStackState /* * Class: org_apache_harmony_vm_VMStack + * Method: getStackClasses + * Signature: (Ljava/lang/Object;)[Ljava/lang/Class; + */ +JNIEXPORT jobjectArray JNICALL Java_org_apache_harmony_vm_VMStack_getStackClasses + (JNIEnv *jenv, jclass, jobject state) +{ + ASSERT_RAISE_AREA; + if (NULL == state) + return NULL; + + Global_Env* genv = jni_get_vm_env(jenv); + + // state object contains raw data as long array + jlongArray array = (jlongArray)state; + assert(array); + + // copy data to array + jlong* array_data = jenv->GetLongArrayElements(array, NULL); + + // get depth of the stack + StackTraceFrame* frames = (StackTraceFrame*) array_data; + unsigned size = jenv->GetArrayLength(array) * 8 / sizeof(StackTraceFrame); + + // get class array class + jclass cac = struct_Class_to_java_lang_Class_Handle(genv->JavaLangClass_Class); + assert(cac); + + // create java array + jobjectArray arr = jenv->NewObjectArray(size, cac, NULL); + if (arr == NULL) { + return NULL; + } + + // find and store classes of the methods on the stack + for (unsigned i=0; i < size; i++) { + Method* m = frames[i].method; + Class* c = m->get_class(); + jclass jc = struct_Class_to_java_lang_Class_Handle(c); + jenv->SetObjectArrayElement(arr, i, jc); + } + + return arr; +} + +/* + * Class: org_apache_harmony_vm_VMStack * Method: getStackTrace * Signature: (Ljava/lang/Object;)[Ljava/lang/StackTraceElement; */ diff --git a/vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.h b/vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.h index 643c700..8018a31 100644 --- a/vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.h +++ b/vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.h @@ -62,6 +62,13 @@ JNIEXPORT jobject JNICALL Java_org_apache_harmony_vm_VMStack_getStackState(JNIEnv *, jclass); /* + * Method: org.apache.harmony.vm.VMStack.getStackClasse(Ljava/lang/Object;)[Ljava/lang/Class + */ +JNIEXPORT jobjectArray JNICALL +Java_org_apache_harmony_vm_VMStack_getStackClasses(JNIEnv *, jclass, + jobject); + +/* * Method: org.apache.harmony.vm.VMStack.getStackTrace(Ljava/lang/Object;)[Ljava/lang/StackTraceElement; */ JNIEXPORT jobjectArray JNICALL -- 1.5.0.3