rt/emul/compact/src/main/java/sun/invoke/util/VerifyType.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 09 Aug 2014 11:11:13 +0200
branchjdk8-b132
changeset 1646 c880a8a8803b
permissions -rw-r--r--
Batch of classes necessary to implement invoke dynamic interfaces. Taken from JDK8 build 132
jaroslav@1646
     1
/*
jaroslav@1646
     2
 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
jaroslav@1646
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jaroslav@1646
     4
 *
jaroslav@1646
     5
 * This code is free software; you can redistribute it and/or modify it
jaroslav@1646
     6
 * under the terms of the GNU General Public License version 2 only, as
jaroslav@1646
     7
 * published by the Free Software Foundation.  Oracle designates this
jaroslav@1646
     8
 * particular file as subject to the "Classpath" exception as provided
jaroslav@1646
     9
 * by Oracle in the LICENSE file that accompanied this code.
jaroslav@1646
    10
 *
jaroslav@1646
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
jaroslav@1646
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jaroslav@1646
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
jaroslav@1646
    14
 * version 2 for more details (a copy is included in the LICENSE file that
jaroslav@1646
    15
 * accompanied this code).
jaroslav@1646
    16
 *
jaroslav@1646
    17
 * You should have received a copy of the GNU General Public License version
jaroslav@1646
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
jaroslav@1646
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jaroslav@1646
    20
 *
jaroslav@1646
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jaroslav@1646
    22
 * or visit www.oracle.com if you need additional information or have any
jaroslav@1646
    23
 * questions.
jaroslav@1646
    24
 */
jaroslav@1646
    25
jaroslav@1646
    26
package sun.invoke.util;
jaroslav@1646
    27
jaroslav@1646
    28
import java.lang.invoke.MethodType;
jaroslav@1646
    29
import sun.invoke.empty.Empty;
jaroslav@1646
    30
jaroslav@1646
    31
/**
jaroslav@1646
    32
 * This class centralizes information about the JVM verifier
jaroslav@1646
    33
 * and its requirements about type correctness.
jaroslav@1646
    34
 * @author jrose
jaroslav@1646
    35
 */
jaroslav@1646
    36
public class VerifyType {
jaroslav@1646
    37
jaroslav@1646
    38
    private VerifyType() { }  // cannot instantiate
jaroslav@1646
    39
jaroslav@1646
    40
    /**
jaroslav@1646
    41
     * True if a value can be stacked as the source type and unstacked as the
jaroslav@1646
    42
     * destination type, without violating the JVM's type consistency.
jaroslav@1646
    43
     *
jaroslav@1646
    44
     * @param src the type of a stacked value
jaroslav@1646
    45
     * @param dst the type by which we'd like to treat it
jaroslav@1646
    46
     * @return whether the retyping can be done without motion or reformatting
jaroslav@1646
    47
     */
jaroslav@1646
    48
    public static boolean isNullConversion(Class<?> src, Class<?> dst) {
jaroslav@1646
    49
        if (src == dst)            return true;
jaroslav@1646
    50
        // Verifier allows any interface to be treated as Object:
jaroslav@1646
    51
        if (dst.isInterface())     dst = Object.class;
jaroslav@1646
    52
        if (src.isInterface())     src = Object.class;
jaroslav@1646
    53
        if (src == dst)            return true;  // check again
jaroslav@1646
    54
        if (dst == void.class)     return true;  // drop any return value
jaroslav@1646
    55
        if (isNullType(src))       return !dst.isPrimitive();
jaroslav@1646
    56
        if (!src.isPrimitive())    return dst.isAssignableFrom(src);
jaroslav@1646
    57
        if (!dst.isPrimitive())    return false;
jaroslav@1646
    58
        // Verifier allows an int to carry byte, short, char, or even boolean:
jaroslav@1646
    59
        Wrapper sw = Wrapper.forPrimitiveType(src);
jaroslav@1646
    60
        if (dst == int.class)      return sw.isSubwordOrInt();
jaroslav@1646
    61
        Wrapper dw = Wrapper.forPrimitiveType(dst);
jaroslav@1646
    62
        if (!sw.isSubwordOrInt())  return false;
jaroslav@1646
    63
        if (!dw.isSubwordOrInt())  return false;
jaroslav@1646
    64
        if (!dw.isSigned() && sw.isSigned())  return false;
jaroslav@1646
    65
        return dw.bitWidth() > sw.bitWidth();
jaroslav@1646
    66
    }
jaroslav@1646
    67
jaroslav@1646
    68
    /**
jaroslav@1646
    69
     * Specialization of isNullConversion to reference types.
jaroslav@1646
    70
     * @param src the type of a stacked value
jaroslav@1646
    71
     * @param dst the reference type by which we'd like to treat it
jaroslav@1646
    72
     * @return whether the retyping can be done without a cast
jaroslav@1646
    73
     */
jaroslav@1646
    74
    public static boolean isNullReferenceConversion(Class<?> src, Class<?> dst) {
jaroslav@1646
    75
        assert(!dst.isPrimitive());
jaroslav@1646
    76
        if (dst.isInterface())  return true;   // verifier allows this
jaroslav@1646
    77
        if (isNullType(src))    return true;
jaroslav@1646
    78
        return dst.isAssignableFrom(src);
jaroslav@1646
    79
    }
jaroslav@1646
    80
jaroslav@1646
    81
    /**
jaroslav@1646
    82
     * Is the given type java.lang.Null or an equivalent null-only type?
jaroslav@1646
    83
     */
jaroslav@1646
    84
    public static boolean isNullType(Class<?> type) {
jaroslav@1646
    85
        if (type == null)  return false;
jaroslav@1646
    86
        return type == NULL_CLASS
jaroslav@1646
    87
            // This one may also be used as a null type.
jaroslav@1646
    88
            // TO DO: Decide if we really want to legitimize it here.
jaroslav@1646
    89
            // Probably we do, unless java.lang.Null really makes it into Java 7
jaroslav@1646
    90
            //|| type == Void.class
jaroslav@1646
    91
            // Locally known null-only class:
jaroslav@1646
    92
            || type == Empty.class
jaroslav@1646
    93
            ;
jaroslav@1646
    94
    }
jaroslav@1646
    95
    private static final Class<?> NULL_CLASS;
jaroslav@1646
    96
    static {
jaroslav@1646
    97
        Class<?> nullClass = null;
jaroslav@1646
    98
        try {
jaroslav@1646
    99
            nullClass = Class.forName("java.lang.Null");
jaroslav@1646
   100
        } catch (ClassNotFoundException ex) {
jaroslav@1646
   101
            // OK, we'll cope
jaroslav@1646
   102
        }
jaroslav@1646
   103
        NULL_CLASS = nullClass;
jaroslav@1646
   104
    }
jaroslav@1646
   105
jaroslav@1646
   106
    /**
jaroslav@1646
   107
     * True if a method handle can receive a call under a slightly different
jaroslav@1646
   108
     * method type, without moving or reformatting any stack elements.
jaroslav@1646
   109
     *
jaroslav@1646
   110
     * @param call the type of call being made
jaroslav@1646
   111
     * @param recv the type of the method handle receiving the call
jaroslav@1646
   112
     * @return whether the retyping can be done without motion or reformatting
jaroslav@1646
   113
     */
jaroslav@1646
   114
    public static boolean isNullConversion(MethodType call, MethodType recv) {
jaroslav@1646
   115
        if (call == recv)  return true;
jaroslav@1646
   116
        int len = call.parameterCount();
jaroslav@1646
   117
        if (len != recv.parameterCount())  return false;
jaroslav@1646
   118
        for (int i = 0; i < len; i++)
jaroslav@1646
   119
            if (!isNullConversion(call.parameterType(i), recv.parameterType(i)))
jaroslav@1646
   120
                return false;
jaroslav@1646
   121
        return isNullConversion(recv.returnType(), call.returnType());
jaroslav@1646
   122
    }
jaroslav@1646
   123
jaroslav@1646
   124
    /**
jaroslav@1646
   125
     * Determine if the JVM verifier allows a value of type call to be
jaroslav@1646
   126
     * passed to a formal parameter (or return variable) of type recv.
jaroslav@1646
   127
     * Returns 1 if the verifier allows the types to match without conversion.
jaroslav@1646
   128
     * Returns -1 if the types can be made to match by a JVM-supported adapter.
jaroslav@1646
   129
     * Cases supported are:
jaroslav@1646
   130
     * <ul><li>checkcast
jaroslav@1646
   131
     * </li><li>conversion between any two integral types (but not floats)
jaroslav@1646
   132
     * </li><li>unboxing from a wrapper to its corresponding primitive type
jaroslav@1646
   133
     * </li><li>conversion in either direction between float and double
jaroslav@1646
   134
     * </li></ul>
jaroslav@1646
   135
     * (Autoboxing is not supported here; it must be done via Java code.)
jaroslav@1646
   136
     * Returns 0 otherwise.
jaroslav@1646
   137
     */
jaroslav@1646
   138
    public static int canPassUnchecked(Class<?> src, Class<?> dst) {
jaroslav@1646
   139
        if (src == dst)
jaroslav@1646
   140
            return 1;
jaroslav@1646
   141
jaroslav@1646
   142
        if (dst.isPrimitive()) {
jaroslav@1646
   143
            if (dst == void.class)
jaroslav@1646
   144
                // Return anything to a caller expecting void.
jaroslav@1646
   145
                // This is a property of the implementation, which links
jaroslav@1646
   146
                // return values via a register rather than via a stack push.
jaroslav@1646
   147
                // This makes it possible to ignore cleanly.
jaroslav@1646
   148
                return 1;
jaroslav@1646
   149
            if (src == void.class)
jaroslav@1646
   150
                return 0;  // void-to-something?
jaroslav@1646
   151
            if (!src.isPrimitive())
jaroslav@1646
   152
                // Cannot pass a reference to any primitive type (exc. void).
jaroslav@1646
   153
                return 0;
jaroslav@1646
   154
            Wrapper sw = Wrapper.forPrimitiveType(src);
jaroslav@1646
   155
            Wrapper dw = Wrapper.forPrimitiveType(dst);
jaroslav@1646
   156
            if (sw.isSubwordOrInt() && dw.isSubwordOrInt()) {
jaroslav@1646
   157
                if (sw.bitWidth() >= dw.bitWidth())
jaroslav@1646
   158
                    return -1;   // truncation may be required
jaroslav@1646
   159
                if (!dw.isSigned() && sw.isSigned())
jaroslav@1646
   160
                    return -1;   // sign elimination may be required
jaroslav@1646
   161
                return 1;
jaroslav@1646
   162
            }
jaroslav@1646
   163
            if (src == float.class || dst == float.class) {
jaroslav@1646
   164
                if (src == double.class || dst == double.class)
jaroslav@1646
   165
                    return -1;   // floating conversion may be required
jaroslav@1646
   166
                else
jaroslav@1646
   167
                    return 0;    // other primitive conversions NYI
jaroslav@1646
   168
            } else {
jaroslav@1646
   169
                // all fixed-point conversions are supported
jaroslav@1646
   170
                return 0;
jaroslav@1646
   171
            }
jaroslav@1646
   172
        } else if (src.isPrimitive()) {
jaroslav@1646
   173
            // Cannot pass a primitive to any reference type.
jaroslav@1646
   174
            // (Maybe allow null.class?)
jaroslav@1646
   175
            return 0;
jaroslav@1646
   176
        }
jaroslav@1646
   177
jaroslav@1646
   178
        // Handle reference types in the rest of the block:
jaroslav@1646
   179
jaroslav@1646
   180
        // The verifier treats interfaces exactly like Object.
jaroslav@1646
   181
        if (isNullReferenceConversion(src, dst))
jaroslav@1646
   182
            // pass any reference to object or an arb. interface
jaroslav@1646
   183
            return 1;
jaroslav@1646
   184
        // else it's a definite "maybe" (cast is required)
jaroslav@1646
   185
        return -1;
jaroslav@1646
   186
    }
jaroslav@1646
   187
jaroslav@1646
   188
    public static boolean isSpreadArgType(Class<?> spreadArg) {
jaroslav@1646
   189
        return spreadArg.isArray();
jaroslav@1646
   190
    }
jaroslav@1646
   191
    public static Class<?> spreadArgElementType(Class<?> spreadArg, int i) {
jaroslav@1646
   192
        return spreadArg.getComponentType();
jaroslav@1646
   193
    }
jaroslav@1646
   194
}