1 package mockit.asm.classes;
2
3 import edu.umd.cs.findbugs.annotations.NonNull;
4 import edu.umd.cs.findbugs.annotations.Nullable;
5
6 import mockit.asm.AnnotatedReader;
7 import mockit.asm.fields.FieldReader;
8 import mockit.asm.jvmConstants.Access;
9 import mockit.asm.jvmConstants.ClassVersion;
10 import mockit.asm.methods.MethodReader;
11
12 import org.checkerframework.checker.index.qual.NonNegative;
13
14
15
16
17
18
19
20
21 public final class ClassReader extends AnnotatedReader {
22
23
24
25 @NonNegative
26 final int header;
27
28 @NonNegative
29 private final int version;
30 @NonNull
31 private final ClassInfo classInfo;
32
33 private ClassVisitor cv;
34 @NonNegative
35 private int innerClassesCodeIndex;
36 @NonNegative
37 private int attributesCodeIndex;
38
39
40
41
42 @Nullable
43 private int[] bootstrapMethods;
44
45
46
47
48 public ClassReader(@NonNull byte[] code) {
49 super(code);
50 header = codeIndex;
51 version = readShort(6);
52 access = readUnsignedShort();
53 classInfo = new ClassInfo();
54 codeIndex += 2;
55 classInfo.superName = readClass();
56 }
57
58
59
60
61 public int getVersion() {
62 return version;
63 }
64
65
66
67
68 public int getAccess() {
69 return access;
70 }
71
72
73
74
75 @NonNull
76 public String getSuperName() {
77 assert classInfo.superName != null;
78 return classInfo.superName;
79 }
80
81
82
83
84 @NonNull
85 public byte[] getBytecode() {
86 return code;
87 }
88
89
90
91
92 public void accept(ClassVisitor visitor) {
93 cv = visitor;
94
95 codeIndex = header + 2;
96 String classDesc = readNonnullClass();
97 codeIndex += 2;
98
99 readInterfaces();
100 readClassAttributes();
101 visitor.visit(version, access, classDesc, classInfo);
102 readAnnotations(visitor);
103 readInnerClasses();
104 readFieldsAndMethods();
105
106 visitor.visitEnd();
107 }
108
109 private void readInterfaces() {
110 int interfaceCount = readUnsignedShort();
111
112 if (interfaceCount > 0) {
113 String[] interfaces = new String[interfaceCount];
114
115 for (int i = 0; i < interfaceCount; i++) {
116 interfaces[i] = readNonnullClass();
117 }
118
119 classInfo.interfaces = interfaces;
120 }
121 }
122
123 private void readClassAttributes() {
124 innerClassesCodeIndex = 0;
125 codeIndex = getAttributesStartIndex();
126 readAttributes();
127 classInfo.signature = signature;
128 }
129
130 @Nullable
131 @Override
132 protected Boolean readAttribute(@NonNull String attributeName) {
133 if ("SourceFile".equals(attributeName)) {
134 classInfo.sourceFileName = readNonnullUTF8();
135 return true;
136 }
137
138 if ("EnclosingMethod".equals(attributeName)) {
139 return false;
140 }
141
142 if ("NestHost".equals(attributeName)) {
143 classInfo.hostClassName = readNonnullClass();
144 return true;
145 }
146
147 if ("NestMembers".equals(attributeName)) {
148 readNestMembers();
149 return true;
150 }
151
152 if ("BootstrapMethods".equals(attributeName)) {
153 readBootstrapMethods();
154 return true;
155 }
156
157 if ("InnerClasses".equals(attributeName)) {
158 innerClassesCodeIndex = codeIndex;
159 return false;
160 }
161
162 return null;
163 }
164
165 private void readNestMembers() {
166 int numberOfClasses = readUnsignedShort();
167 String[] nestMembers = new String[numberOfClasses];
168
169 for (int i = 0; i < numberOfClasses; i++) {
170 nestMembers[i] = readNonnullClass();
171 }
172
173 classInfo.nestMembers = nestMembers;
174 }
175
176 private void readBootstrapMethods() {
177 int bsmCount = readUnsignedShort();
178 bootstrapMethods = new int[bsmCount];
179
180 for (int i = 0; i < bsmCount; i++) {
181 bootstrapMethods[i] = codeIndex;
182 codeIndex += 2;
183 int codeOffset = readUnsignedShort();
184 codeIndex += codeOffset << 1;
185 }
186 }
187
188 private void readInnerClasses() {
189 int startIndex = innerClassesCodeIndex;
190
191 if (startIndex != 0) {
192 codeIndex = startIndex;
193
194 for (int innerClassCount = readUnsignedShort(); innerClassCount > 0; innerClassCount--) {
195 String innerName = readNonnullClass();
196 String outerName = readClass();
197 String simpleInnerName = readUTF8();
198 int innerAccess = readUnsignedShort();
199
200 cv.visitInnerClass(innerName, outerName, simpleInnerName, innerAccess);
201 }
202 }
203 }
204
205 private void readFieldsAndMethods() {
206 codeIndex = getCodeIndexAfterInterfaces(classInfo.interfaces.length);
207
208 FieldReader fieldReader = new FieldReader(this, cv);
209 codeIndex = fieldReader.readFields();
210
211 MethodReader methodReader = new MethodReader(this, cv);
212 codeIndex = methodReader.readMethods();
213 }
214
215 @NonNegative
216 private int getCodeIndexAfterInterfaces(@NonNegative int interfaceCount) {
217 return header + 8 + 2 * interfaceCount;
218 }
219
220
221
222
223 @NonNegative
224 private int getAttributesStartIndex() {
225 if (attributesCodeIndex == 0) {
226 skipHeader();
227 skipClassMembers();
228 skipClassMembers();
229 attributesCodeIndex = codeIndex;
230 }
231
232 return attributesCodeIndex;
233 }
234
235 private void skipHeader() {
236 int interfaceCount = readUnsignedShort(header + 6);
237 codeIndex = getCodeIndexAfterInterfaces(interfaceCount);
238 }
239
240 private void skipClassMembers() {
241 for (int memberCount = readUnsignedShort(); memberCount > 0; memberCount--) {
242 codeIndex += 6;
243 skipMemberAttributes();
244 }
245 }
246
247 private void skipMemberAttributes() {
248 for (int attributeCount = readUnsignedShort(); attributeCount > 0; attributeCount--) {
249 codeIndex += 2;
250 int codeOffsetToNextAttribute = readInt();
251 codeIndex += codeOffsetToNextAttribute;
252 }
253 }
254
255 boolean positionAtBootstrapMethodsAttribute() {
256 codeIndex = getAttributesStartIndex();
257
258 for (int attributeCount = readUnsignedShort(); attributeCount > 0; attributeCount--) {
259 String attrName = readNonnullUTF8();
260
261 if ("BootstrapMethods".equals(attrName)) {
262 return true;
263 }
264
265 int codeOffsetToNextAttribute = readInt();
266 codeIndex += codeOffsetToNextAttribute;
267 }
268
269 return false;
270 }
271
272 @NonNegative
273 public int getBSMCodeIndex(@NonNegative int bsmStartIndex) {
274 assert bootstrapMethods != null;
275 return bootstrapMethods[bsmStartIndex];
276 }
277 }