1 /* 2 * Copyright (c) 2019, 2020, 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 /** 25 * @test 26 * @library /test/lib 27 * @modules java.base/jdk.internal.misc 28 * jdk.compiler 29 * @compile HiddenClassSigTest.java 30 * @run main/othervm/native -agentlib:HiddenClassSigTest P.Q.HiddenClassSigTest 31 */ 32 33 package P.Q; 34 35 import java.io.ByteArrayOutputStream; 36 import java.io.File; 37 import java.io.FileInputStream; 38 39 import java.lang.invoke.MethodHandles; 40 import java.lang.invoke.MethodHandles.Lookup; 41 42 import jdk.test.lib.Utils; 43 import jdk.test.lib.compiler.InMemoryJavaCompiler; 44 45 46 interface Test<T> { 47 String test(T t); 48 } 49 50 class HiddenClassSig<T> implements Test<T> { 51 private String realTest() { return "HiddenClassSig: "; } 52 53 public String test(T t) { 54 String str = realTest(); 55 return str + t.toString(); 56 } 57 } 58 59 public class HiddenClassSigTest { 60 private static void log(String str) { System.out.println(str); } 61 62 private static final String HCName = "P/Q/HiddenClassSig.class"; 63 private static final String DIR = Utils.TEST_CLASSES; 64 private static final String LOG_PREFIX = "HiddenClassSigTest: "; 65 private static final String ARR_PREFIX = "[[L"; 66 private static final String ARR_POSTFIX = "[][]"; 67 private static final String CLASS_PREFIX = "class "; 68 69 static native void checkHiddenClass(Class klass, String sig); 70 static native void checkHiddenClassArray(Class array, String sig); 71 static native boolean checkFailed(); 72 73 static { 74 try { 75 System.loadLibrary("HiddenClassSigTest"); 76 } catch (UnsatisfiedLinkError ule) { 77 System.err.println("Could not load HiddenClassSigTest library"); 78 System.err.println("java.library.path: " 79 + System.getProperty("java.library.path")); 80 throw ule; 81 } 82 } 83 84 static byte[] readClassFile(String classFileName) throws Exception { 85 File classFile = new File(classFileName); 86 try (FileInputStream in = new FileInputStream(classFile); 87 ByteArrayOutputStream out = new ByteArrayOutputStream()) 88 { 89 int b; 90 while ((b = in.read()) != -1) { 91 out.write(b); 92 } 93 return out.toByteArray(); 94 } 95 } 96 97 static Class<?> defineHiddenClass(String classFileName) throws Exception { 98 Lookup lookup = MethodHandles.lookup(); 99 byte[] bytes = readClassFile(DIR + File.separator + classFileName); 100 Class<?> hc = lookup.defineHiddenClass(bytes, false).lookupClass(); 101 return hc; 102 } 103 104 static void logClassInfo(Class<?> klass) { 105 log("\n### Testing class: " + klass); 106 log(LOG_PREFIX + "isHidden: " + klass.isHidden()); 107 log(LOG_PREFIX + "getName: " + klass.getName()); 108 log(LOG_PREFIX + "typeName: " + klass.getTypeName()); 109 log(LOG_PREFIX + "toString: " + klass.toString()); 110 log(LOG_PREFIX + "toGenStr: " + klass.toGenericString()); 111 log(LOG_PREFIX + "elem type: " + klass.componentType()); 112 } 113 114 static boolean checkName(String name, String expName, String msgPart) { 115 boolean failed = false; 116 if (!name.equals(expName)) { 117 log("Test FAIL: result of " + msgPart + " does not match expectation"); 118 failed = true; 119 } 120 return failed; 121 } 122 123 static boolean checkNameHas(String name, String expNamePart, String msgPart) { 124 boolean failed = false; 125 if (name.indexOf(expNamePart) < 0) { 126 log("Test FAIL: result of " + msgPart + " does not match expectation"); 127 failed = true; 128 } 129 return failed; 130 } 131 132 static boolean checkArray(Class<?> arrClass) { 133 boolean failed = false; 134 Class<?> elemClass = arrClass.componentType(); 135 136 String arrName = arrClass.getName(); 137 String arrType = arrClass.getTypeName(); 138 String arrStr = arrClass.toString().substring(CLASS_PREFIX.length()); 139 String arrGen = arrClass.toGenericString(); 140 141 String elemName = elemClass.getName(); 142 String elemType = elemClass.getTypeName(); 143 String elemStr = elemClass.toString().substring(CLASS_PREFIX.length()); 144 String elemGen = elemClass.toGenericString(); 145 146 if (elemClass.isHidden()) { 147 elemGen = elemGen.substring(CLASS_PREFIX.length()); 148 } 149 failed |= checkNameHas(arrName, elemName, "klass.getName()"); 150 failed |= checkNameHas(arrStr, elemStr, "klass.toString()"); 151 failed |= checkNameHas(arrType, elemType, "klass.getTypeName()"); 152 failed |= checkNameHas(arrGen, elemGen, "klass.getGenericString()"); 153 return failed; 154 } 155 156 static boolean testClass(Class<?> klass, int arrLevel, String baseName) { 157 boolean failed = false; 158 boolean isHidden = (arrLevel == 0); 159 String prefix = (arrLevel == 0) ? "" : ARR_PREFIX.substring(2 - arrLevel); 160 String postfix = (arrLevel == 0) ? "" : ";"; 161 162 logClassInfo(klass); 163 164 String expName = ("" + klass).substring(CLASS_PREFIX.length()); 165 String expType = baseName; 166 String expStr = CLASS_PREFIX + prefix + baseName + postfix; 167 String expGen = baseName + "<T>" + ARR_POSTFIX.substring(0, 2*arrLevel); 168 169 if (arrLevel > 0) { 170 expType = expType + ARR_POSTFIX.substring(0, 2*arrLevel); 171 } else { 172 expGen = CLASS_PREFIX + expGen; 173 } 174 failed |= checkName(klass.getName(), expName, "klass.getName()"); 175 failed |= checkName(klass.getTypeName(), expType, "klass.getTypeName()"); 176 failed |= checkName(klass.toString(), expStr, "klass.toString()"); 177 failed |= checkName(klass.toGenericString(), expGen, "klass.toGenericString()"); 178 179 if (klass.isHidden() != isHidden) { 180 log("Test FAIL: result of klass.isHidden() does not match expectation"); 181 failed = true; 182 } 183 String sig = hcSignature(klass); 184 if (arrLevel == 0) { 185 checkHiddenClass(klass, sig); 186 } else { 187 failed |= checkArray(klass); 188 checkHiddenClassArray(klass, sig); 189 } 190 return failed; 191 } 192 193 static String hcSignature(Class<?> klass) { 194 boolean isArray = klass.isArray(); 195 String sig = klass.getName(); 196 String prefix = isArray ? "" : "L"; 197 String postfix = isArray ? "" : ";"; 198 int idx = sig.indexOf("/"); 199 200 sig = prefix + sig.substring(0, idx).replace('.', '/') 201 + "." 202 + sig.substring(idx + 1, sig.length()) 203 + postfix; 204 return sig; 205 } 206 207 public static void main(String args[]) throws Exception { 208 log(LOG_PREFIX + "started"); 209 Class<?> hc = defineHiddenClass(HCName); 210 String baseName = ("" + hc).substring("class ".length()); 211 212 Test<String> t = (Test<String>)hc.newInstance(); 213 String str = t.test("Test generic hidden class"); 214 log(LOG_PREFIX + "hc.test() returned string: " + str); 215 216 boolean failed = testClass(hc, 0, baseName); 217 218 Class<?> hcArr = hc.arrayType(); 219 failed |= testClass(hcArr, 1, baseName); 220 221 Class<?> hcArrArr = hcArr.arrayType(); 222 failed |= testClass(hcArrArr, 2, baseName); 223 224 if (failed) { 225 throw new RuntimeException("FAIL: failed status from java part"); 226 } 227 if (checkFailed()) { 228 throw new RuntimeException("FAIL: failed status from native agent"); 229 } 230 log(LOG_PREFIX + "finished"); 231 } 232 }