Home | History | Annotate | Download | only in graph
      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 
     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
     66   void collectMixedSectionItems(MixedSectionCollection mixedItems) {
     67     throw new Unreachable();
     68   }
     69 
     70   public DexEncodedMethod[] directMethods() {
     71     return MoreObjects.firstNonNull(directMethods, NO_METHODS);
     72   }
     73 
     74   public DexEncodedMethod[] virtualMethods() {
     75     return MoreObjects.firstNonNull(virtualMethods, NO_METHODS);
     76   }
     77 
     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 
     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 
     98   public DexEncodedField[] staticFields() {
     99     return MoreObjects.firstNonNull(staticFields, NO_FIELDS);
    100   }
    101 
    102   public DexEncodedField[] instanceFields() {
    103     return MoreObjects.firstNonNull(instanceFields, NO_FIELDS);
    104   }
    105 
    106   /**
    107    * Find direct method in this class matching method
    108    */
    109   public DexEncodedMethod findDirectTarget(DexMethod method) {
    110     return findTarget(directMethods(), method);
    111   }
    112 
    113   /**
    114    * Find static field in this class matching field
    115    */
    116   public DexEncodedField findStaticTarget(DexField field) {
    117     return findTarget(staticFields(), field);
    118   }
    119 
    120   /**
    121    * Find virtual method in this class matching method
    122    */
    123   public DexEncodedMethod findVirtualTarget(DexMethod method) {
    124     return findTarget(virtualMethods(), method);
    125   }
    126 
    127   /**
    128    * Find instance field in this class matching field
    129    */
    130   public DexEncodedField findInstanceTarget(DexField field) {
    131     return findTarget(instanceFields(), field);
    132   }
    133 
    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.
    144   public boolean isInterface() {
    145     return accessFlags.isInterface();
    146   }
    147 
    148   public abstract void addDependencies(MixedSectionCollection collector);
    149 
    150   public boolean isProgramClass() {
    151     return false;
    152   }
    153 
    154   public DexProgramClass asProgramClass() {
    155     return null;
    156   }
    157 
    158   public boolean isClasspathClass() {
    159     return false;
    160   }
    161 
    162   public DexClasspathClass asClasspathClass() {
    163     return null;
    164   }
    165 
    166   public boolean isLibraryClass() {
    167     return false;
    168   }
    169 
    170   public DexLibraryClass asLibraryClass() {
    171     return null;
    172   }
    173 
    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 
    183   public Resource.Kind getOrigin() {
    184     return this.origin;
    185   }
    186 
    187   public boolean hasClassInitializer() {
    188     return getClassInitializer() != null;
    189   }
    190 
    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