1 /*
   2  * Copyright (c) 2016, 2016, 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 package org.graalvm.compiler.core.common.type;
  26 
  27 import jdk.vm.ci.meta.Assumptions;
  28 import jdk.vm.ci.meta.ResolvedJavaType;
  29 
  30 /**
  31  * This class represents a reference to a Java type and whether this reference is referring only to
  32  * the represented type or also to its sub types in the class hierarchy. When creating a type
  33  * reference, the following options have to be considered:
  34  *
  35  * <ul>
  36  * <li>The reference should always only refer to the given concrete type. Use
  37  * {@link #createExactTrusted(ResolvedJavaType)} for this purpose.</li>
  38  * <li>The reference should be created without assumptions about the class hierarchy. The returned
  39  * reference is exact only when the type is a leaf type (i.e., it cannot have subclasses). Depending
  40  * on whether interface types can be trusted for this type reference use
  41  * {@link #createWithoutAssumptions} or {@link #createTrustedWithoutAssumptions}.</li>
  42  * <li>The reference should be created using assumptions about the class hierarchy. The returned
  43  * reference is also exact, when there is only a single concrete sub type for the given type.
  44  * Depending on whether interface types can be trusted for this type reference use {@link #create}
  45  * or {@link #createTrusted}.</li>
  46  * </ul>
  47  *
  48  * For the methods with untrusted interface types, a {@code null} reference will be constructed for
  49  * untrusted interface types. Examples for interface types that cannot be trusted are types for
  50  * parameters, fields, and return values. They are not checked by the Java verifier.
  51  *
  52  */
  53 public final class TypeReference {
  54     private final ResolvedJavaType type;
  55     private final boolean exactReference;
  56 
  57     private TypeReference(ResolvedJavaType type, boolean exactReference) {
  58         this.type = type;
  59         this.exactReference = exactReference;
  60     }
  61 
  62     /**
  63      * Creates an exact type reference using the given type.
  64      */
  65     public static TypeReference createExactTrusted(ResolvedJavaType type) {
  66         if (type == null) {
  67             return null;
  68         }
  69         return new TypeReference(type, true);
  70     }
  71 
  72     /**
  73      * Creates a type reference using the given type without assumptions and without trusting
  74      * interface types.
  75      */
  76     public static TypeReference createWithoutAssumptions(ResolvedJavaType type) {
  77         return create(null, type);
  78     }
  79 
  80     /**
  81      * Creates a type reference using the given type without assumptions and trusting interface
  82      * types.
  83      */
  84     public static TypeReference createTrustedWithoutAssumptions(ResolvedJavaType type) {
  85         return createTrusted(null, type);
  86     }
  87 
  88     /**
  89      * Creates a type reference using the given type with assumptions and without trusting interface
  90      * types.
  91      */
  92     public static TypeReference create(Assumptions assumptions, ResolvedJavaType type) {
  93         return createTrusted(assumptions, filterInterfaceTypesOut(type));
  94     }
  95 
  96     /**
  97      * Create a type reference using the given type with assumptions and trusting interface types.
  98      */
  99     public static TypeReference createTrusted(Assumptions assumptions, ResolvedJavaType type) {
 100         if (type == null) {
 101             return null;
 102         }
 103         ResolvedJavaType exactType = type.isLeaf() ? type : null;
 104         if (exactType == null) {
 105             Assumptions.AssumptionResult<ResolvedJavaType> leafConcreteSubtype = type.findLeafConcreteSubtype();
 106             if (leafConcreteSubtype != null && leafConcreteSubtype.canRecordTo(assumptions)) {
 107                 leafConcreteSubtype.recordTo(assumptions);
 108                 exactType = leafConcreteSubtype.getResult();
 109             }
 110         }
 111         if (exactType == null) {
 112             return new TypeReference(type, false);
 113         }
 114         return new TypeReference(exactType, true);
 115     }
 116 
 117     /**
 118      * The type this reference refers to.
 119      */
 120     public ResolvedJavaType getType() {
 121         return type;
 122     }
 123 
 124     /**
 125      * @return {@code true} if this reference is exact and only refers to the given type and
 126      *         {@code false} if it also refers to its sub types.
 127      */
 128     public boolean isExact() {
 129         return exactReference;
 130     }
 131 
 132     /**
 133      * @return A new reference that is guaranteed to be exact.
 134      */
 135     public TypeReference asExactReference() {
 136         if (isExact()) {
 137             return this;
 138         }
 139         return new TypeReference(type, true);
 140     }
 141 
 142     private static ResolvedJavaType filterInterfaceTypesOut(ResolvedJavaType type) {
 143         if (type != null) {
 144             if (type.isArray()) {
 145                 ResolvedJavaType componentType = filterInterfaceTypesOut(type.getComponentType());
 146                 if (componentType != null) {
 147                     return componentType.getArrayClass();
 148                 }
 149                 // Returns Object[].class
 150                 return type.getSuperclass().getArrayClass();
 151             }
 152             if (type.isInterface()) {
 153                 return null;
 154             }
 155         }
 156         return type;
 157     }
 158 
 159     @Override
 160     public String toString() {
 161         return (isExact() ? "#" : "") + type;
 162     }
 163 }