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 66 static native void checkHiddenClass(Class klass, String sig); 67 static native void checkHiddenClassArray(Class array, String sig); 68 static native boolean checkFailed(); 69 70 static { 71 try { 72 System.loadLibrary("HiddenClassSigTest"); 73 } catch (UnsatisfiedLinkError ule) { 74 System.err.println("Could not load HiddenClassSigTest library"); 75 System.err.println("java.library.path: " 76 + System.getProperty("java.library.path")); 77 throw ule; 78 } 79 } 80 81 static byte[] readClassFile(String classFileName) throws Exception { 82 File classFile = new File(classFileName); 83 try (FileInputStream in = new FileInputStream(classFile); 84 ByteArrayOutputStream out = new ByteArrayOutputStream()) 85 { 86 int b; 87 while ((b = in.read()) != -1) { 88 out.write(b); 89 } 90 return out.toByteArray(); 91 } 92 } 93 94 static Class<?> defineHiddenClass(String classFileName) throws Exception { 95 Lookup lookup = MethodHandles.lookup(); 96 byte[] bytes = readClassFile(DIR + File.separator + classFileName); 97 Class<?> hc = lookup.defineHiddenClass(bytes, false).lookupClass(); 98 return hc; 99 } 100 101 static void logClassInfo(Class<?> klass) { 102 log("\n### Testing class: " + klass); 103 log(LOG_PREFIX + "isHidden: " + klass.isHidden()); 104 log(LOG_PREFIX + "getName: " + klass.getName()); 105 log(LOG_PREFIX + "typeName: " + klass.getTypeName()); 106 log(LOG_PREFIX + "toString: " + klass.toString()); 107 log(LOG_PREFIX + "toGenStr: " + klass.toGenericString()); 108 log(LOG_PREFIX + "elem type: " + klass.componentType()); 109 } 110 111 private static final String HC_NAME = "P.Q.HiddenClassSig"; 112 private static final String HC_SUFFIX_REGEX = "/0x[0-9a-f]+"; 113 static boolean checkName(Class<?> klass, String name, String toString) { 114 boolean failed = false; 115 String regex = ""; 116 Class<?> c = klass; 117 while (c.isArray()) { 118 regex = "\\[" + regex; 119 c = c.componentType(); 120 } 121 if (klass.isArray()) { 122 regex += "L" + HC_NAME + HC_SUFFIX_REGEX + ";"; 123 } else { 124 regex = HC_NAME + HC_SUFFIX_REGEX; 125 } 126 if (!name.matches(regex)) { 127 log("Test FAIL: result of Class::getName" + " \"" + name + "\" does not match " + regex); 128 failed = true; 129 } 130 if (!toString.matches("class " + regex)) { 131 log("Test FAIL: result of Class::toString" + " \"" + name + "\" does not match " + regex); 132 failed = true; 133 } 134 return failed; 135 } 136 137 static boolean checkTypeName(Class<?> klass, String name) { 138 boolean failed = false; 139 String regex = HC_NAME + HC_SUFFIX_REGEX; 140 Class<?> c = klass; 141 while (c.isArray()) { 142 c = c.componentType(); 143 regex = regex + "\\[\\]"; 144 } 145 if (!name.matches(regex)) { 146 log("Test FAIL: result of Class::getTypeName" + " \"" + name + "\" does not match " + regex); 147 failed = true; 148 } 149 return failed; 150 } 151 152 static boolean checkGenericString(Class<?> klass, String name) { 153 boolean failed = false; 154 Class<?> c = klass; 155 String regex = HC_NAME + HC_SUFFIX_REGEX + "<T>"; 156 if (!klass.isArray()) { 157 regex = "class " + regex; 158 } 159 while (c.isArray()) { 160 c = c.componentType(); 161 regex = regex + "\\[\\]"; 162 } 163 if (!name.matches(regex)) { 164 log("Test FAIL: result of Class::toGenericString" + " \"" + name + "\" does not match " + regex); 165 failed = true; 166 } 167 return failed; 168 } 169 170 static boolean checkDescriptorString(Class<?> klass, String name) { 171 boolean failed = false; 172 String regex = "L" + HC_NAME.replace('.', '/') + ";"; 173 Class<?> c = klass; 174 while (c.isArray()) { 175 regex = "\\[" + regex; 176 c = c.componentType(); 177 } 178 regex += HC_SUFFIX_REGEX; 179 if (!name.matches(regex)) { 180 log("Test FAIL: result of Class::getName" + " \"" + name + "\" does not match " + regex); 181 failed = true; 182 } 183 return failed; 184 } 185 186 static boolean testClass(Class<?> klass) { 187 boolean failed = false; 188 logClassInfo(klass); 189 190 failed |= checkName(klass, klass.getName(), klass.toString()); 191 failed |= checkTypeName(klass, klass.getTypeName()); 192 failed |= checkGenericString(klass, klass.toGenericString()); 193 failed |= checkDescriptorString(klass, klass.descriptorString()); 194 195 if (klass.isArray() && klass.isHidden()) { 196 log("Test FAIL: an array class is never hidden"); 197 failed = true; 198 } 199 if (klass.isArray()) { 200 checkHiddenClassArray(klass, klass.descriptorString()); 201 } else { 202 checkHiddenClass(klass, klass.descriptorString()); 203 } 204 return failed; 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); 217 218 Class<?> hcArr = hc.arrayType(); 219 failed |= testClass(hcArr); 220 221 Class<?> hcArrArr = hcArr.arrayType(); 222 failed |= testClass(hcArrArr); 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 }