blob: 33edbcbf0da3cbda5a55521bdd0ac67a65b1018c [file] [log] [blame]
// Copyright (c) 2022, 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.utils;
import com.android.tools.r8.GlobalSyntheticsResourceProvider;
import com.android.tools.r8.ProgramResource;
import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.ProgramResourceProvider;
import com.android.tools.r8.ResourceException;
import com.android.tools.r8.Version;
import com.android.tools.r8.origin.Origin;
import com.google.common.io.ByteStreams;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class InternalGlobalSyntheticsProgramProvider implements ProgramResourceProvider {
public static class GlobalsEntryOrigin extends Origin {
private final String entryName;
public GlobalsEntryOrigin(String entryName, Origin parent) {
super(parent);
this.entryName = entryName;
}
@Override
public String part() {
return "global(" + entryName + ")";
}
}
private final List<GlobalSyntheticsResourceProvider> providers;
private List<ProgramResource> resources = null;
public InternalGlobalSyntheticsProgramProvider(List<GlobalSyntheticsResourceProvider> providers) {
this.providers = providers;
}
@Override
public Collection<ProgramResource> getProgramResources() throws ResourceException {
if (resources == null) {
ensureResources();
}
return resources;
}
private synchronized void ensureResources() throws ResourceException {
if (resources != null) {
return;
}
List<ProgramResource> resources = new ArrayList<>();
Set<String> seen = new HashSet<>();
for (GlobalSyntheticsResourceProvider provider : providers) {
List<Function<Kind, ProgramResource>> delayedResouces = new ArrayList<>();
Kind providerKind = null;
try (ZipInputStream stream = new ZipInputStream(provider.getByteStream())) {
ZipEntry entry;
while (null != (entry = stream.getNextEntry())) {
String name = entry.getName();
if (name.equals(InternalGlobalSyntheticsProgramConsumer.OUTPUT_KIND_ENTRY_NAME)) {
providerKind =
Kind.valueOf(new String(ByteStreams.toByteArray(stream), StandardCharsets.UTF_8));
} else if (name.equals(
InternalGlobalSyntheticsProgramConsumer.COMPILER_INFO_ENTRY_NAME)) {
String version = new String(ByteStreams.toByteArray(stream), StandardCharsets.UTF_8);
if (!Version.getVersionString().equals(version)) {
throw new ResourceException(
provider.getOrigin(),
"Outdated or inconsistent global synthetics information."
+ "\nGlobal synthetics information version: "
+ version
+ "\nCompiler version: "
+ Version.getVersionString());
}
} else if (name.endsWith(FileUtils.GLOBAL_SYNTHETIC_EXTENSION) && seen.add(name)) {
GlobalsEntryOrigin origin = new GlobalsEntryOrigin(name, provider.getOrigin());
String descriptor = guessTypeDescriptor(name);
byte[] bytes = ByteStreams.toByteArray(stream);
Set<String> descriptors = Collections.singleton(descriptor);
delayedResouces.add(
kind -> OneShotByteResource.create(kind, origin, bytes, descriptors));
}
}
} catch (IOException e) {
throw new ResourceException(provider.getOrigin(), e);
}
if (providerKind == null) {
throw new ResourceException(
provider.getOrigin(),
"Invalid global synthetics provider does not specify its content kind.");
}
for (Function<Kind, ProgramResource> fn : delayedResouces) {
resources.add(fn.apply(providerKind));
}
}
this.resources = resources;
}
private String guessTypeDescriptor(String name) {
String noExt = name.substring(0, name.length() - FileUtils.GLOBAL_SYNTHETIC_EXTENSION.length());
String classExt = noExt + FileUtils.CLASS_EXTENSION;
return DescriptorUtils.guessTypeDescriptor(classExt);
}
}