28 import java.util.stream.Collectors; |
28 import java.util.stream.Collectors; |
29 import java.lang.StackWalker.StackFrame; |
29 import java.lang.StackWalker.StackFrame; |
30 |
30 |
31 public class LocalLongHelper { |
31 public class LocalLongHelper { |
32 static StackWalker sw; |
32 static StackWalker sw; |
33 static Method intValue; |
33 static Method longValue; |
34 static Method getLocals; |
34 static Method getLocals; |
35 static Class<?> primitiveValueClass; |
35 static Class<?> primitiveValueClass; |
36 static Method primitiveType; |
36 static Method primitiveSize; |
37 static Method getMethodType; |
37 static Method getMethodType; |
38 static Field memberName; |
38 static Field memberName; |
39 static Field offset; |
39 static Field offset; |
40 |
40 |
41 public static void main(String[] args) throws Throwable { |
41 public static void main(String[] args) throws Throwable { |
42 setupReflectionStatics(); |
42 setupReflectionStatics(); |
43 new LocalLongHelper().longArg(0xC0FFEE, 0x1234567890ABCDEFL); |
43 new LocalLongHelper().longArg(0xC0FFEE, 0x1234567890ABCDEFL); |
44 } |
44 } |
45 |
45 |
46 // locals[2] contains the high byte of the long argument. |
46 // locals[2] contains the unused slot of the long argument. |
47 public long longArg(int i, long l) throws Throwable { |
47 public long longArg(int i, long l) throws Throwable { |
48 List<StackFrame> frames = sw.walk(s -> s.collect(Collectors.toList())); |
48 List<StackFrame> frames = sw.walk(s -> s.collect(Collectors.toList())); |
49 Object[] locals = (Object[]) getLocals.invoke(frames.get(0)); |
49 Object[] locals = (Object[]) getLocals.invoke(frames.get(0)); |
50 |
50 |
51 int locals_2 = (int) intValue.invoke(locals[2]); |
51 if (8 == (int) primitiveSize.invoke(locals[2])) { // Only test 64-bit |
52 if (locals_2 != 0){ |
52 long locals_2 = (long) longValue.invoke(locals[2]); |
53 throw new RuntimeException("Expected locals_2 == 0"); |
53 if (locals_2 != 0){ |
|
54 throw new RuntimeException("Expected locals_2 == 0"); |
|
55 } |
54 } |
56 } |
55 return l; // Don't want l to become a dead var |
57 return l; // Don't want l to become a dead var |
56 } |
58 } |
57 |
59 |
58 private static void setupReflectionStatics() throws Throwable { |
60 private static void setupReflectionStatics() throws Throwable { |
59 Class<?> liveStackFrameClass = Class.forName("java.lang.LiveStackFrame"); |
61 Class<?> liveStackFrameClass = Class.forName("java.lang.LiveStackFrame"); |
60 primitiveValueClass = Class.forName("java.lang.LiveStackFrame$PrimitiveValue"); |
62 primitiveValueClass = Class.forName("java.lang.LiveStackFrame$PrimitiveSlot"); |
61 |
63 |
62 getLocals = liveStackFrameClass.getDeclaredMethod("getLocals"); |
64 getLocals = liveStackFrameClass.getDeclaredMethod("getLocals"); |
63 getLocals.setAccessible(true); |
65 getLocals.setAccessible(true); |
64 |
66 |
65 intValue = primitiveValueClass.getDeclaredMethod("intValue"); |
67 longValue = primitiveValueClass.getDeclaredMethod("longValue"); |
66 intValue.setAccessible(true); |
68 longValue.setAccessible(true); |
67 |
69 |
68 Class<?> stackFrameInfoClass = Class.forName("java.lang.StackFrameInfo"); |
70 Class<?> stackFrameInfoClass = Class.forName("java.lang.StackFrameInfo"); |
69 memberName = stackFrameInfoClass.getDeclaredField("memberName"); |
71 memberName = stackFrameInfoClass.getDeclaredField("memberName"); |
70 memberName.setAccessible(true); |
72 memberName.setAccessible(true); |
71 offset = stackFrameInfoClass.getDeclaredField("bci"); |
73 offset = stackFrameInfoClass.getDeclaredField("bci"); |
78 ewsNI.setAccessible(true); |
80 ewsNI.setAccessible(true); |
79 Field f = extendedOptionClass.getDeclaredField("LOCALS_AND_OPERANDS"); |
81 Field f = extendedOptionClass.getDeclaredField("LOCALS_AND_OPERANDS"); |
80 f.setAccessible(true); |
82 f.setAccessible(true); |
81 Object localsAndOperandsOption = f.get(null); |
83 Object localsAndOperandsOption = f.get(null); |
82 |
84 |
83 primitiveType = primitiveValueClass.getDeclaredMethod("type"); |
85 primitiveSize = primitiveValueClass.getDeclaredMethod("size"); |
84 primitiveType.setAccessible(true); |
86 primitiveSize.setAccessible(true); |
85 |
|
86 sw = (StackWalker) ewsNI.invoke(null, java.util.Collections.emptySet(), localsAndOperandsOption); |
87 sw = (StackWalker) ewsNI.invoke(null, java.util.Collections.emptySet(), localsAndOperandsOption); |
87 } |
88 } |
88 |
|
89 private static String type(Object o) throws Throwable { |
|
90 if (primitiveValueClass.isInstance(o)) { |
|
91 final char c = (char) primitiveType.invoke(o); |
|
92 return String.valueOf(c); |
|
93 } else if (o != null) { |
|
94 return o.getClass().getName(); |
|
95 } else { |
|
96 return "null"; |
|
97 } |
|
98 } |
|
99 } |
89 } |