OpenJDK / bsd-port / jdk9 / jdk
changeset 13196:cc055d6f9173
Merge
author | ctornqvi |
---|---|
date | Tue, 24 Nov 2015 18:32:38 +0000 |
parents | ff9ac07019d6 bab4cdd396ed |
children | 3e4036277d67 |
files | src/java.base/share/classes/java/lang/LiveStackFrame.java src/java.base/share/classes/java/lang/LiveStackFrameInfo.java src/java.base/share/classes/java/lang/StackFrameInfo.java src/java.base/share/classes/java/lang/StackFramePermission.java src/java.base/share/classes/java/lang/StackStreamFactory.java src/java.base/share/classes/java/lang/StackWalker.java src/java.base/share/classes/java/lang/Thread.java src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java src/java.base/share/native/libjava/StackFrameInfo.c src/java.base/share/native/libjava/StackStreamFactory.c test/java/lang/StackWalker/AcrossThreads.java test/java/lang/StackWalker/Basic.java test/java/lang/StackWalker/CallerFromMain.java test/java/lang/StackWalker/DumpStackTest.java test/java/lang/StackWalker/EmbeddedStackWalkTest.java test/java/lang/StackWalker/GetCallerClassTest.java test/java/lang/StackWalker/HiddenFrames.java test/java/lang/StackWalker/LocalsAndOperands.java test/java/lang/StackWalker/MultiThreadStackWalk.java test/java/lang/StackWalker/SanityTest.java test/java/lang/StackWalker/SecurityExceptions.java test/java/lang/StackWalker/StackRecorderUtil.java test/java/lang/StackWalker/StackStreamState.java test/java/lang/StackWalker/StackStreamTest.java test/java/lang/StackWalker/StackWalkTest.java test/java/lang/StackWalker/VerifyStackTrace.java test/java/lang/StackWalker/WalkFunction.java test/java/lang/StackWalker/noperms.policy test/java/lang/StackWalker/stackwalk.policy test/java/lang/StackWalker/stackwalktest.policy |
diffstat | 39 files changed, 98 insertions(+), 5808 deletions(-) [+] |
line wrap: on
line diff
--- a/make/mapfiles/libjava/mapfile-vers Tue Nov 24 11:50:20 2015 +0000 +++ b/make/mapfiles/libjava/mapfile-vers Tue Nov 24 18:32:38 2015 +0000 @@ -138,14 +138,9 @@ Java_java_lang_Double_longBitsToDouble; Java_java_lang_Double_doubleToRawLongBits; Java_java_lang_reflect_Proxy_defineClass0; + Java_java_lang_Shutdown_runAllFinalizers; Java_java_lang_Float_intBitsToFloat; Java_java_lang_Float_floatToRawIntBits; - Java_java_lang_StackFrameInfo_fillInStackFrames; - Java_java_lang_StackFrameInfo_setMethodInfo; - Java_java_lang_StackStreamFactory_checkStackWalkModes; - Java_java_lang_StackStreamFactory_00024AbstractStackWalker_callStackWalk; - Java_java_lang_StackStreamFactory_00024AbstractStackWalker_fetchStackFrames; - Java_java_lang_Shutdown_runAllFinalizers; Java_java_lang_StrictMath_IEEEremainder; Java_java_lang_StrictMath_acos; Java_java_lang_StrictMath_asin;
--- a/src/java.base/share/classes/java/lang/LiveStackFrame.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,226 +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. - */ -package java.lang; - -import java.lang.StackWalker.StackFrame; -import java.util.EnumSet; -import java.util.Set; - -import static java.lang.StackWalker.ExtendedOption.LOCALS_AND_OPERANDS; - -/** - * <em>UNSUPPORTED</em> This interface is intended to be package-private - * or move to an internal package.<p> - * - * {@code LiveStackFrame} represents a frame storing data and partial results. - * Each frame has its own array of local variables (JVMS section 2.6.1), - * its own operand stack (JVMS section 2.6.2) for a method invocation. - * - * @jvms 2.6 Frames - */ -/* package-private */ -interface LiveStackFrame extends StackFrame { - /** - * Return the monitors held by this stack frame. This method returns - * an empty array if no monitor is held by this stack frame. - * - * @return the monitors held by this stack frames - */ - public Object[] getMonitors(); - - /** - * Gets the local variable array of this stack frame. - * - * <p>A single local variable can hold a value of type boolean, byte, char, - * short, int, float, reference or returnAddress. A pair of local variables - * can hold a value of type long or double. In other words, - * a value of type long or type double occupies two consecutive local - * variables. For a value of primitive type, the element in the - * local variable array is an {@link PrimitiveValue} object; - * otherwise, the element is an {@code Object}. - * - * @return the local variable array of this stack frame. - */ - public Object[] getLocals(); - - /** - * Gets the operand stack of this stack frame. - * - * <p> - * The 0-th element of the returned array represents the top of the operand stack. - * This method returns an empty array if the operand stack is empty. - * - * <p>Each entry on the operand stack can hold a value of any Java Virtual - * Machine Type. - * For a value of primitive type, the element in the returned array is - * an {@link PrimitiveValue} object; otherwise, the element is the {@code Object} - * on the operand stack. - * - * @return the operand stack of this stack frame. - */ - public Object[] getStack(); - - /** - * <em>UNSUPPORTED</em> This interface is intended to be package-private - * or move to an internal package.<p> - * - * Represents a local variable or an entry on the operand whose value is - * of primitive type. - */ - public abstract class PrimitiveValue { - /** - * Returns the base type of this primitive value, one of - * {@code B, D, C, F, I, J, S, Z}. - * - * @return Name of a base type - * @jvms table 4.3-A - */ - abstract char type(); - - /** - * Returns the boolean value if this primitive value is of type boolean. - * @return the boolean value if this primitive value is of type boolean. - * - * @throws UnsupportedOperationException if this primitive value is not - * of type boolean. - */ - public boolean booleanValue() { - throw new UnsupportedOperationException("this primitive of type " + type()); - } - - /** - * Returns the int value if this primitive value is of type int. - * @return the int value if this primitive value is of type int. - * - * @throws UnsupportedOperationException if this primitive value is not - * of type int. - */ - public int intValue() { - throw new UnsupportedOperationException("this primitive of type " + type()); - } - - /** - * Returns the long value if this primitive value is of type long. - * @return the long value if this primitive value is of type long. - * - * @throws UnsupportedOperationException if this primitive value is not - * of type long. - */ - public long longValue() { - throw new UnsupportedOperationException("this primitive of type " + type()); - } - - /** - * Returns the char value if this primitive value is of type char. - * @return the char value if this primitive value is of type char. - * - * @throws UnsupportedOperationException if this primitive value is not - * of type char. - */ - public char charValue() { - throw new UnsupportedOperationException("this primitive of type " + type()); - } - - /** - * Returns the byte value if this primitive value is of type byte. - * @return the byte value if this primitive value is of type byte. - * - * @throws UnsupportedOperationException if this primitive value is not - * of type byte. - */ - public byte byteValue() { - throw new UnsupportedOperationException("this primitive of type " + type()); - } - - /** - * Returns the short value if this primitive value is of type short. - * @return the short value if this primitive value is of type short. - * - * @throws UnsupportedOperationException if this primitive value is not - * of type short. - */ - public short shortValue() { - throw new UnsupportedOperationException("this primitive of type " + type()); - } - - /** - * Returns the float value if this primitive value is of type float. - * @return the float value if this primitive value is of type float. - * - * @throws UnsupportedOperationException if this primitive value is not - * of type float. - */ - public float floatValue() { - throw new UnsupportedOperationException("this primitive of type " + type()); - } - - /** - * Returns the double value if this primitive value is of type double. - * @return the double value if this primitive value is of type double. - * - * @throws UnsupportedOperationException if this primitive value is not - * of type double. - */ - public double doubleValue() { - throw new UnsupportedOperationException("this primitive of type " + type()); - } - } - - - /** - * Gets {@code StackWalker} that can get locals and operands. - * - * @throws SecurityException if the security manager is present and - * denies access to {@code RuntimePermission("liveStackFrames")} - */ - public static StackWalker getStackWalker() { - return getStackWalker(EnumSet.noneOf(StackWalker.Option.class)); - } - - /** - * Gets a {@code StackWalker} instance with the given options specifying - * the stack frame information it can access, and which will traverse at most - * the given {@code maxDepth} number of stack frames. If no option is - * specified, this {@code StackWalker} obtains the method name and - * the class name with all - * {@linkplain StackWalker.Option#SHOW_HIDDEN_FRAMES hidden frames} skipped. - * The returned {@code StackWalker} can get locals and operands. - * - * @param options stack walk {@link StackWalker.Option options} - * - * @throws SecurityException if the security manager is present and - * it denies access to {@code RuntimePermission("liveStackFrames")}; or - * or if the given {@code options} contains - * {@link StackWalker.Option#RETAIN_CLASS_REFERENCE Option.RETAIN_CLASS_REFERENCE} - * and it denies access to {@code StackFramePermission("retainClassReference")}. - */ - public static StackWalker getStackWalker(Set<StackWalker.Option> options) { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new RuntimePermission("liveStackFrames")); - } - return StackWalker.newInstance(options, LOCALS_AND_OPERANDS); - } -}
--- a/src/java.base/share/classes/java/lang/LiveStackFrameInfo.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,271 +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. - */ -package java.lang; - -import java.lang.StackWalker.Option; -import java.util.EnumSet; -import java.util.Set; - -import static java.lang.StackWalker.ExtendedOption.*; - -final class LiveStackFrameInfo extends StackFrameInfo implements LiveStackFrame { - private static Object[] EMPTY_ARRAY = new Object[0]; - - LiveStackFrameInfo(StackWalker walker) { - super(walker); - } - - // These fields are initialized by the VM if ExtendedOption.LOCALS_AND_OPERANDS is set - private Object[] monitors = EMPTY_ARRAY; - private Object[] locals = EMPTY_ARRAY; - private Object[] operands = EMPTY_ARRAY; - - @Override - public Object[] getMonitors() { - return monitors; - } - - @Override - public Object[] getLocals() { - return locals; - } - - @Override - public Object[] getStack() { - return operands; - } - - /* - * Convert primitive value to {@code Primitive} object to represent - * a local variable or an element on the operand stack of primitive type. - */ - static PrimitiveValue asPrimitive(boolean value) { - return new BooleanPrimitive(value); - } - - static PrimitiveValue asPrimitive(int value) { - return new IntPrimitive(value); - } - - static PrimitiveValue asPrimitive(short value) { - return new ShortPrimitive(value); - } - - static PrimitiveValue asPrimitive(char value) { - return new CharPrimitive(value); - } - - static PrimitiveValue asPrimitive(byte value) { - return new BytePrimitive(value); - } - - static PrimitiveValue asPrimitive(long value) { - return new LongPrimitive(value); - } - - static PrimitiveValue asPrimitive(float value) { - return new FloatPrimitive(value); - } - - static PrimitiveValue asPrimitive(double value) { - return new DoublePrimitive(value); - } - - private static class IntPrimitive extends PrimitiveValue { - final int value; - IntPrimitive(int value) { - this.value = value; - } - - @Override - public char type() { - return 'I'; - } - - @Override - public int intValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - } - - private static class ShortPrimitive extends PrimitiveValue { - final short value; - ShortPrimitive(short value) { - this.value = value; - } - - @Override - public char type() { - return 'S'; - } - - @Override - public short shortValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - } - - private static class BooleanPrimitive extends PrimitiveValue { - final boolean value; - BooleanPrimitive(boolean value) { - this.value = value; - } - - @Override - public char type() { - return 'Z'; - } - - @Override - public boolean booleanValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - } - - private static class CharPrimitive extends PrimitiveValue { - final char value; - CharPrimitive(char value) { - this.value = value; - } - - @Override - public char type() { - return 'C'; - } - - @Override - public char charValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - } - - private static class BytePrimitive extends PrimitiveValue { - final byte value; - BytePrimitive(byte value) { - this.value = value; - } - - @Override - public char type() { - return 'B'; - } - - @Override - public byte byteValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - } - - private static class LongPrimitive extends PrimitiveValue { - final long value; - LongPrimitive(long value) { - this.value = value; - } - - @Override - public char type() { - return 'J'; - } - - @Override - public long longValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - } - - private static class FloatPrimitive extends PrimitiveValue { - final float value; - FloatPrimitive(float value) { - this.value = value; - } - - @Override - public char type() { - return 'F'; - } - - @Override - public float floatValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - } - - private static class DoublePrimitive extends PrimitiveValue { - final double value; - DoublePrimitive(double value) { - this.value = value; - } - - @Override - public char type() { - return 'D'; - } - - @Override - public double doubleValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - } -}
--- a/src/java.base/share/classes/java/lang/StackFrameInfo.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +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. - */ -package java.lang; - -import jdk.internal.misc.JavaLangInvokeAccess; -import jdk.internal.misc.SharedSecrets; - -import static java.lang.StackWalker.Option.*; -import java.lang.StackWalker.StackFrame; -import java.util.Optional; -import java.util.OptionalInt; - -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 - - 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 - - /* - * Create StackFrameInfo for StackFrameTraverser and LiveStackFrameTraverser - * to use - */ - StackFrameInfo(StackWalker walker) { - this.walker = walker; - this.declaringClass = null; - this.bci = -1; - this.memberName = jlInvokeAccess.newMemberName(); - } - - @Override - public String getClassName() { - return declaringClass.getName(); - } - - @Override - public Class<?> getDeclaringClass() { - walker.ensureAccessEnabled(RETAIN_CLASS_REFERENCE); - 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; - } - - @Override - public Optional<String> getFileName() { - ensureMethodInfoInitialized(); - return fileName != null ? Optional.of(fileName) : Optional.empty(); - } - - @Override - public OptionalInt getLineNumber() { - ensureMethodInfoInitialized(); - return lineNumber > 0 ? OptionalInt.of(lineNumber) : OptionalInt.empty(); - } - - @Override - public boolean isNativeMethod() { - ensureMethodInfoInitialized(); - return lineNumber == -2; - } - - @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) + ")"; - } - } - - /** - * Lazily initialize method name, file name, line number - */ - 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); -}
--- a/src/java.base/share/classes/java/lang/StackFramePermission.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +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. - */ -package java.lang; - -/** - * Permission to access {@link StackWalker.StackFrame}. - * - * @see java.lang.StackWalker.Option#RETAIN_CLASS_REFERENCE - * @see StackWalker.StackFrame#getDeclaringClass() - */ -public class StackFramePermission extends java.security.BasicPermission { - private static final long serialVersionUID = 2841894854386706014L; - - /** - * Creates a new {@code StackFramePermission} object. - * - * @param name Permission name. Must be "retainClassReference". - * - * @throws IllegalArgumentException if {@code name} is invalid. - * @throws NullPointerException if {@code name} is {@code null}. - */ - public StackFramePermission(String name) { - super(name); - if (!name.equals("retainClassReference")) { - throw new IllegalArgumentException("name: " + name); - } - } -}
--- a/src/java.base/share/classes/java/lang/StackStreamFactory.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1106 +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. - */ -package java.lang; - -import sun.misc.VM; - -import java.io.PrintStream; -import java.lang.StackWalker.Option; -import java.lang.StackWalker.StackFrame; - -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; -import java.util.function.Function; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -import static java.lang.StackStreamFactory.WalkerState.*; - -/** - * StackStreamFactory class provides static factory methods - * to get different kinds of stack walker/traverser. - * - * AbstractStackWalker provides the basic stack walking support - * fetching stack frames from VM in batches. - * - * AbstractStackWalker subclass is specialized for a specific kind of stack traversal - * to avoid overhead of Stream/Lambda - * 1. Support traversing Stream<StackFrame> - * 2. StackWalker::getCallerClass - * 3. Throwable::init and Throwable::getStackTrace - * 4. AccessControlContext getting ProtectionDomain - */ -final class StackStreamFactory { - private StackStreamFactory() {} - - // Stack walk implementation classes to be excluded during stack walking - // lazily add subclasses when they are loaded. - private final static Set<Class<?>> stackWalkImplClasses = init(); - - private static final int SMALL_BATCH = 8; - private static final int BATCH_SIZE = 32; - private static final int LARGE_BATCH_SIZE = 256; - private static final int MIN_BATCH_SIZE = SMALL_BATCH; - - // 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 <T> StackFrameTraverser<T> - makeStackTraverser(StackWalker walker, Function<? super Stream<StackFrame>, ? extends T> function) - { - if (walker.hasLocalsOperandsOption()) - return new LiveStackInfoTraverser<T>(walker, function); - else - return new StackFrameTraverser<T>(walker, function); - } - - /** - * Gets a stack stream to find caller class. - */ - static CallerClassFinder makeCallerFinder(StackWalker walker) { - 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::<init>. - */ - 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<T> { - 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 long anchor; - - // buffers to fill in stack frame information - protected AbstractStackWalker(StackWalker walker, int mode) { - this(walker, mode, Integer.MAX_VALUE); - } - protected AbstractStackWalker(StackWalker walker, int mode, int maxDepth) { - this.thread = Thread.currentThread(); - this.mode = toStackWalkMode(walker, mode); - this.walker = walker; - this.maxDepth = maxDepth; - this.depth = 0; - } - - 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 */) - 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). - * - * Each specialized AbstractStackWalker subclass implements the consumeFrames method - * to control the following: - * 1. fetch the subsequent batches of stack frames - * 2. reuse or expand the allocated buffers - * 3. create specialized StackFrame objects - * - * @return the number of consumed frames - */ - protected abstract T consumeFrames(); - - /** - * Initialize FrameBuffer. Subclass should implement this method to - * create its custom frame buffers. - */ - protected abstract void initFrameBuffer(); - - /** - * Returns the suggested next batch size. - * - * Subclass should override this method to change the batch size - * - * @param lastBatchFrameCount number of frames in the last batch; or zero - * @return suggested batch size - */ - protected abstract int batchSize(int lastBatchFrameCount); - - /* - * Returns the next batch size, always >= minimum batch size (32) - * - * Subclass may override this method if the minimum batch size is different. - */ - protected int getNextBatchSize() { - int lastBatchSize = depth == 0 ? 0 : frameBuffer.curBatchFrameCount(); - int nextBatchSize = batchSize(lastBatchSize); - if (isDebug) { - System.err.println("last batch size = " + lastBatchSize + - " next batch size = " + nextBatchSize); - } - return nextBatchSize >= MIN_BATCH_SIZE ? nextBatchSize : MIN_BATCH_SIZE; - } - - /* - * Checks if this stream is in the given state. Otherwise, throws IllegalStateException. - * - * VM also validates this stream if it's anchored for stack walking - * when stack frames are fetched for each batch. - */ - final void checkState(WalkerState state) { - if (thread != Thread.currentThread()) { - throw new IllegalStateException("Invalid thread walking this stack stream: " + - Thread.currentThread().getName() + " " + thread.getName()); - } - switch (state) { - case NEW: - if (this.anchor != 0) { - throw new IllegalStateException("This stack stream is being reused."); - } - break; - case OPEN: - if (this.anchor <= 0) { - throw new IllegalStateException("This stack stream is not valid for walking"); - } - break; - case CLOSED: - if (this.anchor != -1L) { - throw new IllegalStateException("This stack stream is not closed."); - } - } - } - - /* - * Close this stream. This stream becomes invalid to walk. - */ - private void close() { - this.anchor = -1L; - } - - /* - * Walks stack frames until {@link #consumeFrames} is done consuming - * the frames it is interested in. - */ - final T walk() { - checkState(NEW); - try { - // VM will need to stablize the stack before walking. It will invoke - // the AbstractStackWalker::doStackWalk method once it fetches the first batch. - // the callback will be invoked within the scope of the callStackWalk frame. - return beginStackWalk(); - } finally { - close(); // done traversal; close the stream - } - } - - private boolean skipReflectionFrames() { - return !walker.hasOption(Option.SHOW_REFLECT_FRAMES) && - !walker.hasOption(Option.SHOW_HIDDEN_FRAMES); - } - - /* - * Returns {@code Class} object at the current frame; - * or {@code null} if no more frame. If advanceToNextBatch is true, - * it will only fetch the next batch. - */ - final Class<?> peekFrame() { - while (frameBuffer.isActive() && depth < maxDepth) { - if (frameBuffer.isEmpty()) { - // fetch another batch of stack frames - getNextBatch(); - } else { - Class<?> c = frameBuffer.get(); - if (skipReflectionFrames() && isReflectionFrame(c)) { - if (isDebug) - System.err.println(" skip: frame " + frameBuffer.getIndex() + " " + c); - - frameBuffer.next(); - depth++; - continue; - } else { - return c; - } - } - } - return null; - } - - /* - * This method is only invoked by VM. - * - * It will invoke the consumeFrames method to start the stack walking - * with the first batch of stack frames. Each specialized AbstractStackWalker - * subclass implements the consumeFrames method to control the following: - * 1. fetch the subsequent batches of stack frames - * 2. reuse or expand the allocated buffers - * 3. create specialized StackFrame objects - */ - private Object doStackWalk(long anchor, int skipFrames, int batchSize, - int bufStartIndex, int bufEndIndex) { - checkState(NEW); - - frameBuffer.check(skipFrames); - - if (isDebug) { - System.err.format("doStackWalk: skip %d start %d end %d%n", - skipFrames, bufStartIndex, bufEndIndex); - } - - this.anchor = anchor; // set anchor for this bulk stack frame traversal - frameBuffer.setBatch(bufStartIndex, bufEndIndex); - - // traverse all frames and perform the action on the stack frames, if specified - return consumeFrames(); - } - - /* - * Get next batch of stack frames. - */ - private int getNextBatch() { - int nextBatchSize = Math.min(maxDepth - depth, getNextBatchSize()); - if (!frameBuffer.isActive() || nextBatchSize <= 0) { - if (isDebug) { - System.out.format(" more stack walk done%n"); - } - frameBuffer.freeze(); // stack walk done - return 0; - } - - return fetchStackFrames(nextBatchSize); - } - - /* - * This method traverses the next stack frame and returns the Class - * invoking that stack frame. - * - * This method can only be called during the walk method. This is intended - * to be used to walk the stack frames in one single invocation and - * this stack stream will be invalidated once walk is done. - * - * @see #tryNextFrame - */ - final Class<?> nextFrame() { - if (!hasNext()) { - return null; - } - - Class<?> c = frameBuffer.next(); - depth++; - return c; - } - - /* - * Returns true if there is next frame to be traversed. - * This skips hidden frames unless this StackWalker has - * {@link Option#SHOW_REFLECT_FRAMES} - */ - final boolean hasNext() { - return peekFrame() != null; - } - - /** - * Begin stack walking - pass the allocated arrays to the VM to fill in - * stack frame information. - * - * VM first anchors the frame of the current thread. A traversable stream - * on this thread's stack will be opened. The VM will fetch the first batch - * of stack frames and call AbstractStackWalker::doStackWalk to invoke the - * stack walking function on each stack frame. - * - * If all fetched stack frames are traversed, AbstractStackWalker::fetchStackFrames will - * fetch the next batch of stack frames to continue. - */ - private T beginStackWalk() { - // initialize buffers for VM to fill the stack frame info - initFrameBuffer(); - - return callStackWalk(mode, 0, - frameBuffer.curBatchFrameCount(), - frameBuffer.startIndex(), - frameBuffer.classes, - frameBuffer.stackFrames); - } - - /* - * Fetches stack frames. - * - * @params batchSize number of elements of the frame buffers for this batch - * @returns number of frames fetched in this batch - */ - private int fetchStackFrames(int batchSize) { - int startIndex = frameBuffer.startIndex(); - frameBuffer.resize(startIndex, batchSize); - - int endIndex = fetchStackFrames(mode, anchor, batchSize, - startIndex, - frameBuffer.classes, - frameBuffer.stackFrames); - if (isDebug) { - System.out.format(" more stack walk requesting %d got %d to %d frames%n", - batchSize, frameBuffer.startIndex(), endIndex); - } - int numFrames = endIndex - startIndex; - if (numFrames == 0) { - frameBuffer.freeze(); // done stack walking - } else { - frameBuffer.setBatch(startIndex, endIndex); - } - return numFrames; - } - - /** - * Begins stack walking. This method anchors this frame and invokes - * AbstractStackWalker::doStackWalk after fetching the firt 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 - * @return Result of AbstractStackWalker::doStackWalk - */ - private native T callStackWalk(long mode, int skipframes, - int batchSize, int startIndex, - Class<?>[] classes, - StackFrame[] frames); - - /** - * Fetch the next batch of stack frames. - * - * @param mode mode of stack walking - * @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 - * - * @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. - * - * <p> 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"); - } - } - } - - /* - * This StackFrameTraverser supports {@link Stream} traversal. - * - * This class implements Spliterator::forEachRemaining and Spliterator::tryAdvance. - */ - static class StackFrameTraverser<T> extends AbstractStackWalker<T> - implements Spliterator<StackFrame> - { - static { - stackWalkImplClasses.add(StackFrameTraverser.class); - } - private static final int CHARACTERISTICS = Spliterator.ORDERED | Spliterator.IMMUTABLE; - class Buffer extends FrameBuffer { - Buffer(int initialBatchSize) { - super(initialBatchSize); - - this.stackFrames = new StackFrame[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); - } - } - - @Override - StackFrame nextStackFrame() { - if (isEmpty()) { - throw new NoSuchElementException("origin=" + origin + " fence=" + fence); - } - - StackFrame frame = stackFrames[origin]; - origin++; - return frame; - } - } - - final Function<? super Stream<StackFrame>, ? extends T> function; // callback - - StackFrameTraverser(StackWalker walker, - Function<? super Stream<StackFrame>, ? extends T> function) { - this(walker, function, DEFAULT_MODE); - } - StackFrameTraverser(StackWalker walker, - Function<? super Stream<StackFrame>, ? extends T> function, - int mode) { - super(walker, mode); - this.function = function; - } - - /** - * Returns next StackFrame object in the current batch of stack frames; - * or null if no more stack frame. - */ - StackFrame nextStackFrame() { - if (!hasNext()) { - return null; - } - - StackFrame frame = frameBuffer.nextStackFrame(); - depth++; - return frame; - } - - @Override - protected T consumeFrames() { - checkState(OPEN); - Stream<StackFrame> stream = StreamSupport.stream(this, false); - if (function != null) { - return function.apply(stream); - } else - throw new UnsupportedOperationException(); - } - - @Override - protected void initFrameBuffer() { - this.frameBuffer = new Buffer(getNextBatchSize()); - } - - @Override - protected int batchSize(int lastBatchFrameCount) { - if (lastBatchFrameCount == 0) { - // First batch, use estimateDepth if not exceed the large batch size - // and not too small - int initialBatchSize = Math.max(walker.estimateDepth(), SMALL_BATCH); - return Math.min(initialBatchSize, LARGE_BATCH_SIZE); - } else { - if (lastBatchFrameCount > BATCH_SIZE) { - return lastBatchFrameCount; - } else { - return Math.min(lastBatchFrameCount*2, BATCH_SIZE); - } - } - } - - // ------- Implementation of Spliterator - - @Override - public Spliterator<StackFrame> trySplit() { - return null; // ordered stream and do not allow to split - } - - @Override - public long estimateSize() { - return maxDepth; - } - - @Override - public int characteristics() { - return CHARACTERISTICS; - } - - @Override - public void forEachRemaining(Consumer<? super StackFrame> action) { - checkState(OPEN); - for (int n = 0; n < maxDepth; n++) { - StackFrame frame = nextStackFrame(); - if (frame == null) break; - - action.accept(frame); - } - } - - @Override - public boolean tryAdvance(Consumer<? super StackFrame> action) { - checkState(OPEN); - - int index = frameBuffer.getIndex(); - if (hasNext()) { - StackFrame frame = nextStackFrame(); - action.accept(frame); - if (isDebug) { - System.err.println("tryAdvance: " + index + " " + frame); - } - return true; - } - if (isDebug) { - System.err.println("tryAdvance: " + index + " NO element"); - } - return false; - } - } - - /* - * CallerClassFinder is specialized to return Class<?> for each stack frame. - * StackFrame is not requested. - */ - static class CallerClassFinder extends AbstractStackWalker<Integer> { - static { - stackWalkImplClasses.add(CallerClassFinder.class); - } - - private Class<?> caller; - - CallerClassFinder(StackWalker walker) { - super(walker, FILL_CLASS_REFS_ONLY); - } - - Class<?> findCaller() { - walk(); - return caller; - } - - @Override - protected Integer consumeFrames() { - checkState(OPEN); - int n = 0; - Class<?>[] frames = new Class<?>[2]; - // skip the API calling this getCallerClass method - // 0: StackWalker::getCallerClass - // 1: caller-sensitive method - // 2: caller class - while (n < 2 && (caller = nextFrame()) != null) { - if (isMethodHandleFrame(caller)) continue; - frames[n++] = caller; - } - - if (frames[1] == null) - throw new IllegalStateException("no caller frame"); - return n; - } - - @Override - protected void initFrameBuffer() { - this.frameBuffer = new FrameBuffer(getNextBatchSize()); - } - - @Override - protected int batchSize(int lastBatchFrameCount) { - return MIN_BATCH_SIZE; - } - - @Override - protected int getNextBatchSize() { - return MIN_BATCH_SIZE; - } - } - - /* - * StackTrace caches all frames in the buffer. StackTraceElements are - * created lazily when Throwable::getStackTrace is called. - */ - static class StackTrace extends AbstractStackWalker<Integer> { - 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. - * <p> - * 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 <init> 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. - * <p> - * 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<T> extends StackFrameTraverser<T> { - 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) { - super(initialBatchSize); - this.stackFrames = new StackFrame[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; - - if (stackFrames.length < size) { - this.stackFrames = new StackFrame[size]; - } - - for (int i = startIndex(); i < size; i++) { - stackFrames[i] = new LiveStackFrameInfo(walker); - } - } - - @Override - StackFrame nextStackFrame() { - if (isEmpty()) { - throw new NoSuchElementException("origin=" + origin + " fence=" + fence); - } - - StackFrame frame = stackFrames[origin]; - origin++; - return frame; - } - } - - LiveStackInfoTraverser(StackWalker walker, - Function<? super Stream<StackFrame>, ? extends T> function) { - super(walker, function, DEFAULT_MODE); - } - - @Override - protected void initFrameBuffer() { - this.frameBuffer = new Buffer(getNextBatchSize()); - } - } - - private static native boolean checkStackWalkModes(); - - // avoid loading other subclasses as they may not be used - private static Set<Class<?>> init() { - if (!checkStackWalkModes()) { - throw new InternalError("StackWalker mode values do not match with JVM"); - } - - Set<Class<?>> classes = new HashSet<>(); - classes.add(StackWalker.class); - classes.add(StackStreamFactory.class); - classes.add(AbstractStackWalker.class); - return classes; - } - - private static boolean filterStackWalkImpl(Class<?> c) { - return stackWalkImplClasses.contains(c) || - c.getName().startsWith("java.util.stream."); - } - - // MethodHandle frames are not hidden and CallerClassFinder has - // to filter them out - private static boolean isMethodHandleFrame(Class<?> c) { - return c.getName().startsWith("java.lang.invoke."); - } - - private static boolean isReflectionFrame(Class<?> c) { - if (c.getName().startsWith("sun.reflect") && - !sun.reflect.MethodAccessor.class.isAssignableFrom(c)) { - throw new InternalError("Not sun.reflect.MethodAccessor: " + c.toString()); - } - // ## should filter all @Hidden frames? - return c == Method.class || - sun.reflect.MethodAccessor.class.isAssignableFrom(c) || - c.getName().startsWith("java.lang.invoke.LambdaForm"); - } - - private static boolean getProperty(String key, boolean value) { - String s = AccessController.doPrivileged(new PrivilegedAction<>() { - @Override - public String run() { - return System.getProperty(key); - } - }); - if (s != null) { - return Boolean.valueOf(s); - } - return value; - } -}
--- a/src/java.base/share/classes/java/lang/StackWalker.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,563 +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. - */ -package java.lang; - -import sun.reflect.CallerSensitive; - -import java.util.*; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.stream.Stream; - -/** - * A stack walker. - * - * <p> The {@link StackWalker#walk walk} method opens a sequential stream - * of {@link StackFrame StackFrame}s for the current thread and then applies - * the given function to walk the {@code StackFrame} stream. - * The stream reports stack frame elements in order, from the top most frame - * that represents the execution point at which the stack was generated to - * the bottom most frame. - * The {@code StackFrame} stream is closed when the {@code walk} method returns. - * If an attempt is made to reuse the closed stream, - * {@code IllegalStateException} will be thrown. - * - * <p> The {@linkplain Option <em>stack walking options</em>} of a - * {@code StackWalker} determines the information of - * {@link StackFrame StackFrame} objects to be returned. - * By default, stack frames of the reflection API and implementation - * classes are {@linkplain Option#SHOW_HIDDEN_FRAMES hidden} - * and {@code StackFrame}s have the class name and method name - * available but not the {@link StackFrame#getDeclaringClass() Class reference}. - * - * <p> {@code StackWalker} is thread-safe. Multiple threads can share - * a single {@code StackWalker} object to traverse its own stack. - * A permission check is performed when a {@code StackWalker} is created, - * according to the options it requests. - * No further permission check is done at stack walking time. - * - * @apiNote - * Examples - * - * <p>1. To find the first caller filtering a known list of implementation class: - * <pre>{@code - * StackWalker walker = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE); - * Optional<Class<?>> callerClass = walker.walk(s -> - * s.map(StackFrame::getDeclaringClass) - * .filter(interestingClasses::contains) - * .findFirst()); - * }</pre> - * - * <p>2. To snapshot the top 10 stack frames of the current thread, - * <pre>{@code - * List<StackFrame> stack = StackWalker.getInstance().walk(s -> - * s.limit(10).collect(Collectors.toList())); - * }</pre> - * - * Unless otherwise noted, passing a {@code null} argument to a - * constructor or method in this {@code StackWalker} class - * will cause a {@link NullPointerException NullPointerException} - * to be thrown. - * - * @since 1.9 - */ -public final class StackWalker { - /** - * A {@code StackFrame} object represents a method invocation returned by - * {@link StackWalker}. - * - * <p> The {@link #getDeclaringClass()} method may be unsupported as determined - * by the {@linkplain Option stack walking options} of a {@linkplain - * StackWalker stack walker}. - * - * @since 1.9 - * @jvms 2.6 - */ - public static interface StackFrame { - /** - * Gets the <a href="ClassLoader.html#name">binary name</a> - * of the declaring class of the method represented by this stack frame. - * - * @return the binary name of the declaring class of the method - * represented by this stack frame - * - * @jls 13.1 The Form of a Binary - */ - public String getClassName(); - - /** - * Gets the name of the method represented by this stack frame. - * @return the name of the method represented by this stack frame - */ - public String getMethodName(); - - /** - * Gets the declaring {@code Class} for the method represented by - * this stack frame. - * - * @return the declaring {@code Class} of the method represented by - * this stack frame - * - * @throws UnsupportedOperationException if this {@code StackWalker} - * is not configured with {@link Option#RETAIN_CLASS_REFERENCE - * Option.RETAIN_CLASS_REFERENCE}. - */ - public Class<?> getDeclaringClass(); - - /** - * Returns the name of the source file containing the execution point - * represented by this stack frame. Generally, this corresponds - * to the {@code SourceFile} attribute of the relevant {@code class} - * file as defined by <cite>The Java Virtual Machine Specification</cite>. - * In some systems, the name may refer to some source code unit - * other than a file, such as an entry in a source repository. - * - * @return the name of the file containing the execution point - * represented by this stack frame, or empty {@code Optional} - * is unavailable. - * - * @jvms 4.7.10 The {@code SourceFile} Attribute - */ - public Optional<String> getFileName(); - - /** - * Returns the line number of the source line containing the execution - * point represented by this stack frame. Generally, this is - * derived from the {@code LineNumberTable} attribute of the relevant - * {@code class} file as defined by <cite>The Java Virtual Machine - * Specification</cite>. - * - * @return the line number of the source line containing the execution - * point represented by this stack frame, or empty - * {@code Optional} if this information is unavailable. - * - * @jvms 4.7.12 The {@code LineNumberTable} Attribute - */ - public OptionalInt getLineNumber(); - - /** - * Returns {@code true} if the method containing the execution point - * represented by this stack frame is a native method. - * - * @return {@code true} if the method containing the execution point - * represented by this stack frame is a native method. - */ - public boolean isNativeMethod(); - - /** - * Gets a {@code StackTraceElement} for this stack frame. - * - * @return {@code StackTraceElement} for this stack frame. - * - * */ - public default StackTraceElement toStackTraceElement() { - int lineNumber = isNativeMethod() ? -2 - : getLineNumber().orElse(-1); - return new StackTraceElement(getClassName(), getMethodName(), - getFileName().orElse(null), - lineNumber); - } - } - - /** - * Stack walker option to configure the {@linkplain StackFrame stack frame} - * information obtained by a {@code StackWalker}. - * - * @since 1.9 - */ - public enum Option { - /** - * Retains {@code Class} object in {@code StackFrame}s - * walked by this {@code StackWalker}. - * - * <p> A {@code StackWalker} configured with this option will support - * {@link StackWalker#getCallerClass()} and - * {@link StackFrame#getDeclaringClass() StackFrame.getDeclaringClass()}. - */ - RETAIN_CLASS_REFERENCE, - /** - * Shows all reflection frames. - * - * <p>By default, reflection frames are hidden. This includes the - * {@link java.lang.reflect.Method#invoke} method - * and the reflection implementation classes. A {@code StackWalker} with - * this {@code SHOW_REFLECT_FRAMES} option will show all reflection frames. - * The {@link #SHOW_HIDDEN_FRAMES} option can also be used to show all - * reflection frames and it will also show other hidden frames that - * are implementation-specific. - */ - SHOW_REFLECT_FRAMES, - /** - * Shows all hidden frames. - * - * <p>A Java Virtual Machine implementation may hide implementation - * specific frames in addition to {@linkplain #SHOW_REFLECT_FRAMES - * reflection frames}. A {@code StackWalker} with this {@code SHOW_HIDDEN_FRAMES} - * option will show all hidden frames (including reflection frames). - */ - SHOW_HIDDEN_FRAMES; - } - - enum ExtendedOption { - /** - * Obtain monitors, locals and operands. - */ - LOCALS_AND_OPERANDS - }; - - static final EnumSet<Option> DEFAULT_EMPTY_OPTION = EnumSet.noneOf(Option.class); - - private final static StackWalker DEFAULT_WALKER = - new StackWalker(DEFAULT_EMPTY_OPTION); - - private final Set<Option> options; - private final ExtendedOption extendedOption; - private final int estimateDepth; - - /** - * Returns a {@code StackWalker} instance. - * - * <p> This {@code StackWalker} is configured to skip all - * {@linkplain Option#SHOW_HIDDEN_FRAMES hidden frames} and - * no {@linkplain Option#RETAIN_CLASS_REFERENCE class reference} is retained. - * - * @return a {@code StackWalker} configured to skip all - * {@linkplain Option#SHOW_HIDDEN_FRAMES hidden frames} and - * no {@linkplain Option#RETAIN_CLASS_REFERENCE class reference} is retained. - * - */ - public static StackWalker getInstance() { - // no permission check needed - return DEFAULT_WALKER; - } - - /** - * Returns a {@code StackWalker} instance with the given option specifying - * the stack frame information it can access. - * - * <p> - * If a security manager is present and the given {@code option} is - * {@link Option#RETAIN_CLASS_REFERENCE Option.RETAIN_CLASS_REFERENCE}, - * it calls its {@link SecurityManager#checkPermission checkPermission} - * method for {@code StackFramePermission("retainClassReference")}. - * - * @param option {@link Option stack walking option} - * - * @return a {@code StackWalker} configured with the given option - * - * @throws SecurityException if a security manager exists and its - * {@code checkPermission} method denies access. - */ - public static StackWalker getInstance(Option option) { - return getInstance(EnumSet.of(Objects.requireNonNull(option))); - } - - /** - * Returns a {@code StackWalker} instance with the given {@code options} specifying - * the stack frame information it can access. If the given {@code options} - * is empty, this {@code StackWalker} is configured to skip all - * {@linkplain Option#SHOW_HIDDEN_FRAMES hidden frames} and no - * {@linkplain Option#RETAIN_CLASS_REFERENCE class reference} is retained. - * - * <p> - * If a security manager is present and the given {@code options} contains - * {@link Option#RETAIN_CLASS_REFERENCE Option.RETAIN_CLASS_REFERENCE}, - * it calls its {@link SecurityManager#checkPermission checkPermission} - * method for {@code StackFramePermission("retainClassReference")}. - * - * @param options {@link Option stack walking option} - * - * @return a {@code StackWalker} configured with the given options - * - * @throws SecurityException if a security manager exists and its - * {@code checkPermission} method denies access. - */ - public static StackWalker getInstance(Set<Option> options) { - if (options.isEmpty()) { - return DEFAULT_WALKER; - } - - checkPermission(options); - return new StackWalker(toEnumSet(options)); - } - - /** - * Returns a {@code StackWalker} instance with the given {@ocde options} specifying - * the stack frame information it can access. If the given {@ocde options} - * is empty, this {@code StackWalker} is configured to skip all - * {@linkplain Option#SHOW_HIDDEN_FRAMES hidden frames} and no - * {@linkplain Option#RETAIN_CLASS_REFERENCE class reference} is retained. - * - * <p> - * If a security manager is present and the given {@code options} contains - * {@link Option#RETAIN_CLASS_REFERENCE Option.RETAIN_CLASS_REFERENCE}, - * it calls its {@link SecurityManager#checkPermission checkPermission} - * method for {@code StackFramePermission("retainClassReference")}. - * - * <p> - * The {@code estimateDepth} specifies the estimate number of stack frames - * this {@code StackWalker} will traverse that the {@code StackWalker} could - * use as a hint for the buffer size. - * - * @param options {@link Option stack walking options} - * @param estimateDepth Estimate number of stack frames to be traversed. - * - * @return a {@code StackWalker} configured with the given options - * - * @throws IllegalArgumentException if {@code estimateDepth <= 0} - * @throws SecurityException if a security manager exists and its - * {@code checkPermission} method denies access. - */ - public static StackWalker getInstance(Set<Option> options, int estimateDepth) { - if (estimateDepth <= 0) { - throw new IllegalArgumentException("estimateDepth must be > 0"); - } - checkPermission(options); - return new StackWalker(toEnumSet(options), estimateDepth); - } - - // ----- private constructors ------ - private StackWalker(EnumSet<Option> options) { - this(options, 0, null); - } - private StackWalker(EnumSet<Option> options, int estimateDepth) { - this(options, estimateDepth, null); - } - private StackWalker(EnumSet<Option> options, int estimateDepth, ExtendedOption extendedOption) { - this.options = options; - this.estimateDepth = estimateDepth; - this.extendedOption = extendedOption; - } - - private static void checkPermission(Set<Option> options) { - Objects.requireNonNull(options); - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - if (options.contains(Option.RETAIN_CLASS_REFERENCE)) { - sm.checkPermission(new StackFramePermission("retainClassReference")); - } - } - } - - /* - * Returns a defensive copy - */ - private static EnumSet<Option> toEnumSet(Set<Option> options) { - Objects.requireNonNull(options); - if (options.isEmpty()) { - return DEFAULT_EMPTY_OPTION; - } else { - return EnumSet.copyOf(options); - } - } - - /** - * Applies the given function to the stream of {@code StackFrame}s - * for the current thread, traversing from the top frame of the stack, - * which is the method calling this {@code walk} method. - * - * <p>The {@code StackFrame} stream will be closed when - * this method returns. When a closed {@code Stream<StackFrame>} object - * is reused, {@code IllegalStateException} will be thrown. - * - * @apiNote - * For example, to find the first 10 calling frames, first skipping those frames - * whose declaring class is in package {@code com.foo}: - * <blockquote> - * <pre>{@code - * List<StackFrame> frames = StackWalker.getInstance().walk(s -> - * s.dropWhile(f -> f.getClassName().startsWith("com.foo.")) - * .limit(10) - * .collect(Collectors.toList())); - * }</pre></blockquote> - * - * <p>This method takes a {@code Function} accepting a {@code Stream<StackFrame>}, - * rather than returning a {@code Stream<StackFrame>} and allowing the - * caller to directly manipulate the stream. The Java virtual machine is - * free to reorganize a thread's control stack, for example, via - * deoptimization. By taking a {@code Function} parameter, this method - * allows access to stack frames through a stable view of a thread's control - * stack. - * - * <p>Parallel execution is effectively disabled and stream pipeline - * execution will only occur on the current thread. - * - * @implNote The implementation stabilizes the stack by anchoring a frame - * specific to the stack walking and ensures that the stack walking is - * performed above the anchored frame. When the stream object is closed or - * being reused, {@code IllegalStateException} will be thrown. - * - * @param function a function that takes a stream of - * {@linkplain StackFrame stack frames} and returns a result. - * @param <T> The type of the result of applying the function to the - * stream of {@linkplain StackFrame stack frame}. - * - * @return the result of applying the function to the stream of - * {@linkplain StackFrame stack frame}. - */ - @CallerSensitive - public <T> T walk(Function<? super Stream<StackFrame>, ? extends T> function) { - // Returning a Stream<StackFrame> would be unsafe, as the stream could - // be used to access the stack frames in an uncontrolled manner. For - // example, a caller might pass a Spliterator of stack frames after one - // or more frames had been traversed. There is no robust way to detect - // whether the execution point when - // Spliterator.tryAdvance(java.util.function.Consumer<? super T>) is - // invoked is the exact same execution point where the stack frame - // traversal is expected to resume. - - Objects.requireNonNull(function); - return StackStreamFactory.makeStackTraverser(this, function) - .walk(); - } - - /** - * Performs the given action on each element of {@code StackFrame} stream - * of the current thread, traversing from the top frame of the stack, - * which is the method calling this {@code forEach} method. - * - * <p> This method is equivalent to calling - * <blockquote> - * {@code walk(s -> { s.forEach(action); return null; });} - * </blockquote> - * - * @param action an action to be performed on each {@code StackFrame} - * of the stack of the current thread - */ - @CallerSensitive - public void forEach(Consumer<? super StackFrame> action) { - Objects.requireNonNull(action); - StackStreamFactory.makeStackTraverser(this, s -> { - s.forEach(action); - return null; - }).walk(); - } - - /** - * Gets the {@code Class} object of the caller invoking the method - * that calls this {@code getCallerClass} method. - * - * <p> Reflection frames, {@link java.lang.invoke.MethodHandle} and - * hidden frames are filtered regardless of the - * {@link Option#SHOW_REFLECT_FRAMES SHOW_REFLECT_FRAMES} - * and {@link Option#SHOW_HIDDEN_FRAMES SHOW_HIDDEN_FRAMES} options - * this {@code StackWalker} has been configured. - * - * <p> This method throws {@code UnsupportedOperationException} - * if this {@code StackWalker} is not configured with - * {@link Option#RETAIN_CLASS_REFERENCE RETAIN_CLASS_REFERENCE} option, - * This method should be called when a caller frame is present. If - * it is called from the last frame on the stack; - * {@code IllegalStateException} will be thrown. - * - * @apiNote - * For example, {@code Util::getResourceBundle} loads a resource bundle - * on behalf of the caller. It calls this {@code getCallerClass} method - * to find the method calling {@code Util::getResourceBundle} and use the caller's - * class loader to load the resource bundle. The caller class in this example - * is the {@code MyTool} class. - * - * <pre>{@code - * class Util { - * private final StackWalker walker = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE); - * public ResourceBundle getResourceBundle(String bundleName) { - * Class<?> caller = walker.getCallerClass(); - * return ResourceBundle.getBundle(bundleName, Locale.getDefault(), caller.getClassLoader()); - * } - * } - * - * class MyTool { - * private final Util util = new Util(); - * private void init() { - * ResourceBundle rb = util.getResourceBundle("mybundle"); - * } - * } - * }</pre> - * - * An equivalent way to find the caller class using the - * {@link StackWalker#walk walk} method is as follows - * (filtering the reflection frames, {@code MethodHandle} and hidden frames - * not shown below): - * <pre>{@code - * Optional<Class<?>> caller = walker.walk(s -> - * s.map(StackFrame::getDeclaringClass) - * .skip(2) - * .findFirst()); - * }</pre> - * - * When the {@code getCallerClass} method is called from a method that - * is the last frame on the stack, - * for example, {@code static public void main} method launched by the - * {@code java} launcher or a method invoked from a JNI attached thread. - * {@code IllegalStateException} is thrown. - * - * @return {@code Class} object of the caller's caller invoking this method. - * - * @throws UnsupportedOperationException if this {@code StackWalker} - * is not configured with {@link Option#RETAIN_CLASS_REFERENCE - * Option.RETAIN_CLASS_REFERENCE}. - * @throws IllegalStateException if there is no caller frame, i.e. - * when this {@code getCallerClass} method is called from a method - * which is the last frame on the stack. - */ - @CallerSensitive - public Class<?> getCallerClass() { - if (!options.contains(Option.RETAIN_CLASS_REFERENCE)) { - throw new UnsupportedOperationException("This stack walker " + - "does not have RETAIN_CLASS_REFERENCE access"); - } - - return StackStreamFactory.makeCallerFinder(this).findCaller(); - } - - // ---- package access ---- - static StackWalker newInstanceNoCheck(EnumSet<Option> options) { - return new StackWalker(options, 0, null); - } - - static StackWalker newInstance(Set<Option> options, ExtendedOption extendedOption) { - checkPermission(options); - return new StackWalker(toEnumSet(options), 0, extendedOption); - } - - int estimateDepth() { - return estimateDepth; - } - - boolean hasOption(Option option) { - return options.contains(option); - } - - boolean hasLocalsOperandsOption() { - return extendedOption == ExtendedOption.LOCALS_AND_OPERANDS; - } - - void ensureAccessEnabled(Option access) { - if (!hasOption(access)) { - throw new UnsupportedOperationException("No access to " + access + - ": " + options.toString()); - } - } -}
--- a/src/java.base/share/classes/java/lang/System.java Tue Nov 24 11:50:20 2015 +0000 +++ b/src/java.base/share/classes/java/lang/System.java Tue Nov 24 18:32:38 2015 +0000 @@ -28,11 +28,11 @@ import java.lang.reflect.Executable; import java.lang.annotation.Annotation; import java.security.AccessControlContext; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.Properties; import java.util.PropertyPermission; import java.util.Map; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.nio.channels.Channel; import java.nio.channels.spi.SelectorProvider; import java.util.Objects; @@ -1896,6 +1896,12 @@ public void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook) { Shutdown.add(slot, registerShutdownInProgress, hook); } + public int getStackTraceDepth(Throwable t) { + return t.getStackTraceDepth(); + } + public StackTraceElement getStackTraceElement(Throwable t, int i) { + return t.getStackTraceElement(i); + } public String newStringUnsafe(char[] chars) { return new String(chars, true); }
--- a/src/java.base/share/classes/java/lang/Thread.java Tue Nov 24 11:50:20 2015 +0000 +++ b/src/java.base/share/classes/java/lang/Thread.java Tue Nov 24 18:32:38 2015 +0000 @@ -1329,9 +1329,11 @@ /** * Prints a stack trace of the current thread to the standard error stream. * This method is used only for debugging. + * + * @see Throwable#printStackTrace() */ public static void dumpStack() { - StackStreamFactory.makeStackTrace().printStackTrace(System.err); + new Exception("Stack trace").printStackTrace(); } /** @@ -1554,7 +1556,7 @@ return stackTrace; } else { // Don't need JVM help for current thread - return StackStreamFactory.makeStackTrace().getStackTraceElements(); + return (new Exception()).getStackTrace(); } }
--- a/src/java.base/share/classes/java/lang/Throwable.java Tue Nov 24 11:50:20 2015 +0000 +++ b/src/java.base/share/classes/java/lang/Throwable.java Tue Nov 24 18:32:38 2015 +0000 @@ -24,8 +24,6 @@ */ package java.lang; -import sun.misc.VM; - import java.io.*; import java.util.*; @@ -780,11 +778,7 @@ 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; @@ -825,14 +819,10 @@ // 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 { - int depth = getStackTraceDepth(); - stackTrace = new StackTraceElement[depth]; - for (int i = 0; i < depth; i++) - stackTrace[i] = getStackTraceElement(i); - } + int depth = getStackTraceDepth(); + stackTrace = new StackTraceElement[depth]; + for (int i=0; i < depth; i++) + stackTrace[i] = getStackTraceElement(i); } else if (stackTrace == null) { return UNASSIGNED_STACK; }
--- a/src/java.base/share/classes/java/lang/invoke/MemberName.java Tue Nov 24 11:50:20 2015 +0000 +++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java Tue Nov 24 18:32:38 2015 +0000 @@ -1077,13 +1077,4 @@ // System.out.println("Hello world! My methods are:"); // System.out.println(Factory.INSTANCE.getMethods(MemberName.class, true, null)); // } - - static { - // Allow privileged classes outside of java.lang - jdk.internal.misc.SharedSecrets.setJavaLangInvokeAccess(new jdk.internal.misc.JavaLangInvokeAccess() { - public Object newMemberName() { - return new MemberName(); - } - }); - } }
--- a/src/java.base/share/classes/jdk/internal/logger/SimpleConsoleLogger.java Tue Nov 24 11:50:20 2015 +0000 +++ b/src/java.base/share/classes/jdk/internal/logger/SimpleConsoleLogger.java Tue Nov 24 18:32:38 2015 +0000 @@ -31,12 +31,13 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.time.ZonedDateTime; -import java.util.Optional; import java.util.ResourceBundle; import java.util.function.Function; import java.lang.System.Logger; -import java.util.function.Predicate; +import java.lang.System.Logger.Level; import java.util.function.Supplier; +import jdk.internal.misc.JavaLangAccess; +import jdk.internal.misc.SharedSecrets; import sun.util.logging.PlatformLogger; import sun.util.logging.PlatformLogger.ConfigurableBridge.LoggerConfiguration; @@ -168,55 +169,42 @@ // Returns the caller's class and method's name; best effort // if cannot infer, return the logger's name. private String getCallerInfo() { - Optional<StackWalker.StackFrame> frame = new CallerFinder().get(); - if (frame.isPresent()) { - return frame.get().getClassName() + " " + frame.get().getMethodName(); - } else { - return name; - } - } + String sourceClassName = null; + String sourceMethodName = null; + + JavaLangAccess access = SharedSecrets.getJavaLangAccess(); + Throwable throwable = new Throwable(); + int depth = access.getStackTraceDepth(throwable); - /* - * CallerFinder is a stateful predicate. - */ - static final class CallerFinder implements Predicate<StackWalker.StackFrame> { - static final StackWalker WALKER = StackWalker.getInstance(); - - /** - * Returns StackFrame of the caller's frame. - * @return StackFrame of the caller's frame. - */ - Optional<StackWalker.StackFrame> get() { - return WALKER.walk((s) -> s.filter(this).findFirst()); + String logClassName = "sun.util.logging.PlatformLogger"; + String simpleLoggerClassName = "jdk.internal.logger.SimpleConsoleLogger"; + boolean lookingForLogger = true; + for (int ix = 0; ix < depth; ix++) { + // Calling getStackTraceElement directly prevents the VM + // from paying the cost of building the entire stack frame. + final StackTraceElement frame = + access.getStackTraceElement(throwable, ix); + final String cname = frame.getClassName(); + if (lookingForLogger) { + // Skip all frames until we have found the first logger frame. + if (cname.equals(logClassName) || cname.equals(simpleLoggerClassName)) { + lookingForLogger = false; + } + } else { + if (skipLoggingFrame(cname)) continue; + if (!cname.equals(logClassName) && !cname.equals(simpleLoggerClassName)) { + // We've found the relevant frame. + sourceClassName = cname; + sourceMethodName = frame.getMethodName(); + break; + } + } } - private boolean lookingForLogger = true; - /** - * Returns true if we have found the caller's frame, false if the frame - * must be skipped. - * - * @param t The frame info. - * @return true if we have found the caller's frame, false if the frame - * must be skipped. - */ - @Override - public boolean test(StackWalker.StackFrame t) { - final String cname = t.getClassName(); - // We should skip all frames until we have found the logger, - // because these frames could be frames introduced by e.g. custom - // sub classes of Handler. - if (lookingForLogger) { - // Skip all frames until we have found the first logger frame. - lookingForLogger = !isLoggerImplFrame(cname); - return false; - } - // We've found the relevant frame. - return !skipLoggingFrame(cname) && !isLoggerImplFrame(cname); - } - - private boolean isLoggerImplFrame(String cname) { - return (cname.equals("sun.util.logging.PlatformLogger") || - cname.equals("jdk.internal.logger.SimpleConsoleLogger")); + if (sourceClassName != null) { + return sourceClassName + " " + sourceMethodName; + } else { + return name; } }
--- a/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java Tue Nov 24 11:50:20 2015 +0000 +++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java Tue Nov 24 18:32:38 2015 +0000 @@ -103,6 +103,16 @@ void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook); /** + * Returns the number of stack frames represented by the given throwable. + */ + int getStackTraceDepth(Throwable t); + + /** + * Returns the ith StackTraceElement for the given throwable. + */ + StackTraceElement getStackTraceElement(Throwable t, int i); + + /** * Returns a new string backed by the provided character array. The * character array is not copied and must never be modified after the * String is created, in order to fulfill String's contract.
--- a/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +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. - */ - -package jdk.internal.misc; - -public interface JavaLangInvokeAccess { - /** - * Create a new MemberName instance - */ - Object newMemberName(); -}
--- a/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java Tue Nov 24 11:50:20 2015 +0000 +++ b/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java Tue Nov 24 18:32:38 2015 +0000 @@ -45,7 +45,6 @@ private static final Unsafe unsafe = Unsafe.getUnsafe(); private static JavaUtilJarAccess javaUtilJarAccess; private static JavaLangAccess javaLangAccess; - private static JavaLangInvokeAccess javaLangInvokeAccess; private static JavaLangRefAccess javaLangRefAccess; private static JavaIOAccess javaIOAccess; private static JavaNetAccess javaNetAccess; @@ -81,20 +80,6 @@ return javaLangAccess; } - public static void setJavaLangInvokeAccess(JavaLangInvokeAccess jlia) { - javaLangInvokeAccess = jlia; - } - - public static JavaLangInvokeAccess getJavaLangInvokeAccess() { - if (javaLangInvokeAccess == null) { - try { - Class<?> c = Class.forName("java.lang.invoke.MemberName"); - unsafe.ensureClassInitialized(c); - } catch (ClassNotFoundException e) {}; - } - return javaLangInvokeAccess; - } - public static void setJavaLangRefAccess(JavaLangRefAccess jlra) { javaLangRefAccess = jlra; }
--- a/src/java.base/share/native/include/jvm.h Tue Nov 24 11:50:20 2015 +0000 +++ b/src/java.base/share/native/include/jvm.h Tue Nov 24 18:32:38 2015 +0000 @@ -178,37 +178,6 @@ JVM_GetStackTraceElement(JNIEnv *env, jobject throwable, jint index); /* - * java.lang.StackWalker - */ -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 -}; - -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); - -/* * java.lang.Thread */ JNIEXPORT void JNICALL
--- a/src/java.base/share/native/libjava/StackFrameInfo.c Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +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 <stdio.h> -#include <signal.h> - -#include "jni.h" -#include "jvm.h" - -#include "java_lang_StackFrameInfo.h" - - -/* - * Class: java_lang_StackFrameInfo - * Method: fillInStackFrames - * Signature: (I[Ljava/lang/Object;[Ljava/lang/Object;II)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); -}
--- a/src/java.base/share/native/libjava/StackStreamFactory.c Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +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 StackStreamfactory and AbstractStackWalker - */ - -#include <stdio.h> -#include <signal.h> - -#include "jni.h" -#include "jvm.h" - -#include "java_lang_StackStreamFactory.h" -#include "java_lang_StackStreamFactory_AbstractStackWalker.h" - -/* - * Class: java_lang_StackStreamFactory - * Method: checkStackWalkModes - * Signature: () - */ -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; -} - -/* - * Class: java_lang_StackStreamFactory_AbstractStackWalker - * Method: callStackWalk - * Signature: (JIII[Ljava/lang/Class;[Ljava/lang/StackWalker/StackFrame;)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) -{ - return JVM_CallStackWalk(env, stackstream, mode, skipFrames, batchSize, - startIndex, classes, frames); -} - -/* - * Class: java_lang_StackStreamFactory_AbstractStackWalker - * Method: fetchStackFrames - * Signature: (JJII[Ljava/lang/Class;[Ljava/lang/StackWalker/StackFrame;)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) -{ - return JVM_MoreStackWalk(env, stackstream, mode, anchor, batchSize, - startIndex, classes, frames); -}
--- a/src/java.logging/share/classes/java/util/logging/LogRecord.java Tue Nov 24 11:50:20 2015 +0000 +++ b/src/java.logging/share/classes/java/util/logging/LogRecord.java Tue Nov 24 18:32:38 2015 +0000 @@ -30,8 +30,9 @@ import java.util.concurrent.atomic.AtomicLong; import java.io.*; import java.time.Clock; -import java.util.function.Predicate; +import jdk.internal.misc.JavaLangAccess; +import jdk.internal.misc.SharedSecrets; import static jdk.internal.logger.SimpleConsoleLogger.skipLoggingFrame; /** @@ -660,58 +661,42 @@ // private void inferCaller() { needToInferCaller = false; - // Skip all frames until we have found the first logger frame. - Optional<StackWalker.StackFrame> frame = new CallerFinder().get(); - frame.ifPresent(f -> { - setSourceClassName(f.getClassName()); - setSourceMethodName(f.getMethodName()); - }); + JavaLangAccess access = SharedSecrets.getJavaLangAccess(); + Throwable throwable = new Throwable(); + int depth = access.getStackTraceDepth(throwable); + boolean lookingForLogger = true; + for (int ix = 0; ix < depth; ix++) { + // Calling getStackTraceElement directly prevents the VM + // from paying the cost of building the entire stack frame. + StackTraceElement frame = + access.getStackTraceElement(throwable, ix); + String cname = frame.getClassName(); + boolean isLoggerImpl = isLoggerImplFrame(cname); + if (lookingForLogger) { + // Skip all frames until we have found the first logger frame. + if (isLoggerImpl) { + lookingForLogger = false; + } + } else { + if (!isLoggerImpl) { + // skip logging/logger infrastructure and reflection calls + if (!skipLoggingFrame(cname)) { + // We've found the relevant frame. + setSourceClassName(cname); + setSourceMethodName(frame.getMethodName()); + return; + } + } + } + } // We haven't found a suitable frame, so just punt. This is // OK as we are only committed to making a "best effort" here. } - /* - * CallerFinder is a stateful predicate. - */ - static final class CallerFinder implements Predicate<StackWalker.StackFrame> { - static final StackWalker WALKER = StackWalker.getInstance(); - - /** - * Returns StackFrame of the caller's frame. - * @return StackFrame of the caller's frame. - */ - Optional<StackWalker.StackFrame> get() { - return WALKER.walk((s) -> s.filter(this).findFirst()); - } - - private boolean lookingForLogger = true; - /** - * Returns true if we have found the caller's frame, false if the frame - * must be skipped. - * - * @param t The frame info. - * @return true if we have found the caller's frame, false if the frame - * must be skipped. - */ - @Override - public boolean test(StackWalker.StackFrame t) { - final String cname = t.getClassName(); - // We should skip all frames until we have found the logger, - // because these frames could be frames introduced by e.g. custom - // sub classes of Handler. - if (lookingForLogger) { - // the log record could be created for a platform logger - lookingForLogger = !isLoggerImplFrame(cname); - return false; - } - // skip logging/logger infrastructure and reflection calls - return !skipLoggingFrame(cname); - } - - private boolean isLoggerImplFrame(String cname) { - return (cname.equals("java.util.logging.Logger") || - cname.startsWith("sun.util.logging.PlatformLogger")); - } + private boolean isLoggerImplFrame(String cname) { + // the log record could be created for a platform logger + return (cname.equals("java.util.logging.Logger") || + cname.startsWith("sun.util.logging.PlatformLogger")); } }
--- a/test/java/lang/StackWalker/AcrossThreads.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,227 +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. - * - * 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 8140450 - * @summary Verify that StackWalker works well when one instance of StackWalker - * is used by several threads sequentially or concurrently. - * @run testng AcrossThreads - */ - -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import java.lang.StackWalker.StackFrame; -import static java.lang.StackWalker.Option.*; - -import org.testng.annotations.*; -import static org.testng.Assert.*; - -public class AcrossThreads { - static final StackWalker WALKERS[] = new StackWalker[] { - StackWalker.getInstance(RETAIN_CLASS_REFERENCE), - StackWalker.getInstance(EnumSet.of(SHOW_REFLECT_FRAMES, RETAIN_CLASS_REFERENCE)), - StackWalker.getInstance(EnumSet.of(SHOW_HIDDEN_FRAMES, RETAIN_CLASS_REFERENCE)) - }; - - @DataProvider - public StackWalker[][] walkerProvider() { - return new StackWalker[][] { - new StackWalker[] { WALKERS[0] }, - new StackWalker[] { WALKERS[1] }, - new StackWalker[] { WALKERS[2] } - }; - } - - @Test(dataProvider = "walkerProvider") - public void test(StackWalker walker) { - Thread t1 = new T1(walker); - // call methods of one instance of StackWalker sequentially in T1, T2, T3. - t1.start(); - try { - t1.join(); - } catch (InterruptedException e) { } - - List<Thread> threads = new ArrayList<Thread>(); - for (int i = 0; i < 100; i++) { - threads.add(new T1(walker)); - threads.add(new T2(walker)); - threads.add(new T3(walker)); - } - // call methods of one instance of StackWalker concurrently in several threads. - threads.parallelStream().forEach(t -> { - t.setDaemon(true); - t.start(); - }); - threads.parallelStream().forEach(t -> { - try { - t.join(); - } catch (InterruptedException e) { } - }); - } - - interface Consumer { - final int LOOPS = 5; - - public void consume(); - - default public void assertWalker(StackWalker walker, int n) { - if (--n == 0) { - Map<String, Integer> methods = new HashMap<String, Integer>(); - walker.forEach(f -> { - Integer i = methods.putIfAbsent(f.getMethodName(), 1); - if (i != null) { - methods.put(f.getMethodName(), i + 1); - } - }); - - // verify that walker.forEach(...) reaches the specified methods. - assertTrue(methods.get("consume") == 1); - assertTrue(methods.get("run") == 1); - assertTrue(methods.get("assertWalker") == LOOPS); - - // verify that walker.walk(...) reaches the specified methods. - assertTrue(walker.walk(s -> s.map(StackFrame::getMethodName) - .filter(mn -> mn.equals("consume")) - .count()) == 1); - assertTrue(walker.walk(s -> s.map(StackFrame::getMethodName) - .filter(mn -> mn.equals("run")) - .count()) == 1); - assertTrue(walker.walk(s -> s.map(StackFrame::getMethodName) - .filter(mn -> mn.equals("assertWalker")) - .count()) == LOOPS); - } else { - assertWalker(walker, n); - } - } - } - - class T1 extends Thread implements Consumer { - final StackWalker walker; - - public T1(StackWalker walker) { - this.walker = walker; - } - - public void run() { - consume(); - - Thread t2 = new T2(walker); - t2.start(); - try { - t2.join(); - } catch (InterruptedException e) { } - - consume(); - } - - public void consume() { - assertWalker(walker, LOOPS); - - // verify walker.walk() reaches T1 class through methods run() and consume(). - assertTrue(walker.walk(s -> s.filter(f -> T1.class == f.getDeclaringClass()) - .count()) == 2); - - assertCallerClass(walker); - assertEquals(T1.class, walker.getCallerClass()); - } - } - - class T2 extends Thread implements Consumer { - final StackWalker walker; - - public T2(StackWalker walker) { - this.walker = walker; - } - - public void run() { - consume(); - - Thread t3 = new T3(walker); - t3.start(); - try { - t3.join(); - } catch (InterruptedException e) { } - - consume(); - } - - public void consume() { - assertWalker(walker, LOOPS); - - // verify walker.walk() reaches T2 class through methods run() and consume(). - assertTrue(walker.walk(s -> s.filter(f -> T2.class == f.getDeclaringClass()) - .count()) == 2); - // verify T1 is not reached, even if call is invoked - // from test()->T1.start()->T1.run()->T2 - assertTrue(walker.walk(s -> s.filter(f -> T1.class == f.getDeclaringClass()) - .count()) == 0); - - assertCallerClass(walker); - assertEquals(T2.class, walker.getCallerClass()); - } - } - - class T3 extends Thread implements Consumer { - final StackWalker walker; - - public T3(StackWalker walker) { - this.walker = walker; - } - - public void run() { - consume(); - } - - public void consume() { - assertWalker(walker, LOOPS); - - // verify walker.walk() reaches T1 class through methods run() and consume(). - assertTrue(walker.walk(s -> s.filter(f -> T3.class == f.getDeclaringClass()) - .count()) == 2); - // verify T1, T2 is not reached, even if call is invoked - // from test() -> T1.start() -> T1.run() -> T2.start() -> T2.run() -> T3 - assertTrue(walker.walk(s -> s.filter(f -> T2.class == f.getDeclaringClass()) - .count()) == 0); - assertTrue(walker.walk(s -> s.filter(f -> T1.class == f.getDeclaringClass()) - .count()) == 0); - - assertCallerClass(walker); - assertEquals(T3.class, walker.getCallerClass()); - } - } - - static void assertCallerClass(StackWalker walker) { - // verify walker.getCallerClass() get the expected class. - call(walker); - } - - static void call(StackWalker walker) { - Class<?> c = walker.getCallerClass(); - assertEquals(c, AcrossThreads.class); - } -}
--- a/test/java/lang/StackWalker/Basic.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,139 +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. - * - * 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 8140450 - * @summary Basic test for the StackWalker::walk method - * @run testng Basic - */ - -import java.lang.StackWalker.StackFrame; -import java.util.List; -import java.util.stream.Collectors; -import static java.lang.StackWalker.Option.*; - -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -public class Basic { - private static boolean verbose = false; - - @DataProvider(name = "stackDepths") - public static Object[][] stackDepths() { - return new Object[][] { - { new int[] { 12 }, new int[] { 4, 8, 12} }, - { new int[] { 18 }, new int[] { 8, 16, 20} }, - { new int[] { 32 }, new int[] { 16, 32, 64} }, - }; - } - - /** - * For a stack of a given depth, it creates a StackWalker with an estimate. - * Test walking different number of frames - */ - @Test(dataProvider = "stackDepths") - public static void test(int[] depth, int[] estimates) { - Basic test = new Basic(depth[0]); - for (int estimate : estimates) { - test.walk(estimate); - } - } - - private final int depth; - Basic(int depth) { - this.depth = depth; - } - - /* - * Setup a stack builder with the expected stack depth - * Walk the stack and count the frames. - */ - void walk(int estimate) { - int limit = Math.min(depth, 16); - List<StackFrame> frames = new StackBuilder(depth, limit).build(); - System.out.format("depth=%d estimate=%d expected=%d walked=%d%n", - depth, estimate, limit, frames.size()); - assertEquals(limit, frames.size()); - } - - class StackBuilder { - private final int stackDepth; - private final int limit; - private int depth = 0; - private List<StackFrame> result; - StackBuilder(int stackDepth, int limit) { - this.stackDepth = stackDepth; // build method; - this.limit = limit; - } - List<StackFrame> build() { - trace("build"); - m1(); - return result; - } - void m1() { - trace("m1"); - m2(); - } - void m2() { - trace("m2"); - m3(); - } - void m3() { - trace("m3"); - m4(); - } - void m4() { - trace("m4"); - int remaining = stackDepth-depth-1; - if (remaining >= 4) { - m1(); - } else { - filler(remaining); - } - } - void filler(int i) { - trace("filler"); - if (i == 0) - walk(); - else - filler(--i); - } - - void walk() { - StackWalker walker = StackWalker.getInstance(RETAIN_CLASS_REFERENCE); - result = walker.walk(s -> s.limit(limit).collect(Collectors.toList())); - } - void trace(String methodname) { - ++depth; - if (verbose) - System.out.format("%2d: %s%n", depth, methodname); - } - } - - static void assertEquals(int x, int y) { - if (x != y) { - throw new RuntimeException(x + " != " + y); - } - } -}
--- a/test/java/lang/StackWalker/CallerFromMain.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +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. - * - * 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 8140450 - * @library /lib/testlibrary - * @build jdk.testlibrary.* - * @summary Test if the getCallerClass method returns empty optional - * @run main CallerFromMain exec - */ - -import jdk.testlibrary.ProcessTools; -import jdk.testlibrary.OutputAnalyzer; - -public class CallerFromMain { - - private static final StackWalker sw = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); - public static void main(String[] args) throws Exception { - if (args.length > 0) { - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, "CallerFromMain"); - OutputAnalyzer output = ProcessTools.executeProcess(pb); - System.out.println(output.getOutput()); - output.shouldHaveExitValue(0); - return; - } - - // StackWalker::getCallerClass - // CallerFromMain::main - // no caller - try { - Class<?> c = sw.getCallerClass(); - throw new RuntimeException("UOE not thrown. Caller: " + c); - } catch (IllegalStateException e) {} - - // StackWalker::getCallerClass - // Runnable::run - // Thread::run - Thread t1 = new Thread(new Runnable() { - @Override - public void run() { - Class<?> c = sw.getCallerClass(); - System.out.println("Call from Thread.run: " + c); - assertThreadClassAsCaller(c); - } - }); - t1.setDaemon(true); - t1.start(); - - // StackWalker::getCallerClass - // CallerFromMain::doit - // Thread::run - Thread t2 = new Thread(CallerFromMain::doit); - t2.setDaemon(true); - t2.start(); - - // StackWalker::getCallerClass - // MyRunnable::run - // Thread::run - Thread t3 = new Thread(new MyRunnable()); - t3.setDaemon(true); - t3.start(); - - // StackWalker::getCallerClass - // Runnable::run - // MyThread::run - Thread t4 = new MyThread(new Runnable() { - @Override - public void run() { - Class<?> c = sw.getCallerClass(); - System.out.println("Call from MyThread.run: " + c); - if (c != MyThread.class) { - throw new RuntimeException("Expected MyThread.class but got " + c); - } - } - }); - t4.setDaemon(true); - t4.start(); - - t1.join(); - t2.join(); - t3.join(); - t4.join(); - } - - static class MyThread extends Thread { - final Runnable runnable; - MyThread(Runnable runnable) { - super("MyThread"); - this.runnable = runnable; - } - public void run() { - runnable.run(); - } - } - - static class MyRunnable implements Runnable { - @Override - public void run() { - Class<?> c = sw.getCallerClass(); - System.out.println("Call from Thread::run: " + c); - assertThreadClassAsCaller(c); - } - } - - static void doit() { - Class<?> c = sw.getCallerClass(); - System.out.println("Call from CallerFromMain.doit: " + c); - assertThreadClassAsCaller(c); - } - - static void assertThreadClassAsCaller(Class<?> caller) { - if (caller != Thread.class) { - throw new RuntimeException("Expected Thread.class but got " + caller); - } - } -}
--- a/test/java/lang/StackWalker/DumpStackTest.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,234 +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. - * - * 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 8140450 - * @summary Verify outputs of Thread.dumpStack() and Throwable.printStackTrace(). - * 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; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.function.Consumer; - -public class DumpStackTest { - - public static void main(String args[]) { - test(); - testThread(); - testLambda(); - testMethodInvoke(); - testMethodHandle(); - } - - static class CallFrame { - final String classname; - final String methodname; - CallFrame(Class<?> c, String methodname) { - this(c.getName(), methodname); - } - CallFrame(String classname, String methodname) { - this.classname = classname; - this.methodname = methodname; - } - - String getClassName() { - return classname; - } - String getMethodName() { - return methodname; - } - String getFileName() { - int i = classname.lastIndexOf('.'); - int j = classname.lastIndexOf('$'); - String name = classname.substring(i+1, j >= 0 ? j : classname.length()); - return name + ".java"; - } - @Override - public String toString() { - return classname + "." + methodname + "(" + getFileName() + ")"; - } - } - - static void test() { - CallFrame[] callStack = new CallFrame[] { - new CallFrame(Thread.class, "getStackTrace"), - new CallFrame(DumpStackTest.class, "test"), - new CallFrame(DumpStackTest.class, "main"), - // if invoked from jtreg - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke0"), // non-public class - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke"), - new CallFrame("sun.reflect.DelegatingMethodAccessorImpl", "invoke"), - new CallFrame(Method.class, "invoke"), - new CallFrame(Thread.class, "run"), - }; - - assertStackTrace(Thread.currentThread().getStackTrace(), callStack); - getStackTrace(callStack); - } - - static void getStackTrace(CallFrame[] callStack) { - // this method is the top of the stack - callStack[0] = new CallFrame(DumpStackTest.class, "getStackTrace"); - - try { - throw new RuntimeException(); - } catch(RuntimeException ex) { - assertStackTrace(ex.getStackTrace(), callStack); - } - } - static void testThread() { - Thread t1 = new Thread() { - public void run() { - c(); - } - - void c() { - CallFrame[] callStack = new CallFrame[] { - new CallFrame(Thread.class, "getStackTrace"), - new CallFrame(this.getClass(), "c"), - new CallFrame(this.getClass(), "run") - }; - assertStackTrace(Thread.currentThread().getStackTrace(), callStack); - DumpStackTest.getStackTrace(callStack); - } - }; - t1.start(); - try { - t1.join(); - } catch(InterruptedException e) {} - } - - static void testLambda() { - Consumer<Void> c = (x) -> consumeLambda(); - c.accept(null); - } - - static void consumeLambda() { - CallFrame[] callStack = new CallFrame[]{ - new CallFrame(Thread.class, "getStackTrace"), - new CallFrame(DumpStackTest.class, "consumeLambda"), - new CallFrame(DumpStackTest.class, "lambda$testLambda$0"), - new CallFrame(DumpStackTest.class, "testLambda"), - new CallFrame(DumpStackTest.class, "main"), - // if invoked from jtreg - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke0"), - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke"), - new CallFrame("sun.reflect.DelegatingMethodAccessorImpl", "invoke"), - new CallFrame(Method.class, "invoke"), - new CallFrame(Thread.class, "run") - }; - assertStackTrace(Thread.currentThread().getStackTrace(), callStack); - DumpStackTest.getStackTrace(callStack); - } - - static void testMethodInvoke() { - try { - Method m = DumpStackTest.class.getDeclaredMethod("methodInvoke"); - m.invoke(null); - } catch(Exception e) { - throw new RuntimeException(e); - } - } - - static void methodInvoke() { - CallFrame[] callStack = new CallFrame[] { - new CallFrame(Thread.class, "getStackTrace"), - new CallFrame(DumpStackTest.class, "methodInvoke"), - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke0"), - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke"), - new CallFrame("sun.reflect.DelegatingMethodAccessorImpl", "invoke"), - new CallFrame(Method.class, "invoke"), - new CallFrame(DumpStackTest.class, "testMethodInvoke"), - new CallFrame(DumpStackTest.class, "main"), - // if invoked from jtreg - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke0"), - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke"), - new CallFrame("sun.reflect.DelegatingMethodAccessorImpl", "invoke"), - new CallFrame(Method.class, "invoke"), - new CallFrame(Thread.class, "run") - }; - assertStackTrace(Thread.currentThread().getStackTrace(), callStack); - DumpStackTest.getStackTrace(callStack); - } - - static void testMethodHandle() { - MethodHandles.Lookup lookup = MethodHandles.lookup(); - try { - MethodHandle handle = lookup.findStatic(DumpStackTest.class, "methodHandle", - MethodType.methodType(void.class)); - handle.invoke(); - } catch(Throwable t) { - throw new RuntimeException(t); - } - } - - static void methodHandle() { - CallFrame[] callStack = new CallFrame[]{ - new CallFrame(Thread.class, "getStackTrace"), - new CallFrame(DumpStackTest.class, "methodHandle"), - new CallFrame(DumpStackTest.class, "testMethodHandle"), - new CallFrame(DumpStackTest.class, "main"), - // if invoked from jtreg - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke0"), - new CallFrame("sun.reflect.NativeMethodAccessorImpl", "invoke"), - new CallFrame("sun.reflect.DelegatingMethodAccessorImpl", "invoke"), - new CallFrame(Method.class, "invoke"), - new CallFrame(Thread.class, "run") - }; - assertStackTrace(Thread.currentThread().getStackTrace(), callStack); - DumpStackTest.getStackTrace(callStack); - } - - static void assertStackTrace(StackTraceElement[] actual, CallFrame[] expected) { - System.out.println("--- Actual ---"); - Arrays.stream(actual).forEach(e -> System.out.println(e)); - System.out.println("--- Expected ---"); - Arrays.stream(expected).forEach(e -> System.out.println(e)); - - for (int i = 0, j = 0; i < actual.length; i++) { - // filter test framework classes - if (actual[i].getClassName().startsWith("com.sun.javatest.regtest")) - continue; - assertEquals(actual[i], expected[j++], i); - } - - } - static void assertEquals(StackTraceElement actual, CallFrame expected, int idx) { - if (!actual.getClassName().equals(expected.getClassName()) || - !actual.getFileName().equals(expected.getFileName()) || - !actual.getMethodName().equals(expected.getMethodName())) { - throw new RuntimeException("StackTraceElements mismatch at index " + idx + - ". Expected [" + expected + "], but get [" + actual + "]"); - } - } -}
--- a/test/java/lang/StackWalker/EmbeddedStackWalkTest.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,158 +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. - * - * 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 8140450 - * @summary Verify StackWalker works well when embedded in another - * StackWalker's functions. - * @run testng/othervm EmbeddedStackWalkTest - */ - -import java.lang.StackWalker.StackFrame; -import static java.lang.StackWalker.Option.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.util.Arrays; -import java.util.EnumSet; - -import org.testng.annotations.*; -import static org.testng.Assert.*; - -public class EmbeddedStackWalkTest { - static final StackWalker WALKERS[] = new StackWalker[] { - StackWalker.getInstance(RETAIN_CLASS_REFERENCE), - StackWalker.getInstance(EnumSet.of(SHOW_REFLECT_FRAMES, RETAIN_CLASS_REFERENCE)), - StackWalker.getInstance(EnumSet.of(SHOW_HIDDEN_FRAMES, RETAIN_CLASS_REFERENCE)) - }; - - static final int BIG_LOOP = 30; - static final int SMALL_LOOP = 5; - - @DataProvider - public StackWalker[][] walkerProvider() { - return new StackWalker[][] { - new StackWalker[] { WALKERS[0] }, - new StackWalker[] { WALKERS[1] }, - new StackWalker[] { WALKERS[2] } - }; - } - - @Test(dataProvider = "walkerProvider") - public void test(StackWalker walker) { - C1.call(walker, BIG_LOOP); - } - - // line numbers are hardcoded for now. - // Should annotate the line numbers and auto-generated these constants - // for test verification instead - static final int BEGIN_LINE = 71; // the begin line number of approximate range. - static final int END_LINE = 136; // the end line number of approximate range. - static class C1 { // here is the begin line number of approximate range, L71. - public static void call(StackWalker walker, int loops) { - if (loops == 0) { - String caller = walker.walk(s -> - s.map(StackFrame::getClassName) - .filter(cn -> !cn.startsWith("sun.reflect.") && !cn.startsWith("java.lang.invoke")) - .skip(2).findFirst() - ).get(); - assertEquals(caller, C1.class.getName()); - - walker.forEach(f -> C2.testEmbeddedWalker()); - } else { - call(walker, --loops); - } - } - } - - static class C2 { - static final StackWalker embeddedWalkers[] = new StackWalker[] { - StackWalker.getInstance(), - StackWalker.getInstance(SHOW_REFLECT_FRAMES), - StackWalker.getInstance(SHOW_HIDDEN_FRAMES) - }; - - public static void testEmbeddedWalker() { - walk(SMALL_LOOP); - } - - static void walk(int loops) { - if (loops == 0) { - Arrays.stream(embeddedWalkers) - .forEach(walker -> run(walker)); - } else { - walk(--loops); - } - } - - static void run(StackWalker walker) { - MethodHandles.Lookup lookup = MethodHandles.lookup(); - MethodHandle handle = null; - try { - handle = lookup.findStatic(C2.class, "call", - MethodType.methodType(void.class, StackWalker.class)); - handle.invoke(walker); - } catch(Throwable t) { - throw new RuntimeException(t); - } - } - - static void call(StackWalker walker) { - String caller = walker.walk(s -> - s.map(StackFrame::getClassName) - .filter(cn -> !cn.startsWith("sun.reflect.") && !cn.startsWith("java.lang.invoke")) - .skip(2).findFirst() - ).get(); - assertEquals(caller, C2.class.getName()); - - verify(walker, C1.class, "call"); - verify(walker, C2.class, "call"); - verify(walker, C2.class, "run"); - verify(walker, C2.class, "walk"); - verify(walker, C2.class, "testEmbeddedWalker"); - } // here is the end line number of approximate range, L136. - - static void verify(StackWalker walker, Class<?> c, String mn) { - final String fileName = "EmbeddedStackWalkTest.java"; - walker.walk(s -> { - s.limit(BIG_LOOP) - .filter(f -> c.getName().equals(f.getClassName()) && mn.equals(f.getMethodName())) - .forEach(f -> { - assertEquals(f.getFileName().get(), fileName); - int line = f.getLineNumber().getAsInt(); - assertTrue(line >= BEGIN_LINE && line <= END_LINE); - - StackTraceElement st = f.toStackTraceElement(); - assertEquals(c.getName(), st.getClassName()); - assertEquals(mn, st.getMethodName()); - assertEquals(st.getFileName(), fileName); - line = st.getLineNumber(); - assertTrue(line >= BEGIN_LINE && line <= END_LINE); - }); - return null; - }); - } - } -}
--- a/test/java/lang/StackWalker/GetCallerClassTest.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,253 +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. - * - * 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 8140450 - * @summary Basic test for StackWalker.getCallerClass() - * @run main/othervm -XX:-MemberNameInStackFrame GetCallerClassTest - * @run main/othervm -XX:+MemberNameInStackFrame GetCallerClassTest - * @run main/othervm GetCallerClassTest sm - */ - -import static java.lang.StackWalker.Option.*; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.security.Permission; -import java.security.PermissionCollection; -import java.security.Permissions; -import java.security.Policy; -import java.security.ProtectionDomain; -import java.util.Arrays; -import java.util.List; - -public class GetCallerClassTest { - private final StackWalker walker; - private final boolean expectUOE; - - public GetCallerClassTest(StackWalker sw, boolean expect) { - this.walker = sw; - this.expectUOE = expect; - } - public static void main(String... args) throws Exception { - if (args.length > 0 && args[0].equals("sm")) { - PermissionCollection perms = new Permissions(); - perms.add(new StackFramePermission("retainClassReference")); - Policy.setPolicy(new Policy() { - @Override - public boolean implies(ProtectionDomain domain, Permission p) { - return perms.implies(p); - } - }); - System.setSecurityManager(new SecurityManager()); - } - new GetCallerClassTest(StackWalker.getInstance(), true).test(); - new GetCallerClassTest(StackWalker.getInstance(RETAIN_CLASS_REFERENCE), false).test(); - } - - public void test() { - new TopLevelCaller().run(); - new Nested().createNestedCaller().run(); - new InnerClassCaller().run(); - new ReflectionTest().run(); - - List<Thread> threads = Arrays.asList( - new Thread(new TopLevelCaller()), - new Thread(new Nested().createNestedCaller()), - new Thread(new InnerClassCaller()), - new Thread(new ReflectionTest()) - ); - threads.stream().forEach(Thread::start); - threads.stream().forEach(t -> { - try { - t.join(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - }); - } - - public static void staticGetCallerClass(StackWalker stackWalker, - Class<?> expected, - boolean expectUOE) { - try { - Class<?> c = stackWalker.getCallerClass(); - assertEquals(c, expected); - if (expectUOE) { // Should have thrown - throw new RuntimeException("Didn't get expected exception"); - } - } catch (RuntimeException e) { // also catches UOE - if (expectUOE && causeIsUOE(e)) { - return; /* expected */ - } - System.err.println("Unexpected exception:"); - throw e; - } - } - - public static void reflectiveGetCallerClass(StackWalker stackWalker, - Class<?> expected, - boolean expectUOE) { - try { - Method m = StackWalker.class.getMethod("getCallerClass"); - Class<?> c = (Class<?>) m.invoke(stackWalker); - assertEquals(c, expected); - if (expectUOE) { // Should have thrown - throw new RuntimeException("Didn't get expected exception"); - } - } catch (Throwable e) { - if (expectUOE && causeIsUOE(e)) { - return; /* expected */ - } - System.err.println("Unexpected exception:"); - throw new RuntimeException(e); - } - } - - public static void methodHandleGetCallerClass(StackWalker stackWalker, - Class<?> expected, - boolean expectUOE) { - MethodHandles.Lookup lookup = MethodHandles.lookup(); - try { - MethodHandle mh = lookup.findVirtual(StackWalker.class, "getCallerClass", - MethodType.methodType(Class.class)); - Class<?> c = (Class<?>) mh.invokeExact(stackWalker); - assertEquals(c, expected); - if (expectUOE) { // Should have thrown - throw new RuntimeException("Didn't get expected exception"); - } - } catch (Throwable e) { - if (expectUOE && causeIsUOE(e)) { - return; /* expected */ - } - System.err.println("Unexpected exception:"); - throw new RuntimeException(e); - } - } - - public static void assertEquals(Class<?> c, Class<?> expected) { - if (expected != c) { - throw new RuntimeException(c + " != " + expected); - } - } - - /** Is there an UnsupportedOperationException in there? */ - public static boolean causeIsUOE(Throwable t) { - while (t != null) { - if (t instanceof UnsupportedOperationException) { - return true; - } - t = t.getCause(); - } - return false; - } - - class TopLevelCaller implements Runnable { - public void run() { - GetCallerClassTest.staticGetCallerClass(walker, this.getClass(), expectUOE); - GetCallerClassTest.reflectiveGetCallerClass(walker, this.getClass(), expectUOE); - GetCallerClassTest.methodHandleGetCallerClass(walker, this.getClass(), expectUOE); - } - } - - class Nested { - NestedClassCaller createNestedCaller() { return new NestedClassCaller(); } - class NestedClassCaller implements Runnable { - public void run() { - GetCallerClassTest.staticGetCallerClass(walker, this.getClass(), expectUOE); - GetCallerClassTest.reflectiveGetCallerClass(walker, this.getClass(), expectUOE); - GetCallerClassTest.methodHandleGetCallerClass(walker, this.getClass(), expectUOE); - } - } - } - - class InnerClassCaller implements Runnable { - public void run() { - new Inner().test(); - } - class Inner { - void test() { - GetCallerClassTest.staticGetCallerClass(walker, this.getClass(), expectUOE); - GetCallerClassTest.reflectiveGetCallerClass(walker, this.getClass(), expectUOE); - GetCallerClassTest.methodHandleGetCallerClass(walker, this.getClass(), expectUOE); - } - } - } - - class ReflectionTest implements Runnable { - final MethodType methodType = - MethodType.methodType(void.class, StackWalker.class, Class.class, boolean.class); - - public void run() { - callMethodHandle(); - callMethodHandleRefl(); - callMethodInvoke(); - callMethodInvokeRefl(); - } - void callMethodHandle() { - MethodHandles.Lookup lookup = MethodHandles.publicLookup(); - try { - MethodHandle mh = lookup.findStatic(GetCallerClassTest.class, - "staticGetCallerClass", - methodType); - mh.invokeExact(walker, ReflectionTest.class, expectUOE); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - void callMethodHandleRefl() { - MethodHandles.Lookup lookup = MethodHandles.publicLookup(); - try { - MethodHandle mh = lookup.findStatic(GetCallerClassTest.class, - "reflectiveGetCallerClass", - methodType); - mh.invokeExact(walker, ReflectionTest.class, expectUOE); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - void callMethodInvoke() { - try { - Method m = GetCallerClassTest.class.getMethod("staticGetCallerClass", - StackWalker.class, Class.class, boolean.class); - m.invoke(null, walker, ReflectionTest.class, expectUOE); - } catch (NoSuchMethodException|IllegalAccessException|InvocationTargetException e) { - throw new RuntimeException(e); - } - } - void callMethodInvokeRefl() { - try { - Method m = GetCallerClassTest.class.getMethod("reflectiveGetCallerClass", - StackWalker.class, Class.class, boolean.class); - m.invoke(null, walker, ReflectionTest.class, expectUOE); - } catch (UnsupportedOperationException e) { - throw e; - } catch (NoSuchMethodException|IllegalAccessException|InvocationTargetException e) { - throw new RuntimeException(e); - } - } - } -}
--- a/test/java/lang/StackWalker/HiddenFrames.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +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. - * - * 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 8140450 - * @summary Basic test for hidden frames - * @run main HiddenFrames - */ - -import java.lang.StackWalker.Option; -import java.lang.StackWalker.StackFrame; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Stream; - -public class HiddenFrames { - public static void main(String... args) throws Exception { - new HiddenFrames().test(); - new HiddenFrames(Option.SHOW_REFLECT_FRAMES).test(); - new HiddenFrames(Option.SHOW_HIDDEN_FRAMES).test(); - } - - private final Option option; - private final StackWalker walker; - private final List<StackFrame> lambdas = new ArrayList<>(); - private final List<StackFrame> reflects = new ArrayList<>(); - - HiddenFrames() { - this.option = null; - this.walker = StackWalker.getInstance(); - } - HiddenFrames(Option option) { - this.option = option; - this.walker = StackWalker.getInstance(option); - } - - void test() throws Exception { - walk(); - walkFromReflection(); - } - - void walk() { - Stream.of(0).forEach(i -> walker.walk(s -> - { - s.forEach(this::checkFrame); - return null; - })); - - // only check hidden frames but not reflection frames - // walk is not invoked via reflection - if (option == null && !lambdas.isEmpty()) { - throw new RuntimeException("Hidden frames are shown"); - } - - if (option == Option.SHOW_HIDDEN_FRAMES && lambdas.isEmpty()) { - throw new RuntimeException("No hidden Lambda frame"); - } - } - - void walkFromReflection() throws Exception { - Method m = HiddenFrames.class.getDeclaredMethod("walk"); - m.invoke(this); - - if (option == null && !lambdas.isEmpty()) { - throw new RuntimeException("Hidden frames are shown"); - } - - if (option == Option.SHOW_HIDDEN_FRAMES && lambdas.isEmpty()) { - throw new RuntimeException("No hidden Lambda frame"); - } - - if (option != null && reflects.isEmpty()) { - throw new RuntimeException("No reflection frame"); - } - } - - void checkFrame(StackFrame frame) { - String cn = frame.getClassName(); - if (cn.startsWith("java.lang.reflect.") || cn.startsWith("sun.reflect.")) { - reflects.add(frame); - } - if (cn.contains("$$Lambda$")) { - lambdas.add(frame); - } - } -}
--- a/test/java/lang/StackWalker/LocalsAndOperands.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +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. - * - * 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 8140450 - * @summary Sanity test for locals and operands - * @run main LocalsAndOperands - */ - -import java.lang.StackWalker.StackFrame; -import java.lang.reflect.*; -import java.util.List; -import java.util.stream.Collectors; - -public class LocalsAndOperands { - static Class<?> liveStackFrameClass; - static Class<?> primitiveValueClass; - static StackWalker extendedWalker; - static Method getLocals; - static Method getOperands; - static Method getMonitors; - static Method primitiveType; - public static void main(String... args) throws Exception { - liveStackFrameClass = Class.forName("java.lang.LiveStackFrame"); - primitiveValueClass = Class.forName("java.lang.LiveStackFrame$PrimitiveValue"); - - getLocals = liveStackFrameClass.getDeclaredMethod("getLocals"); - getLocals.setAccessible(true); - - getOperands = liveStackFrameClass.getDeclaredMethod("getStack"); - getOperands.setAccessible(true); - - getMonitors = liveStackFrameClass.getDeclaredMethod("getMonitors"); - getMonitors.setAccessible(true); - - primitiveType = primitiveValueClass.getDeclaredMethod("type"); - primitiveType.setAccessible(true); - - Method method = liveStackFrameClass.getMethod("getStackWalker"); - method.setAccessible(true); - extendedWalker = (StackWalker) method.invoke(null); - new LocalsAndOperands(extendedWalker, true).test(); - - // no access to local and operands. - new LocalsAndOperands(StackWalker.getInstance(), false).test(); - } - - private final StackWalker walker; - private final boolean extended; - LocalsAndOperands(StackWalker walker, boolean extended) { - this.walker = walker; - this.extended = extended; - } - - synchronized void test() throws Exception { - int x = 10; - char c = 'z'; - String hi = "himom"; - long l = 1000000L; - double d = 3.1415926; - - List<StackWalker.StackFrame> frames = walker.walk(s -> s.collect(Collectors.toList())); - if (extended) { - for (StackWalker.StackFrame f : frames) { - System.out.println("frame: " + f); - Object[] locals = (Object[]) getLocals.invoke(f); - for (int i = 0; i < locals.length; i++) { - System.out.format("local %d: %s type %s%n", i, locals[i], type(locals[i])); - } - - Object[] operands = (Object[]) getOperands.invoke(f); - for (int i = 0; i < operands.length; i++) { - System.out.format("operand %d: %s type %s%n", i, operands[i], type(operands[i])); - } - - Object[] monitors = (Object[]) getMonitors.invoke(f); - for (int i = 0; i < monitors.length; i++) { - System.out.format("monitor %d: %s%n", i, monitors[i]); - } - } - } else { - for (StackFrame f : frames) { - if (liveStackFrameClass.isInstance(f)) - throw new RuntimeException("should not be LiveStackFrame"); - } - } - } - - String type(Object o) throws Exception { - if (primitiveValueClass.isInstance(o)) { - char c = (char)primitiveType.invoke(o); - return String.valueOf(c); - } else { - return o.getClass().getName(); - } - } -}
--- a/test/java/lang/StackWalker/MultiThreadStackWalk.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,362 +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. - * - * 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 java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; -import java.lang.StackWalker.StackFrame; -import static java.lang.StackWalker.Option.*; - - -/** - * @test - * @bug 8140450 - * @summary This test will walk the stack using different methods, called - * from several threads running concurrently. - * Except in the case of MTSTACKSTREAM - which takes a snapshot - * of the stack before walking, all the methods only allow to - * walk the current thread stack. - * @run main/othervm MultiThreadStackWalk - * @author danielfuchs - */ -public class MultiThreadStackWalk { - - static Set<String> infrastructureClasses = new TreeSet<>(Arrays.asList( - "sun.reflect.NativeMethodAccessorImpl", - "sun.reflect.DelegatingMethodAccessorImpl", - "java.lang.reflect.Method", - "com.sun.javatest.regtest.MainWrapper$MainThread", - "java.lang.Thread" - )); - - - static final List<Class<?>> streamPipelines = Arrays.asList( - classForName("java.util.stream.AbstractPipeline"), - classForName("java.util.stream.TerminalOp") - ); - - static Class<?> classForName(String name) { - try { - return Class.forName(name); - } catch (ClassNotFoundException e){ - throw new RuntimeException(e); - } - } - - private static boolean isStreamPipeline(Class<?> clazz) { - for (Class<?> c : streamPipelines) { - if (c.isAssignableFrom(clazz)) { - return true; - } - } - return false; - } - - /** - * An object that contains variables pertaining to the execution - * of the test within one thread. - * A small amount of those variable are shared with sub threads when - * the stack walk is executed in parallel - that is when spliterators - * obtained from trySplit are handed over to an instance of SplitThread - * in order to parallelize thread walking. - * @see WalkThread#handOff(MultiThreadStackWalk.Env, java.util.Spliterator, boolean, boolean) - * @see Env#split(MultiThreadStackWalk.Env) - */ - public static class Env { - final AtomicLong frameCounter; // private: the counter for the current thread. - final long checkMarkAt; // constant: the point at which we expect to - // find the marker in consume() - final long max; // constant: the maximum number of recursive - // calls to Call. - final AtomicBoolean debug ; // shared: whether debug is active for the - // instance of Test from which this instance - // of Env was spawned - final AtomicLong markerCalled; // shared: whether the marker was reached - final AtomicLong maxReached; // shared: whether max was reached - final Set<String> unexpected; // shared: list of unexpected infrastructure - // classes encountered after max is reached - - public Env(long total, long markAt, AtomicBoolean debug) { - this.debug = debug; - frameCounter = new AtomicLong(); - maxReached = new AtomicLong(); - unexpected = Collections.synchronizedSet(new TreeSet<>()); - this.max = total+2; - this.checkMarkAt = total - markAt + 1; - this.markerCalled = new AtomicLong(); - } - - // Used when delegating part of the stack walking to a sub thread - // see WalkThread.handOff. - private Env(Env orig, long start) { - debug = orig.debug; - frameCounter = new AtomicLong(start); - maxReached = orig.maxReached; - unexpected = orig.unexpected; - max = orig.max; - checkMarkAt = orig.checkMarkAt; - markerCalled = orig.markerCalled; - } - - // The stack walk consumer method, where all the checks are - // performed. - public void consume(StackFrame sfi) { - if (frameCounter.get() == 0 && isStreamPipeline(sfi.getDeclaringClass())) { - return; - } - - final long count = frameCounter.getAndIncrement(); - final StringBuilder builder = new StringBuilder(); - builder.append("Declaring class[") - .append(count) - .append("]: ") - .append(sfi.getDeclaringClass()); - builder.append('\n'); - builder.append("\t") - .append(sfi.getClassName()) - .append(".") - .append(sfi.toStackTraceElement().getMethodName()) - .append(sfi.toStackTraceElement().isNativeMethod() - ? "(native)" - : "(" + sfi.toStackTraceElement().getFileName() - +":"+sfi.toStackTraceElement().getLineNumber()+")"); - builder.append('\n'); - if (debug.get()) { - System.out.print("[debug] " + builder.toString()); - builder.setLength(0); - } - if (count == max) { - maxReached.incrementAndGet(); - } - if (count == checkMarkAt) { - if (sfi.getDeclaringClass() != MultiThreadStackWalk.Marker.class) { - throw new RuntimeException("Expected Marker at " + count - + ", found " + sfi.getDeclaringClass()); - } - } else { - if (count <= 0 && sfi.getDeclaringClass() != MultiThreadStackWalk.Call.class) { - throw new RuntimeException("Expected Call at " + count - + ", found " + sfi.getDeclaringClass()); - } else if (count > 0 && count < max && sfi.getDeclaringClass() != MultiThreadStackWalk.Test.class) { - throw new RuntimeException("Expected Test at " + count - + ", found " + sfi.getDeclaringClass()); - } else if (count == max && sfi.getDeclaringClass() != MultiThreadStackWalk.class) { - throw new RuntimeException("Expected MultiThreadStackWalk at " - + count + ", found " + sfi.getDeclaringClass()); - } else if (count == max && !sfi.toStackTraceElement().getMethodName().equals("runTest")) { - throw new RuntimeException("Expected runTest method at " - + count + ", found " + sfi.toStackTraceElement().getMethodName()); - } else if (count == max+1) { - if (sfi.getDeclaringClass() != MultiThreadStackWalk.WalkThread.class) { - throw new RuntimeException("Expected MultiThreadStackWalk at " - + count + ", found " + sfi.getDeclaringClass()); - } - if (count == max && !sfi.toStackTraceElement().getMethodName().equals("run")) { - throw new RuntimeException("Expected main method at " - + count + ", found " + sfi.toStackTraceElement().getMethodName()); - } - } else if (count > max+1) { - // expect JTreg infrastructure... - if (!infrastructureClasses.contains(sfi.getDeclaringClass().getName())) { - System.err.println("**** WARNING: encountered unexpected infrastructure class at " - + count +": " + sfi.getDeclaringClass().getName()); - unexpected.add(sfi.getDeclaringClass().getName()); - } - } - } - if (count == 100) { - // Maybe we should had some kind of checking inside that lambda - // too. For the moment we should be satisfied if it doesn't throw - // any exception and doesn't make the outer walk fail... - StackWalker.getInstance(RETAIN_CLASS_REFERENCE).forEach(x -> { - StackTraceElement st = x.toStackTraceElement(); - StringBuilder b = new StringBuilder(); - b.append("*** inner walk: ") - .append(x.getClassName()) - .append(st == null ? "- no stack trace element -" : - ("." + st.getMethodName() - + (st.isNativeMethod() ? "(native)" : - "(" + st.getFileName() - + ":" + st.getLineNumber() + ")"))) - .append('\n'); - if (debug.get()) { - System.out.print(b.toString()); - b.setLength(0); - } - }); - } - } - } - - public interface Call { - enum WalkType { - WALKSTACK, // use Thread.walkStack - } - default WalkType getWalkType() { return WalkType.WALKSTACK;} - default void walk(Env env) { - WalkType walktype = getWalkType(); - System.out.println("Thread "+ Thread.currentThread().getName() - +" starting walk with " + walktype); - switch(walktype) { - case WALKSTACK: - StackWalker.getInstance(RETAIN_CLASS_REFERENCE) - .forEach(env::consume); - break; - default: - throw new InternalError("Unknown walk type: " + walktype); - } - } - default void call(Env env, Call next, int total, int current, int markAt) { - if (current < total) { - next.call(env, next, total, current+1, markAt); - } - } - } - - public static class Marker implements Call { - final WalkType walkType; - Marker(WalkType walkType) { - this.walkType = walkType; - } - @Override - public WalkType getWalkType() { - return walkType; - } - - @Override - public void call(Env env, Call next, int total, int current, int markAt) { - env.markerCalled.incrementAndGet(); - if (current < total) { - next.call(env, next, total, current+1, markAt); - } else { - next.walk(env); - } - } - } - - public static class Test implements Call { - final Marker marker; - final WalkType walkType; - final AtomicBoolean debug; - Test(WalkType walkType) { - this.walkType = walkType; - this.marker = new Marker(walkType); - this.debug = new AtomicBoolean(); - } - @Override - public WalkType getWalkType() { - return walkType; - } - @Override - public void call(Env env, Call next, int total, int current, int markAt) { - if (current < total) { - int nexti = current + 1; - Call nextObj = nexti==markAt ? marker : next; - nextObj.call(env, next, total, nexti, markAt); - } else { - walk(env); - } - } - } - - public static Env runTest(Test test, int total, int markAt) { - Env env = new Env(total, markAt, test.debug); - test.call(env, test, total, 0, markAt); - return env; - } - - public static void checkTest(Env env, Test test) { - String threadName = Thread.currentThread().getName(); - System.out.println(threadName + ": Marker called: " + env.markerCalled.get()); - System.out.println(threadName + ": Max reached: " + env.maxReached.get()); - System.out.println(threadName + ": Frames consumed: " + env.frameCounter.get()); - if (env.markerCalled.get() == 0) { - throw new RuntimeException(Thread.currentThread().getName() + ": Marker was not called."); - } - if (env.markerCalled.get() > 1) { - throw new RuntimeException(Thread.currentThread().getName() - + ": Marker was called more than once: " + env.maxReached.get()); - } - if (!env.unexpected.isEmpty()) { - System.out.flush(); - System.err.println("Encountered some unexpected infrastructure classes below 'main': " - + env.unexpected); - } - if (env.maxReached.get() == 0) { - throw new RuntimeException(Thread.currentThread().getName() - + ": max not reached"); - } - if (env.maxReached.get() > 1) { - throw new RuntimeException(Thread.currentThread().getName() - + ": max was reached more than once: " + env.maxReached.get()); - } - } - - static class WalkThread extends Thread { - final static AtomicLong walkersCount = new AtomicLong(); - Throwable failed = null; - final Test test; - public WalkThread(Test test) { - super("WalkThread[" + walkersCount.incrementAndGet() + ", type=" - + test.getWalkType() + "]"); - this.test = test; - } - - public void run() { - try { - Env env = runTest(test, 2000, 10); - //waitWalkers(env); - checkTest(env, test); - } catch(Throwable t) { - failed = t; - } - } - } - - public static void main(String[] args) throws Throwable { - WalkThread[] threads = new WalkThread[Call.WalkType.values().length*3]; - Throwable failed = null; - for (int i=0; i<threads.length; i++) { - Test test = new Test(Call.WalkType.values()[i%Call.WalkType.values().length]); - threads[i] = new WalkThread(test); - } - for (int i=0; i<threads.length; i++) { - threads[i].start(); - } - for (int i=0; i<threads.length; i++) { - threads[i].join(); - if (failed == null) failed = threads[i].failed; - else if (threads[i].failed == null) { - failed.addSuppressed(threads[i].failed); - } - } - if (failed != null) { - throw failed; - } - } - -}
--- a/test/java/lang/StackWalker/SanityTest.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +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. - * - * 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 8140450 - * @summary Sanity test for exception cases - * @run testng SanityTest - */ - - -import java.util.Collections; -import java.util.Set; - -import org.testng.annotations.Test; - -public class SanityTest { - @Test - public static void testNPE() { - try { - StackWalker sw = StackWalker.getInstance((Set<StackWalker.Option>) null); - throw new RuntimeException("NPE expected"); - } catch (NullPointerException e) {} - - try { - StackWalker sw = StackWalker.getInstance((StackWalker.Option) null); - throw new RuntimeException("NPE expected"); - } catch (NullPointerException e) {} - } - - @Test - public static void testUOE() { - try { - StackWalker.getInstance().getCallerClass(); - throw new RuntimeException("UOE expected"); - } catch (UnsupportedOperationException expected) {} - } - - @Test - public static void testInvalidEstimateDepth() { - try { - StackWalker sw = StackWalker.getInstance(Collections.emptySet(), 0); - throw new RuntimeException("Illegal estimateDepth should throw IAE"); - } catch (IllegalArgumentException e) {} - } - - @Test - public static void testNullFuncation() { - try { - StackWalker.getInstance().walk(null); - throw new RuntimeException("NPE expected"); - } catch (NullPointerException e) {} - } - - @Test - public static void testNullConsumer() { - try { - StackWalker.getInstance().forEach(null); - throw new RuntimeException("NPE expected"); - } catch (NullPointerException e) {} - } -}
--- a/test/java/lang/StackWalker/SecurityExceptions.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +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. - * - * 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 8140450 - * @summary Test security permission check - * @run main/othervm/java.security.policy=noperms.policy SecurityExceptions true - * @run main/othervm/java.security.policy=stackwalk.policy SecurityExceptions false - */ -public class SecurityExceptions { - public static void main(String[] args) { - boolean expectException = Boolean.parseBoolean(args[0]); - - StackWalker sw = StackWalker.getInstance(); - - try { - sw = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); - if (expectException) { - throw new RuntimeException("Expected SecurityException, but none thrown"); - } - } catch (SecurityException e) { - if (!expectException) { - System.err.println("Unexpected security exception:"); - throw e; - } - } - } -}
--- a/test/java/lang/StackWalker/StackRecorderUtil.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +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. - * - * 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 java.lang.StackWalker.Option; -import java.lang.StackWalker.StackFrame; -import java.util.*; - -/** - * Utility class for recording a stack trace for later comparison to - * StackWalker results. - * - * StackTraceElement comparison does not include line number, isNativeMethod - */ -public class StackRecorderUtil implements Iterable<StackRecorderUtil.TestFrame> { - private List<TestFrame> testFrames = new LinkedList(); - - private boolean compareClasses; - private boolean compareClassNames = true; - private boolean compareMethodNames = true; - private boolean compareSTEs; - - public StackRecorderUtil(Set<StackWalker.Option> swOptions) { - compareClasses = swOptions.contains(Option.RETAIN_CLASS_REFERENCE); - compareSTEs = true; - } - - /** - * Add a method call to this recorded stack. - */ - public void add(Class declaringClass, String methodName, String fileName) { - testFrames.add(0, new TestFrame(declaringClass, methodName, fileName)); - } - - public int frameCount() { return testFrames.size(); } - - /** - * Compare the given StackFrame returned from the StackWalker to the - * recorded frame at the given index. - * - * Tests for equality, as well as functional correctness with respect to - * the StackWalker's options (e.g. throws or doesn't throw exceptions) - */ - public void compareFrame(int index, StackFrame sf) { - TestFrame tf = testFrames.get(index); - if (compareClasses) { - if (!tf.declaringClass.equals(sf.getDeclaringClass())) { - throw new RuntimeException("Expected class: " + - tf.declaringClass.toString() + ", but got: " + - sf.getDeclaringClass().toString()); - } - } else { - boolean caught = false; - try { - sf.getDeclaringClass(); - } catch (UnsupportedOperationException e) { - caught = true; - } - if (!caught) { - throw new RuntimeException("StackWalker did not have " + - "RETAIN_CLASS_REFERENCE Option, but did not throw " + - "UnsupportedOperationException"); - } - } - - if (compareClassNames && !tf.className().equals(sf.getClassName())) { - throw new RuntimeException("Expected class name: " + tf.className() + - ", but got: " + sf.getClassName()); - } - if (compareMethodNames && !tf.methodName.equals(sf.getMethodName())) { - throw new RuntimeException("Expected method name: " + tf.methodName + - ", but got: " + sf.getMethodName()); - } - if (compareSTEs) { - StackTraceElement ste = sf.toStackTraceElement(); - if (!(ste.getClassName().equals(tf.className()) && - ste.getMethodName().equals(tf.methodName)) && - ste.getFileName().equals(tf.fileName)) { - throw new RuntimeException("Expected StackTraceElement info: " + - tf + ", but got: " + ste); - } - if (!Objects.equals(ste.getClassName(), sf.getClassName()) - || !Objects.equals(ste.getMethodName(), sf.getMethodName()) - || !Objects.equals(ste.getFileName(), sf.getFileName().orElse(null)) - || !Objects.equals(ste.getLineNumber(), sf.getLineNumber().orElse(-1)) - || !Objects.equals(ste.isNativeMethod(), sf.isNativeMethod())) { - throw new RuntimeException("StackFrame and StackTraceElement differ: " + - "sf=" + sf + ", ste=" + ste); - } - } - } - - public Iterator<TestFrame> iterator() { - return testFrames.iterator(); - } - - /** - * Class used to record stack frame information. - */ - public static class TestFrame { - public Class declaringClass; - public String methodName; - public String fileName = null; - - public TestFrame (Class declaringClass, String methodName, String fileName) { - this.declaringClass = declaringClass; - this.methodName = methodName; - this.fileName = fileName; - } - public String className() { - return declaringClass.getName(); - } - public String toString() { - return "TestFrame: " + className() + "." + methodName + - (fileName == null ? "" : "(" + fileName + ")"); - } - } -}
--- a/test/java/lang/StackWalker/StackStreamState.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +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. - * - * 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 8140450 - * @summary Basic test for Stream<StackFrame> state - * @run main StackStreamState - */ - -import java.lang.StackWalker.StackFrame; -import java.util.stream.Stream; - -public class StackStreamState { - public static void main(String... args) { - StackStreamState test = new StackStreamState(); - test.testStatic(); - test.testInstance(); - test.testLocal(); - } - - private static Stream<StackFrame> staticStream; - private Stream<StackFrame> instanceStream; - private final StackWalker walker = StackWalker.getInstance(); - void testStatic() { - walker.walk(s -> { - staticStream = s; - return null; - }); - checkStreamState(staticStream); - } - void testInstance() { - walker.walk(s -> { - instanceStream = s; - return null; - }); - checkStreamState(instanceStream); - } - void testLocal() { - Stream<StackFrame> stream = walker.walk(s -> { - return s; - }); - checkStreamState(stream); - } - void checkStreamState(Stream<StackFrame> stream) { - try { - stream.count(); - throw new RuntimeException("IllegalStateException not thrown"); - } catch (IllegalStateException e) { - System.out.println("Got expected IllegalStateException: " + e.getMessage()); - e.printStackTrace(System.out); - } - } -}
--- a/test/java/lang/StackWalker/StackStreamTest.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,290 +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. - * - * 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 static java.lang.StackWalker.Option.*; -import java.lang.StackWalker.StackFrame; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -/** - * @test - * @bug 8140450 - * @summary Stack Stream Test - * @run main/othervm StackStreamTest - */ -public class StackStreamTest { - public static void main(String[] argv) throws Exception { - new StackStreamTest().test(); - } - - private static Logger logger = Logger.getLogger("stackstream"); - public StackStreamTest() { - } - - public void test() { - A.a(); - } - static class A { - public static void a() { - B.b(); - } - } - static class B { - public static void b() { - C.c(); - } - } - static class C { - public static void c() { - D.d(); - } - } - static class D { - public static void d() { - E.e(); - } - } - static class E { - public static void e() { - F.f(); - } - } - static class F { - public static void f() { - logger.severe("log message"); - G.g(); - new K().k(); - } - } - - private static boolean isTestClass(StackFrame f) { - // Filter jtreg frames from the end of the stack - return f.getClassName().startsWith("StackStreamTest"); - } - - static class G { - static StackWalker STE_WALKER = StackWalker.getInstance(); - static StackWalker DEFAULT_WALKER = StackWalker.getInstance(); - - private static final List<String> GOLDEN_CLASS_NAMES = - Arrays.asList("StackStreamTest$G", - "StackStreamTest$F", - "StackStreamTest$E", - "StackStreamTest$D", - "StackStreamTest$C", - "StackStreamTest$B", - "StackStreamTest$A", - "StackStreamTest", - "StackStreamTest"); - private static final List<String> GOLDEN_METHOD_NAMES = - Arrays.asList("g", "f", "e", "d", "c", "b", "a", "test", "main"); - - - public static void g() { - - System.out.println("Thread dump"); - Thread.dumpStack(); - - caller(); - firstFrame(); - - // Check class names - System.out.println("check class names"); - List<String> sfs = DEFAULT_WALKER.walk(s -> { - return s.filter(StackStreamTest::isTestClass) - .map(StackFrame::getClassName) - .collect(Collectors.toList()); - }); - equalsOrThrow("class names", sfs, GOLDEN_CLASS_NAMES); - - // Check method names - System.out.println("methodNames()"); - sfs = DEFAULT_WALKER.walk(s -> { - return s.filter(StackStreamTest::isTestClass) - .map(StackFrame::getMethodName) - .collect(Collectors.toList());} - ); - equalsOrThrow("method names", sfs, GOLDEN_METHOD_NAMES); - - Exception exc = new Exception("G.g stack"); - exc.printStackTrace(); - - System.out.println("Stream of StackTraceElement"); - StackWalker.getInstance() - .walk(s -> - { - s.map(StackFrame::toStackTraceElement) - .forEach(ste -> System.out.println("STE: " + ste)); - return null; - }); - - // Do we need this? - System.out.println("Collect StackTraceElement"); - List<StackTraceElement> stacktrace = STE_WALKER.walk(s -> - { - // Filter out jtreg frames - return s.filter(StackStreamTest::isTestClass) - .collect(Collectors.mapping(StackFrame::toStackTraceElement, Collectors.toList())); - }); - int i=0; - for (StackTraceElement s : stacktrace) { - System.out.format(" %d: %s%n", i++, s); - } - - // Check STEs for correctness - checkStackTraceElements(GOLDEN_CLASS_NAMES, GOLDEN_METHOD_NAMES, stacktrace); - } - - static void checkStackTraceElements(List<String> classNames, - List<String> methodNames, - List<StackTraceElement> stes) { - if (classNames.size() != methodNames.size() ) { - throw new RuntimeException("Test error: classNames and methodNames should be same size"); - } - if (classNames.size() != stes.size()) { - dumpSTEInfo(classNames, methodNames, stes); - throw new RuntimeException("wrong number of elements in stes"); - } - for (int i = 0; i < classNames.size() ; i++) { - if (!classNames.get(i).equals(stes.get(i).getClassName()) || - !methodNames.get(i).equals(stes.get(i).getMethodName())) { - dumpSTEInfo(classNames, methodNames, stes); - throw new RuntimeException("class & method names don't match"); - } - } - } - - static void dumpSTEInfo(List<String> classNames, List<String> methodNames, - List<StackTraceElement> stes) { - System.out.println("Observed class, method names:"); - for (StackTraceElement ste : stes) { - System.out.println(" " + ste.getClassName() + ", " + ste.getMethodName()); - } - System.out.println("Expected class, method names:"); - for (int i = 0; i < classNames.size(); i++) { - System.out.println(" " + classNames.get(i) + ", " + methodNames.get(i)); - } - } - - static void firstFrame() { - System.out.println("first frame()"); - StackWalker sw = StackWalker.getInstance(RETAIN_CLASS_REFERENCE); - sw.forEach(e -> { - System.out.println(e.getClassName() + "," + e.getMethodName()); - }); - System.out.println("\n"); - Optional<StackFrame> frame = sw.walk(s -> - { - return s.filter(e -> { - System.err.println(e.getClassName() + " == " + - e.getClassName().equals("StackStreamTest")); - return e.getClassName().equals("StackStreamTest"); - }).findFirst(); - }); - Class<?> c = frame.get().getDeclaringClass(); - System.out.println("\nfirst frame: " + c); - if (c != StackStreamTest.class) { - throw new RuntimeException("Unexpected first caller class " + c); - } - } - } - - private static <T> void equalsOrThrow(String label, List<T> list, List<T> expected) { - System.out.println("List: " + list); - System.out.println("Expectd: " + list); - if (!list.equals(expected)) { - System.err.println("Observed " + label); - for (T s1 : list) { - System.out.println(" " + s1); - } - System.err.println("Expected " + label); - for (T s2 : expected) { - System.out.println(" " + s2); - } - throw new RuntimeException("Error with " + label); - } - } - - - static class K { - void k() { - k1(); - } - void k1() { - k2(); - } - void k2() { - k3(); - } - void k3() { - k4(); - } - void k4() { - k5(); - } - void k5() { - k6(); - } - void k6() { - k7(); - } - void k7() { - k8(); - } - void k8() { - k9(); - } - void k9() { - k10(); - } - void k10() { - k20(); - } - void k20() { - new Caller().test(); - } - - class Caller { - void test() { - Class<?> c = StackWalker.getInstance(RETAIN_CLASS_REFERENCE).getCallerClass(); - System.out.println("\nTesting K class : " + c); - Thread.dumpStack(); - if (c != K.class) { - throw new RuntimeException("Unexpected caller class "+ c); - } - } - } - } - - static void caller() { - Class<?> c = StackWalker.getInstance(RETAIN_CLASS_REFERENCE).getCallerClass(); - System.out.println("\ncaller class : " + c); - if (c != G.class) { - throw new RuntimeException("Unexpected caller class "+ c); - } - } - -}
--- a/test/java/lang/StackWalker/StackWalkTest.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,355 +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. - * - * 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 static java.lang.StackWalker.Option.*; -import java.lang.StackWalker.StackFrame; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.List; -import java.util.Random; -import java.util.Set; -import java.util.TreeSet; - -import jdk.testlibrary.RandomFactory; - -/** - * @test - * @bug 8140450 - * @summary Stack Walk Test (use -Dseed=X to set PRNG seed) - * @library /lib/testlibrary - * @build jdk.testlibrary.* - * @compile StackRecorderUtil.java - * @run main/othervm StackWalkTest - * @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 - */ -public class StackWalkTest { - private static boolean random = false; - private static boolean verbose = false; - private static int randomRuns = 50; - - private static final int MAX_RANDOM_DEPTH = 1000; - - static final Set<String> infrastructureClasses = new TreeSet<>(Arrays.asList( - "sun.reflect.NativeMethodAccessorImpl", - "sun.reflect.DelegatingMethodAccessorImpl", - "java.lang.reflect.Method", - "com.sun.javatest.regtest.MainWrapper$MainThread", - "com.sun.javatest.regtest.agent.MainWrapper$MainThread", - "java.lang.Thread" - )); - static final List<Class<?>> streamPipelines = Arrays.asList( - classForName("java.util.stream.AbstractPipeline"), - classForName("java.util.stream.TerminalOp") - ); - static Class<?> classForName(String name) { - try { - return Class.forName(name); - } catch (ClassNotFoundException e){ - throw new RuntimeException(e); - } - } - - private static boolean isStreamPipeline(Class<?> clazz) { - for (Class<?> c : streamPipelines) { - if (c.isAssignableFrom(clazz)) { - return true; - } - } - return false; - } - - StackRecorderUtil recorder; - int count = 0; - boolean didWalk = false; - - final int estDepth; - final Set<StackWalker.Option> swOptions; - - public StackWalkTest() { - this(EnumSet.noneOf(StackWalker.Option.class), -1); - } - - public StackWalkTest(Set<StackWalker.Option> swOptions) { - this(swOptions, -1); - } - - public StackWalkTest(int estimatedDepth) { - this(EnumSet.noneOf(StackWalker.Option.class), -1); - } - - public StackWalkTest(Set<StackWalker.Option> swOptions, int estimatedDepth) { - this.swOptions = swOptions; - this.estDepth = estimatedDepth; - } - - private StackWalker createStackWalker() { - // test all StackWalker factory methods - if (this.estDepth < 0) { - if (swOptions.isEmpty()) { - return StackWalker.getInstance(); - } else { - return StackWalker.getInstance(swOptions); - } - } - return StackWalker.getInstance(swOptions, estDepth); - } - public void consume(StackFrame sf) { - if (count == 0 && swOptions.contains(StackWalker.Option.RETAIN_CLASS_REFERENCE) - && isStreamPipeline(sf.getDeclaringClass())) { - return; - } - if (verbose) { - System.out.println("\t" + sf.getClassName() + "." + sf.getMethodName()); - } - if (count >= recorder.frameCount()) { - // We've gone past main()... - if (infrastructureClasses.contains(sf.getClassName())) { - // safe to ignore - return; - } - } - try { - recorder.compareFrame(count, sf); - } catch (IndexOutOfBoundsException e) { - // Extra non-infra frame in stream - throw new RuntimeException("extra non-infra stack frame at count " - + count + ": <" + sf + ">", e); - } - count++; - } - - public class Call { - public void walk(int total, int markAt) { - recorder.add(Call.class, "walk", "StackWalkTest.java"); - long swFrameCount = createStackWalker().walk(s -> s.count()); - - if (verbose) { - System.out.println("Call.walk() total=" + total + ", markAt=" + markAt); - System.out.println("recorder frames:"); - for (StackRecorderUtil.TestFrame f : recorder) { - System.out.println("\t" + f.declaringClass + "." + f.methodName); - } - System.out.println("\nStackWalker recorded " + swFrameCount + " frames"); - System.out.flush(); - } - long recFrameCount = (long)recorder.frameCount(); - if (swFrameCount < recFrameCount) { - throw new RuntimeException("StackWalker recorded fewer frames ("+ - swFrameCount + ") than recorded ("+ recorder.frameCount() + - ") - " + "estimatedDepth set to " + estDepth); - } - if (verbose) { - System.out.println("StackWalker frames:"); - } - createStackWalker().forEach(StackWalkTest.this::consume); - didWalk = true; - } - public void call(int total, int current, int markAt) { - recorder.add(Call.class, "call", "StackWalkTest.java"); - if (current < total) { - testCall.call(total, current+1, markAt); - } else { - walk(total, markAt); - } - } - } - - public class Marker extends Call { - @Override - public void call(int total, int current, int markAt) { - recorder.add(Marker.class, "call", "StackWalkTest.java"); - if (current < total) { - testCall.call(total, current+1, markAt); - } else { - walk(total, markAt); - } - } - } - private Call markerCall = new Marker(); - - public class Test extends Call { - @Override - public void call(int total, int current, int markAt) { - recorder.add(Test.class, "call", "StackWalkTest.java"); - if (current < total) { - int nexti = current + 1; - if (nexti==markAt) { - markerCall.call(total, nexti, markAt); - } else { - testCall.call2(total, nexti, markAt); - } - } else { - walk(total, markAt); - } - } - public void call2(int total, int current, int markAt) { - recorder.add(Test.class, "call2", "StackWalkTest.java"); - if (current < total) { - int nexti = current + 1; - if (nexti==markAt) { - markerCall.call(total, nexti, markAt); - } else { - test2Call.call(total, nexti, markAt); - } - } else { - walk(total, markAt); - } - } - } - private Test testCall = new Test(); - - /** Inherits call() from Call */ - public class Test2 extends Call {} - private Test2 test2Call = new Test2(); - - public void runTest(Class callerClass, String callerMethod, int stackDepth, - int markAt) { - if (didWalk) { - throw new IllegalStateException("StackWalkTest already used"); - } - assert markAt <= stackDepth : "markAt(" + markAt + ") > stackDepth(" - + stackDepth + ")"; - System.out.print("runTest(" + swOptions - + "), estimatedDepth=" + estDepth); - - recorder = new StackRecorderUtil(swOptions); - recorder.add(callerClass, callerMethod, "StackWalkTest.java"); - recorder.add(StackWalkTest.class, "runTest", "StackWalkTest.java"); - - Test test1 = new Test(); - test1.call(stackDepth, 0, markAt); - - System.out.println(" finished"); - if (!didWalk) { - throw new IllegalStateException("Test wasn't actually performed"); - } - } - - public static void main(String[] args) { - String rand = "-random"; - String randItems = "-random:"; - for(String arg : args) { - if (arg.startsWith(rand)) { - random = true; - try { - if(arg.startsWith(randItems)) { - randomRuns = Integer.valueOf(arg.substring(randItems.length())); - } - } catch(NumberFormatException e) {} - } else if("-verbose".equals(arg)) { - verbose = true; - } - } - if (random) { - Random rng = RandomFactory.getRandom(); - for (int iters = 0; iters < randomRuns; iters++) { - Set<StackWalker.Option> opts = new HashSet<>(); - if (rng.nextBoolean()) { - opts.add(RETAIN_CLASS_REFERENCE); - } - - int depth = 1 + rng.nextInt(MAX_RANDOM_DEPTH); - - StackWalkTest swt; - if (rng.nextBoolean() && depth > 1) { - // Test that specifying an estimatedDepth doesn't prevent - // full stack traversal - swt = new StackWalkTest(opts, 1+rng.nextInt(depth-1)); - } else { - swt = new StackWalkTest(opts); - } - - int markAt = rng.nextInt(depth+1); - System.out.print(depth + "@" + markAt + " "); - System.out.flush(); - swt.runTest(StackWalkTest.class, "main", depth, markAt); - } - } else { - // Long stack, default maxDepth - StackWalkTest swt; - swt = new StackWalkTest(); - swt.runTest(StackWalkTest.class, "main", 2000, 10); - - // Long stack, matching maxDepth - swt = new StackWalkTest(2000); - swt.runTest(StackWalkTest.class, "main", 2000, 10); - - // Long stack, maximum maxDepth - swt = new StackWalkTest(Integer.MAX_VALUE); - swt.runTest(StackWalkTest.class, "main", 2000, 10); - - // - // Single batch - // - swt = new StackWalkTest(); // default maxDepth - swt.runTest(StackWalkTest.class, "main", 6, 3); - - swt = new StackWalkTest(4); // maxDepth < stack - swt.runTest(StackWalkTest.class, "main", 6, 3); - - swt = new StackWalkTest(2); // maxDepth < marker - swt.runTest(StackWalkTest.class, "main", 6, 4); - - // - // 2 batches - // - swt = new StackWalkTest(); // default maxDepth - swt.runTest(StackWalkTest.class, "main", 24, 10); - swt = new StackWalkTest(18); // maxDepth < stack - swt.runTest(StackWalkTest.class, "main", 24, 10); - swt = new StackWalkTest(8); // maxDepth < marker - swt.runTest(StackWalkTest.class, "main", 24, 10); - - // - // 3 batch - // - swt = new StackWalkTest(); // default maxDepth - swt.runTest(StackWalkTest.class, "main", 60, 20); - swt = new StackWalkTest(35); // maxDepth < stack - swt.runTest(StackWalkTest.class, "main", 60, 20); - swt = new StackWalkTest(8); // maxDepth < marker - swt.runTest(StackWalkTest.class, "main", 60, 20); - - // - // StackWalker.Options - // - swt = new StackWalkTest(); - swt.runTest(StackWalkTest.class, "main", 50, 10); - - swt = new StackWalkTest(EnumSet.of(RETAIN_CLASS_REFERENCE)); - swt.runTest(StackWalkTest.class, "main", 80, 40); - - swt = new StackWalkTest(EnumSet.of(RETAIN_CLASS_REFERENCE), 50); - swt.runTest(StackWalkTest.class, "main", 2000, 1048); - } - } -}
--- a/test/java/lang/StackWalker/VerifyStackTrace.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,284 +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. - * - * 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 java.lang.reflect.InvocationTargetException; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.EnumSet; -import java.util.concurrent.atomic.AtomicLong; -import java.lang.StackWalker.StackFrame; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.util.Objects; - -import static java.lang.StackWalker.Option.*; - -/** - * @test - * @bug 8140450 - * @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/java.security.policy=stackwalk.policy VerifyStackTrace - * @author danielfuchs - */ -public class VerifyStackTrace { - - static interface TestCase { - StackWalker walker(); - String description(); - String expected(); - } - static final class TestCase1 implements TestCase { - private final StackWalker walker = StackWalker.getInstance(RETAIN_CLASS_REFERENCE); - - private final String description = "StackWalker.getInstance(" + - "StackWalker.Option.RETAIN_CLASS_REFERENCE)"; - - // Note: line numbers and lambda hashes will be erased when - // comparing stack traces. However, the stack may change - // if some methods are being renamed in the code base. - // If the JDKcode base changes and the test fails because of that, - // then after validating that the actual stack trace obtained - // is indeed correct (no frames are skipped that shouldn't) - // then you can cut & paste the <-- actual --> stack printed in the - // test output in here: - private final String expected = - "1: VerifyStackTrace.lambda$test$1(VerifyStackTrace.java:209)\n" + - "2: VerifyStackTrace$Handle.execute(VerifyStackTrace.java:145)\n" + - "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(Native Method)\n" + - "7: VerifyStackTrace.test(VerifyStackTrace.java:227)\n" + - "8: VerifyStackTrace.main(VerifyStackTrace.java:182)\n"; - - @Override public StackWalker walker() { return walker;} - @Override public String description() { return description;} - @Override public String expected() { return expected;} - } - static final class TestCase2 implements TestCase { - private final StackWalker walker = StackWalker.getInstance( - EnumSet.of(RETAIN_CLASS_REFERENCE, SHOW_REFLECT_FRAMES)); - - private final String description = "nStackWalker.getInstance(" + - "StackWalker.Option.RETAIN_CLASS_REFERENCE, " + - "StackWalker.Option.SHOW_REFLECT_FRAMES)"; - - // Note: line numbers and lambda hashes will be erased when - // comparing stack traces. However, the stack may change - // if some methods are being renamed in the code base. - // If the JDK code base changes and the test fails because of that, - // then after validating that the actual stack trace obtained - // is indeed correct (no frames are skipped that shouldn't) - // then you can cut & paste the <-- actual --> stack printed in the - // test output in here (don't forget the final \n): - private final String expected = - "1: VerifyStackTrace.lambda$test$1(VerifyStackTrace.java:211)\n" + - "2: VerifyStackTrace$Handle.execute(VerifyStackTrace.java:147)\n" + - "3: VerifyStackTrace$Handle.run(VerifyStackTrace.java:160)\n" + - "4: VerifyStackTrace.invoke(VerifyStackTrace.java:190)\n" + - "5: sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n" + - "6: sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n" + - "7: sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n" + - "8: java.lang.reflect.Method.invoke(Method.java:520)\n" + - "9: VerifyStackTrace$1.run(VerifyStackTrace.java:220)\n" + - "10: java.security.AccessController.doPrivileged(Native Method)\n" + - "11: VerifyStackTrace.test(VerifyStackTrace.java:229)\n" + - "12: VerifyStackTrace.main(VerifyStackTrace.java:185)\n"; - - @Override public StackWalker walker() { return walker;} - @Override public String description() { return description;} - @Override public String expected() { return expected;} - } - static class TestCase3 implements TestCase { - private final StackWalker walker = StackWalker.getInstance( - EnumSet.of(RETAIN_CLASS_REFERENCE, SHOW_HIDDEN_FRAMES)); - - private final String description = "StackWalker.getInstance(" + - "StackWalker.Option.RETAIN_CLASS_REFERENCE, " + - "StackWalker.Option.SHOW_HIDDEN_FRAMES)"; - - // Note: line numbers and lambda hashes will be erased when - // comparing stack traces. However, the stack may change - // if some methods are being renamed in the code base. - // If the JDK code base changes and the test fails because of that, - // then after validating that the actual stack trace obtained - // is indeed correct (no frames are skipped that shouldn't) - // then you can cut & paste the <-- actual --> stack printed in the - // test output in here (don't forget the final \n): - private final String expected = - "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(LambdaForm$DMH)\n" + - "5: 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: sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n" + - "9: sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n" + - "10: sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n" + - "11: java.lang.reflect.Method.invoke(Method.java:520)\n" + - "12: VerifyStackTrace$1.run(VerifyStackTrace.java:222)\n" + - "13: java.security.AccessController.doPrivileged(Native Method)\n" + - "14: VerifyStackTrace.test(VerifyStackTrace.java:231)\n" + - "15: VerifyStackTrace.main(VerifyStackTrace.java:188)\n"; - - @Override public StackWalker walker() { return walker;} - @Override public String description() { return description;} - @Override public String expected() { return expected;} - } - - static final class TestCase4 extends TestCase3 { - private final StackWalker walker = StackWalker.getInstance( - EnumSet.allOf(StackWalker.Option.class)); - - private final String description = "StackWalker.getInstance(" + - "StackWalker.Option.RETAIN_CLASS_REFERENCE, " + - "StackWalker.Option.SHOW_HIDDEN_FRAMES, " + - "StackWalker.Option.SHOW_REFLECT_FRAMES)"; - - @Override public StackWalker walker() {return walker;} - @Override public String description() {return description;} - } - - public static class Handle implements Runnable { - - Runnable impl; - public Handle(Runnable run) { - this.impl = run; - } - - public void execute(Runnable run) { - run.run(); - } - - public void run() { - MethodHandles.Lookup lookup = MethodHandles.lookup(); - MethodHandle handle = null; - try { - handle = lookup.findVirtual(Handle.class, "execute", - MethodType.methodType(void.class, Runnable.class)); - } catch(NoSuchMethodException | IllegalAccessException x) { - throw new RuntimeException(x); - } - try { - handle.invoke(this, impl); - } catch(Error | RuntimeException x) { - throw x; - } catch(Throwable t) { - throw new RuntimeException(t); - } - } - } - - static String prepare(String produced, boolean eraseSensitiveInfo) { - if (eraseSensitiveInfo) { - // Erase sensitive information before comparing: - // comparing line numbers is too fragile, so we just erase them - // 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("/[0-9]+\\.run", "/xxxxxxxx.run") - .replaceAll("/[0-9]+\\.invoke", "/xxxxxxxx.invoke") - .replaceAll("\\$[0-9]+", "\\$??"); - } else { - return produced; - } - } - - - public static void main(String[] args) { - test(new TestCase1()); - test(new TestCase2()); - test(new TestCase3()); - test(new TestCase4()); - } - - public static void invoke(Runnable run) { - run.run(); - } - - static final class Recorder { - boolean found; // stop recording after main - public void recordSTE(long counter, StringBuilder s, StackFrame f) { - if (found) return; - found = VerifyStackTrace.class.equals(f.getDeclaringClass()) && - "main".equals(f.getMethodName()); - String line = String.format("%d: %s", counter, f.toStackTraceElement()); - s.append(line).append('\n'); - System.out.println(line); - } - } - - - static void test(TestCase test) { - System.out.println("\nTesting: " + test.description()); - final AtomicLong counter = new AtomicLong(); - final StringBuilder builder = new StringBuilder(); - final Recorder recorder = new Recorder(); - final Runnable run = () -> test.walker().forEach( - f -> recorder.recordSTE(counter.incrementAndGet(), builder, f)); - final Handle handle = new Handle(run); - - // We're not using lambda on purpose here. We want the anonymous - // class on the stack. - PrivilegedAction<Object> pa = new PrivilegedAction<Object>() { - @Override - public Object run() { - try { - return VerifyStackTrace.class - .getMethod("invoke", Runnable.class) - .invoke(null, handle); - } catch (NoSuchMethodException - | IllegalAccessException - | InvocationTargetException ex) { - System.out.flush(); - throw new RuntimeException(ex); - } - } - }; - AccessController.doPrivileged(pa); - System.out.println("Main found: " + recorder.found); - if (!Objects.equals(prepare(test.expected(), true), prepare(builder.toString(), true))) { - System.out.flush(); - try { - // sleep to make it less likely that System.out & System.err will - // interleave. - Thread.sleep(1000); - } catch (InterruptedException ex) { - } - System.err.println("\nUnexpected stack trace: " - + "\n<!-- expected -->\n" - + prepare(test.expected(), true) - + "\n<-- actual -->\n" - + prepare(builder.toString(), false)); - throw new RuntimeException("Unexpected stack trace for: " + test.description()); - } - } - - -}
--- a/test/java/lang/StackWalker/WalkFunction.java Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +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. - * - * 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 8140450 - * @summary Sanity test for Function wildcard signature - * @run main WalkFunction - */ - -import java.lang.StackWalker.StackFrame; -import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Stream; - -public class WalkFunction { - private static final StackWalker walker = StackWalker.getInstance(); - - public static void main(String... args) throws Exception { - testFunctions(); - testWildcards(); - walker.walk(counter()); - walker.walk(wildCounter()); - } - - private static void testFunctions() { - walker.walk(Stream::count); - - try { - walker.walk(null); - throw new RuntimeException("NPE expected"); - } catch (NullPointerException e) {} - - Optional<StackFrame> result = walker.walk(WalkFunction::reduce); - if (!result.get().getClassName().equals(WalkFunction.class.getName())) { - throw new RuntimeException(result.get() + " expected: " + WalkFunction.class.getName()); - } - } - - static Optional<StackFrame> reduce(Stream<StackFrame> stream) { - return stream.reduce((r,f) -> r.getClassName().compareTo(f.getClassName()) > 0 ? f : r); - } - - private static void testWildcards() { - Function<? super Stream<? extends StackFrame>, Void> f1 = WalkFunction::function; - Function<? super Stream<? super StackFrame>, Void> f2 = WalkFunction::function; - Function<? super Stream<StackFrame>, Void> f3 = WalkFunction::function; - Function<Stream<? extends StackFrame>, Void> f4 = WalkFunction::function; - Function<Stream<? super StackFrame>, Void> f5 = WalkFunction::function; - Function<Stream<StackFrame>, Void> f6 = WalkFunction::function; - walker.walk(f1); - walker.walk(f2); - walker.walk(f3); - walker.walk(f4); - walker.walk(f5); - walker.walk(f6); - } - - private static Void function(Stream<?> s) { - return null; - } - - private static Function<Stream<?>, Long> wildCounter() { - return Stream::count; - } - private static <T> Function<Stream<T>, Long> counter() { - return Stream::count; - } -}
--- a/test/java/lang/StackWalker/noperms.policy Tue Nov 24 11:50:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -/* - * grant nothing - */ -grant {}; -