Home | History | Annotate | Download | only in cst
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.dx.rop.cst;
     18 
     19 import com.android.dx.rop.type.Type;
     20 import java.util.concurrent.ConcurrentHashMap;
     21 import java.util.concurrent.ConcurrentMap;
     22 
     23 /**
     24  * Constants that represent an arbitrary type (reference or primitive).
     25  */
     26 public final class CstType extends TypedConstant {
     27 
     28     /**
     29      * Intern table for instances.
     30      *
     31      * <p>The initial capacity is based on a medium-size project.
     32      */
     33     private static final ConcurrentMap<Type, CstType> interns =
     34             new ConcurrentHashMap<>(1_000, 0.75f);
     35 
     36     /** {@code non-null;} instance corresponding to the class {@code Object} */
     37     public static final CstType OBJECT = new CstType(Type.OBJECT);
     38 
     39     /** {@code non-null;} instance corresponding to the class {@code Boolean} */
     40     public static final CstType BOOLEAN = new CstType(Type.BOOLEAN_CLASS);
     41 
     42     /** {@code non-null;} instance corresponding to the class {@code Byte} */
     43     public static final CstType BYTE = new CstType(Type.BYTE_CLASS);
     44 
     45     /** {@code non-null;} instance corresponding to the class {@code Character} */
     46     public static final CstType CHARACTER = new CstType(Type.CHARACTER_CLASS);
     47 
     48     /** {@code non-null;} instance corresponding to the class {@code Double} */
     49     public static final CstType DOUBLE = new CstType(Type.DOUBLE_CLASS);
     50 
     51     /** {@code non-null;} instance corresponding to the class {@code Float} */
     52     public static final CstType FLOAT = new CstType(Type.FLOAT_CLASS);
     53 
     54     /** {@code non-null;} instance corresponding to the class {@code Long} */
     55     public static final CstType LONG = new CstType(Type.LONG_CLASS);
     56 
     57     /** {@code non-null;} instance corresponding to the class {@code Integer} */
     58     public static final CstType INTEGER = new CstType(Type.INTEGER_CLASS);
     59 
     60     /** {@code non-null;} instance corresponding to the class {@code Short} */
     61     public static final CstType SHORT = new CstType(Type.SHORT_CLASS);
     62 
     63     /** {@code non-null;} instance corresponding to the class {@code Void} */
     64     public static final CstType VOID = new CstType(Type.VOID_CLASS);
     65 
     66     /** {@code non-null;} instance corresponding to the type {@code boolean[]} */
     67     public static final CstType BOOLEAN_ARRAY = new CstType(Type.BOOLEAN_ARRAY);
     68 
     69     /** {@code non-null;} instance corresponding to the type {@code byte[]} */
     70     public static final CstType BYTE_ARRAY = new CstType(Type.BYTE_ARRAY);
     71 
     72     /** {@code non-null;} instance corresponding to the type {@code char[]} */
     73     public static final CstType CHAR_ARRAY = new CstType(Type.CHAR_ARRAY);
     74 
     75     /** {@code non-null;} instance corresponding to the type {@code double[]} */
     76     public static final CstType DOUBLE_ARRAY = new CstType(Type.DOUBLE_ARRAY);
     77 
     78     /** {@code non-null;} instance corresponding to the type {@code float[]} */
     79     public static final CstType FLOAT_ARRAY = new CstType(Type.FLOAT_ARRAY);
     80 
     81     /** {@code non-null;} instance corresponding to the type {@code long[]} */
     82     public static final CstType LONG_ARRAY = new CstType(Type.LONG_ARRAY);
     83 
     84     /** {@code non-null;} instance corresponding to the type {@code int[]} */
     85     public static final CstType INT_ARRAY = new CstType(Type.INT_ARRAY);
     86 
     87     /** {@code non-null;} instance corresponding to the type {@code short[]} */
     88     public static final CstType SHORT_ARRAY = new CstType(Type.SHORT_ARRAY);
     89 
     90     /**
     91      * {@code non-null;} instance corresponding to the type {@code java.lang.invoke.MethodHandle}
     92      */
     93     public static final CstType METHOD_HANDLE = new CstType(Type.METHOD_HANDLE);
     94 
     95     /**
     96      * {@code non-null;} instance corresponding to the type {@code java.lang.invoke.VarHandle}
     97      */
     98     public static final CstType VAR_HANDLE = new CstType(Type.VAR_HANDLE);
     99 
    100     static {
    101         initInterns();
    102     }
    103 
    104     private static void initInterns() {
    105         internInitial(OBJECT);
    106         internInitial(BOOLEAN);
    107         internInitial(BYTE);
    108         internInitial(CHARACTER);
    109         internInitial(DOUBLE);
    110         internInitial(FLOAT);
    111         internInitial(LONG);
    112         internInitial(INTEGER);
    113         internInitial(SHORT);
    114         internInitial(VOID);
    115         internInitial(BOOLEAN_ARRAY);
    116         internInitial(BYTE_ARRAY);
    117         internInitial(CHAR_ARRAY);
    118         internInitial(DOUBLE_ARRAY);
    119         internInitial(FLOAT_ARRAY);
    120         internInitial(LONG_ARRAY);
    121         internInitial(INT_ARRAY);
    122         internInitial(SHORT_ARRAY);
    123         internInitial(METHOD_HANDLE);
    124     }
    125 
    126     private static void internInitial(CstType cst) {
    127         if (interns.putIfAbsent(cst.getClassType(), cst) != null) {
    128             throw new IllegalStateException("Attempted re-init of " + cst);
    129         }
    130     }
    131 
    132 
    133     /** {@code non-null;} the underlying type */
    134     private final Type type;
    135 
    136     /**
    137      * {@code null-ok;} the type descriptor corresponding to this instance, if
    138      * calculated
    139      */
    140     private CstString descriptor;
    141 
    142     /**
    143      * Returns an instance of this class that represents the wrapper
    144      * class corresponding to a given primitive type. For example, if
    145      * given {@link Type#INT}, this method returns the class reference
    146      * {@code java.lang.Integer}.
    147      *
    148      * @param primitiveType {@code non-null;} the primitive type
    149      * @return {@code non-null;} the corresponding wrapper class
    150      */
    151     public static CstType forBoxedPrimitiveType(Type primitiveType) {
    152         switch (primitiveType.getBasicType()) {
    153             case Type.BT_BOOLEAN: return BOOLEAN;
    154             case Type.BT_BYTE:    return BYTE;
    155             case Type.BT_CHAR:    return CHARACTER;
    156             case Type.BT_DOUBLE:  return DOUBLE;
    157             case Type.BT_FLOAT:   return FLOAT;
    158             case Type.BT_INT:     return INTEGER;
    159             case Type.BT_LONG:    return LONG;
    160             case Type.BT_SHORT:   return SHORT;
    161             case Type.BT_VOID:    return VOID;
    162         }
    163 
    164         throw new IllegalArgumentException("not primitive: " + primitiveType);
    165     }
    166 
    167     /**
    168      * Returns an interned instance of this class for the given type.
    169      *
    170      * @param type {@code non-null;} the underlying type
    171      * @return {@code non-null;} an appropriately-constructed instance
    172      */
    173     public static CstType intern(Type type) {
    174         CstType cst = new CstType(type);
    175         CstType result = interns.putIfAbsent(type, cst);
    176         return result != null ? result : cst;
    177     }
    178 
    179     /**
    180      * Constructs an instance.
    181      *
    182      * @param type {@code non-null;} the underlying type
    183      */
    184     public CstType(Type type) {
    185         if (type == null) {
    186             throw new NullPointerException("type == null");
    187         }
    188 
    189         if (type == Type.KNOWN_NULL) {
    190             throw new UnsupportedOperationException(
    191                     "KNOWN_NULL is not representable");
    192         }
    193 
    194         this.type = type;
    195         this.descriptor = null;
    196     }
    197 
    198     /** {@inheritDoc} */
    199     @Override
    200     public boolean equals(Object other) {
    201         if (!(other instanceof CstType)) {
    202             return false;
    203         }
    204 
    205         return type == ((CstType) other).type;
    206     }
    207 
    208     /** {@inheritDoc} */
    209     @Override
    210     public int hashCode() {
    211         return type.hashCode();
    212     }
    213 
    214     /** {@inheritDoc} */
    215     @Override
    216     protected int compareTo0(Constant other) {
    217         String thisDescriptor = type.getDescriptor();
    218         String otherDescriptor = ((CstType) other).type.getDescriptor();
    219         return thisDescriptor.compareTo(otherDescriptor);
    220     }
    221 
    222     /** {@inheritDoc} */
    223     @Override
    224     public String toString() {
    225         return "type{" + toHuman() + '}';
    226     }
    227 
    228     /** {@inheritDoc} */
    229     @Override
    230     public Type getType() {
    231         return Type.CLASS;
    232     }
    233 
    234     /** {@inheritDoc} */
    235     @Override
    236     public String typeName() {
    237         return "type";
    238     }
    239 
    240     /** {@inheritDoc} */
    241     @Override
    242     public boolean isCategory2() {
    243         return false;
    244     }
    245 
    246     /** {@inheritDoc} */
    247     @Override
    248     public String toHuman() {
    249         return type.toHuman();
    250     }
    251 
    252     /**
    253      * Gets the underlying type (as opposed to the type corresponding
    254      * to this instance as a constant, which is always
    255      * {@code Class}).
    256      *
    257      * @return {@code non-null;} the type corresponding to the name
    258      */
    259     public Type getClassType() {
    260         return type;
    261     }
    262 
    263     /**
    264      * Gets the type descriptor for this instance.
    265      *
    266      * @return {@code non-null;} the descriptor
    267      */
    268     public CstString getDescriptor() {
    269         if (descriptor == null) {
    270             descriptor = new CstString(type.getDescriptor());
    271         }
    272 
    273         return descriptor;
    274     }
    275 
    276     /**
    277      * Returns a human readable package name for this type, like "java.util".
    278      * If this is an array type, this returns the package name of the array's
    279      * component type. If this is a primitive type, this returns "default".
    280      */
    281     public String getPackageName() {
    282         // descriptor is a string like "[[Ljava/util/String;"
    283         String descriptor = getDescriptor().getString();
    284         int lastSlash = descriptor.lastIndexOf('/');
    285         int lastLeftSquare = descriptor.lastIndexOf('['); // -1 unless this is an array
    286         if (lastSlash == -1) {
    287             return "default";
    288         } else {
    289             // +2 to skip the '[' and the 'L' prefix
    290             return descriptor.substring(lastLeftSquare + 2, lastSlash).replace('/', '.');
    291         }
    292     }
    293 
    294     public static void clearInternTable() {
    295         interns.clear();
    296         initInterns();
    297     }
    298 
    299 }
    300