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