1fe7450192ce5268d73f19b404ca8d454023b3569cushon/*
2fe7450192ce5268d73f19b404ca8d454023b3569cushon * Copyright 2016 Google Inc. All Rights Reserved.
3fe7450192ce5268d73f19b404ca8d454023b3569cushon *
4fe7450192ce5268d73f19b404ca8d454023b3569cushon * Licensed under the Apache License, Version 2.0 (the "License");
5fe7450192ce5268d73f19b404ca8d454023b3569cushon * you may not use this file except in compliance with the License.
6fe7450192ce5268d73f19b404ca8d454023b3569cushon * You may obtain a copy of the License at
7fe7450192ce5268d73f19b404ca8d454023b3569cushon *
8fe7450192ce5268d73f19b404ca8d454023b3569cushon *     http://www.apache.org/licenses/LICENSE-2.0
9fe7450192ce5268d73f19b404ca8d454023b3569cushon *
10fe7450192ce5268d73f19b404ca8d454023b3569cushon * Unless required by applicable law or agreed to in writing, software
11fe7450192ce5268d73f19b404ca8d454023b3569cushon * distributed under the License is distributed on an "AS IS" BASIS,
12fe7450192ce5268d73f19b404ca8d454023b3569cushon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fe7450192ce5268d73f19b404ca8d454023b3569cushon * See the License for the specific language governing permissions and
14fe7450192ce5268d73f19b404ca8d454023b3569cushon * limitations under the License.
15fe7450192ce5268d73f19b404ca8d454023b3569cushon */
16fe7450192ce5268d73f19b404ca8d454023b3569cushon
17fe7450192ce5268d73f19b404ca8d454023b3569cushonpackage com.google.turbine.bytecode;
18fe7450192ce5268d73f19b404ca8d454023b3569cushon
19783f80f37ad70eba7fd4b5e11a34854724227bf6cushonimport com.google.common.collect.ImmutableList;
20fe7450192ce5268d73f19b404ca8d454023b3569cushonimport com.google.common.collect.ImmutableMap;
21d01fe55c0e5007580f441eb336a14473e00b8f54cushonimport com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue;
2286eb6f1c5b02fc461b47602de67551361f9d695fcushonimport com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.ConstClassValue;
23d01fe55c0e5007580f441eb336a14473e00b8f54cushonimport com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.EnumConstValue;
24fe7450192ce5268d73f19b404ca8d454023b3569cushonimport com.google.turbine.model.Const;
25fe7450192ce5268d73f19b404ca8d454023b3569cushonimport com.google.turbine.model.TurbineFlag;
26fe7450192ce5268d73f19b404ca8d454023b3569cushonimport java.util.ArrayList;
27fe7450192ce5268d73f19b404ca8d454023b3569cushonimport java.util.Collections;
28fe7450192ce5268d73f19b404ca8d454023b3569cushonimport java.util.List;
2928fc0ccb690cad787da840572c73fd3e3311047dcushonimport javax.annotation.CheckReturnValue;
3028fc0ccb690cad787da840572c73fd3e3311047dcushonimport javax.annotation.Nullable;
31fe7450192ce5268d73f19b404ca8d454023b3569cushon
32fe7450192ce5268d73f19b404ca8d454023b3569cushon/** A JVMS §4 class file reader. */
33fe7450192ce5268d73f19b404ca8d454023b3569cushonpublic class ClassReader {
34fe7450192ce5268d73f19b404ca8d454023b3569cushon
35fe7450192ce5268d73f19b404ca8d454023b3569cushon  /** Reads the given bytes into an {@link ClassFile}. */
3628fc0ccb690cad787da840572c73fd3e3311047dcushon  @Deprecated
37fe7450192ce5268d73f19b404ca8d454023b3569cushon  public static ClassFile read(byte[] bytes) {
3828fc0ccb690cad787da840572c73fd3e3311047dcushon    return read(null, bytes);
39fe7450192ce5268d73f19b404ca8d454023b3569cushon  }
40fe7450192ce5268d73f19b404ca8d454023b3569cushon
4128fc0ccb690cad787da840572c73fd3e3311047dcushon  /** Reads the given bytes into an {@link ClassFile}. */
4228fc0ccb690cad787da840572c73fd3e3311047dcushon  public static ClassFile read(@Nullable String path, byte[] bytes) {
4328fc0ccb690cad787da840572c73fd3e3311047dcushon    return new ClassReader(path, bytes).read();
4428fc0ccb690cad787da840572c73fd3e3311047dcushon  }
4528fc0ccb690cad787da840572c73fd3e3311047dcushon
4628fc0ccb690cad787da840572c73fd3e3311047dcushon  @Nullable private final String path;
47fe7450192ce5268d73f19b404ca8d454023b3569cushon  private final ByteReader reader;
48fe7450192ce5268d73f19b404ca8d454023b3569cushon
4928fc0ccb690cad787da840572c73fd3e3311047dcushon  private ClassReader(@Nullable String path, byte[] bytes) {
5028fc0ccb690cad787da840572c73fd3e3311047dcushon    this.path = path;
51fe7450192ce5268d73f19b404ca8d454023b3569cushon    this.reader = new ByteReader(bytes, 0);
52fe7450192ce5268d73f19b404ca8d454023b3569cushon  }
53fe7450192ce5268d73f19b404ca8d454023b3569cushon
5428fc0ccb690cad787da840572c73fd3e3311047dcushon  @CheckReturnValue
5528fc0ccb690cad787da840572c73fd3e3311047dcushon  Error error(String format, Object... args) {
5628fc0ccb690cad787da840572c73fd3e3311047dcushon    StringBuilder sb = new StringBuilder();
5728fc0ccb690cad787da840572c73fd3e3311047dcushon    if (path != null) {
5828fc0ccb690cad787da840572c73fd3e3311047dcushon      sb.append(path).append(": ");
5928fc0ccb690cad787da840572c73fd3e3311047dcushon    }
6028fc0ccb690cad787da840572c73fd3e3311047dcushon    sb.append(String.format(format, args));
6128fc0ccb690cad787da840572c73fd3e3311047dcushon    return new AssertionError(sb.toString());
6228fc0ccb690cad787da840572c73fd3e3311047dcushon  }
6328fc0ccb690cad787da840572c73fd3e3311047dcushon
64fe7450192ce5268d73f19b404ca8d454023b3569cushon  private ClassFile read() {
65fe7450192ce5268d73f19b404ca8d454023b3569cushon    int magic = reader.u4();
66fe7450192ce5268d73f19b404ca8d454023b3569cushon    if (magic != 0xcafebabe) {
6728fc0ccb690cad787da840572c73fd3e3311047dcushon      throw error("bad magic: 0x%x", path, magic);
68fe7450192ce5268d73f19b404ca8d454023b3569cushon    }
697700e365dd9cd14b9a03bda4cf10bc9f7dc1d8d4cushon    int minorVersion = reader.u2();
707700e365dd9cd14b9a03bda4cf10bc9f7dc1d8d4cushon    int majorVersion = reader.u2();
7128fc0ccb690cad787da840572c73fd3e3311047dcushon    if (majorVersion < 45 || majorVersion > 53) {
7228fc0ccb690cad787da840572c73fd3e3311047dcushon      throw error("bad version: %d.%d", majorVersion, minorVersion);
73fe7450192ce5268d73f19b404ca8d454023b3569cushon    }
74fe7450192ce5268d73f19b404ca8d454023b3569cushon    ConstantPoolReader constantPool = ConstantPoolReader.readConstantPool(reader);
757700e365dd9cd14b9a03bda4cf10bc9f7dc1d8d4cushon    int accessFlags = reader.u2();
76fe7450192ce5268d73f19b404ca8d454023b3569cushon    String thisClass = constantPool.classInfo(reader.u2());
777700e365dd9cd14b9a03bda4cf10bc9f7dc1d8d4cushon    int superClassIndex = reader.u2();
78fe7450192ce5268d73f19b404ca8d454023b3569cushon    String superClass;
79fe7450192ce5268d73f19b404ca8d454023b3569cushon    if (superClassIndex != 0) {
80fe7450192ce5268d73f19b404ca8d454023b3569cushon      superClass = constantPool.classInfo(superClassIndex);
81fe7450192ce5268d73f19b404ca8d454023b3569cushon    } else {
82fe7450192ce5268d73f19b404ca8d454023b3569cushon      superClass = null;
83fe7450192ce5268d73f19b404ca8d454023b3569cushon    }
847700e365dd9cd14b9a03bda4cf10bc9f7dc1d8d4cushon    int interfacesCount = reader.u2();
85fe7450192ce5268d73f19b404ca8d454023b3569cushon    List<String> interfaces = new ArrayList<>();
86fe7450192ce5268d73f19b404ca8d454023b3569cushon    for (int i = 0; i < interfacesCount; i++) {
87fe7450192ce5268d73f19b404ca8d454023b3569cushon      interfaces.add(constantPool.classInfo(reader.u2()));
88fe7450192ce5268d73f19b404ca8d454023b3569cushon    }
89fe7450192ce5268d73f19b404ca8d454023b3569cushon
90d01fe55c0e5007580f441eb336a14473e00b8f54cushon    List<ClassFile.FieldInfo> fieldinfos = readFields(constantPool);
91fe7450192ce5268d73f19b404ca8d454023b3569cushon
92d01fe55c0e5007580f441eb336a14473e00b8f54cushon    List<ClassFile.MethodInfo> methodinfos = readMethods(constantPool);
93fe7450192ce5268d73f19b404ca8d454023b3569cushon
94fe7450192ce5268d73f19b404ca8d454023b3569cushon    String signature = null;
95d01fe55c0e5007580f441eb336a14473e00b8f54cushon    List<ClassFile.InnerClass> innerclasses = Collections.emptyList();
96d01fe55c0e5007580f441eb336a14473e00b8f54cushon    List<ClassFile.AnnotationInfo> annotations = Collections.emptyList();
97fe7450192ce5268d73f19b404ca8d454023b3569cushon    int attributesCount = reader.u2();
98fe7450192ce5268d73f19b404ca8d454023b3569cushon    for (int j = 0; j < attributesCount; j++) {
99fe7450192ce5268d73f19b404ca8d454023b3569cushon      int attributeNameIndex = reader.u2();
100fe7450192ce5268d73f19b404ca8d454023b3569cushon      String name = constantPool.utf8(attributeNameIndex);
101fe7450192ce5268d73f19b404ca8d454023b3569cushon      switch (name) {
102fe7450192ce5268d73f19b404ca8d454023b3569cushon        case "RuntimeVisibleAnnotations":
103fe7450192ce5268d73f19b404ca8d454023b3569cushon          annotations = readAnnotations(constantPool, accessFlags);
104fe7450192ce5268d73f19b404ca8d454023b3569cushon          break;
105fe7450192ce5268d73f19b404ca8d454023b3569cushon        case "Signature":
106fe7450192ce5268d73f19b404ca8d454023b3569cushon          signature = readSignature(constantPool);
107fe7450192ce5268d73f19b404ca8d454023b3569cushon          break;
108fe7450192ce5268d73f19b404ca8d454023b3569cushon        case "InnerClasses":
109fe7450192ce5268d73f19b404ca8d454023b3569cushon          innerclasses = readInnerClasses(constantPool, thisClass);
110fe7450192ce5268d73f19b404ca8d454023b3569cushon          break;
111fe7450192ce5268d73f19b404ca8d454023b3569cushon        default:
112fe7450192ce5268d73f19b404ca8d454023b3569cushon          reader.skip(reader.u4());
113fe7450192ce5268d73f19b404ca8d454023b3569cushon          break;
114fe7450192ce5268d73f19b404ca8d454023b3569cushon      }
115fe7450192ce5268d73f19b404ca8d454023b3569cushon    }
116fe7450192ce5268d73f19b404ca8d454023b3569cushon
117fe7450192ce5268d73f19b404ca8d454023b3569cushon    return new ClassFile(
118fe7450192ce5268d73f19b404ca8d454023b3569cushon        accessFlags,
119fe7450192ce5268d73f19b404ca8d454023b3569cushon        thisClass,
120fe7450192ce5268d73f19b404ca8d454023b3569cushon        signature,
121fe7450192ce5268d73f19b404ca8d454023b3569cushon        superClass,
122fe7450192ce5268d73f19b404ca8d454023b3569cushon        interfaces,
123fe7450192ce5268d73f19b404ca8d454023b3569cushon        methodinfos,
124fe7450192ce5268d73f19b404ca8d454023b3569cushon        fieldinfos,
125fe7450192ce5268d73f19b404ca8d454023b3569cushon        annotations,
1263e5b0c401c8d93182e9f0ce6f0de81f7574f5acacushon        innerclasses,
1273e5b0c401c8d93182e9f0ce6f0de81f7574f5acacushon        ImmutableList.of());
128fe7450192ce5268d73f19b404ca8d454023b3569cushon  }
129fe7450192ce5268d73f19b404ca8d454023b3569cushon
130fe7450192ce5268d73f19b404ca8d454023b3569cushon  /** Reads a JVMS 4.7.9 Signature attribute. */
131fe7450192ce5268d73f19b404ca8d454023b3569cushon  private String readSignature(ConstantPoolReader constantPool) {
132fe7450192ce5268d73f19b404ca8d454023b3569cushon    String signature;
133fe7450192ce5268d73f19b404ca8d454023b3569cushon    reader.u4(); // length
134fe7450192ce5268d73f19b404ca8d454023b3569cushon    signature = constantPool.utf8(reader.u2());
135fe7450192ce5268d73f19b404ca8d454023b3569cushon    return signature;
136fe7450192ce5268d73f19b404ca8d454023b3569cushon  }
137fe7450192ce5268d73f19b404ca8d454023b3569cushon
138fe7450192ce5268d73f19b404ca8d454023b3569cushon  /** Reads JVMS 4.7.6 InnerClasses attributes. */
139d01fe55c0e5007580f441eb336a14473e00b8f54cushon  private List<ClassFile.InnerClass> readInnerClasses(
140d01fe55c0e5007580f441eb336a14473e00b8f54cushon      ConstantPoolReader constantPool, String thisClass) {
141fe7450192ce5268d73f19b404ca8d454023b3569cushon    reader.u4(); // length
142fe7450192ce5268d73f19b404ca8d454023b3569cushon    int numberOfClasses = reader.u2();
143d01fe55c0e5007580f441eb336a14473e00b8f54cushon    List<ClassFile.InnerClass> innerclasses = new ArrayList<>();
144fe7450192ce5268d73f19b404ca8d454023b3569cushon    for (int i = 0; i < numberOfClasses; i++) {
145fe7450192ce5268d73f19b404ca8d454023b3569cushon      int innerClassInfoIndex = reader.u2();
146fe7450192ce5268d73f19b404ca8d454023b3569cushon      String innerClass = constantPool.classInfo(innerClassInfoIndex);
147fe7450192ce5268d73f19b404ca8d454023b3569cushon      int outerClassInfoIndex = reader.u2();
148fe7450192ce5268d73f19b404ca8d454023b3569cushon      String outerClass =
149fe7450192ce5268d73f19b404ca8d454023b3569cushon          outerClassInfoIndex != 0 ? constantPool.classInfo(outerClassInfoIndex) : null;
150fe7450192ce5268d73f19b404ca8d454023b3569cushon      int innerNameIndex = reader.u2();
151fe7450192ce5268d73f19b404ca8d454023b3569cushon      String innerName = innerNameIndex != 0 ? constantPool.utf8(innerNameIndex) : null;
1527700e365dd9cd14b9a03bda4cf10bc9f7dc1d8d4cushon      int innerClassAccessFlags = reader.u2();
1534a9a664dd17b17d4ca4641f6267a59f644f20a07cushon      if (innerName != null && (thisClass.equals(innerClass) || thisClass.equals(outerClass))) {
154d01fe55c0e5007580f441eb336a14473e00b8f54cushon        innerclasses.add(
155d01fe55c0e5007580f441eb336a14473e00b8f54cushon            new ClassFile.InnerClass(innerClass, outerClass, innerName, innerClassAccessFlags));
156fe7450192ce5268d73f19b404ca8d454023b3569cushon      }
157fe7450192ce5268d73f19b404ca8d454023b3569cushon    }
158fe7450192ce5268d73f19b404ca8d454023b3569cushon    return innerclasses;
159fe7450192ce5268d73f19b404ca8d454023b3569cushon  }
160fe7450192ce5268d73f19b404ca8d454023b3569cushon
161fe7450192ce5268d73f19b404ca8d454023b3569cushon  /**
162fe7450192ce5268d73f19b404ca8d454023b3569cushon   * Processes a JVMS 4.7.16 RuntimeVisibleAnnotations attribute.
163fe7450192ce5268d73f19b404ca8d454023b3569cushon   *
164ecb791c15008191f75be7a7e747bb387530d16d2cushon   * <p>The only annotations that affect header compilation are {@link @Retention} and
165ecb791c15008191f75be7a7e747bb387530d16d2cushon   * {@link @Target} on annotation declarations.
166fe7450192ce5268d73f19b404ca8d454023b3569cushon   */
167d01fe55c0e5007580f441eb336a14473e00b8f54cushon  private List<ClassFile.AnnotationInfo> readAnnotations(
1687700e365dd9cd14b9a03bda4cf10bc9f7dc1d8d4cushon      ConstantPoolReader constantPool, int accessFlags) {
169d01fe55c0e5007580f441eb336a14473e00b8f54cushon    List<ClassFile.AnnotationInfo> annotations = new ArrayList<>();
170fe7450192ce5268d73f19b404ca8d454023b3569cushon    if ((accessFlags & TurbineFlag.ACC_ANNOTATION) == 0) {
171fe7450192ce5268d73f19b404ca8d454023b3569cushon      reader.skip(reader.u4());
172d1509927c68b994ecb9eb95a8ae8478da9f04ed4cushon      return ImmutableList.of();
173fe7450192ce5268d73f19b404ca8d454023b3569cushon    }
174fe7450192ce5268d73f19b404ca8d454023b3569cushon    reader.u4(); // length
175fe7450192ce5268d73f19b404ca8d454023b3569cushon    int numAnnotations = reader.u2();
176fe7450192ce5268d73f19b404ca8d454023b3569cushon    for (int n = 0; n < numAnnotations; n++) {
177d01fe55c0e5007580f441eb336a14473e00b8f54cushon      ClassFile.AnnotationInfo tmp = readAnnotation(constantPool);
178fe7450192ce5268d73f19b404ca8d454023b3569cushon      if (tmp != null) {
179fe7450192ce5268d73f19b404ca8d454023b3569cushon        annotations.add(tmp);
180fe7450192ce5268d73f19b404ca8d454023b3569cushon      }
181fe7450192ce5268d73f19b404ca8d454023b3569cushon    }
182fe7450192ce5268d73f19b404ca8d454023b3569cushon    return annotations;
183fe7450192ce5268d73f19b404ca8d454023b3569cushon  }
184fe7450192ce5268d73f19b404ca8d454023b3569cushon
185d01fe55c0e5007580f441eb336a14473e00b8f54cushon  /**
186ecb791c15008191f75be7a7e747bb387530d16d2cushon   * Extracts an {@link @Retention} or {@link ElementType} {@link ClassFile.AnnotationInfo}, or else
187ecb791c15008191f75be7a7e747bb387530d16d2cushon   * skips over the annotation.
188d01fe55c0e5007580f441eb336a14473e00b8f54cushon   */
189d01fe55c0e5007580f441eb336a14473e00b8f54cushon  private ClassFile.AnnotationInfo readAnnotation(ConstantPoolReader constantPool) {
190fe7450192ce5268d73f19b404ca8d454023b3569cushon    int typeIndex = reader.u2();
191fe7450192ce5268d73f19b404ca8d454023b3569cushon    String annotationType = constantPool.utf8(typeIndex);
192ecb791c15008191f75be7a7e747bb387530d16d2cushon    boolean read;
193ecb791c15008191f75be7a7e747bb387530d16d2cushon    switch (annotationType) {
194ecb791c15008191f75be7a7e747bb387530d16d2cushon      case "Ljava/lang/annotation/Retention;":
195ecb791c15008191f75be7a7e747bb387530d16d2cushon      case "Ljava/lang/annotation/Target;":
19686eb6f1c5b02fc461b47602de67551361f9d695fcushon      case "Ljava/lang/annotation/Repeatable;":
197ecb791c15008191f75be7a7e747bb387530d16d2cushon        read = true;
198ecb791c15008191f75be7a7e747bb387530d16d2cushon        break;
199ecb791c15008191f75be7a7e747bb387530d16d2cushon      default:
200ecb791c15008191f75be7a7e747bb387530d16d2cushon        read = false;
201ecb791c15008191f75be7a7e747bb387530d16d2cushon        break;
202ecb791c15008191f75be7a7e747bb387530d16d2cushon    }
203fe7450192ce5268d73f19b404ca8d454023b3569cushon    int numElementValuePairs = reader.u2();
204d01fe55c0e5007580f441eb336a14473e00b8f54cushon    ClassFile.AnnotationInfo result = null;
205fe7450192ce5268d73f19b404ca8d454023b3569cushon    for (int e = 0; e < numElementValuePairs; e++) {
206fe7450192ce5268d73f19b404ca8d454023b3569cushon      int elementNameIndex = reader.u2();
207fe7450192ce5268d73f19b404ca8d454023b3569cushon      String key = constantPool.utf8(elementNameIndex);
208ecb791c15008191f75be7a7e747bb387530d16d2cushon      boolean value = read && key.equals("value");
209fe7450192ce5268d73f19b404ca8d454023b3569cushon      ElementValue tmp = readElementValue(constantPool, value);
210fe7450192ce5268d73f19b404ca8d454023b3569cushon      if (tmp != null) {
211d01fe55c0e5007580f441eb336a14473e00b8f54cushon        result = new ClassFile.AnnotationInfo(annotationType, true, ImmutableMap.of(key, tmp));
212fe7450192ce5268d73f19b404ca8d454023b3569cushon      }
213fe7450192ce5268d73f19b404ca8d454023b3569cushon    }
214fe7450192ce5268d73f19b404ca8d454023b3569cushon    return result;
215fe7450192ce5268d73f19b404ca8d454023b3569cushon  }
216fe7450192ce5268d73f19b404ca8d454023b3569cushon
217fe7450192ce5268d73f19b404ca8d454023b3569cushon  /**
21886eb6f1c5b02fc461b47602de67551361f9d695fcushon   * Extracts the value of an annotation declaration meta-annotation, or else skips over the element
21986eb6f1c5b02fc461b47602de67551361f9d695fcushon   * value pair.
220fe7450192ce5268d73f19b404ca8d454023b3569cushon   */
221fe7450192ce5268d73f19b404ca8d454023b3569cushon  private ElementValue readElementValue(ConstantPoolReader constantPool, boolean value) {
222fe7450192ce5268d73f19b404ca8d454023b3569cushon    int tag = reader.u1();
223fe7450192ce5268d73f19b404ca8d454023b3569cushon    switch (tag) {
224fe7450192ce5268d73f19b404ca8d454023b3569cushon      case 'B':
225fe7450192ce5268d73f19b404ca8d454023b3569cushon      case 'C':
226fe7450192ce5268d73f19b404ca8d454023b3569cushon      case 'D':
227fe7450192ce5268d73f19b404ca8d454023b3569cushon      case 'F':
228fe7450192ce5268d73f19b404ca8d454023b3569cushon      case 'I':
229fe7450192ce5268d73f19b404ca8d454023b3569cushon      case 'J':
230fe7450192ce5268d73f19b404ca8d454023b3569cushon      case 'S':
231fe7450192ce5268d73f19b404ca8d454023b3569cushon      case 'Z':
232fe7450192ce5268d73f19b404ca8d454023b3569cushon      case 's':
233fe7450192ce5268d73f19b404ca8d454023b3569cushon        reader.u2(); // constValueIndex
234fe7450192ce5268d73f19b404ca8d454023b3569cushon        break;
235fe7450192ce5268d73f19b404ca8d454023b3569cushon      case 'e':
236fe7450192ce5268d73f19b404ca8d454023b3569cushon        {
237fe7450192ce5268d73f19b404ca8d454023b3569cushon          int typeNameIndex = reader.u2();
238fe7450192ce5268d73f19b404ca8d454023b3569cushon          int constNameIndex = reader.u2();
239fe7450192ce5268d73f19b404ca8d454023b3569cushon          if (value) {
240fe7450192ce5268d73f19b404ca8d454023b3569cushon            String typeName = constantPool.utf8(typeNameIndex);
241ecb791c15008191f75be7a7e747bb387530d16d2cushon            switch (typeName) {
242ecb791c15008191f75be7a7e747bb387530d16d2cushon              case "Ljava/lang/annotation/RetentionPolicy;":
243ecb791c15008191f75be7a7e747bb387530d16d2cushon              case "Ljava/lang/annotation/ElementType;":
244ecb791c15008191f75be7a7e747bb387530d16d2cushon                String constName = constantPool.utf8(constNameIndex);
245ecb791c15008191f75be7a7e747bb387530d16d2cushon                return new EnumConstValue(typeName, constName);
246ecb791c15008191f75be7a7e747bb387530d16d2cushon              default:
247ecb791c15008191f75be7a7e747bb387530d16d2cushon                break;
248fe7450192ce5268d73f19b404ca8d454023b3569cushon            }
249fe7450192ce5268d73f19b404ca8d454023b3569cushon          }
250fe7450192ce5268d73f19b404ca8d454023b3569cushon          break;
251fe7450192ce5268d73f19b404ca8d454023b3569cushon        }
252fe7450192ce5268d73f19b404ca8d454023b3569cushon      case 'c':
25386eb6f1c5b02fc461b47602de67551361f9d695fcushon        int classInfoIndex = reader.u2();
25486eb6f1c5b02fc461b47602de67551361f9d695fcushon        String className = constantPool.utf8(classInfoIndex);
25586eb6f1c5b02fc461b47602de67551361f9d695fcushon        return new ConstClassValue(className);
256fe7450192ce5268d73f19b404ca8d454023b3569cushon      case '@':
257fe7450192ce5268d73f19b404ca8d454023b3569cushon        readAnnotation(constantPool);
258fe7450192ce5268d73f19b404ca8d454023b3569cushon        break;
259fe7450192ce5268d73f19b404ca8d454023b3569cushon      case '[':
260fe7450192ce5268d73f19b404ca8d454023b3569cushon        {
261fe7450192ce5268d73f19b404ca8d454023b3569cushon          int numValues = reader.u2();
262ecb791c15008191f75be7a7e747bb387530d16d2cushon          if (value) {
263ecb791c15008191f75be7a7e747bb387530d16d2cushon            ImmutableList.Builder<ElementValue> elements = ImmutableList.builder();
264ecb791c15008191f75be7a7e747bb387530d16d2cushon            for (int i = 0; i < numValues; i++) {
265ecb791c15008191f75be7a7e747bb387530d16d2cushon              elements.add(readElementValue(constantPool, true));
266ecb791c15008191f75be7a7e747bb387530d16d2cushon            }
267ecb791c15008191f75be7a7e747bb387530d16d2cushon            return new ElementValue.ArrayValue(elements.build());
268ecb791c15008191f75be7a7e747bb387530d16d2cushon          } else {
269ecb791c15008191f75be7a7e747bb387530d16d2cushon            for (int i = 0; i < numValues; i++) {
270ecb791c15008191f75be7a7e747bb387530d16d2cushon              readElementValue(constantPool, false);
271ecb791c15008191f75be7a7e747bb387530d16d2cushon            }
272fe7450192ce5268d73f19b404ca8d454023b3569cushon          }
273fe7450192ce5268d73f19b404ca8d454023b3569cushon          break;
274fe7450192ce5268d73f19b404ca8d454023b3569cushon        }
275fe7450192ce5268d73f19b404ca8d454023b3569cushon      default:
27628fc0ccb690cad787da840572c73fd3e3311047dcushon        throw error("bad tag value %c", tag);
277fe7450192ce5268d73f19b404ca8d454023b3569cushon    }
278fe7450192ce5268d73f19b404ca8d454023b3569cushon    return null;
279fe7450192ce5268d73f19b404ca8d454023b3569cushon  }
280fe7450192ce5268d73f19b404ca8d454023b3569cushon
281fe7450192ce5268d73f19b404ca8d454023b3569cushon  /** Reads JVMS 4.6 method_infos. */
282d01fe55c0e5007580f441eb336a14473e00b8f54cushon  private List<ClassFile.MethodInfo> readMethods(ConstantPoolReader constantPool) {
283fe7450192ce5268d73f19b404ca8d454023b3569cushon    int methodsCount = reader.u2();
284d01fe55c0e5007580f441eb336a14473e00b8f54cushon    List<ClassFile.MethodInfo> methods = new ArrayList<>();
285fe7450192ce5268d73f19b404ca8d454023b3569cushon    for (int i = 0; i < methodsCount; i++) {
286fe7450192ce5268d73f19b404ca8d454023b3569cushon      int accessFlags = reader.u2();
287fe7450192ce5268d73f19b404ca8d454023b3569cushon      int nameIndex = reader.u2();
288fe7450192ce5268d73f19b404ca8d454023b3569cushon      String name = constantPool.utf8(nameIndex);
289fe7450192ce5268d73f19b404ca8d454023b3569cushon      int descriptorIndex = reader.u2();
290fe7450192ce5268d73f19b404ca8d454023b3569cushon      String desc = constantPool.utf8(descriptorIndex);
291fe7450192ce5268d73f19b404ca8d454023b3569cushon      int attributesCount = reader.u2();
292fe7450192ce5268d73f19b404ca8d454023b3569cushon      String signature = null;
293783f80f37ad70eba7fd4b5e11a34854724227bf6cushon      ImmutableList<String> exceptions = ImmutableList.of();
294fe7450192ce5268d73f19b404ca8d454023b3569cushon      for (int j = 0; j < attributesCount; j++) {
295fe7450192ce5268d73f19b404ca8d454023b3569cushon        String attributeName = constantPool.utf8(reader.u2());
296fe7450192ce5268d73f19b404ca8d454023b3569cushon        switch (attributeName) {
297fe7450192ce5268d73f19b404ca8d454023b3569cushon          case "Exceptions":
298fe7450192ce5268d73f19b404ca8d454023b3569cushon            exceptions = readExceptions(constantPool);
299fe7450192ce5268d73f19b404ca8d454023b3569cushon            break;
300fe7450192ce5268d73f19b404ca8d454023b3569cushon          case "Signature":
301fe7450192ce5268d73f19b404ca8d454023b3569cushon            signature = readSignature(constantPool);
302fe7450192ce5268d73f19b404ca8d454023b3569cushon            break;
303fe7450192ce5268d73f19b404ca8d454023b3569cushon          default:
304fe7450192ce5268d73f19b404ca8d454023b3569cushon            reader.skip(reader.u4());
305fe7450192ce5268d73f19b404ca8d454023b3569cushon            break;
306fe7450192ce5268d73f19b404ca8d454023b3569cushon        }
307fe7450192ce5268d73f19b404ca8d454023b3569cushon      }
308fe7450192ce5268d73f19b404ca8d454023b3569cushon      methods.add(
309d01fe55c0e5007580f441eb336a14473e00b8f54cushon          new ClassFile.MethodInfo(
310fe7450192ce5268d73f19b404ca8d454023b3569cushon              accessFlags,
311fe7450192ce5268d73f19b404ca8d454023b3569cushon              name,
312fe7450192ce5268d73f19b404ca8d454023b3569cushon              desc,
313fe7450192ce5268d73f19b404ca8d454023b3569cushon              signature,
314fe7450192ce5268d73f19b404ca8d454023b3569cushon              exceptions,
315fe7450192ce5268d73f19b404ca8d454023b3569cushon              null,
3163088f83b806b82d866d119e344da274105f42821cushon              ImmutableList.of(),
3173e5b0c401c8d93182e9f0ce6f0de81f7574f5acacushon              ImmutableList.of(),
3183d2df35d983a31bc7a68e1d76b7c71956f477871cushon              ImmutableList.of(),
3193088f83b806b82d866d119e344da274105f42821cushon              ImmutableList.of()));
320fe7450192ce5268d73f19b404ca8d454023b3569cushon    }
321fe7450192ce5268d73f19b404ca8d454023b3569cushon    return methods;
322fe7450192ce5268d73f19b404ca8d454023b3569cushon  }
323fe7450192ce5268d73f19b404ca8d454023b3569cushon
324fe7450192ce5268d73f19b404ca8d454023b3569cushon  /** Reads an Exceptions attribute. */
325783f80f37ad70eba7fd4b5e11a34854724227bf6cushon  private ImmutableList<String> readExceptions(ConstantPoolReader constantPool) {
326783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    ImmutableList.Builder<String> exceptions = ImmutableList.builder();
327fe7450192ce5268d73f19b404ca8d454023b3569cushon    reader.u4(); // length
328fe7450192ce5268d73f19b404ca8d454023b3569cushon    int numberOfExceptions = reader.u2();
329fe7450192ce5268d73f19b404ca8d454023b3569cushon    for (int exceptionIndex = 0; exceptionIndex < numberOfExceptions; exceptionIndex++) {
330fe7450192ce5268d73f19b404ca8d454023b3569cushon      exceptions.add(constantPool.classInfo(reader.u2()));
331fe7450192ce5268d73f19b404ca8d454023b3569cushon    }
332783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    return exceptions.build();
333fe7450192ce5268d73f19b404ca8d454023b3569cushon  }
334fe7450192ce5268d73f19b404ca8d454023b3569cushon
335fe7450192ce5268d73f19b404ca8d454023b3569cushon  /** Reads JVMS 4.5 field_infos. */
336d01fe55c0e5007580f441eb336a14473e00b8f54cushon  private List<ClassFile.FieldInfo> readFields(ConstantPoolReader constantPool) {
337fe7450192ce5268d73f19b404ca8d454023b3569cushon    int fieldsCount = reader.u2();
338d01fe55c0e5007580f441eb336a14473e00b8f54cushon    List<ClassFile.FieldInfo> fields = new ArrayList<>();
339fe7450192ce5268d73f19b404ca8d454023b3569cushon    for (int i = 0; i < fieldsCount; i++) {
340fe7450192ce5268d73f19b404ca8d454023b3569cushon      int accessFlags = reader.u2();
341fe7450192ce5268d73f19b404ca8d454023b3569cushon      int nameIndex = reader.u2();
342fe7450192ce5268d73f19b404ca8d454023b3569cushon      String name = constantPool.utf8(nameIndex);
343fe7450192ce5268d73f19b404ca8d454023b3569cushon      int descriptorIndex = reader.u2();
344fe7450192ce5268d73f19b404ca8d454023b3569cushon      String desc = constantPool.utf8(descriptorIndex);
345fe7450192ce5268d73f19b404ca8d454023b3569cushon      int attributesCount = reader.u2();
346fe7450192ce5268d73f19b404ca8d454023b3569cushon      Const.Value value = null;
347fe7450192ce5268d73f19b404ca8d454023b3569cushon      for (int j = 0; j < attributesCount; j++) {
348fe7450192ce5268d73f19b404ca8d454023b3569cushon        String attributeName = constantPool.utf8(reader.u2());
349fe7450192ce5268d73f19b404ca8d454023b3569cushon        switch (attributeName) {
350fe7450192ce5268d73f19b404ca8d454023b3569cushon          case "ConstantValue":
351fe7450192ce5268d73f19b404ca8d454023b3569cushon            reader.u4(); // length
352fe7450192ce5268d73f19b404ca8d454023b3569cushon            value = constantPool.constant(reader.u2());
353fe7450192ce5268d73f19b404ca8d454023b3569cushon            break;
354fe7450192ce5268d73f19b404ca8d454023b3569cushon          default:
355fe7450192ce5268d73f19b404ca8d454023b3569cushon            reader.skip(reader.u4());
356fe7450192ce5268d73f19b404ca8d454023b3569cushon            break;
357fe7450192ce5268d73f19b404ca8d454023b3569cushon        }
358fe7450192ce5268d73f19b404ca8d454023b3569cushon      }
359fe7450192ce5268d73f19b404ca8d454023b3569cushon      fields.add(
360d01fe55c0e5007580f441eb336a14473e00b8f54cushon          new ClassFile.FieldInfo(
361fe7450192ce5268d73f19b404ca8d454023b3569cushon              accessFlags,
362fe7450192ce5268d73f19b404ca8d454023b3569cushon              name,
363fe7450192ce5268d73f19b404ca8d454023b3569cushon              desc,
364fe7450192ce5268d73f19b404ca8d454023b3569cushon              /*signature*/ null,
365fe7450192ce5268d73f19b404ca8d454023b3569cushon              value,
3663e5b0c401c8d93182e9f0ce6f0de81f7574f5acacushon              ImmutableList.of(),
3673e5b0c401c8d93182e9f0ce6f0de81f7574f5acacushon              ImmutableList.of()));
368fe7450192ce5268d73f19b404ca8d454023b3569cushon    }
369fe7450192ce5268d73f19b404ca8d454023b3569cushon    return fields;
370fe7450192ce5268d73f19b404ca8d454023b3569cushon  }
371fe7450192ce5268d73f19b404ca8d454023b3569cushon}
372