| // Copyright (c) 2019, 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; | 
 |  | 
 | import static com.android.tools.r8.utils.ExceptionUtils.unwrapExecutionException; | 
 |  | 
 | import com.android.tools.r8.dex.ApplicationReader; | 
 | import com.android.tools.r8.dex.Marker.Tool; | 
 | import com.android.tools.r8.graph.AppInfo; | 
 | import com.android.tools.r8.graph.AppView; | 
 | import com.android.tools.r8.graph.DexApplication; | 
 | import com.android.tools.r8.graph.LazyLoadedDexApplication; | 
 | import com.android.tools.r8.ir.conversion.IRConverter; | 
 | import com.android.tools.r8.ir.desugar.TypeRewriter; | 
 | import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAmender; | 
 | import com.android.tools.r8.jar.CfApplicationWriter; | 
 | import com.android.tools.r8.naming.PrefixRewritingNamingLens; | 
 | import com.android.tools.r8.naming.signature.GenericSignatureRewriter; | 
 | import com.android.tools.r8.origin.CommandLineOrigin; | 
 | import com.android.tools.r8.shaking.AnnotationRemover; | 
 | import com.android.tools.r8.shaking.L8TreePruner; | 
 | import com.android.tools.r8.synthesis.SyntheticFinalization; | 
 | import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy; | 
 | import com.android.tools.r8.utils.AndroidApp; | 
 | import com.android.tools.r8.utils.ExceptionUtils; | 
 | import com.android.tools.r8.utils.InternalOptions; | 
 | import com.android.tools.r8.utils.SelfRetraceTest; | 
 | import com.android.tools.r8.utils.StringUtils; | 
 | import com.android.tools.r8.utils.ThreadUtils; | 
 | import com.android.tools.r8.utils.Timing; | 
 | import java.io.IOException; | 
 | import java.util.concurrent.ExecutionException; | 
 | import java.util.concurrent.ExecutorService; | 
 |  | 
 | /** | 
 |  * The L8 compiler. | 
 |  */ | 
 | @Keep | 
 | public class L8 { | 
 |  | 
 |   /** | 
 |    * Main API entry for the L8 compiler. | 
 |    * | 
 |    * @param command L8 command. | 
 |    */ | 
 |   public static void run(L8Command command) throws CompilationFailedException { | 
 |     runForTesting( | 
 |         command.getInputApp(), | 
 |         command.getInternalOptions(), | 
 |         command.isShrinking(), | 
 |         command.getD8Command(), | 
 |         command.getR8Command()); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Main API entry for the L8 compiler. | 
 |    * | 
 |    * @param command L8 command. | 
 |    * @param executor executor service from which to get threads for multi-threaded processing. | 
 |    */ | 
 |   public static void run(L8Command command, ExecutorService executor) | 
 |       throws CompilationFailedException { | 
 |     run( | 
 |         command.getInputApp(), | 
 |         command.getInternalOptions(), | 
 |         command.isShrinking(), | 
 |         command.getD8Command(), | 
 |         command.getR8Command(), | 
 |         executor); | 
 |   } | 
 |  | 
 |   static void runForTesting( | 
 |       AndroidApp app, | 
 |       InternalOptions options, | 
 |       boolean shrink, | 
 |       D8Command d8Command, | 
 |       R8Command r8Command) | 
 |       throws CompilationFailedException { | 
 |     ExecutorService executorService = ThreadUtils.getExecutorService(options); | 
 |     run(app, options, shrink, d8Command, r8Command, executorService); | 
 |   } | 
 |  | 
 |   private static void run( | 
 |       AndroidApp app, | 
 |       InternalOptions options, | 
 |       boolean shrink, | 
 |       D8Command d8Command, | 
 |       R8Command r8Command, | 
 |       ExecutorService executorService) | 
 |       throws CompilationFailedException { | 
 |     try { | 
 |       ExceptionUtils.withD8CompilationHandler( | 
 |           options.reporter, | 
 |           () -> { | 
 |             // Desugar to class file format and turn off switch optimizations, as the final | 
 |             // compilation with D8 or R8 will do that. | 
 |             assert options.isCfDesugaring(); | 
 |             assert !options.forceAnnotateSynthetics; | 
 |             options.forceAnnotateSynthetics = true; | 
 |             assert options.enableSwitchRewriting; | 
 |             options.enableSwitchRewriting = false; | 
 |             assert options.enableStringSwitchConversion; | 
 |             options.enableStringSwitchConversion = false; | 
 |  | 
 |             desugar(app, options, executorService); | 
 |  | 
 |             options.forceAnnotateSynthetics = false; | 
 |             options.enableSwitchRewriting = true; | 
 |             options.enableStringSwitchConversion = true; | 
 |           }); | 
 |       if (shrink) { | 
 |         R8.run(r8Command, executorService); | 
 |       } else if (d8Command != null) { | 
 |         D8.run(d8Command, executorService); | 
 |       } | 
 |     } finally { | 
 |       executorService.shutdown(); | 
 |     } | 
 |   } | 
 |  | 
 |   private static void desugar( | 
 |       AndroidApp inputApp, InternalOptions options, ExecutorService executor) throws IOException { | 
 |     Timing timing = Timing.create("L8 desugaring", options); | 
 |     assert options.isCfDesugaring(); | 
 |     try { | 
 |       // Since L8 Cf representation is temporary, just disable long running back-end optimizations | 
 |       // on it. | 
 |       options.enableLoadStoreOptimization = false; | 
 |  | 
 |       AppView<AppInfo> appView = readApp(inputApp, options, executor, timing); | 
 |       DesugaredLibraryAmender.run(appView); | 
 |  | 
 |       if (!options.disableL8AnnotationRemoval) { | 
 |         AnnotationRemover.clearAnnotations(appView); | 
 |       } | 
 |  | 
 |       new IRConverter(appView, timing).convert(appView, executor); | 
 |  | 
 |       SyntheticFinalization.finalize(appView, timing, executor); | 
 |  | 
 |       appView.setNamingLens(PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView)); | 
 |       new GenericSignatureRewriter(appView).run(appView.appInfo().classes(), executor); | 
 |  | 
 |       new CfApplicationWriter(appView, options.getMarker(Tool.L8)) | 
 |           .write(options.getClassFileConsumer()); | 
 |       options.printWarnings(); | 
 |     } catch (ExecutionException e) { | 
 |       throw unwrapExecutionException(e); | 
 |     } finally { | 
 |       inputApp.signalFinishedToProviders(options.reporter); | 
 |       options.signalFinishedToConsumers(); | 
 |       // Dump timings. | 
 |       if (options.printTimes) { | 
 |         timing.report(); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   private static AppView<AppInfo> readApp( | 
 |       AndroidApp inputApp, InternalOptions options, ExecutorService executor, Timing timing) | 
 |       throws IOException { | 
 |     LazyLoadedDexApplication lazyApp = | 
 |         new ApplicationReader(inputApp, options, timing).read(executor); | 
 |     options.loadMachineDesugaredLibrarySpecification(timing, lazyApp); | 
 |     TypeRewriter typeRewriter = options.getTypeRewriter(); | 
 |  | 
 |     DexApplication app = new L8TreePruner(options).prune(lazyApp, typeRewriter); | 
 |     return AppView.createForL8( | 
 |         AppInfo.createInitialAppInfo(app, GlobalSyntheticsStrategy.forSingleOutputMode()), | 
 |         typeRewriter); | 
 |   } | 
 |  | 
 |   private static void run(String[] args) throws CompilationFailedException { | 
 |     L8Command command = L8Command.parse(args, CommandLineOrigin.INSTANCE).build(); | 
 |     if (command.isPrintHelp()) { | 
 |       SelfRetraceTest.test(); | 
 |       System.out.println(L8CommandParser.getUsageMessage()); | 
 |       return; | 
 |     } | 
 |     if (command.isPrintVersion()) { | 
 |       System.out.println("L8 " + Version.getVersionString()); | 
 |       return; | 
 |     } | 
 |     run(command); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Command-line entry to L8. | 
 |    * | 
 |    * <p>See {@link L8CommandParser#getUsageMessage()} or run {@code l8 --help} for usage | 
 |    * information. | 
 |    */ | 
 |   public static void main(String[] args) { | 
 |     if (args.length == 0) { | 
 |       throw new RuntimeException( | 
 |           StringUtils.joinLines("Invalid invocation.", L8CommandParser.getUsageMessage())); | 
 |     } | 
 |     ExceptionUtils.withMainProgramHandler(() -> run(args)); | 
 |   } | 
 | } |