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