@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; }
/** * Returns true if we have found the caller's frame, false if the frame * must be skipped. * * @param t The frame info. * @return true if we have found the caller's frame, false if the frame * must be skipped. */ @Override public boolean test(StackWalker.StackFrame t) { final String cname = t.getClassName(); // We should skip all frames until we have found the logger, // because these frames could be frames introduced by e.g. custom // sub classes of Handler. if (lookingForLogger) { // Skip all frames until we have found the first logger frame. lookingForLogger = !isLoggerImplFrame(cname); return false; } // Continue walking until we've found the relevant calling frame. // Skips logging/logger infrastructure. return !Formatting.isFilteredFrame(t); }
/** * Perform stackwalk, keeping local variables alive, and return a list of * the collected StackFrames */ private synchronized StackFrame[] testLocalsKeepAlive() { int x = 0xA; char c = 'z'; // 0x7A String hi = "himom"; long l = 0x3FF00000000L + 0xFFFFL; double d = Math.PI; StackFrame[] frames = walker.walk(s -> s.filter(f -> TEST_METHODS.contains(f.getMethodName())) .toArray(StackFrame[]::new) ); // Use local variables so they stay alive System.out.println("Stayin' alive: "+this+" "+x+" "+c+" "+hi+" "+l+" "+d); return frames; }
private static void usedLong(long longArg) throws Exception { StackFrame[] frames = extendedWalker.walk(s -> s.filter(f -> "usedLong".equals(f.getMethodName())) .toArray(StackFrame[]::new) ); try { dumpFramesIfDebug(frames); Object[] locals = (Object[]) getLocals.invoke(frames[0]); assertLongIsInSlots(locals[0], locals[1], longArg); System.out.println("Stayin' alive: " + longArg); } catch (Exception t) { dumpFramesIfNotDebug(frames); throw t; } }
private static void usedDouble(double doubleArg) throws Exception { StackFrame[] frames = extendedWalker.walk(s -> s.filter(f -> "usedDouble".equals(f.getMethodName())) .toArray(StackFrame[]::new) ); try { dumpFramesIfDebug(frames); Object[] locals = (Object[]) getLocals.invoke(frames[0]); assertDoubleIsInSlots(locals[0], locals[1], doubleArg); System.out.println("Stayin' alive: " + doubleArg); } catch (Exception t) { dumpFramesIfNotDebug(frames); throw t; } }
public boolean accept(StackFrame f) { // Frames whose class names don't contain "." // are our own test frames. These are the ones // we expect. // Frames whose class names contain ".reflect." // are reflection frames. None should be present, // since they are supposed to be filtered by // by StackWalker. If we find any, we want to fail. if (!f.getClassName().contains(".") || f.getClassName().contains(".reflect.")) { System.out.println(" " + f); return true; } // Filter out all other frames (in particular // those from the test framework) in order to // have predictable results. return false; }
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++; }
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); } }
void verify(StackFrame frame) { if (frame.getDeclaringClass() != clazz) return; int bci = frame.getByteCodeIndex(); int lineNumber = frame.getLineNumber(); System.out.format("%s.%s bci %d (%s:%d)%n", frame.getClassName(), frame.getMethodName(), bci, frame.getFileName(), lineNumber); MethodInfo method = methods.get(frame.getMethodName()); SortedSet<Integer> values = method.findLineNumbers(bci).get(); if (!values.contains(lineNumber)) { throw new RuntimeException("line number for bci: " + bci + " " + lineNumber + " not matched line number table: " + values); } }
/** * 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 s) { // 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. Class<?> c = s.getDeclaringClass(); boolean isLogger = System.Logger.class.isAssignableFrom(c); if (lookingForLogger) { // Skip all frames until we have found the first logger frame. lookingForLogger = c != TestLogger.class; return false; } // Continue walking until we've found the relevant calling frame. // Skips logging/logger infrastructure. return !isLogger; }
@Test(dataProvider = "provider", dataProviderClass = LocalsAndOperands.class) public void countLocalSlots(StackFrame... frames) { for (StackFrame frame : frames) { if (debug) { System.out.println("Running countLocalSlots"); LocalsAndOperands.dumpStackWithLocals(frames); } // Confirm expected number of locals String methodName = frame.getMethodName(); Integer expectedObj = (Integer) LocalsAndOperands.Tester.NUM_LOCALS.get(methodName); if (expectedObj == null) { if (!debug) { LocalsAndOperands.dumpStackWithLocals(frames); } throw new RuntimeException("No NUM_LOCALS entry for " + methodName + "(). Update test?"); } Object[] locals = (Object[]) LocalsAndOperands.invokeGetLocals(frame); if (locals.length != expectedObj) { if (!debug) { LocalsAndOperands.dumpStackWithLocals(frames); } throw new RuntimeException(methodName + "(): number of locals (" + locals.length + ") did not match expected (" + expectedObj + ")"); } } }
/** * Basic sanity check for locals and operands */ @Test(dataProvider = "provider") public static void sanityCheck(StackFrame... frames) { if (debug) { System.out.println("Running sanityCheck"); } try { Stream<StackFrame> stream = Arrays.stream(frames); if (debug) { stream.forEach(LocalsAndOperands::printLocals); } else { System.out.println(stream.count() + " frames"); } } catch (Throwable t) { dumpStackWithLocals(frames); throw t; } }
/** * Sanity check for locals and operands, including testng/jtreg frames */ @Test(dataProvider = "unfilteredProvider") public static void unfilteredSanityCheck(StackFrame... frames) { if (debug) { System.out.println("Running unfilteredSanityCheck"); } try { Stream<StackFrame> stream = Arrays.stream(frames); if (debug) { stream.forEach(f -> { System.out.println(f + ": " + invokeGetLocals(f).length + " locals"); } ); } else { System.out.println(stream.count() + " frames"); } } catch (Throwable t) { dumpStackWithLocals(frames); throw t; } }
/** * Perform stackwalk without keeping local variables alive and return an * array of the collected StackFrames */ private synchronized StackFrame[] testLocals() { // Unused local variables will become dead int x = 10; char c = 'z'; String hi = "himom"; long l = 1000000L; double d = 3.1415926; if (filter) { return walker.walk(s -> s.filter(f -> TEST_METHODS.contains(f .getMethodName())).collect(Collectors.toList())) .toArray(new StackFrame[0]); } else { return walker.walk(s -> s.collect(Collectors.toList())) .toArray(new StackFrame[0]); } }
/** * Perform stackwalk, keeping local variables alive, and return a list of * the collected StackFrames */ private synchronized StackFrame[] testLocalsKeepAlive() { int x = 10; char c = 'z'; String hi = "himom"; long l = 1000000L; double d = 3.1415926; List<StackWalker.StackFrame> frames; if (filter) { frames = walker.walk(s -> s.filter(f -> TEST_METHODS.contains(f .getMethodName())).collect(Collectors.toList())); } else { frames = walker.walk(s -> s.collect(Collectors.toList())); } // Use local variables so they stay alive System.out.println("Stayin' alive: "+x+" "+c+" "+hi+" "+l+" "+d); return frames.toArray(new StackFrame[0]); // FIXME: convert to Array here }
/** * Print the StackFrame and an indexed list of its locals */ public static void printLocals(StackWalker.StackFrame frame) { try { System.out.println(frame); Object[] locals = (Object[]) getLocals.invoke(frame); 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(frame); 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(frame); for (int i = 0; i < monitors.length; i++) { System.out.format(" monitor %d: %s%n", i, monitors[i]); } } catch (Exception e) { throw new RuntimeException(e); } }
public long longArg(int i, long l) throws Throwable { List<StackFrame> frames = sw.walk(s -> s.collect(Collectors.toList())); Object[] locals = (Object[]) getLocals.invoke(frames.get(0)); if (8 == (int) primitiveSize.invoke(locals[2])) { // Only test 64-bit long locals_2 = (long) longValue.invoke(locals[2]); if (locals_2 != 0){ throw new RuntimeException("Expected locals_2 == 0"); } } return l; // Don't want l to become a dead var }
/** Returns true if the loader that loaded the frame's declaring class * is a user loader (if it is not the platform class loader or one of * its ancestor). */ private boolean isUserLoader(StackFrame sf) { ClassLoader cl = sf.getDeclaringClass().getClassLoader(); if (cl == null) return false; ClassLoader p = ClassLoader.getPlatformClassLoader(); while (cl != p && p != null) p = p.getParent(); return cl != p; }
static <T> StackFrameTraverser<T> makeStackTraverser(StackWalker walker, Function<? super Stream<StackFrame>, ? extends T> function) { if (walker.hasLocalsOperandsOption()) return new LiveStackInfoTraverser<>(walker, function); else return new StackFrameTraverser<>(walker, 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; } StackFrameInfo 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 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); } }
private String getCallerInfo() { Optional<StackWalker.StackFrame> frame = new CallerFinder().get(); if (frame.isPresent()) { return frame.get().getClassName() + " " + frame.get().getMethodName(); } else { return name; } }
static boolean isFilteredFrame(StackFrame st) { // skip logging/logger infrastructure if (System.Logger.class.isAssignableFrom(st.getDeclaringClass())) { return true; } // fast escape path: all the prefixes below start with 's' or 'j' and // have more than 12 characters. final String cname = st.getClassName(); char c = cname.length() < 12 ? 0 : cname.charAt(0); if (c == 's') { // skip internal machinery classes if (cname.startsWith("sun.util.logging.")) return true; if (cname.startsWith("sun.rmi.runtime.Log")) return true; } else if (c == 'j') { // Message delayed at Bootstrap: no need to go further up. if (cname.startsWith("jdk.internal.logger.BootstrapLogger$LogEvent")) return false; // skip public machinery classes if (cname.startsWith("jdk.internal.logger.")) return true; if (cname.startsWith("java.util.logging.")) return true; if (cname.startsWith("java.lang.invoke.MethodHandle")) return true; if (cname.startsWith("java.security.AccessController")) return true; } // check additional prefixes if any are specified. if (skips.length > 0) { for (int i=0; i<skips.length; i++) { if (!skips[i].isEmpty() && cname.startsWith(skips[i])) { return true; } } } return false; }
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); }
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); } }
/** Calls KnownLocalsTester.testLocals* and provides LiveStackFrames */ @DataProvider public static StackFrame[][] knownLocalsProvider() { List<StackFrame[]> list = new ArrayList<>(3); list.add(new KnownLocalsTester().testLocalsKeepAlive()); list.add(new KnownLocalsTester().testLocalsKeepAliveArgs(0xA, 'z', "himom", 0x3FF00000000L + 0xFFFF, Math.PI)); if (testUnused) { list.add(new KnownLocalsTester().testLocalsUnused()); } return list.toArray(new StackFrame[1][1]); }
/** * Check for expected local values in the LiveStackFrame */ @Test(dataProvider = "knownLocalsProvider") public static void checkLocalValues(StackFrame... frames) { dumpFramesIfDebug(frames); try { Stream.of(frames) .filter(f -> KnownLocalsTester.TEST_METHODS.contains(f.getMethodName())) .forEach(LocalsAndOperands::checkFrameLocals); } catch (Exception e) { dumpFramesIfNotDebug(frames); throw e; } }
/** * Check the locals in the given StackFrame against the expected values. */ private static void checkFrameLocals(StackFrame f) { Object[] expectedArray = KnownLocalsTester.LOCAL_VALUES; Object[] locals = invokeGetLocals(f); for (int i = 0; i < locals.length; i++) { Object expected = expectedArray[i]; Object observed = locals[i]; if (expected == null) { /* skip nulls in golden values */ continue; } else if (expected instanceof KnownLocalsTester.TwoSlotValue) { // confirm integrity of expected values assertEquals(expectedArray[i+1], null, "Malformed array of expected values - slot after TwoSlotValue should be null"); assertLongIsInSlots(locals[i], locals[i+1], ((KnownLocalsTester.TwoSlotValue)expected).value); i++; // skip following slot } else if (primitiveSlotClass.isInstance(observed)) { // single slot primitive assertTrue(primitiveValueEquals(observed, expected), "Local value mismatch: local " + i + " value is " + observed + ", expected " + expected); } else if (expected instanceof Class) { assertTrue(((Class)expected).isInstance(observed), "Local value mismatch: local " + i + " expected instancof " + expected + " but got " + observed); } else if (expected instanceof String) { assertEquals(expected, observed, "Local value mismatch: local " + i + " value is " + observed + ", expected " + expected); } else { throw new RuntimeException("Unrecognized expected local value " + i + ": " + expected); } } }
/** * Perform stackwalk without keeping local variables alive and return an * array of the collected StackFrames */ private synchronized StackFrame[] testLocalsUnused() { // Unused local variables will become dead int x = 0xA; char c = 'z'; // 0x7A String hi = "himom"; long l = 0x3FF00000000L + 0xFFFFL; double d = Math.PI; return walker.walk(s -> s.filter(f -> TEST_METHODS.contains(f.getMethodName())) .toArray(StackFrame[]::new) ); }
/** * Perform stackwalk, keeping method arguments alive, and return a list of * the collected StackFrames */ private synchronized StackFrame[] testLocalsKeepAliveArgs(int x, char c, String hi, long l, double d) { StackFrame[] frames = walker.walk(s -> s.filter(f -> TEST_METHODS.contains(f.getMethodName())) .toArray(StackFrame[]::new) ); // Use local variables so they stay alive System.out.println("Stayin' alive: "+this+" "+x+" "+c+" "+hi+" "+l+" "+d); return frames; }
private static void unusedLong(long longArg) throws Exception { StackFrame[] frames = extendedWalker.walk(s -> s.filter(f -> "unusedLong".equals(f.getMethodName())) .toArray(StackFrame[]::new) ); try { dumpFramesIfDebug(frames); final Object[] locals = (Object[]) getLocals.invoke(frames[0]); assertLongIsInSlots(locals[0], locals[1], NEG_LONG_VAL); } catch (Exception t) { dumpFramesIfNotDebug(frames); throw t; } }
/** * Print the StackFrame and an indexed list of its locals */ public static void printLocals(StackWalker.StackFrame frame) { try { System.out.println("Locals for: " + frame); Object[] locals = (Object[]) getLocals.invoke(frame); for (int i = 0; i < locals.length; i++) { String localStr = null; if (primitiveSlot64Class.isInstance(locals[i])) { localStr = String.format("0x%X", (Long)primitiveLongValue.invoke(locals[i])); } else if (primitiveSlot32Class.isInstance(locals[i])) { localStr = String.format("0x%X", (Integer)primitiveIntValue.invoke(locals[i])); } else if (locals[i] != null) { localStr = locals[i].toString(); } System.out.format(" local %d: %s type %s\n", i, localStr, type(locals[i])); } Object[] operands = (Object[]) getOperands.invoke(frame); 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(frame); for (int i = 0; i < monitors.length; i++) { System.out.format(" monitor %d: %s%n", i, monitors[i]); } } catch (Exception e) { throw new RuntimeException(e); } }
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); } }
public static void call(StackWalker walker, int loops) { if (loops == 0) { String caller = walker.walk(s -> s.map(StackFrame::getClassName) .filter(cn -> !cn.startsWith("jdk.internal.reflect.") && !cn.startsWith("java.lang.invoke")) .skip(2).findFirst() ).get(); assertEquals(caller, C1.class.getName()); walker.forEach(f -> C2.testEmbeddedWalker()); } else { call(walker, --loops); } }