On Fri, Oct 5, 2018 at 1:58 PM Ralph Goers <rgo...@apache.org> wrote:
> I didn’t write this particular test. I will have to find it. > I'm curious to see the test as well, especially to see what the "defaultJava8" test is. Is that a method for getting the stack frames using Exception::getStackTrace or something? On Fri, Oct 5, 2018 at 11:55 AM David Lloyd <david.ll...@redhat.com> wrote: > Something to consider is _how_ the StackWalker is used. It's > potentially quite expensive in that it produces a Stream in its full > usage mode. Have you compared using the stream + lambda approach > versus extracting the stream iterator and iterating in the classic > Java fashion? I doubt it would make the benchmark competitive, but it > might help a little bit. In my own code, I used StackWalker::forEach rather than StalkWalker::walk, since the stream API has such high overhead. Even lambdas have a high startup overhead for some reason (I think it was 20ms of incurred latency when you first use a lambda, last time I measured it?), but at least forEach should deliver much higher throughput than walk. The code I'm using currently is below. I have a few questions: (1) Is it correct to try both StackWalker and SecurityManager first with doPrivileged, and then if that fails, without doPrivileged? (i.e. I think it is possible for doPrivileged to fail when non-doPrivileged doesn't fail, *or* vice versa, depending on the security configuration?) -- sorry for the newbie question re. JVM security, I'm having a hard time getting my head around it... (2) Is it reasonable to fail over from StackWalker to SecurityManager? Or if StackWalker fails due to security limitations, will SecurityManager always fail due to the same security limitations? (Are their security models a 1:1 match?) (3) Under what circumstances can StackWalker and/or SecurityManager obtain more information about a stacktrace than Exception::getStackTrace? ---- private static final class CallerResolver extends SecurityManager { @Override protected Class<?>[] getClassContext() { return super.getClassContext(); } } private static Class<?>[] getCallStack() { // Try StackWalker (JDK 9+) PrivilegedAction<Object> stackWalkerAction = new PrivilegedAction<Object>() { @Override public Object run() { List<Class<?>> stackFrameClasses = new ArrayList<>(); StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE) .forEach(sf -> stackFrameClasses.add(sf.getDeclaringClass())); return stackFrameClasses.toArray(new Class<?>[0]); } }; try { // Try with doPrivileged() return (Class<?>[]) AccessController.doPrivileged(stackWalkerAction); } catch (Exception e) { } try { // Try without doPrivileged() return (Class<?>[]) stackWalkerAction.run(); } catch (Exception e) { } // Try SecurityManager PrivilegedAction<Object> callerResolverAction = new PrivilegedAction<Object>() { @Override public Object run() { return new CallerResolver().getClassContext(); } }; try { // Try with doPrivileged() return (Class<?>[]) AccessController.doPrivileged(callerResolverAction); } catch (Exception e) { } try { // Try without doPrivileged() return (Class<?>[]) callerResolverAction.run(); } catch (Exception e) { } // As a fallback, use getStackTrace() to try to get the call stack try { throw new Exception(); } catch (final Exception e) { final List<Class<?>> classes = new ArrayList<>(); for (final StackTraceElement elt : e.getStackTrace()) { try { classes.add(Class.forName(elt.getClassName())); } catch (final Throwable e2) { // Ignore } } if (classes.size() > 0) { return classes.toArray(new Class<?>[0]); } else { // Last-ditch effort -- include just this class in the call stack return new Class<?>[] { Java9Scanner.class }; } } }