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.Resource; 7 import com.android.tools.r8.dex.MixedSectionCollection; 8 import com.android.tools.r8.errors.CompilationError; 9 import com.android.tools.r8.errors.Unreachable; 10 11 import com.google.common.base.MoreObjects; 12 13 import java.util.Arrays; 14 import java.util.function.Consumer; 15 16 public abstract class DexClass extends DexItem { 17 18 private static final DexEncodedMethod[] NO_METHODS = {}; 19 private static final DexEncodedField[] NO_FIELDS = {}; 20 21 public final Resource.Kind origin; 22 public final DexType type; 23 public final DexAccessFlags accessFlags; 24 public DexType superType; 25 public DexTypeList interfaces; 26 public final DexString sourceFile; 27 public DexEncodedField[] staticFields; 28 public DexEncodedField[] instanceFields; 29 public DexEncodedMethod[] directMethods; 30 public DexEncodedMethod[] virtualMethods; 31 public DexAnnotationSet annotations; 32 DexClass( DexString sourceFile, DexTypeList interfaces, DexAccessFlags accessFlags, DexType superType, DexType type, DexEncodedField[] staticFields, DexEncodedField[] instanceFields, DexEncodedMethod[] directMethods, DexEncodedMethod[] virtualMethods, DexAnnotationSet annotations, Resource.Kind origin)33 public DexClass( 34 DexString sourceFile, DexTypeList interfaces, DexAccessFlags accessFlags, DexType superType, 35 DexType type, DexEncodedField[] staticFields, DexEncodedField[] instanceFields, 36 DexEncodedMethod[] directMethods, DexEncodedMethod[] virtualMethods, 37 DexAnnotationSet annotations, Resource.Kind origin) { 38 this.origin = origin; 39 this.sourceFile = sourceFile; 40 this.interfaces = interfaces; 41 this.accessFlags = accessFlags; 42 this.superType = superType; 43 this.type = type; 44 this.staticFields = staticFields; 45 this.instanceFields = instanceFields; 46 this.directMethods = directMethods; 47 this.virtualMethods = virtualMethods; 48 this.annotations = annotations; 49 if (type == superType) { 50 throw new CompilationError("Class " + type.toString() + " cannot extend itself"); 51 } 52 for (DexType interfaceType : interfaces.values) { 53 if (type == interfaceType) { 54 throw new CompilationError("Interface " + type.toString() + " cannot implement itself"); 55 } 56 } 57 if (!type.descriptor.isValidClassDescriptor()) { 58 throw new CompilationError( 59 "Class descriptor '" 60 + type.descriptor.toString() 61 + "' cannot be represented in dex format."); 62 } 63 } 64 65 @Override collectMixedSectionItems(MixedSectionCollection mixedItems)66 void collectMixedSectionItems(MixedSectionCollection mixedItems) { 67 throw new Unreachable(); 68 } 69 directMethods()70 public DexEncodedMethod[] directMethods() { 71 return MoreObjects.firstNonNull(directMethods, NO_METHODS); 72 } 73 virtualMethods()74 public DexEncodedMethod[] virtualMethods() { 75 return MoreObjects.firstNonNull(virtualMethods, NO_METHODS); 76 } 77 forEachMethod(Consumer<DexEncodedMethod> consumer)78 public void forEachMethod(Consumer<DexEncodedMethod> consumer) { 79 for (DexEncodedMethod method : directMethods()) { 80 consumer.accept(method); 81 } 82 for (DexEncodedMethod method : virtualMethods()) { 83 consumer.accept(method); 84 } 85 } 86 allMethodsSorted()87 public DexEncodedMethod[] allMethodsSorted() { 88 int vLen = virtualMethods().length; 89 int dLen = directMethods().length; 90 DexEncodedMethod[] result = new DexEncodedMethod[vLen+dLen]; 91 System.arraycopy(virtualMethods(), 0, result, 0, vLen); 92 System.arraycopy(directMethods(), 0, result, vLen, dLen); 93 Arrays.sort(result, 94 (DexEncodedMethod a, DexEncodedMethod b) -> a.method.slowCompareTo(b.method)); 95 return result; 96 } 97 staticFields()98 public DexEncodedField[] staticFields() { 99 return MoreObjects.firstNonNull(staticFields, NO_FIELDS); 100 } 101 instanceFields()102 public DexEncodedField[] instanceFields() { 103 return MoreObjects.firstNonNull(instanceFields, NO_FIELDS); 104 } 105 106 /** 107 * Find direct method in this class matching method 108 */ findDirectTarget(DexMethod method)109 public DexEncodedMethod findDirectTarget(DexMethod method) { 110 return findTarget(directMethods(), method); 111 } 112 113 /** 114 * Find static field in this class matching field 115 */ findStaticTarget(DexField field)116 public DexEncodedField findStaticTarget(DexField field) { 117 return findTarget(staticFields(), field); 118 } 119 120 /** 121 * Find virtual method in this class matching method 122 */ findVirtualTarget(DexMethod method)123 public DexEncodedMethod findVirtualTarget(DexMethod method) { 124 return findTarget(virtualMethods(), method); 125 } 126 127 /** 128 * Find instance field in this class matching field 129 */ findInstanceTarget(DexField field)130 public DexEncodedField findInstanceTarget(DexField field) { 131 return findTarget(instanceFields(), field); 132 } 133 findTarget(T[] items, S descriptor)134 private <T extends DexItem, S extends Descriptor<T, S>> T findTarget(T[] items, S descriptor) { 135 for (T entry : items) { 136 if (descriptor.match(entry)) { 137 return entry; 138 } 139 } 140 return null; 141 } 142 143 // Tells whether this is an interface. isInterface()144 public boolean isInterface() { 145 return accessFlags.isInterface(); 146 } 147 addDependencies(MixedSectionCollection collector)148 public abstract void addDependencies(MixedSectionCollection collector); 149 isProgramClass()150 public boolean isProgramClass() { 151 return false; 152 } 153 asProgramClass()154 public DexProgramClass asProgramClass() { 155 return null; 156 } 157 isClasspathClass()158 public boolean isClasspathClass() { 159 return false; 160 } 161 asClasspathClass()162 public DexClasspathClass asClasspathClass() { 163 return null; 164 } 165 isLibraryClass()166 public boolean isLibraryClass() { 167 return false; 168 } 169 asLibraryClass()170 public DexLibraryClass asLibraryClass() { 171 return null; 172 } 173 getClassInitializer()174 public DexEncodedMethod getClassInitializer() { 175 for (DexEncodedMethod method : directMethods()) { 176 if (method.accessFlags.isConstructor() && method.accessFlags.isStatic()) { 177 return method; 178 } 179 } 180 return null; 181 } 182 getOrigin()183 public Resource.Kind getOrigin() { 184 return this.origin; 185 } 186 hasClassInitializer()187 public boolean hasClassInitializer() { 188 return getClassInitializer() != null; 189 } 190 hasNonTrivialClassInitializer()191 public boolean hasNonTrivialClassInitializer() { 192 DexEncodedMethod clinit = getClassInitializer(); 193 if (clinit == null || clinit.getCode() == null) { 194 return false; 195 } 196 if (clinit.getCode().isDexCode()) { 197 return !clinit.getCode().asDexCode().isEmptyVoidMethod(); 198 } 199 // For non-dex code we don't try to check the code. 200 return true; 201 } 202 } 203