import java.lang.StackWalker.StackFrame;
import java.lang.reflect.Method;
import java.lang.ref.Reference;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Principal;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Optional;
import java.util.Set;
import java.util.EnumSet;

public class StackWalkTest9 {
    static Class<?> liveStackFrameClass;
    static StackWalker stackWalker;
    static Method getLocals;

    static Method getExtendedWalker;

    static {
        try {
            liveStackFrameClass = Class.forName("java.lang.LiveStackFrame");

            getLocals = liveStackFrameClass.getDeclaredMethod("getLocals");
            getLocals.setAccessible(true);

            getExtendedWalker = liveStackFrameClass.getMethod("getStackWalker", Set.class);
            getExtendedWalker.setAccessible(true);

            stackWalker = (StackWalker) getExtendedWalker.invoke(null,
                    EnumSet.noneOf(StackWalker.Option.class));
        } catch (Throwable t) { throw new RuntimeException(t);}
    }

    static void check(int count) {
        Optional<StackFrame> of = stackWalker.walk(s -> s.skip(1).findFirst());
        //if (of.isEmpty()) throw new AssertionError("no frame");
        if (!of.isPresent()) throw new AssertionError("no frame");

        //LiveStackFrameInfo lf = (LiveStackFrameInfo)of.get();
        StackFrame lf = of.get();
        Object l = null;
        try {
            l = ((Object[])getLocals.invoke(lf))[1];
        } catch (Throwable t) { throw new RuntimeException(t);}

        if (l == null || !"hi".equals(l)) {
            throw new AssertionError("bad frame local " + l + " at iteration " + count);
        }
    }

    static void go(int count) {
        String hi = new String("hi");
        if ((count % 1000) == 999) {
            check(count);
        }
        Reference.reachabilityFence(hi);
    }

    public static void main(String[] args) throws PrivilegedActionException {
        for (int i = 0; i < 200_000; ++i) {
            go(i);
        }
    }
}

