|  | // Copyright (c) 2024, 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.synthesis; | 
|  |  | 
|  | import com.android.tools.r8.ByteDataView; | 
|  | import com.android.tools.r8.ClassFileConsumer; | 
|  | import com.android.tools.r8.DexFilePerClassFileConsumer; | 
|  | import com.android.tools.r8.DexIndexedConsumer; | 
|  | import com.android.tools.r8.DiagnosticsHandler; | 
|  | import com.android.tools.r8.GlobalSyntheticsConsumer; | 
|  | import com.android.tools.r8.ProgramConsumer; | 
|  | import com.android.tools.r8.errors.Unreachable; | 
|  | import com.android.tools.r8.references.ClassReference; | 
|  | import com.android.tools.r8.utils.ArchiveBuilder; | 
|  | import com.android.tools.r8.utils.DirectoryBuilder; | 
|  | import com.android.tools.r8.utils.OutputBuilder; | 
|  | import com.android.tools.r8.utils.StringDiagnostic; | 
|  | import java.nio.file.Files; | 
|  | import java.nio.file.Path; | 
|  |  | 
|  | public final class GlobalSyntheticsUtils { | 
|  |  | 
|  | private GlobalSyntheticsUtils() {} | 
|  |  | 
|  | public static GlobalSyntheticsConsumer determineGlobalSyntheticsConsumer( | 
|  | boolean intermediate, | 
|  | Path output, | 
|  | GlobalSyntheticsConsumer consumer, | 
|  | ProgramConsumer programConsumer) { | 
|  | assert output == null || consumer == null; | 
|  | if (!intermediate) { | 
|  | return null; | 
|  | } | 
|  | if (consumer != null) { | 
|  | return consumer; | 
|  | } | 
|  | if (output == null) { | 
|  | return null; | 
|  | } | 
|  |  | 
|  | // Output is non-null, and we must create a consumer compatible with the program consumer. | 
|  | OutputBuilder builder = | 
|  | Files.isDirectory(output) ? new DirectoryBuilder(output) : new ArchiveBuilder(output); | 
|  | builder.open(); | 
|  |  | 
|  | if (programConsumer instanceof DexIndexedConsumer) { | 
|  | return new GlobalSyntheticsConsumer() { | 
|  | boolean written = false; | 
|  |  | 
|  | @Override | 
|  | public synchronized void accept( | 
|  | ByteDataView data, ClassReference context, DiagnosticsHandler handler) { | 
|  | assert context == null; | 
|  | if (written) { | 
|  | String msg = "Attempt to write multiple global-synthetics files in dex-indexed mode."; | 
|  | handler.error(new StringDiagnostic(msg)); | 
|  | throw new RuntimeException(msg); | 
|  | } | 
|  | builder.addFile("classes.globals", data, handler); | 
|  | builder.close(handler); | 
|  | written = true; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void finished(DiagnosticsHandler handler) { | 
|  | // If not global info was written, close the builder with empty content. | 
|  | if (!written) { | 
|  | builder.close(handler); | 
|  | written = true; | 
|  | } | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | if (programConsumer instanceof DexFilePerClassFileConsumer) { | 
|  | return new GlobalSyntheticsConsumer() { | 
|  |  | 
|  | @Override | 
|  | public void accept(ByteDataView data, ClassReference context, DiagnosticsHandler handler) { | 
|  | builder.addFile(context.getBinaryName() + ".globals", data, handler); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void finished(DiagnosticsHandler handler) { | 
|  | builder.close(handler); | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | if (programConsumer instanceof ClassFileConsumer) { | 
|  | return new GlobalSyntheticsConsumer() { | 
|  | @Override | 
|  | public void accept(ByteDataView data, ClassReference context, DiagnosticsHandler handler) { | 
|  | builder.addFile(context.getBinaryName() + ".globals", data, handler); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void finished(DiagnosticsHandler handler) { | 
|  | builder.close(handler); | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | throw new Unreachable("Unexpected program consumer type"); | 
|  | } | 
|  | } |