blob: 0a90db409fbcddbdaea630619ade02f5f79b1ba1 [file] [log] [blame]
// 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");
}
}