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