blob: 84ce916b99f0ca194ada71c7cd407a3a9e009fa4 [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.jack;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Iterators;
import com.google.common.eventbus.EventBus;
import com.android.jack.Options.AssertionPolicy;
import com.android.jack.Options.SwitchEnumOptStrategy;
import com.android.jack.abort.Aborter;
import com.android.jack.analysis.DefinitionMarkerAdder;
import com.android.jack.analysis.DefinitionMarkerRemover;
import com.android.jack.analysis.UsedVariableAdder;
import com.android.jack.analysis.UsedVariableRemover;
import com.android.jack.analysis.defsuses.DefUsesAndUseDefsChainComputation;
import com.android.jack.analysis.defsuses.DefUsesAndUseDefsChainRemover;
import com.android.jack.analysis.defsuses.UseDefsChecker;
import com.android.jack.analysis.dependency.DependencyInLibraryProduct;
import com.android.jack.analysis.dependency.file.FileDependenciesCollector;
import com.android.jack.analysis.dependency.file.FileDependenciesInLibraryWriter;
import com.android.jack.analysis.dependency.library.LibraryDependenciesInLibraryWriter;
import com.android.jack.analysis.dependency.type.TypeDependenciesCollector;
import com.android.jack.analysis.dependency.type.TypeDependenciesInLibraryWriter;
import com.android.jack.analysis.dfa.reachingdefs.ReachingDefinitions;
import com.android.jack.analysis.tracer.SubClassOrInterfaceFinder;
import com.android.jack.api.impl.ApiFeature;
import com.android.jack.api.v01.impl.Api01Feature;
import com.android.jack.api.v02.impl.Api02Feature;
import com.android.jack.api.v03.impl.Api03Feature;
import com.android.jack.backend.ResourceWriter;
import com.android.jack.backend.dex.ClassAnnotationBuilder;
import com.android.jack.backend.dex.ClassDefItemBuilder;
import com.android.jack.backend.dex.ClassDefItemMarkerRemover;
import com.android.jack.backend.dex.DalvikProtectedInnerChecker;
import com.android.jack.backend.dex.DalvikProtectedInnerChecker.DalvikProtectedInnerCheck;
import com.android.jack.backend.dex.DexFileProduct;
import com.android.jack.backend.dex.DexFileWriter;
import com.android.jack.backend.dex.DexInLibraryProduct;
import com.android.jack.backend.dex.DexInLibraryWriterAll;
import com.android.jack.backend.dex.DexInLibraryWriterNoPrebuilt;
import com.android.jack.backend.dex.DexWritingTool;
import com.android.jack.backend.dex.EncodedFieldBuilder;
import com.android.jack.backend.dex.EncodedMethodBuilder;
import com.android.jack.backend.dex.EnsureAndroidCompatibility;
import com.android.jack.backend.dex.FieldAnnotationBuilder;
import com.android.jack.backend.dex.FieldInitializerRemover;
import com.android.jack.backend.dex.MainDexCollector;
import com.android.jack.backend.dex.MainDexTracer;
import com.android.jack.backend.dex.MethodAnnotationBuilder;
import com.android.jack.backend.dex.MethodBodyRemover;
import com.android.jack.backend.dex.MultiDex;
import com.android.jack.backend.dex.MultiDexAnnotationsFinder;
import com.android.jack.backend.dex.MultiDexLegacy;
import com.android.jack.backend.dex.MultiDexWritingTool;
import com.android.jack.backend.dex.OrphanDexFileWriter;
import com.android.jack.backend.dex.annotations.DefaultValueAnnotationAdder;
import com.android.jack.backend.dex.annotations.ParameterMetadataAnnotationsAdder;
import com.android.jack.backend.dex.annotations.ReflectAnnotationsAdder;
import com.android.jack.backend.dex.annotations.tag.ParameterMetadataFeature;
import com.android.jack.backend.dex.compatibility.AndroidCompatibilityChecker;
import com.android.jack.backend.dex.compatibility.CheckAndroidCompatibility;
import com.android.jack.backend.dex.multidex.legacy.AnnotatedFinder;
import com.android.jack.backend.dex.multidex.legacy.RuntimeAnnotationFinder;
import com.android.jack.backend.dex.rop.CodeItemBuilder;
import com.android.jack.backend.dex.rop.DexCodeMarkerRemover;
import com.android.jack.backend.jayce.JayceFileImporter;
import com.android.jack.backend.jayce.JayceInLibraryProduct;
import com.android.jack.backend.jayce.JayceInLibraryWriterAll;
import com.android.jack.backend.jayce.JayceInLibraryWriterNoPrebuilt;
import com.android.jack.cfg.CfgBuilder;
import com.android.jack.cfg.CfgMarkerRemover;
import com.android.jack.config.id.Carnac;
import com.android.jack.config.id.JavaVersionPropertyId.JavaVersion;
import com.android.jack.digest.OriginDigestAdder;
import com.android.jack.digest.OriginDigestFeature;
import com.android.jack.frontend.FrontendCompilationException;
import com.android.jack.frontend.MethodIdDuplicateRemover;
import com.android.jack.frontend.MethodIdMerger;
import com.android.jack.frontend.TypeDuplicateRemoverChecker;
import com.android.jack.frontend.VirtualMethodsMarker;
import com.android.jack.frontend.java.JackBatchCompiler;
import com.android.jack.frontend.java.JackBatchCompiler.TransportExceptionAroundEcjError;
import com.android.jack.frontend.java.JackBatchCompiler.TransportJUEAroundEcjError;
import com.android.jack.incremental.GenerateLibraryFromIncrementalFolder;
import com.android.jack.incremental.Incremental;
import com.android.jack.incremental.InputFilter;
import com.android.jack.ir.JackFormatIr;
import com.android.jack.ir.JavaSourceIr;
import com.android.jack.ir.ast.JCastOperation;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
import com.android.jack.ir.ast.JField;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JPackage;
import com.android.jack.ir.ast.JSession;
import com.android.jack.ir.ast.JSwitchStatement;
import com.android.jack.ir.ast.Resource;
import com.android.jack.ir.formatter.InternalFormatter;
import com.android.jack.ir.formatter.TypePackageAndMethodFormatter;
import com.android.jack.ir.formatter.UserFriendlyFormatter;
import com.android.jack.ir.sourceinfo.SourceInfoCreation;
import com.android.jack.jayce.JaycePackageLoader;
import com.android.jack.library.FileType;
import com.android.jack.library.InputJackLibrary;
import com.android.jack.library.InputLibrary;
import com.android.jack.library.JackLibraryFactory;
import com.android.jack.library.LibraryIOException;
import com.android.jack.library.LibraryReadingException;
import com.android.jack.library.LibraryWritingException;
import com.android.jack.library.OutputJackLibrary;
import com.android.jack.meta.LibraryMetaWriter;
import com.android.jack.meta.Meta;
import com.android.jack.optimizations.ConstantRefiner;
import com.android.jack.optimizations.DefUsesChainsSimplifier;
import com.android.jack.optimizations.ExpressionSimplifier;
import com.android.jack.optimizations.IfWithConstantSimplifier;
import com.android.jack.optimizations.NotSimplifier;
import com.android.jack.optimizations.Optimizations;
import com.android.jack.optimizations.UnusedDefinitionRemover;
import com.android.jack.optimizations.UseDefsChainsSimplifier;
import com.android.jack.optimizations.common.DirectlyDerivedClassesProvider;
import com.android.jack.optimizations.inlining.InlineAnnotatedMethods;
import com.android.jack.optimizations.inlining.InlineAnnotationSanityCheck;
import com.android.jack.optimizations.inlining.JMethodInliner;
import com.android.jack.optimizations.modifiers.ClassFinalizer;
import com.android.jack.optimizations.modifiers.FieldFinalizer;
import com.android.jack.optimizations.modifiers.MethodFinalizer;
import com.android.jack.optimizations.tailrecursion.TailRecursionOptimization;
import com.android.jack.optimizations.tailrecursion.TailRecursionOptimizer;
import com.android.jack.optimizations.valuepropagation.argument.AvpCalculateTaintedMethods;
import com.android.jack.optimizations.valuepropagation.argument.AvpCollectMethodCallArguments;
import com.android.jack.optimizations.valuepropagation.argument.AvpComputeMethodArgumentsValues;
import com.android.jack.optimizations.valuepropagation.argument.AvpPropagateArgumentValues;
import com.android.jack.optimizations.valuepropagation.field.FvpCollectFieldAssignments;
import com.android.jack.optimizations.valuepropagation.field.FvpPropagateFieldValues;
import com.android.jack.optimizations.wofr.WofrCollectFieldAccesses;
import com.android.jack.optimizations.wofr.WofrRemoveFieldWrites;
import com.android.jack.optimizations.wofr.WofrRemoveFields;
import com.android.jack.plugin.PluginManager;
import com.android.jack.plugin.v01.Plugin;
import com.android.jack.preprocessor.PreProcessor;
import com.android.jack.preprocessor.PreProcessorApplier;
import com.android.jack.reporting.ReportableIOException;
import com.android.jack.reporting.Reporter;
import com.android.jack.reporting.Reporter.Severity;
import com.android.jack.resource.LibraryResourceWriter;
import com.android.jack.scheduling.adapter.JDefinedClassOrInterfaceAdapter;
import com.android.jack.scheduling.adapter.JFieldAdapter;
import com.android.jack.scheduling.adapter.JMethodAdapter;
import com.android.jack.scheduling.adapter.JPackageAdapter;
import com.android.jack.scheduling.feature.CompiledTypeStats;
import com.android.jack.scheduling.feature.DropMethodBody;
import com.android.jack.scheduling.feature.Resources;
import com.android.jack.scheduling.feature.SourceVersion7;
import com.android.jack.scheduling.feature.SourceVersion8;
import com.android.jack.scheduling.feature.VisibilityBridge;
import com.android.jack.shrob.obfuscation.Mapping;
import com.android.jack.shrob.obfuscation.MappingPrinter;
import com.android.jack.shrob.obfuscation.NameFinalizer;
import com.android.jack.shrob.obfuscation.NameKeeper;
import com.android.jack.shrob.obfuscation.Obfuscation;
import com.android.jack.shrob.obfuscation.OriginalNames;
import com.android.jack.shrob.obfuscation.RemoveSourceFile;
import com.android.jack.shrob.obfuscation.Renamer;
import com.android.jack.shrob.obfuscation.SourceFileRemover;
import com.android.jack.shrob.obfuscation.SourceFileRenamer;
import com.android.jack.shrob.obfuscation.SourceFileRenaming;
import com.android.jack.shrob.obfuscation.annotation.AnnotationDefaultValueRemover;
import com.android.jack.shrob.obfuscation.annotation.FieldAnnotationRemover;
import com.android.jack.shrob.obfuscation.annotation.FieldGenericSignatureRemover;
import com.android.jack.shrob.obfuscation.annotation.LineNumberRemover;
import com.android.jack.shrob.obfuscation.annotation.LocalVariableAndThisNameRemover;
import com.android.jack.shrob.obfuscation.annotation.LocalVariableGenericSignatureRemover;
import com.android.jack.shrob.obfuscation.annotation.MethodAnnotationRemover;
import com.android.jack.shrob.obfuscation.annotation.MethodGenericSignatureRemover;
import com.android.jack.shrob.obfuscation.annotation.ParameterAnnotationRemover;
import com.android.jack.shrob.obfuscation.annotation.ParameterNameRemover;
import com.android.jack.shrob.obfuscation.annotation.RemoveAnnotationDefaultValue;
import com.android.jack.shrob.obfuscation.annotation.RemoveEnclosingMethodFeature;
import com.android.jack.shrob.obfuscation.annotation.RemoveEnclosingType;
import com.android.jack.shrob.obfuscation.annotation.RemoveGenericSignature;
import com.android.jack.shrob.obfuscation.annotation.RemoveLineNumber;
import com.android.jack.shrob.obfuscation.annotation.RemoveLocalVariableGenericSignature;
import com.android.jack.shrob.obfuscation.annotation.RemoveLocalVariableName;
import com.android.jack.shrob.obfuscation.annotation.RemoveParameterName;
import com.android.jack.shrob.obfuscation.annotation.RemoveThrownException;
import com.android.jack.shrob.obfuscation.annotation.ThrownExceptionRemover;
import com.android.jack.shrob.obfuscation.annotation.TypeAnnotationRemover;
import com.android.jack.shrob.obfuscation.annotation.TypeEnclosingMethodRemover;
import com.android.jack.shrob.obfuscation.annotation.TypeEnclosingTypeRemover;
import com.android.jack.shrob.obfuscation.annotation.TypeGenericSignatureRemover;
import com.android.jack.shrob.obfuscation.resource.AdaptResourceFileContent;
import com.android.jack.shrob.obfuscation.resource.ResourceContentRefiner;
import com.android.jack.shrob.obfuscation.resource.ResourceRefiner;
import com.android.jack.shrob.proguard.GrammarActions;
import com.android.jack.shrob.seed.SeedFile;
import com.android.jack.shrob.seed.SeedFinder;
import com.android.jack.shrob.seed.SeedPrinter;
import com.android.jack.shrob.shrink.FieldShrinker;
import com.android.jack.shrob.shrink.Keeper;
import com.android.jack.shrob.shrink.MethodShrinker;
import com.android.jack.shrob.shrink.ShrinkAndMainDexTracer;
import com.android.jack.shrob.shrink.ShrinkStructurePrinter;
import com.android.jack.shrob.shrink.Shrinking;
import com.android.jack.shrob.shrink.StructurePrinting;
import com.android.jack.shrob.shrink.TypeShrinker;
import com.android.jack.shrob.spec.Flags;
import com.android.jack.statistics.BinaryOperationWithCst;
import com.android.jack.statistics.CodeStats;
import com.android.jack.statistics.FieldStats;
import com.android.jack.statistics.MethodStats;
import com.android.jack.transformations.BoostLockedRegionPriorityFeature;
import com.android.jack.transformations.BridgeInInterfaceRemover;
import com.android.jack.transformations.EmptyClinitRemover;
import com.android.jack.transformations.FieldInitializer;
import com.android.jack.transformations.Jarjar;
import com.android.jack.transformations.OptimizedSwitchEnumFeedbackFeature;
import com.android.jack.transformations.OptimizedSwitchEnumNonFeedbackFeature;
import com.android.jack.transformations.SanityChecks;
import com.android.jack.transformations.UnusedLocalRemover;
import com.android.jack.transformations.VisibilityBridgeAdder;
import com.android.jack.transformations.annotation.ContainerAnnotationAdder;
import com.android.jack.transformations.annotation.ContainerAnnotationMarkerAdder;
import com.android.jack.transformations.assertion.AssertionRemover;
import com.android.jack.transformations.assertion.DisabledAssertionFeature;
import com.android.jack.transformations.assertion.DynamicAssertionFeature;
import com.android.jack.transformations.assertion.DynamicAssertionTransformer;
import com.android.jack.transformations.assertion.EnabledAssertionFeature;
import com.android.jack.transformations.assertion.EnabledAssertionTransformer;
import com.android.jack.transformations.ast.BooleanTestTransformer;
import com.android.jack.transformations.ast.BoostLockedRegionPriority;
import com.android.jack.transformations.ast.CompoundAssignmentRemover;
import com.android.jack.transformations.ast.ConcatRemover;
import com.android.jack.transformations.ast.ExpressionStatementLegalizer;
import com.android.jack.transformations.ast.ImplicitBlocks;
import com.android.jack.transformations.ast.ImplicitBlocksChecker;
import com.android.jack.transformations.ast.IncDecRemover;
import com.android.jack.transformations.ast.InitInNewArrayRemover;
import com.android.jack.transformations.ast.IntersectionTypeRemover;
import com.android.jack.transformations.ast.MultiDimensionNewArrayRemover;
import com.android.jack.transformations.ast.NestedAssignRemover;
import com.android.jack.transformations.ast.NumericConversionChecker;
import com.android.jack.transformations.ast.PrimitiveClassTransformer;
import com.android.jack.transformations.ast.RefAsStatementRemover;
import com.android.jack.transformations.ast.SynchronizeTransformer;
import com.android.jack.transformations.ast.TryWithResourcesTransformer;
import com.android.jack.transformations.ast.TypeLegalizer;
import com.android.jack.transformations.ast.inner.AvoidSynthethicAccessors;
import com.android.jack.transformations.ast.inner.InnerAccessorAdder;
import com.android.jack.transformations.ast.inner.InnerAccessorGenerator;
import com.android.jack.transformations.ast.inner.MethodCallDispatchAdjuster;
import com.android.jack.transformations.ast.inner.OptimizedInnerAccessorGenerator;
import com.android.jack.transformations.ast.inner.ReferencedOuterFieldsExposer;
import com.android.jack.transformations.ast.removeinit.FieldInitMethodCallRemover;
import com.android.jack.transformations.ast.removeinit.FieldInitMethodRemover;
import com.android.jack.transformations.ast.splitnew.SplitNewInstance;
import com.android.jack.transformations.ast.splitnew.SplitNewInstanceChecker;
import com.android.jack.transformations.ast.string.FieldGenericSignatureSplitter;
import com.android.jack.transformations.ast.string.FieldStringLiteralRefiner;
import com.android.jack.transformations.ast.string.MethodGenericSignatureSplitter;
import com.android.jack.transformations.ast.string.MethodStringLiteralRefiner;
import com.android.jack.transformations.ast.string.ReflectionStringLiteralRefiner;
import com.android.jack.transformations.ast.string.SimpleNameRefiner;
import com.android.jack.transformations.ast.string.TypeGenericSignatureSplitter;
import com.android.jack.transformations.ast.string.TypeStringLiteralRefiner;
import com.android.jack.transformations.ast.switches.SwitchStringSupport;
import com.android.jack.transformations.ast.switches.UselessCaseChecker;
import com.android.jack.transformations.ast.switches.UselessCaseRemover;
import com.android.jack.transformations.ast.switches.UselessSwitchesRemover;
import com.android.jack.transformations.booleanoperators.ConditionalAndOrRemover;
import com.android.jack.transformations.booleanoperators.ConditionalAndOrRemoverChecker;
import com.android.jack.transformations.cast.UselessCastRemover;
import com.android.jack.transformations.enums.EnumMappingMarkerRemover;
import com.android.jack.transformations.enums.SwitchEnumSupport;
import com.android.jack.transformations.enums.UsedEnumFieldCollector;
import com.android.jack.transformations.enums.UsedEnumFieldMarkerRemover;
import com.android.jack.transformations.enums.opt.OptimizedSwitchEnumSupport;
import com.android.jack.transformations.enums.opt.SwitchEnumUsageCollector;
import com.android.jack.transformations.exceptions.ExceptionRuntimeValueAdder;
import com.android.jack.transformations.exceptions.TryCatchRemover;
import com.android.jack.transformations.finallyblock.FinallyRemover;
import com.android.jack.transformations.flow.FlowNormalizer;
import com.android.jack.transformations.lambda.DefaultBridgeInLambdaAdder;
import com.android.jack.transformations.lambda.LambdaCollector;
import com.android.jack.transformations.lambda.LambdaConverter;
import com.android.jack.transformations.lambda.LambdaGroupClassCreator;
import com.android.jack.transformations.lambda.LambdaGroupClassFinalizer;
import com.android.jack.transformations.lambda.LambdaToAnonymousConverter;
import com.android.jack.transformations.parent.AstChecker;
import com.android.jack.transformations.parent.TypeAstChecker;
import com.android.jack.transformations.renamepackage.PackageRenamer;
import com.android.jack.transformations.rop.cast.RopCastLegalizer;
import com.android.jack.transformations.threeaddresscode.ThreeAddressCodeBuilder;
import com.android.jack.transformations.typedef.TypeDefRemover;
import com.android.jack.transformations.typedef.TypeDefRemover.RemoveTypeDef;
import com.android.jack.transformations.uselessif.UselessIfChecker;
import com.android.jack.transformations.uselessif.UselessIfRemover;
import com.android.jack.util.collect.UnmodifiableCollections;
import com.android.sched.item.Component;
import com.android.sched.reflections.ReflectionFactory;
import com.android.sched.schedulable.RunnableSchedulable;
import com.android.sched.scheduler.EvenSimplerPlanAmender;
import com.android.sched.scheduler.FeatureSet;
import com.android.sched.scheduler.IllegalRequestException;
import com.android.sched.scheduler.ManagedRunnable;
import com.android.sched.scheduler.Plan;
import com.android.sched.scheduler.PlanBuilder;
import com.android.sched.scheduler.PlanConstructor;
import com.android.sched.scheduler.PlanNotFoundException;
import com.android.sched.scheduler.PlanPrinterFactory;
import com.android.sched.scheduler.ProcessException;
import com.android.sched.scheduler.ProductionSet;
import com.android.sched.scheduler.Request;
import com.android.sched.scheduler.Scheduler;
import com.android.sched.scheduler.SubPlanBuilder;
import com.android.sched.scheduler.TagOrMarkerOrComponentSet;
import com.android.sched.util.RunnableHooks;
import com.android.sched.util.Version;
import com.android.sched.util.config.Config;
import com.android.sched.util.config.ConfigPrinterFactory;
import com.android.sched.util.config.ConfigurationException;
import com.android.sched.util.config.HasKeyId;
import com.android.sched.util.config.ReflectFactory;
import com.android.sched.util.config.ThreadConfig;
import com.android.sched.util.config.id.BooleanPropertyId;
import com.android.sched.util.config.id.ObjectId;
import com.android.sched.util.config.id.ReflectFactoryPropertyId;
import com.android.sched.util.file.CannotCloseException;
import com.android.sched.util.file.CannotWriteException;
import com.android.sched.util.file.ReaderFile;
import com.android.sched.util.log.Event;
import com.android.sched.util.log.LoggerFactory;
import com.android.sched.util.log.Tracer;
import com.android.sched.util.log.TracerFactory;
import com.android.sched.util.log.stats.Percent;
import com.android.sched.util.log.stats.PercentImpl;
import com.android.sched.util.log.stats.StatisticId;
import com.android.sched.util.log.stats.Value;
import com.android.sched.util.log.stats.ValueImpl;
import com.android.sched.vfs.Container;
import com.android.sched.vfs.ReadWriteZipFS;
import com.android.sched.vfs.VFS;
import org.antlr.runtime.RecognitionException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
* Executable class to run the jack compiler.
*/
@HasKeyId
public abstract class Jack {
@Nonnull
private static final Logger logger = LoggerFactory.getLogger();
@Nonnull
private static final TypePackageAndMethodFormatter lookupFormatter =
InternalFormatter.getFormatter();
@Nonnull
private static final TypePackageAndMethodFormatter userFriendlyFormatter =
UserFriendlyFormatter.getFormatter();
@Nonnull
public static final ObjectId<JSession> SESSION =
new ObjectId<JSession>("jack.session", JSession.class);
@Nonnull
private static final EventBus requestBus = new EventBus("JackResourceRequest");
// Compilation configuration kept in a static field to avoid ThreadConfig overhead
@CheckForNull
private static UnmodifiableCollections unmodifiableCollections;
@Nonnull
public static final
ReflectFactoryPropertyId<JaycePackageLoader> CLASSPATH_POLICY =
ReflectFactoryPropertyId.create(
"jack.internal.jayce.loader.classpath.policy",
"Hint on default load policy for classpath entries",
JaycePackageLoader.class)
.addArgType(InputJackLibrary.class)
.addArgType(JSession.class)
.bypassAccessibility()
.addDefaultValue("type");
@Nonnull
public static final
ReflectFactoryPropertyId<JaycePackageLoader> IMPORT_POLICY = ReflectFactoryPropertyId.create(
"jack.internal.jayce.loader.import.policy",
"Hint on default load policy for import entries",
JaycePackageLoader.class)
.addArgType(InputJackLibrary.class)
.addArgType(JSession.class)
.bypassAccessibility()
.addDefaultValue("type");
@Nonnull
public static final BooleanPropertyId STRICT_CLASSPATH = BooleanPropertyId.create(
"jack.classpath.strict", "Do not ignore missing or malformed class path entries")
.addDefaultValue(Boolean.FALSE).addCategory(Carnac.class);
@Nonnull
private static final StatisticId<Percent> INCOMPATIBLE_PREDEX = new StatisticId<
Percent>("jack.library.prebuilt.incompatible",
"Imported library incompatible prebuilts",
PercentImpl.class, Percent.class);
@Nonnull
public static JSession getSession() {
return ThreadConfig.get(Jack.SESSION);
}
@Nonnull
public static String getEmitterId() {
return "jack";
}
@Nonnull
public static UnmodifiableCollections getUnmodifiableCollections() {
if (unmodifiableCollections == null) {
unmodifiableCollections =
ThreadConfig.get(UnmodifiableCollections.UNMODIFIABLE_COLLECTION).create();
}
assert unmodifiableCollections != null; // FINDBUGS
return unmodifiableCollections;
}
public static void checkAndRun(@Nonnull Class<? extends ApiFeature> api, @Nonnull Options options)
throws IllegalOptionsException, ConfigurationException, JackUserException, ProcessException {
RunnableHooks hooks = new RunnableHooks();
try {
check(api, options, hooks);
run(api, options, hooks);
} catch (Throwable e1) {
// If any exception, run hooks and ignore exceptions
try {
hooks.runHooks();
} catch (Error | RuntimeException e2) {
// Ignored but already logged in runHooks.
}
throw e1;
}
// If everything goes well, run hooks and report exception
hooks.runHooks();
}
public static void check(
@SuppressWarnings("unused")
@Nonnull Class<? extends ApiFeature> api,
@Nonnull Options options,
@Nonnull RunnableHooks hooks)
throws IllegalOptionsException, ConfigurationException {
if (options.proguardFlagsFiles != null && !options.proguardFlagsFiles.isEmpty()) {
if (options.flags == null) {
options.flags = new Flags();
}
for (File proguardFlagsFile : options.getProguardFlagsFile()) {
try {
assert options.flags != null;
GrammarActions.parse(proguardFlagsFile.getPath(), ".", options.flags);
} catch (RecognitionException e) {
throw new IllegalOptionsException(
"Error while parsing '" + e.input.getSourceName() + "':" + e.line, e);
}
}
options.applyShrobFlags();
}
options.checkValidity(hooks);
Config config = options.getConfig();
boolean sanityChecks = config.get(Options.SANITY_CHECKS).booleanValue();
logger.log(Level.INFO, "Jack sanity checks {0}", (sanityChecks ? "enabled" : "disabled"));
}
/**
* Runs the jack compiler.
* @param options options for the compiler.
* @param hooks hooks that allow to attach actions that should be run after calling this method
* @throws JackUserException thrown to report information to the user
* @throws ProcessException thrown during schedulable execution
*/
public static void run(
@Nonnull Class<? extends ApiFeature> api,
@Nonnull Options options,
@Nonnull RunnableHooks hooks)
throws JackUserException, ProcessException {
try {
Config config = options.getConfig();
ThreadConfig.setConfig(config);
Tracer tracer = TracerFactory.getTracer();
try (Event event = tracer.open(JackEventType.JACK_RUN)) {
if (tracer.isTracing()) {
StatisticId<Value> id = new StatisticId<>("jack.version.jack", "Version of Jack",
ValueImpl.class, Value.class);
tracer.getStatistic(id).set(getVersion().getVerboseVersion());
for (Plugin plugin : options.getPluginManager().getPlugins()) {
id = new StatisticId<>(
"jack.version.plugin." + plugin.getCanonicalName().replace('.', '-'),
"Version of plugin " + plugin.getFriendlyName(), ValueImpl.class, Value.class);
tracer.getStatistic(id).set(plugin.getVersion().getVerboseVersion());
}
}
ConfigPrinterFactory.getConfigPrinter().printConfig(config);
JSession session = getSession();
OutputJackLibrary outputJackLibrary = null;
try {
outputJackLibrary = createOutputJackLibrary();
session.setJackOutputLibrary(outputJackLibrary);
buildSession(session, options, hooks);
PluginManager pluginManager = options.getPluginManager();
Scheduler scheduler =
new Scheduler(pluginManager.getReflectionManager(ReflectionFactory.getManager()));
Request request = createInitialRequest(scheduler);
request.addFeature(api);
request.addFeature(PreProcessor.class);
request.addFeature(Resources.class);
JavaVersion sourceVersion = config.get(Options.JAVA_SOURCE_VERSION);
if (sourceVersion.compareTo(JavaVersion.JAVA_7) >= 0) {
request.addFeature(SourceVersion7.class);
}
if (sourceVersion.compareTo(JavaVersion.JAVA_8) >= 0) {
request.addFeature(SourceVersion8.class);
}
if (config.get(Options.DROP_METHOD_BODY).booleanValue()) {
request.addFeature(DropMethodBody.class);
}
if (config.get(Options.ENABLE_COMPILED_FILES_STATISTICS).booleanValue()) {
request.addFeature(CompiledTypeStats.class);
request.addFeature(CodeStats.class);
}
if (config.get(Options.SANITY_CHECKS).booleanValue()) {
request.addFeature(SanityChecks.class);
}
if (config.get(OriginDigestFeature.ORIGIN_DIGEST).booleanValue()) {
request.addFeature(OriginDigestFeature.class);
}
if (config.get(PackageRenamer.JARJAR_ENABLED).booleanValue()) {
request.addFeature(Jarjar.class);
}
if (config.get(VisibilityBridgeAdder.VISIBILITY_BRIDGE).booleanValue()) {
request.addFeature(VisibilityBridge.class);
}
if (options.flags != null) {
if (options.flags.shrink()) {
request.addFeature(Shrinking.class);
}
if (options.flags.obfuscate()) {
request.addFeature(Obfuscation.class);
if (!options.flags.keepAttribute("EnclosingMethod")) {
request.addFeature(RemoveEnclosingMethodFeature.class);
}
if (!options.flags.keepAttribute("InnerClasses")) {
request.addFeature(RemoveEnclosingType.class);
}
if (!options.flags.keepAttribute("Signature")) {
request.addFeature(RemoveGenericSignature.class);
}
if (!options.flags.keepAttribute("AnnotationDefault")) {
request.addFeature(RemoveAnnotationDefaultValue.class);
}
if (!options.flags.keepAttribute("LocalVariableTypeTable")) {
request.addFeature(RemoveLocalVariableGenericSignature.class);
}
if (!options.flags.keepAttribute("Exceptions")) {
request.addFeature(RemoveThrownException.class);
}
if (!options.flags.keepAttribute("SourceFile")) {
request.addFeature(RemoveSourceFile.class);
}
if (!options.flags.keepAttribute("LineNumberTable")) {
request.addFeature(RemoveLineNumber.class);
}
if (!options.flags.keepAttribute("LocalVariableTable")) {
request.addFeature(RemoveLocalVariableName.class);
if (!options.flags.getKeepParameterNames()) {
request.addFeature(RemoveParameterName.class);
}
}
}
if (options.flags.printSeeds()) {
request.addProduction(SeedFile.class);
}
if (options.flags.getRenameSourceFileAttribute() != null) {
request.addFeature(SourceFileRenaming.class);
}
if (options.flags.getAdaptResourceFileContents() != null) {
request.addFeature(AdaptResourceFileContent.class);
}
}
if (config.get(MappingPrinter.MAPPING_OUTPUT_ENABLED).booleanValue()) {
request.addProduction(Mapping.class);
}
if (config.get(ShrinkStructurePrinter.STRUCTURE_PRINTING).booleanValue()) {
request.addProduction(StructurePrinting.class);
}
if (config.get(MultiDexLegacy.MULTIDEX_LEGACY).booleanValue()) {
request.addFeature(MultiDexLegacy.class);
}
request.addFeature(DalvikProtectedInnerCheck.class);
DexWritingTool dexWritingTool = config.get(DexFileWriter.DEX_WRITING_POLICY);
if (dexWritingTool instanceof MultiDexWritingTool) {
request.addFeature(MultiDex.class);
}
if (config.get(Options.INCREMENTAL_MODE).booleanValue()) {
request.addFeature(Incremental.class);
}
if (config.get(Options.GENERATE_LIBRARY_FROM_INCREMENTAL_FOLDER).booleanValue()) {
request.addFeature(GenerateLibraryFromIncrementalFolder.class);
}
if (config.get(Options.OPTIMIZE_INNER_CLASSES_ACCESSORS).booleanValue()) {
request.addFeature(AvoidSynthethicAccessors.class);
}
if (config.get(Options.OPTIMIZE_TAIL_RECURSION).booleanValue()) {
request.addFeature(TailRecursionOptimization.class);
}
request.addInitialTagsOrMarkers(getJavaSourceInitialTagSet(scheduler));
request.addInitialTagsOrMarkers(getJackFormatInitialTagSet(scheduler));
if (config.get(Options.GENERATE_DEX_IN_LIBRARY).booleanValue()) {
request.addProduction(DexInLibraryProduct.class);
if (api != Api01Feature.class &&
api != Api02Feature.class &&
api != Api03Feature.class) {
request.addFeature(CheckAndroidCompatibility.class);
}
}
if (config.get(Options.LAMBDA_TO_ANONYMOUS_CONVERTER).booleanValue()) {
request.addFeature(LambdaToAnonymousConverter.class);
}
if (config.get(Options.GENERATE_DEX_FILE).booleanValue()) {
request.addProduction(DexFileProduct.class);
session.addGeneratedFileType(FileType.PREBUILT);
request.addFeature(EnsureAndroidCompatibility.class);
}
if (config.get(AndroidCompatibilityChecker.CHECK_COMPATIBILITY).booleanValue()) {
request.addFeature(CheckAndroidCompatibility.class);
}
if (config.get(Options.OPTIMIZED_ENUM_SWITCH) == SwitchEnumOptStrategy.FEEDBACK) {
request.addFeature(OptimizedSwitchEnumFeedbackFeature.class);
} else if (config.get(Options.OPTIMIZED_ENUM_SWITCH) == SwitchEnumOptStrategy.ALWAYS) {
request.addFeature(OptimizedSwitchEnumNonFeedbackFeature.class);
}
if (config.get(Optimizations.DefUseSimplifier.ENABLE).booleanValue()) {
request.addFeature(Optimizations.DefUseSimplifier.class);
}
if (config.get(Optimizations.UseDefSimplifier.ENABLE).booleanValue()) {
request.addFeature(Optimizations.UseDefSimplifier.class);
}
if (config.get(Optimizations.ExpressionSimplifier.ENABLE).booleanValue()) {
request.addFeature(Optimizations.ExpressionSimplifier.class);
}
if (config.get(Optimizations.IfSimplifier.ENABLE).booleanValue()) {
request.addFeature(Optimizations.IfSimplifier.class);
}
if (config.get(Optimizations.NotSimplifier.ENABLE).booleanValue()) {
request.addFeature(Optimizations.NotSimplifier.class);
}
if (config.get(BoostLockedRegionPriorityFeature.ENABLE).booleanValue()) {
request.addFeature(BoostLockedRegionPriorityFeature.class);
}
if (config.get(Optimizations.ClassFinalizer.ENABLE).booleanValue()) {
request.addFeature(Optimizations.ClassFinalizer.class);
}
if (config.get(Optimizations.MethodFinalizer.ENABLE).booleanValue()) {
request.addFeature(Optimizations.MethodFinalizer.class);
}
if (config.get(Optimizations.FieldFinalizer.ENABLE).booleanValue()) {
request.addFeature(Optimizations.FieldFinalizer.class);
}
if (config.get(Optimizations.FieldValuePropagation.ENABLE).booleanValue()) {
request.addFeature(Optimizations.FieldValuePropagation.class);
}
if (config.get(Optimizations.ArgumentValuePropagation.ENABLE).booleanValue()) {
request.addFeature(Optimizations.ArgumentValuePropagation.class);
}
if (config.get(Optimizations.WriteOnlyFieldRemoval.ENABLE).booleanValue()) {
request.addFeature(Optimizations.WriteOnlyFieldRemoval.class);
}
if (config.get(Optimizations.InlineAnnotatedMethods.ENABLE).booleanValue()) {
request.addFeature(Optimizations.InlineAnnotatedMethods.class);
}
if (config.get(Options.ASSERTION_POLICY) == AssertionPolicy.ALWAYS) {
request.addFeature(EnabledAssertionFeature.class);
} else if (config.get(Options.ASSERTION_POLICY) == AssertionPolicy.RUNTIME) {
request.addFeature(DynamicAssertionFeature.class);
} else if (config.get(Options.ASSERTION_POLICY) == AssertionPolicy.NEVER) {
request.addFeature(DisabledAssertionFeature.class);
}
if (config.get(Options.GENERATE_JAYCE_IN_LIBRARY).booleanValue()) {
request.addProduction(JayceInLibraryProduct.class);
}
if (config.get(Options.GENERATE_DEPENDENCIES_IN_LIBRARY).booleanValue()) {
request.addProduction(DependencyInLibraryProduct.class);
}
if (config.get(TypeDefRemover.REMOVE_TYPEDEF).booleanValue()) {
request.addFeature(TypeDefRemover.RemoveTypeDef.class);
}
if (config.get(ParameterMetadataAnnotationsAdder.PARAMETER_ANNOTATION).booleanValue()) {
request.addFeature(ParameterMetadataFeature.class);
}
List<InputLibrary> importedLibraries = session.getImportedLibraries();
for (InputLibrary il : importedLibraries) {
if (!il.containsFileType(FileType.PREBUILT)) {
logger.log(Level.INFO,
il.getLocation().getDescription() + " does not have prebuilts.");
}
}
Percent incompatiblePredexStatistic = tracer.getStatistic(INCOMPATIBLE_PREDEX);
boolean usePrebuilt = config.get(Options.USE_PREBUILT_FROM_LIBRARY).booleanValue();
for (InputLibrary il : importedLibraries) {
boolean compatible = ((InputJackLibrary) il).hasCompliantPrebuilts();
incompatiblePredexStatistic.add(!compatible);
if (!usePrebuilt || !compatible) {
((InputJackLibrary) il).fileTypes.remove(FileType.PREBUILT);
}
}
ProductionSet targetProduction = request.getTargetProductions();
FeatureSet features = request.getFeatures();
PlanBuilder<JSession> planBuilder;
try {
planBuilder = request.getPlanBuilder(JSession.class);
} catch (IllegalRequestException e) {
throw new AssertionError(e);
}
if (features.contains(OriginDigestFeature.class)) {
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan.append(OriginDigestAdder.class);
}
planBuilder.append(PreProcessorApplier.class);
fillDexPlan(planBuilder);
if (targetProduction.contains(DexFileProduct.class)) {
planBuilder.append(DexFileWriter.class);
}
if (features.contains(Resources.class)) {
if (targetProduction.contains(DexFileProduct.class)) {
planBuilder.append(ResourceWriter.class);
}
if (targetProduction.contains(JayceInLibraryProduct.class)) {
planBuilder.append(LibraryResourceWriter.class);
}
}
if (targetProduction.contains(JayceInLibraryProduct.class)) {
planBuilder.append(LibraryMetaWriter.class);
}
if (targetProduction.contains(JayceInLibraryProduct.class)
&& targetProduction.contains(DexInLibraryProduct.class)) {
// Orphan dex files must only be copied into a Jack library when prebuilts are requested
// (DexInLibraryProduct). Jack must also check JayceInLibraryProduct to be sure that a
// Jack library is requested since DexInLibraryProduct is also used to generate an
// internal intermediate library that must not be take into account.
planBuilder.append(OrphanDexFileWriter.class);
}
Plan<JSession> plan = null;
try {
try {
// Try to build an automatic plan ...
plan = request.buildPlan(JSession.class);
} catch (IllegalRequestException e) {
throw new AssertionError(e);
} catch (PlanNotFoundException e) {
throw new AssertionError(e);
}
} catch (UnsupportedOperationException e) {
// ... but use a manual one if not supported
if (pluginManager.hasPlugins()) {
// If there are some plugins, amend the handcrafted plan
// Add features and productions according to plugins
for (Plugin plugin : pluginManager.getPlugins()) {
request.addFeatures(plugin.getFeatures(config, scheduler));
request.addProductions(plugin.getProductions(config, scheduler));
}
PlanConstructor<JSession> ctor =
new PlanConstructor<JSession>(request, JSession.class, planBuilder);
EvenSimplerPlanAmender<JSession> amender = new EvenSimplerPlanAmender<JSession>();
for (Plugin plugin : pluginManager.getPlugins()) {
Collection<Class<? extends RunnableSchedulable<? extends Component>>> classes =
plugin.getSortedRunners();
List<ManagedRunnable> runners = new ArrayList<ManagedRunnable>(classes.size());
for (Class<? extends RunnableSchedulable<? extends Component>> c : classes) {
runners.add(
(ManagedRunnable) scheduler.getSchedulableManager().getManagedSchedulable(c));
}
if (!amender.amendPlan(request, JSession.class, runners, ctor)) {
throw new JackUserException("Jack cannot insert plugin '"
+ plugin.getFriendlyName() + "' (" + plugin.getCanonicalName() + ")");
}
}
if (!ctor.isValid()) {
String list = Joiner.on(", ")
.appendTo(new StringBuilder(), Iterators.<Plugin, String>transform(
pluginManager.getPlugins().iterator(), new Function<Plugin, String>() {
@Override
public String apply(Plugin plugin) {
return "'" + plugin.getFriendlyName() + "' ("
+ plugin.getCanonicalName() + ")";
}
}))
.toString();
throw new JackUserException("Jack cannot insert plugin(s) " + list);
}
try {
assert ctor != null;
plan = ctor.getPlanBuilder().getPlan();
logger.log(Level.FINE, "Plan candidate: {0}", plan);
} catch (IllegalRequestException ire) {
throw new AssertionError(ire);
}
} else {
// ... without plugins, use the handcrafted plan as is
plan = planBuilder.getPlan();
}
}
assert plan != null;
assert !targetProduction.contains(JayceInLibraryProduct.class) ||
targetProduction.contains(DexFileProduct.class) ||
(plan.computeFinalTagsOrMarkers(request.getInitialTags()).contains(
JackFormatIr.class) &&
!targetProduction.contains(DexInLibraryProduct.class)) ||
((targetProduction.contains(DexInLibraryProduct.class) &&
targetProduction.contains(JayceInLibraryProduct.class)) ||
!config.get(Options.GENERATE_DEX_IN_LIBRARY).booleanValue());
try {
PlanPrinterFactory.getPlanPrinter().printPlan(plan);
} catch (CannotWriteException e) {
session.getReporter().report(Severity.FATAL, new ReportableIOException("Plan", e));
session.abortEventually();
}
assert plan != null;
try (Event allJackSchedulablesEvent = tracer.open(JackEventType.ALL_JACK_SCHEDULABLES)) {
plan.getScheduleInstance().process(session);
}
} finally {
if (outputJackLibrary != null) {
try {
outputJackLibrary.close();
} catch (LibraryIOException e) {
LibraryWritingException reportable = new LibraryWritingException(e);
Jack.getSession().getReporter().report(Severity.FATAL, reportable);
throw new JackAbortException(reportable);
}
}
// TODO(jack-team): auto-close
if (config.get(Options.GENERATE_DEX_FILE).booleanValue()
&& config.get(Options.DEX_OUTPUT_CONTAINER_TYPE) == Container.ZIP) {
try {
config.get(Options.DEX_OUTPUT_ZIP).close();
} catch (CannotCloseException e) {
ReportableIOException ioReportable = new ReportableIOException("Dex output", e);
throw new JackAbortException(ioReportable);
}
}
for (InputLibrary importedLibrary : session.getImportedLibraries()) {
try {
importedLibrary.close();
} catch (LibraryIOException e) {
session.getReporter().report(Severity.FATAL, new LibraryReadingException(e));
session.abortEventually();
}
}
for (InputLibrary classpathLibrary : session.getLibraryOnClasspath()) {
try {
classpathLibrary.close();
} catch (LibraryIOException e) {
session.getReporter().report(Severity.FATAL, new LibraryReadingException(e));
session.abortEventually();
}
}
}
}
} finally {
ThreadConfig.unsetConfig();
}
}
@Nonnull
private static OutputJackLibrary createOutputJackLibrary() {
VFS outputJackVfs = null;
if (ThreadConfig.get(Options.GENERATE_LIBRARY_FROM_INCREMENTAL_FOLDER).booleanValue()) {
VFS dirVFS = ThreadConfig.get(Options.LIBRARY_OUTPUT_DIR);
outputJackVfs = ThreadConfig.get(Options.LIBRARY_OUTPUT_ZIP);
((ReadWriteZipFS) outputJackVfs).setWorkVFS(dirVFS);
} else {
if (ThreadConfig.get(Options.LIBRARY_OUTPUT_CONTAINER_TYPE) == Container.DIR) {
outputJackVfs = ThreadConfig.get(Options.LIBRARY_OUTPUT_DIR);
} else {
outputJackVfs = ThreadConfig.get(Options.LIBRARY_OUTPUT_ZIP);
}
}
return JackLibraryFactory.getOutputLibrary(outputJackVfs,
Jack.getEmitterId(), Jack.getVersion().getVerboseVersion());
}
@Nonnull
public static Request createInitialRequest(@Nonnull Scheduler scheduler) {
Request request = scheduler.createScheduleRequest();
request.addSchedulables(scheduler.getAllSchedulable());
return request;
}
@Nonnull
public static TagOrMarkerOrComponentSet getJavaSourceInitialTagSet(@Nonnull Scheduler scheduler) {
TagOrMarkerOrComponentSet set = scheduler.createTagOrMarkerOrComponentSet();
set.add(JavaSourceIr.class);
set.add(OriginalNames.class);
set.add(SourceInfoCreation.class);
if (ThreadConfig.get(Options.JAVA_SOURCE_VERSION).compareTo(JavaVersion.JAVA_7) >= 0) {
set.add(JSwitchStatement.SwitchWithString.class);
}
if (ThreadConfig.get(Options.JAVA_SOURCE_VERSION).compareTo(JavaVersion.JAVA_8) >= 0) {
set.add(JCastOperation.WithIntersectionType.class);
}
return set;
}
@Nonnull
public static TagOrMarkerOrComponentSet getJackFormatInitialTagSet(@Nonnull Scheduler scheduler) {
TagOrMarkerOrComponentSet set = scheduler.createTagOrMarkerOrComponentSet();
set.add(JackFormatIr.class);
set.add(OriginalNames.class);
set.add(SourceInfoCreation.class);
return set;
}
@Nonnull
static JSession buildSession(@Nonnull Options options,
@Nonnull RunnableHooks hooks) throws JackUserException {
JSession session = getSession();
buildSession(session, options, hooks);
return session;
}
@Nonnull
private static void buildSession(@Nonnull JSession session, @Nonnull Options options,
@Nonnull RunnableHooks hooks) throws JackUserException {
Tracer tracer = TracerFactory.getTracer();
session.setHooks(hooks);
session.setReporter(ThreadConfig.get(Reporter.REPORTER));
Config config = ThreadConfig.getConfig();
InputFilter inputFilter;
try {
inputFilter = config.get(Options.INPUT_FILTER).create(options);
session.setInputFilter(inputFilter);
} catch (RuntimeException e) {
Throwable cause = e.getCause();
if (cause instanceof JackAbortException) {
throw (JackAbortException) cause;
} else if (cause instanceof JackUserException) {
throw (JackUserException) cause;
} else {
throw e;
}
}
List<InputJackLibrary> inputJackLibraries = new ArrayList<InputJackLibrary>();
for (InputLibrary library : inputFilter.getImportedLibraries()) {
if (library instanceof InputJackLibrary) {
addPackageLoaderForLibrary(session, config.get(IMPORT_POLICY),
(InputJackLibrary) library);
inputJackLibraries.add((InputJackLibrary) library);
session.addImportedLibrary(library);
}
}
JayceFileImporter jayceImporter = new JayceFileImporter(inputJackLibraries);
for (InputLibrary library : inputFilter.getClasspath()) {
if (library instanceof InputJackLibrary) {
addPackageLoaderForLibrary(session, config.get(CLASSPATH_POLICY),
(InputJackLibrary) library);
session.addLibraryOnClasspath(library);
}
}
Set<ReaderFile> fileNamesToCompile = inputFilter.getFileToCompile();
if (!fileNamesToCompile.isEmpty()) {
JackBatchCompiler jbc = new JackBatchCompiler(session);
try (Event event = tracer.open(JackEventType.ECJ_COMPILATION)) {
List<String> ecjExtraArguments = options.getEcjExtraArguments();
List<String> ecjArguments =
new ArrayList<String>(ecjExtraArguments.size() + fileNamesToCompile.size());
ecjArguments.addAll(ecjExtraArguments);
for (ReaderFile rf : fileNamesToCompile) {
ecjArguments.add(rf.getPath() + "[" + rf.getCharset().name() + "]");
}
try {
if (!jbc.compile(ecjArguments.toArray(new String[ecjArguments.size()]))) {
throw new FrontendCompilationException("Failed to compile");
}
} catch (TransportExceptionAroundEcjError e) {
throw e.getCause();
} catch (TransportJUEAroundEcjError e) {
throw e.getCause();
}
}
}
// we're assuming that there is no resource in the session yet, or we would have to check for
// conflicts
assert session.getResources().isEmpty();
for (Resource resource : inputFilter.getImportedResources()) {
session.addResource(resource);
}
for (Meta meta : inputFilter.getImportedMetas()) {
session.addMeta(meta);
}
try {
jayceImporter.doJayceImport(session);
jayceImporter.doResourceImport(session);
} catch (LibraryReadingException e) {
session.getReporter().report(Severity.FATAL, e);
throw new JackAbortException(e);
}
}
private static void addPackageLoaderForLibrary(JSession session,
ReflectFactory<JaycePackageLoader> factory, InputJackLibrary inputJackLibrary) {
if (inputJackLibrary.containsFileType(FileType.JAYCE)) {
JaycePackageLoader rootPLoader =
factory.create(inputJackLibrary, session);
session.getTopLevelPackage().addLoader(rootPLoader);
}
}
private static void appendMultiDexAndShrobStartPlan(@Nonnull PlanBuilder<JSession> planBuilder) {
ProductionSet productions = planBuilder.getRequest().getTargetProductions();
FeatureSet features = planBuilder.getRequest().getFeatures();
boolean shrinking = features.contains(Shrinking.class);
boolean obfuscating = features.contains(Obfuscation.class);
boolean multiDexLegacy = features.contains(MultiDexLegacy.class);
boolean multiDex = features.contains(MultiDex.class);
if (!(shrinking || obfuscating || multiDex || productions.contains(SeedFile.class))) {
// nothing to do
return;
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
if (shrinking || obfuscating || productions.contains(SeedFile.class)) {
typePlan.append(SeedFinder.class);
}
if (multiDex) {
typePlan.append(MultiDexAnnotationsFinder.class);
}
if (multiDexLegacy) {
typePlan.append(RuntimeAnnotationFinder.class);
typePlan.append(AnnotatedFinder.class);
}
if (multiDexLegacy || shrinking || obfuscating) {
SubPlanBuilder<JPackage> packagePlan = planBuilder.appendSubPlan(JPackageAdapter.class);
packagePlan.append(SubClassOrInterfaceFinder.class);
}
}
if (shrinking) {
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
Request request = planBuilder.getRequest();
if (multiDexLegacy &&
request.getTargetProductions().contains(DexFileProduct.class)) {
typePlan.append(ShrinkAndMainDexTracer.class);
} else {
typePlan.append(Keeper.class);
}
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan.append(TypeShrinker.class);
{
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
methodPlan.append(MethodShrinker.class);
}
{
SubPlanBuilder<JField> fieldPlan = typePlan.appendSubPlan(JFieldAdapter.class);
fieldPlan.append(FieldShrinker.class);
}
}
} else if (multiDexLegacy) {
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan.append(MainDexTracer.class);
}
if (multiDex) {
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan.append(MainDexCollector.class);
}
}
private static void appendStringRefiners(@Nonnull PlanBuilder<JSession> planBuilder) {
FeatureSet features = planBuilder.getRequest().getFeatures();
boolean shrinking = features.contains(Shrinking.class);
if (shrinking || features.contains(Obfuscation.class) || features.contains(Jarjar.class)) {
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan.append(TypeGenericSignatureSplitter.class);
typePlan.append(TypeStringLiteralRefiner.class);
typePlan.append(SimpleNameRefiner.class);
{
SubPlanBuilder<JMethod> methodPlan =
typePlan.appendSubPlan(JMethodAdapter.class);
methodPlan.append(MethodGenericSignatureSplitter.class);
methodPlan.append(ReflectionStringLiteralRefiner.class);
methodPlan.append(MethodStringLiteralRefiner.class);
}
{
SubPlanBuilder<JField> fieldPlan =
typePlan.appendSubPlan(JFieldAdapter.class);
fieldPlan.append(FieldGenericSignatureSplitter.class);
fieldPlan.append(FieldStringLiteralRefiner.class);
}
}
}
static void fillDexPlan(@Nonnull PlanBuilder<JSession> planBuilder) {
FeatureSet features = planBuilder.getRequest().getFeatures();
ProductionSet productions = planBuilder.getRequest().getTargetProductions();
boolean hasSanityChecks = features.contains(SanityChecks.class);
// Build the plan
if (features.contains(Shrinking.class) || features.contains(Obfuscation.class)
|| features.contains(MultiDexLegacy.class)) {
planBuilder.append(MethodIdMerger.class);
planBuilder.append(VirtualMethodsMarker.Remover.class);
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class)
.append(MethodIdDuplicateRemover.class);
}
if (hasSanityChecks) {
planBuilder.append(TypeDuplicateRemoverChecker.class);
}
if (features.contains(RemoveTypeDef.class)) {
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan.append(TypeDefRemover.class);
}
appendStringRefiners(planBuilder);
if (features.contains(Jarjar.class)) {
planBuilder.append(PackageRenamer.class);
}
if (hasSanityChecks) {
planBuilder.append(AstChecker.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
{
if (features.contains(CompiledTypeStats.class)) {
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
methodPlan.append(MethodStats.class);
}
}
{
SubPlanBuilder<JField> fieldPlan = typePlan.appendSubPlan(JFieldAdapter.class);
if (features.contains(CompiledTypeStats.class)) {
fieldPlan.append(FieldStats.class);
}
fieldPlan.append(FieldInitializerRemover.class);
fieldPlan.append(ContainerAnnotationMarkerAdder.FieldContainerAnnotationMarkerAdder.class);
}
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan.append(UsedEnumFieldCollector.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan2 =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
{
if (features.contains(VisibilityBridge.class)) {
typePlan2.append(VisibilityBridgeAdder.class);
}
if (features.contains(SourceVersion7.class)) {
SubPlanBuilder<JMethod> methodPlan = typePlan2.appendSubPlan(JMethodAdapter.class);
if (features.contains(SourceVersion7.class)) {
methodPlan.append(TryWithResourcesTransformer.class);
}
}
}
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan3 =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
{
{
SubPlanBuilder<JMethod> methodPlan2 =
typePlan3.appendSubPlan(JMethodAdapter.class);
methodPlan2.append(ImplicitBlocks.class);
if (hasSanityChecks) {
methodPlan2.append(ImplicitBlocksChecker.class);
}
if (hasSanityChecks) {
methodPlan2.append(UselessIfChecker.class);
}
methodPlan2.append(IncDecRemover.class);
methodPlan2.append(CompoundAssignmentRemover.class);
methodPlan2.append(ConcatRemover.class);
}
}
}
if (features.contains(OptimizedSwitchEnumFeedbackFeature.class)) {
// add one more traversal at compile-time to collect the usage for each enum,
// figure out how many classes use enum in switch statement.
// this step is enabled only when feedback-based optimization is enabled
SubPlanBuilder<JDefinedClassOrInterface> typePlan = planBuilder.appendSubPlan(
JDefinedClassOrInterfaceAdapter.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
methodPlan.append(SwitchEnumUsageCollector.class);
}
if ((features.contains(OptimizedSwitchEnumFeedbackFeature.class)
|| features.contains(OptimizedSwitchEnumNonFeedbackFeature.class))
&& hasSanityChecks) {
// check the validity of instrumentation if switch enum optimization and
// hasSanityCheck are both set
planBuilder.append(AstChecker.class);
}
// InnerAccessor visits inner types while running on outer
// types and therefore should be alone in its plan.
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
if (features.contains(AvoidSynthethicAccessors.class)) {
typePlan.append(OptimizedInnerAccessorGenerator.class);
} else {
typePlan.append(InnerAccessorGenerator.class);
}
}
if (features.contains(AvoidSynthethicAccessors.class)) {
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan.append(ReferencedOuterFieldsExposer.class);
SubPlanBuilder<JDefinedClassOrInterface> typePlan2 =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
SubPlanBuilder<JMethod> methodPlan =
typePlan2.appendSubPlan(JMethodAdapter.class);
methodPlan.append(MethodCallDispatchAdjuster.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan4 =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan4.append(InnerAccessorAdder.class);
{
SubPlanBuilder<JMethod> methodPlan =
typePlan4.appendSubPlan(JMethodAdapter.class);
methodPlan.append(FlowNormalizer.class);
methodPlan
.append(ContainerAnnotationMarkerAdder.MethodContainerAnnotationMarkerAdder.class);
if (features.contains(SourceVersion7.class)) {
methodPlan.append(SwitchStringSupport.class);
}
}
{
SubPlanBuilder<JMethod> methodPlan3 =
typePlan4.appendSubPlan(JMethodAdapter.class);
methodPlan3.append(FieldInitMethodCallRemover.class);
if (features.contains(TailRecursionOptimization.class)) {
methodPlan3.append(TailRecursionOptimizer.class);
}
}
typePlan4.append(FieldInitMethodRemover.class);
}
appendMultiDexAndShrobStartPlan(planBuilder);
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan = planBuilder.appendSubPlan(
JDefinedClassOrInterfaceAdapter.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
if (features.contains(OptimizedSwitchEnumFeedbackFeature.class)
|| features.contains(OptimizedSwitchEnumNonFeedbackFeature.class)) {
methodPlan.append(OptimizedSwitchEnumSupport.class);
} else {
methodPlan.append(SwitchEnumSupport.class);
}
typePlan.append(UsedEnumFieldMarkerRemover.class);
typePlan.append(ContainerAnnotationMarkerAdder.TypeContainerAnnotationMarkerAdder.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan = planBuilder.appendSubPlan(
JDefinedClassOrInterfaceAdapter.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
methodPlan.append(EnumMappingMarkerRemover.class);
}
if (features.contains(Obfuscation.class)) {
appendObfuscationPlan(planBuilder, features);
} else {
planBuilder.append(NameFinalizer.class);
}
if (productions.contains(JayceInLibraryProduct.class)) {
// Jayce files must be copied into output library in incremental library mode or in non
// incremental mode
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
if (features.contains(GenerateLibraryFromIncrementalFolder.class)
|| !features.contains(Incremental.class)) {
typePlan.append(JayceInLibraryWriterAll.class);
} else {
typePlan.append(JayceInLibraryWriterNoPrebuilt.class);
}
}
{
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
methodPlan.append(DefaultBridgeInLambdaAdder.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
methodPlan.append(BridgeInInterfaceRemover.class);
}
{
if (features.contains(CheckAndroidCompatibility.class)) {
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
methodPlan.append(AndroidCompatibilityChecker.class);
}
}
}
if (productions.contains(DexInLibraryProduct.class)
|| productions.contains(DexFileProduct.class)) {
if (features.contains(LambdaToAnonymousConverter.class)) {
// Collect and group lambdas
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class)
.appendSubPlan(JMethodAdapter.class).append(LambdaCollector.class);
// NOTE: wait until all lambdas are collected
// Create classes and fill in their content
planBuilder.append(LambdaGroupClassCreator.class);
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class)
.append(LambdaGroupClassFinalizer.class);
// NOTE: wait until all lambdas classes are created
// Replace all references to lambdas
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class)
.appendSubPlan(JMethodAdapter.class).append(LambdaConverter.class);
}
}
boolean enableInlineAnnotatedMethods =
features.contains(Optimizations.InlineAnnotatedMethods.class);
if (productions.contains(DependencyInLibraryProduct.class)) {
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan.append(TypeDependenciesCollector.class);
typePlan.append(FileDependenciesCollector.class);
}
if (productions.contains(DexInLibraryProduct.class)
|| productions.contains(DexFileProduct.class)) {
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
if (features.contains(DynamicAssertionFeature.class)) {
methodPlan.append(DynamicAssertionTransformer.class);
} else if (features.contains(EnabledAssertionFeature.class)) {
methodPlan.append(EnabledAssertionTransformer.class);
} else if (features.contains(DisabledAssertionFeature.class)) {
methodPlan.append(AssertionRemover.class);
}
if (features.contains(Optimizations.NotSimplifier.class)) {
methodPlan.append(NotSimplifier.class);
}
}
boolean enableClassFinalizer = features.contains(Optimizations.ClassFinalizer.class);
boolean enableMethodFinalizer = features.contains(Optimizations.MethodFinalizer.class);
if (enableClassFinalizer || enableMethodFinalizer) {
// Dependencies
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class)
.append(DirectlyDerivedClassesProvider.class);
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
if (enableClassFinalizer) {
typePlan.append(ClassFinalizer.class);
}
if (enableMethodFinalizer) {
typePlan.append(MethodFinalizer.class);
}
}
{
// After this point {@link JDcoiExcludeJackFileAdapter} must not be used since
// schedulables are not executed into the Java to Jayce plan.
SubPlanBuilder<JDefinedClassOrInterface> typePlan4 =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
if (features.contains(DynamicAssertionFeature.class)) {
SubPlanBuilder<JField> fieldPlan = typePlan4.appendSubPlan(JFieldAdapter.class);
fieldPlan.append(FieldInitializer.class);
}
{
SubPlanBuilder<JMethod> methodPlan = typePlan4.appendSubPlan(JMethodAdapter.class);
methodPlan.append(ConditionalAndOrRemover.class);
if (hasSanityChecks) {
methodPlan.append(ConditionalAndOrRemoverChecker.class);
}
methodPlan.append(BooleanTestTransformer.class);
methodPlan.append(SplitNewInstance.class);
if (hasSanityChecks) {
methodPlan.append(SplitNewInstanceChecker.class);
}
methodPlan.append(MultiDimensionNewArrayRemover.class);
methodPlan.append(InitInNewArrayRemover.class);
methodPlan.append(PrimitiveClassTransformer.class);
methodPlan.append(SynchronizeTransformer.class);
if (features.contains(BoostLockedRegionPriorityFeature.class)) {
methodPlan.append(BoostLockedRegionPriority.class);
}
methodPlan.append(NestedAssignRemover.class);
methodPlan.append(IntersectionTypeRemover.class);
methodPlan.append(UselessCaseRemover.class);
if (hasSanityChecks) {
methodPlan.append(UselessCaseChecker.class);
}
methodPlan.append(UselessSwitchesRemover.class);
methodPlan.append(TypeLegalizer.class);
methodPlan.append(RopCastLegalizer.class);
if (features.contains(CodeStats.class)) {
methodPlan.append(BinaryOperationWithCst.class);
}
methodPlan.append(FinallyRemover.class);
methodPlan.append(ExceptionRuntimeValueAdder.class);
methodPlan.append(DefinitionMarkerAdder.class);
methodPlan.append(ThreeAddressCodeBuilder.class);
methodPlan.append(UselessCastRemover.class);
methodPlan.append(DefinitionMarkerRemover.class);
methodPlan.append(TryCatchRemover.class);
methodPlan.append(ExpressionStatementLegalizer.class);
if (hasSanityChecks) {
methodPlan.append(NumericConversionChecker.class);
}
methodPlan.append(EmptyClinitRemover.class);
}
}
if (enableInlineAnnotatedMethods) {
SubPlanBuilder<JMethod> methodPlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class)
.appendSubPlan(JMethodAdapter.class);
if (hasSanityChecks) {
methodPlan.append(InlineAnnotationSanityCheck.class);
}
methodPlan.append(InlineAnnotatedMethods.class);
methodPlan.append(JMethodInliner.class);
}
if (features.contains(DalvikProtectedInnerCheck.class)) {
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
methodPlan.append(DalvikProtectedInnerChecker.class);
}
}
if (productions.contains(DependencyInLibraryProduct.class)) {
planBuilder.append(TypeDependenciesInLibraryWriter.class);
planBuilder.append(FileDependenciesInLibraryWriter.class);
planBuilder.append(LibraryDependenciesInLibraryWriter.class);
}
if (productions.contains(SeedFile.class)) {
planBuilder.append(SeedPrinter.class);
}
if (productions.contains(Mapping.class)) {
planBuilder.append(MappingPrinter.class);
}
if (productions.contains(StructurePrinting.class)) {
planBuilder.append(ShrinkStructurePrinter.class);
}
if (productions.contains(DexInLibraryProduct.class)
|| productions.contains(DexFileProduct.class)) {
boolean enableArgumentValuePropagation =
features.contains(Optimizations.ArgumentValuePropagation.class);
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan.append(ReflectAnnotationsAdder.class);
if (enableArgumentValuePropagation) {
typePlan.append(AvpCalculateTaintedMethods.class);
}
{
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
methodPlan.append(DefaultValueAnnotationAdder.class);
}
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan.append(ClassDefItemBuilder.class);
typePlan.append(ContainerAnnotationAdder.TypeContainerAnnotationAdder.class);
typePlan.append(ClassAnnotationBuilder.class);
}
if (features.contains(Optimizations.FieldFinalizer.class)) {
// Phase 1: field assignment information collection
planBuilder
.appendSubPlan(JDefinedClassOrInterfaceAdapter.class)
.appendSubPlan(JMethodAdapter.class)
.append(FieldFinalizer.CollectionPhase.class);
// Phase 2: constructors analysis
SubPlanBuilder<JDefinedClassOrInterface> phase3 =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
SubPlanBuilder<JMethod> phase3method = phase3.appendSubPlan(JMethodAdapter.class);
phase3method.append(RefAsStatementRemover.class);
phase3method.append(CfgBuilder.class);
phase3method.append(FieldFinalizer.ConstructorsAnalysisPhase.class);
phase3method.append(CfgMarkerRemover.class);
// Phase 3: field finalization
phase3
.appendSubPlan(JFieldAdapter.class)
.append(FieldFinalizer.FinalizingPhase.class);
}
boolean enableFieldValuePropagation =
features.contains(Optimizations.FieldValuePropagation.class);
boolean enableWriteOnlyFieldRemoval =
features.contains(Optimizations.WriteOnlyFieldRemoval.class);
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan5 =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
{
{
SubPlanBuilder<JMethod> methodPlan4 = typePlan5.appendSubPlan(JMethodAdapter.class);
methodPlan4.append(RefAsStatementRemover.class);
methodPlan4.append(CfgBuilder.class);
methodPlan4.append(DefinitionMarkerAdder.class);
methodPlan4.append(ReachingDefinitions.class);
methodPlan4.append(UsedVariableAdder.class);
methodPlan4.append(DefUsesAndUseDefsChainComputation.class);
if (hasSanityChecks) {
methodPlan4.append(UseDefsChecker.class);
}
methodPlan4.append(ConstantRefiner.class);
if (features.contains(Optimizations.UseDefSimplifier.class)) {
methodPlan4.append(UseDefsChainsSimplifier.class);
}
if (features.contains(Optimizations.DefUseSimplifier.class)) {
methodPlan4.append(DefUsesChainsSimplifier.class);
}
methodPlan4.append(UnusedDefinitionRemover.class);
methodPlan4.append(RefAsStatementRemover.class);
methodPlan4.append(CfgMarkerRemover.class);
methodPlan4.append(CfgBuilder.class);
if (features.contains(Optimizations.IfSimplifier.class)) {
methodPlan4.append(IfWithConstantSimplifier.class);
}
methodPlan4.append(UnusedLocalRemover.class);
if (enableFieldValuePropagation) {
methodPlan4.append(FvpCollectFieldAssignments.class);
}
if (enableArgumentValuePropagation) {
methodPlan4.append(AvpCollectMethodCallArguments.class);
}
if (enableWriteOnlyFieldRemoval) {
methodPlan4.append(WofrCollectFieldAccesses.class);
}
methodPlan4.append(DefUsesAndUseDefsChainRemover.class);
methodPlan4.append(DefinitionMarkerRemover.class);
methodPlan4.append(UsedVariableRemover.class);
if (features.contains(Optimizations.ExpressionSimplifier.class)) {
methodPlan4.append(ExpressionSimplifier.class);
}
methodPlan4.append(UselessIfRemover.class);
methodPlan4.append(CfgMarkerRemover.class);
methodPlan4.append(CfgBuilder.class);
methodPlan4.append(ContainerAnnotationAdder.MethodContainerAnnotationAdder.class);
}
}
}
if (enableArgumentValuePropagation) {
planBuilder.append(AvpComputeMethodArgumentsValues.class);
}
if (enableFieldValuePropagation || enableArgumentValuePropagation
|| enableWriteOnlyFieldRemoval) {
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
if (enableFieldValuePropagation) {
methodPlan.append(FvpPropagateFieldValues.class);
}
if (enableArgumentValuePropagation) {
methodPlan.append(AvpPropagateArgumentValues.class);
}
if (enableWriteOnlyFieldRemoval) {
methodPlan.append(WofrRemoveFieldWrites.class);
}
methodPlan.append(CfgMarkerRemover.class);
methodPlan.append(CfgBuilder.class);
}
SubPlanBuilder<JDefinedClassOrInterface> typePlan1 =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
SubPlanBuilder<JField> fieldPlan = typePlan1.appendSubPlan(JFieldAdapter.class);
fieldPlan.append(ContainerAnnotationAdder.FieldContainerAnnotationAdder.class);
if (enableWriteOnlyFieldRemoval) {
fieldPlan.append(WofrRemoveFields.class);
}
// The sub plan that write dex files representing type must not be split in order to remove dx
// IR from memory when dex file is written.
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan6 =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
{
SubPlanBuilder<JMethod> methodPlan5 = typePlan6.appendSubPlan(JMethodAdapter.class);
methodPlan5.append(CodeItemBuilder.class);
methodPlan5.append(CfgMarkerRemover.class);
methodPlan5.append(EncodedMethodBuilder.class);
methodPlan5.append(DexCodeMarkerRemover.class);
if (features.contains(ParameterMetadataFeature.class)) {
methodPlan5.append(ParameterMetadataAnnotationsAdder.class);
}
methodPlan5.append(MethodAnnotationBuilder.class);
if (features.contains(DropMethodBody.class)) {
methodPlan5.append(MethodBodyRemover.class);
}
}
{
SubPlanBuilder<JField> fieldPlan2 = typePlan6.appendSubPlan(JFieldAdapter.class);
fieldPlan2.append(EncodedFieldBuilder.class);
fieldPlan2.append(FieldAnnotationBuilder.class);
}
if (hasSanityChecks) {
typePlan6.append(TypeAstChecker.class);
}
// Jayce files must be copied into output library in incremental library mode or in non
// incremental mode
if (features.contains(GenerateLibraryFromIncrementalFolder.class)
|| !features.contains(Incremental.class)) {
typePlan6.append(DexInLibraryWriterAll.class);
} else {
typePlan6.append(DexInLibraryWriterNoPrebuilt.class);
}
typePlan6.append(ClassDefItemMarkerRemover.class);
}
}
if (hasSanityChecks) {
planBuilder.append(AstChecker.class);
}
planBuilder.append(Aborter.class);
}
private static void appendObfuscationPlan(@Nonnull PlanBuilder<JSession> planBuilder,
@Nonnull FeatureSet features) {
{
SubPlanBuilder<JPackage> packagePlan = planBuilder.appendSubPlan(JPackageAdapter.class);
packagePlan.append(NameKeeper.class);
}
planBuilder.append(ResourceRefiner.class);
if (features.contains(AdaptResourceFileContent.class)) {
planBuilder.append(ResourceContentRefiner.class);
}
planBuilder.append(Renamer.class);
if (features.contains(RemoveSourceFile.class)) {
planBuilder.append(SourceFileRemover.class);
} else if (features.contains(SourceFileRenaming.class)) {
planBuilder.append(SourceFileRenamer.class);
}
{
SubPlanBuilder<JDefinedClassOrInterface> typePlan =
planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
typePlan.append(TypeAnnotationRemover.class);
if (features.contains(RemoveEnclosingMethodFeature.class)) {
typePlan.append(TypeEnclosingMethodRemover.class);
}
if (features.contains(RemoveEnclosingType.class)) {
typePlan.append(TypeEnclosingTypeRemover.class);
}
if (features.contains(RemoveGenericSignature.class)) {
typePlan.append(TypeGenericSignatureRemover.class);
}
if (features.contains(RemoveLineNumber.class)) {
typePlan.append(LineNumberRemover.class);
}
{
SubPlanBuilder<JField> fieldPlan = typePlan.appendSubPlan(JFieldAdapter.class);
fieldPlan.append(FieldAnnotationRemover.class);
if (features.contains(RemoveGenericSignature.class)) {
fieldPlan.append(FieldGenericSignatureRemover.class);
}
}
{
SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class);
methodPlan.append(MethodAnnotationRemover.class);
methodPlan.append(ParameterAnnotationRemover.class);
if (features.contains(RemoveGenericSignature.class)) {
methodPlan.append(MethodGenericSignatureRemover.class);
}
if (features.contains(RemoveLocalVariableGenericSignature.class)) {
methodPlan.append(LocalVariableGenericSignatureRemover.class);
}
if (features.contains(RemoveAnnotationDefaultValue.class)) {
methodPlan.append(AnnotationDefaultValueRemover.class);
}
if (features.contains(RemoveThrownException.class)) {
methodPlan.append(ThrownExceptionRemover.class);
}
if (features.contains(RemoveParameterName.class)) {
methodPlan.append(ParameterNameRemover.class);
}
if (features.contains(RemoveLocalVariableName.class)) {
methodPlan.append(LocalVariableAndThisNameRemover.class);
}
}
}
}
@CheckForNull
private static Version version = null;
@Nonnull
public static Version getVersion() {
if (version == null) {
try {
version = new Version("jack", Jack.class.getClassLoader());
} catch (IOException e) {
logger.log(Level.SEVERE, "Failed to open Jack version file", e);
throw new AssertionError();
}
}
assert version != null;
return version;
}
@Nonnull
public static TypePackageAndMethodFormatter getLookupFormatter() {
return lookupFormatter;
}
@Nonnull
public static TypePackageAndMethodFormatter getUserFriendlyFormatter() {
return userFriendlyFormatter;
}
@Nonnull
public static EventBus getResourceRequestBus() {
return requestBus;
}
}