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