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.android.tools.r8.graph.DexDebugEvent.AdvanceLine; 8 import com.android.tools.r8.graph.DexDebugEvent.AdvancePC; 9 import com.android.tools.r8.graph.DexDebugEvent.Default; 10 import com.android.tools.r8.graph.DexDebugEvent.EndLocal; 11 import com.android.tools.r8.graph.DexDebugEvent.RestartLocal; 12 import com.android.tools.r8.graph.DexDebugEvent.SetEpilogueBegin; 13 import com.android.tools.r8.graph.DexDebugEvent.SetFile; 14 import com.android.tools.r8.graph.DexDebugEvent.SetPrologueEnd; 15 import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType; 16 import com.android.tools.r8.naming.NamingLens; 17 import com.google.common.collect.ImmutableSet; 18 import it.unimi.dsi.fastutil.ints.Int2ObjectMap; 19 import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; 20 import java.util.ArrayList; 21 import java.util.Collection; 22 import java.util.HashMap; 23 import java.util.List; 24 import java.util.Map; 25 import java.util.Set; 26 import java.util.function.Consumer; 27 28 public class DexItemFactory { 29 30 private final Map<String, DexString> strings = new HashMap<>(); 31 private final Map<DexType, DexType> types = new HashMap<>(); 32 private final Map<DexField, DexField> fields = new HashMap<>(); 33 private final Map<DexProto, DexProto> protos = new HashMap<>(); 34 private final Map<DexMethod, DexMethod> methods = new HashMap<>(); 35 private final Map<DexCallSite, DexCallSite> callSites = new HashMap<>(); 36 private final Map<DexMethodHandle, DexMethodHandle> methodHandles = new HashMap<>(); 37 38 // DexDebugEvent Canonicalization. 39 private final Int2ObjectMap<AdvanceLine> advanceLines = new Int2ObjectOpenHashMap<>(); 40 private final Int2ObjectMap<AdvancePC> advancePCs = new Int2ObjectOpenHashMap<>(); 41 private final Int2ObjectMap<Default> defaults = new Int2ObjectOpenHashMap<>(); 42 private final Int2ObjectMap<EndLocal> endLocals = new Int2ObjectOpenHashMap<>(); 43 private final Int2ObjectMap<RestartLocal> restartLocals = new Int2ObjectOpenHashMap<>(); 44 private final SetEpilogueBegin setEpilogueBegin = new SetEpilogueBegin(); 45 private final SetPrologueEnd setPrologueEnd = new SetPrologueEnd(); 46 private final Map<DexString, SetFile> setFiles = new HashMap<>(); 47 48 boolean sorted = false; 49 50 public static final DexType catchAllType = new DexType(new DexString("CATCH_ALL")); 51 private static final Set<DexItem> internalSentinels = ImmutableSet.of(catchAllType); 52 53 public DexString booleanDescriptor = createString("Z"); 54 public DexString byteDescriptor = createString("B"); 55 public DexString charDescriptor = createString("C"); 56 public DexString doubleDescriptor = createString("D"); 57 public DexString floatDescriptor = createString("F"); 58 public DexString intDescriptor = createString("I"); 59 public DexString longDescriptor = createString("J"); 60 public DexString shortDescriptor = createString("S"); 61 public DexString voidDescriptor = createString("V"); 62 63 public DexString boxedBooleanDescriptor = createString("Ljava/lang/Boolean;"); 64 public DexString boxedByteDescriptor = createString("Ljava/lang/Byte;"); 65 public DexString boxedCharDescriptor = createString("Ljava/lang/Character;"); 66 public DexString boxedDoubleDescriptor = createString("Ljava/lang/Double;"); 67 public DexString boxedFloatDescriptor = createString("Ljava/lang/Float;"); 68 public DexString boxedIntDescriptor = createString("Ljava/lang/Integer;"); 69 public DexString boxedLongDescriptor = createString("Ljava/lang/Long;"); 70 public DexString boxedShortDescriptor = createString("Ljava/lang/Short;"); 71 public DexString boxedNumberDescriptor = createString("Ljava/lang/Number;"); 72 73 public DexString unboxBooleanMethodName = createString("booleanValue"); 74 public DexString unboxByteMethodName = createString("byteValue"); 75 public DexString unboxCharMethodName = createString("charValue"); 76 public DexString unboxShortMethodName = createString("shortValue"); 77 public DexString unboxIntMethodName = createString("intValue"); 78 public DexString unboxLongMethodName = createString("longValue"); 79 public DexString unboxFloatMethodName = createString("floatValue"); 80 public DexString unboxDoubleMethodName = createString("doubleValue"); 81 82 public DexString valueOfMethodName = createString("valueOf"); 83 84 public DexString getClassMethodName = createString("getClass"); 85 public DexString ordinalMethodName = createString("ordinal"); 86 public final DexString desiredAssertionStatusMethodName = createString("desiredAssertionStatus"); 87 public final DexString assertionsDisabled = createString("$assertionsDisabled"); 88 89 public DexString stringDescriptor = createString("Ljava/lang/String;"); 90 public DexString objectDescriptor = createString("Ljava/lang/Object;"); 91 public DexString classDescriptor = createString("Ljava/lang/Class;"); 92 public DexString enumDescriptor = createString("Ljava/lang/Enum;"); 93 public DexString annotationDescriptor = createString("Ljava/lang/annotation/Annotation;"); 94 public DexString throwableDescriptor = createString("Ljava/lang/Throwable;"); 95 public DexString objectsDescriptor = createString("Ljava/util/Objects;"); 96 97 public DexString constructorMethodName = createString(Constants.INSTANCE_INITIALIZER_NAME); 98 public DexString classConstructorMethodName = createString(Constants.CLASS_INITIALIZER_NAME); 99 100 public DexString thisName = createString("this"); 101 102 private DexString charArrayDescriptor = createString("[C"); 103 private DexType charArrayType = createType(charArrayDescriptor); 104 public DexString throwableArrayDescriptor = createString("[Ljava/lang/Throwable;"); 105 106 public DexType booleanType = createType(booleanDescriptor); 107 public DexType byteType = createType(byteDescriptor); 108 public DexType charType = createType(charDescriptor); 109 public DexType doubleType = createType(doubleDescriptor); 110 public DexType floatType = createType(floatDescriptor); 111 public DexType intType = createType(intDescriptor); 112 public DexType longType = createType(longDescriptor); 113 public DexType shortType = createType(shortDescriptor); 114 public DexType voidType = createType(voidDescriptor); 115 116 public DexType boxedBooleanType = createType(boxedBooleanDescriptor); 117 public DexType boxedByteType = createType(boxedByteDescriptor); 118 public DexType boxedCharType = createType(boxedCharDescriptor); 119 public DexType boxedDoubleType = createType(boxedDoubleDescriptor); 120 public DexType boxedFloatType = createType(boxedFloatDescriptor); 121 public DexType boxedIntType = createType(boxedIntDescriptor); 122 public DexType boxedLongType = createType(boxedLongDescriptor); 123 public DexType boxedShortType = createType(boxedShortDescriptor); 124 public DexType boxedNumberType = createType(boxedNumberDescriptor); 125 126 public DexType stringType = createType(stringDescriptor); 127 public DexType objectType = createType(objectDescriptor); 128 public DexType enumType = createType(enumDescriptor); 129 public DexType annotationType = createType(annotationDescriptor); 130 public DexType throwableType = createType(throwableDescriptor); 131 132 public DexType stringBuilderType = createType("Ljava/lang/StringBuilder;"); 133 public DexType stringBufferType = createType("Ljava/lang/StringBuffer;"); 134 135 public StringBuildingMethods stringBuilderMethods = new StringBuildingMethods(stringBuilderType); 136 public StringBuildingMethods stringBufferMethods = new StringBuildingMethods(stringBufferType); 137 public ObjectsMethods objectsMethods = new ObjectsMethods(); 138 public ObjectMethods objectMethods = new ObjectMethods(); 139 public LongMethods longMethods = new LongMethods(); 140 public ThrowableMethods throwableMethods = new ThrowableMethods(); 141 public ClassMethods classMethods = new ClassMethods(); 142 143 // Dex system annotations. 144 // See https://source.android.com/devices/tech/dalvik/dex-format.html#system-annotation 145 public final DexType annotationDefault = createType("Ldalvik/annotation/AnnotationDefault;"); 146 public final DexType annotationEnclosingClass = createType("Ldalvik/annotation/EnclosingClass;"); 147 public final DexType annotationEnclosingMethod = createType( 148 "Ldalvik/annotation/EnclosingMethod;"); 149 public final DexType annotationInnerClass = createType("Ldalvik/annotation/InnerClass;"); 150 public final DexType annotationMemberClasses = createType("Ldalvik/annotation/MemberClasses;"); 151 public final DexType annotationMethodParameters = createType( 152 "Ldalvik/annotation/MethodParameters;"); 153 public final DexType annotationSignature = createType("Ldalvik/annotation/Signature;"); 154 public final DexType annotationSourceDebugExtension = createType( 155 "Ldalvik/annotation/SourceDebugExtension;"); 156 public final DexType annotationThrows = createType("Ldalvik/annotation/Throws;"); 157 clearSubtypeInformation()158 public void clearSubtypeInformation() { 159 types.values().forEach(DexType::clearSubtypeInformation); 160 } 161 162 public class LongMethods { 163 164 public DexMethod compare; 165 LongMethods()166 private LongMethods() { 167 compare = createMethod(boxedLongDescriptor, 168 createString("compare"), intDescriptor, new DexString[]{longDescriptor, longDescriptor}); 169 } 170 } 171 172 public class ThrowableMethods { 173 174 public final DexMethod addSuppressed; 175 public final DexMethod getSuppressed; 176 ThrowableMethods()177 private ThrowableMethods() { 178 addSuppressed = createMethod(throwableDescriptor, 179 createString("addSuppressed"), voidDescriptor, new DexString[]{throwableDescriptor}); 180 getSuppressed = createMethod(throwableDescriptor, 181 createString("getSuppressed"), throwableArrayDescriptor, DexString.EMPTY_ARRAY); 182 } 183 } 184 185 public class ObjectMethods { 186 187 public DexMethod getClass; 188 ObjectMethods()189 private ObjectMethods() { 190 getClass = createMethod(objectsDescriptor, 191 getClassMethodName, classDescriptor, new DexString[]{}); 192 } 193 } 194 195 public class ObjectsMethods { 196 197 public DexMethod requireNonNull; 198 ObjectsMethods()199 private ObjectsMethods() { 200 requireNonNull = createMethod(objectsDescriptor, 201 createString("requireNonNull"), objectDescriptor, new DexString[]{objectDescriptor}); 202 } 203 } 204 205 public class ClassMethods { 206 207 public DexMethod desiredAssertionStatus; 208 ClassMethods()209 private ClassMethods() { 210 desiredAssertionStatus = createMethod(classDescriptor, 211 desiredAssertionStatusMethodName, booleanDescriptor, new DexString[]{}); 212 } 213 } 214 215 216 public class StringBuildingMethods { 217 218 public DexMethod appendBoolean; 219 public DexMethod appendChar; 220 public DexMethod appendCharArray; 221 public DexMethod appendSubCharArray; 222 public DexMethod appendCharSequence; 223 public DexMethod appendSubCharSequence; 224 public DexMethod appendInt; 225 public DexMethod appendDouble; 226 public DexMethod appendFloat; 227 public DexMethod appendLong; 228 public DexMethod appendObject; 229 public DexMethod appendString; 230 public DexMethod appendStringBuffer; 231 public DexMethod toString; 232 StringBuildingMethods(DexType receiver)233 private StringBuildingMethods(DexType receiver) { 234 DexType sbufType = createType(createString("Ljava/lang/StringBuffer;")); 235 DexType charSequenceType = createType(createString("Ljava/lang/CharSequence;")); 236 DexString append = createString("append"); 237 DexString toStringMethodName = createString("toString"); 238 239 240 appendBoolean = createMethod(receiver, createProto(receiver, booleanType), append); 241 appendChar = createMethod(receiver, createProto(receiver, charType), append); 242 appendCharArray = createMethod(receiver, createProto(receiver, charArrayType), append); 243 appendSubCharArray = 244 createMethod(receiver, createProto(receiver, charArrayType, intType, intType), append); 245 appendCharSequence = createMethod(receiver, createProto(receiver, charSequenceType), append); 246 appendSubCharSequence = 247 createMethod(receiver, createProto(receiver, charSequenceType, intType, intType), append); 248 appendInt = createMethod(receiver, createProto(receiver, intType), append); 249 appendDouble = createMethod(receiver, createProto(receiver, doubleType), append); 250 appendFloat = createMethod(receiver, createProto(receiver, floatType), append); 251 appendLong = createMethod(receiver, createProto(receiver, longType), append); 252 appendObject = createMethod(receiver, createProto(receiver, objectType), append); 253 appendString = createMethod(receiver, createProto(receiver, stringType), append); 254 appendStringBuffer = createMethod(receiver, createProto(receiver, sbufType), append); 255 toString = createMethod(receiver, createProto(stringType), toStringMethodName); 256 } 257 forEachAppendMethod(Consumer<DexMethod> consumer)258 public void forEachAppendMethod(Consumer<DexMethod> consumer) { 259 consumer.accept(appendBoolean); 260 consumer.accept(appendChar); 261 consumer.accept(appendCharArray); 262 consumer.accept(appendSubCharArray); 263 consumer.accept(appendCharSequence); 264 consumer.accept(appendSubCharSequence); 265 consumer.accept(appendInt); 266 consumer.accept(appendDouble); 267 consumer.accept(appendFloat); 268 consumer.accept(appendLong); 269 consumer.accept(appendObject); 270 consumer.accept(appendString); 271 consumer.accept(appendStringBuffer); 272 consumer.accept(appendBoolean); 273 } 274 } 275 canonicalize(Map<T, T> map, T item)276 synchronized private static <T extends DexItem> T canonicalize(Map<T, T> map, T item) { 277 assert item != null; 278 assert !internalSentinels.contains(item); 279 T previous = map.putIfAbsent(item, item); 280 return previous == null ? item : previous; 281 } 282 canonicalizeString(String key)283 synchronized private DexString canonicalizeString(String key) { 284 assert key != null; 285 return strings.computeIfAbsent(key, k -> new DexString(k)); 286 } 287 createString(int size, byte[] content)288 public DexString createString(int size, byte[] content) { 289 assert !sorted; 290 return canonicalizeString(new DexString(size, content).toString()); 291 } 292 createString(String source)293 public DexString createString(String source) { 294 assert !sorted; 295 return canonicalizeString(source); 296 } 297 createType(DexString descriptor)298 public DexType createType(DexString descriptor) { 299 assert !sorted; 300 DexType type = new DexType(descriptor); 301 return canonicalize(types, type); 302 } 303 createType(String descriptor)304 public DexType createType(String descriptor) { 305 return createType(createString(descriptor)); 306 } 307 createField(DexType clazz, DexType type, DexString name)308 public DexField createField(DexType clazz, DexType type, DexString name) { 309 assert !sorted; 310 DexField field = new DexField(clazz, type, name); 311 return canonicalize(fields, field); 312 } 313 createField(DexType clazz, DexType type, String name)314 public DexField createField(DexType clazz, DexType type, String name) { 315 return createField(clazz, type, createString(name)); 316 } 317 createProto(DexString shorty, DexType returnType, DexTypeList parameters)318 public DexProto createProto(DexString shorty, DexType returnType, DexTypeList parameters) { 319 assert !sorted; 320 DexProto proto = new DexProto(shorty, returnType, parameters); 321 return canonicalize(protos, proto); 322 } 323 createProto(DexString shorty, DexType returnType, DexType[] parameters)324 public DexProto createProto(DexString shorty, DexType returnType, DexType[] parameters) { 325 assert !sorted; 326 return createProto(shorty, returnType, 327 parameters.length == 0 ? DexTypeList.empty() : new DexTypeList(parameters)); 328 } 329 createProto(DexType returnType, DexType... parameters)330 public DexProto createProto(DexType returnType, DexType... parameters) { 331 return createProto(createShorty(returnType, parameters), returnType, parameters); 332 } 333 createShorty(DexType returnType, DexType[] argumentTypes)334 public DexString createShorty(DexType returnType, DexType[] argumentTypes) { 335 StringBuilder shortyBuilder = new StringBuilder(); 336 shortyBuilder.append(returnType.toShorty()); 337 for (DexType argumentType : argumentTypes) { 338 shortyBuilder.append(argumentType.toShorty()); 339 } 340 return createString(shortyBuilder.toString()); 341 } 342 createMethod(DexType holder, DexProto proto, DexString name)343 public DexMethod createMethod(DexType holder, DexProto proto, DexString name) { 344 assert !sorted; 345 DexMethod method = new DexMethod(holder, proto, name); 346 return canonicalize(methods, method); 347 } 348 createMethod(DexType holder, DexProto proto, String name)349 public DexMethod createMethod(DexType holder, DexProto proto, String name) { 350 return createMethod(holder, proto, createString(name)); 351 } 352 createMethodHandle( MethodHandleType type, Descriptor<? extends DexItem, ? extends Descriptor> fieldOrMethod)353 public DexMethodHandle createMethodHandle( 354 MethodHandleType type, Descriptor<? extends DexItem, ? extends Descriptor> fieldOrMethod) { 355 assert !sorted; 356 DexMethodHandle methodHandle = new DexMethodHandle(type, fieldOrMethod); 357 return canonicalize(methodHandles, methodHandle); 358 } 359 createCallSite( DexString methodName, DexProto methodProto, DexMethodHandle bootstrapMethod, List<DexValue> bootstrapArgs)360 public DexCallSite createCallSite( 361 DexString methodName, DexProto methodProto, 362 DexMethodHandle bootstrapMethod, List<DexValue> bootstrapArgs) { 363 assert !sorted; 364 DexCallSite callSite = new DexCallSite(methodName, methodProto, bootstrapMethod, bootstrapArgs); 365 return canonicalize(callSites, callSite); 366 } 367 createMethod(DexString clazzDescriptor, DexString name, DexString returnTypeDescriptor, DexString[] parameterDescriptors)368 public DexMethod createMethod(DexString clazzDescriptor, DexString name, 369 DexString returnTypeDescriptor, 370 DexString[] parameterDescriptors) { 371 assert !sorted; 372 DexType clazz = createType(clazzDescriptor); 373 DexType returnType = createType(returnTypeDescriptor); 374 DexType[] parameterTypes = new DexType[parameterDescriptors.length]; 375 for (int i = 0; i < parameterDescriptors.length; i++) { 376 parameterTypes[i] = createType(parameterDescriptors[i]); 377 } 378 DexProto proto = createProto(shorty(returnType, parameterTypes), returnType, parameterTypes); 379 380 return createMethod(clazz, proto, name); 381 } 382 createAdvanceLine(int delta)383 public AdvanceLine createAdvanceLine(int delta) { 384 synchronized (advanceLines) { 385 AdvanceLine result = advanceLines.get(delta); 386 if (result == null) { 387 result = new AdvanceLine(delta); 388 advanceLines.put(delta, result); 389 } 390 return result; 391 } 392 } 393 createAdvancePC(int delta)394 public AdvancePC createAdvancePC(int delta) { 395 synchronized (advancePCs) { 396 AdvancePC result = advancePCs.get(delta); 397 if (result == null) { 398 result = new AdvancePC(delta); 399 advancePCs.put(delta, result); 400 } 401 return result; 402 } 403 } 404 createDefault(int value)405 public Default createDefault(int value) { 406 synchronized (defaults) { 407 Default result = defaults.get(value); 408 if (result == null) { 409 result = new Default(value); 410 defaults.put(value, result); 411 } 412 return result; 413 } 414 } 415 createEndLocal(int registerNum)416 public EndLocal createEndLocal(int registerNum) { 417 synchronized (endLocals) { 418 EndLocal result = endLocals.get(registerNum); 419 if (result == null) { 420 result = new EndLocal(registerNum); 421 endLocals.put(registerNum, result); 422 } 423 return result; 424 } 425 } 426 createRestartLocal(int registerNum)427 public RestartLocal createRestartLocal(int registerNum) { 428 synchronized (restartLocals) { 429 RestartLocal result = restartLocals.get(registerNum); 430 if (result == null) { 431 result = new RestartLocal(registerNum); 432 restartLocals.put(registerNum, result); 433 } 434 return result; 435 } 436 } 437 createSetEpilogueBegin()438 public SetEpilogueBegin createSetEpilogueBegin() { 439 return setEpilogueBegin; 440 } 441 createSetPrologueEnd()442 public SetPrologueEnd createSetPrologueEnd() { 443 return setPrologueEnd; 444 } 445 createSetFile(DexString fileName)446 public SetFile createSetFile(DexString fileName) { 447 synchronized (setFiles) { 448 SetFile result = setFiles.get(fileName); 449 if (result == null) { 450 result = new SetFile(fileName); 451 setFiles.put(fileName, result); 452 } 453 return result; 454 } 455 } 456 isConstructor(DexMethod method)457 public boolean isConstructor(DexMethod method) { 458 return method.name == constructorMethodName; 459 } 460 isClassConstructor(DexMethod method)461 public boolean isClassConstructor(DexMethod method) { 462 return method.name == classConstructorMethodName; 463 } 464 shorty(DexType returnType, DexType[] parameters)465 private DexString shorty(DexType returnType, DexType[] parameters) { 466 StringBuilder builder = new StringBuilder(); 467 addToShorty(builder, returnType); 468 for (DexType parameter : parameters) { 469 addToShorty(builder, parameter); 470 } 471 return createString(builder.toString()); 472 } 473 addToShorty(StringBuilder builder, DexType type)474 private void addToShorty(StringBuilder builder, DexType type) { 475 char first = type.toDescriptorString().charAt(0); 476 builder.append(first == '[' ? 'L' : first); 477 } 478 assignSortedIndices(Collection<S> items, NamingLens namingLens)479 private static <S extends PresortedComparable<S>> void assignSortedIndices(Collection<S> items, 480 NamingLens namingLens) { 481 List<S> sorted = new ArrayList<>(items); 482 sorted.sort((a, b) -> a.layeredCompareTo(b, namingLens)); 483 int i = 0; 484 for (S value : sorted) { 485 value.setSortedIndex(i++); 486 } 487 } 488 sort(NamingLens namingLens)489 synchronized public void sort(NamingLens namingLens) { 490 assert !sorted; 491 assignSortedIndices(strings.values(), namingLens); 492 assignSortedIndices(types.values(), namingLens); 493 assignSortedIndices(fields.values(), namingLens); 494 assignSortedIndices(protos.values(), namingLens); 495 assignSortedIndices(methods.values(), namingLens); 496 sorted = true; 497 } 498 resetSortedIndices()499 synchronized public void resetSortedIndices() { 500 if (!sorted) { 501 return; 502 } 503 // Only used for asserting that we don't use the sorted index after we build the graph. 504 strings.values().forEach(IndexedDexItem::resetSortedIndex); 505 types.values().forEach(IndexedDexItem::resetSortedIndex); 506 fields.values().forEach(IndexedDexItem::resetSortedIndex); 507 protos.values().forEach(IndexedDexItem::resetSortedIndex); 508 methods.values().forEach(IndexedDexItem::resetSortedIndex); 509 sorted = false; 510 } 511 forAllTypes(Consumer<DexType> f)512 synchronized public void forAllTypes(Consumer<DexType> f) { 513 new ArrayList<>(types.values()).forEach(f); 514 } 515 } 516