< prev index next >

src/java.base/share/classes/sun/invoke/util/Wrapper.java

Print this page
rev 13066 : 8142487: Cleanup sun.invoke.util.Wrapper zeroes to be both reliable and lazy
Reviewed-by: vlivanov, jrose


   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  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 
  26 package sun.invoke.util;
  27 
  28 public enum Wrapper {
  29     //        wrapperType    primitiveType  char            zero         emptyArray          format
  30     BOOLEAN(  Boolean.class, boolean.class, 'Z',          Boolean.FALSE, new boolean[0], Format.unsigned( 1)),
  31     // These must be in the order defined for widening primitive conversions in JLS 5.1.2
  32     // Avoid boxing integral types here to defer initialization of internal caches
  33     BYTE   (     Byte.class,    byte.class, 'B',      new Byte((byte)0), new    byte[0], Format.signed(   8)),
  34     SHORT  (    Short.class,   short.class, 'S',    new Short((short)0), new   short[0], Format.signed(  16)),
  35     CHAR   (Character.class,    char.class, 'C', new Character((char)0), new    char[0], Format.unsigned(16)),
  36     INT    (  Integer.class,     int.class, 'I',         new Integer(0), new     int[0], Format.signed(  32)),
  37     LONG   (     Long.class,    long.class, 'J',            new Long(0), new    long[0], Format.signed(  64)),
  38     FLOAT  (    Float.class,   float.class, 'F',        (Float)(float)0, new   float[0], Format.floating(32)),
  39     DOUBLE (   Double.class,  double.class, 'D',      (Double)(double)0, new  double[0], Format.floating(64)),
  40     OBJECT (   Object.class,  Object.class, 'L',                   null, new  Object[0], Format.other(    1)),
  41     // VOID must be the last type, since it is "assignable" from any other type:
  42     VOID   (     Void.class,    void.class, 'V',                   null,           null, Format.other(    0)),
  43     ;
  44 
  45     private final Class<?> wrapperType;
  46     private final Class<?> primitiveType;
  47     private final char     basicTypeChar;
  48     private final Object   zero;
  49     private final Object   emptyArray;
  50     private final int      format;
  51     private final String   wrapperSimpleName;
  52     private final String   primitiveSimpleName;
  53 
  54     private Wrapper(Class<?> wtype, Class<?> ptype, char tchar, Object zero, Object emptyArray, int format) {
  55         this.wrapperType = wtype;
  56         this.primitiveType = ptype;
  57         this.basicTypeChar = tchar;
  58         this.zero = zero;
  59         this.emptyArray = emptyArray;
  60         this.format = format;
  61         this.wrapperSimpleName = wtype.getSimpleName();
  62         this.primitiveSimpleName = ptype.getSimpleName();
  63     }
  64 
  65     /** For debugging, give the details of this wrapper. */
  66     public String detailString() {
  67         return wrapperSimpleName+
  68                 java.util.Arrays.asList(wrapperType, primitiveType,
  69                 basicTypeChar, zero,
  70                 "0x"+Integer.toHexString(format));
  71     }
  72 
  73     private abstract static class Format {
  74         static final int SLOT_SHIFT = 0, SIZE_SHIFT = 2, KIND_SHIFT = 12;
  75         static final int
  76                 SIGNED   = (-1) << KIND_SHIFT,
  77                 UNSIGNED = 0    << KIND_SHIFT,
  78                 FLOATING = 1    << KIND_SHIFT;
  79         static final int
  80                 SLOT_MASK = ((1<<(SIZE_SHIFT-SLOT_SHIFT))-1),
  81                 SIZE_MASK = ((1<<(KIND_SHIFT-SIZE_SHIFT))-1);
  82         static int format(int kind, int size, int slots) {
  83             assert(((kind >> KIND_SHIFT) << KIND_SHIFT) == kind);
  84             assert((size & (size-1)) == 0); // power of two
  85             assert((kind == SIGNED)   ? (size > 0) :
  86                    (kind == UNSIGNED) ? (size > 0) :
  87                    (kind == FLOATING) ? (size == 32 || size == 64)  :
  88                    false);
  89             assert((slots == 2) ? (size == 64) :


 206                     else if (x.isFloating()) {
 207                         if (w.compareTo(x) < 0)
 208                             assert(!w.isConvertibleFrom(x));
 209                         else
 210                             assert(w.isConvertibleFrom(x));
 211                     }
 212                 }
 213             }
 214         }
 215         return true;  // i.e., assert(true)
 216     }
 217 
 218     /** Produce a zero value for the given wrapper type.
 219      *  This will be a numeric zero for a number or character,
 220      *  false for a boolean, and null for a reference or void.
 221      *  The common thread is that this is what is contained
 222      *  in a default-initialized variable of the given primitive
 223      *  type.  (For void, it is what a reflective method returns
 224      *  instead of no value at all.)
 225      */
 226     public Object zero() { return zero; }


























 227 
 228     /** Produce a zero value for the given wrapper type T.
 229      *  The optional argument must a type compatible with this wrapper.
 230      *  Equivalent to {@code this.cast(this.zero(), type)}.
 231      */
 232     public <T> T zero(Class<T> type) { return convert(zero, type); }
 233 
 234     /** Return the wrapper that wraps values of the given type.
 235      *  The type may be {@code Object}, meaning the {@code OBJECT} wrapper.
 236      *  Otherwise, the type must be a primitive.
 237      *  @throws IllegalArgumentException for unexpected types
 238      */
 239     public static Wrapper forPrimitiveType(Class<?> type) {
 240         Wrapper w = findPrimitiveType(type);
 241         if (w != null)  return w;
 242         if (type.isPrimitive())
 243             throw new InternalError(); // redo hash function
 244         throw newIllegalArgumentException("not primitive: "+type);
 245     }
 246 
 247     static Wrapper findPrimitiveType(Class<?> type) {
 248         Wrapper w = FROM_PRIM[hashPrim(type)];
 249         if (w != null && w.primitiveType == type) {
 250             return w;
 251         }
 252         return null;


 457             // If the target type is a primitive, change it to a wrapper.
 458             assert(!type.isPrimitive());
 459             if (!type.isInterface())
 460                 type.cast(x);
 461             @SuppressWarnings("unchecked")
 462             T result = (T) x;  // unchecked warning is expected here
 463             return result;
 464         }
 465         Class<T> wtype = wrapperType(type);
 466         if (wtype.isInstance(x)) {
 467             return wtype.cast(x);
 468         }
 469         if (!isCast) {
 470             Class<?> sourceType = x.getClass();  // throw NPE if x is null
 471             Wrapper source = findWrapperType(sourceType);
 472             if (source == null || !this.isConvertibleFrom(source)) {
 473                 throw newClassCastException(wtype, sourceType);
 474             }
 475         } else if (x == null) {
 476             @SuppressWarnings("unchecked")
 477             T z = (T) zero;
 478             return z;
 479         }
 480         @SuppressWarnings("unchecked")
 481         T result = (T) wrap(x);  // unchecked warning is expected here
 482         assert (result == null ? Void.class : result.getClass()) == wtype;
 483         return result;
 484     }
 485 
 486     /** Cast a reference type to another reference type.
 487      * If the target type is an interface, perform no runtime check.
 488      * (This loophole is safe, and is allowed by the JVM verifier.)
 489      * If the target type is a primitive, change it to a wrapper.
 490      */
 491     static <T> Class<T> forceType(Class<?> type, Class<T> exampleType) {
 492         boolean z = (type == exampleType ||
 493                type.isPrimitive() && forPrimitiveType(type) == findWrapperType(exampleType) ||
 494                exampleType.isPrimitive() && forPrimitiveType(exampleType) == findWrapperType(type) ||
 495                type == Object.class && !exampleType.isPrimitive());
 496         if (!z)
 497             System.out.println(type+" <= "+exampleType);




   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  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 
  26 package sun.invoke.util;
  27 
  28 public enum Wrapper {
  29     //        wrapperType    primitiveType  char     emptyArray          format
  30     BOOLEAN(  Boolean.class, boolean.class, 'Z', new boolean[0], Format.unsigned( 1)),
  31     // These must be in the order defined for widening primitive conversions in JLS 5.1.2
  32     // Avoid boxing integral types here to defer initialization of internal caches
  33     BYTE   (     Byte.class,    byte.class, 'B', new    byte[0], Format.signed(   8)),
  34     SHORT  (    Short.class,   short.class, 'S', new   short[0], Format.signed(  16)),
  35     CHAR   (Character.class,    char.class, 'C', new    char[0], Format.unsigned(16)),
  36     INT    (  Integer.class,     int.class, 'I', new     int[0], Format.signed(  32)),
  37     LONG   (     Long.class,    long.class, 'J', new    long[0], Format.signed(  64)),
  38     FLOAT  (    Float.class,   float.class, 'F', new   float[0], Format.floating(32)),
  39     DOUBLE (   Double.class,  double.class, 'D', new  double[0], Format.floating(64)),
  40     OBJECT (   Object.class,  Object.class, 'L', new  Object[0], Format.other(    1)),
  41     // VOID must be the last type, since it is "assignable" from any other type:
  42     VOID   (     Void.class,    void.class, 'V',           null, Format.other(    0)),
  43     ;
  44 
  45     private final Class<?> wrapperType;
  46     private final Class<?> primitiveType;
  47     private final char     basicTypeChar;

  48     private final Object   emptyArray;
  49     private final int      format;
  50     private final String   wrapperSimpleName;
  51     private final String   primitiveSimpleName;
  52 
  53     private Wrapper(Class<?> wtype, Class<?> ptype, char tchar, Object emptyArray, int format) {
  54         this.wrapperType = wtype;
  55         this.primitiveType = ptype;
  56         this.basicTypeChar = tchar;

  57         this.emptyArray = emptyArray;
  58         this.format = format;
  59         this.wrapperSimpleName = wtype.getSimpleName();
  60         this.primitiveSimpleName = ptype.getSimpleName();
  61     }
  62 
  63     /** For debugging, give the details of this wrapper. */
  64     public String detailString() {
  65         return wrapperSimpleName+
  66                 java.util.Arrays.asList(wrapperType, primitiveType,
  67                 basicTypeChar, zero(),
  68                 "0x"+Integer.toHexString(format));
  69     }
  70 
  71     private abstract static class Format {
  72         static final int SLOT_SHIFT = 0, SIZE_SHIFT = 2, KIND_SHIFT = 12;
  73         static final int
  74                 SIGNED   = (-1) << KIND_SHIFT,
  75                 UNSIGNED = 0    << KIND_SHIFT,
  76                 FLOATING = 1    << KIND_SHIFT;
  77         static final int
  78                 SLOT_MASK = ((1<<(SIZE_SHIFT-SLOT_SHIFT))-1),
  79                 SIZE_MASK = ((1<<(KIND_SHIFT-SIZE_SHIFT))-1);
  80         static int format(int kind, int size, int slots) {
  81             assert(((kind >> KIND_SHIFT) << KIND_SHIFT) == kind);
  82             assert((size & (size-1)) == 0); // power of two
  83             assert((kind == SIGNED)   ? (size > 0) :
  84                    (kind == UNSIGNED) ? (size > 0) :
  85                    (kind == FLOATING) ? (size == 32 || size == 64)  :
  86                    false);
  87             assert((slots == 2) ? (size == 64) :


 204                     else if (x.isFloating()) {
 205                         if (w.compareTo(x) < 0)
 206                             assert(!w.isConvertibleFrom(x));
 207                         else
 208                             assert(w.isConvertibleFrom(x));
 209                     }
 210                 }
 211             }
 212         }
 213         return true;  // i.e., assert(true)
 214     }
 215 
 216     /** Produce a zero value for the given wrapper type.
 217      *  This will be a numeric zero for a number or character,
 218      *  false for a boolean, and null for a reference or void.
 219      *  The common thread is that this is what is contained
 220      *  in a default-initialized variable of the given primitive
 221      *  type.  (For void, it is what a reflective method returns
 222      *  instead of no value at all.)
 223      */
 224     public Object zero() {
 225         switch (this) {
 226             case BOOLEAN:
 227                 return Boolean.FALSE;
 228             case INT:
 229                 return (Integer)0;
 230             case BYTE:
 231                 return (Byte)(byte)0;
 232             case CHAR:
 233                 return (Character)(char)0;
 234             case SHORT:
 235                 return (Short)(short)0;
 236             case LONG:
 237                 return (Long)(long)0;
 238             case FLOAT:
 239                 return FLOAT_ZERO;
 240             case DOUBLE:
 241                 return DOUBLE_ZERO;
 242             case VOID:
 243             case OBJECT:
 244             default:
 245                 return null;
 246         }
 247     }
 248 
 249     private static final Object DOUBLE_ZERO = (Double)(double)0;
 250     private static final Object FLOAT_ZERO = (Float)(float)0;
 251 
 252     /** Produce a zero value for the given wrapper type T.
 253      *  The optional argument must a type compatible with this wrapper.
 254      *  Equivalent to {@code this.cast(this.zero(), type)}.
 255      */
 256     public <T> T zero(Class<T> type) { return convert(zero(), type); }
 257 
 258     /** Return the wrapper that wraps values of the given type.
 259      *  The type may be {@code Object}, meaning the {@code OBJECT} wrapper.
 260      *  Otherwise, the type must be a primitive.
 261      *  @throws IllegalArgumentException for unexpected types
 262      */
 263     public static Wrapper forPrimitiveType(Class<?> type) {
 264         Wrapper w = findPrimitiveType(type);
 265         if (w != null)  return w;
 266         if (type.isPrimitive())
 267             throw new InternalError(); // redo hash function
 268         throw newIllegalArgumentException("not primitive: "+type);
 269     }
 270 
 271     static Wrapper findPrimitiveType(Class<?> type) {
 272         Wrapper w = FROM_PRIM[hashPrim(type)];
 273         if (w != null && w.primitiveType == type) {
 274             return w;
 275         }
 276         return null;


 481             // If the target type is a primitive, change it to a wrapper.
 482             assert(!type.isPrimitive());
 483             if (!type.isInterface())
 484                 type.cast(x);
 485             @SuppressWarnings("unchecked")
 486             T result = (T) x;  // unchecked warning is expected here
 487             return result;
 488         }
 489         Class<T> wtype = wrapperType(type);
 490         if (wtype.isInstance(x)) {
 491             return wtype.cast(x);
 492         }
 493         if (!isCast) {
 494             Class<?> sourceType = x.getClass();  // throw NPE if x is null
 495             Wrapper source = findWrapperType(sourceType);
 496             if (source == null || !this.isConvertibleFrom(source)) {
 497                 throw newClassCastException(wtype, sourceType);
 498             }
 499         } else if (x == null) {
 500             @SuppressWarnings("unchecked")
 501             T z = (T) zero();
 502             return z;
 503         }
 504         @SuppressWarnings("unchecked")
 505         T result = (T) wrap(x);  // unchecked warning is expected here
 506         assert (result == null ? Void.class : result.getClass()) == wtype;
 507         return result;
 508     }
 509 
 510     /** Cast a reference type to another reference type.
 511      * If the target type is an interface, perform no runtime check.
 512      * (This loophole is safe, and is allowed by the JVM verifier.)
 513      * If the target type is a primitive, change it to a wrapper.
 514      */
 515     static <T> Class<T> forceType(Class<?> type, Class<T> exampleType) {
 516         boolean z = (type == exampleType ||
 517                type.isPrimitive() && forPrimitiveType(type) == findWrapperType(exampleType) ||
 518                exampleType.isPrimitive() && forPrimitiveType(exampleType) == findWrapperType(type) ||
 519                type == Object.class && !exampleType.isPrimitive());
 520         if (!z)
 521             System.out.println(type+" <= "+exampleType);


< prev index next >