1 // Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file 2 // for details. All rights reserved. Use of this source code is governed by a 3 // BSD-style license that can be found in the LICENSE file. 4 package com.android.tools.r8.graph; 5 6 import com.android.tools.r8.dex.Constants; 7 import com.google.common.collect.Sets; 8 import java.util.Arrays; 9 import java.util.Collections; 10 import java.util.Set; 11 12 public class ObjectToOffsetMapping { 13 14 private final int virtualFileId; 15 16 private final DexProgramClass[] classes; 17 private final DexProto[] protos; 18 private final DexType[] types; 19 private final DexMethod[] methods; 20 private final DexField[] fields; 21 private final DexString[] strings; 22 private final DexCallSite[] callSites; 23 private final DexMethodHandle[] methodHandles; 24 private DexString firstJumboString; 25 ObjectToOffsetMapping( int virtualFileId, DexApplication application, DexProgramClass[] classes, DexProto[] protos, DexType[] types, DexMethod[] methods, DexField[] fields, DexString[] strings, DexCallSite[] callSites, DexMethodHandle[] methodHandles)26 public ObjectToOffsetMapping( 27 int virtualFileId, 28 DexApplication application, 29 DexProgramClass[] classes, 30 DexProto[] protos, 31 DexType[] types, 32 DexMethod[] methods, 33 DexField[] fields, 34 DexString[] strings, 35 DexCallSite[] callSites, 36 DexMethodHandle[] methodHandles) { 37 assert application != null; 38 assert classes != null; 39 assert protos != null; 40 assert types != null; 41 assert methods != null; 42 assert fields != null; 43 assert strings != null; 44 assert callSites != null; 45 assert methodHandles != null; 46 47 this.virtualFileId = virtualFileId; 48 this.classes = sortClasses(application, classes); 49 this.protos = protos; 50 this.types = types; 51 this.methods = methods; 52 this.fields = fields; 53 this.strings = strings; 54 this.callSites = callSites; 55 this.methodHandles = methodHandles; 56 57 Arrays.sort(protos); 58 setIndexes(protos); 59 60 Arrays.sort(types); 61 setIndexes(types); 62 63 Arrays.sort(methods); 64 setIndexes(methods); 65 66 Arrays.sort(fields); 67 setIndexes(fields); 68 69 Arrays.sort(strings); 70 setIndexes(strings); 71 72 // No need to sort CallSite, they will be written in data section in the callSites order, 73 // consequently offset of call site used into the call site section will be in ascending order. 74 setIndexes(callSites); 75 76 // No need to sort method handle 77 setIndexes(methodHandles); 78 } 79 sortClasses( DexApplication application, DexProgramClass[] classes)80 private static DexProgramClass[] sortClasses( 81 DexApplication application, DexProgramClass[] classes) { 82 Arrays.sort(classes, (o1, o2) -> o1.type.descriptor.slowCompareTo(o2.type.descriptor)); 83 SortingProgramClassVisitor classVisitor = new SortingProgramClassVisitor(application, classes); 84 classVisitor.run(classes); 85 return classVisitor.getSortedClasses(); 86 } 87 setIndexes(IndexedDexItem[] items)88 private void setIndexes(IndexedDexItem[] items) { 89 int index = 0; 90 for (IndexedDexItem item : items) { 91 item.assignVirtualFileIndex(virtualFileId, index); 92 // For strings collect the first jumbo string (if any). 93 if (index > Constants.MAX_NON_JUMBO_INDEX) { 94 assert item instanceof DexString; 95 if (index == Constants.FIRST_JUMBO_INDEX) { 96 firstJumboString = (DexString) item; 97 } 98 } 99 index++; 100 } 101 } 102 getMethods()103 public DexMethod[] getMethods() { 104 return methods; 105 } 106 getClasses()107 public DexProgramClass[] getClasses() { 108 return classes; 109 } 110 getTypes()111 public DexType[] getTypes() { 112 return types; 113 } 114 getProtos()115 public DexProto[] getProtos() { 116 return protos; 117 } 118 getFields()119 public DexField[] getFields() { 120 return fields; 121 } 122 getStrings()123 public DexString[] getStrings() { 124 return strings; 125 } 126 getCallSites()127 public DexCallSite[] getCallSites() { 128 return callSites; 129 } 130 getMethodHandles()131 public DexMethodHandle[] getMethodHandles() { 132 return methodHandles; 133 } 134 hasJumboStrings()135 public boolean hasJumboStrings() { 136 return firstJumboString != null; 137 } 138 getFirstJumboString()139 public DexString getFirstJumboString() { 140 return firstJumboString; 141 } 142 isContainedInMapping(IndexedDexItem item)143 private boolean isContainedInMapping(IndexedDexItem item) { 144 return item.getVirtualFileIndex(virtualFileId) != IndexedDexItem.UNASSOCIATED_VALUE; 145 } 146 getOffsetFor(DexProto proto)147 public int getOffsetFor(DexProto proto) { 148 assert isContainedInMapping(proto) : "Missing dependency: " + proto; 149 return proto.getVirtualFileIndex(virtualFileId); 150 } 151 getOffsetFor(DexField field)152 public int getOffsetFor(DexField field) { 153 assert isContainedInMapping(field) : "Missing dependency: " + field; 154 return field.getVirtualFileIndex(virtualFileId); 155 } 156 getOffsetFor(DexMethod method)157 public int getOffsetFor(DexMethod method) { 158 assert isContainedInMapping(method) : "Missing dependency: " + method; 159 return method.getVirtualFileIndex(virtualFileId); 160 } 161 getOffsetFor(DexString string)162 public int getOffsetFor(DexString string) { 163 assert isContainedInMapping(string) : "Missing dependency: " + string; 164 return string.getVirtualFileIndex(virtualFileId); 165 } 166 getOffsetFor(DexType type)167 public int getOffsetFor(DexType type) { 168 assert isContainedInMapping(type) : "Missing dependency: " + type; 169 return type.getVirtualFileIndex(virtualFileId); 170 } 171 getOffsetFor(DexCallSite callSite)172 public int getOffsetFor(DexCallSite callSite) { 173 assert isContainedInMapping(callSite) : "Missing dependency: " + callSite; 174 return callSite.getVirtualFileIndex(virtualFileId); 175 } 176 getOffsetFor(DexMethodHandle methodHandle)177 public int getOffsetFor(DexMethodHandle methodHandle) { 178 assert isContainedInMapping(methodHandle) : "Missing dependency: " + methodHandle; 179 return methodHandle.getVirtualFileIndex(virtualFileId); 180 } 181 182 private static class SortingProgramClassVisitor extends ProgramClassVisitor { 183 private final Set<DexClass> classSet = Sets.newIdentityHashSet(); 184 private final DexProgramClass[] sortedClasses; 185 186 private int index = 0; 187 SortingProgramClassVisitor(DexApplication application, DexProgramClass[] classes)188 public SortingProgramClassVisitor(DexApplication application, DexProgramClass[] classes) { 189 super(application); 190 this.sortedClasses = new DexProgramClass[classes.length]; 191 Collections.addAll(classSet, classes); 192 } 193 194 @Override visit(DexType type)195 public void visit(DexType type) {} 196 197 @Override visit(DexClass clazz)198 public void visit(DexClass clazz) { 199 if (classSet.contains(clazz)) { 200 assert index < sortedClasses.length; 201 sortedClasses[index++] = (DexProgramClass) clazz; 202 } 203 } 204 205 public DexProgramClass[] getSortedClasses() { 206 assert index == sortedClasses.length; 207 return sortedClasses; 208 } 209 } 210 } 211