nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/internal/InternalTypeUtilities.java
changeset 34456 84eaea8d0574
parent 34096 5ac6287ec71a
parent 34455 cc9f05d3caf0
child 34457 81a65a2faef3
equal deleted inserted replaced
34096:5ac6287ec71a 34456:84eaea8d0574
     1 /*
       
     2  * Copyright (c) 2015, 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.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     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 package jdk.internal.dynalink.internal;
       
    26 
       
    27 import java.util.ArrayList;
       
    28 import java.util.HashSet;
       
    29 import java.util.Iterator;
       
    30 import java.util.List;
       
    31 import java.util.Set;
       
    32 import jdk.internal.dynalink.linker.support.TypeUtilities;
       
    33 
       
    34 /**
       
    35  * Various static utility methods for testing type relationships; internal to Dynalink.
       
    36  */
       
    37 public class InternalTypeUtilities {
       
    38     private InternalTypeUtilities() {
       
    39     }
       
    40 
       
    41     /**
       
    42      * Returns true if either of the types is assignable from the other.
       
    43      * @param c1 one type
       
    44      * @param c2 another type
       
    45      * @return true if either c1 is assignable from c2 or c2 is assignable from c1.
       
    46      */
       
    47     public static boolean areAssignable(final Class<?> c1, final Class<?> c2) {
       
    48         return c1.isAssignableFrom(c2) || c2.isAssignableFrom(c1);
       
    49     }
       
    50 
       
    51     /**
       
    52      * Return true if it is safe to strongly reference a class from the referred
       
    53      * class loader from a class associated with the referring class loader
       
    54      * without risking a class loader memory leak. Generally, it is only safe
       
    55      * to reference classes from the same or ancestor class loader. {@code null}
       
    56      * indicates the system class loader; classes from it can always be
       
    57      * directly referenced, and it can only directly reference classes from
       
    58      * itself. This method can be used by language runtimes to ensure they are
       
    59      * using weak references in their linkages when they need to link to methods
       
    60      * in unrelated class loaders.
       
    61      *
       
    62      * @param referrerLoader the referrer class loader.
       
    63      * @param referredLoader the referred class loader
       
    64      * @return true if it is safe to strongly reference the class from referred
       
    65      * in referred.
       
    66      * @throws SecurityException if the caller does not have the
       
    67      * {@code RuntimePermission("getClassLoader")} permission and the method
       
    68      * needs to traverse the parent class loader chain.
       
    69      */
       
    70     public static boolean canReferenceDirectly(final ClassLoader referrerLoader, final ClassLoader referredLoader) {
       
    71         if(referredLoader == null) {
       
    72             // Can always refer directly to a system class
       
    73             return true;
       
    74         }
       
    75         if(referrerLoader == null) {
       
    76             // System classes can't refer directly to any non-system class
       
    77             return false;
       
    78         }
       
    79         // Otherwise, can only refer directly to classes residing in same or
       
    80         // parent class loader.
       
    81 
       
    82         ClassLoader referrer = referrerLoader;
       
    83         do {
       
    84             if(referrer == referredLoader) {
       
    85                 return true;
       
    86             }
       
    87             referrer = referrer.getParent();
       
    88         } while(referrer != null);
       
    89         return false;
       
    90     }
       
    91 
       
    92     /**
       
    93      * Given two types represented by c1 and c2, returns a type that is their
       
    94      * most specific common supertype for purposes of lossless conversions.
       
    95      *
       
    96      * @param c1 one type
       
    97      * @param c2 another type
       
    98      * @return their most common superclass or superinterface for purposes of
       
    99      * lossless conversions. If they have several unrelated superinterfaces as
       
   100      * their most specific common type, or the types themselves are completely
       
   101      * unrelated interfaces, {@link java.lang.Object} is returned.
       
   102      */
       
   103     public static Class<?> getCommonLosslessConversionType(final Class<?> c1, final Class<?> c2) {
       
   104         if(c1 == c2) {
       
   105             return c1;
       
   106         } else if (c1 == void.class || c2 == void.class) {
       
   107             return Object.class;
       
   108         } else if(TypeUtilities.isConvertibleWithoutLoss(c2, c1)) {
       
   109             return c1;
       
   110         } else if(TypeUtilities.isConvertibleWithoutLoss(c1, c2)) {
       
   111             return c2;
       
   112         } else if(c1.isPrimitive() && c2.isPrimitive()) {
       
   113             if((c1 == byte.class && c2 == char.class) || (c1 == char.class && c2 == byte.class)) {
       
   114                 // byte + char = int
       
   115                 return int.class;
       
   116             } else if((c1 == short.class && c2 == char.class) || (c1 == char.class && c2 == short.class)) {
       
   117                 // short + char = int
       
   118                 return int.class;
       
   119             } else if((c1 == int.class && c2 == float.class) || (c1 == float.class && c2 == int.class)) {
       
   120                 // int + float = double
       
   121                 return double.class;
       
   122             }
       
   123         }
       
   124         // For all other cases. This will handle long + (float|double) = Number case as well as boolean + anything = Object case too.
       
   125         return getMostSpecificCommonTypeUnequalNonprimitives(c1, c2);
       
   126     }
       
   127 
       
   128     private static Class<?> getMostSpecificCommonTypeUnequalNonprimitives(final Class<?> c1, final Class<?> c2) {
       
   129         final Class<?> npc1 = c1.isPrimitive() ? TypeUtilities.getWrapperType(c1) : c1;
       
   130         final Class<?> npc2 = c2.isPrimitive() ? TypeUtilities.getWrapperType(c2) : c2;
       
   131         final Set<Class<?>> a1 = getAssignables(npc1, npc2);
       
   132         final Set<Class<?>> a2 = getAssignables(npc2, npc1);
       
   133         a1.retainAll(a2);
       
   134         if(a1.isEmpty()) {
       
   135             // Can happen when at least one of the arguments is an interface,
       
   136             // as they don't have Object at the root of their hierarchy.
       
   137             return Object.class;
       
   138         }
       
   139         // Gather maximally specific elements. Yes, there can be more than one
       
   140         // thank to interfaces. I.e., if you call this method for String.class
       
   141         // and Number.class, you'll have Comparable, Serializable, and Object
       
   142         // as maximal elements.
       
   143         final List<Class<?>> max = new ArrayList<>();
       
   144         outer: for(final Class<?> clazz: a1) {
       
   145             for(final Iterator<Class<?>> maxiter = max.iterator(); maxiter.hasNext();) {
       
   146                 final Class<?> maxClazz = maxiter.next();
       
   147                 if(TypeUtilities.isSubtype(maxClazz, clazz)) {
       
   148                     // It can't be maximal, if there's already a more specific
       
   149                     // maximal than it.
       
   150                     continue outer;
       
   151                 }
       
   152                 if(TypeUtilities.isSubtype(clazz, maxClazz)) {
       
   153                     // If it's more specific than a currently maximal element,
       
   154                     // that currently maximal is no longer a maximal.
       
   155                     maxiter.remove();
       
   156                 }
       
   157             }
       
   158             // If we get here, no current maximal is more specific than the
       
   159             // current class, so it is considered maximal as well
       
   160             max.add(clazz);
       
   161         }
       
   162         if(max.size() > 1) {
       
   163             return Object.class;
       
   164         }
       
   165         return max.get(0);
       
   166     }
       
   167 
       
   168     private static Set<Class<?>> getAssignables(final Class<?> c1, final Class<?> c2) {
       
   169         final Set<Class<?>> s = new HashSet<>();
       
   170         collectAssignables(c1, c2, s);
       
   171         return s;
       
   172     }
       
   173 
       
   174     private static void collectAssignables(final Class<?> c1, final Class<?> c2, final Set<Class<?>> s) {
       
   175         if(c1.isAssignableFrom(c2)) {
       
   176             s.add(c1);
       
   177         }
       
   178         final Class<?> sc = c1.getSuperclass();
       
   179         if(sc != null) {
       
   180             collectAssignables(sc, c2, s);
       
   181         }
       
   182         final Class<?>[] itf = c1.getInterfaces();
       
   183         for(int i = 0; i < itf.length; ++i) {
       
   184             collectAssignables(itf[i], c2, s);
       
   185         }
       
   186     }
       
   187 }