changeset 13154:94838afd5e5b

8140450: Implement JEP 259: Stack-Walking API Reviewed-by: coleenp, dfuchs, bchristi, psandoz, sspitsyn Contributed-by: Mandy Chung <mandy.chung@oracle.com>, Brent Christian <brent.christian@oracle.com>, Daniel Fuchs <daniel.fuchs@oracle.com>, Hamlin Li <huaming.li@oracle.com>
author mchung
date Mon, 23 Nov 2015 12:44:50 -0800
parents 445d56c343c7
children 11a6ba96c417 683721c7f5f4
files make/mapfiles/libjava/mapfile-vers 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/System.java src/java.base/share/classes/java/lang/Thread.java src/java.base/share/classes/java/lang/Throwable.java src/java.base/share/classes/java/lang/invoke/MemberName.java src/java.base/share/classes/jdk/internal/logger/SimpleConsoleLogger.java src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java src/java.base/share/native/include/jvm.h src/java.base/share/native/libjava/StackFrameInfo.c src/java.base/share/native/libjava/StackStreamFactory.c src/java.logging/share/classes/java/util/logging/LogRecord.java 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, 5804 insertions(+), 94 deletions(-) [+]
line wrap: on
line diff
--- a/make/mapfiles/libjava/mapfile-vers	Fri Nov 20 19:26:16 2015 +0100
+++ b/make/mapfiles/libjava/mapfile-vers	Mon Nov 23 12:44:50 2015 -0800
@@ -138,9 +138,14 @@
 		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;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/LiveStackFrame.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,226 @@
+/*
+ * 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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/LiveStackFrameInfo.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,271 @@
+/*
+ * 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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/StackFrameInfo.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,136 @@
+/*
+ * 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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/StackFramePermission.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,50 @@
+/*
+ * 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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/StackStreamFactory.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,1106 @@
+/*
+ * 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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/StackWalker.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,563 @@
+/*
+ * 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	Fri Nov 20 19:26:16 2015 +0100
+++ b/src/java.base/share/classes/java/lang/System.java	Mon Nov 23 12:44:50 2015 -0800
@@ -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,12 +1896,6 @@
             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	Fri Nov 20 19:26:16 2015 +0100
+++ b/src/java.base/share/classes/java/lang/Thread.java	Mon Nov 23 12:44:50 2015 -0800
@@ -1329,11 +1329,9 @@
     /**
      * 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() {
-        new Exception("Stack trace").printStackTrace();
+        StackStreamFactory.makeStackTrace().printStackTrace(System.err);
     }
 
     /**
@@ -1556,7 +1554,7 @@
             return stackTrace;
         } else {
             // Don't need JVM help for current thread
-            return (new Exception()).getStackTrace();
+            return StackStreamFactory.makeStackTrace().getStackTraceElements();
         }
     }
 
--- a/src/java.base/share/classes/java/lang/Throwable.java	Fri Nov 20 19:26:16 2015 +0100
+++ b/src/java.base/share/classes/java/lang/Throwable.java	Mon Nov 23 12:44:50 2015 -0800
@@ -24,6 +24,8 @@
  */
 
 package java.lang;
+import sun.misc.VM;
+
 import  java.io.*;
 import  java.util.*;
 
@@ -778,7 +780,11 @@
     public synchronized Throwable fillInStackTrace() {
         if (stackTrace != null ||
             backtrace != null /* Out of protocol state */ ) {
-            fillInStackTrace(0);
+            if (backtrace == null && StackStreamFactory.useStackTrace(this)) {
+                backtrace = StackStreamFactory.makeStackTrace(this);
+            } else {
+                fillInStackTrace(0);
+            }
             stackTrace = UNASSIGNED_STACK;
         }
         return this;
@@ -819,10 +825,14 @@
         // backtrace if this is the first call to this method
         if (stackTrace == UNASSIGNED_STACK ||
             (stackTrace == null && backtrace != null) /* Out of protocol state */) {
-            int depth = getStackTraceDepth();
-            stackTrace = new StackTraceElement[depth];
-            for (int i=0; i < depth; i++)
-                stackTrace[i] = getStackTraceElement(i);
+            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);
+            }
         } else if (stackTrace == null) {
             return UNASSIGNED_STACK;
         }
--- a/src/java.base/share/classes/java/lang/invoke/MemberName.java	Fri Nov 20 19:26:16 2015 +0100
+++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java	Mon Nov 23 12:44:50 2015 -0800
@@ -1077,4 +1077,13 @@
 //        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	Fri Nov 20 19:26:16 2015 +0100
+++ b/src/java.base/share/classes/jdk/internal/logger/SimpleConsoleLogger.java	Mon Nov 23 12:44:50 2015 -0800
@@ -31,13 +31,12 @@
 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.lang.System.Logger.Level;
+import java.util.function.Predicate;
 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;
 
@@ -169,42 +168,55 @@
     // Returns the caller's class and method's name; best effort
     // if cannot infer, return the logger's name.
     private String getCallerInfo() {
-        String sourceClassName = null;
-        String sourceMethodName = null;
+        Optional<StackWalker.StackFrame> frame = new CallerFinder().get();
+        if (frame.isPresent()) {
+            return frame.get().getClassName() + " " + frame.get().getMethodName();
+        } else {
+            return name;
+        }
+    }
 
-        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();
 
-        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();
+        /**
+         * 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) {
                 // 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;
-                }
+                lookingForLogger = !isLoggerImplFrame(cname);
+                return false;
             }
+            // We've found the relevant frame.
+            return !skipLoggingFrame(cname) && !isLoggerImplFrame(cname);
         }
 
-        if (sourceClassName != null) {
-            return sourceClassName + " " + sourceMethodName;
-        } else {
-            return name;
+        private boolean isLoggerImplFrame(String cname) {
+            return (cname.equals("sun.util.logging.PlatformLogger") ||
+                    cname.equals("jdk.internal.logger.SimpleConsoleLogger"));
         }
     }
 
--- a/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java	Fri Nov 20 19:26:16 2015 +0100
+++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java	Mon Nov 23 12:44:50 2015 -0800
@@ -103,16 +103,6 @@
     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.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,33 @@
+/*
+ * 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	Fri Nov 20 19:26:16 2015 +0100
+++ b/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java	Mon Nov 23 12:44:50 2015 -0800
@@ -45,6 +45,7 @@
     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;
@@ -80,6 +81,20 @@
         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	Fri Nov 20 19:26:16 2015 +0100
+++ b/src/java.base/share/native/include/jvm.h	Mon Nov 23 12:44:50 2015 -0800
@@ -178,6 +178,37 @@
 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/native/libjava/StackFrameInfo.c	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,59 @@
+/*
+ * 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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/native/libjava/StackStreamFactory.c	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,78 @@
+/*
+ * 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	Fri Nov 20 19:26:16 2015 +0100
+++ b/src/java.logging/share/classes/java/util/logging/LogRecord.java	Mon Nov 23 12:44:50 2015 -0800
@@ -30,9 +30,8 @@
 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;
 
 /**
@@ -661,42 +660,58 @@
     //
     private void inferCaller() {
         needToInferCaller = false;
-        JavaLangAccess access = SharedSecrets.getJavaLangAccess();
-        Throwable throwable = new Throwable();
-        int depth = access.getStackTraceDepth(throwable);
+        // 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());
+        });
 
-        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.
     }
 
-    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"));
+    /*
+     * 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"));
+        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/AcrossThreads.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,227 @@
+/*
+ * 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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/Basic.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,139 @@
+/*
+ * 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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/CallerFromMain.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,137 @@
+/*
+ * 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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/DumpStackTest.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,234 @@
+/*
+ * 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 + "]");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/EmbeddedStackWalkTest.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,158 @@
+/*
+ * 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;
+            });
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/GetCallerClassTest.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,253 @@
+/*
+ * 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);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/HiddenFrames.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,108 @@
+/*
+ * 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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/LocalsAndOperands.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,118 @@
+/*
+ * 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();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/MultiThreadStackWalk.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,362 @@
+/*
+ * 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;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/SanityTest.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,82 @@
+/*
+ * 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) {}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/SecurityExceptions.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,48 @@
+/*
+ * 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;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/StackRecorderUtil.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,137 @@
+/*
+ * 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 + ")");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/StackStreamState.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,74 @@
+/*
+ * 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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/StackStreamTest.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,290 @@
+/*
+ * 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);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/StackWalkTest.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,355 @@
+/*
+ * 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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/VerifyStackTrace.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,284 @@
+/*
+ * 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());
+        }
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/WalkFunction.java	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,89 @@
+/*
+ * 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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/noperms.policy	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,5 @@
+/*
+ * grant nothing
+ */
+grant {};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/stackwalk.policy	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,4 @@
+grant {
+  permission java.lang.StackFramePermission "retainClassReference";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StackWalker/stackwalktest.policy	Mon Nov 23 12:44:50 2015 -0800
@@ -0,0 +1,5 @@
+grant {
+  permission java.lang.StackFramePermission "retainClassReference";
+  permission java.util.PropertyPermission "seed", "read";
+};
+