1418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
2418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager// for details. All rights reserved. Use of this source code is governed by a
3418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager// BSD-style license that can be found in the LICENSE file.
4418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerpackage com.android.tools.r8.dex;
5418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
6418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport static com.android.tools.r8.utils.EncodedValueUtils.parseDouble;
7418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport static com.android.tools.r8.utils.EncodedValueUtils.parseFloat;
8418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport static com.android.tools.r8.utils.EncodedValueUtils.parseSigned;
9418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport static com.android.tools.r8.utils.EncodedValueUtils.parseUnsigned;
10418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
11f4a7dd77cef798fd0c3ef6d787f81f51297bd9a3Mads Agerimport com.android.tools.r8.Resource;
12418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.code.Instruction;
13418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.code.InstructionFactory;
14a60f2aa119b2ac6d5128683e6a98fd53334327f6Denis Vnukovimport com.android.tools.r8.graph.ClassKind;
15418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.Descriptor;
16418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexAccessFlags;
17418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexAnnotation;
18418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexAnnotationElement;
19418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexAnnotationSet;
20418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexAnnotationSetRefList;
21418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexCallSite;
22418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexClass;
23418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexCode;
24418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexCode.Try;
25418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexCode.TryHandler;
26418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexCode.TryHandler.TypeAddrPair;
27418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexDebugEvent;
28418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexDebugInfo;
29418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexEncodedAnnotation;
30418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexEncodedArray;
31418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexEncodedField;
32418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexEncodedMethod;
33418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexField;
34418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexItem;
35418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexItemFactory;
36418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexMemberAnnotation;
37418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexMemberAnnotation.DexFieldAnnotation;
38418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexMemberAnnotation.DexMethodAnnotation;
39418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexMemberAnnotation.DexParameterAnnotation;
40418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexMethod;
41418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexMethodHandle;
42418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexMethodHandle.MethodHandleType;
43418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexProto;
44418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexString;
45418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexType;
46418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexTypeList;
47418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexValue;
48418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexValue.DexValueMethodHandle;
49418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexValue.DexValueMethodType;
50127cf8f5c1c98d408526ee6895fc3911689c9ad2Mads Agerimport com.android.tools.r8.graph.DexValue.DexValueNull;
51418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexValue.DexValueString;
52418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.OffsetToObjectMapping;
53418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.logging.Log;
54b17bb8d16da782186a30dc935a3ff12dca8abb09Stephan Herhutimport it.unimi.dsi.fastutil.ints.Int2ObjectMap;
55b17bb8d16da782186a30dc935a3ff12dca8abb09Stephan Herhutimport it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
56418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.io.ByteArrayOutputStream;
57418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.io.IOException;
5890c1804c404872c83fdb5b53a6d45406321cff5fLars Bakimport java.io.InputStream;
59418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.nio.ShortBuffer;
60418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.nio.file.Path;
61418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.ArrayList;
62418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.Arrays;
63418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.Hashtable;
64418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.List;
65418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.function.Consumer;
66418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.function.Supplier;
67418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
68418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerpublic class DexFileReader {
69418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
70418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  final int NO_INDEX = -1;
71418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexFile file;
72418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private final Segment[] segments;
73418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private int[] stringIDs;
74a60f2aa119b2ac6d5128683e6a98fd53334327f6Denis Vnukov  private final ClassKind classKind;
75418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
76418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  public static Segment[] parseMapFrom(Path file) throws IOException {
7790c1804c404872c83fdb5b53a6d45406321cff5fLars Bak    return parseMapFrom(new DexFile(file.toString()));
7890c1804c404872c83fdb5b53a6d45406321cff5fLars Bak  }
7990c1804c404872c83fdb5b53a6d45406321cff5fLars Bak
8090c1804c404872c83fdb5b53a6d45406321cff5fLars Bak  public static Segment[] parseMapFrom(InputStream stream) throws IOException {
8190c1804c404872c83fdb5b53a6d45406321cff5fLars Bak    return parseMapFrom(new DexFile(stream));
8290c1804c404872c83fdb5b53a6d45406321cff5fLars Bak  }
8390c1804c404872c83fdb5b53a6d45406321cff5fLars Bak
8490c1804c404872c83fdb5b53a6d45406321cff5fLars Bak  private static Segment[] parseMapFrom(DexFile dex) throws IOException {
8590c1804c404872c83fdb5b53a6d45406321cff5fLars Bak    DexFileReader reader = new DexFileReader(dex, ClassKind.PROGRAM, new DexItemFactory());
8690c1804c404872c83fdb5b53a6d45406321cff5fLars Bak    return reader.segments;
87418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
88418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
89418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  public void close() {
90418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    // This close behavior is needed to reduce peak memory usage of D8/R8.
91418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    indexedItems = null;
92418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    codes = null;
93418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    offsetMap = null;
94418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    file = null;
95418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    stringIDs = null;
96418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
97418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
98418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  // Mapping from indexes to indexable dex items.
99418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private OffsetToObjectMapping indexedItems = new OffsetToObjectMapping();
100418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
101418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  // Mapping from offset to code item;
102b17bb8d16da782186a30dc935a3ff12dca8abb09Stephan Herhut  private Int2ObjectMap<DexCode> codes = new Int2ObjectOpenHashMap<>();
103418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
104418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  // Mapping from offset to dex item;
105b17bb8d16da782186a30dc935a3ff12dca8abb09Stephan Herhut  private Int2ObjectMap<Object> offsetMap = new Int2ObjectOpenHashMap<>();
106418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
107418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  // Factory to canonicalize certain dexitems.
108418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private final DexItemFactory dexItemFactory;
109418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
110a60f2aa119b2ac6d5128683e6a98fd53334327f6Denis Vnukov  public DexFileReader(DexFile file, ClassKind classKind, DexItemFactory dexItemFactory) {
111418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    this.file = file;
112418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    this.dexItemFactory = dexItemFactory;
113418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    file.setByteOrder();
114418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    segments = parseMap();
115418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    parseStringIDs();
116a60f2aa119b2ac6d5128683e6a98fd53334327f6Denis Vnukov    this.classKind = classKind;
117418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
118418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
119418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  public OffsetToObjectMapping getIndexedItemsMap() {
120418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return indexedItems;
121418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
122418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
123418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  void addCodeItemsTo() {
124a60f2aa119b2ac6d5128683e6a98fd53334327f6Denis Vnukov    if (classKind == ClassKind.LIBRARY) {
125418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      // Ignore contents of library files.
126418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      return;
127418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
128418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Segment segment = lookupSegment(Constants.TYPE_CODE_ITEM);
12924e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    if (segment.length == 0) {
130418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      return;
131418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
132418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    file.position(segment.offset);
13324e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    for (int i = 0; i < segment.length; i++) {
134418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      file.align(4);  // code items are 4 byte aligned.
135418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      int offset = file.position();
136418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexCode code = parseCodeItem();
137418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      codes.put(offset, code);  // Update the file local offset to code mapping.
138418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
139418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
140418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
141418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexTypeList parseTypeList() {
142418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexType[] result = new DexType[file.getUint()];
143418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int j = 0; j < result.length; j++) {
144418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      result[j] = indexedItems.getType(file.getUshort());
145418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
146418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return new DexTypeList(result);
147418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
148418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
149418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexTypeList typeListAt(int offset) {
150b17bb8d16da782186a30dc935a3ff12dca8abb09Stephan Herhut    if (offset == 0) {
151b17bb8d16da782186a30dc935a3ff12dca8abb09Stephan Herhut      return DexTypeList.empty();
152b17bb8d16da782186a30dc935a3ff12dca8abb09Stephan Herhut    }
153418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return (DexTypeList) cacheAt(offset, this::parseTypeList);
154418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
155418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
156418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  public DexValue parseEncodedValue() {
157418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int header = file.get() & 0xff;
158418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int valueArg = header >> 5;
159418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int valueType = header & 0x1f;
160418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    switch (valueType) {
161418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case DexValue.VALUE_BYTE: {
162418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        assert valueArg == 0;
163418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        byte value = (byte) parseSigned(file, 1);
164418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return DexValue.DexValueByte.create(value);
165418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
166418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case DexValue.VALUE_SHORT: {
167418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int size = valueArg + 1;
168418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        short value = (short) parseSigned(file, size);
169418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return DexValue.DexValueShort.create(value);
170418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
171418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case DexValue.VALUE_CHAR: {
172418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int size = valueArg + 1;
173418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        char value = (char) parseUnsigned(file, size);
174418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return DexValue.DexValueChar.create(value);
175418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
176418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case DexValue.VALUE_INT: {
177418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int size = valueArg + 1;
178418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int value = (int) parseSigned(file, size);
179418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return DexValue.DexValueInt.create(value);
180418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
181418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case DexValue.VALUE_LONG: {
182418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int size = valueArg + 1;
183418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        long value = parseSigned(file, size);
184418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return DexValue.DexValueLong.create(value);
185418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
186418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case DexValue.VALUE_FLOAT: {
187418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int size = valueArg + 1;
188418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return DexValue.DexValueFloat.create(parseFloat(file, size));
189418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
190418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case DexValue.VALUE_DOUBLE: {
191418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int size = valueArg + 1;
192418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return DexValue.DexValueDouble.create(parseDouble(file, size));
193418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
194418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case DexValue.VALUE_STRING: {
195418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int size = valueArg + 1;
196418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int index = (int) parseUnsigned(file, size);
197418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        DexString value = indexedItems.getString(index);
198418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return new DexValue.DexValueString(value);
199418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
200418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case DexValue.VALUE_TYPE: {
201418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int size = valueArg + 1;
202418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        DexType value = indexedItems.getType((int) parseUnsigned(file, size));
203418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return new DexValue.DexValueType(value);
204418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
205418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case DexValue.VALUE_FIELD: {
206418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int size = valueArg + 1;
207418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        DexField value = indexedItems.getField((int) parseUnsigned(file, size));
208418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return new DexValue.DexValueField(value);
209418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
210418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case DexValue.VALUE_METHOD: {
211418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int size = valueArg + 1;
212418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        DexMethod value = indexedItems.getMethod((int) parseUnsigned(file, size));
213418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return new DexValue.DexValueMethod(value);
214418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
215418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case DexValue.VALUE_ENUM: {
216418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int size = valueArg + 1;
217418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        DexField value = indexedItems.getField((int) parseUnsigned(file, size));
218418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return new DexValue.DexValueEnum(value);
219418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
220418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case DexValue.VALUE_ARRAY: {
221418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        assert valueArg == 0;
222418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return new DexValue.DexValueArray(parseEncodedArrayValues());
223418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
224418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case DexValue.VALUE_ANNOTATION: {
225418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        assert valueArg == 0;
226418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return new DexValue.DexValueAnnotation(parseEncodedAnnotation());
227418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
228418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case DexValue.VALUE_NULL: {
229418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        assert valueArg == 0;
230127cf8f5c1c98d408526ee6895fc3911689c9ad2Mads Ager        return DexValueNull.NULL;
231418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
232418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case DexValue.VALUE_BOOLEAN: {
233418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        // 0 is false, and 1 is true.
234418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return DexValue.DexValueBoolean.create(valueArg != 0);
235418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
236418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case DexValue.VALUE_METHOD_TYPE: {
237418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int size = valueArg + 1;
238418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        DexProto value = indexedItems.getProto((int) parseUnsigned(file, size));
239418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return new DexValue.DexValueMethodType(value);
240418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
241418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case DexValue.VALUE_METHOD_HANDLE: {
242418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int size = valueArg + 1;
243418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        DexMethodHandle value = indexedItems.getMethodHandle((int) parseUnsigned(file, size));
244418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return new DexValue.DexValueMethodHandle(value);
245418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
246418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      default:
247418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        throw new IndexOutOfBoundsException();
248418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
249418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
250418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
251418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexEncodedAnnotation parseEncodedAnnotation() {
252418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int typeIdx = file.getUleb128();
253418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int size = file.getUleb128();
254418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexAnnotationElement[] elements = new DexAnnotationElement[size];
255418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < size; i++) {
256418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      int nameIdx = file.getUleb128();
257418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexValue value = parseEncodedValue();
258418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      elements[i] = new DexAnnotationElement(indexedItems.getString(nameIdx), value);
259418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
260418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return new DexEncodedAnnotation(indexedItems.getType(typeIdx), elements);
261418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
262418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
263418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexValue[] parseEncodedArrayValues() {
264418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int size = file.getUleb128();
265418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexValue[] values = new DexValue[size];
266418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < size; i++) {
267418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      values[i] = parseEncodedValue();
268418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
269418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return values;
270418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
271418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
272418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
273418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexEncodedArray parseEncodedArray() {
274418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return new DexEncodedArray(parseEncodedArrayValues());
275418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
276418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
277418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexEncodedArray encodedArrayAt(int offset) {
278418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return (DexEncodedArray) cacheAt(offset, this::parseEncodedArray);
279418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
280418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
281418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexFieldAnnotation[] parseFieldAnnotations(int size) {
282418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    if (size == 0) {
283418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      return null;
284418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
285418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int[] fieldIndices = new int[size];
286418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int[] annotationOffsets = new int[size];
287418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < size; i++) {
288418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      fieldIndices[i] = file.getUint();
289418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      annotationOffsets[i] = file.getUint();
290418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
291418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int saved = file.position();
292418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexFieldAnnotation[] result = new DexFieldAnnotation[size];
293418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < size; i++) {
294418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexField field = indexedItems.getField(fieldIndices[i]);
295418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexAnnotationSet annotation = annotationSetAt(annotationOffsets[i]);
296418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      result[i] = new DexFieldAnnotation(field, annotation);
297418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
298418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    file.position(saved);
299418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return result;
300418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
301418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
302418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexMethodAnnotation[] parseMethodAnnotations(int size) {
303418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    if (size == 0) {
304418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      return null;
305418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
306418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int[] methodIndices = new int[size];
307418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int[] annotationOffsets = new int[size];
308418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < size; i++) {
309418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      methodIndices[i] = file.getUint();
310418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      annotationOffsets[i] = file.getUint();
311418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
312418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int saved = file.position();
313418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexMethodAnnotation[] result = new DexMethodAnnotation[size];
314418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < size; i++) {
315418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexMethod method = indexedItems.getMethod(methodIndices[i]);
316418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexAnnotationSet annotation = annotationSetAt(annotationOffsets[i]);
317418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      result[i] = new DexMethodAnnotation(method, annotation);
318418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
319418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    file.position(saved);
320418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return result;
321418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
322418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
323418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexAnnotationSetRefList annotationSetRefListAt(int offset) {
324418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return (DexAnnotationSetRefList) cacheAt(offset, this::parseAnnotationSetRefList);
325418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
326418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
327418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexAnnotationSetRefList parseAnnotationSetRefList() {
328418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int size = file.getUint();
329418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int[] annotationOffsets = new int[size];
330418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < size; i++) {
331418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      annotationOffsets[i] = file.getUint();
332418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
333418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexAnnotationSet[] values = new DexAnnotationSet[size];
334418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < size; i++) {
335418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      values[i] = annotationSetAt(annotationOffsets[i]);
336418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
337418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return new DexAnnotationSetRefList(values);
338418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
339418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
340418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexParameterAnnotation[] parseParameterAnnotations(int size) {
341418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    if (size == 0) {
342418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      return null;
343418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
344418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int[] methodIndices = new int[size];
345418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int[] annotationOffsets = new int[size];
346418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < size; i++) {
347418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      methodIndices[i] = file.getUint();
348418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      annotationOffsets[i] = file.getUint();
349418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
350418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int saved = file.position();
351418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexParameterAnnotation[] result = new DexParameterAnnotation[size];
352418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < size; i++) {
353418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexMethod method = indexedItems.getMethod(methodIndices[i]);
354418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      result[i] = new DexParameterAnnotation(
355418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          method,
356418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          annotationSetRefListAt(annotationOffsets[i]));
357418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
358418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    file.position(saved);
359418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return result;
360418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
361418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
362418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private <T> Object cacheAt(int offset, Supplier<T> function, Supplier<T> defaultValue) {
363418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    if (offset == 0) {
364418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      return defaultValue.get();
365418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
366418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return cacheAt(offset, function);
367418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
368418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
369418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private <T> Object cacheAt(int offset, Supplier<T> function) {
370b17bb8d16da782186a30dc935a3ff12dca8abb09Stephan Herhut    if (offset == 0) {
371b17bb8d16da782186a30dc935a3ff12dca8abb09Stephan Herhut      return null;  // return null for offset zero.
372b17bb8d16da782186a30dc935a3ff12dca8abb09Stephan Herhut    }
373418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Object result = offsetMap.get(offset);
374b17bb8d16da782186a30dc935a3ff12dca8abb09Stephan Herhut    if (result != null) {
375b17bb8d16da782186a30dc935a3ff12dca8abb09Stephan Herhut      return result;  // return the cached result.
376b17bb8d16da782186a30dc935a3ff12dca8abb09Stephan Herhut    }
377418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    // Cache is empty so parse the structure.
378418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    file.position(offset);
379418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    result = function.get();
380418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    // Update the map.
381418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    offsetMap.put(offset, result);
382418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    assert offsetMap.get(offset) == result;
383418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return result;
384418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
385418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
386418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexAnnotation parseAnnotation() {
387418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    if (Log.ENABLED) {
388418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      Log.verbose(getClass(), "Reading Annotation @ 0x%08x.", file.position());
389418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
390418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int visibility = file.get();
391418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return new DexAnnotation(visibility, parseEncodedAnnotation());
392418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
393418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
394418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexAnnotation annotationAt(int offset) {
395418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return (DexAnnotation) cacheAt(offset, this::parseAnnotation);
396418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
397418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
398418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexAnnotationSet parseAnnotationSet() {
399418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    if (Log.ENABLED) {
400418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      Log.verbose(getClass(), "Reading AnnotationSet @ 0x%08x.", file.position());
401418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
402418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int size = file.getUint();
403418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int[] annotationOffsets = new int[size];
404418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < size; i++) {
405418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      annotationOffsets[i] = file.getUint();
406418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
407418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexAnnotation[] result = new DexAnnotation[size];
408418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < size; i++) {
409418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      result[i] = annotationAt(annotationOffsets[i]);
410418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
411418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return new DexAnnotationSet(result);
412418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
413418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
414418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexAnnotationSet annotationSetAt(int offset) {
415418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return (DexAnnotationSet) cacheAt(offset, this::parseAnnotationSet, DexAnnotationSet::empty);
416418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
417418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
418418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private AnnotationsDirectory annotationsDirectoryAt(int offset) {
419418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return (AnnotationsDirectory) cacheAt(offset, this::parseAnnotationsDirectory,
420418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        AnnotationsDirectory::empty);
421418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
422418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
423418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private AnnotationsDirectory parseAnnotationsDirectory() {
424418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int classAnnotationsOff = file.getUint();
425418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int fieldsSize = file.getUint();
426418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int methodsSize = file.getUint();
427418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int parametersSize = file.getUint();
428418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    final DexFieldAnnotation[] fields = parseFieldAnnotations(fieldsSize);
429418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    final DexMethodAnnotation[] methods = parseMethodAnnotations(methodsSize);
430418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    final DexParameterAnnotation[] parameters = parseParameterAnnotations(parametersSize);
431418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return new AnnotationsDirectory(
432418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        annotationSetAt(classAnnotationsOff),
433418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        fields,
434418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        methods,
435418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        parameters);
436418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
437418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
438418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexDebugInfo debugInfoAt(int offset) {
439418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return (DexDebugInfo) cacheAt(offset, this::parseDebugInfo);
440418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
441418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
442418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexDebugInfo parseDebugInfo() {
443418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int start = file.getUleb128();
444418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int parametersSize = file.getUleb128();
445418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexString[] parameters = new DexString[parametersSize];
446418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < parametersSize; i++) {
447418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      int index = file.getUleb128p1();
448418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      if (index != NO_INDEX) {
449418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        parameters[i] = indexedItems.getString(index);
450418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
451418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
452418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    List<DexDebugEvent> events = new ArrayList<>();
453418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int head = file.getUbyte(); head != Constants.DBG_END_SEQUENCE; head = file.getUbyte()) {
454418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      switch (head) {
455418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        case Constants.DBG_ADVANCE_PC:
45639cdb4cb692e28fb956bef615546f4899861f901Alan Leung          events.add(dexItemFactory.createAdvancePC(file.getUleb128()));
457418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          break;
458418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        case Constants.DBG_ADVANCE_LINE:
45939cdb4cb692e28fb956bef615546f4899861f901Alan Leung          events.add(dexItemFactory.createAdvanceLine(file.getSleb128()));
460418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          break;
461418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        case Constants.DBG_START_LOCAL: {
462418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          int registerNum = file.getUleb128();
463418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          int nameIdx = file.getUleb128p1();
464418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          int typeIdx = file.getUleb128p1();
465418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          events.add(new DexDebugEvent.StartLocal(
466418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager              registerNum,
467418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager              nameIdx == NO_INDEX ? null : indexedItems.getString(nameIdx),
468418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager              typeIdx == NO_INDEX ? null : indexedItems.getType(typeIdx),
469418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager              null));
470418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          break;
471418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        }
472418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        case Constants.DBG_START_LOCAL_EXTENDED: {
473418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          int registerNum = file.getUleb128();
474418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          int nameIdx = file.getUleb128p1();
475418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          int typeIdx = file.getUleb128p1();
476418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          int sigIdx = file.getUleb128p1();
477418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          events.add(new DexDebugEvent.StartLocal(
478418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager              registerNum,
479418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager              nameIdx == NO_INDEX ? null : indexedItems.getString(nameIdx),
480418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager              typeIdx == NO_INDEX ? null : indexedItems.getType(typeIdx),
481418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager              sigIdx == NO_INDEX ? null : indexedItems.getString(sigIdx)));
482418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          break;
483418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        }
484418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        case Constants.DBG_END_LOCAL: {
48539cdb4cb692e28fb956bef615546f4899861f901Alan Leung          events.add(dexItemFactory.createEndLocal(file.getUleb128()));
486418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          break;
487418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        }
488418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        case Constants.DBG_RESTART_LOCAL: {
48939cdb4cb692e28fb956bef615546f4899861f901Alan Leung          events.add(dexItemFactory.createRestartLocal(file.getUleb128()));
490418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          break;
491418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        }
492418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        case Constants.DBG_SET_PROLOGUE_END: {
49339cdb4cb692e28fb956bef615546f4899861f901Alan Leung          events.add(dexItemFactory.createSetPrologueEnd());
494418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          break;
495418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        }
496418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        case Constants.DBG_SET_EPILOGUE_BEGIN: {
49739cdb4cb692e28fb956bef615546f4899861f901Alan Leung          events.add(dexItemFactory.createSetEpilogueBegin());
498418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          break;
499418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        }
500418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        case Constants.DBG_SET_FILE: {
501418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          int nameIdx = file.getUleb128p1();
502418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          DexString sourceFile = nameIdx == NO_INDEX ? null : indexedItems.getString(nameIdx);
50339cdb4cb692e28fb956bef615546f4899861f901Alan Leung          events.add(dexItemFactory.createSetFile(sourceFile));
504418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          break;
505418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        }
506418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        default: {
507418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          assert head >= 0x0a && head <= 0xff;
50839cdb4cb692e28fb956bef615546f4899861f901Alan Leung          events.add(dexItemFactory.createDefault(head));
509418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        }
510418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
511418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
512418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return new DexDebugInfo(start, parameters, events.toArray(new DexDebugEvent[events.size()]));
513418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
514418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
515418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private static class MemberAnnotationIterator<S extends Descriptor<?, S>, T extends DexItem> {
516418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
517418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    private int index = 0;
518418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    private final DexMemberAnnotation<S, T>[] annotations;
519418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    private final Supplier<T> emptyValue;
520418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
521418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    private MemberAnnotationIterator(DexMemberAnnotation<S, T>[] annotations,
522418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        Supplier<T> emptyValue) {
523418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      this.annotations = annotations;
524418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      this.emptyValue = emptyValue;
525418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
526418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
527418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    // Get the annotation set for an item. This method assumes that it is always called with
528418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    // an item that is higher in the sorting order than the last item.
529418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    T getNextFor(S item) {
530418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      // TODO(ager): We could use the indices from the file to make this search faster using
531418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      // compareTo instead of slowCompareTo. That would require us to assign indices during
532418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      // reading. Those indices should be cleared after reading to make sure that we resort
533418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      // everything correctly at the end.
534418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      while (index < annotations.length && annotations[index].item.slowCompareTo(item) < 0) {
535418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        index++;
536418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
537418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      if (index >= annotations.length || !annotations[index].item.equals(item)) {
538418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return emptyValue.get();
539418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
540418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      return annotations[index].annotations;
541418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
542418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
543418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
544418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexEncodedField[] readFields(int size, DexFieldAnnotation[] annotations,
545418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexValue[] staticValues) {
546418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexEncodedField[] fields = new DexEncodedField[size];
547418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int fieldIndex = 0;
548418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    MemberAnnotationIterator<DexField, DexAnnotationSet> annotationIterator =
549418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        new MemberAnnotationIterator<>(annotations, DexAnnotationSet::empty);
550418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < size; i++) {
551418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      fieldIndex += file.getUleb128();
552418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexField field = indexedItems.getField(fieldIndex);
553418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexAccessFlags accessFlags = new DexAccessFlags(file.getUleb128());
554418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexAnnotationSet fieldAnnotations = annotationIterator.getNextFor(field);
555418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexValue staticValue = null;
556418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      if (accessFlags.isStatic()) {
557418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        if (staticValues != null && i < staticValues.length) {
558418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          staticValue = staticValues[i];
559418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        } else {
560418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          staticValue = DexValue.defaultForType(field.type, dexItemFactory);
561418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        }
562418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
563418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      fields[i] = new DexEncodedField(field, accessFlags, fieldAnnotations, staticValue);
564418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
565418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return fields;
566418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
567418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
568418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexEncodedMethod[] readMethods(int size, DexMethodAnnotation[] annotations,
569418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexParameterAnnotation[] parameters, boolean skipCodes) {
570418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexEncodedMethod[] methods = new DexEncodedMethod[size];
571418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int methodIndex = 0;
572418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    MemberAnnotationIterator<DexMethod, DexAnnotationSet> annotationIterator =
573418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        new MemberAnnotationIterator<>(annotations, DexAnnotationSet::empty);
574418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    MemberAnnotationIterator<DexMethod, DexAnnotationSetRefList> parameterAnnotationsIterator =
575418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        new MemberAnnotationIterator<>(parameters, DexAnnotationSetRefList::empty);
576418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < size; i++) {
577418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      methodIndex += file.getUleb128();
578418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexAccessFlags accessFlags = new DexAccessFlags(file.getUleb128());
579418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      int codeOff = file.getUleb128();
580418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexCode code = null;
581418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      if (!skipCodes) {
582418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        assert codeOff == 0 || codes.get(codeOff) != null;
583418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        code = codes.get(codeOff);
584418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
585418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexMethod method = indexedItems.getMethod(methodIndex);
586418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      methods[i] = new DexEncodedMethod(method, accessFlags, annotationIterator.getNextFor(method),
587418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          parameterAnnotationsIterator.getNextFor(method), code);
588418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
589418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return methods;
590418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
591418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
592418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  void addClassDefsTo(Consumer<DexClass> classCollection) {
593418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    final Segment segment = lookupSegment(Constants.TYPE_CLASS_DEF_ITEM);
59424e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    final int length = segment.length;
59524e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    indexedItems.initializeClasses(length);
59624e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    if (length == 0) {
597418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      return;
598418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
599418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    file.position(segment.offset);
600418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
60124e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    int[] classIndices = new int[length];
60224e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    int[] accessFlags = new int[length];
60324e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    int[] superclassIndices = new int[length];
60424e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    int[] interfacesOffsets = new int[length];
60524e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    int[] sourceFileIndices = new int[length];
60624e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    int[] annotationsOffsets = new int[length];
60724e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    int[] classDataOffsets = new int[length];
60824e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    int[] staticValuesOffsets = new int[length];
609418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
61024e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    for (int i = 0; i < length; i++) {
611418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      if (Log.ENABLED) {
612418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        Log.verbose(getClass(), "Reading ClassDef @ 0x%08x.", file.position());
613418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
614418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      classIndices[i] = file.getUint();
615418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      accessFlags[i] = file.getUint();
616418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      superclassIndices[i] = file.getInt();
617418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      interfacesOffsets[i] = file.getUint();
618418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      sourceFileIndices[i] = file.getInt();
619418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      annotationsOffsets[i] = file.getUint();
620418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      classDataOffsets[i] = file.getUint();
621418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      staticValuesOffsets[i] = file.getUint();
622418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
623418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
62424e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    for (int i = 0; i < length; i++) {
625418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      int superclassIdx = superclassIndices[i];
626418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexType superclass = superclassIdx == NO_INDEX ? null : indexedItems.getType(superclassIdx);
627418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      int srcIdx = sourceFileIndices[i];
628418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexString source = srcIdx == NO_INDEX ? null : indexedItems.getString(srcIdx);
629418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      // fix annotations.
630418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexType type = indexedItems.getType(classIndices[i]);
631418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexAccessFlags flags = new DexAccessFlags(accessFlags[i]);
632418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexClass clazz;
633418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexEncodedField[] staticFields = DexEncodedField.EMPTY_ARRAY;
634418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexEncodedField[] instanceFields = DexEncodedField.EMPTY_ARRAY;
635418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexEncodedMethod[] directMethods = DexEncodedMethod.EMPTY_ARRAY;
636418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      DexEncodedMethod[] virtualMethods = DexEncodedMethod.EMPTY_ARRAY;
637418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      AnnotationsDirectory annotationsDirectory = annotationsDirectoryAt(annotationsOffsets[i]);
638418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      if (classDataOffsets[i] != 0) {
639418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        DexEncodedArray staticValues = encodedArrayAt(staticValuesOffsets[i]);
640418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
641418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        file.position(classDataOffsets[i]);
642418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int staticFieldsSize = file.getUleb128();
643418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int instanceFieldsSize = file.getUleb128();
644418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int directMethodsSize = file.getUleb128();
645418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int virtualMethodsSize = file.getUleb128();
646418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
647418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        staticFields = readFields(staticFieldsSize, annotationsDirectory.fields,
648418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager            staticValues != null ? staticValues.values : null);
649418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        instanceFields = readFields(instanceFieldsSize, annotationsDirectory.fields, null);
650418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        directMethods =
651418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager            readMethods(
652418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager                directMethodsSize,
653418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager                annotationsDirectory.methods,
654418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager                annotationsDirectory.parameters,
655a60f2aa119b2ac6d5128683e6a98fd53334327f6Denis Vnukov                classKind != ClassKind.PROGRAM);
656418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        virtualMethods =
657418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager            readMethods(
658418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager                virtualMethodsSize,
659418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager                annotationsDirectory.methods,
660418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager                annotationsDirectory.parameters,
661a60f2aa119b2ac6d5128683e6a98fd53334327f6Denis Vnukov                classKind != ClassKind.PROGRAM);
662418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
663a60f2aa119b2ac6d5128683e6a98fd53334327f6Denis Vnukov      clazz = classKind.create(
664418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          type,
665a60f2aa119b2ac6d5128683e6a98fd53334327f6Denis Vnukov          Resource.Kind.DEX,
666418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          flags,
667418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          superclass,
668418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          typeListAt(interfacesOffsets[i]),
669418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          source,
670418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          annotationsDirectory.clazz,
671418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          staticFields,
672418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          instanceFields,
673418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          directMethods,
674418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          virtualMethods);
675418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      classCollection.accept(clazz);  // Update the application object.
676418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
677418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
678418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
679418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private void parseStringIDs() {
680418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Segment segment = lookupSegment(Constants.TYPE_STRING_ID_ITEM);
68124e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    stringIDs = new int[segment.length];
68224e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    if (segment.length == 0) {
683418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      return;
684418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
685418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    file.position(segment.offset);
68624e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    for (int i = 0; i < segment.length; i++) {
687418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      stringIDs[i] = file.getUint();
688418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
689418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
690418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
691418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private Segment lookupSegment(int type) {
692418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (Segment s : segments) {
693418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      if (s.type == type) {
694418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        return s;
695418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
696418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
697418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    // If the segment doesn't exist, return an empty segment of this type.
698418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return new Segment(type, 0, 0, 0);
699418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
700418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
701418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private Segment[] parseMap() {
702418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    // Read the segments information from the MAP.
703418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int mapOffset = file.getUint(Constants.MAP_OFF_OFFSET);
704418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    file.position(mapOffset);
705418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int mapSize = file.getUint();
706418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    final Segment[] result = new Segment[mapSize];
707418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < mapSize; i++) {
708418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      int type = file.getUshort();
709418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      int unused = file.getUshort();
710418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      int size = file.getUint();
711418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      int offset = file.getUint();
712418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      result[i] = new Segment(type, unused, size, offset);
713418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
714418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    if (Log.ENABLED) {
715418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      for (int i = 0; i < result.length; i++) {
716418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        Segment segment = result[i];
717418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int nextOffset = i < result.length - 1 ? result[i + 1].offset : segment.offset;
718418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        Log.debug(this.getClass(), "Read segment 0x%04x @ 0x%08x #items %08d size 0x%08x.",
71924e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak            segment.type, segment.offset, segment.length, nextOffset - segment.offset);
720418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
721418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
722418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < mapSize - 1; i++) {
723418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      result[i].setEnd(result[i + 1].offset);
724418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
725418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    result[mapSize - 1].setEnd(file.end());
726418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return result;
727418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
728418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
729418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexCode parseCodeItem() {
730418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int registerSize = file.getUshort();
731418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int insSize = file.getUshort();
732418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int outsSize = file.getUshort();
733418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int triesSize = file.getUshort();
734418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int debugInfoOff = file.getUint();
735418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int insnsSize = file.getUint();
736418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    short[] code = new short[insnsSize];
737418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Try[] tries = new Try[triesSize];
738418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexCode.TryHandler[] handlers = null;
739418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
740418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    if (insnsSize != 0) {
741418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      for (int i = 0; i < insnsSize; i++) {
742418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        code[i] = file.getShort();
743418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
744418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      if (insnsSize % 2 != 0) {
745418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        file.getUshort();  // Skip padding ushort
746418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
747418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      if (triesSize > 0) {
748418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        Hashtable<Integer, Integer> handlerMap = new Hashtable<>();
749418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        // tries: try_item[tries_size].
750418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        for (int i = 0; i < triesSize; i++) {
751418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          int startAddr = file.getUint();
752418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          int insnCount = file.getUshort();
753418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          int handlerOff = file.getUshort();
754418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          tries[i] = new Try(startAddr, insnCount, handlerOff);
755418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        }
756418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        // handlers: encoded_catch_handler_list
757418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int encodedCatchHandlerListPosition = file.position();
758418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        // - size: uleb128
759418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        int size = file.getUleb128();
760418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        handlers = new TryHandler[size];
761418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        // - list: encoded_catch_handler[handlers_size]
762418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        for (int i = 0; i < size; i++) {
763418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          // encoded_catch_handler
764418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          int encodedCatchHandlerOffset = file.position() - encodedCatchHandlerListPosition;
765418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          handlerMap.put(encodedCatchHandlerOffset, i);
766418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          // - size:	sleb128
767418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          int hsize = file.getSleb128();
768418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          int realHsize = Math.abs(hsize);
769418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          // - handlers	encoded_type_addr_pair[abs(size)]
770418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          TryHandler.TypeAddrPair pairs[] = new TryHandler.TypeAddrPair[realHsize];
771418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          for (int j = 0; j < realHsize; j++) {
772418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager            int typeIdx = file.getUleb128();
773418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager            int addr = file.getUleb128();
774418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager            pairs[j] = new TypeAddrPair(indexedItems.getType(typeIdx), addr,
775418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager                encodedCatchHandlerOffset);
776418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          }
777418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          int catchAllAddr = -1;
778418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          if (hsize <= 0) {
779418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager            catchAllAddr = file.getUleb128();
780418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          }
781418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          handlers[i] = new TryHandler(pairs, catchAllAddr);
782418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        }
783418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        // Convert the handler offsets inside the Try objects to indexes.
784418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        for (Try t : tries) {
785418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager          t.setHandlerIndex(handlerMap);
786418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        }
787418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
788418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
789418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    // Store and restore offset information around reading debug info.
790418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int saved = file.position();
791418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexDebugInfo debugInfo = debugInfoAt(debugInfoOff);
792418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    file.position(saved);
793418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    InstructionFactory factory = new InstructionFactory();
794418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Instruction[] instructions =
795418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        factory.readSequenceFrom(ShortBuffer.wrap(code), 0, code.length, indexedItems);
796418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return new DexCode(
797418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        registerSize,
798418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        insSize,
799418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        outsSize,
800418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        instructions,
801418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        tries,
802418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        handlers,
803418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        debugInfo,
804418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        factory.getHighestSortingString());
805418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
806418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
807418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  static void populateIndexTables(DexFileReader fileReader) {
808418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    // Populate structures that are already sorted upon read.
809418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexFileReader.populateStrings(fileReader);  // Depends on nothing.
810418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexFileReader.populateTypes(fileReader);  // Depends on Strings.
811418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexFileReader.populateFields(fileReader);  // Depends on Types, and Strings.
812418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexFileReader.populateProtos(fileReader);  // Depends on Types and Strings.
813418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexFileReader.populateMethods(fileReader);  // Depends on Protos, Types, and Strings.
814418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexFileReader.populateMethodHandles(fileReader); // Depends on Methods and Fields
815418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexFileReader.populateCallSites(fileReader); // Depends on MethodHandles
816418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
817418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
818418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private static void populateStrings(DexFileReader reader) {
819418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    reader.indexedItems.initializeStrings(reader.stringIDs.length);
820418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < reader.stringIDs.length; i++) {
821418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      reader.indexedItems.setString(i, reader.stringAt(i));
822418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
823418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
824418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
825418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private static void populateMethodHandles(DexFileReader reader) {
826418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Segment segment = reader.lookupSegment(Constants.TYPE_METHOD_HANDLE_ITEM);
82724e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    reader.indexedItems.initializeMethodHandles(segment.length);
82824e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    for (int i = 0; i < segment.length; i++) {
829418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      reader.indexedItems.setMethodHandle(i, reader.methodHandleAt(i));
830418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
831418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
832418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
833418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private static void populateCallSites(DexFileReader reader) {
834418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Segment segment = reader.lookupSegment(Constants.TYPE_CALL_SITE_ID_ITEM);
83524e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    reader.indexedItems.initializeCallSites(segment.length);
83624e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    for (int i = 0; i < segment.length; i++) {
837418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      reader.indexedItems.setCallSites(i, reader.callSiteAt(i));
838418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
839418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
840418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
841418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private static void populateTypes(DexFileReader reader) {
842418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Segment segment = reader.lookupSegment(Constants.TYPE_TYPE_ID_ITEM);
84324e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    reader.indexedItems.initializeTypes(segment.length);
84424e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    for (int i = 0; i < segment.length; i++) {
845418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      reader.indexedItems.setType(i, reader.typeAt(i));
846418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
847418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
848418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
849418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private static void populateFields(DexFileReader reader) {
850418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Segment segment = reader.lookupSegment(Constants.TYPE_FIELD_ID_ITEM);
85124e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    reader.indexedItems.initializeFields(segment.length);
85224e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    for (int i = 0; i < segment.length; i++) {
853418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      reader.indexedItems.setField(i, reader.fieldAt(i));
854418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
855418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
856418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
857418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private static void populateProtos(DexFileReader reader) {
858418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Segment segment = reader.lookupSegment(Constants.TYPE_PROTO_ID_ITEM);
85924e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    reader.indexedItems.initializeProtos(segment.length);
86024e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    for (int i = 0; i < segment.length; i++) {
861418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      reader.indexedItems.setProto(i, reader.protoAt(i));
862418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
863418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
864418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
865418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private static void populateMethods(DexFileReader reader) {
866418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Segment segment = reader.lookupSegment(Constants.TYPE_METHOD_ID_ITEM);
86724e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    reader.indexedItems.initializeMethods(segment.length);
86824e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    for (int i = 0; i < segment.length; i++) {
869418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      reader.indexedItems.setMethod(i, reader.methodAt(i));
870418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
871418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
872418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
873418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexString stringAt(int index) {
874418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    final int offset = stringIDs[index];
875418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    file.position(offset);
876418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int size = file.getUleb128();
877418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    ByteArrayOutputStream os = new ByteArrayOutputStream();
878418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    byte read;
879418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    do {
880418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      read = file.get();
881418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      os.write(read);
882418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    } while (read != 0);
883418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return dexItemFactory.createString(size, os.toByteArray());
884418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
885418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
886418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexType typeAt(int index) {
887418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Segment segment = lookupSegment(Constants.TYPE_TYPE_ID_ITEM);
88824e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    if (index >= segment.length) {
889418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      return null;
890418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
891418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int offset = segment.offset + (Constants.TYPE_TYPE_ID_ITEM_SIZE * index);
892418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int stringIndex = file.getUint(offset);
893418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return dexItemFactory.createType(indexedItems.getString(stringIndex));
894418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
895418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
896418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexField fieldAt(int index) {
897418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Segment segment = lookupSegment(Constants.TYPE_FIELD_ID_ITEM);
89824e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    if (index >= segment.length) {
899418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      return null;
900418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
901418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int offset = segment.offset + (Constants.TYPE_FIELD_ID_ITEM_SIZE * index);
902418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    file.position(offset);
903418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int classIndex = file.getUshort();
904418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int typeIndex = file.getUshort();
905418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int nameIndex = file.getUint();
906418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexType clazz = indexedItems.getType(classIndex);
907418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexType type = indexedItems.getType(typeIndex);
908418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexString name = indexedItems.getString(nameIndex);
909418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return dexItemFactory.createField(clazz, type, name);
910418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
911418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
912418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexMethodHandle methodHandleAt(int index) {
913418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Segment segment = lookupSegment(Constants.TYPE_METHOD_HANDLE_ITEM);
91424e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    if (index >= segment.length) {
915418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      return null;
916418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
917418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int offset = segment.offset + (Constants.TYPE_METHOD_HANDLE_ITEM_SIZE * index);
918418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    file.position(offset);
919418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    MethodHandleType type = MethodHandleType.getKind(file.getUshort());
920418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    file.getUshort(); // unused
921418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int indexFieldOrMethod = file.getUshort();
922418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Descriptor<? extends DexItem, ? extends Descriptor> fieldOrMethod;
923418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    switch (type) {
924418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case INSTANCE_GET:
925418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case INSTANCE_PUT:
926418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case STATIC_GET:
927418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case STATIC_PUT: {
928418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        fieldOrMethod = indexedItems.getField(indexFieldOrMethod);
929418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        break;
930418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
931418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case INVOKE_INSTANCE:
932418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      case INVOKE_STATIC: {
933418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        fieldOrMethod = indexedItems.getMethod(indexFieldOrMethod);
934418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        break;
935418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
936418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      default:
937418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        throw new AssertionError("Method handle type unsupported in a dex file.");
938418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
939418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    file.getUshort(); // unused
940418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
941418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return dexItemFactory.createMethodHandle(type, fieldOrMethod);
942418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
943418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
944418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexCallSite callSiteAt(int index) {
945418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Segment segment = lookupSegment(Constants.TYPE_CALL_SITE_ID_ITEM);
94624e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    if (index >= segment.length) {
947418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      return null;
948418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
949418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int callSiteOffset =
950418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        file.getUint(segment.offset + (Constants.TYPE_CALL_SITE_ID_ITEM_SIZE * index));
951418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexEncodedArray callSiteEncodedArray = encodedArrayAt(callSiteOffset);
952418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexValue[] values = callSiteEncodedArray.values;
953418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    assert values[0] instanceof DexValueMethodHandle;
954418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    assert values[1] instanceof DexValueString;
955418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    assert values[2] instanceof DexValueMethodType;
956418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
957418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return dexItemFactory.createCallSite(
958418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        ((DexValueString) values[1]).value,
959418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        ((DexValueMethodType) values[2]).value,
960418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        ((DexValueMethodHandle) values[0]).value,
961418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        // 3 means first extra args
962418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        Arrays.asList(Arrays.copyOfRange(values, 3, values.length)));
963418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
964418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
965418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexProto protoAt(int index) {
966418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Segment segment = lookupSegment(Constants.TYPE_PROTO_ID_ITEM);
96724e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    if (index >= segment.length) {
968418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      return null;
969418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
970418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int offset = segment.offset + (Constants.TYPE_PROTO_ID_ITEM_SIZE * index);
971418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    file.position(offset);
972418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int shortyIndex = file.getUint();
973418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int returnTypeIndex = file.getUint();
974418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int parametersOffsetIndex = file.getUint();
975418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexString shorty = indexedItems.getString(shortyIndex);
976418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexType returnType = indexedItems.getType(returnTypeIndex);
977418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    DexTypeList parameters = typeListAt(parametersOffsetIndex);
978418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return dexItemFactory.createProto(shorty, returnType, parameters);
979418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
980418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
981418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private DexMethod methodAt(int index) {
982418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Segment segment = lookupSegment(Constants.TYPE_METHOD_ID_ITEM);
98324e0f5c8959e87bb7d0ecb461808c03abb0abc85Lars Bak    if (index >= segment.length) {
984418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      return null;
985418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
986418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int offset = segment.offset + (Constants.TYPE_METHOD_ID_ITEM_SIZE * index);
987418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    file.position(offset);
988418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int classIndex = file.getUshort();
989418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int protoIndex = file.getUshort();
990418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    int nameIndex = file.getUint();
991418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    return dexItemFactory.createMethod(
992418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        indexedItems.getType(classIndex),
993418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        indexedItems.getProto(protoIndex),
994418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        indexedItems.getString(nameIndex));
995418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
996418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
997418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private static class AnnotationsDirectory {
998418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
999418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    private static final DexParameterAnnotation[] NO_PARAMETER_ANNOTATIONS =
1000418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        new DexParameterAnnotation[0];
1001418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
1002418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    private static final DexFieldAnnotation[] NO_FIELD_ANNOTATIONS =
1003418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        new DexFieldAnnotation[0];
1004418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
1005418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    private static final DexMethodAnnotation[] NO_METHOD_ANNOTATIONS =
1006418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        new DexMethodAnnotation[0];
1007418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
1008418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    private static final AnnotationsDirectory THE_EMPTY_ANNOTATIONS_DIRECTORY =
1009418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        new AnnotationsDirectory(DexAnnotationSet.empty(),
1010418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager            NO_FIELD_ANNOTATIONS, new DexMethodAnnotation[0],
1011418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager            NO_PARAMETER_ANNOTATIONS);
1012418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
1013418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    public final DexAnnotationSet clazz;
1014418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    public final DexFieldAnnotation[] fields;
1015418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    public final DexMethodAnnotation[] methods;
1016418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    public final DexParameterAnnotation[] parameters;
1017418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
1018418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    AnnotationsDirectory(DexAnnotationSet clazz,
1019418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        DexFieldAnnotation[] fields,
1020418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        DexMethodAnnotation[] methods,
1021418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        DexParameterAnnotation[] parameters) {
1022418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      this.clazz = clazz == null ? DexAnnotationSet.empty() : clazz;
1023418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      this.fields = fields == null ? NO_FIELD_ANNOTATIONS : fields;
1024418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      this.methods = methods == null ? NO_METHOD_ANNOTATIONS : methods;
1025418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      this.parameters = parameters == null ? NO_PARAMETER_ANNOTATIONS : parameters;
1026418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
1027418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
1028418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    public static AnnotationsDirectory empty() {
1029418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      return THE_EMPTY_ANNOTATIONS_DIRECTORY;
1030418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
1031418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
1032418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager}
1033