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 jdk.internal.misc.VM; 30 import sun.security.action.GetPropertyAction; 31 32 import java.io.BufferedOutputStream; 33 import java.io.File; 34 import java.io.IOException; 35 import java.io.OutputStream; 36 import java.nio.file.Files; 37 import java.nio.file.Path; 38 import java.nio.file.Paths; 39 import java.security.ProtectionDomain; 40 import java.util.Properties; 41 42 import static jdk.internal.org.objectweb.asm.Opcodes.*; 43 44 import jdk.internal.misc.JavaLangAccess; 45 import jdk.internal.misc.SharedSecrets; 46 public class MinimalValueTypes_1_0 { 47 48 public static final int V53_1 = 1 << 16 | 53; 49 public static final int ACC_VALUE = ACC_NATIVE; 50 public static final String OBJECT_CLASS_DESC = "java/lang/Object"; 51 public static final String VALUE_CLASS_DESC = "java/lang/__Value"; 52 53 public static final String DERIVE_VALUE_TYPE_DESC = "Ljvm/internal/value/ValueCapableClass;"; 54 public static final String DERIVE_VT_CLASSNAME_POSTFIX = "$Value"; 55 public static final int DERIVE_VT_CLASS_ACCESS = ACC_PUBLIC|ACC_SUPER|ACC_FINAL|ACC_VALUE|ACC_SYNTHETIC; 56 57 public static final boolean DUMP_CLASS_FILES; 58 private static final boolean VALUE_TYPE_ENABLED; 59 private static final JavaLangAccess JLA; 60 61 static { 62 // Use same property as in j.l.invoke.MethodHandleStatics 63 Properties props = GetPropertyAction.privilegedGetProperties(); 64 DUMP_CLASS_FILES = Boolean.parseBoolean( 65 props.getProperty("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES")); 66 67 VALUE_TYPE_ENABLED = Boolean.parseBoolean( 68 props.getProperty("valhalla.enableValueType")); 69 70 JLA = SharedSecrets.getJavaLangAccess(); 71 } 72 73 public static boolean isValueTypeEnabled() { 74 return VALUE_TYPE_ENABLED; 75 } 76 77 public static String getValueTypeClassName(ValueTypeDesc valueTypeDesc) { 78 return getValueTypeClassName(valueTypeDesc.getName()); 79 } 80 81 public static String getValueTypeClassName(String vccName) { 82 return vccName + DERIVE_VT_CLASSNAME_POSTFIX; 83 } 84 85 public static String getValueCapableClassName(String valName) { 86 return valName.substring(0, valName.length() - DERIVE_VT_CLASSNAME_POSTFIX.length()); 87 } 88 89 public static boolean isValueType(Class<?> dvt) { 90 return (dvt.getModifiers() & ACC_VALUE) != 0; 91 } 92 93 public static boolean isValueCapable(Class<?> vcc) { 94 return vcc.getDeclaredAnnotation(jvm.internal.value.ValueCapableClass.class) != null; 95 } 96 97 public static Class<?> getValueCapableClass(Class<?> dvt) { 98 if (!isValueType(dvt)) { 99 throw new IllegalArgumentException(dvt + " is not a derived value type"); 100 } 101 102 Class<?> c = Class.forName(dvt.getModule(), getValueCapableClassName(dvt.getName())); 103 if (c == null || !isValueCapable(c)) { 104 throw new InternalError(dvt + " not bound to ValueType"); 105 } 106 return c; 107 } 108 109 public static Class<?> getValueTypeClass(Class<?> vcc) { 110 if (!isValueCapable(vcc)) { 111 throw new IllegalArgumentException(vcc + " is not a value capable class"); 112 } 113 return loadValueTypeClass(vcc, getValueTypeClassName(vcc.getName())); 114 } 185 if (!root.exists() && !root.mkdirs()) { 186 throw new IllegalStateException("Could not create dump file directory: " + root); 187 } 188 System.out.println("dump: " + dumpFile); 189 try (OutputStream os = Files.newOutputStream(dumpFile); 190 BufferedOutputStream bos = new BufferedOutputStream(os)) { 191 bos.write(classFile); 192 } catch (IOException ex) { 193 throw new InternalError(ex); 194 } 195 return null; 196 } 197 }); 198 199 } 200 } 201 202 private final native Class<?> getDerivedValueType(Class<?> ofClass); 203 204 public static Class<?> getValueClass() { 205 return VALUE_TYPE_ENABLED ? ValueClassHolder.CLASS_OBJECT : null; 206 } 207 208 public static String mangleValueClassName(String name) { 209 return ";Q" + name + ";"; 210 } 211 212 /* 213 * A holder class that references __Value to be loaded only when MVT is enabled. 214 * 215 * This holder class would fail verification if loaded if MVT is not enabled. 216 */ 217 private static class ValueClassHolder { 218 static final Class<?> CLASS_OBJECT = 219 (Class<?>)(Object)__Value.class; //hack around static type-system checks 220 } 221 } | 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 jdk.internal.misc.VM; 30 import sun.security.action.GetPropertyAction; 31 32 import java.lang.annotation.Annotation; 33 import java.io.BufferedOutputStream; 34 import java.io.File; 35 import java.io.IOException; 36 import java.io.OutputStream; 37 import java.nio.file.Files; 38 import java.nio.file.Path; 39 import java.nio.file.Paths; 40 import java.security.ProtectionDomain; 41 import java.util.Properties; 42 import java.util.concurrent.ConcurrentHashMap; 43 44 import static jdk.internal.org.objectweb.asm.Opcodes.*; 45 46 import jdk.internal.misc.JavaLangAccess; 47 import jdk.internal.misc.SharedSecrets; 48 public class MinimalValueTypes_1_0 { 49 50 public static final int V53_1 = 1 << 16 | 53; 51 public static final int ACC_VALUE = ACC_NATIVE; 52 public static final String OBJECT_CLASS_DESC = "java/lang/Object"; 53 public static final String VALUE_CLASS_DESC = "java/lang/__Value"; 54 55 public static final String DERIVE_VALUE_TYPE_DESC = "Ljdk/incubator/mvt/ValueCapableClass;"; 56 public static final String DERIVE_VT_CLASSNAME_POSTFIX = "$Value"; 57 public static final int DERIVE_VT_CLASS_ACCESS = ACC_PUBLIC|ACC_SUPER|ACC_FINAL|ACC_VALUE|ACC_SYNTHETIC; 58 59 public static final boolean DUMP_CLASS_FILES; 60 private static final boolean VALUE_TYPE_ENABLED; 61 private static final JavaLangAccess JLA; 62 63 static { 64 // Use same property as in j.l.invoke.MethodHandleStatics 65 Properties props = GetPropertyAction.privilegedGetProperties(); 66 DUMP_CLASS_FILES = Boolean.parseBoolean( 67 props.getProperty("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES")); 68 69 VALUE_TYPE_ENABLED = Boolean.parseBoolean( 70 props.getProperty("valhalla.enableValueType")); 71 72 JLA = SharedSecrets.getJavaLangAccess(); 73 } 74 75 private static final ConcurrentHashMap<Class<?>, ValueTypeHolder<?>> BOX_TO_VT 76 = new ConcurrentHashMap<>(); 77 78 /** 79 * Returns the {@code ValueTypeHolder} representing the value type 80 * for the given value capable type. 81 * 82 * @throws UnsupportedOperationException if MVT is not enabled 83 * @throws IllegalArgumentException if the given class is not value capable class 84 */ 85 @SuppressWarnings("unchecked") 86 public static <T> ValueTypeHolder<T> getValueFor(Class<T> vcc) { 87 if (!MinimalValueTypes_1_0.isValueTypeEnabled()) { 88 throw new UnsupportedOperationException("MVT is not enabled"); 89 } 90 91 if (!MinimalValueTypes_1_0.isValueCapable(vcc)) { 92 throw new IllegalArgumentException("Class " + vcc + " not a value capable class"); 93 } 94 95 ValueTypeHolder<T> vt = (ValueTypeHolder<T>) BOX_TO_VT.get(vcc); 96 if (vt != null) { 97 return vt; 98 } 99 100 Class<T> valueClass = (Class<T>) MinimalValueTypes_1_0.getValueTypeClass(vcc); 101 vt = new ValueTypeHolder<T>(vcc, valueClass); 102 ValueTypeHolder<T> old = (ValueTypeHolder<T>) BOX_TO_VT.putIfAbsent(vcc, vt); 103 if (old != null) { 104 vt = old; 105 } 106 return vt; 107 } 108 109 /** 110 * Returns the {@code ValueTypeHolder} representing the value type 111 * for the given class is a derived value type; otherwise {@code null}. 112 */ 113 @SuppressWarnings("unchecked") 114 public static <T> ValueTypeHolder<T> findValueType(Class<T> c) { 115 if (MinimalValueTypes_1_0.isValueType(c)) { 116 return (ValueTypeHolder<T>) getValueFor(MinimalValueTypes_1_0.getValueCapableClass(c)); 117 } else { 118 return null; 119 } 120 } 121 122 /** 123 * Returns true if MVT is enabled. 124 * 125 * jdk.incubator.mvt must be resolved in the boot layer. 126 */ 127 public static boolean isValueTypeEnabled() { 128 return VALUE_TYPE_ENABLED; 129 } 130 131 public static boolean isValueType(Class<?> dvt) { 132 return (dvt.getModifiers() & ACC_VALUE) != 0; 133 } 134 135 /** 136 * Returns true if the given class is a value-capable class, i.e. 137 * annotated with @ValueCapableClass. 138 */ 139 public static boolean isValueCapable(Class<?> vcc) { 140 if (!isValueTypeEnabled()) { 141 return false; 142 } 143 144 return ValueClassHelper.hasValueCapableAnnotation(vcc); 145 } 146 147 public static Class<?> getValueCapableClass(Class<?> dvt) { 148 if (!isValueType(dvt)) { 149 throw new IllegalArgumentException(dvt + " is not a derived value type"); 150 } 151 152 Class<?> c = Class.forName(dvt.getModule(), getValueCapableClassName(dvt.getName())); 153 if (c == null || !isValueCapable(c)) { 154 throw new InternalError(dvt + " not bound to ValueType"); 155 } 156 return c; 157 } 158 159 public static Class<?> getValueTypeClass(Class<?> vcc) { 160 if (!isValueCapable(vcc)) { 161 throw new IllegalArgumentException(vcc + " is not a value capable class"); 162 } 163 return loadValueTypeClass(vcc, getValueTypeClassName(vcc.getName())); 164 } 235 if (!root.exists() && !root.mkdirs()) { 236 throw new IllegalStateException("Could not create dump file directory: " + root); 237 } 238 System.out.println("dump: " + dumpFile); 239 try (OutputStream os = Files.newOutputStream(dumpFile); 240 BufferedOutputStream bos = new BufferedOutputStream(os)) { 241 bos.write(classFile); 242 } catch (IOException ex) { 243 throw new InternalError(ex); 244 } 245 return null; 246 } 247 }); 248 249 } 250 } 251 252 private final native Class<?> getDerivedValueType(Class<?> ofClass); 253 254 public static Class<?> getValueClass() { 255 return isValueTypeEnabled() ? ValueClassHelper.VALUE_CLASS : null; 256 } 257 258 public static String getValueTypeClassName(ValueTypeDesc valueTypeDesc) { 259 return getValueTypeClassName(valueTypeDesc.getName()); 260 } 261 262 public static String getValueTypeClassName(String vccName) { 263 return vccName + DERIVE_VT_CLASSNAME_POSTFIX; 264 } 265 266 public static String getValueCapableClassName(String valName) { 267 return valName.substring(0, valName.length() - DERIVE_VT_CLASSNAME_POSTFIX.length()); 268 } 269 270 public static String mangleValueClassName(String name) { 271 return ";Q" + name + ";"; 272 } 273 274 /* 275 * This helper class should only be loaded when MVT is enabled. 276 * Otherwise, it will load __Value but if MVT is not enabled and 277 * that would fail verification. 278 */ 279 private static class ValueClassHelper { 280 static final Class<?> VALUE_CLASS = 281 (Class<?>)(Object)__Value.class; //hack around static type-system checks 282 283 static volatile Class<? extends Annotation> annotationClass; 284 static volatile Class<?> valueTypeClass; 285 286 static boolean hasValueCapableAnnotation(Class<?> c) { 287 if (!VM.isModuleSystemInited()) { 288 return false; 289 } 290 Class<? extends Annotation> annClass = annotationClass; 291 if (annClass == null) { 292 annotationClass = annClass = loadValueCapableAnnotation(); 293 } 294 return annClass != null && 295 c.getDeclaredAnnotation(annClass) != null; 296 } 297 298 static Class<? extends Annotation> loadValueCapableAnnotation() { 299 try { 300 @SuppressWarnings("unchecked") 301 Class<? extends Annotation> c = (Class<? extends Annotation>) 302 Class.forName("jdk.incubator.mvt.ValueCapableClass", false, 303 ClassLoader.getPlatformClassLoader()); 304 return c; 305 306 } catch (ClassNotFoundException e) { 307 return null; 308 } 309 } 310 311 static Class<?> incubatorValueTypeClass() { 312 Class<?> c = valueTypeClass; 313 if (c == null) { 314 try { 315 valueTypeClass = c = 316 Class.forName("jdk.incubator.mvt.ValueType", false, 317 ClassLoader.getPlatformClassLoader()); 318 } catch (ClassNotFoundException e) { 319 } 320 } 321 return valueTypeClass; 322 } 323 } 324 325 static Class<?> getIncubatorValueTypeClass() { 326 if (!isValueTypeEnabled()) { 327 throw new UnsupportedOperationException("MVT is not enabled"); 328 } 329 return ValueClassHelper.incubatorValueTypeClass(); 330 } 331 } |