| // Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| package com.android.tools.r8.graph; |
| |
| import com.android.tools.r8.ProgramResource; |
| import com.android.tools.r8.ProgramResource.Kind; |
| import com.android.tools.r8.dex.MixedSectionCollection; |
| import com.android.tools.r8.errors.Unreachable; |
| import com.android.tools.r8.graph.GenericSignature.ClassSignature; |
| import com.android.tools.r8.kotlin.KotlinClassLevelInfo; |
| import com.android.tools.r8.origin.Origin; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.function.Consumer; |
| import java.util.function.Predicate; |
| import java.util.function.Supplier; |
| |
| public class DexLibraryClass extends DexClass implements LibraryClass, Supplier<DexLibraryClass> { |
| |
| public DexLibraryClass( |
| DexType type, |
| ProgramResource.Kind kind, |
| Origin origin, |
| ClassAccessFlags accessFlags, |
| DexType superType, |
| DexTypeList interfaces, |
| DexString sourceFile, |
| NestHostClassAttribute nestHost, |
| List<NestMemberClassAttribute> nestMembers, |
| EnclosingMethodAttribute enclosingMember, |
| List<InnerClassAttribute> innerClasses, |
| ClassSignature classSignature, |
| DexAnnotationSet annotations, |
| DexEncodedField[] staticFields, |
| DexEncodedField[] instanceFields, |
| DexEncodedMethod[] directMethods, |
| DexEncodedMethod[] virtualMethods, |
| boolean skipNameValidationForTesting) { |
| super( |
| sourceFile, |
| interfaces, |
| accessFlags, |
| superType, |
| type, |
| staticFields, |
| instanceFields, |
| directMethods, |
| virtualMethods, |
| nestHost, |
| nestMembers, |
| enclosingMember, |
| innerClasses, |
| classSignature, |
| annotations, |
| origin, |
| skipNameValidationForTesting); |
| assert Arrays.stream(directMethods).allMatch(DexLibraryClass::verifyLibraryMethod); |
| assert Arrays.stream(virtualMethods).allMatch(DexLibraryClass::verifyLibraryMethod); |
| assert Arrays.stream(staticFields).allMatch(DexLibraryClass::verifyLibraryField); |
| assert Arrays.stream(instanceFields).allMatch(DexLibraryClass::verifyLibraryField); |
| // Set all static field values to unknown. We don't want to use the value from the library |
| // at compile time, as it can be different at runtime. |
| for (DexEncodedField staticField : staticFields) { |
| staticField.clearStaticValue(); |
| } |
| assert kind == Kind.CF : "Invalid kind " + kind + " for library-path class " + type; |
| } |
| |
| public static Builder builder(DexItemFactory dexItemFactory) { |
| return new Builder(dexItemFactory); |
| } |
| |
| public static DexLibraryClass asLibraryClassOrNull(DexClass clazz) { |
| return clazz != null ? clazz.asLibraryClass() : null; |
| } |
| |
| private static boolean verifyLibraryMethod(DexEncodedMethod method) { |
| assert !method.isClassInitializer(); |
| assert !method.isPrivateMethod(); |
| assert !method.hasCode(); |
| return true; |
| } |
| |
| private static boolean verifyLibraryField(DexEncodedField field) { |
| assert !field.isPrivate(); |
| assert !field.isStatic() || !field.hasExplicitStaticValue(); |
| return true; |
| } |
| |
| @Override |
| public void accept( |
| Consumer<DexProgramClass> programClassConsumer, |
| Consumer<DexClasspathClass> classpathClassConsumer, |
| Consumer<DexLibraryClass> libraryClassConsumer) { |
| libraryClassConsumer.accept(this); |
| } |
| |
| @Override |
| public String toString() { |
| return type.toString() + "(library class)"; |
| } |
| |
| @Override |
| public String toSourceString() { |
| return type.toSourceString() + "(library class)"; |
| } |
| |
| @Override |
| public void addDependencies(MixedSectionCollection collector) { |
| // Should never happen but does not harm. |
| assert false; |
| } |
| |
| @Override |
| public boolean isNotProgramClass() { |
| return true; |
| } |
| |
| @Override |
| public boolean isLibraryClass() { |
| return true; |
| } |
| |
| @Override |
| public DexLibraryClass asLibraryClass() { |
| return this; |
| } |
| |
| @Override |
| public DexLibraryClass asClasspathOrLibraryClass() { |
| return this; |
| } |
| |
| @Override |
| public KotlinClassLevelInfo getKotlinInfo() { |
| throw new Unreachable("We should never consider metadata for library classes"); |
| } |
| |
| @Override |
| public DexLibraryClass get() { |
| return this; |
| } |
| |
| @Override |
| boolean internalClassOrInterfaceMayHaveInitializationSideEffects( |
| AppView<?> appView, |
| DexClass initialAccessHolder, |
| Predicate<DexType> ignore, |
| Set<DexType> seen) { |
| if (!seen.add(getType()) || ignore.test(getType())) { |
| return false; |
| } |
| return isInterface() |
| ? appView.options().libraryInterfacesMayHaveStaticInitialization |
| : !appView.dexItemFactory().libraryClassesWithoutStaticInitialization.contains(type); |
| } |
| |
| public static class Builder { |
| |
| // Required. |
| private DexType type; |
| private ClassAccessFlags accessFlags; |
| |
| // Optional. |
| private Origin origin = Origin.unknown(); |
| private DexType superType; |
| private DexTypeList interfaces = DexTypeList.empty(); |
| private DexString sourceFile = null; |
| private NestHostClassAttribute nestHost = null; |
| private List<NestMemberClassAttribute> nestMembers = Collections.emptyList(); |
| private EnclosingMethodAttribute enclosingMember = null; |
| private List<InnerClassAttribute> innerClasses = Collections.emptyList(); |
| private ClassSignature classSignature = ClassSignature.noSignature(); |
| private DexAnnotationSet annotations = DexAnnotationSet.empty(); |
| private DexEncodedField[] staticFields = DexEncodedField.EMPTY_ARRAY; |
| private DexEncodedField[] instanceFields = DexEncodedField.EMPTY_ARRAY; |
| private DexEncodedMethod[] directMethods = DexEncodedMethod.EMPTY_ARRAY; |
| private DexEncodedMethod[] virtualMethods = DexEncodedMethod.EMPTY_ARRAY; |
| private boolean skipNameValidationForTesting; |
| |
| private Builder(DexItemFactory dexItemFactory) { |
| this.superType = dexItemFactory.objectType; |
| this.skipNameValidationForTesting = dexItemFactory.getSkipNameValidationForTesting(); |
| } |
| |
| public Builder setAccessFlags(ClassAccessFlags accessFlags) { |
| this.accessFlags = accessFlags; |
| return this; |
| } |
| |
| public Builder setDirectMethods(Collection<DexEncodedMethod> directMethods) { |
| this.directMethods = directMethods.toArray(DexEncodedMethod.EMPTY_ARRAY); |
| return this; |
| } |
| |
| public Builder setType(DexType type) { |
| this.type = type; |
| return this; |
| } |
| |
| public DexLibraryClass build() { |
| assert validate(); |
| return new DexLibraryClass( |
| type, |
| ProgramResource.Kind.CF, |
| origin, |
| accessFlags, |
| superType, |
| interfaces, |
| sourceFile, |
| nestHost, |
| nestMembers, |
| enclosingMember, |
| innerClasses, |
| classSignature, |
| annotations, |
| staticFields, |
| instanceFields, |
| directMethods, |
| virtualMethods, |
| skipNameValidationForTesting); |
| } |
| |
| private boolean validate() { |
| assert type != null; |
| assert accessFlags != null; |
| return true; |
| } |
| } |
| } |