< prev index next >

jdk/src/java.base/share/classes/jdk/experimental/value/ValueType.java

Print this page
rev 14083 : vwithfield class/field access


  24  */
  25 
  26 package jdk.experimental.value;
  27 
  28 import java.lang.invoke.MethodHandle;
  29 import java.lang.invoke.MethodHandles.Lookup;
  30 import java.lang.invoke.MethodType;
  31 import java.lang.reflect.Field;
  32 import java.lang.reflect.Method;
  33 import java.lang.reflect.Modifier;
  34 import java.util.Arrays;
  35 import java.util.Map;
  36 import java.util.Objects;
  37 import java.util.Optional;
  38 import java.util.concurrent.ConcurrentHashMap;
  39 import java.util.stream.Stream;
  40 
  41 import jdk.experimental.value.ValueType.ValueHandleKind.ValueHandleKey;
  42 import jdk.experimental.bytecode.MacroCodeBuilder.CondKind;
  43 import jdk.experimental.bytecode.TypeTag;
  44 import jdk.internal.misc.Unsafe;
  45 import sun.invoke.util.BytecodeDescriptor;
  46 import sun.invoke.util.Wrapper;
  47 import valhalla.shady.MinimalValueTypes_1_0;
  48 
  49 // Rough place holder just now...
  50 public class ValueType<T> {
  51 
  52     static final Unsafe UNSAFE = Unsafe.getUnsafe();
  53 
  54     enum ValueHandleKind {
  55         BOX,
  56         UNBOX,
  57         DEFAULT,
  58         EQ,
  59         HASH,
  60         WITHER() {
  61             @Override
  62             ValueHandleKey key(Object fieldName) {
  63                return new ValueHandleKey(this, fieldName);
  64             }
  65         },
  66         MAKE,
  67         NEWARRAY,
  68         VALOAD,
  69         VASTORE,
  70         MULTINEWARRAY() {
  71             @Override
  72             ValueHandleKey key(Object dims) {
  73                return new ValueHandleKey(this, dims);


 180             String dimsStr = "[[[[[[[[[[[[[[[[";
 181             if (dims < 1 || dims > 16) {
 182                 throw new IllegalArgumentException("cannot create array class for dimension > 16");
 183             }
 184             return Class.forName(dimsStr.substring(0, dims) + "Q" + valueClass().getName() + ";", false, lookup.lookupClass().getClassLoader());
 185         } catch (ClassNotFoundException ex) {
 186             throw new IllegalStateException(ex);
 187         }
 188     }
 189 
 190     public String toString() {
 191         return "ValueType boxClass=" + boxClass() + " valueClass=" + valueClass();
 192     }
 193 
 194     public MethodHandle defaultValueConstant() {
 195         ValueHandleKey key = ValueHandleKind.DEFAULT.key();
 196         MethodHandle result = handleMap.get(key);
 197         if (result == null) {
 198             result = MethodHandleBuilder.loadCode(lookup, "default" + sourceClass().getName(), MethodType.methodType(valueClass()),
 199                     C -> {
 200                         C.new_(boxClass()).vunbox(valueClass()).vreturn();
 201                     });
 202             handleMap.put(key, result);
 203         }
 204         return result;
 205     }
 206 
 207     public MethodHandle substitutabilityTest() {
 208         ValueHandleKey key = ValueHandleKind.EQ.key();
 209         MethodHandle result = handleMap.get(key);
 210         if (result == null) {
 211             result = MethodHandleBuilder.loadCode(lookup, "subTest" + sourceClass().getName(), MethodType.methodType(boolean.class, valueClass(), valueClass()),
 212                     C -> {
 213                         for (Field f : valueFields()) {
 214                             C.vload(0).vgetfield(valueClass(), f.getName(), BytecodeDescriptor.unparse(f.getType()));
 215                             C.vload(1).vgetfield(valueClass(), f.getName(), BytecodeDescriptor.unparse(f.getType()));
 216                             if (f.getType().isPrimitive()) {
 217                                 C.ifcmp(TypeTag.I, CondKind.NE, "fail");
 218                             } else {
 219                                 C.invokestatic(Objects.class, "equals", "(Ljava/lang/Object;Ljava/lang/Object;)Z", false);
 220                                 C.const_(0).ifcmp(TypeTag.I, CondKind.NE, "fail");


 240                         C.withLocal("res", "I");
 241                         C.const_(1).store("res");
 242                         for (Field f : valueFields()) {
 243                             String desc = BytecodeDescriptor.unparse(f.getType());
 244                             C.vload(0).vgetfield(valueClass(), f.getName(), desc);
 245                             C.load("res").const_(31).imul();
 246                             if (f.getType().isPrimitive()) {
 247                                 C.invokestatic(Wrapper.asWrapperType(f.getType()), "hashCode", "(" + desc + ")I", false);
 248                             } else {
 249                                 C.invokestatic(Objects.class, "hashCode", "(Ljava/lang/Object)I", false);
 250                             }
 251                             C.iadd().store("res");
 252                         }
 253                         C.load("res").ireturn();
 254                     });
 255             handleMap.put(key, result);
 256         }
 257         return result;
 258     }
 259 
 260     //Todo: when 'vwithfield' is ready, this handle could be greatly simplified
 261     public MethodHandle findWither(String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
 262         ValueHandleKey key = ValueHandleKind.WITHER.key(name);
 263         MethodHandle result = handleMap.get(key);
 264         if (result == null) {
 265             Field field = boxClass().getDeclaredField(name);
 266             if (field == null || !field.getType().equals(type) ||
 267                     (field.getModifiers() & Modifier.STATIC) != 0) {
 268                 throw new NoSuchFieldException(name);
 269             }
 270             Class<?> erasedType = type.isPrimitive() ?
 271                     type : Object.class;
 272             Method unsafeMethod = Stream.of(UNSAFE.getClass().getDeclaredMethods())
 273                     .filter(m -> m.getName().startsWith("put") &&
 274                             Arrays.asList(m.getParameterTypes()).equals(Arrays.asList(Object.class, long.class, erasedType)))
 275                     .findFirst().get();
 276             long fieldOffset = UNSAFE.objectFieldOffset(field);
 277             result = MethodHandleBuilder.loadCode(lookup, "wither" + sourceClass().getName() + ":" + name, MethodType.methodType(valueClass(), UNSAFE.getClass(), valueClass(), type),
 278                     C -> {
 279                         C.withLocal("boxedVal", BytecodeDescriptor.unparse(boxClass()))
 280                          .load(1)
 281                          .vbox(boxClass())
 282                          .store("boxedVal")
 283                          .load(0)
 284                          .load("boxedVal")
 285                          .const_(fieldOffset)
 286                          .load(2);
 287                          MethodType unsafeMT = MethodType.methodType(unsafeMethod.getReturnType(), unsafeMethod.getParameterTypes());
 288                          C.invokevirtual(UNSAFE.getClass(), unsafeMethod.getName(), BytecodeDescriptor.unparse(unsafeMT), false)
 289                           .load("boxedVal")
 290                           .vunbox(valueClass())
 291                           .vreturn();
 292                     }).bindTo(UNSAFE);
 293             handleMap.put(key, result);
 294         }
 295         return result;
 296     }
 297 
 298     public MethodHandle unbox() {
 299         ValueHandleKey key = ValueHandleKind.UNBOX.key();
 300         MethodHandle result = handleMap.get(key);
 301         if (result == null) {
 302             result = MethodHandleBuilder.loadCode(lookup, "unbox" + sourceClass().getName(), MethodType.methodType(valueClass(), boxClass()),
 303                     C -> {
 304                         C.load(0).vunbox(valueClass()).vreturn();
 305                     });
 306             handleMap.put(key, result);
 307         }
 308         return result;
 309     }
 310 
 311     public MethodHandle box() {
 312         ValueHandleKey key = ValueHandleKind.BOX.key();




  24  */
  25 
  26 package jdk.experimental.value;
  27 
  28 import java.lang.invoke.MethodHandle;
  29 import java.lang.invoke.MethodHandles.Lookup;
  30 import java.lang.invoke.MethodType;
  31 import java.lang.reflect.Field;
  32 import java.lang.reflect.Method;
  33 import java.lang.reflect.Modifier;
  34 import java.util.Arrays;
  35 import java.util.Map;
  36 import java.util.Objects;
  37 import java.util.Optional;
  38 import java.util.concurrent.ConcurrentHashMap;
  39 import java.util.stream.Stream;
  40 
  41 import jdk.experimental.value.ValueType.ValueHandleKind.ValueHandleKey;
  42 import jdk.experimental.bytecode.MacroCodeBuilder.CondKind;
  43 import jdk.experimental.bytecode.TypeTag;

  44 import sun.invoke.util.BytecodeDescriptor;
  45 import sun.invoke.util.Wrapper;
  46 import valhalla.shady.MinimalValueTypes_1_0;
  47 
  48 // Rough place holder just now...
  49 public class ValueType<T> {
  50 


  51     enum ValueHandleKind {
  52         BOX,
  53         UNBOX,
  54         DEFAULT,
  55         EQ,
  56         HASH,
  57         WITHER() {
  58             @Override
  59             ValueHandleKey key(Object fieldName) {
  60                return new ValueHandleKey(this, fieldName);
  61             }
  62         },
  63         MAKE,
  64         NEWARRAY,
  65         VALOAD,
  66         VASTORE,
  67         MULTINEWARRAY() {
  68             @Override
  69             ValueHandleKey key(Object dims) {
  70                return new ValueHandleKey(this, dims);


 177             String dimsStr = "[[[[[[[[[[[[[[[[";
 178             if (dims < 1 || dims > 16) {
 179                 throw new IllegalArgumentException("cannot create array class for dimension > 16");
 180             }
 181             return Class.forName(dimsStr.substring(0, dims) + "Q" + valueClass().getName() + ";", false, lookup.lookupClass().getClassLoader());
 182         } catch (ClassNotFoundException ex) {
 183             throw new IllegalStateException(ex);
 184         }
 185     }
 186 
 187     public String toString() {
 188         return "ValueType boxClass=" + boxClass() + " valueClass=" + valueClass();
 189     }
 190 
 191     public MethodHandle defaultValueConstant() {
 192         ValueHandleKey key = ValueHandleKind.DEFAULT.key();
 193         MethodHandle result = handleMap.get(key);
 194         if (result == null) {
 195             result = MethodHandleBuilder.loadCode(lookup, "default" + sourceClass().getName(), MethodType.methodType(valueClass()),
 196                     C -> {
 197                         C.vdefault(valueClass()).vreturn();
 198                     });
 199             handleMap.put(key, result);
 200         }
 201         return result;
 202     }
 203 
 204     public MethodHandle substitutabilityTest() {
 205         ValueHandleKey key = ValueHandleKind.EQ.key();
 206         MethodHandle result = handleMap.get(key);
 207         if (result == null) {
 208             result = MethodHandleBuilder.loadCode(lookup, "subTest" + sourceClass().getName(), MethodType.methodType(boolean.class, valueClass(), valueClass()),
 209                     C -> {
 210                         for (Field f : valueFields()) {
 211                             C.vload(0).vgetfield(valueClass(), f.getName(), BytecodeDescriptor.unparse(f.getType()));
 212                             C.vload(1).vgetfield(valueClass(), f.getName(), BytecodeDescriptor.unparse(f.getType()));
 213                             if (f.getType().isPrimitive()) {
 214                                 C.ifcmp(TypeTag.I, CondKind.NE, "fail");
 215                             } else {
 216                                 C.invokestatic(Objects.class, "equals", "(Ljava/lang/Object;Ljava/lang/Object;)Z", false);
 217                                 C.const_(0).ifcmp(TypeTag.I, CondKind.NE, "fail");


 237                         C.withLocal("res", "I");
 238                         C.const_(1).store("res");
 239                         for (Field f : valueFields()) {
 240                             String desc = BytecodeDescriptor.unparse(f.getType());
 241                             C.vload(0).vgetfield(valueClass(), f.getName(), desc);
 242                             C.load("res").const_(31).imul();
 243                             if (f.getType().isPrimitive()) {
 244                                 C.invokestatic(Wrapper.asWrapperType(f.getType()), "hashCode", "(" + desc + ")I", false);
 245                             } else {
 246                                 C.invokestatic(Objects.class, "hashCode", "(Ljava/lang/Object)I", false);
 247                             }
 248                             C.iadd().store("res");
 249                         }
 250                         C.load("res").ireturn();
 251                     });
 252             handleMap.put(key, result);
 253         }
 254         return result;
 255     }
 256 

 257     public MethodHandle findWither(String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
 258         ValueHandleKey key = ValueHandleKind.WITHER.key(name);
 259         MethodHandle result = handleMap.get(key);
 260         if (result == null) {
 261             result = MethodHandleBuilder.loadCode(lookup, "wither" + sourceClass().getName() + ":" + name,
 262                                                   MethodType.methodType(valueClass(), valueClass(), type),
 263                                                   C -> { C.load(0).load(1).vwithfield(valueClass(), name, BytecodeDescriptor.unparse(type)).vreturn(); });

























 264             handleMap.put(key, result);
 265         }
 266         return result;
 267     }
 268 
 269     public MethodHandle unbox() {
 270         ValueHandleKey key = ValueHandleKind.UNBOX.key();
 271         MethodHandle result = handleMap.get(key);
 272         if (result == null) {
 273             result = MethodHandleBuilder.loadCode(lookup, "unbox" + sourceClass().getName(), MethodType.methodType(valueClass(), boxClass()),
 274                     C -> {
 275                         C.load(0).vunbox(valueClass()).vreturn();
 276                     });
 277             handleMap.put(key, result);
 278         }
 279         return result;
 280     }
 281 
 282     public MethodHandle box() {
 283         ValueHandleKey key = ValueHandleKind.BOX.key();


< prev index next >