From d3b1596a8b9abbae5b7f52d75c69e683785ea9d0 Mon Sep 17 00:00:00 2001 From: Alexander Kulyakhtin Date: Wed, 6 Apr 2016 13:47:18 +0300 Subject: [PATCH 1/6] 8153584: New jtreg test to verify PathSearchingVirutalMachine.bootClassPath() behaviour Adding a new jtreg test Reviewed-by: dsamersoff --- .../sun/jdi/SunBootClassPathEmptyTest.java | 97 +++++++++++++++++++ jdk/test/com/sun/jdi/TestClass.java | 30 ++++++ 2 files changed, 127 insertions(+) create mode 100644 jdk/test/com/sun/jdi/SunBootClassPathEmptyTest.java create mode 100644 jdk/test/com/sun/jdi/TestClass.java diff --git a/jdk/test/com/sun/jdi/SunBootClassPathEmptyTest.java b/jdk/test/com/sun/jdi/SunBootClassPathEmptyTest.java new file mode 100644 index 00000000000..e062996ee6a --- /dev/null +++ b/jdk/test/com/sun/jdi/SunBootClassPathEmptyTest.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +import com.sun.jdi.connect.*; +import com.sun.jdi.*; +import java.util.Map; +import java.util.List; +import jdk.test.lib.Asserts; + +/* + * @test + * @summary Verifies that PathSearchingVirtualMachine.bootClassPath() + * returns an empty list in case no bootclass path specified + * regardless of sun.boot.class.path option, which is now obsolete + * @library /test/lib/share/classes + * @compile TestClass.java + * @compile SunBootClassPathEmptyTest.java + * @run main/othervm SunBootClassPathEmptyTest + */ +public class SunBootClassPathEmptyTest { + + /** + * Helper class to facilitate the debuggee VM launching + */ + private static class VmConnector { + + LaunchingConnector lc; + VirtualMachine vm; + + VmConnector() { + for (LaunchingConnector c : Bootstrap.virtualMachineManager().launchingConnectors()) { + System.out.println("name: " + c.name()); + if (c.name().equals("com.sun.jdi.CommandLineLaunch")) { + lc = c; + break; + } + } + if (lc == null) { + throw new RuntimeException("Connector not found"); + } + } + + PathSearchingVirtualMachine launchVm(String cmdLine, String options) throws Exception { + Map vmArgs = lc.defaultArguments(); + vmArgs.get("main").setValue(cmdLine); + if (options != null) { + vmArgs.get("options").setValue(options); + } + System.out.println("Debugger is launching vm ..."); + vm = lc.launch(vmArgs); + if (!(vm instanceof PathSearchingVirtualMachine)) { + throw new RuntimeException("VM is not a PathSearchingVirtualMachine"); + } + return (PathSearchingVirtualMachine) vm; + } + + } + + private static VmConnector connector = new VmConnector(); + + public static void main(String[] args) throws Exception { + testWithObsoleteClassPathOption(null); + testWithObsoleteClassPathOption("someclasspath"); + } + + private static void testWithObsoleteClassPathOption(String obsoleteClassPath) throws Exception { + PathSearchingVirtualMachine vm = connector.launchVm("TestClass", makeClassPathOptions(obsoleteClassPath)); + List bootClassPath = vm.bootClassPath(); + Asserts.assertNotNull(bootClassPath, "Expected bootClassPath to be empty but was null"); + Asserts.assertEquals(0, bootClassPath.size(), "Expected bootClassPath.size() 0 but was: " + bootClassPath.size()); + } + + private static String makeClassPathOptions(String obsoleteClassPath) { + return obsoleteClassPath == null ? null : "-Dsun.boot.class.path=" + obsoleteClassPath; + } + +} diff --git a/jdk/test/com/sun/jdi/TestClass.java b/jdk/test/com/sun/jdi/TestClass.java new file mode 100644 index 00000000000..dab6b66648c --- /dev/null +++ b/jdk/test/com/sun/jdi/TestClass.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +public class TestClass { + + public static void main(String[] args) { + System.out.println("This is a test"); + } + +} From fd6a72271b19efd83d54d758cdae294a70e87c2c Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Fri, 8 Apr 2016 13:14:23 +0200 Subject: [PATCH 2/6] 8152666: The new Hotspot Build System Co-authored-by: Magnus Ihse Bursie Co-authored-by: Ingemar Aberg Reviewed-by: ihse, dcubed, erikj --- jdk/make/Import.gmk | 8 ++++---- jdk/make/copy/Copy-java.base.gmk | 22 +++++++++++----------- jdk/make/lib/CoreLibraries.gmk | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/jdk/make/Import.gmk b/jdk/make/Import.gmk index 42155494fb2..d479b095514 100644 --- a/jdk/make/Import.gmk +++ b/jdk/make/Import.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 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 @@ -83,20 +83,20 @@ ifneq ($(STATIC_BUILD), true) endif ifneq ($(OPENJDK_TARGET_OS), windows) - ifeq ($(JVM_VARIANT_SERVER), true) + ifeq ($(call check-jvm-variant, server), true) BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/server/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX) ifneq (, $(JSIG_DEBUGINFO)) BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/server/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I)) endif endif - ifeq ($(JVM_VARIANT_CLIENT), true) + ifeq ($(call check-jvm-variant, client), true) BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/client/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX) ifneq (, $(JSIG_DEBUGINFO)) BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/client/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I)) endif endif ifneq ($(OPENJDK_TARGET_OS), macosx) - ifeq ($(JVM_VARIANT_MINIMAL1), true) + ifeq ($(call check-jvm-variant, minimal), true) BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/minimal/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX) ifneq (,$(JSIG_DEBUGINFO)) BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/minimal/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I)) diff --git a/jdk/make/copy/Copy-java.base.gmk b/jdk/make/copy/Copy-java.base.gmk index 04988de5f85..d50b52378f9 100644 --- a/jdk/make/copy/Copy-java.base.gmk +++ b/jdk/make/copy/Copy-java.base.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 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 @@ -88,7 +88,7 @@ endif # # How to install jvm.cfg. # -ifeq ($(JVM_VARIANT_ZERO), true) +ifeq ($(call check-jvm-variant, zero zeroshark), true) JVMCFG_ARCH := zero else JVMCFG_ARCH := $(OPENJDK_TARGET_CPU_LEGACY) @@ -99,7 +99,7 @@ ifeq ($(OPENJDK_TARGET_OS), macosx) else JVMCFG_SRC := $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/conf/$(JVMCFG_ARCH)/jvm.cfg # Allow override by ALT_JVMCFG_SRC if it exists - JVMCFG_SRC := $(if $(wildcard $(ALT_JVMCFG_SRC)),$(ALT_JVMCFG_SRC),$(JVMCFG_SRC)) + JVMCFG_SRC := $(if $(wildcard $(ALT_JVMCFG_SRC)),$(ALT_JVMCFG_SRC),$(JVMCFG_SRC)) endif JVMCFG_DIR := $(LIB_DST_DIR)$(OPENJDK_TARGET_CPU_LIBDIR) JVMCFG := $(JVMCFG_DIR)/jvm.cfg @@ -117,12 +117,12 @@ else # The main problem is deciding whether to use aliases for the VMs that are not # present and the current position is that we add aliases for client and server, but # not for minimal. - CLIENT_AND_SERVER := $(and $(findstring true, $(JVM_VARIANT_SERVER)), $(findstring true, $(JVM_VARIANT_CLIENT))) - ifeq ($(CLIENT_AND_SERVER), true) + CLIENT_AND_SERVER := $(call check-jvm-variant, client)+$(call check-jvm-variant, server) + ifeq ($(CLIENT_AND_SERVER), true+true) COPY_JVM_CFG_FILE := true else # For zero, the default jvm.cfg file is sufficient - ifeq ($(JVM_VARIANT_ZERO), true) + ifeq ($(call check-jvm-variant, zero zeroshark), true) COPY_JVM_CFG_FILE := true endif endif @@ -136,21 +136,21 @@ else $(MKDIR) -p $(@D) $(RM) $(@) # Now check for other permutations - ifeq ($(JVM_VARIANT_SERVER), true) + ifeq ($(call check-jvm-variant, server), true) $(PRINTF) "-server KNOWN\n">>$(@) $(PRINTF) "-client ALIASED_TO -server\n">>$(@) - ifeq ($(JVM_VARIANT_MINIMAL1), true) + ifeq ($(call check-jvm-variant, minimal), true) $(PRINTF) "-minimal KNOWN\n">>$(@) endif else - ifeq ($(JVM_VARIANT_CLIENT), true) + ifeq ($(call check-jvm-variant, client), true) $(PRINTF) "-client KNOWN\n">>$(@) $(PRINTF) "-server ALIASED_TO -client\n">>$(@) - ifeq ($(JVM_VARIANT_MINIMAL1), true) + ifeq ($(call check-jvm-variant, minimal), true) $(PRINTF) "-minimal KNOWN\n">>$(@) endif else - ifeq ($(JVM_VARIANT_MINIMAL1), true) + ifeq ($(call check-jvm-variant, minimal), true) $(PRINTF) "-minimal KNOWN\n">>$(@) $(PRINTF) "-server ALIASED_TO -minimal\n">>$(@) $(PRINTF) "-client ALIASED_TO -minimal\n">>$(@) diff --git a/jdk/make/lib/CoreLibraries.gmk b/jdk/make/lib/CoreLibraries.gmk index f114c9b7d33..bccf46bb824 100644 --- a/jdk/make/lib/CoreLibraries.gmk +++ b/jdk/make/lib/CoreLibraries.gmk @@ -289,7 +289,7 @@ LIBJLI_SRC_DIRS := $(call FindSrcDirsForLib, java.base, jli) LIBJLI_CFLAGS := $(CFLAGS_JDKLIB) -ifeq ($(JVM_VARIANT_ZERO), true) +ifeq ($(call check-jvm-variant, zero zeroshark), true) ERGO_FAMILY := zero else ifeq ($(OPENJDK_TARGET_CPU_ARCH), x86) From 74f12569ece839f772463d081d8ba954962a1af9 Mon Sep 17 00:00:00 2001 From: Brent Christian Date: Fri, 8 Apr 2016 12:26:47 -0700 Subject: [PATCH 3/6] 8153123: Streamline StackWalker code Reviewed-by: coleenp, dfuchs, mchung, redestad --- jdk/make/mapfiles/libjava/mapfile-vers | 3 +- .../classes/java/lang/StackFrameInfo.java | 92 +-- .../classes/java/lang/StackStreamFactory.java | 765 ++++++++---------- .../share/classes/java/lang/Thread.java | 5 +- .../share/classes/java/lang/Throwable.java | 18 +- .../classes/java/lang/invoke/MemberName.java | 4 + .../internal/misc/JavaLangInvokeAccess.java | 5 + jdk/src/java.base/share/native/include/jvm.h | 11 +- .../share/native/libjava/StackFrameInfo.c | 22 +- .../share/native/libjava/StackStreamFactory.c | 13 +- .../java/lang/StackWalker/DumpStackTest.java | 3 - .../lang/StackWalker/GetCallerClassTest.java | 3 +- .../java/lang/StackWalker/StackWalkTest.java | 4 - .../lang/StackWalker/VerifyStackTrace.java | 3 +- 14 files changed, 391 insertions(+), 560 deletions(-) diff --git a/jdk/make/mapfiles/libjava/mapfile-vers b/jdk/make/mapfiles/libjava/mapfile-vers index eb35a623fb2..24db66e8e29 100644 --- a/jdk/make/mapfiles/libjava/mapfile-vers +++ b/jdk/make/mapfiles/libjava/mapfile-vers @@ -139,8 +139,7 @@ SUNWprivate_1.1 { Java_java_lang_Double_doubleToRawLongBits; Java_java_lang_Float_intBitsToFloat; Java_java_lang_Float_floatToRawIntBits; - Java_java_lang_StackFrameInfo_fillInStackFrames; - Java_java_lang_StackFrameInfo_setMethodInfo; + Java_java_lang_StackFrameInfo_toStackTraceElement0; Java_java_lang_StackStreamFactory_checkStackWalkModes; Java_java_lang_StackStreamFactory_00024AbstractStackWalker_callStackWalk; Java_java_lang_StackStreamFactory_00024AbstractStackWalker_fetchStackFrames; diff --git a/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java b/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java index 0750af15b03..187a737d7c4 100644 --- a/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java +++ b/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java @@ -37,24 +37,14 @@ class StackFrameInfo implements StackFrame { private final static JavaLangInvokeAccess jlInvokeAccess = SharedSecrets.getJavaLangInvokeAccess(); - // -XX:+MemberNameInStackFrame will initialize MemberName and all other fields; - // otherwise, VM will set the hidden fields (injected by the VM). - // -XX:+MemberNameInStackFrame is temporary to enable performance measurement - // - // Footprint improvement: MemberName::clazz and MemberName::name - // can replace StackFrameInfo::declaringClass and StackFrameInfo::methodName - // Currently VM sets StackFrameInfo::methodName instead of expanding MemberName::name + // Footprint improvement: MemberName::clazz can replace + // StackFrameInfo::declaringClass. final StackWalker walker; final Class declaringClass; final Object memberName; - final int bci; - - // methodName, fileName, and lineNumber will be lazily set by the VM - // when first requested. - private String methodName; - private String fileName = null; // default for unavailable filename - private int lineNumber = -1; // default for unavailable lineNumber + final short bci; + private volatile StackTraceElement ste; /* * Create StackFrameInfo for StackFrameTraverser and LiveStackFrameTraverser @@ -78,77 +68,53 @@ class StackFrameInfo implements StackFrame { return declaringClass; } - // Call the VM to set methodName, lineNumber, and fileName - private synchronized void ensureMethodInfoInitialized() { - if (methodName == null) { - setMethodInfo(); - } - } - @Override public String getMethodName() { - ensureMethodInfoInitialized(); - return methodName; + return jlInvokeAccess.getName(memberName); } @Override - public Optional getFileName() { - ensureMethodInfoInitialized(); - return fileName != null ? Optional.of(fileName) : Optional.empty(); + public final Optional getFileName() { + StackTraceElement ste = toStackTraceElement(); + return ste.getFileName() != null ? Optional.of(ste.getFileName()) : Optional.empty(); } @Override - public OptionalInt getLineNumber() { - ensureMethodInfoInitialized(); - return lineNumber > 0 ? OptionalInt.of(lineNumber) : OptionalInt.empty(); + public final OptionalInt getLineNumber() { + StackTraceElement ste = toStackTraceElement(); + return ste.getLineNumber() > 0 ? OptionalInt.of(ste.getLineNumber()) : OptionalInt.empty(); } @Override - public boolean isNativeMethod() { - ensureMethodInfoInitialized(); - return lineNumber == -2; + public final boolean isNativeMethod() { + StackTraceElement ste = toStackTraceElement(); + return ste.isNativeMethod(); } @Override public String toString() { - ensureMethodInfoInitialized(); - // similar format as StackTraceElement::toString - if (isNativeMethod()) { - return getClassName() + "." + getMethodName() + "(Native Method)"; - } else { - // avoid allocating Optional objects - return getClassName() + "." + getMethodName() + - "(" + (fileName != null ? fileName : "Unknown Source") + - (lineNumber > 0 ? ":" + lineNumber : " bci:" + bci) + ")"; - } + StackTraceElement ste = toStackTraceElement(); + return ste.toString(); } /** - * Lazily initialize method name, file name, line number + * Fill in the fields of the given StackTraceElement */ - private native void setMethodInfo(); - - /** - * Fill in source file name and line number of the given StackFrame array. - */ - static native void fillInStackFrames(int startIndex, - Object[] stackframes, - int fromIndex, int toIndex); + private native void toStackTraceElement0(StackTraceElement ste); @Override public StackTraceElement toStackTraceElement() { - ensureMethodInfoInitialized(); - - Module module = declaringClass.getModule(); - String moduleName = module.isNamed() ? module.getName() : null; - String moduleVersion = null; - if (module.isNamed() && module.getDescriptor().version().isPresent()) { - moduleVersion = module.getDescriptor().version().get().toString(); + StackTraceElement s = ste; + if (s == null) { + synchronized (this) { + s = ste; + if (s == null) { + s = new StackTraceElement(); + toStackTraceElement0(s); + ste = s; + } + } } - return new StackTraceElement(moduleName, moduleVersion, - getClassName(), getMethodName(), - fileName, - lineNumber); + return s; } - } diff --git a/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java b/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java index dcb471c4cc2..ac2e8916bea 100644 --- a/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java +++ b/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java @@ -24,9 +24,6 @@ */ package java.lang; -import jdk.internal.misc.VM; - -import java.io.PrintStream; import java.lang.StackWalker.Option; import java.lang.StackWalker.StackFrame; @@ -34,12 +31,9 @@ import java.lang.annotation.Native; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; -import java.util.Arrays; -import java.util.EnumSet; import java.util.HashSet; import java.util.NoSuchElementException; import java.util.Objects; -import java.util.Optional; import java.util.Set; import java.util.Spliterator; import java.util.function.Consumer; @@ -60,8 +54,7 @@ import static java.lang.StackStreamFactory.WalkerState.*; * to avoid overhead of Stream/Lambda * 1. Support traversing Stream * 2. StackWalker::getCallerClass - * 3. Throwable::init and Throwable::getStackTrace - * 4. AccessControlContext getting ProtectionDomain + * 3. AccessControlContext getting ProtectionDomain */ final class StackStreamFactory { private StackStreamFactory() {} @@ -78,25 +71,22 @@ final class StackStreamFactory { // These flags must match the values maintained in the VM @Native private static final int DEFAULT_MODE = 0x0; @Native private static final int FILL_CLASS_REFS_ONLY = 0x2; - @Native private static final int FILTER_FILL_IN_STACKTRACE = 0x10; @Native private static final int SHOW_HIDDEN_FRAMES = 0x20; // LambdaForms are hidden by the VM @Native private static final int FILL_LIVE_STACK_FRAMES = 0x100; - /* * For Throwable to use StackWalker, set useNewThrowable to true. * Performance work and extensive testing is needed to replace the * VM built-in backtrace filled in Throwable with the StackWalker. */ - final static boolean useNewThrowable = getProperty("stackwalk.newThrowable", false); final static boolean isDebug = getProperty("stackwalk.debug", false); static StackFrameTraverser makeStackTraverser(StackWalker walker, Function, ? extends T> function) { if (walker.hasLocalsOperandsOption()) - return new LiveStackInfoTraverser(walker, function); + return new LiveStackInfoTraverser<>(walker, function); else - return new StackFrameTraverser(walker, function); + return new StackFrameTraverser<>(walker, function); } /** @@ -106,40 +96,31 @@ final class StackStreamFactory { return new CallerClassFinder(walker); } - static boolean useStackTrace(Throwable t) { - if (t instanceof VirtualMachineError) - return false; - - return VM.isBooted() && StackStreamFactory.useNewThrowable; - } - - /* - * This should only be used by Throwable::. - */ - static StackTrace makeStackTrace(Throwable ex) { - return StackTrace.dump(ex); - } - - /* - * This creates StackTrace for Thread::dumpThread to use. - */ - static StackTrace makeStackTrace() { - return StackTrace.dump(); - } - enum WalkerState { NEW, // the stream is new and stack walking has not started OPEN, // the stream is open when it is being traversed. CLOSED; // the stream is closed when the stack walking is done } - static abstract class AbstractStackWalker { + /** + * Subclass of AbstractStackWalker implements a specific stack walking logic. + * It needs to set up the frame buffer and stack walking mode. + * + * It initiates the VM stack walking via the callStackWalk method that serves + * as the anchored frame and VM will call up to AbstractStackWalker::doStackWalk. + * + * @param the type of the result returned from stack walking + * @param the type of the data gathered for each frame. + * For example, StackFrameInfo for StackWalker::walk or + * Class for StackWalker::getCallerClass + */ + static abstract class AbstractStackWalker { protected final StackWalker walker; protected final Thread thread; protected final int maxDepth; protected final long mode; - protected int depth; // traversed stack depth - protected FrameBuffer frameBuffer; // buffer for VM to fill in + protected int depth; // traversed stack depth + protected FrameBuffer frameBuffer; protected long anchor; // buffers to fill in stack frame information @@ -157,16 +138,13 @@ final class StackStreamFactory { private int toStackWalkMode(StackWalker walker, int mode) { int newMode = mode; if (walker.hasOption(Option.SHOW_HIDDEN_FRAMES) && - !fillCallerClassOnly(newMode) /* don't show hidden frames for getCallerClass */) + (mode & FILL_CLASS_REFS_ONLY) != FILL_CLASS_REFS_ONLY) newMode |= SHOW_HIDDEN_FRAMES; if (walker.hasLocalsOperandsOption()) newMode |= FILL_LIVE_STACK_FRAMES; return newMode; } - private boolean fillCallerClassOnly(int mode) { - return (mode|FILL_CLASS_REFS_ONLY) != FILL_CLASS_REFS_ONLY; - } /** * A callback method to consume the stack frames. This method is invoked * once stack walking begins (i.e. it is only invoked when walkFrames is called). @@ -179,7 +157,7 @@ final class StackStreamFactory { * * @return the number of consumed frames */ - protected abstract T consumeFrames(); + protected abstract R consumeFrames(); /** * Initialize FrameBuffer. Subclass should implement this method to @@ -252,7 +230,7 @@ final class StackStreamFactory { * Walks stack frames until {@link #consumeFrames} is done consuming * the frames it is interested in. */ - final T walk() { + final R walk() { checkState(NEW); try { // VM will need to stablize the stack before walking. It will invoke @@ -318,7 +296,7 @@ final class StackStreamFactory { } this.anchor = anchor; // set anchor for this bulk stack frame traversal - frameBuffer.setBatch(bufStartIndex, bufEndIndex); + frameBuffer.setBatch(depth, bufStartIndex, bufEndIndex); // traverse all frames and perform the action on the stack frames, if specified return consumeFrames(); @@ -381,15 +359,14 @@ final class StackStreamFactory { * If all fetched stack frames are traversed, AbstractStackWalker::fetchStackFrames will * fetch the next batch of stack frames to continue. */ - private T beginStackWalk() { + private R beginStackWalk() { // initialize buffers for VM to fill the stack frame info initFrameBuffer(); return callStackWalk(mode, 0, frameBuffer.curBatchFrameCount(), frameBuffer.startIndex(), - frameBuffer.classes, - frameBuffer.stackFrames); + frameBuffer.frames()); } /* @@ -404,8 +381,7 @@ final class StackStreamFactory { int endIndex = fetchStackFrames(mode, anchor, batchSize, startIndex, - frameBuffer.classes, - frameBuffer.stackFrames); + frameBuffer.frames()); if (isDebug) { System.out.format(" more stack walk requesting %d got %d to %d frames%n", batchSize, frameBuffer.startIndex(), endIndex); @@ -414,27 +390,26 @@ final class StackStreamFactory { if (numFrames == 0) { frameBuffer.freeze(); // done stack walking } else { - frameBuffer.setBatch(startIndex, endIndex); + frameBuffer.setBatch(depth, startIndex, endIndex); } return numFrames; } /** * Begins stack walking. This method anchors this frame and invokes - * AbstractStackWalker::doStackWalk after fetching the firt batch of stack frames. + * AbstractStackWalker::doStackWalk after fetching the first batch of stack frames. * * @param mode mode of stack walking * @param skipframes number of frames to be skipped before filling the frame buffer. * @param batchSize the batch size, max. number of elements to be filled in the frame buffers. * @param startIndex start index of the frame buffers to be filled. - * @param classes Classes buffer of the stack frames - * @param frames StackFrame buffer, or null + * @param frames Either a Class array, if mode is {@link #FILL_CLASS_REFS_ONLY} + * or a {@link StackFrameInfo} (or derivative) array otherwise. * @return Result of AbstractStackWalker::doStackWalk */ - private native T callStackWalk(long mode, int skipframes, + private native R callStackWalk(long mode, int skipframes, int batchSize, int startIndex, - Class[] classes, - StackFrame[] frames); + T[] frames); /** * Fetch the next batch of stack frames. @@ -443,185 +418,14 @@ final class StackStreamFactory { * @param anchor * @param batchSize the batch size, max. number of elements to be filled in the frame buffers. * @param startIndex start index of the frame buffers to be filled. - * @param classes Classes buffer of the stack frames - * @param frames StackFrame buffer, or null + * @param frames Either a Class array, if mode is {@link #FILL_CLASS_REFS_ONLY} + * or a {@link StackFrameInfo} (or derivative) array otherwise. * * @return the end index to the frame buffers */ private native int fetchStackFrames(long mode, long anchor, int batchSize, int startIndex, - Class[] classes, - StackFrame[] frames); - - - /* - * Frame buffer - * - * Each specialized AbstractStackWalker subclass may subclass the FrameBuffer. - */ - class FrameBuffer { - static final int START_POS = 2; // 0th and 1st elements are reserved - - // buffers for VM to fill stack frame info - int currentBatchSize; // current batch size - Class[] classes; // caller class for fast path - - StackFrame[] stackFrames; - - int origin; // index to the current traversed stack frame - int fence; // index to the last frame in the current batch - - FrameBuffer(int initialBatchSize) { - if (initialBatchSize < MIN_BATCH_SIZE) { - throw new IllegalArgumentException(initialBatchSize + " < minimum batch size: " + MIN_BATCH_SIZE); - } - this.origin = START_POS; - this.fence = 0; - this.currentBatchSize = initialBatchSize; - this.classes = new Class[currentBatchSize]; - } - - int curBatchFrameCount() { - return currentBatchSize-START_POS; - } - - /* - * Tests if this frame buffer is empty. All frames are fetched. - */ - final boolean isEmpty() { - return origin >= fence || (origin == START_POS && fence == 0); - } - - /* - * Freezes this frame buffer. The stack stream source is done fetching. - */ - final void freeze() { - origin = 0; - fence = 0; - } - - /* - * Tests if this frame buffer is active. It is inactive when - * it is done for traversal. All stack frames have been traversed. - */ - final boolean isActive() { - return origin > 0 && (fence == 0 || origin < fence || fence == currentBatchSize); - } - - /** - * Gets the class at the current frame and move to the next frame. - */ - final Class next() { - if (isEmpty()) { - throw new NoSuchElementException("origin=" + origin + " fence=" + fence); - } - Class c = classes[origin++]; - if (isDebug) { - int index = origin-1; - System.out.format(" next frame at %d: %s (origin %d fence %d)%n", index, - Objects.toString(c), index, fence); - } - return c; - } - - /** - * Gets the class at the current frame. - */ - final Class get() { - if (isEmpty()) { - throw new NoSuchElementException("origin=" + origin + " fence=" + fence); - } - return classes[origin]; - } - - /* - * Returns the index of the current frame. - */ - final int getIndex() { - return origin; - } - - /* - * Set the start and end index of a new batch of stack frames that have - * been filled in this frame buffer. - */ - final void setBatch(int startIndex, int endIndex) { - if (startIndex <= 0 || endIndex <= 0) - throw new IllegalArgumentException("startIndex=" + startIndex + " endIndex=" + endIndex); - - this.origin = startIndex; - this.fence = endIndex; - if (depth == 0 && fence > 0) { - // filter the frames due to the stack stream implementation - for (int i = START_POS; i < fence; i++) { - Class c = classes[i]; - if (isDebug) System.err.format(" frame %d: %s%n", i, c); - if (filterStackWalkImpl(c)) { - origin++; - } else { - break; - } - } - } - } - - /* - * Checks if the origin is the expected start index. - */ - final void check(int skipFrames) { - int index = skipFrames + START_POS; - if (origin != index) { - // stack walk must continue with the previous frame depth - throw new IllegalStateException("origin " + origin + " != " + index); - } - } - - // ------ subclass may override the following methods ------- - /** - * Resizes the buffers for VM to fill in the next batch of stack frames. - * The next batch will start at the given startIndex with the maximum number - * of elements. - * - *

Subclass may override this method to manage the allocated buffers. - * - * @param startIndex the start index for the first frame of the next batch to fill in. - * @param elements the number of elements for the next batch to fill in. - * - */ - void resize(int startIndex, int elements) { - if (!isActive()) - throw new IllegalStateException("inactive frame buffer can't be resized"); - - int size = startIndex+elements; - if (classes.length < size) { - // copy the elements in classes array to the newly allocated one. - // classes[0] is a Thread object - Class[] prev = classes; - classes = new Class[size]; - System.arraycopy(prev, 0, classes, 0, START_POS); - } - currentBatchSize = size; - } - - /* - * Returns the start index for this frame buffer is refilled. - * - * This implementation reuses the allocated buffer for the next batch - * of stack frames. For subclass to retain the fetched stack frames, - * it should override this method to return the index at which the frame - * should be filled in for the next batch. - */ - int startIndex() { - return START_POS; - } - - /** - * Returns next StackFrame object in the current batch of stack frames - */ - StackFrame nextStackFrame() { - throw new InternalError("should not reach here"); - } - } + T[] frames); } /* @@ -629,46 +433,66 @@ final class StackStreamFactory { * * This class implements Spliterator::forEachRemaining and Spliterator::tryAdvance. */ - static class StackFrameTraverser extends AbstractStackWalker + static class StackFrameTraverser extends AbstractStackWalker implements Spliterator { static { stackWalkImplClasses.add(StackFrameTraverser.class); } private static final int CHARACTERISTICS = Spliterator.ORDERED | Spliterator.IMMUTABLE; - class Buffer extends FrameBuffer { - Buffer(int initialBatchSize) { + + final class StackFrameBuffer extends FrameBuffer { + private StackFrameInfo[] stackFrames; + StackFrameBuffer(int initialBatchSize) { super(initialBatchSize); - this.stackFrames = new StackFrame[initialBatchSize]; + this.stackFrames = new StackFrameInfo[initialBatchSize]; for (int i = START_POS; i < initialBatchSize; i++) { stackFrames[i] = new StackFrameInfo(walker); } } @Override - void resize(int startIndex, int elements) { - super.resize(startIndex, elements); - - int size = startIndex+elements; - if (stackFrames.length < size) { - stackFrames = new StackFrame[size]; - } - for (int i = startIndex(); i < size; i++) { - stackFrames[i] = new StackFrameInfo(walker); - } + StackFrameInfo[] frames() { + return stackFrames; } @Override - StackFrame nextStackFrame() { + void resize(int startIndex, int elements) { + if (!isActive()) + throw new IllegalStateException("inactive frame buffer can't be resized"); + + assert startIndex == START_POS : + "bad start index " + startIndex + " expected " + START_POS; + + int size = startIndex+elements; + if (stackFrames.length < size) { + StackFrameInfo[] newFrames = new StackFrameInfo[size]; + // copy initial magic... + System.arraycopy(stackFrames, 0, newFrames, 0, startIndex); + stackFrames = newFrames; + } + for (int i = startIndex; i < size; i++) { + stackFrames[i] = new StackFrameInfo(walker); + } + currentBatchSize = size; + } + + @Override + StackFrameInfo nextStackFrame() { if (isEmpty()) { throw new NoSuchElementException("origin=" + origin + " fence=" + fence); } - StackFrame frame = stackFrames[origin]; + StackFrameInfo frame = stackFrames[origin]; origin++; return frame; } + + @Override + final Class at(int index) { + return stackFrames[index].declaringClass; + } } final Function, ? extends T> function; // callback @@ -693,7 +517,7 @@ final class StackStreamFactory { return null; } - StackFrame frame = frameBuffer.nextStackFrame(); + StackFrameInfo frame = frameBuffer.nextStackFrame(); depth++; return frame; } @@ -710,7 +534,7 @@ final class StackStreamFactory { @Override protected void initFrameBuffer() { - this.frameBuffer = new Buffer(getNextBatchSize()); + this.frameBuffer = new StackFrameBuffer(getNextBatchSize()); } @Override @@ -781,7 +605,7 @@ final class StackStreamFactory { * CallerClassFinder is specialized to return Class for each stack frame. * StackFrame is not requested. */ - static class CallerClassFinder extends AbstractStackWalker { + static final class CallerClassFinder extends AbstractStackWalker> { static { stackWalkImplClasses.add(CallerClassFinder.class); } @@ -790,6 +614,54 @@ final class StackStreamFactory { CallerClassFinder(StackWalker walker) { super(walker, FILL_CLASS_REFS_ONLY); + assert (mode & FILL_CLASS_REFS_ONLY) == FILL_CLASS_REFS_ONLY + : "mode should contain FILL_CLASS_REFS_ONLY"; + } + + final class ClassBuffer extends FrameBuffer> { + Class[] classes; // caller class for fast path + ClassBuffer(int batchSize) { + super(batchSize); + classes = new Class[batchSize]; + } + + @Override + Class[] frames() { return classes;} + + @Override + final Class at(int index) { return classes[index];} + + + // ------ subclass may override the following methods ------- + /** + * Resizes the buffers for VM to fill in the next batch of stack frames. + * The next batch will start at the given startIndex with the maximum number + * of elements. + * + *

Subclass may override this method to manage the allocated buffers. + * + * @param startIndex the start index for the first frame of the next batch to fill in. + * @param elements the number of elements for the next batch to fill in. + * + */ + @Override + void resize(int startIndex, int elements) { + if (!isActive()) + throw new IllegalStateException("inactive frame buffer can't be resized"); + + assert startIndex == START_POS : + "bad start index " + startIndex + " expected " + START_POS; + + int size = startIndex+elements; + if (classes.length < size) { + // copy the elements in classes array to the newly allocated one. + // classes[0] is a Thread object + Class[] prev = classes; + classes = new Class[size]; + System.arraycopy(prev, 0, classes, 0, startIndex); + } + currentBatchSize = size; + } } Class findCaller() { @@ -810,15 +682,15 @@ final class StackStreamFactory { if (isMethodHandleFrame(caller)) continue; frames[n++] = caller; } - - if (frames[1] == null) + if (frames[1] == null) { throw new IllegalStateException("no caller frame"); + } return n; } @Override protected void initFrameBuffer() { - this.frameBuffer = new FrameBuffer(getNextBatchSize()); + this.frameBuffer = new ClassBuffer(getNextBatchSize()); } @Override @@ -832,215 +704,64 @@ final class StackStreamFactory { } } - /* - * StackTrace caches all frames in the buffer. StackTraceElements are - * created lazily when Throwable::getStackTrace is called. - */ - static class StackTrace extends AbstractStackWalker { - static { - stackWalkImplClasses.add(StackTrace.class); - } - - class GrowableBuffer extends FrameBuffer { - GrowableBuffer(int initialBatchSize) { - super(initialBatchSize); - - this.stackFrames = new StackFrame[initialBatchSize]; - for (int i = START_POS; i < initialBatchSize; i++) { - stackFrames[i] = new StackFrameInfo(walker); - } - } - - /* - * Returns the next index to fill - */ - @Override - int startIndex() { - return origin; - } - - /** - * Initialize the buffers for VM to fill in the stack frame information. - * The next batch will start at the given startIndex to - * the length of the buffer. - */ - @Override - void resize(int startIndex, int elements) { - // Expand the frame buffer. - // Do not call super.resize that will reuse the filled elements - // in this frame buffer - int size = startIndex+elements; - if (classes.length < size) { - // resize the frame buffer - classes = Arrays.copyOf(classes, size); - stackFrames = Arrays.copyOf(stackFrames, size); - } - for (int i = startIndex; i < size; i++) { - stackFrames[i] = new StackFrameInfo(walker); - } - currentBatchSize = size; - } - - StackTraceElement get(int index) { - return new StackTraceElement(classes[index].getName(), "unknown", null, -1); - } - - /** - * Returns an array of StackTraceElement for all stack frames cached in - * this StackTrace object. - *

- * This method is intended for Throwable::getOurStackTrace use only. - */ - StackTraceElement[] toStackTraceElements() { - int startIndex = START_POS; - for (int i = startIndex; i < classes.length; i++) { - if (classes[i] != null && filterStackWalkImpl(classes[i])) { - startIndex++; - } else { - break; - } - } - - // VM fills in the method name, filename, line number info - StackFrameInfo.fillInStackFrames(0, stackFrames, startIndex, startIndex + depth); - - StackTraceElement[] stes = new StackTraceElement[depth]; - for (int i = startIndex, j = 0; i < classes.length && j < depth; i++, j++) { - if (isDebug) { - System.err.println("StackFrame: " + i + " " + stackFrames[i]); - } - stes[j] = stackFrames[i].toStackTraceElement(); - } - return stes; - } - } - - private static final int MAX_STACK_FRAMES = 1024; - private static final StackWalker STACKTRACE_WALKER = - StackWalker.newInstanceNoCheck(EnumSet.of(Option.SHOW_REFLECT_FRAMES)); - - private StackTraceElement[] stes; - static StackTrace dump() { - return new StackTrace(); - } - - static StackTrace dump(Throwable ex) { - return new StackTrace(ex); - } - - private StackTrace() { - this(STACKTRACE_WALKER, DEFAULT_MODE); - } - - /* - * Throwable::fillInStackTrace and of Throwable and subclasses - * are filtered in the VM. - */ - private StackTrace(Throwable ex) { - this(STACKTRACE_WALKER, FILTER_FILL_IN_STACKTRACE); // skip Throwable::init frames - if (isDebug) { - System.err.println("dump stack for " + ex.getClass().getName()); - } - } - - StackTrace(StackWalker walker, int mode) { - super(walker, mode, MAX_STACK_FRAMES); - - // snapshot the stack trace - walk(); - } - - @Override - protected Integer consumeFrames() { - // traverse all frames and perform the action on the stack frames, if specified - int n = 0; - while (n < maxDepth && nextFrame() != null) { - n++; - } - return n; - } - - @Override - protected void initFrameBuffer() { - this.frameBuffer = new GrowableBuffer(getNextBatchSize()); - } - - // TODO: implement better heuristic - @Override - protected int batchSize(int lastBatchFrameCount) { - // chunk size of VM backtrace is 32 - return lastBatchFrameCount == 0 ? 32 : 32; - } - - /** - * Returns an array of StackTraceElement for all stack frames cached in - * this StackTrace object. - *

- * This method is intended for Throwable::getOurStackTrace use only. - */ - synchronized StackTraceElement[] getStackTraceElements() { - if (stes == null) { - stes = ((GrowableBuffer) frameBuffer).toStackTraceElements(); - // release the frameBuffer memory - frameBuffer = null; - } - return stes; - } - - /* - * Prints stack trace to the given PrintStream. - * - * Further implementation could skip creating StackTraceElement objects - * print directly to the PrintStream. - */ - void printStackTrace(PrintStream s) { - StackTraceElement[] stes = getStackTraceElements(); - synchronized (s) { - s.println("Stack trace"); - for (StackTraceElement traceElement : stes) - s.println("\tat " + traceElement); - } - } - } - - static class LiveStackInfoTraverser extends StackFrameTraverser { + static final class LiveStackInfoTraverser extends StackFrameTraverser { static { stackWalkImplClasses.add(LiveStackInfoTraverser.class); } // VM will fill in all method info and live stack info directly in StackFrameInfo - class Buffer extends FrameBuffer { - Buffer(int initialBatchSize) { + final class LiveStackFrameBuffer extends FrameBuffer { + private LiveStackFrameInfo[] stackFrames; + LiveStackFrameBuffer(int initialBatchSize) { super(initialBatchSize); - this.stackFrames = new StackFrame[initialBatchSize]; + this.stackFrames = new LiveStackFrameInfo[initialBatchSize]; for (int i = START_POS; i < initialBatchSize; i++) { stackFrames[i] = new LiveStackFrameInfo(walker); } } @Override - void resize(int startIndex, int elements) { - super.resize(startIndex, elements); - int size = startIndex + elements; + LiveStackFrameInfo[] frames() { + return stackFrames; + } + @Override + void resize(int startIndex, int elements) { + if (!isActive()) { + throw new IllegalStateException("inactive frame buffer can't be resized"); + } + assert startIndex == START_POS : + "bad start index " + startIndex + " expected " + START_POS; + + int size = startIndex + elements; if (stackFrames.length < size) { - this.stackFrames = new StackFrame[size]; + LiveStackFrameInfo[] newFrames = new LiveStackFrameInfo[size]; + // copy initial magic... + System.arraycopy(stackFrames, 0, newFrames, 0, startIndex); + stackFrames = newFrames; } for (int i = startIndex(); i < size; i++) { stackFrames[i] = new LiveStackFrameInfo(walker); } + + currentBatchSize = size; } @Override - StackFrame nextStackFrame() { + LiveStackFrameInfo nextStackFrame() { if (isEmpty()) { throw new NoSuchElementException("origin=" + origin + " fence=" + fence); } - StackFrame frame = stackFrames[origin]; + LiveStackFrameInfo frame = stackFrames[origin]; origin++; return frame; } + + @Override + final Class at(int index) { + return stackFrames[index].declaringClass; + } } LiveStackInfoTraverser(StackWalker walker, @@ -1050,7 +771,183 @@ final class StackStreamFactory { @Override protected void initFrameBuffer() { - this.frameBuffer = new Buffer(getNextBatchSize()); + this.frameBuffer = new LiveStackFrameBuffer(getNextBatchSize()); + } + } + + /* + * Frame buffer + * + * Each specialized AbstractStackWalker subclass may subclass the FrameBuffer. + */ + static abstract class FrameBuffer { + static final int START_POS = 2; // 0th and 1st elements are reserved + + // buffers for VM to fill stack frame info + int currentBatchSize; // current batch size + int origin; // index to the current traversed stack frame + int fence; // index to the last frame in the current batch + + FrameBuffer(int initialBatchSize) { + if (initialBatchSize < MIN_BATCH_SIZE) { + throw new IllegalArgumentException(initialBatchSize + + " < minimum batch size: " + MIN_BATCH_SIZE); + } + this.origin = START_POS; + this.fence = 0; + this.currentBatchSize = initialBatchSize; + } + + /** + * Returns an array of frames that may be used to store frame objects + * when walking the stack. + * + * May be an array of {@code Class} if the {@code AbstractStackWalker} + * mode is {@link #FILL_CLASS_REFS_ONLY}, or an array of + * {@link StackFrameInfo} (or derivative) array otherwise. + * + * @return An array of frames that may be used to store frame objects + * when walking the stack. Must not be null. + */ + abstract F[] frames(); // must not return null + + /** + * Resizes the buffers for VM to fill in the next batch of stack frames. + * The next batch will start at the given startIndex with the maximum number + * of elements. + * + *

Subclass may override this method to manage the allocated buffers. + * + * @param startIndex the start index for the first frame of the next batch to fill in. + * @param elements the number of elements for the next batch to fill in. + * + */ + abstract void resize(int startIndex, int elements); + + /** + * Return the class at the given position in the current batch. + * @param index the position of the frame. + * @return the class at the given position in the current batch. + */ + abstract Class at(int index); + + // ------ subclass may override the following methods ------- + + /* + * Returns the start index for this frame buffer is refilled. + * + * This implementation reuses the allocated buffer for the next batch + * of stack frames. For subclass to retain the fetched stack frames, + * it should override this method to return the index at which the frame + * should be filled in for the next batch. + */ + int startIndex() { + return START_POS; + } + + /** + * Returns next StackFrame object in the current batch of stack frames + */ + F nextStackFrame() { + throw new InternalError("should not reach here"); + } + + // ------ FrameBuffer implementation ------ + + final int curBatchFrameCount() { + return currentBatchSize-START_POS; + } + + /* + * Tests if this frame buffer is empty. All frames are fetched. + */ + final boolean isEmpty() { + return origin >= fence || (origin == START_POS && fence == 0); + } + + /* + * Freezes this frame buffer. The stack stream source is done fetching. + */ + final void freeze() { + origin = 0; + fence = 0; + } + + /* + * Tests if this frame buffer is active. It is inactive when + * it is done for traversal. All stack frames have been traversed. + */ + final boolean isActive() { + return origin > 0 && (fence == 0 || origin < fence || fence == currentBatchSize); + } + + /** + * Gets the class at the current frame and move to the next frame. + */ + final Class next() { + if (isEmpty()) { + throw new NoSuchElementException("origin=" + origin + " fence=" + fence); + } + Class c = at(origin); + origin++; + if (isDebug) { + int index = origin-1; + System.out.format(" next frame at %d: %s (origin %d fence %d)%n", index, + Objects.toString(c), index, fence); + } + return c; + } + + /** + * Gets the class at the current frame. + */ + final Class get() { + if (isEmpty()) { + throw new NoSuchElementException("origin=" + origin + " fence=" + fence); + } + return at(origin); + } + + /* + * Returns the index of the current frame. + */ + final int getIndex() { + return origin; + } + + /* + * Set the start and end index of a new batch of stack frames that have + * been filled in this frame buffer. + */ + final void setBatch(int depth, int startIndex, int endIndex) { + if (startIndex <= 0 || endIndex <= 0) + throw new IllegalArgumentException("startIndex=" + startIndex + " endIndex=" + endIndex); + + this.origin = startIndex; + this.fence = endIndex; + if (depth == 0 && fence > 0) { + // filter the frames due to the stack stream implementation + for (int i = START_POS; i < fence; i++) { + Class c = at(i); + if (isDebug) System.err.format(" frame %d: %s%n", i, c); + if (filterStackWalkImpl(c)) { + origin++; + } else { + break; + } + } + } + } + + /* + * Checks if the origin is the expected start index. + */ + final void check(int skipFrames) { + int index = skipFrames + START_POS; + if (origin != index) { + // stack walk must continue with the previous frame depth + throw new IllegalStateException("origin " + origin + " != " + index); + } } } diff --git a/jdk/src/java.base/share/classes/java/lang/Thread.java b/jdk/src/java.base/share/classes/java/lang/Thread.java index eb47a05427d..39afad9795f 100644 --- a/jdk/src/java.base/share/classes/java/lang/Thread.java +++ b/jdk/src/java.base/share/classes/java/lang/Thread.java @@ -1388,7 +1388,7 @@ class Thread implements Runnable { * This method is used only for debugging. */ public static void dumpStack() { - StackStreamFactory.makeStackTrace().printStackTrace(System.err); + new Exception("Stack trace").printStackTrace(); } /** @@ -1610,8 +1610,7 @@ class Thread implements Runnable { } return stackTrace; } else { - // Don't need JVM help for current thread - return StackStreamFactory.makeStackTrace().getStackTraceElements(); + return (new Exception()).getStackTrace(); } } diff --git a/jdk/src/java.base/share/classes/java/lang/Throwable.java b/jdk/src/java.base/share/classes/java/lang/Throwable.java index 72a3455e637..a609719c9cd 100644 --- a/jdk/src/java.base/share/classes/java/lang/Throwable.java +++ b/jdk/src/java.base/share/classes/java/lang/Throwable.java @@ -785,11 +785,7 @@ public class Throwable implements Serializable { public synchronized Throwable fillInStackTrace() { if (stackTrace != null || backtrace != null /* Out of protocol state */ ) { - if (backtrace == null && StackStreamFactory.useStackTrace(this)) { - backtrace = StackStreamFactory.makeStackTrace(this); - } else { - fillInStackTrace(0); - } + fillInStackTrace(0); stackTrace = UNASSIGNED_STACK; } return this; @@ -830,15 +826,11 @@ public class Throwable implements Serializable { // backtrace if this is the first call to this method if (stackTrace == UNASSIGNED_STACK || (stackTrace == null && backtrace != null) /* Out of protocol state */) { - if (backtrace instanceof StackStreamFactory.StackTrace) { - stackTrace = ((StackStreamFactory.StackTrace)backtrace).getStackTraceElements(); - } else { - stackTrace = new StackTraceElement[depth]; - for (int i = 0; i < depth; i++) { - stackTrace[i] = new StackTraceElement(); - } - getStackTraceElements(stackTrace); + stackTrace = new StackTraceElement[depth]; + for (int i = 0; i < depth; i++) { + stackTrace[i] = new StackTraceElement(); } + getStackTraceElements(stackTrace); } else if (stackTrace == null) { return UNASSIGNED_STACK; } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java b/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java index da91db90da3..5945bcc1f85 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java @@ -1132,6 +1132,10 @@ import java.util.Objects; public Object newMemberName() { return new MemberName(); } + public String getName(Object mname) { + MemberName memberName = (MemberName)mname; + return memberName.getName(); + } }); } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java index 776c24dc95a..1a4aba5d79b 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java @@ -30,4 +30,9 @@ public interface JavaLangInvokeAccess { * Create a new MemberName instance */ Object newMemberName(); + + /** + * Returns the name for the given MemberName + */ + String getName(Object mname); } diff --git a/jdk/src/java.base/share/native/include/jvm.h b/jdk/src/java.base/share/native/include/jvm.h index c5fc7e91178..2011e58352a 100644 --- a/jdk/src/java.base/share/native/include/jvm.h +++ b/jdk/src/java.base/share/native/include/jvm.h @@ -179,7 +179,6 @@ JVM_GetStackTraceElements(JNIEnv *env, jobject throwable, jobjectArray elements) */ enum { JVM_STACKWALK_FILL_CLASS_REFS_ONLY = 0x2, - JVM_STACKWALK_FILTER_FILL_IN_STACK_TRACE = 0x10, JVM_STACKWALK_SHOW_HIDDEN_FRAMES = 0x20, JVM_STACKWALK_FILL_LIVE_STACK_FRAMES = 0x100 }; @@ -187,23 +186,15 @@ enum { JNIEXPORT jobject JNICALL JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jint skip_frames, jint frame_count, jint start_index, - jobjectArray classes, jobjectArray frames); JNIEXPORT jint JNICALL JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jlong anchor, jint frame_count, jint start_index, - jobjectArray classes, jobjectArray frames); JNIEXPORT void JNICALL -JVM_FillStackFrames(JNIEnv* env, jclass cls, - jint start_index, - jobjectArray stackFrames, - jint from_index, jint toIndex); - -JNIEXPORT void JNICALL -JVM_SetMethodInfo(JNIEnv* env, jobject frame); +JVM_ToStackTraceElement(JNIEnv* env, jobject frame, jobject stackElement); JNIEXPORT jobjectArray JNICALL JVM_GetVmArguments(JNIEnv *env); diff --git a/jdk/src/java.base/share/native/libjava/StackFrameInfo.c b/jdk/src/java.base/share/native/libjava/StackFrameInfo.c index f7930a45924..41c021a2027 100644 --- a/jdk/src/java.base/share/native/libjava/StackFrameInfo.c +++ b/jdk/src/java.base/share/native/libjava/StackFrameInfo.c @@ -38,22 +38,10 @@ /* * Class: java_lang_StackFrameInfo - * Method: fillInStackFrames - * Signature: (I[Ljava/lang/Object;[Ljava/lang/Object;II)V + * Method: toStackTraceElement0 + * Signature: (Ljava/lang/StackTraceElement;)V */ -JNIEXPORT void JNICALL Java_java_lang_StackFrameInfo_fillInStackFrames - (JNIEnv *env, jclass dummy, jint startIndex, - jobjectArray stackFrames, jint fromIndex, jint toIndex) { - JVM_FillStackFrames(env, dummy, startIndex, - stackFrames, fromIndex, toIndex); -} - -/* - * Class: java_lang_StackFrameInfo - * Method: setMethodInfo - * Signature: (Ljava/lang/Class;)V - */ -JNIEXPORT void JNICALL Java_java_lang_StackFrameInfo_setMethodInfo - (JNIEnv *env, jobject stackframeinfo) { - JVM_SetMethodInfo(env, stackframeinfo); +JNIEXPORT void JNICALL Java_java_lang_StackFrameInfo_toStackTraceElement0 + (JNIEnv *env, jobject stackframeinfo, jobject stacktraceinfo) { + JVM_ToStackTraceElement(env, stackframeinfo, stacktraceinfo); } diff --git a/jdk/src/java.base/share/native/libjava/StackStreamFactory.c b/jdk/src/java.base/share/native/libjava/StackStreamFactory.c index c23e9d04918..099b09b3cc6 100644 --- a/jdk/src/java.base/share/native/libjava/StackStreamFactory.c +++ b/jdk/src/java.base/share/native/libjava/StackStreamFactory.c @@ -45,7 +45,6 @@ JNIEXPORT jboolean JNICALL Java_java_lang_StackStreamFactory_checkStackWalkModes (JNIEnv *env, jclass dummy) { return JVM_STACKWALK_FILL_CLASS_REFS_ONLY == java_lang_StackStreamFactory_FILL_CLASS_REFS_ONLY && - JVM_STACKWALK_FILTER_FILL_IN_STACK_TRACE == java_lang_StackStreamFactory_FILTER_FILL_IN_STACKTRACE && JVM_STACKWALK_SHOW_HIDDEN_FRAMES == java_lang_StackStreamFactory_SHOW_HIDDEN_FRAMES && JVM_STACKWALK_FILL_LIVE_STACK_FRAMES == java_lang_StackStreamFactory_FILL_LIVE_STACK_FRAMES; } @@ -53,26 +52,26 @@ JNIEXPORT jboolean JNICALL Java_java_lang_StackStreamFactory_checkStackWalkModes /* * Class: java_lang_StackStreamFactory_AbstractStackWalker * Method: callStackWalk - * Signature: (JIII[Ljava/lang/Class;[Ljava/lang/StackWalker/StackFrame;)Ljava/lang/Object; + * Signature: (JIII[Ljava/lang/Object;)Ljava/lang/Object; */ JNIEXPORT jobject JNICALL Java_java_lang_StackStreamFactory_00024AbstractStackWalker_callStackWalk (JNIEnv *env, jobject stackstream, jlong mode, jint skipFrames, jint batchSize, jint startIndex, - jobjectArray classes, jobjectArray frames) + jobjectArray frames) { return JVM_CallStackWalk(env, stackstream, mode, skipFrames, batchSize, - startIndex, classes, frames); + startIndex, frames); } /* * Class: java_lang_StackStreamFactory_AbstractStackWalker * Method: fetchStackFrames - * Signature: (JJII[Ljava/lang/Class;[Ljava/lang/StackWalker/StackFrame;)I + * Signature: (JJII[Ljava/lang/Object;)I */ JNIEXPORT jint JNICALL Java_java_lang_StackStreamFactory_00024AbstractStackWalker_fetchStackFrames (JNIEnv *env, jobject stackstream, jlong mode, jlong anchor, jint batchSize, jint startIndex, - jobjectArray classes, jobjectArray frames) + jobjectArray frames) { return JVM_MoreStackWalk(env, stackstream, mode, anchor, batchSize, - startIndex, classes, frames); + startIndex, frames); } diff --git a/jdk/test/java/lang/StackWalker/DumpStackTest.java b/jdk/test/java/lang/StackWalker/DumpStackTest.java index 667e325a8f0..2aa97d7c93e 100644 --- a/jdk/test/java/lang/StackWalker/DumpStackTest.java +++ b/jdk/test/java/lang/StackWalker/DumpStackTest.java @@ -28,9 +28,6 @@ * This test should also been run against jdk9 successfully except of * VM option MemberNameInStackFrame. * @run main/othervm DumpStackTest - * @run main/othervm -Dstackwalk.newThrowable=false DumpStackTest - * @run main/othervm -Dstackwalk.newThrowable=true -XX:-MemberNameInStackFrame DumpStackTest - * @run main/othervm -Dstackwalk.newThrowable=true -XX:+MemberNameInStackFrame DumpStackTest */ import java.lang.invoke.MethodHandle; diff --git a/jdk/test/java/lang/StackWalker/GetCallerClassTest.java b/jdk/test/java/lang/StackWalker/GetCallerClassTest.java index 53a3f70c52a..8276d721087 100644 --- a/jdk/test/java/lang/StackWalker/GetCallerClassTest.java +++ b/jdk/test/java/lang/StackWalker/GetCallerClassTest.java @@ -25,8 +25,7 @@ * @test * @bug 8140450 * @summary Basic test for StackWalker.getCallerClass() - * @run main/othervm -XX:-MemberNameInStackFrame GetCallerClassTest - * @run main/othervm -XX:+MemberNameInStackFrame GetCallerClassTest + * @run main/othervm GetCallerClassTest * @run main/othervm GetCallerClassTest sm */ diff --git a/jdk/test/java/lang/StackWalker/StackWalkTest.java b/jdk/test/java/lang/StackWalker/StackWalkTest.java index 7bbcc6150f8..5c4782fb46a 100644 --- a/jdk/test/java/lang/StackWalker/StackWalkTest.java +++ b/jdk/test/java/lang/StackWalker/StackWalkTest.java @@ -44,10 +44,6 @@ import jdk.testlibrary.RandomFactory; * @run main/othervm/java.security.policy=stackwalktest.policy StackWalkTest * @run main/othervm StackWalkTest -random:50 * @run main/othervm/java.security.policy=stackwalktest.policy StackWalkTest -random:50 - * @run main/othervm -XX:-MemberNameInStackFrame -Dstackwalk.newThrowable=false StackWalkTest -random:50 - * @run main/othervm -XX:-MemberNameInStackFrame -Dstackwalk.newThrowable=true StackWalkTest -random:50 - * @run main/othervm -XX:+MemberNameInStackFrame -Dstackwalk.newThrowable=false StackWalkTest -random:50 - * @run main/othervm -XX:+MemberNameInStackFrame -Dstackwalk.newThrowable=true StackWalkTest -random:50 * @author danielfuchs, bchristi * @key randomness */ diff --git a/jdk/test/java/lang/StackWalker/VerifyStackTrace.java b/jdk/test/java/lang/StackWalker/VerifyStackTrace.java index b5f8653bc1b..d9cfcf6aba5 100644 --- a/jdk/test/java/lang/StackWalker/VerifyStackTrace.java +++ b/jdk/test/java/lang/StackWalker/VerifyStackTrace.java @@ -40,8 +40,7 @@ import static java.lang.StackWalker.Option.*; * @summary Verify stack trace information obtained with respect to StackWalker * options, when the stack contains lambdas, method handle invoke * virtual calls, and reflection. - * @run main/othervm -XX:-MemberNameInStackFrame VerifyStackTrace - * @run main/othervm -XX:+MemberNameInStackFrame VerifyStackTrace + * @run main/othervm VerifyStackTrace * @run main/othervm/java.security.policy=stackwalk.policy VerifyStackTrace * @author danielfuchs */ From a64d3028c346b5ae1b8c0eba04f18bc6367173b3 Mon Sep 17 00:00:00 2001 From: Serguei Spitsyn Date: Tue, 12 Apr 2016 00:43:57 -0700 Subject: [PATCH 4/6] 8153902: remove com/sun/jdi/InterfaceMethodsTest.java, com/sun/jdi/InvokeTest.java from ProblemList Enable the jdi tests again Reviewed-by: sundar --- jdk/test/ProblemList.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index cec532e0634..11e567fc1fa 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -333,10 +333,6 @@ com/sun/jdi/CatchPatternTest.sh 8068645 generic- com/sun/jdi/GetLocalVariables4Test.sh 8067354 windows-all -com/sun/jdi/InterfaceMethodsTest.java 8152586 generic-all - -com/sun/jdi/InvokeTest.java 8152586 generic-all - ############################################################################ # jdk_util From 17344961d2026a3567c5e638cd6eef6a4efb9cda Mon Sep 17 00:00:00 2001 From: Dmitry Samersoff Date: Wed, 13 Apr 2016 12:10:42 +0300 Subject: [PATCH 5/6] 8153856: com/sun/jdi/WatchFramePop.sh fails with exit code 1 Fixed sed expression in a test Reviewed-by: sla --- jdk/test/com/sun/jdi/ShellScaffold.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/test/com/sun/jdi/ShellScaffold.sh b/jdk/test/com/sun/jdi/ShellScaffold.sh index ed5f79e58ac..eb7e6b45351 100644 --- a/jdk/test/com/sun/jdi/ShellScaffold.sh +++ b/jdk/test/com/sun/jdi/ShellScaffold.sh @@ -924,7 +924,7 @@ dojstack() # If jstack exists, so will jps # Show stack traces of jdb and debuggee as a possible debugging aid. jdbCmd=`$jdk/bin/jps -v | $grep $jdbKeyword` - realJdbPid=`echo "$jdbCmd" | sed -e 's@ TTY.*@@'` + realJdbPid=`echo "$jdbCmd" | sed -e 's@ .*@@'` if [ ! -z "$realJdbPid" ] ; then echo "-- jdb process info ----------------------" >&2 echo " $jdbCmd" >&2 From a98a7da445dc5f085a3a530ab7949ea8807e1a42 Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Wed, 13 Apr 2016 11:13:15 +0200 Subject: [PATCH 6/6] 8154087: Fix AIX and Linux/ppc64le after the integration of the new hotspot build Reviewed-by: erikj, goetz --- jdk/make/lib/Awt2dLibraries.gmk | 7 +++++++ jdk/make/lib/CoreLibraries.gmk | 1 + jdk/make/lib/NioLibraries.gmk | 1 + 3 files changed, 9 insertions(+) diff --git a/jdk/make/lib/Awt2dLibraries.gmk b/jdk/make/lib/Awt2dLibraries.gmk index d6ba6443bf2..b8941c0b105 100644 --- a/jdk/make/lib/Awt2dLibraries.gmk +++ b/jdk/make/lib/Awt2dLibraries.gmk @@ -370,6 +370,7 @@ ifeq ($(findstring $(OPENJDK_TARGET_OS),windows macosx),) OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_XAWT_CFLAGS) \ $(X_CFLAGS), \ + WARNINGS_AS_ERRORS_xlc := false, \ DISABLED_WARNINGS_gcc := type-limits pointer-to-int-cast \ deprecated-declarations unused-result maybe-uninitialized format \ format-security int-to-pointer-cast parentheses, \ @@ -582,6 +583,7 @@ ifeq ($(BUILD_HEADLESS), true) $(CUPS_CFLAGS) \ $(X_CFLAGS) \ $(LIBAWT_HEADLESS_CFLAGS), \ + DISABLED_WARNINGS_xlc := 1506-356, \ DISABLED_WARNINGS_gcc := maybe-uninitialized int-to-pointer-cast, \ DISABLED_WARNINGS_solstudio := E_DECLARATION_IN_CODE \ E_EMPTY_TRANSLATION_UNIT, \ @@ -598,6 +600,10 @@ ifeq ($(BUILD_HEADLESS), true) OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libawt_headless, \ )) + # AIX warning explanation: + # 1506-356 : (W) Compilation unit is empty. + # This happens during the headless build + $(BUILD_LIBAWT_HEADLESS): $(BUILD_LIBAWT) TARGETS += $(BUILD_LIBAWT_HEADLESS) @@ -695,6 +701,7 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBFONTMANAGER, \ CXXFLAGS := $(CXXFLAGS_JDKLIB) $(LIBFONTMANAGER_CFLAGS), \ OPTIMIZATION := $(LIBFONTMANAGER_OPTIMIZATION), \ CFLAGS_windows = -DCC_NOEX, \ + WARNINGS_AS_ERRORS_xlc := false, \ DISABLED_WARNINGS_gcc := sign-compare int-to-pointer-cast \ type-limits missing-field-initializers, \ DISABLED_WARNINGS_CXX_gcc := reorder delete-non-virtual-dtor strict-overflow \ diff --git a/jdk/make/lib/CoreLibraries.gmk b/jdk/make/lib/CoreLibraries.gmk index bccf46bb824..e4a24e47904 100644 --- a/jdk/make/lib/CoreLibraries.gmk +++ b/jdk/make/lib/CoreLibraries.gmk @@ -146,6 +146,7 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBJAVA, \ $(LIBJAVA_CFLAGS), \ System.c_CFLAGS := $(VERSION_CFLAGS), \ jdk_util.c_CFLAGS := $(VERSION_CFLAGS), \ + WARNINGS_AS_ERRORS_xlc := false, \ DISABLED_WARNINGS_gcc := unused-result, \ DISABLED_WARNINGS_solstudio := E_STATEMENT_NOT_REACHED, \ MAPFILE := $(LIBJAVA_MAPFILE), \ diff --git a/jdk/make/lib/NioLibraries.gmk b/jdk/make/lib/NioLibraries.gmk index de2cdea0727..203447c513f 100644 --- a/jdk/make/lib/NioLibraries.gmk +++ b/jdk/make/lib/NioLibraries.gmk @@ -70,6 +70,7 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBNIO, \ SRC := $(BUILD_LIBNIO_SRC), \ EXCLUDE_FILES := $(BUILD_LIBNIO_EXFILES), \ OPTIMIZATION := HIGH, \ + WARNINGS_AS_ERRORS_xlc := false, \ CFLAGS := $(CFLAGS_JDKLIB) \ $(BUILD_LIBNIO_CFLAGS), \ MAPFILE := $(BUILD_LIBNIO_MAPFILE), \