11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package valhalla.shady; 26 27 import jdk.experimental.bytecode.BasicClassBuilder; 28 import jdk.internal.misc.Unsafe; 29 import sun.security.action.GetPropertyAction; 30 31 import java.io.File; 32 import java.io.FileOutputStream; 33 import java.io.IOException; 34 import java.security.ProtectionDomain; 35 import java.util.Properties; 36 37 import static jdk.internal.org.objectweb.asm.Opcodes.*; 38 39 public class MinimalValueTypes_1_0 { 40 41 public static final int V53_1 = 1 << 16 | 53; 42 public static final int ACC_VALUE = ACC_NATIVE; 43 public static final String OBJECT_CLASS_DESC = "java/lang/Object"; 44 public static final String VALUE_CLASS_DESC = "java/lang/__Value"; 45 46 public static final String DERIVE_VALUE_TYPE_DESC = "Ljvm/internal/value/DeriveValueType;"; 47 public static final String DERIVE_VT_CLASSNAME_POSTFIX = "$Value"; 48 public static final int DERIVE_VT_CLASS_ACCESS = ACC_PUBLIC|ACC_SUPER|ACC_FINAL|ACC_VALUE|ACC_SYNTHETIC; 49 50 public static final boolean DUMP_CLASS_FILES; 51 52 static { 53 // Use same property as in j.l.invoke.MethodHandleStatics 54 Properties props = GetPropertyAction.privilegedGetProperties(); 55 DUMP_CLASS_FILES = Boolean.parseBoolean( 56 props.getProperty("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES")); 57 } 58 59 public static String getValueTypeClassName(ValueTypeDesc valueTypeDesc) { 60 return getValueTypeClassName(valueTypeDesc.getName()); 61 } 62 63 public static String getValueTypeClassName(String vccName) { 64 return vccName + DERIVE_VT_CLASSNAME_POSTFIX; 65 } 66 67 public static String getValueCapableClassName(String valName) { 68 return valName.substring(0, valName.length() - DERIVE_VT_CLASSNAME_POSTFIX.length()); 69 } 70 71 public static boolean isValueType(Class<?> x) { 72 return (x.getModifiers() & ACC_VALUE) != 0; 73 } 74 75 public static Class<?> getValueCapableClass(Class<?> x) throws ClassNotFoundException { 76 if (!isValueType(x)) { 77 throw new IllegalArgumentException("Expected ValueType"); 78 } 79 return Class.forName(getValueCapableClassName(x.getName()), true, x.getClassLoader()); 80 } 81 82 public static Class<?> getValueTypeClass(Class<?> x) throws ClassNotFoundException { 83 if (isValueType(x)) { 84 throw new IllegalArgumentException("Expected Value Capable Class"); 85 } 86 return Class.forName(getValueTypeClassName(x.getName()), true, x.getClassLoader()); 87 } 88 89 public static String getValueTypeClassName(Class<?> x) { 90 String vtName = x.getName(); 91 if (!isValueType(x)) { 92 vtName += DERIVE_VT_CLASSNAME_POSTFIX; 93 } 94 return vtName; 95 } 96 97 public static boolean classHasValueType(Class<?> x) { 98 if (x.getDeclaredAnnotation(jvm.internal.value.DeriveValueType.class) == null) { 99 return false; 100 } 101 try { 102 Class.forName(getValueTypeClassName(x), true, x.getClassLoader()); 103 return true; 104 } 105 catch (ClassNotFoundException cnfe) { 106 return false; 107 } 108 } 109 110 // fds : name/sig pairs 111 // fmods : field modifiers 112 public static String createDerivedValueType(String vccInternalClassName, ClassLoader cl, ProtectionDomain pd, String[] fds, int[] fmods) { 113 String vtInternalClassName = getValueTypeClassName(vccInternalClassName); 114 ValueTypeDesc valueTypeDesc = new ValueTypeDesc(vccInternalClassName, fds, fmods); 115 byte[] valueTypeBytes = createValueType(valueTypeDesc); 116 Class<?> vtClass = Unsafe.getUnsafe().defineClass(vtInternalClassName, valueTypeBytes, 0, valueTypeBytes.length, cl, pd); 117 return vtInternalClassName; 118 } 119 120 public static byte[] createValueType(ValueTypeDesc valueTypeDesc) { 121 122 String valueTypeClassName = getValueTypeClassName(valueTypeDesc); 123 124 BasicClassBuilder builder = new BasicClassBuilder(valueTypeClassName, 53, 1) 125 .withFlags(DERIVE_VT_CLASS_ACCESS) 126 .withSuperclass(VALUE_CLASS_DESC); 127 128 ValueTypeDesc.Field[] fields = valueTypeDesc.getFields(); 129 for (ValueTypeDesc.Field field : fields) { 130 builder.withField(field.name, field.type, F -> F.withFlags(field.modifiers)); 131 } 132 133 byte[] newBytes = builder.build(); 134 maybeDump(valueTypeClassName, newBytes); 135 return newBytes; 136 } 137 138 /** debugging flag for saving generated class files */ 139 private static final File DUMP_CLASS_FILES_DIR; 140 141 static { 142 if (DUMP_CLASS_FILES) { 143 try { 144 File dumpDir = new File("DUMP_CLASS_FILES"); 145 if (!dumpDir.exists()) { 146 dumpDir.mkdirs(); 147 } 148 DUMP_CLASS_FILES_DIR = dumpDir; 149 } catch (Exception e) { 150 throw new InternalError(e); 151 } 152 } else { 153 DUMP_CLASS_FILES_DIR = null; 154 } 155 } 156 157 public static void maybeDump(final String className, final byte[] classFile) { 158 if (DUMP_CLASS_FILES) { 159 java.security.AccessController.doPrivileged( 160 new java.security.PrivilegedAction<>() { 161 public Void run() { 162 try { 163 String dumpName = className; 164 //dumpName = dumpName.replace('/', '-'); 165 File dumpFile = new File(DUMP_CLASS_FILES_DIR, dumpName+".class"); 166 System.out.println("dump: " + dumpFile); 167 dumpFile.getParentFile().mkdirs(); 168 FileOutputStream file = new FileOutputStream(dumpFile); 169 file.write(classFile); 170 file.close(); 171 return null; 172 } catch (IOException ex) { 173 throw new InternalError(ex); 174 } 175 } 176 }); 177 } 178 } 179 180 private final native Class<?> getDerivedValueType(Class<?> ofClass); 181 182 public static Class<?> getValueClass() { 183 return (Class<?>)(Object)__Value.class; //hack around static type-system checks 184 } 185 } | 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package valhalla.shady; 26 27 import jdk.experimental.bytecode.BasicClassBuilder; 28 import jdk.internal.misc.Unsafe; 29 import sun.security.action.GetPropertyAction; 30 31 import java.io.BufferedOutputStream; 32 import java.io.IOException; 33 import java.io.OutputStream; 34 import java.nio.file.Files; 35 import java.nio.file.Path; 36 import java.nio.file.Paths; 37 import java.security.ProtectionDomain; 38 import java.util.Properties; 39 40 import static jdk.internal.org.objectweb.asm.Opcodes.*; 41 42 import jdk.internal.misc.JavaLangAccess; 43 import jdk.internal.misc.SharedSecrets; 44 public class MinimalValueTypes_1_0 { 45 46 public static final int V53_1 = 1 << 16 | 53; 47 public static final int ACC_VALUE = ACC_NATIVE; 48 public static final String OBJECT_CLASS_DESC = "java/lang/Object"; 49 public static final String VALUE_CLASS_DESC = "java/lang/__Value"; 50 51 public static final String DERIVE_VALUE_TYPE_DESC = "Ljvm/internal/value/DeriveValueType;"; 52 public static final String DERIVE_VT_CLASSNAME_POSTFIX = "$Value"; 53 public static final int DERIVE_VT_CLASS_ACCESS = ACC_PUBLIC|ACC_SUPER|ACC_FINAL|ACC_VALUE|ACC_SYNTHETIC; 54 55 public static final boolean DUMP_CLASS_FILES; 56 private static final JavaLangAccess JLA; 57 58 static { 59 // Use same property as in j.l.invoke.MethodHandleStatics 60 Properties props = GetPropertyAction.privilegedGetProperties(); 61 DUMP_CLASS_FILES = Boolean.parseBoolean( 62 props.getProperty("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES")); 63 64 JLA = SharedSecrets.getJavaLangAccess(); 65 } 66 67 public static String getValueTypeClassName(ValueTypeDesc valueTypeDesc) { 68 return getValueTypeClassName(valueTypeDesc.getName()); 69 } 70 71 public static String getValueTypeClassName(String vccName) { 72 return vccName + DERIVE_VT_CLASSNAME_POSTFIX; 73 } 74 75 public static String getValueCapableClassName(String valName) { 76 return valName.substring(0, valName.length() - DERIVE_VT_CLASSNAME_POSTFIX.length()); 77 } 78 79 public static boolean isValueType(Class<?> x) { 80 return (x.getModifiers() & ACC_VALUE) != 0; 81 } 82 83 public static Class<?> getValueCapableClass(Class<?> x) throws ClassNotFoundException { 84 if (!isValueType(x)) { 85 throw new IllegalArgumentException("Expected ValueType"); 86 } 87 return Class.forName(getValueCapableClassName(x.getName()), true, x.getClassLoader()); 88 } 89 90 public static Class<?> getValueTypeClass(Class<?> x) throws ClassNotFoundException { 91 if (isValueType(x)) { 92 throw new IllegalArgumentException("Expected Value Capable Class"); 93 } 94 return loadValueTypeClass(x, getValueTypeClassName(x.getName())); 95 } 96 97 public static String getValueTypeClassName(Class<?> x) { 98 String vtName = x.getName(); 99 if (!isValueType(x)) { 100 vtName += DERIVE_VT_CLASSNAME_POSTFIX; 101 } 102 return vtName; 103 } 104 105 public static boolean classHasValueType(Class<?> x) { 106 if (x.getDeclaredAnnotation(jvm.internal.value.DeriveValueType.class) == null) { 107 return false; 108 } 109 return loadValueTypeClass(x, getValueTypeClassName(x)) != null; 110 } 111 112 public static Class<?> loadValueTypeClass(Class<?> vcc, String className) { 113 if (isValueType(vcc)) { 114 throw new IllegalArgumentException(vcc.getName() + " already a derived value type"); 115 } 116 Class<?> c = JLA.loadValueTypeClass(vcc.getModule(), vcc.getClassLoader(), className); 117 if (c == null) { 118 throw new InternalError(className + " not loaded"); 119 } 120 return c; 121 } 122 123 // fds : name/sig pairs 124 // fmods : field modifiers 125 public static String createDerivedValueType(String vccInternalClassName, 126 ClassLoader cl, 127 ProtectionDomain pd, 128 String[] fds, 129 int[] fmods) { 130 String vtInternalClassName = getValueTypeClassName(vccInternalClassName); 131 ValueTypeDesc valueTypeDesc = new ValueTypeDesc(vccInternalClassName, fds, fmods); 132 byte[] valueTypeBytes = createValueType(valueTypeDesc); 133 Class<?> vtClass = Unsafe.getUnsafe().defineClass(vtInternalClassName, valueTypeBytes, 0, valueTypeBytes.length, cl, pd); 134 return vtInternalClassName; 135 } 136 137 public static byte[] createValueType(ValueTypeDesc valueTypeDesc) { 138 139 String valueTypeClassName = getValueTypeClassName(valueTypeDesc); 140 141 BasicClassBuilder builder = new BasicClassBuilder(valueTypeClassName, 53, 1) 142 .withFlags(DERIVE_VT_CLASS_ACCESS) 143 .withSuperclass(VALUE_CLASS_DESC); 144 145 ValueTypeDesc.Field[] fields = valueTypeDesc.getFields(); 146 for (ValueTypeDesc.Field field : fields) { 147 builder.withField(field.name, field.type, F -> F.withFlags(field.modifiers)); 148 } 149 150 byte[] newBytes = builder.build(); 151 maybeDump(valueTypeClassName, newBytes); 152 return newBytes; 153 } 154 155 /** debugging flag for saving generated class files */ 156 private static final Path DUMP_CLASS_FILES_DIR; 157 158 static { 159 if (DUMP_CLASS_FILES) { 160 try { 161 Path dumpDir = Paths.get("DUMP_CLASS_FILES"); 162 Files.createDirectories(dumpDir); 163 DUMP_CLASS_FILES_DIR = dumpDir; 164 } catch (Exception e) { 165 throw new InternalError(e); 166 } 167 } else { 168 DUMP_CLASS_FILES_DIR = null; 169 } 170 } 171 172 public static void maybeDump(final String className, final byte[] classFile) { 173 if (DUMP_CLASS_FILES_DIR != null) { 174 java.security.AccessController.doPrivileged( 175 new java.security.PrivilegedAction<>() { 176 public Void run() { 177 String dumpName = className; 178 //dumpName = dumpName.replace('/', '-'); 179 Path dumpFile = DUMP_CLASS_FILES_DIR.resolve(dumpName + ".class"); 180 System.out.println("dump: " + dumpFile); 181 try (OutputStream os = Files.newOutputStream(dumpFile); 182 BufferedOutputStream bos = new BufferedOutputStream(os)) { 183 bos.write(classFile); 184 } catch (IOException ex) { 185 throw new InternalError(ex); 186 } 187 return null; 188 } 189 }); 190 191 } 192 } 193 194 private final native Class<?> getDerivedValueType(Class<?> ofClass); 195 196 public static Class<?> getValueClass() { 197 return (Class<?>)(Object)__Value.class; //hack around static type-system checks 198 } 199 } |