1 /*
   2  * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package impl.java.dyn.util;
  27 
  28 import java.dyn.MethodType;
  29 
  30 /**
  31  * This class centralizes information about the JVM verifier
  32  * and its requirements about type correctness.
  33  * @author jrose
  34  */
  35 public class VerifyType {
  36 
  37     private VerifyType() { }  // cannot instantiate
  38 
  39     /**
  40      * True if a value can be stacked as the source type and unstacked as the
  41      * destination type, without violating the JVM's type consistency.
  42      *
  43      * @param call the type of a stacked value
  44      * @param recv the type by which we'd like to treat it
  45      * @return whether the retyping can be done without motion or reformatting
  46      */
  47     public static boolean isNullConversion(Class<?> src, Class<?> dst) {
  48         if (src == dst)            return true;
  49         // Verifier allows any interface to be treated as Object:
  50         if (dst.isInterface())     dst = Object.class;
  51         if (src.isInterface())     src = Object.class;
  52         if (src == dst)            return true;  // check again
  53         if (dst == void.class)     return true;  // drop any return value
  54         if (!src.isPrimitive())    return dst.isAssignableFrom(src);
  55         // Verifier allows an int to carry byte, short, char, or even boolean:
  56         if (dst == int.class)      return Wrappers.isSubwordOrInt(src);
  57         return false;
  58     }
  59 
  60     /**
  61      * True if a method handle can receive a call under a slightly different
  62      * method type, without moving or reformatting any stack elements.
  63      *
  64      * @param call the type of call being made
  65      * @param recv the type of the method handle receiving the call
  66      * @return whether the retyping can be done without motion or reformatting
  67      */
  68     public static boolean isNullConversion(MethodType call, MethodType recv) {
  69         if (call == recv)  return true;
  70         int len = call.parameterCount();
  71         if (len != recv.parameterCount())  return false;
  72         for (int i = 0; i < len; i++)
  73             if (!isNullConversion(call.parameterType(i), recv.parameterType(i)))
  74                 return false;
  75         return isNullConversion(recv.returnType(), call.returnType());
  76     }
  77 
  78     /**
  79      * Determine if the JVM verifier allows a value of type call to be
  80      * passed to a formal parameter (or return variable) of type recv.
  81      * Returns 1 if the verifier allows the types to match without conversion.
  82      * Returns -1 if the types can be made to match by a JVM-supported adapter.
  83      * Cases supported are:
  84      * <ul><li>checkcast
  85      * </li><li>conversion between any two integral types (but not floats)
  86      * </li><li>unboxing from a wrapper to its corresponding primitive type
  87      * </li><li>conversion in either direction between float and double
  88      * </li></ul>
  89      * (Autoboxing is not supported here; it must be done via Java code.)
  90      * Returns 0 otherwise.
  91      */
  92     public static int canPassUnchecked(Class<?> src, Class<?> dst) {
  93         if (src == dst)
  94             return 1;
  95 
  96         if (dst.isPrimitive()) {
  97             if (dst == void.class)
  98                 // Return anything to a caller expecting void.
  99                 return 1;
 100             if (src == void.class)
 101                 return 0;  // void-to-something?
 102             if (!src.isPrimitive())
 103                 // Cannot pass a reference to any primitive type (exc. void).
 104                 return 0;
 105             boolean swt = Wrappers.isSubwordOrInt(src);
 106             boolean dwt = Wrappers.isSubwordOrInt(dst);
 107             if (swt && dwt) {
 108                 if (Wrappers.bitWidth(src) >= Wrappers.bitWidth(dst))
 109                     return -1;   // truncation may be required
 110                 if (!Wrappers.isSigned(dst) && Wrappers.isSigned(src))
 111                     return -1;   // sign elimination may be required
 112             }
 113             if (src == float.class || dst == float.class) {
 114                 if (src == double.class || dst == double.class)
 115                     return -1;   // floating conversion may be required
 116                 else
 117                     return 0;    // other primitive conversions NYI
 118             } else {
 119                 // all fixed-point conversions are supported
 120                 return 0;
 121             }
 122         } else if (src.isPrimitive()) {
 123             // Cannot pass a primitive to any reference type.
 124             // (Maybe allow null.class?)
 125             return 0;
 126         }
 127 
 128         // Handle reference types in the rest of the block:
 129 
 130         // The verifier treats interfaces exactly like Object.
 131         if (dst.isInterface())  dst = Object.class;
 132         //if (call.isInterface()) call  = Object.class;
 133         if (dst == Object.class)
 134             // pass any reference to object or an arb. interface
 135             return 1;
 136         // else it's a definite "maybe" (cast is required)
 137         return -1;
 138     }
 139 
 140 }