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