1 /* 2 * Copyright (c) 2019, 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.StackWalker.StackFrame; 25 import java.util.List; 26 import java.util.stream.Collectors; 27 import java.util.Set; 28 import sun.hotspot.WhiteBox; 29 30 public class LambdaVerification { 31 static void verifyCallerIsArchivedLambda(boolean isRuntime) { 32 // getCallerClass(0) = verifyCallerIsArchivedLambda 33 // getCallerClass(1) = testNonCapturingLambda or testCapturingLambda 34 // getCallerClass(2) = the lambda proxy class that should be archived by CDS. 35 Class<?> c = getCallerClass(2); 36 System.out.println("Lambda proxy class = " + c); 37 String cn = c.getName(); 38 System.out.println(" cn = " + cn); 39 String hiddenClassName = cn.replace('/', '+'); 40 String lambdaClassName = cn.substring(0, cn.lastIndexOf('/')); 41 System.out.println(" lambda name = " + lambdaClassName); 42 WhiteBox wb = WhiteBox.getWhiteBox(); 43 if (isRuntime) { 44 // check that c is a shared class 45 if (wb.isSharedClass(c)) { 46 System.out.println("As expected, " + c + " is in shared space."); 47 } else { 48 throw new java.lang.RuntimeException(c + " must be in shared space."); 49 } 50 // check that lambda class cannot be found manually 51 try { 52 Class.forName(hiddenClassName); 53 } catch (ClassNotFoundException cnfe) { 54 cnfe.printStackTrace(System.out); 55 System.out.println("As expected, loading of " + hiddenClassName + " should result in ClassNotFoundException."); 56 } catch (Exception ex) { 57 throw ex; 58 } 59 // check that lambda class is alive 60 if (wb.isClassAlive(hiddenClassName)) { 61 System.out.println("As expected, " + cn + " is alive."); 62 } else { 63 throw new java.lang.RuntimeException(cn + " should be alive."); 64 } 65 } else { 66 if (wb.isSharedClass(c)) { 67 throw new java.lang.RuntimeException(c + " must not be in shared space."); 68 } else { 69 System.out.println("As expected, " + c + " is not in shared space."); 70 } 71 } 72 //System.out.println("=== Here's the call stack"); 73 //(new Throwable()).printStackTrace(System.out); 74 //System.out.println("==="); 75 System.out.println("Succeeded"); 76 } 77 78 // depth is 0-based -- i.e., depth==0 returns the class of the immediate caller of getCallerClass 79 static Class<?> getCallerClass(int depth) { 80 // Need to add the frame of the getCallerClass -- so the immediate caller (depth==0) of this method 81 // is at stack.get(1) == stack.get(depth+1); 82 StackWalker walker = StackWalker.getInstance( 83 Set.of(StackWalker.Option.RETAIN_CLASS_REFERENCE, 84 StackWalker.Option.SHOW_HIDDEN_FRAMES)); 85 List<StackFrame> stack = walker.walk(s -> s.limit(depth+2).collect(Collectors.toList())); 86 return stack.get(depth+1).getDeclaringClass(); 87 } 88 }