• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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