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();
|