blob: be0c645c0bf2337c060390b57d892e4c8a6a07ec [file] [log] [blame]
// Copyright (c) 2017, 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.dex.Marker;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import java.util.function.Consumer;
public abstract class DexByteCodeWriter {
public interface OutputStreamProvider {
PrintStream get(DexClass clazz) throws IOException;
}
final DexApplication application;
final InternalOptions options;
DexByteCodeWriter(DexApplication application,
InternalOptions options) {
this.application = application;
this.options = options;
}
private static void ensureParentExists(Path path) throws IOException {
Path parent = path.getParent();
if (parent != null) {
Files.createDirectories(parent);
}
}
public static OutputStreamProvider oneFilePerClass(
ClassNameMapper classNameMapper, Path path, String fileEnding) {
return (clazz) -> {
String className =
DescriptorUtils.descriptorToJavaType(clazz.type.toDescriptorString(), classNameMapper);
Path classOutput = path.resolve(className.replace('.', File.separatorChar) + fileEnding);
ensureParentExists(classOutput);
return new PrintStream(Files.newOutputStream(classOutput));
};
}
public void writeMarkers(PrintStream output) {
Collection<Marker> markers = application.dexItemFactory.extractMarkers();
System.out.println("Number of markers: " + markers.size());
for (Marker marker : markers) {
output.println(marker.toString());
}
}
public void write(PrintStream output) throws IOException {
writeMarkers(output);
write(x -> output, x -> {});
}
public void write(OutputStreamProvider outputStreamProvider, Consumer<PrintStream> closer)
throws IOException {
Iterable<DexProgramClass> classes = application.classesWithDeterministicOrder();
for (DexProgramClass clazz : classes) {
if (anyMethodMatches(clazz)) {
PrintStream ps = outputStreamProvider.get(clazz);
try {
writeClass(clazz, ps);
} finally {
closer.accept(ps);
}
}
}
}
private boolean anyMethodMatches(DexClass clazz) {
return !options.hasMethodsFilter()
|| clazz.getMethodCollection().hasMethods(options::methodMatchesFilter);
}
private void writeClass(DexProgramClass clazz, PrintStream ps) {
writeClassHeader(clazz, ps);
writeFieldsHeader(clazz, ps);
clazz.forEachField(field -> writeField(field, ps));
writeFieldsFooter(clazz, ps);
writeMethodsHeader(clazz, ps);
clazz.forEachProgramMethod(method -> writeMethod(method, ps));
writeMethodsFooter(clazz, ps);
writeClassFooter(clazz, ps);
}
abstract void writeClassHeader(DexProgramClass clazz, PrintStream ps);
void writeFieldsHeader(DexProgramClass clazz, PrintStream ps) {
// Do nothing.
}
abstract void writeField(DexEncodedField field, PrintStream ps);
void writeFieldsFooter(DexProgramClass clazz, PrintStream ps) {
// Do nothing.
}
void writeMethodsHeader(DexProgramClass clazz, PrintStream ps) {
// Do nothing.
}
abstract void writeMethod(ProgramMethod method, PrintStream ps);
void writeMethodsFooter(DexProgramClass clazz, PrintStream ps) {
// Do nothing.
}
abstract void writeClassFooter(DexProgramClass clazz, PrintStream ps);
}