View Javadoc
1   package mockit.asm.types;
2   
3   import static mockit.asm.jvmConstants.Opcodes.DCONST_0;
4   import static mockit.asm.jvmConstants.Opcodes.DLOAD;
5   import static mockit.asm.jvmConstants.Opcodes.FCONST_0;
6   import static mockit.asm.jvmConstants.Opcodes.FLOAD;
7   import static mockit.asm.jvmConstants.Opcodes.IALOAD;
8   import static mockit.asm.jvmConstants.Opcodes.IASTORE;
9   import static mockit.asm.jvmConstants.Opcodes.ICONST_0;
10  import static mockit.asm.jvmConstants.Opcodes.ILOAD;
11  import static mockit.asm.jvmConstants.Opcodes.LCONST_0;
12  import static mockit.asm.jvmConstants.Opcodes.LLOAD;
13  
14  import edu.umd.cs.findbugs.annotations.NonNull;
15  import edu.umd.cs.findbugs.annotations.Nullable;
16  
17  import mockit.asm.jvmConstants.ArrayElementType;
18  
19  import org.checkerframework.checker.index.qual.NonNegative;
20  
21  public final class PrimitiveType extends JavaType {
22      private static final Class<?>[] TYPES = { void.class, boolean.class, char.class, byte.class, short.class, int.class,
23              float.class, long.class, double.class };
24      private static final String[] WRAPPER_TYPE_DESCS = { "java/lang/Void", "java/lang/Boolean", "java/lang/Character",
25              "java/lang/Byte", "java/lang/Short", "java/lang/Integer", "java/lang/Float", "java/lang/Long",
26              "java/lang/Double" };
27      private static final char[] TYPE_CODES = { 'V', 'Z', 'C', 'B', 'S', 'I', 'F', 'J', 'D' };
28      private static final String TYPE_CODES_STR = "VZCBSIFJD";
29      private static final int[] ARRAY_ELEMENT_TYPES = { 0, ArrayElementType.BOOLEAN, ArrayElementType.CHAR,
30              ArrayElementType.BYTE, ArrayElementType.SHORT, ArrayElementType.INT, ArrayElementType.FLOAT,
31              ArrayElementType.LONG, ArrayElementType.DOUBLE };
32      private static final PrimitiveType VOID = new PrimitiveType(0, 0);
33      private static final PrimitiveType BOOLEAN = new PrimitiveType(1, 5);
34      private static final PrimitiveType CHAR = new PrimitiveType(2, 6);
35      private static final PrimitiveType BYTE = new PrimitiveType(3, 5);
36      private static final PrimitiveType SHORT = new PrimitiveType(4, 7);
37      private static final PrimitiveType INT = new PrimitiveType(5, 0);
38      private static final PrimitiveType FLOAT = new PrimitiveType(6, 2);
39      private static final PrimitiveType LONG = new PrimitiveType(7, 1);
40      private static final PrimitiveType DOUBLE = new PrimitiveType(8, 3);
41      private static final PrimitiveType[] JAVA_TYPES = { VOID, BOOLEAN, CHAR, BYTE, SHORT, INT, FLOAT, LONG, DOUBLE };
42  
43      @NonNegative
44      private final int index; // index of the type for lookup in several data type arrays
45      @NonNegative
46      private final int loadOrStoreOffset; // instruction offset for IALOAD or IASTORE
47      @NonNegative
48      private final int otherOffset; // offset for all other instructions
49      @NonNegative
50      private final int size; // the size in words of the primitive type
51      @NonNegative
52      private final int loadOpcode; // the xLOAD instruction for this primitive type
53      @NonNegative
54      private final int constOpcode; // the xCONST_0 value for this primitive type
55      @NonNull
56      private final String wrapperTypeDesc; // internal name of the corresponding "java.lang" wrapper class
57  
58      private PrimitiveType(@NonNegative int index, @NonNegative int otherOffset) {
59          super(1);
60          this.index = index;
61          this.otherOffset = otherOffset;
62          wrapperTypeDesc = WRAPPER_TYPE_DESCS[index];
63  
64          Class<?> type = TYPES[index];
65  
66          if (type == void.class) {
67              loadOrStoreOffset = 5;
68              size = 0;
69              loadOpcode = 0;
70              constOpcode = 0;
71          } else if (type == float.class) {
72              loadOrStoreOffset = 2;
73              size = 1;
74              loadOpcode = FLOAD;
75              constOpcode = FCONST_0;
76          } else if (type == long.class) {
77              loadOrStoreOffset = 1;
78              size = 2;
79              loadOpcode = LLOAD;
80              constOpcode = LCONST_0;
81          } else if (type == double.class) {
82              loadOrStoreOffset = 3;
83              size = 2;
84              loadOpcode = DLOAD;
85              constOpcode = DCONST_0;
86          } else {
87              loadOrStoreOffset = 0;
88              size = 1;
89              loadOpcode = ILOAD;
90              constOpcode = ICONST_0;
91          }
92      }
93  
94      @NonNull
95      static PrimitiveType getPrimitiveType(@NonNull Class<?> aClass) {
96          for (int i = 0; i < 9; i++) {
97              if (aClass == TYPES[i]) {
98                  return JAVA_TYPES[i];
99              }
100         }
101 
102         throw new IllegalArgumentException("Not a primitive type: " + aClass);
103     }
104 
105     @Nullable
106     public static PrimitiveType getPrimitiveType(int typeCode) {
107         int i = TYPE_CODES_STR.indexOf(typeCode);
108         return i < 0 ? null : JAVA_TYPES[i];
109     }
110 
111     @Nullable
112     public static PrimitiveType getCorrespondingPrimitiveTypeIfWrapperType(@NonNull String typeDesc) {
113         for (int i = 0; i < 9; i++) {
114             if (typeDesc.equals(WRAPPER_TYPE_DESCS[i])) {
115                 return JAVA_TYPES[i];
116             }
117         }
118 
119         return null;
120     }
121 
122     @NonNull
123     public static Class<?> getType(int typeCode) {
124         int i = TYPE_CODES_STR.indexOf((char) typeCode);
125         return TYPES[i];
126     }
127 
128     /**
129      * Maps a <code>PrimitiveType</code> to the corresponding {@link ArrayElementType}.
130      */
131     public static int getArrayElementType(@NonNull PrimitiveType elementType) {
132         return ARRAY_ELEMENT_TYPES[elementType.index];
133     }
134 
135     public char getTypeCode() {
136         return TYPE_CODES[index];
137     }
138 
139     @NonNull
140     public Class<?> getType() {
141         return TYPES[index];
142     }
143 
144     @NonNull
145     public String getWrapperTypeDesc() {
146         return wrapperTypeDesc;
147     }
148 
149     @Override
150     void getDescriptor(@NonNull StringBuilder typeDesc) {
151         typeDesc.append(getTypeCode());
152     }
153 
154     @NonNull
155     @Override
156     public String getClassName() {
157         return getType().getName();
158     }
159 
160     @NonNegative
161     @Override
162     public int getSize() {
163         return size;
164     }
165 
166     @Override
167     public int getOpcode(int opcode) {
168         int offset = opcode == IALOAD || opcode == IASTORE ? otherOffset : loadOrStoreOffset;
169         return opcode + offset;
170     }
171 
172     @Override
173     public int getLoadOpcode() {
174         return loadOpcode;
175     }
176 
177     @Override
178     public int getConstOpcode() {
179         return constOpcode;
180     }
181 
182     @Override
183     public boolean equals(Object o) {
184         return this == o || o instanceof PrimitiveType && index == ((PrimitiveType) o).index;
185     }
186 
187     @Override
188     public int hashCode() {
189         return 13 * index;
190     }
191 }