--- old/hotspot/src/share/vm/classfile/javaClasses.cpp 2016-10-28 21:41:44.000000000 -0700 +++ new/hotspot/src/share/vm/classfile/javaClasses.cpp 2016-10-28 21:41:43.000000000 -0700 @@ -2175,6 +2175,14 @@ const char* str = holder->external_name(); oop classname = StringTable::intern((char*) str, CHECK); java_lang_StackTraceElement::set_declaringClass(element(), classname); + java_lang_StackTraceElement::set_declaringClassObject(element(), holder->java_mirror()); + + oop loader = holder->class_loader(); + if (loader != NULL) { + oop loader_name = java_lang_ClassLoader::name(loader); + if (loader_name != NULL) + java_lang_StackTraceElement::set_classLoaderName(element(), loader_name); + } // The method can be NULL if the requested class version is gone Symbol* sym = !method.is_null() ? method->name() : holder->constants()->symbol_at(cpref); @@ -3433,6 +3441,7 @@ bool java_lang_ClassLoader::offsets_computed = false; int java_lang_ClassLoader::_loader_data_offset = -1; int java_lang_ClassLoader::parallelCapable_offset = -1; +int java_lang_ClassLoader::name_offset = -1; int java_lang_ClassLoader::unnamedModule_offset = -1; ClassLoaderData** java_lang_ClassLoader::loader_data_addr(oop loader) { @@ -3453,6 +3462,9 @@ compute_optional_offset(parallelCapable_offset, k1, vmSymbols::parallelCapable_name(), vmSymbols::concurrenthashmap_signature()); + compute_offset(name_offset, + k1, vmSymbols::name_name(), vmSymbols::string_signature()); + compute_offset(unnamedModule_offset, k1, vmSymbols::unnamedModule_name(), vmSymbols::module_signature()); @@ -3464,6 +3476,11 @@ return loader->obj_field(parent_offset); } +oop java_lang_ClassLoader::name(oop loader) { + assert(is_instance(loader), "loader must be oop"); + return loader->obj_field(name_offset); +} + bool java_lang_ClassLoader::isAncestor(oop loader, oop cl) { assert(is_instance(loader), "loader must be oop"); assert(cl == NULL || is_instance(cl), "cl argument must be oop"); @@ -3619,12 +3636,14 @@ int java_lang_System::static_out_offset; int java_lang_System::static_err_offset; int java_lang_System::static_security_offset; -int java_lang_StackTraceElement::declaringClass_offset; int java_lang_StackTraceElement::methodName_offset; int java_lang_StackTraceElement::fileName_offset; int java_lang_StackTraceElement::lineNumber_offset; int java_lang_StackTraceElement::moduleName_offset; int java_lang_StackTraceElement::moduleVersion_offset; +int java_lang_StackTraceElement::classLoaderName_offset; +int java_lang_StackTraceElement::declaringClass_offset; +int java_lang_StackTraceElement::classOrLoaderModuleClassName_offset; int java_lang_StackFrameInfo::_declaringClass_offset; int java_lang_StackFrameInfo::_memberName_offset; int java_lang_StackFrameInfo::_bci_offset; @@ -3669,6 +3688,14 @@ element->obj_field_put(moduleVersion_offset, value); } +void java_lang_StackTraceElement::set_classLoaderName(oop element, oop value) { + element->obj_field_put(classLoaderName_offset, value); +} + +void java_lang_StackTraceElement::set_declaringClassObject(oop element, oop value) { + element->obj_field_put(classOrLoaderModuleClassName_offset, value); +} + // Support for java_lang_StackFrameInfo void java_lang_StackFrameInfo::set_declaringClass(oop element, oop value) { element->obj_field_put(_declaringClass_offset, value); @@ -3784,6 +3811,8 @@ java_lang_System::static_security_offset = java_lang_System::hc_static_security_offset * x; // java_lang_StackTraceElement + java_lang_StackTraceElement::classOrLoaderModuleClassName_offset= java_lang_StackTraceElement::hc_classOrLoaderModuleClassName_offset* x + header; + java_lang_StackTraceElement::classLoaderName_offset = java_lang_StackTraceElement::hc_classLoaderName_offset * x + header; java_lang_StackTraceElement::moduleName_offset = java_lang_StackTraceElement::hc_moduleName_offset * x + header; java_lang_StackTraceElement::moduleVersion_offset = java_lang_StackTraceElement::hc_moduleVersion_offset * x + header; java_lang_StackTraceElement::declaringClass_offset = java_lang_StackTraceElement::hc_declaringClass_offset * x + header; @@ -3985,10 +4014,14 @@ // java.lang.StackTraceElement - CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, declaringClass, "Ljava/lang/String;"); - CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, methodName, "Ljava/lang/String;"); - CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, fileName, "Ljava/lang/String;"); - CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, lineNumber, "I"); + CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, classOrLoaderModuleClassName, "Ljava/lang/Object;"); + CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, classLoaderName, "Ljava/lang/String;"); + CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, moduleName, "Ljava/lang/String;"); + CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, moduleVersion, "Ljava/lang/String;"); + CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, declaringClass, "Ljava/lang/String;"); + CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, methodName, "Ljava/lang/String;"); + CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, fileName, "Ljava/lang/String;"); + CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, lineNumber, "I"); // java.lang.ref.Reference --- old/hotspot/src/share/vm/classfile/javaClasses.hpp 2016-10-28 21:41:45.000000000 -0700 +++ new/hotspot/src/share/vm/classfile/javaClasses.hpp 2016-10-28 21:41:45.000000000 -0700 @@ -1225,6 +1225,7 @@ static bool offsets_computed; static int parent_offset; static int parallelCapable_offset; + static int name_offset; static int unnamedModule_offset; public: @@ -1234,6 +1235,7 @@ static ClassLoaderData* loader_data(oop loader); static oop parent(oop loader); + static oop name(oop loader); static bool isAncestor(oop loader, oop cl); // Support for parallelCapable field @@ -1291,14 +1293,18 @@ class java_lang_StackTraceElement: AllStatic { private: enum { - hc_moduleName_offset = 0, - hc_moduleVersion_offset = 1, - hc_declaringClass_offset = 2, - hc_methodName_offset = 3, - hc_fileName_offset = 4, - hc_lineNumber_offset = 5 + hc_classOrLoaderModuleClassName_offset = 0, + hc_classLoaderName_offset = 1, + hc_moduleName_offset = 2, + hc_moduleVersion_offset = 3, + hc_declaringClass_offset = 4, + hc_methodName_offset = 5, + hc_fileName_offset = 6, + hc_lineNumber_offset = 7 }; + static int classOrLoaderModuleClassName_offset; + static int classLoaderName_offset; static int moduleName_offset; static int moduleVersion_offset; static int declaringClass_offset; @@ -1307,12 +1313,14 @@ static int lineNumber_offset; // Setters + static void set_classLoaderName(oop element, oop value); static void set_moduleName(oop element, oop value); static void set_moduleVersion(oop element, oop value); static void set_declaringClass(oop element, oop value); static void set_methodName(oop element, oop value); static void set_fileName(oop element, oop value); static void set_lineNumber(oop element, int value); + static void set_declaringClassObject(oop element, oop value); public: // Create an instance of StackTraceElement --- old/jdk/make/mapfiles/libjava/mapfile-vers 2016-10-28 21:41:46.000000000 -0700 +++ new/jdk/make/mapfiles/libjava/mapfile-vers 2016-10-28 21:41:46.000000000 -0700 @@ -140,7 +140,6 @@ Java_java_lang_Double_doubleToRawLongBits; Java_java_lang_Float_intBitsToFloat; Java_java_lang_Float_floatToRawIntBits; - Java_java_lang_StackFrameInfo_toStackTraceElement0; Java_java_lang_StackStreamFactory_checkStackWalkModes; Java_java_lang_StackStreamFactory_00024AbstractStackWalker_callStackWalk; Java_java_lang_StackStreamFactory_00024AbstractStackWalker_fetchStackFrames; @@ -215,6 +214,8 @@ Java_java_lang_SecurityManager_currentLoadedClass0; Java_java_lang_SecurityManager_getClassContext; Java_java_lang_Shutdown_halt0; + Java_java_lang_StackTraceElement_fillFromStackFrameInfo; + Java_java_lang_StackTraceElement_fillStackTraceFromThrowable; Java_java_lang_String_intern; Java_java_lang_StringCoding_err; Java_java_lang_StringUTF16_isBigEndian; @@ -227,7 +228,6 @@ Java_java_lang_System_setOut0; Java_java_lang_Thread_registerNatives; Java_java_lang_Throwable_fillInStackTrace; - Java_java_lang_Throwable_getStackTraceElements; Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2; Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2; Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2; --- old/jdk/make/mapfiles/libjava/reorder-sparc 2016-10-28 21:41:47.000000000 -0700 +++ new/jdk/make/mapfiles/libjava/reorder-sparc 2016-10-28 21:41:47.000000000 -0700 @@ -78,7 +78,7 @@ text: .text%JNU_GetEnv; text: .text%Java_java_io_UnixFileSystem_checkAccess; text: .text%Java_java_lang_reflect_Array_newArray; -text: .text%Java_java_lang_Throwable_getStackTraceElements; +text: .text%Java_java_lang_StackTraceElement_fillStackTraceFromThrowable; text: .text%throwFileNotFoundException; text: .text%JNU_NotifyAll; # Test LoadFrame --- old/jdk/make/mapfiles/libjava/reorder-sparcv9 2016-10-28 21:41:49.000000000 -0700 +++ new/jdk/make/mapfiles/libjava/reorder-sparcv9 2016-10-28 21:41:48.000000000 -0700 @@ -74,7 +74,7 @@ text: .text%JNU_GetEnv; text: .text%Java_java_io_UnixFileSystem_checkAccess; text: .text%Java_java_lang_reflect_Array_newArray; -text: .text%Java_java_lang_Throwable_getStackTraceElements; +text: .text%Java_java_lang_StackTraceElement_fillStackTraceFromThrowable; text: .text%throwFileNotFoundException: OUTPUTDIR/io_util.o; text: .text%JNU_NotifyAll; # Test LoadFrame --- old/jdk/make/mapfiles/libjava/reorder-x86 2016-10-28 21:41:50.000000000 -0700 +++ new/jdk/make/mapfiles/libjava/reorder-x86 2016-10-28 21:41:50.000000000 -0700 @@ -78,7 +78,7 @@ text: .text%Java_sun_reflect_NativeMethodAccessorImpl_invoke0; text: .text%Java_java_io_FileInputStream_available; text: .text%Java_java_lang_reflect_Array_newArray; -text: .text%Java_java_lang_Throwable_getStackTraceElements; +text: .text%Java_java_lang_StackTraceElement_fillStackTraceFromThrowable; text: .text%Java_java_lang_System_identityHashCode; text: .text%JNU_NotifyAll; # Test LoadFrame --- old/jdk/src/java.base/share/classes/java/lang/ClassLoader.java 2016-10-28 21:41:52.000000000 -0700 +++ new/jdk/src/java.base/share/classes/java/lang/ClassLoader.java 2016-10-28 21:41:51.000000000 -0700 @@ -222,6 +222,9 @@ // must be added *after* it. private final ClassLoader parent; + // class loader name + private final String name; + // the unnamed module for this ClassLoader private final Module unnamedModule; @@ -338,7 +341,8 @@ return null; } - private ClassLoader(Void unused, ClassLoader parent) { + private ClassLoader(Void unused, String name, ClassLoader parent) { + this.name = name; this.parent = parent; this.unnamedModule = SharedSecrets.getJavaLangReflectModuleAccess() @@ -356,6 +360,25 @@ } /** + * Creates a new class loader of the specified name and using the + * specified parent class loader for delegation. + * + * @param name class loader name; or {@code null} if not named + * @param parent the parent class loader + * + * @throws SecurityException + * If a security manager exists and its + * {@link SecurityManager#checkCreateClassLoader()} + * method doesn't allow creation of a new class loader. + * + * @since 9 + */ + protected ClassLoader(String name, ClassLoader parent) { + this(checkCreateClassLoader(), name, parent); + } + + + /** * Creates a new class loader using the specified parent class loader for * delegation. * @@ -375,9 +398,10 @@ * @since 1.2 */ protected ClassLoader(ClassLoader parent) { - this(checkCreateClassLoader(), parent); + this(checkCreateClassLoader(), null, parent); } + /** * Creates a new class loader using the ClassLoader returned by * the method {@link #getSystemClassLoader() @@ -394,9 +418,24 @@ * of a new class loader. */ protected ClassLoader() { - this(checkCreateClassLoader(), getSystemClassLoader()); + this(checkCreateClassLoader(), null, getSystemClassLoader()); + } + + + /** + * Returns the name of this class loader or {@code null} if + * this class loader is not named. + * + * @return name of this class loader; or {@code null} if + * this class loader is not named. + * + * @since 9 + */ + public String getName() { + return name; } + // -- Class -- /** --- old/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java 2016-10-28 21:41:53.000000000 -0700 +++ new/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java 2016-10-28 21:41:53.000000000 -0700 @@ -112,11 +112,6 @@ return toStackTraceElement().toString(); } - /** - * Fill in the fields of the given StackTraceElement - */ - private native void toStackTraceElement0(StackTraceElement ste); - @Override public StackTraceElement toStackTraceElement() { StackTraceElement s = ste; @@ -124,9 +119,7 @@ synchronized (this) { s = ste; if (s == null) { - s = new StackTraceElement(); - toStackTraceElement0(s); - ste = s; + ste = s = StackTraceElement.of(this); } } } --- old/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java 2016-10-28 21:41:54.000000000 -0700 +++ new/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java 2016-10-28 21:41:54.000000000 -0700 @@ -25,7 +25,18 @@ package java.lang; +import jdk.internal.loader.BuiltinClassLoader; +import jdk.internal.misc.SharedSecrets; +import jdk.internal.misc.VM; +import jdk.internal.module.ModuleHashes; + +import java.lang.module.ModuleDescriptor.Version; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.util.HashSet; import java.util.Objects; +import java.util.Optional; +import java.util.Set; /** * An element in a stack trace, as returned by {@link @@ -40,7 +51,15 @@ * @author Josh Bloch */ public final class StackTraceElement implements java.io.Serializable { - // Normally initialized by VM (public constructor added in 1.5) + // This field is set to the compacted String representation used + // by StackTraceElement::toString and stored in serial form. + // + // This field is of Object type. VM initially sets this field to + // the Class object of the declaring class to build the compacted string. + private Object classOrLoaderModuleClassName; + + // Normally initialized by VM + private String classLoaderName; private String moduleName; private String moduleVersion; private String declaringClass; @@ -72,19 +91,22 @@ */ public StackTraceElement(String declaringClass, String methodName, String fileName, int lineNumber) { - this(null, null, declaringClass, methodName, fileName, lineNumber); + this(null, null, null, declaringClass, methodName, fileName, lineNumber); } /** * Creates a stack trace element representing the specified execution * point. * + * @param classLoaderName the class loader name if the class loader of + * the class containing the execution point represented by + * the stack trace is named; otherwise {@code null} * @param moduleName the module name if the class containing the * execution point represented by the stack trace is in a named - * module; can be {@code null} + * module; otherwise {@code null} * @param moduleVersion the module version if the class containing the * execution point represented by the stack trace is in a named - * module that has a version; can be {@code null} + * module that has a version; otherwise {@code null} * @param declaringClass the fully qualified name of the class containing * the execution point represented by the stack trace element * @param methodName the name of the method containing the execution point @@ -101,22 +123,24 @@ * or {@code methodName} is {@code null} * @since 9 */ - public StackTraceElement(String moduleName, String moduleVersion, + public StackTraceElement(String classLoaderName, + String moduleName, String moduleVersion, String declaringClass, String methodName, String fileName, int lineNumber) { - this.moduleName = moduleName; - this.moduleVersion = moduleVersion; + this.classLoaderName = classLoaderName; + this.moduleName = moduleName; + this.moduleVersion = moduleVersion; this.declaringClass = Objects.requireNonNull(declaringClass, "Declaring class is null"); - this.methodName = Objects.requireNonNull(methodName, "Method name is null"); - this.fileName = fileName; - this.lineNumber = lineNumber; + this.methodName = Objects.requireNonNull(methodName, "Method name is null"); + this.fileName = fileName; + this.lineNumber = lineNumber; } - - /** - * Creates an empty stack frame element to be filled in by Throwable. + /* + * Private constructor for the factory methods to create StackTraceElement + * for Throwable and StackFrameInfo */ - StackTraceElement() { } + private StackTraceElement() {} /** * Returns the name of the source file containing the execution point @@ -178,6 +202,21 @@ } /** + * Returns the name of the class loader of the class containing the + * execution point represented by this stack trace element. + * + * @return the name of the class loader of the class containing the execution + * point represented by this stack trace element; {@code null} + * if the class loader is not named. + * + * @since 9 + * @see java.lang.ClassLoader#getName() + */ + public String getClassLoaderName() { + return classLoaderName; + } + + /** * Returns the fully qualified name of the class containing the * execution point represented by this stack trace element. * @@ -220,38 +259,82 @@ * examples may be regarded as typical: * - * If the execution point is not in a named module, {@code "my.module@9.0/"} - * will be omitted from the above. + * + *

The first example shows a stack trace element consisting of + * three elements, each separated by {@code "/"} followed with + * the source file name and the line number of the source line + * containing the execution point. + * + * The first element "{@code com.foo.loader}" is + * the name of the class loader. The second element "{@code foo@9.0}" + * is the module name and version. The third element is the method + * containing the execution point; "{@code com.foo.Main"}" is the + * fully-qualified class name and "{@code run}" is the name of the method. + * "{@code Main.java}" is the source file name and "{@code 101}" is + * the line number. + * + *

If a class is defined in an unnamed module + * then the second element is omitted as shown in + * "{@code com.foo.loader//com.foo.bar.App.run(App.java:12)}". + * + * If the class loader is a + * built-in class loader or is not named then the first element + * and its following {@code "/"} are omitted as shown in + * "{@code acme@2.1/org.acme.Lib.test(Lib.java:80)}". + * If the first element is omitted and the module is an unnamed module, + * the second element and its following {@code "/"} are also omitted + * as shown in "{@code MyClass.mash(MyClass.java:9)}". * * @see Throwable#printStackTrace() */ public String toString() { - String mid = ""; - if (moduleName != null) { - mid = moduleName; - if (moduleVersion != null) - mid += "@" + moduleVersion; - mid += "/"; + String s = buildLoaderModuleClassName(); + if (s == null) { + // all elements will be included + s = ""; + if (classLoaderName != null && !classLoaderName.isEmpty()) { + s += classLoaderName + "/"; + } + if (moduleName != null && !moduleName.isEmpty()) { + s += moduleName; + } + if (moduleVersion != null && !moduleVersion.isEmpty()) { + s += "@" + moduleVersion; + } + s += declaringClass; } - return getClassName() + "." + methodName + "(" + mid + + + return s + "." + methodName + "(" + (isNativeMethod() ? "Native Method)" : (fileName != null && lineNumber >= 0 ? fileName + ":" + lineNumber + ")" : @@ -264,12 +347,14 @@ * point as this instance. Two stack trace elements {@code a} and * {@code b} are equal if and only if: *

{@code
-     *     equals(a.getFileName(), b.getFileName()) &&
-     *     a.getLineNumber() == b.getLineNumber()) &&
+     *     equals(a.getClassLoaderName(), b.getClassLoaderName()) &&
      *     equals(a.getModuleName(), b.getModuleName()) &&
      *     equals(a.getModuleVersion(), b.getModuleVersion()) &&
      *     equals(a.getClassName(), b.getClassName()) &&
      *     equals(a.getMethodName(), b.getMethodName())
+     *     equals(a.getFileName(), b.getFileName()) &&
+     *     a.getLineNumber() == b.getLineNumber()
+     *
      * }
* where {@code equals} has the semantics of {@link * java.util.Objects#equals(Object, Object) Objects.equals}. @@ -285,9 +370,10 @@ if (!(obj instanceof StackTraceElement)) return false; StackTraceElement e = (StackTraceElement)obj; - return e.declaringClass.equals(declaringClass) && + return Objects.equals(classLoaderName, e.classLoaderName) && Objects.equals(moduleName, e.moduleName) && Objects.equals(moduleVersion, e.moduleVersion) && + e.declaringClass.equals(declaringClass) && e.lineNumber == lineNumber && Objects.equals(methodName, e.methodName) && Objects.equals(fileName, e.fileName); @@ -298,6 +384,7 @@ */ public int hashCode() { int result = 31*declaringClass.hashCode() + methodName.hashCode(); + result = 31*result + Objects.hashCode(classLoaderName); result = 31*result + Objects.hashCode(moduleName); result = 31*result + Objects.hashCode(moduleVersion); result = 31*result + Objects.hashCode(fileName); @@ -305,5 +392,144 @@ return result; } + + /** + * Build the compacted String representation to be returned by + * toString method from the declaring Class object. + */ + synchronized String buildLoaderModuleClassName() { + if (classOrLoaderModuleClassName == null) + return null; + + if (classOrLoaderModuleClassName instanceof Class) { + Class cls = (Class)classOrLoaderModuleClassName; + classOrLoaderModuleClassName = toLoaderModuleClassName(cls); + } + return (String)classOrLoaderModuleClassName; + } + + /** + * Returns // string + * representation of the given class. + *

+ * If the module is a non-upgradeable JDK module then omit + * its version string. + *

+ * If the loader has no name, or if the loader is one of the built-in + * loaders (`boot`, `platform`, or `app`) then drop the first element + * (`/`). + *

+ * If the first element has been dropped and the module is unnamed + * then drop the second element (`/`). + *

+ * If the first element is not dropped and the module is unnamed + * then drop ``. + */ + private static String toLoaderModuleClassName(Class cls) { + ClassLoader loader = cls.getClassLoader0(); + Module m = cls.getModule(); + + // First element - class loader name + String s = ""; + if (loader != null && loader.getName() != null && + !(loader instanceof BuiltinClassLoader)) { + s = loader.getName() + "/"; + } + + // Second element - module name and version + if (m != null && m.isNamed()) { + s += m.getName(); + // Include version if it is a user module or upgradeable module + // + // If it is JDK non-upgradeable module which is recorded + // in the hashes in java.base, omit the version. + if (VM.isModuleSystemInited() && !HashedModules.contains(m)) { + Optional ov = m.getDescriptor().version(); + if (ov.isPresent()) { + String version = "@" + ov.get().toString(); + s += version; + } + } + } + + // fully-qualified class name + return s.isEmpty() ? cls.getName() : s + "/" + cls.getName(); + } + + /* + * Finds JDK non-upgradeable modules, i.e. the modules that are + * included in the hashes in java.base. + */ + private static class HashedModules { + static final Set HASHED_MODULES = getHashedModuleNames(); + + static Set getHashedModuleNames() { + Module javaBase = Layer.boot().findModule("java.base").get(); + Optional ohashes = SharedSecrets.getJavaLangModuleAccess() + .hashes(javaBase.getDescriptor()); + + if (ohashes.isPresent()) { + Set names = new HashSet<>(ohashes.get().names()); + names.add("java.base"); + return names; + } + + return Set.of(); + } + + /** + * Returns true if the module is in the boot layer and + * is tied to java.base. + * + * This method returns false when running on the exploded image + * since JDK modules are not hashed. They have no Version attribute + * and so "@" part will be omitted anyway. + */ + static boolean contains(Module m) { + return m.getLayer() == Layer.boot() && + HASHED_MODULES.contains(m.getName()); + } + } + + /* + * Returns a StackTraceElement from a given StackFrameInfo. + */ + static StackTraceElement of(StackFrameInfo sfi) { + StackTraceElement ste = new StackTraceElement(); + ste.fillFromStackFrameInfo(sfi); + ste.buildLoaderModuleClassName(); + return ste; + } + + /* + * Returns an array of StackTraceElements of the given depth + * filled from the backtrace of a given Throwable. + */ + static StackTraceElement[] of(Throwable x, int depth) { + StackTraceElement[] stackTrace = new StackTraceElement[depth]; + for (int i = 0; i < depth; i++) { + stackTrace[i] = new StackTraceElement(); + } + + // VM to fill in StackTraceElement + fillStackTraceFromThrowable(stackTrace, x); + + // ensure the proper StackTraceElement initialization + for (StackTraceElement ste : stackTrace) { + ste.buildLoaderModuleClassName(); + } + return stackTrace; + } + + /* + * Fill in the stack trace elements from a given Throwable. + */ + private static native void fillStackTraceFromThrowable(StackTraceElement[] elements, + Throwable x); + /* + * Fill in the stack trace elements from a given StackFrameInfo. + */ + private native void fillFromStackFrameInfo(StackFrameInfo sfi); + private static final long serialVersionUID = 6992337162326171013L; } --- old/jdk/src/java.base/share/classes/java/lang/Throwable.java 2016-10-28 21:41:56.000000000 -0700 +++ new/jdk/src/java.base/share/classes/java/lang/Throwable.java 2016-10-28 21:41:56.000000000 -0700 @@ -24,7 +24,6 @@ */ package java.lang; -import jdk.internal.misc.VM; import java.io.*; import java.util.*; @@ -826,11 +825,7 @@ // backtrace if this is the first call to this method if (stackTrace == UNASSIGNED_STACK || (stackTrace == null && backtrace != null) /* Out of protocol state */) { - stackTrace = new StackTraceElement[depth]; - for (int i = 0; i < depth; i++) { - stackTrace[i] = new StackTraceElement(); - } - getStackTraceElements(stackTrace); + stackTrace = StackTraceElement.of(this, depth); } else if (stackTrace == null) { return UNASSIGNED_STACK; } @@ -882,13 +877,6 @@ } /** - * Gets the stack trace elements. - * @param elements - * @throws IndexOutOfBoundsException if {@code elements.length != depth } - */ - private native void getStackTraceElements(StackTraceElement[] elements); - - /** * Reads a {@code Throwable} from a stream, enforcing * well-formedness constraints on fields. Null entries and * self-pointers are not allowed in the list of {@code --- old/jdk/src/java.base/share/classes/java/net/URLClassLoader.java 2016-10-28 21:41:58.000000000 -0700 +++ new/jdk/src/java.base/share/classes/java/net/URLClassLoader.java 2016-10-28 21:41:57.000000000 -0700 @@ -110,19 +110,19 @@ if (security != null) { security.checkCreateClassLoader(); } - ucp = new URLClassPath(urls); + this.ucp = new URLClassPath(urls); this.acc = AccessController.getContext(); } - URLClassLoader(URL[] urls, ClassLoader parent, + URLClassLoader(String name, URL[] urls, ClassLoader parent, AccessControlContext acc) { - super(parent); + super(name, parent); // this is to make the stack depth consistent with 1.1 SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkCreateClassLoader(); } - ucp = new URLClassPath(urls); + this.ucp = new URLClassPath(urls); this.acc = acc; } @@ -154,7 +154,7 @@ if (security != null) { security.checkCreateClassLoader(); } - ucp = new URLClassPath(urls); + this.ucp = new URLClassPath(urls); this.acc = AccessController.getContext(); } @@ -165,7 +165,7 @@ if (security != null) { security.checkCreateClassLoader(); } - ucp = new URLClassPath(urls); + this.ucp = new URLClassPath(urls); this.acc = acc; } @@ -198,8 +198,72 @@ if (security != null) { security.checkCreateClassLoader(); } - ucp = new URLClassPath(urls, factory); - acc = AccessController.getContext(); + this.ucp = new URLClassPath(urls, factory); + this.acc = AccessController.getContext(); + } + + + /** + * Constructs a new named {@code URLClassLoader} for the specified URLs. + * The URLs will be searched in the order specified for classes + * and resources after first searching in the specified parent class loader. + * Any URL that ends with a '/' is assumed to refer to a directory. + * Otherwise, the URL is assumed to refer to a JAR file which will be + * downloaded and opened as needed. + * + * @param name class loader name; or {@code null} if not named + * @param urls the URLs from which to load classes and resources + * @param parent the parent class loader for delegation + * + * @throws SecurityException if a security manager exists and its + * {@link SecurityManager#checkCreateClassLoader()} method doesn't + * allow creation of a class loader. + * @throws NullPointerException if {@code urls} is {@code null}. + * + * @since 9 + */ + public URLClassLoader(String name, + URL[] urls, + ClassLoader parent) { + super(name, parent); + // this is to make the stack depth consistent with 1.1 + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkCreateClassLoader(); + } + this.ucp = new URLClassPath(urls); + this.acc = AccessController.getContext(); + } + + /** + * Constructs a new named {@code URLClassLoader} for the specified URLs, + * parent class loader, and URLStreamHandlerFactory. + * The parent argument will be used as the parent class loader for delegation. + * The factory argument will be used as the stream handler factory to + * obtain protocol handlers when creating new jar URLs. + * + * @param name class loader name; or {@code null} if not named + * @param urls the URLs from which to load classes and resources + * @param parent the parent class loader for delegation + * @param factory the URLStreamHandlerFactory to use when creating URLs + * + * @throws SecurityException if a security manager exists and its + * {@code checkCreateClassLoader} method doesn't allow + * creation of a class loader. + * @throws NullPointerException if {@code urls} is {@code null}. + * + * @since 9 + */ + public URLClassLoader(String name, URL[] urls, ClassLoader parent, + URLStreamHandlerFactory factory) { + super(name, parent); + // this is to make the stack depth consistent with 1.1 + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkCreateClassLoader(); + } + this.ucp = new URLClassPath(urls, factory); + this.acc = AccessController.getContext(); } /* A map (used as a set) to keep track of closeable local resources @@ -735,7 +799,7 @@ URLClassLoader ucl = AccessController.doPrivileged( new PrivilegedAction<>() { public URLClassLoader run() { - return new FactoryURLClassLoader(urls, parent, acc); + return new FactoryURLClassLoader(null, urls, parent, acc); } }); return ucl; @@ -785,9 +849,9 @@ ClassLoader.registerAsParallelCapable(); } - FactoryURLClassLoader(URL[] urls, ClassLoader parent, + FactoryURLClassLoader(String name, URL[] urls, ClassLoader parent, AccessControlContext acc) { - super(urls, parent, acc); + super(name, urls, parent, acc); } FactoryURLClassLoader(URL[] urls, AccessControlContext acc) { --- old/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java 2016-10-28 21:41:59.000000000 -0700 +++ new/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java 2016-10-28 21:41:59.000000000 -0700 @@ -25,8 +25,6 @@ package java.security; -import java.net.URL; -import java.util.ArrayList; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; @@ -114,6 +112,28 @@ } /** + * Creates a new {@code SecureClassLoader} of the specified name and + * using the specified parent class loader for delegation. + * + * @param name class loader name; or {@code null} if not named + * @param parent the parent class loader + * + * @throws SecurityException if a security manager exists and its + * {@link SecurityManager#checkCreateClassLoader()} method + * doesn't allow creation of a class loader. + * + * @since 9 + */ + protected SecureClassLoader(String name, ClassLoader parent) { + super(name, parent); + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkCreateClassLoader(); + } + initialized = true; + } + + /** * Converts an array of bytes into an instance of class Class, * with an optional CodeSource. Before the * class can be used it must be resolved. --- old/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java 2016-10-28 21:42:00.000000000 -0700 +++ new/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java 2016-10-28 21:42:00.000000000 -0700 @@ -144,9 +144,9 @@ /** * Create a new instance. */ - BuiltinClassLoader(BuiltinClassLoader parent, URLClassPath ucp) { + BuiltinClassLoader(String name, BuiltinClassLoader parent, URLClassPath ucp) { // ensure getParent() returns null when the parent is the boot loader - super(parent == null || parent == ClassLoaders.bootLoader() ? null : parent); + super(name, parent == null || parent == ClassLoaders.bootLoader() ? null : parent); this.parent = parent; this.ucp = ucp; --- old/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java 2016-10-28 21:42:01.000000000 -0700 +++ new/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java 2016-10-28 21:42:01.000000000 -0700 @@ -117,7 +117,7 @@ */ private static class BootClassLoader extends BuiltinClassLoader { BootClassLoader(URLClassPath bcp) { - super(null, bcp); + super(null, null, bcp); } @Override @@ -137,7 +137,7 @@ } PlatformClassLoader(BootClassLoader parent) { - super(parent, null); + super("platform", parent, null); } /** @@ -164,7 +164,7 @@ final URLClassPath ucp; AppClassLoader(PlatformClassLoader parent, URLClassPath ucp) { - super(parent, ucp); + super("app", parent, ucp); this.ucp = ucp; } --- old/jdk/src/java.base/share/native/libjava/Throwable.c 2016-10-28 21:42:03.000000000 -0700 +++ new/jdk/src/java.base/share/native/libjava/Throwable.c 2016-10-28 21:42:02.000000000 -0700 @@ -49,10 +49,3 @@ JVM_FillInStackTrace(env, throwable); return throwable; } - -JNIEXPORT void JNICALL -Java_java_lang_Throwable_getStackTraceElements(JNIEnv *env, - jobject throwable, jobjectArray elements) -{ - JVM_GetStackTraceElements(env, throwable, elements); -} --- old/jdk/src/java.management/share/classes/sun/management/StackTraceElementCompositeData.java 2016-10-28 21:42:04.000000000 -0700 +++ new/jdk/src/java.management/share/classes/sun/management/StackTraceElementCompositeData.java 2016-10-28 21:42:03.000000000 -0700 @@ -58,7 +58,8 @@ getString(cd, FILE_NAME), getInt(cd, LINE_NUMBER)); } else { - return new StackTraceElement(getString(cd, MODULE_NAME), + return new StackTraceElement(getString(cd, CLASS_LOADER_NAME), + getString(cd, MODULE_NAME), getString(cd, MODULE_VERSION), getString(cd, CLASS_NAME), getString(cd, METHOD_NAME), @@ -76,13 +77,14 @@ // CONTENTS OF THIS ARRAY MUST BE SYNCHRONIZED WITH // stackTraceElementItemNames! final Object[] stackTraceElementItemValues = { + ste.getClassLoaderName(), + ste.getModuleName(), + ste.getModuleVersion(), ste.getClassName(), ste.getMethodName(), ste.getFileName(), ste.getLineNumber(), ste.isNativeMethod(), - ste.getModuleName(), - ste.getModuleVersion(), }; try { return new CompositeDataSupport(stackTraceElementCompositeType, @@ -95,25 +97,29 @@ } // Attribute names - private static final String CLASS_NAME = "className"; - private static final String METHOD_NAME = "methodName"; - private static final String FILE_NAME = "fileName"; - private static final String LINE_NUMBER = "lineNumber"; - private static final String NATIVE_METHOD = "nativeMethod"; - private static final String MODULE_NAME = "moduleName"; - private static final String MODULE_VERSION = "moduleVersion"; + private static final String CLASS_LOADER_NAME = "classLoaderName"; + private static final String MODULE_NAME = "moduleName"; + private static final String MODULE_VERSION = "moduleVersion"; + private static final String CLASS_NAME = "className"; + private static final String METHOD_NAME = "methodName"; + private static final String FILE_NAME = "fileName"; + private static final String LINE_NUMBER = "lineNumber"; + private static final String NATIVE_METHOD = "nativeMethod"; + private static final String[] stackTraceElementItemNames = { + CLASS_LOADER_NAME, + MODULE_NAME, + MODULE_VERSION, CLASS_NAME, METHOD_NAME, FILE_NAME, LINE_NUMBER, NATIVE_METHOD, - MODULE_NAME, - MODULE_VERSION, }; private static final String[] stackTraceElementV9ItemNames = { + CLASS_LOADER_NAME, MODULE_NAME, MODULE_VERSION, }; --- old/jdk/test/java/lang/StackTraceElement/PublicConstructor.java 2016-10-28 21:42:05.000000000 -0700 +++ new/jdk/test/java/lang/StackTraceElement/PublicConstructor.java 2016-10-28 21:42:05.000000000 -0700 @@ -42,7 +42,8 @@ if (ste.isNativeMethod()) throw new RuntimeException("2"); StackTraceElement ste2 - = new StackTraceElement("jdk.module", + = new StackTraceElement("app", + "jdk.module", "9.0", "com.acme.Widget", "frobnicate", @@ -51,6 +52,7 @@ if (!(ste2.getClassName().equals("com.acme.Widget") && ste2.getModuleName().equals("jdk.module") && ste2.getModuleVersion().equals("9.0") && + ste2.getClassLoaderName().equals("app") && ste2.getFileName().equals("Widget.java") && ste2.getMethodName().equals("frobnicate") && ste2.getLineNumber() == 42)) --- old/jdk/test/java/lang/StackWalker/VerifyStackTrace.java 2016-10-28 21:42:06.000000000 -0700 +++ new/jdk/test/java/lang/StackWalker/VerifyStackTrace.java 2016-10-28 21:42:06.000000000 -0700 @@ -71,7 +71,7 @@ "3: VerifyStackTrace$Handle.run(VerifyStackTrace.java:158)\n" + "4: VerifyStackTrace.invoke(VerifyStackTrace.java:188)\n" + "5: VerifyStackTrace$1.run(VerifyStackTrace.java:218)\n" + - "6: java.security.AccessController.doPrivileged(java.base/Native Method)\n" + + "6: java.base/java.security.AccessController.doPrivileged(Native Method)\n" + "7: VerifyStackTrace.test(VerifyStackTrace.java:227)\n" + "8: VerifyStackTrace.main(VerifyStackTrace.java:182)\n"; @@ -100,12 +100,12 @@ "2: VerifyStackTrace$Handle.execute(VerifyStackTrace.java:147)\n" + "3: VerifyStackTrace$Handle.run(VerifyStackTrace.java:160)\n" + "4: VerifyStackTrace.invoke(VerifyStackTrace.java:190)\n" + - "5: jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base/Native Method)\n" + - "6: jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base/NativeMethodAccessorImpl.java:62)\n" + - "7: jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base/DelegatingMethodAccessorImpl.java:43)\n" + - "8: java.lang.reflect.Method.invoke(java.base/Method.java:520)\n" + + "5: java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n" + + "6: java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n" + + "7: java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n" + + "8: java.base/java.lang.reflect.Method.invoke(Method.java:520)\n" + "9: VerifyStackTrace$1.run(VerifyStackTrace.java:220)\n" + - "10: java.security.AccessController.doPrivileged(java.base/Native Method)\n" + + "10: java.base/java.security.AccessController.doPrivileged(Native Method)\n" + "11: VerifyStackTrace.test(VerifyStackTrace.java:229)\n" + "12: VerifyStackTrace.main(VerifyStackTrace.java:185)\n"; @@ -133,16 +133,16 @@ "1: VerifyStackTrace.lambda$test$1(VerifyStackTrace.java:213)\n" + "2: VerifyStackTrace$$Lambda$1/662441761.run(Unknown Source)\n" + "3: VerifyStackTrace$Handle.execute(VerifyStackTrace.java:149)\n" + - "4: java.lang.invoke.LambdaForm$DMH/2008017533.invokeVirtual_LL_V(java.base/LambdaForm$DMH)\n" + - "5: java.lang.invoke.LambdaForm$MH/1395089624.invoke_MT(java.base/LambdaForm$MH)\n" + + "4: java.base/java.lang.invoke.LambdaForm$DMH/2008017533.invokeVirtual_LL_V(LambdaForm$DMH)\n" + + "5: java.base/java.lang.invoke.LambdaForm$MH/1395089624.invoke_MT(LambdaForm$MH)\n" + "6: VerifyStackTrace$Handle.run(VerifyStackTrace.java:162)\n" + "7: VerifyStackTrace.invoke(VerifyStackTrace.java:192)\n" + - "8: jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base/Native Method)\n" + - "9: jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base/NativeMethodAccessorImpl.java:62)\n" + - "10: jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base/DelegatingMethodAccessorImpl.java:43)\n" + - "11: java.lang.reflect.Method.invoke(java.base/Method.java:520)\n" + + "8: java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n" + + "9: java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n" + + "10: java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n" + + "11: java.base/java.lang.reflect.Method.invoke(Method.java:520)\n" + "12: VerifyStackTrace$1.run(VerifyStackTrace.java:222)\n" + - "13: java.security.AccessController.doPrivileged(java.base/Native Method)\n" + + "13: java.base/java.security.AccessController.doPrivileged(Native Method)\n" + "14: VerifyStackTrace.test(VerifyStackTrace.java:231)\n" + "15: VerifyStackTrace.main(VerifyStackTrace.java:188)\n"; @@ -201,8 +201,6 @@ // out before comparing. We also erase the hash-like names of // synthetic frames introduced by lambdas & method handles return produced.replaceAll(":[1-9][0-9]*\\)", ":00)") - .replaceAll("-internal/", "/").replaceAll("-ea/", "/") - .replaceAll("java.base@(\\d+\\.){0,3}(\\d+)/", "java.base/") .replaceAll("/[0-9]+\\.run", "/xxxxxxxx.run") .replaceAll("/[0-9]+\\.invoke", "/xxxxxxxx.invoke") // LFs may or may not be pre-generated, making frames differ --- old/jdk/test/java/lang/management/CompositeData/ThreadInfoCompositeData.java 2016-10-28 21:42:07.000000000 -0700 +++ new/jdk/test/java/lang/management/CompositeData/ThreadInfoCompositeData.java 2016-10-28 21:42:07.000000000 -0700 @@ -337,9 +337,10 @@ }; private static final String[] steItemNames = { - "className", "moduleName", "moduleVersion", + "classLoaderName", + "className", "methodName", "fileName", "lineNumber", @@ -362,9 +363,10 @@ validItemTypes[STACK_TRACE] = new ArrayType(1, steCType); final Object[] steValue = { - ste[0].getClassName(), ste[0].getModuleName(), ste[0].getModuleVersion(), + ste[0].getClassLoaderName(), + ste[0].getClassName(), ste[0].getMethodName(), ste[0].getFileName(), new Integer(ste[0].getLineNumber()), --- old/jdk/test/java/net/URLClassLoader/NullURLTest.java 2016-10-28 21:42:09.000000000 -0700 +++ new/jdk/test/java/net/URLClassLoader/NullURLTest.java 2016-10-28 21:42:08.000000000 -0700 @@ -109,7 +109,7 @@ failures++; } try { - loader = new URLClassLoader(null, null, null); + loader = new URLClassLoader((URL[])null, null, null); System.err.println("URLClassLoader(null, null, null) did not throw NPE"); failures++; } catch (NullPointerException e) { --- old/jdk/src/java.base/share/native/libjava/StackFrameInfo.c 2016-10-28 21:42:10.000000000 -0700 +++ /dev/null 2016-10-28 21:42:10.000000000 -0700 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * Implementation of class StackFrameInfo - */ - -#include -#include - -#include "jni.h" -#include "jvm.h" - -#include "java_lang_StackFrameInfo.h" - - -/* - * Class: java_lang_StackFrameInfo - * Method: toStackTraceElement0 - * Signature: (Ljava/lang/StackTraceElement;)V - */ -JNIEXPORT void JNICALL Java_java_lang_StackFrameInfo_toStackTraceElement0 - (JNIEnv *env, jobject stackframeinfo, jobject stacktraceinfo) { - JVM_ToStackTraceElement(env, stackframeinfo, stacktraceinfo); -} --- /dev/null 2016-10-28 21:42:10.000000000 -0700 +++ new/jdk/src/java.base/share/native/libjava/StackTraceElement.c 2016-10-28 21:42:10.000000000 -0700 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include + +#include "jni.h" +#include "jvm.h" + +#include "java_lang_StackTraceElement.h" + +JNIEXPORT void JNICALL Java_java_lang_StackTraceElement_fillFromStackFrameInfo + (JNIEnv *env, jobject element, jobject stackframeinfo) { + JVM_ToStackTraceElement(env, stackframeinfo, element); +} + +JNIEXPORT void JNICALL Java_java_lang_StackTraceElement_fillStackTraceFromThrowable + (JNIEnv *env, jobject dummy, jobjectArray elements, jobject throwable) +{ + JVM_GetStackTraceElements(env, throwable, elements); +} --- /dev/null 2016-10-28 21:42:12.000000000 -0700 +++ new/jdk/test/java/lang/StackTraceElement/SerialTest.java 2016-10-28 21:42:11.000000000 -0700 @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6479237 + * @summary Test the format of StackTraceElement::toString and its serial form + * @modules java.logging + * java.xml.bind + * @run main SerialTest + */ + +import javax.xml.bind.JAXBElement; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.logging.Logger; + +public class SerialTest { + private static final Path SER_DIR = Paths.get("sers"); + private static final String JAVA_BASE = "java.base"; + private static final String JAVA_LOGGING = "java.logging"; + private static final String JAVA_XML_BIND = "java.xml.bind"; + + private static boolean isImage; + + public static void main(String... args) throws Exception { + Files.createDirectories(SER_DIR); + + // detect if exploded image build + Path home = Paths.get(System.getProperty("java.home")); + isImage = Files.exists(home.resolve("lib").resolve("modules")); + + // test stack trace from built-in loaders + try { + Logger.getLogger(null); + } catch (NullPointerException e) { + Arrays.stream(e.getStackTrace()) + .filter(ste -> ste.getClassName().startsWith("java.util.logging.") || + ste.getClassName().equals("SerialTest")) + .forEach(SerialTest::test); + } + + // test stack trace with upgradeable module + try { + new JAXBElement(null, null, null); + } catch (IllegalArgumentException e) { + Arrays.stream(e.getStackTrace()) + .filter(ste -> ste.getModuleName() != null) + .forEach(SerialTest::test); + } + + // test stack trace with class loader name from other class loader + Path path = Paths.get(System.getProperty("test.classes")); + URL[] urls = new URL[] { + path.toUri().toURL() + }; + URLClassLoader loader = new URLClassLoader("myloader", urls, null); + Class cls = Class.forName("SerialTest", true, loader); + Method method = cls.getMethod("throwException"); + StackTraceElement ste = (StackTraceElement)method.invoke(null); + test(ste, loader); + } + + private static void test(StackTraceElement ste) { + test(ste, null); + } + + private static void test(StackTraceElement ste, ClassLoader loader) { + try { + SerialTest serialTest = new SerialTest(ste); + StackTraceElement ste2 = serialTest.serialize().deserialize(); + System.out.println(ste2); + if (!ste.equals(ste2) || !ste.toString().equals(ste2.toString())) { + throw new RuntimeException(ste + " != " + ste2); + } + + String mn = ste.getModuleName(); + if (mn != null) { + switch (mn) { + case JAVA_BASE: + case JAVA_LOGGING: + checkNamedModule(ste, loader, false); + break; + case JAVA_XML_BIND: + // for exploded build, no version is shown + checkNamedModule(ste, loader, isImage); + break; + default: // ignore + } + } else { + checkUnnamedModule(ste, loader); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private static void checkUnnamedModule(StackTraceElement ste, ClassLoader loader) { + String mn = ste.getModuleName(); + String s = ste.toString(); + int i = s.indexOf('/'); + + if (mn != null) { + throw new RuntimeException("expected null but got " + mn); + } + + if (loader != null) { + // Expect //.(:) + if (i <= 0) { + throw new RuntimeException("loader name missing: " + s); + } + if (!loader.getName().equals(s.substring(0, i))) { + throw new RuntimeException("unexpected loader name: " + s); + } + int j = s.substring(i+1).indexOf('/'); + if (j != 0) { + throw new RuntimeException("unexpected element for unnamed module: " + s); + } + } + } + + private static void checkNamedModule(StackTraceElement ste, + ClassLoader loader, + boolean showVersion) { + String loaderName = loader != null ? loader.getName() : ""; + String mn = ste.getModuleName(); + String s = ste.toString(); + int i = s.indexOf('/'); + + if (mn == null) { + throw new RuntimeException("expected module name: " + s); + } + + if (i <= 0) { + throw new RuntimeException("module name missing: " + s); + } + + // Expect /.(:) + if (!loaderName.isEmpty()) { + throw new IllegalArgumentException(loaderName); + } + + // : name@version + int j = s.indexOf('@'); + if ((showVersion && j <= 0) || (!showVersion && j >= 0)) { + throw new RuntimeException("unexpected version: " + s); + } + + String name = j < 0 ? s.substring(0, i) : s.substring(0, j); + if (!name.equals(mn)) { + throw new RuntimeException("unexpected module name: " + s); + } + } + + private final Path ser; + private final StackTraceElement ste; + SerialTest(StackTraceElement ste) throws IOException { + this.ser = Files.createTempFile(SER_DIR, "SerialTest", ".ser"); + this.ste = ste; + } + + private StackTraceElement deserialize() throws IOException { + try (InputStream in = Files.newInputStream(ser); + BufferedInputStream bis = new BufferedInputStream(in); + ObjectInputStream ois = new ObjectInputStream(bis)) { + return (StackTraceElement)ois.readObject(); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + private SerialTest serialize() throws IOException { + try (OutputStream out = Files.newOutputStream(ser); + BufferedOutputStream bos = new BufferedOutputStream(out); + ObjectOutputStream oos = new ObjectOutputStream(bos)) { + oos.writeObject(ste); + } + return this; + } + + + public static StackTraceElement throwException() { + try { + Integer.parseInt(null); + } catch (NumberFormatException e) { + return Arrays.stream(e.getStackTrace()) + .filter(ste -> ste.getMethodName().equals("throwException")) + .findFirst().get(); + } + return null; + } +} --- /dev/null 2016-10-28 21:42:13.000000000 -0700 +++ new/jdk/test/java/lang/StackTraceElement/WithClassLoaderName.java 2016-10-28 21:42:12.000000000 -0700 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6479237 + * @summary Basic test StackTraceElement with class loader names + * @library lib /lib/testlibrary + * @build m1/* WithClassLoaderName + * @run main/othervm m1/com.app.Main + * @run main/othervm WithClassLoaderName + */ + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Path; +import java.nio.file.Paths; + +import com.app.Utils; + +public class WithClassLoaderName { + private static final String TEST_SRC = System.getProperty("test.src"); + private static final String SRC_FILENAME = "WithClassLoaderName.java"; + + private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + private static final Path CLASSES_DIR = Paths.get("classes"); + private static final String THROW_EXCEPTION_CLASS = "p.ThrowException"; + + public static void main(String... args) throws Exception { + /* + * Test the following frames both have the same class loader name "app" + * com.app.Test::test + * WithClassLoaderName::test + */ + Utils.verify(WithClassLoaderName.class, "app", "main", SRC_FILENAME); + + /* + * Test StackTraceElement for a class loaded by a named URLClassLoader + */ + compile(); + testURLClassLoader("myloader"); + + // loader name same as application class loader + testURLClassLoader("app"); + } + + private static void compile() throws Exception { + boolean rc = CompilerUtils.compile(SRC_DIR, CLASSES_DIR); + if (!rc) { + throw new RuntimeException("compilation fails"); + } + } + + public static void testURLClassLoader(String loaderName) throws Exception { + System.err.println("---- test URLClassLoader name: " + loaderName); + + URL[] urls = new URL[] { CLASSES_DIR.toUri().toURL() }; + ClassLoader parent = ClassLoader.getSystemClassLoader(); + URLClassLoader loader = new URLClassLoader(loaderName, urls, parent); + + Class c = Class.forName(THROW_EXCEPTION_CLASS, true, loader); + Method method = c.getMethod("throwError"); + try { + // invoke p.ThrowException::throwError + method.invoke(null); + } catch (InvocationTargetException x) { + Throwable e = x.getCause(); + e.printStackTrace(); + + StackTraceElement[] stes = e.getStackTrace(); + StackWalker.StackFrame[] frames = new StackWalker.StackFrame[] { + Utils.makeStackFrame(c, "throwError", "ThrowException.java"), + Utils.makeStackFrame(WithClassLoaderName.class, "testURLClassLoader", + SRC_FILENAME), + Utils.makeStackFrame(WithClassLoaderName.class, "main", SRC_FILENAME), + }; + + // p.ThrowException.throwError + Utils.checkFrame(loaderName, frames[0], stes[0]); + // skip reflection frames + int i = 1; + while (i < stes.length) { + String cn = stes[i].getClassName(); + if (!cn.startsWith("java.lang.reflect.") && + !cn.startsWith("jdk.internal.reflect.")) + break; + i++; + } + // WithClassLoaderName.testURLClassLoader + Utils.checkFrame("app", frames[1], stes[i]); + + // WithClassLoaderName.main + Utils.checkFrame("app", frames[2], stes[i+1]); + + } + } + +} + --- /dev/null 2016-10-28 21:42:14.000000000 -0700 +++ new/jdk/test/java/lang/StackTraceElement/lib/m1/com/app/Main.java 2016-10-28 21:42:13.000000000 -0700 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.app; + +import java.lang.StackWalker.StackFrame; + +public class Main { + public static void main(String... args) throws Exception { + StackFrame frame = Utils.makeStackFrame(Main.class, "main", "Main.java"); + Utils.checkFrame("app", frame, caller()); + } + + private static StackTraceElement caller() { + StackTraceElement[] stes = Thread.currentThread().getStackTrace(); + return stes[2]; + } +} --- /dev/null 2016-10-28 21:42:15.000000000 -0700 +++ new/jdk/test/java/lang/StackTraceElement/lib/m1/com/app/Utils.java 2016-10-28 21:42:15.000000000 -0700 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.app; + +import java.lang.StackWalker.StackFrame; +import java.lang.module.ModuleDescriptor; +import java.lang.reflect.Module; +import java.util.Objects; + +public class Utils { + public static void verify(Class caller, String loaderName, + String methodname, String filename) { + StackTraceElement[] stes = Thread.currentThread().getStackTrace(); + StackWalker.StackFrame[] frames = new StackFrame[] { + makeStackFrame(Utils.class, "verify", "Utils.java"), + makeStackFrame(caller, methodname, filename) + }; + + checkFrame("app", frames[0], stes[1]); + checkFrame(loaderName, frames[1], stes[2]); + } + + public static StackFrame makeStackFrame(Class c, String methodname, String filename) { + return new StackFrame() { + @Override + public String getClassName() { + return c.getName(); + } + @Override + public String getMethodName() { + return methodname; + } + @Override + public Class getDeclaringClass() { + return c; + } + @Override + public int getByteCodeIndex() { + return 0; + } + @Override + public String getFileName() { + return filename; + } + + @Override + public int getLineNumber() { + return 0; + } + @Override + public boolean isNativeMethod() { + return false; + } + @Override + public StackTraceElement toStackTraceElement() { + return null; + } + + private String getClassLoaderName(Class c) { + ClassLoader loader = c.getClassLoader(); + String name = ""; + if (loader == null) { + name = "boot"; + } else if (loader.getName() != null) { + name = loader.getName(); + } + return name; + } + + @Override + public String toString() { + String mid = getClassLoaderName(c); + Module module = c.getModule(); + if (module.isNamed()) { + ModuleDescriptor md = module.getDescriptor(); + mid = md.name(); + if (md.version().isPresent()) + mid += "@" + md.version().get().toString(); + mid += "/"; + } + String fileName = getFileName(); + int lineNumber = getLineNumber(); + String sourceinfo = "Unknown Source"; + if (isNativeMethod()) { + sourceinfo = "Native Method"; + } else if (fileName != null && lineNumber >= 0) { + sourceinfo = fileName + ":" + lineNumber; + } + return String.format("%s/%s.%s(%s)", mid, getClassName(), getMethodName(), + sourceinfo); + + } + }; + } + + public static void checkFrame(String loaderName, StackFrame frame, + StackTraceElement ste) { + System.err.println("checking " + ste.toString() + " expected: " + frame.toString()); + Class c = frame.getDeclaringClass(); + Module module = c.getModule(); + assertEquals(ste.getModuleName(), module.getName(), "module name"); + assertEquals(ste.getClassLoaderName(), loaderName, "class loader name"); + assertEquals(ste.getClassLoaderName(), c.getClassLoader().getName(), + "class loader name"); + assertEquals(ste.getClassName(), c.getName(), "class name"); + assertEquals(ste.getMethodName(), frame.getMethodName(), "method name"); + assertEquals(ste.getFileName(), frame.getFileName(), "file name"); + + } + private static void assertEquals(String actual, String expected, String msg) { + if (!Objects.equals(actual, expected)) + throw new AssertionError("Actual: " + actual + " Excepted: " + + expected + " mismatched " + msg); + } +} --- /dev/null 2016-10-28 21:42:16.000000000 -0700 +++ new/jdk/test/java/lang/StackTraceElement/lib/m1/module-info.java 2016-10-28 21:42:16.000000000 -0700 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module m1 { + exports com.app; +} --- /dev/null 2016-10-28 21:42:17.000000000 -0700 +++ new/jdk/test/java/lang/StackTraceElement/src/p/ThrowException.java 2016-10-28 21:42:17.000000000 -0700 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +import java.lang.StackWalker.StackFrame; + +public class ThrowException { + public static void throwError() { + throw new Error("testing"); + } +}