1 /*
   2  * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.lang.reflect.Field;
  25 import java.lang.reflect.Method;
  26 import java.util.List;
  27 import java.util.Set;
  28 import java.util.stream.Collectors;
  29 import java.lang.StackWalker.StackFrame;
  30 
  31 public class LocalLongHelper {
  32     static StackWalker sw;
  33     static Method longValue;
  34     static Method getLocals;
  35     static Class<?> primitiveValueClass;
  36     static Method primitiveSize;
  37     static Method getMethodType;
  38     static Field memberName;
  39     static Field offset;
  40 
  41     public static void main(String[] args) throws Throwable {
  42         setupReflectionStatics();
  43         new LocalLongHelper().longArg(0xC0FFEE, 0x1234567890ABCDEFL);
  44     }
  45 
  46     // locals[2] contains the unused slot of the long argument.
  47     public long longArg(int i, long l) throws Throwable {
  48         List<StackFrame> frames = sw.walk(s -> s.collect(Collectors.toList()));
  49         Object[] locals = (Object[]) getLocals.invoke(frames.get(0));
  50 
  51         if (8 == (int) primitiveSize.invoke(locals[2])) { // Only test 64-bit
  52             long locals_2 = (long) longValue.invoke(locals[2]);
  53             if (locals_2 != 0){
  54                 throw new RuntimeException("Expected locals_2 == 0");
  55             }
  56         }
  57         return l; // Don't want l to become a dead var
  58     }
  59 
  60     private static void setupReflectionStatics() throws Throwable {
  61         Class<?> liveStackFrameClass = Class.forName("java.lang.LiveStackFrame");
  62         primitiveValueClass = Class.forName("java.lang.LiveStackFrame$PrimitiveSlot");
  63 
  64         getLocals = liveStackFrameClass.getDeclaredMethod("getLocals");
  65         getLocals.setAccessible(true);
  66 
  67         longValue = primitiveValueClass.getDeclaredMethod("longValue");
  68         longValue.setAccessible(true);
  69 
  70         Class<?> stackFrameInfoClass = Class.forName("java.lang.StackFrameInfo");
  71         memberName = stackFrameInfoClass.getDeclaredField("memberName");
  72         memberName.setAccessible(true);
  73         offset = stackFrameInfoClass.getDeclaredField("bci");
  74         offset.setAccessible(true);
  75         getMethodType = Class.forName("java.lang.invoke.MemberName").getDeclaredMethod("getMethodType");
  76         getMethodType.setAccessible(true);
  77 
  78         Class<?> extendedOptionClass = Class.forName("java.lang.StackWalker$ExtendedOption");
  79         Method ewsNI = StackWalker.class.getDeclaredMethod("newInstance", Set.class, extendedOptionClass);
  80         ewsNI.setAccessible(true);
  81         Field f = extendedOptionClass.getDeclaredField("LOCALS_AND_OPERANDS");
  82         f.setAccessible(true);
  83         Object localsAndOperandsOption = f.get(null);
  84 
  85         primitiveSize = primitiveValueClass.getDeclaredMethod("size");
  86         primitiveSize.setAccessible(true);
  87         sw = (StackWalker) ewsNI.invoke(null, java.util.Collections.emptySet(), localsAndOperandsOption);
  88     }
  89 }