1 import java.lang.reflect.Field;
   2 import java.lang.reflect.Method;
   3 import java.util.List;
   4 import java.util.Set;
   5 import java.util.stream.Collectors;
   6 import java.lang.StackWalker.StackFrame;
   7 
   8 public class LocalLongHelper {
   9     static StackWalker sw;
  10     static Method intValue;
  11     static Method getLocals;
  12     static Class<?> primitiveValueClass;
  13     static Method primitiveType;
  14     static Method getMethodType;
  15     static Field memberName;
  16     static Field offset;
  17     
  18     public static void main(String[] args) throws Throwable {
  19         setupReflectionStatics();
  20         new LocalLongHelper().longArg(0xC0FFEE, 0x1234567890ABCDEFL);
  21     }
  22 
  23     /*
  24      * The first 4 local slots should be:
  25      * 0: this
  26      * 1: int "i"
  27      * 2: long "l", first slot
  28      * 3: long "l", second slot
  29      */
  30     public long longArg(int i, long l) throws Throwable {        
  31         List<StackFrame> frames = sw.walk(s -> s.collect(Collectors.toList()));
  32         Object[] locals = (Object[]) getLocals.invoke(frames.get(0));
  33                 
  34         int locals_1 = (int) intValue.invoke(locals[1]); // java.lang.LiveStackFrame$PrimitiveValue.intValue()
  35         int locals_2 = (int) intValue.invoke(locals[2]);
  36         int locals_3 = (int) intValue.invoke(locals[3]);
  37         if (locals_2 != 0){
  38             throw new RuntimeException("Expected locals_2 == 0");
  39         }
  40         return l; // Don't want l to become a dead var
  41     }
  42     
  43     private static void setupReflectionStatics() throws Throwable {
  44         Class<?> liveStackFrameClass = Class.forName("java.lang.LiveStackFrame");
  45         primitiveValueClass = Class.forName("java.lang.LiveStackFrame$PrimitiveValue");
  46 
  47         getLocals = liveStackFrameClass.getDeclaredMethod("getLocals");
  48         getLocals.setAccessible(true);
  49 
  50         intValue = primitiveValueClass.getDeclaredMethod("intValue");
  51         intValue.setAccessible(true);
  52 
  53         Class<?> stackFrameInfoClass = Class.forName("java.lang.StackFrameInfo");
  54         memberName = stackFrameInfoClass.getDeclaredField("memberName");
  55         memberName.setAccessible(true);
  56         offset = stackFrameInfoClass.getDeclaredField("bci");
  57         offset.setAccessible(true);
  58         getMethodType = Class.forName("java.lang.invoke.MemberName").getDeclaredMethod("getMethodType");
  59         getMethodType.setAccessible(true);
  60         
  61         Class<?> extendedOptionClass = Class.forName("java.lang.StackWalker$ExtendedOption");
  62         Method ewsNI = StackWalker.class.getDeclaredMethod("newInstance", Set.class, extendedOptionClass);
  63         ewsNI.setAccessible(true);
  64         Field f = extendedOptionClass.getDeclaredField("LOCALS_AND_OPERANDS");
  65         f.setAccessible(true);
  66         Object localsAndOperandsOption = f.get(null);        
  67         
  68         primitiveType = primitiveValueClass.getDeclaredMethod("type");
  69         primitiveType.setAccessible(true);        
  70         
  71         sw = (StackWalker) ewsNI.invoke(null, java.util.Collections.emptySet(), localsAndOperandsOption);        
  72     }
  73 
  74     private static String type(Object o) throws Throwable {
  75         if (primitiveValueClass.isInstance(o)) {
  76             final char c = (char) primitiveType.invoke(o);
  77             return String.valueOf(c);
  78         } else if (o != null) {
  79             return o.getClass().getName();
  80         } else {
  81             return "null";
  82         }
  83     }
  84 }