diff --git a/jdk/make/mapfiles/libjava/mapfile-vers b/jdk/make/mapfiles/libjava/mapfile-vers index c1c80820a71..7ae48fec8e3 100644 --- a/jdk/make/mapfiles/libjava/mapfile-vers +++ b/jdk/make/mapfiles/libjava/mapfile-vers @@ -138,14 +138,9 @@ SUNWprivate_1.1 { 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; diff --git a/jdk/src/java.base/share/classes/java/lang/LiveStackFrame.java b/jdk/src/java.base/share/classes/java/lang/LiveStackFrame.java deleted file mode 100644 index 1ef4a2aa041..00000000000 --- a/jdk/src/java.base/share/classes/java/lang/LiveStackFrame.java +++ /dev/null @@ -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; - -/** - * UNSUPPORTED This interface is intended to be package-private - * or move to an internal package.

- * - * {@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. - * - *

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. - * - *

- * 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. - * - *

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(); - - /** - * UNSUPPORTED This interface is intended to be package-private - * or move to an internal package.

- * - * 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 options) { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new RuntimePermission("liveStackFrames")); - } - return StackWalker.newInstance(options, LOCALS_AND_OPERANDS); - } -} diff --git a/jdk/src/java.base/share/classes/java/lang/LiveStackFrameInfo.java b/jdk/src/java.base/share/classes/java/lang/LiveStackFrameInfo.java deleted file mode 100644 index db8901ea731..00000000000 --- a/jdk/src/java.base/share/classes/java/lang/LiveStackFrameInfo.java +++ /dev/null @@ -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); - } - } -} diff --git a/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java b/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java deleted file mode 100644 index 5c7fbde5810..00000000000 --- a/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java +++ /dev/null @@ -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 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); -} diff --git a/jdk/src/java.base/share/classes/java/lang/StackFramePermission.java b/jdk/src/java.base/share/classes/java/lang/StackFramePermission.java deleted file mode 100644 index 58dcba496be..00000000000 --- a/jdk/src/java.base/share/classes/java/lang/StackFramePermission.java +++ /dev/null @@ -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); - } - } -} diff --git a/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java b/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java deleted file mode 100644 index 7379184b643..00000000000 --- a/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java +++ /dev/null @@ -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 - * 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> 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 StackFrameTraverser - makeStackTraverser(StackWalker walker, Function, ? extends T> function) - { - if (walker.hasLocalsOperandsOption()) - return new LiveStackInfoTraverser(walker, function); - else - return new StackFrameTraverser(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::. - */ - 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 { - 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. - * - *

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 extends AbstractStackWalker - implements Spliterator - { - static { - stackWalkImplClasses.add(StackFrameTraverser.class); - } - private static final int CHARACTERISTICS = Spliterator.ORDERED | Spliterator.IMMUTABLE; - class Buffer extends FrameBuffer { - Buffer(int initialBatchSize) { - 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, ? extends T> function; // callback - - StackFrameTraverser(StackWalker walker, - Function, ? extends T> function) { - this(walker, function, DEFAULT_MODE); - } - StackFrameTraverser(StackWalker walker, - Function, ? 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 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 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 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 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 { - 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 { - static { - stackWalkImplClasses.add(StackTrace.class); - } - - class GrowableBuffer extends FrameBuffer { - GrowableBuffer(int initialBatchSize) { - super(initialBatchSize); - - this.stackFrames = new StackFrame[initialBatchSize]; - for (int i = START_POS; i < initialBatchSize; i++) { - stackFrames[i] = new StackFrameInfo(walker); - } - } - - /* - * Returns the next index to fill - */ - @Override - int startIndex() { - return origin; - } - - /** - * Initialize the buffers for VM to fill in the stack frame information. - * The next batch will start at the given startIndex to - * the length of the buffer. - */ - @Override - void resize(int startIndex, int elements) { - // Expand the frame buffer. - // Do not call super.resize that will reuse the filled elements - // in this frame buffer - int size = startIndex+elements; - if (classes.length < size) { - // resize the frame buffer - classes = Arrays.copyOf(classes, size); - stackFrames = Arrays.copyOf(stackFrames, size); - } - for (int i = startIndex; i < size; i++) { - stackFrames[i] = new StackFrameInfo(walker); - } - currentBatchSize = size; - } - - StackTraceElement get(int index) { - return new StackTraceElement(classes[index].getName(), "unknown", null, -1); - } - - /** - * Returns an array of StackTraceElement for all stack frames cached in - * this StackTrace object. - *

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

- * This method is intended for Throwable::getOurStackTrace use only. - */ - synchronized StackTraceElement[] getStackTraceElements() { - if (stes == null) { - stes = ((GrowableBuffer) frameBuffer).toStackTraceElements(); - // release the frameBuffer memory - frameBuffer = null; - } - return stes; - } - - /* - * Prints stack trace to the given PrintStream. - * - * Further implementation could skip creating StackTraceElement objects - * print directly to the PrintStream. - */ - void printStackTrace(PrintStream s) { - StackTraceElement[] stes = getStackTraceElements(); - synchronized (s) { - s.println("Stack trace"); - for (StackTraceElement traceElement : stes) - s.println("\tat " + traceElement); - } - } - } - - static class LiveStackInfoTraverser extends StackFrameTraverser { - static { - 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, ? 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> init() { - if (!checkStackWalkModes()) { - throw new InternalError("StackWalker mode values do not match with JVM"); - } - - Set> 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; - } -} diff --git a/jdk/src/java.base/share/classes/java/lang/StackWalker.java b/jdk/src/java.base/share/classes/java/lang/StackWalker.java deleted file mode 100644 index ec5e581b7a6..00000000000 --- a/jdk/src/java.base/share/classes/java/lang/StackWalker.java +++ /dev/null @@ -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. - * - *

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. - * - *

The {@linkplain Option stack walking options} 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}. - * - *

{@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 - * - *

1. To find the first caller filtering a known list of implementation class: - *

{@code
- *     StackWalker walker = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE);
- *     Optional> callerClass = walker.walk(s ->
- *         s.map(StackFrame::getDeclaringClass)
- *          .filter(interestingClasses::contains)
- *          .findFirst());
- * }
- * - *

2. To snapshot the top 10 stack frames of the current thread, - *

{@code
- *     List stack = StackWalker.getInstance().walk(s ->
- *         s.limit(10).collect(Collectors.toList()));
- * }
- * - * 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}. - * - *

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 binary name - * 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 The Java Virtual Machine Specification. - * 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 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 The Java Virtual Machine - * Specification. - * - * @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}. - * - *

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. - * - *

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. - * - *

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

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. - * - *

- * 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. - * - *

- * 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

- * 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")}. - * - *

- * 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

The {@code StackFrame} stream will be closed when - * this method returns. When a closed {@code Stream} 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}: - *

- *
{@code
-     * List frames = StackWalker.getInstance().walk(s ->
-     *     s.dropWhile(f -> f.getClassName().startsWith("com.foo."))
-     *      .limit(10)
-     *      .collect(Collectors.toList()));
-     * }
- * - *

This method takes a {@code Function} accepting a {@code Stream}, - * rather than returning a {@code Stream} 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. - * - *

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 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 walk(Function, ? extends T> function) { - // Returning a Stream 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) 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. - * - *

This method is equivalent to calling - *

- * {@code walk(s -> { s.forEach(action); return null; });} - *
- * - * @param action an action to be performed on each {@code StackFrame} - * of the stack of the current thread - */ - @CallerSensitive - public void forEach(Consumer 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. - * - *

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. - * - *

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. - * - *

{@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");
-     *     }
-     * }
-     * }
- * - * 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): - *
{@code
-     *     Optional> caller = walker.walk(s ->
-     *         s.map(StackFrame::getDeclaringClass)
-     *          .skip(2)
-     *          .findFirst());
-     * }
- * - * 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