1 /*
   2  * Copyright (c) 2011, 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 /**
  26  * @test
  27  * @bug 6998541
  28  * @summary JSR 292 implement missing return-type conversion for OP_RETYPE_RAW
  29  *
  30  * @run main/othervm -Xbatch
  31  *    -XX:+UnlockDiagnosticVMOptions -XX:ScavengeRootsInCode=2
  32  *       -DTest6998541.N=100000 -DTest6998541.KIND=cast Test6998541
  33  * @run main/othervm -Xbatch
  34  *    -XX:+UnlockDiagnosticVMOptions -XX:ScavengeRootsInCode=2
  35  *       -DTest6998541.N=100000 -DTest6998541.KIND=normal Test6998541
  36  */
  37 
  38 import java.util.*;
  39 
  40 import java.lang.invoke.*;
  41 import static java.lang.invoke.MethodHandles.*;
  42 
  43 public class Test6998541 {
  44     private static final Class  CLASS = Test6998541.class;
  45     private static final String NAME  = "identity";
  46     private static final int    N     = Math.max(2, Integer.getInteger(CLASS.getSimpleName()+".N", 10000));
  47     private static final String KIND  = System.getProperty(CLASS.getSimpleName()+".KIND", "cast");
  48     private static final int    BITS  = 0x00000201;
  49 
  50     private static final boolean DO_CASTS = !KIND.equals("normal");
  51 
  52     public static void main(String[] args) throws Throwable {
  53         System.out.println("KIND="+KIND+" DO_CASTS="+DO_CASTS+" N="+N);
  54         doboolean();
  55         dobyte();
  56         dochar();
  57         doshort();
  58         doint();
  59         dolong();
  60         dofloat();
  61         dodouble();
  62         dovoid();
  63     }
  64 
  65     private static void doboolean() throws Throwable {
  66         for (int i = 0; i < N; i++) {
  67             boolean2prim(false);
  68             boolean2prim(true);
  69         }
  70         boolean2prim_invalid(true);
  71     }
  72     private static void dobyte() throws Throwable {
  73         byte x = Byte.MIN_VALUE;
  74         for (int i = 0; i < N; i++, x++)
  75             byte2prim(x);
  76         byte2prim_invalid(x);
  77     }
  78     private static void dochar() throws Throwable {
  79         char x = Character.MIN_VALUE;
  80         for (int i = 0; i < N; i++, x++)
  81             char2prim(x);
  82         char2prim_invalid(x);
  83     }
  84     private static void doshort() throws Throwable {
  85         short x = Short.MIN_VALUE;
  86         for (int i = 0; i < N; i++, x++)
  87             short2prim(x);
  88         short2prim_invalid(x);
  89     }
  90     private static void doint() throws Throwable {
  91         int x = Integer.MIN_VALUE;
  92         int D = Integer.MAX_VALUE / (N / 2) | BITS;
  93         for (int i = 0; i < N; i++, x += D) {
  94             int2prim(x);
  95         }
  96         int2prim_invalid(x);
  97     }
  98     private static void dolong() throws Throwable {
  99         long x = Long.MIN_VALUE;
 100         long D = Long.MAX_VALUE / ((long) (N / 2)) | BITS;
 101         for (int i = 0; i < N; i++, x += D)
 102             long2prim(x);
 103         long2prim_invalid(x);
 104     }
 105     private static void dofloat() throws Throwable {
 106         float x = Float.MIN_VALUE;
 107         float D = Float.MAX_VALUE / ((float) (N / 2));
 108         for (int i = 0; i < N; i++, x += D)
 109             float2prim(x);
 110         float2prim_invalid(x);
 111     }
 112     private static void dodouble() throws Throwable {
 113         double x = Double.MIN_VALUE;
 114         double D = Double.MAX_VALUE / ((double) (N / 2));
 115         for (int i = 0; i < N; i++, x += D)
 116             double2prim(x);
 117         double2prim_invalid(x);
 118     }
 119     private static void dovoid() throws Throwable {
 120         for (int i = 0; i < N; i++) {
 121             void2prim(i);
 122         }
 123         void2prim_invalid(0);
 124         // do the other direction here also:
 125         for (int i = 0; i < N; i++) {
 126             prim2void(i);
 127         }
 128         prim2void_invalid(0);
 129     }
 130 
 131     private static void assertEquals(Object o, Object o2) {
 132         if (!o.equals(o2))
 133             throw new AssertionError("expected: " + o + ", found: " + o2);
 134     }
 135     private static void fail() {
 136         throw new AssertionError();
 137     }
 138 
 139     private final static MethodHandles.Lookup lookup = MethodHandles.lookup();
 140 
 141     private static MethodHandle mh(Class ret, Class... args) {
 142         try {
 143             MethodType mt  = MethodType.methodType(ret, args);
 144             Class lookupRet = (args.length == 0 ? void.class : args[0]);
 145             MethodHandle mh = lookup.findStatic(CLASS, NAME, mt.changeReturnType(lookupRet));
 146             if (DO_CASTS)
 147                 return MethodHandles.explicitCastArguments(mh, mt);
 148             if (canDoAsType(mh.type(), mt))
 149                 return mh.asType(mt);
 150             try {
 151                 mh.asType(mt);
 152                 throw new AssertionError("asType should not succeed: "+mh+" => "+mt);
 153             } catch (WrongMethodTypeException ex) {
 154                 // this was a required WMTE
 155                 return mh.asType(mt.generic()).asType(mt);
 156             }
 157         } catch (ReflectiveOperationException e) {
 158             throw new RuntimeException(e);
 159         }
 160     }
 161     private static final Class<?>[] NUMERIC_TYPE_WIDENING_ORDER = {
 162         byte.class, short.class, int.class, long.class, float.class, double.class
 163     };
 164     private static boolean canDoAsType(Class<?> src, Class<?> dst) {
 165         if (src == dst)  return true;
 166         if (dst == void.class)  return true;
 167         if (src == void.class)  return true;  // allow void->zero
 168         if (!src.isPrimitive() || !dst.isPrimitive())  return true;
 169         // primitive conversion works for asType only when it's widening
 170         if (src == boolean.class || dst == boolean.class)  return false;
 171         if (dst == char.class)  return false;
 172         if (src == char.class)  src = int.class;  // can widen char to int
 173         for (Class<?> ntype : NUMERIC_TYPE_WIDENING_ORDER) {
 174             if (src == ntype)  return true;
 175             if (dst == ntype)  return false;
 176         }
 177         throw new AssertionError("should not reach here: "+src+", "+dst);
 178     }
 179     private static boolean canDoAsType(MethodType mt0, MethodType mt1) {
 180         Class<?> rt0 = mt0.returnType();
 181         Class<?> rt1 = mt1.returnType();
 182         if (!canDoAsType(rt0, rt1))  return false;
 183         int argc = mt0.parameterCount();
 184         if (argc != mt1.parameterCount())  return false;
 185         for (int i = 0; i < argc; i++) {
 186             if (!canDoAsType(mt1.parameterType(i), mt0.parameterType(i)))
 187                 return false;
 188         }
 189         return true;
 190     }
 191 
 192     private static MethodHandle mh_z(Class ret) { return mh(ret, boolean.class); }
 193 
 194     private final static MethodHandle mh_zz = mh_z(boolean.class);
 195     private final static MethodHandle mh_bz = mh_z(byte.class   );
 196     private final static MethodHandle mh_cz = mh_z(char.class   );
 197     private final static MethodHandle mh_sz = mh_z(short.class  );
 198     private final static MethodHandle mh_iz = mh_z(int.class    );
 199     private final static MethodHandle mh_jz = mh_z(long.class   );
 200     private final static MethodHandle mh_fz = mh_z(float.class  );
 201     private final static MethodHandle mh_dz = mh_z(double.class );
 202 
 203     private static void boolean2prim(boolean x) throws Throwable {
 204         int i = x ? 1 : 0;
 205         assertEquals(          x, (boolean) mh_zz.invokeExact(x));  // boolean -> boolean
 206         if (!DO_CASTS)  return;
 207         assertEquals((byte)    i, (byte)    mh_bz.invokeExact(x));  // boolean -> byte
 208         assertEquals((char)    i, (char)    mh_cz.invokeExact(x));  // boolean -> char
 209         assertEquals((short)   i, (short)   mh_sz.invokeExact(x));  // boolean -> short
 210         assertEquals((int)     i, (int)     mh_iz.invokeExact(x));  // boolean -> int
 211         assertEquals((long)    i, (long)    mh_jz.invokeExact(x));  // boolean -> long
 212         assertEquals((float)   i, (float)   mh_fz.invokeExact(x));  // boolean -> float
 213         assertEquals((double)  i, (double)  mh_dz.invokeExact(x));  // boolean -> double
 214     }
 215     private static void boolean2prim_invalid(boolean x) throws Throwable {
 216         if (DO_CASTS)  return;
 217         try { byte    y = (byte)    mh_bz.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // boolean -> byte
 218         try { char    y = (char)    mh_cz.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // boolean -> char
 219         try { short   y = (short)   mh_sz.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // boolean -> short
 220         try { int     y = (int)     mh_iz.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // boolean -> int
 221         try { long    y = (long)    mh_jz.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // boolean -> long
 222         try { float   y = (float)   mh_fz.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // boolean -> float
 223         try { double  y = (double)  mh_dz.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // boolean -> double
 224     }
 225 
 226     private static MethodHandle mh_b(Class ret) { return mh(ret, byte.class); }
 227 
 228     private final static MethodHandle mh_zb = mh_b(boolean.class);
 229     private final static MethodHandle mh_bb = mh_b(byte.class   );
 230     private final static MethodHandle mh_cb = mh_b(char.class   );
 231     private final static MethodHandle mh_sb = mh_b(short.class  );
 232     private final static MethodHandle mh_ib = mh_b(int.class    );
 233     private final static MethodHandle mh_jb = mh_b(long.class   );
 234     private final static MethodHandle mh_fb = mh_b(float.class  );
 235     private final static MethodHandle mh_db = mh_b(double.class );
 236 
 237     private static void byte2prim(byte x) throws Throwable {
 238         assertEquals((byte)    x, (byte)    mh_bb.invokeExact(x));  // byte -> byte
 239         assertEquals((short)   x, (short)   mh_sb.invokeExact(x));  // byte -> short
 240         assertEquals((int)     x, (int)     mh_ib.invokeExact(x));  // byte -> int
 241         assertEquals((long)    x, (long)    mh_jb.invokeExact(x));  // byte -> long
 242         assertEquals((float)   x, (float)   mh_fb.invokeExact(x));  // byte -> float
 243         assertEquals((double)  x, (double)  mh_db.invokeExact(x));  // byte -> double
 244         if (!DO_CASTS)  return;
 245         boolean z = ((x & 1) != 0);
 246         assertEquals((char)    x, (char)    mh_cb.invokeExact(x));  // byte -> char
 247         assertEquals((boolean) z, (boolean) mh_zb.invokeExact(x));  // byte -> boolean
 248     }
 249     private static void byte2prim_invalid(byte x) throws Throwable {
 250         if (DO_CASTS)  return;
 251         try { char    y = (char)    mh_cb.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // byte -> char
 252         try { boolean y = (boolean) mh_zb.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // byte -> boolean
 253     }
 254 
 255     private static MethodHandle mh_c(Class ret) { return mh(ret, char.class); }
 256 
 257     private final static MethodHandle mh_zc = mh_c(boolean.class);
 258     private final static MethodHandle mh_bc = mh_c(byte.class   );
 259     private final static MethodHandle mh_cc = mh_c(char.class   );
 260     private final static MethodHandle mh_sc = mh_c(short.class  );
 261     private final static MethodHandle mh_ic = mh_c(int.class    );
 262     private final static MethodHandle mh_jc = mh_c(long.class   );
 263     private final static MethodHandle mh_fc = mh_c(float.class  );
 264     private final static MethodHandle mh_dc = mh_c(double.class );
 265 
 266     private static void char2prim(char x) throws Throwable {
 267         assertEquals((char)    x, (char)    mh_cc.invokeExact(x));  // char -> char
 268         assertEquals((int)     x, (int)     mh_ic.invokeExact(x));  // char -> int
 269         assertEquals((long)    x, (long)    mh_jc.invokeExact(x));  // char -> long
 270         assertEquals((float)   x, (float)   mh_fc.invokeExact(x));  // char -> float
 271         assertEquals((double)  x, (double)  mh_dc.invokeExact(x));  // char -> double
 272         if (!DO_CASTS)  return;
 273         boolean z = ((x & 1) != 0);
 274         assertEquals((boolean) z, (boolean) mh_zc.invokeExact(x));  // char -> boolean
 275         assertEquals((byte)    x, (byte)    mh_bc.invokeExact(x));  // char -> byte
 276         assertEquals((short)   x, (short)   mh_sc.invokeExact(x));  // char -> short
 277     }
 278     private static void char2prim_invalid(char x) throws Throwable {
 279         if (DO_CASTS)  return;
 280         try { boolean y = (boolean) mh_zc.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // char -> boolean
 281         try { byte    y = (byte)    mh_bc.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // char -> byte
 282         try { short   y = (short)   mh_sc.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // char -> short
 283     }
 284 
 285     private static MethodHandle mh_s(Class ret) { return mh(ret, short.class); }
 286 
 287     private final static MethodHandle mh_zs = mh_s(boolean.class);
 288     private final static MethodHandle mh_bs = mh_s(byte.class   );
 289     private final static MethodHandle mh_cs = mh_s(char.class   );
 290     private final static MethodHandle mh_ss = mh_s(short.class  );
 291     private final static MethodHandle mh_is = mh_s(int.class    );
 292     private final static MethodHandle mh_js = mh_s(long.class   );
 293     private final static MethodHandle mh_fs = mh_s(float.class  );
 294     private final static MethodHandle mh_ds = mh_s(double.class );
 295 
 296     private static void short2prim(short x) throws Throwable {
 297         assertEquals((short)   x, (short)   mh_ss.invokeExact(x));  // short -> short
 298         assertEquals((int)     x, (int)     mh_is.invokeExact(x));  // short -> int
 299         assertEquals((long)    x, (long)    mh_js.invokeExact(x));  // short -> long
 300         assertEquals((float)   x, (float)   mh_fs.invokeExact(x));  // short -> float
 301         assertEquals((double)  x, (double)  mh_ds.invokeExact(x));  // short -> double
 302         if (!DO_CASTS)  return;
 303         boolean z = ((x & 1) != 0);
 304         assertEquals((boolean) z, (boolean) mh_zs.invokeExact(x));  // short -> boolean
 305         assertEquals((byte)    x, (byte)    mh_bs.invokeExact(x));  // short -> byte
 306         assertEquals((char)    x, (char)    mh_cs.invokeExact(x));  // short -> char
 307     }
 308     private static void short2prim_invalid(short x) throws Throwable {
 309         if (DO_CASTS)  return;
 310         try { boolean y = (boolean) mh_zs.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // short -> boolean
 311         try { byte    y = (byte)    mh_bs.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // short -> byte
 312         try { char    y = (char)    mh_cs.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // short -> char
 313     }
 314 
 315     private static MethodHandle mh_i(Class ret) { return mh(ret, int.class); }
 316 
 317     private final static MethodHandle mh_zi = mh_i(boolean.class);
 318     private final static MethodHandle mh_bi = mh_i(byte.class   );
 319     private final static MethodHandle mh_ci = mh_i(char.class   );
 320     private final static MethodHandle mh_si = mh_i(short.class  );
 321     private final static MethodHandle mh_ii = mh_i(int.class    );
 322     private final static MethodHandle mh_ji = mh_i(long.class   );
 323     private final static MethodHandle mh_fi = mh_i(float.class  );
 324     private final static MethodHandle mh_di = mh_i(double.class );
 325 
 326     private static void int2prim(int x) throws Throwable {
 327         assertEquals((int)     x, (int)     mh_ii.invokeExact(x));  // int -> int
 328         assertEquals((long)    x, (long)    mh_ji.invokeExact(x));  // int -> long
 329         assertEquals((float)   x, (float)   mh_fi.invokeExact(x));  // int -> float
 330         assertEquals((double)  x, (double)  mh_di.invokeExact(x));  // int -> double
 331         if (!DO_CASTS)  return;
 332         boolean z = ((x & 1) != 0);
 333         assertEquals((boolean) z, (boolean) mh_zi.invokeExact(x));  // int -> boolean
 334         assertEquals((byte)    x, (byte)    mh_bi.invokeExact(x));  // int -> byte
 335         assertEquals((char)    x, (char)    mh_ci.invokeExact(x));  // int -> char
 336         assertEquals((short)   x, (short)   mh_si.invokeExact(x));  // int -> short
 337     }
 338     private static void int2prim_invalid(int x) throws Throwable {
 339         if (DO_CASTS)  return;
 340         try { boolean y = (boolean) mh_zi.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // int -> boolean
 341         try { byte    y = (byte)    mh_bi.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // int -> byte
 342         try { char    y = (char)    mh_ci.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // int -> char
 343         try { short   y = (short)   mh_si.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // int -> short
 344     }
 345 
 346     private static MethodHandle mh_j(Class ret) { return mh(ret, long.class); }
 347 
 348     private final static MethodHandle mh_zj = mh_j(boolean.class);
 349     private final static MethodHandle mh_bj = mh_j(byte.class   );
 350     private final static MethodHandle mh_cj = mh_j(char.class   );
 351     private final static MethodHandle mh_sj = mh_j(short.class  );
 352     private final static MethodHandle mh_ij = mh_j(int.class    );
 353     private final static MethodHandle mh_jj = mh_j(long.class   );
 354     private final static MethodHandle mh_fj = mh_j(float.class  );
 355     private final static MethodHandle mh_dj = mh_j(double.class );
 356 
 357     private static void long2prim(long x) throws Throwable {
 358         assertEquals((long)   x, (long)    mh_jj.invokeExact(x));  // long -> long
 359         assertEquals((float)  x, (float)   mh_fj.invokeExact(x));  // long -> float
 360         assertEquals((double) x, (double)  mh_dj.invokeExact(x));  // long -> double
 361         if (!DO_CASTS)  return;
 362         boolean z = ((x & 1) != 0);
 363         assertEquals((boolean)z, (boolean) mh_zj.invokeExact(x));  // long -> boolean
 364         assertEquals((byte)   x, (byte)    mh_bj.invokeExact(x));  // long -> byte
 365         assertEquals((char)   x, (char)    mh_cj.invokeExact(x));  // long -> char
 366         assertEquals((short)  x, (short)   mh_sj.invokeExact(x));  // long -> short
 367         assertEquals((int)    x, (int)     mh_ij.invokeExact(x));  // long -> int
 368     }
 369     private static void long2prim_invalid(long x) throws Throwable {
 370         if (DO_CASTS)  return;
 371         try { boolean y = (boolean) mh_zj.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // long -> boolean
 372         try { byte    y = (byte)    mh_bj.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // long -> byte
 373         try { char    y = (char)    mh_cj.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // long -> char
 374         try { short   y = (short)   mh_sj.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // long -> short
 375         try { int     y = (int)     mh_ij.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // long -> int
 376     }
 377 
 378     private static MethodHandle mh_f(Class ret) { return mh(ret, float.class); }
 379 
 380     private final static MethodHandle mh_zf = mh_f(boolean.class);
 381     private final static MethodHandle mh_bf = mh_f(byte.class   );
 382     private final static MethodHandle mh_cf = mh_f(char.class   );
 383     private final static MethodHandle mh_sf = mh_f(short.class  );
 384     private final static MethodHandle mh_if = mh_f(int.class    );
 385     private final static MethodHandle mh_jf = mh_f(long.class   );
 386     private final static MethodHandle mh_ff = mh_f(float.class  );
 387     private final static MethodHandle mh_df = mh_f(double.class );
 388 
 389     private static void float2prim(float x) throws Throwable {
 390         assertEquals((float)   x, (float)   mh_ff.invokeExact(x));  // float -> float
 391         assertEquals((double)  x, (double)  mh_df.invokeExact(x));  // float -> double
 392         if (!DO_CASTS)  return;
 393         boolean z = (((byte) x & 1) != 0);
 394         assertEquals((boolean) z, (boolean) mh_zf.invokeExact(x));  // float -> boolean
 395         assertEquals((byte)    x, (byte)    mh_bf.invokeExact(x));  // float -> byte
 396         assertEquals((char)    x, (char)    mh_cf.invokeExact(x));  // float -> char
 397         assertEquals((short)   x, (short)   mh_sf.invokeExact(x));  // float -> short
 398         assertEquals((int)     x, (int)     mh_if.invokeExact(x));  // float -> int
 399         assertEquals((long)    x, (long)    mh_jf.invokeExact(x));  // float -> long
 400     }
 401     private static void float2prim_invalid(float x) throws Throwable {
 402         if (DO_CASTS)  return;
 403         try { boolean y = (boolean) mh_zf.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // float -> boolean
 404         try { byte    y = (byte)    mh_bf.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // float -> byte
 405         try { char    y = (char)    mh_cf.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // float -> char
 406         try { short   y = (short)   mh_sf.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // float -> short
 407         try { int     y = (int)     mh_if.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // float -> int
 408         try { long    y = (long)    mh_jf.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // float -> long
 409     }
 410 
 411     private static MethodHandle mh_d(Class ret) { return mh(ret, double.class); }
 412 
 413     private final static MethodHandle mh_zd = mh_d(boolean.class);
 414     private final static MethodHandle mh_bd = mh_d(byte.class   );
 415     private final static MethodHandle mh_cd = mh_d(char.class   );
 416     private final static MethodHandle mh_sd = mh_d(short.class  );
 417     private final static MethodHandle mh_id = mh_d(int.class    );
 418     private final static MethodHandle mh_jd = mh_d(long.class   );
 419     private final static MethodHandle mh_fd = mh_d(float.class  );
 420     private final static MethodHandle mh_dd = mh_d(double.class );
 421 
 422     private static void double2prim(double x) throws Throwable {
 423         assertEquals((double) x, (double)  mh_dd.invokeExact(x));  // double -> double
 424         if (!DO_CASTS)  return;
 425         boolean z = (((byte) x & 1) != 0);
 426         assertEquals((boolean) z, (boolean) mh_zd.invokeExact(x));  // double -> boolean
 427         assertEquals((byte)    x, (byte)    mh_bd.invokeExact(x));  // double -> byte
 428         assertEquals((char)    x, (char)    mh_cd.invokeExact(x));  // double -> char
 429         assertEquals((short)   x, (short)   mh_sd.invokeExact(x));  // double -> short
 430         assertEquals((int)     x, (int)     mh_id.invokeExact(x));  // double -> int
 431         assertEquals((long)    x, (long)    mh_jd.invokeExact(x));  // double -> long
 432         assertEquals((float)   x, (float)   mh_fd.invokeExact(x));  // double -> float
 433     }
 434     private static void double2prim_invalid(double x) throws Throwable {
 435         if (DO_CASTS)  return;
 436         try { boolean y = (boolean) mh_zd.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // double -> boolean
 437         try { byte    y = (byte)    mh_bd.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // double -> byte
 438         try { char    y = (char)    mh_cd.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // double -> char
 439         try { short   y = (short)   mh_sd.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // double -> short
 440         try { int     y = (int)     mh_id.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // double -> int
 441         try { long    y = (long)    mh_jd.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // double -> long
 442         try { float   y = (float)   mh_fd.invokeExact(x); fail(); } catch (ClassCastException expected) {}  // double -> float
 443     }
 444 
 445     private final static MethodHandle mh_zv = mh(boolean.class);
 446     private final static MethodHandle mh_bv = mh(byte.class   );
 447     private final static MethodHandle mh_cv = mh(char.class   );
 448     private final static MethodHandle mh_sv = mh(short.class  );
 449     private final static MethodHandle mh_iv = mh(int.class    );
 450     private final static MethodHandle mh_jv = mh(long.class   );
 451     private final static MethodHandle mh_fv = mh(float.class  );
 452     private final static MethodHandle mh_dv = mh(double.class );
 453 
 454     private static void void2prim(int i) throws Throwable {
 455         assertEquals(        false, (boolean) mh_zv.invokeExact());  // void -> boolean
 456         assertEquals((byte)  0,     (byte)    mh_bv.invokeExact());  // void -> byte
 457         assertEquals((char)  0,     (char)    mh_cv.invokeExact());  // void -> char
 458         assertEquals((short) 0,     (short)   mh_sv.invokeExact());  // void -> short
 459         assertEquals(        0,     (int)     mh_iv.invokeExact());  // void -> int
 460         assertEquals(        0L,    (long)    mh_jv.invokeExact());  // void -> long
 461         assertEquals(        0.0f,  (float)   mh_fv.invokeExact());  // void -> float
 462         assertEquals(        0.0d,  (double)  mh_dv.invokeExact());  // void -> double
 463     }
 464 
 465     private static void void2prim_invalid(double x) throws Throwable {
 466         // no cases
 467     }
 468 
 469     private static MethodHandle mh_v(Class arg) { return mh(void.class, arg); }
 470 
 471     private final static MethodHandle mh_vz = mh_v(boolean.class);
 472     private final static MethodHandle mh_vb = mh_v(byte.class   );
 473     private final static MethodHandle mh_vc = mh_v(char.class   );
 474     private final static MethodHandle mh_vs = mh_v(short.class  );
 475     private final static MethodHandle mh_vi = mh_v(int.class    );
 476     private final static MethodHandle mh_vj = mh_v(long.class   );
 477     private final static MethodHandle mh_vf = mh_v(float.class  );
 478     private final static MethodHandle mh_vd = mh_v(double.class );
 479 
 480     private static void prim2void(int x) throws Throwable {
 481         boolean z = ((x & 1) != 0);
 482         mh_vz.invokeExact(         z);  // boolean -> void
 483         mh_vb.invokeExact((byte)   x);  // byte    -> void
 484         mh_vc.invokeExact((char)   x);  // char    -> void
 485         mh_vs.invokeExact((short)  x);  // short   -> void
 486         mh_vi.invokeExact((int)    x);  // int     -> void
 487         mh_vj.invokeExact((long)   x);  // long    -> void
 488         mh_vf.invokeExact((float)  x);  // float   -> void
 489         mh_vd.invokeExact((double) x);  // double  -> void
 490     }
 491 
 492     private static void prim2void_invalid(int x) throws Throwable {
 493         // no cases
 494     }
 495 
 496     private static boolean identity(boolean v) { return v; }
 497     private static byte    identity(byte    v) { return v; }
 498     private static char    identity(char    v) { return v; }
 499     private static short   identity(short   v) { return v; }
 500     private static int     identity(int     v) { return v; }
 501     private static long    identity(long    v) { return v; }
 502     private static float   identity(float   v) { return v; }
 503     private static double  identity(double  v) { return v; }
 504     private static void    identity() {}
 505 }