blob: 98ebaed6e736f2e5bcb35f6ab5f0cd133031ba89 [file] [log] [blame]
// Copyright (c) 2021, 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.kotlin;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.ReflectionHelper;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import kotlin.Pair;
import kotlinx.metadata.internal.metadata.ProtoBuf;
import kotlinx.metadata.internal.metadata.jvm.JvmProtoBuf;
import kotlinx.metadata.jvm.KotlinClassMetadata;
import kotlinx.metadata.jvm.KotlinClassMetadata.FileFacade;
import kotlinx.metadata.jvm.KotlinClassMetadata.MultiFileClassPart;
import kotlinx.metadata.jvm.KotlinClassMetadata.SyntheticClass;
// Due to kotlin-metadata-jvm library synthesizing jvm method signatures from type-information
// we do an extra check to figure out if we should model the signature. If we model it, we will
// add name and descriptor information to the string pool for the proto message, so it is
// better to avoid it.
// https://github.com/Kotlin/kotlinx.reflect.lite/blob/46d47f118f9846166b6b8f8212bdbc822fe2f634/src/main/java/org/jetbrains/kotlin/serialization/jvm/JvmProtoBufUtil.kt
public class KotlinJvmSignatureExtensionInformation {
private final Set<Integer> noExtensionIndicesForFunctions;
private final Set<Integer> noExtensionIndicesForConstructors;
private static final KotlinJvmSignatureExtensionInformation EMPTY = builder().build();
private KotlinJvmSignatureExtensionInformation(
Set<Integer> noExtensionIndicesForFunctions, Set<Integer> noExtensionIndicesForConstructors) {
this.noExtensionIndicesForFunctions = noExtensionIndicesForFunctions;
this.noExtensionIndicesForConstructors = noExtensionIndicesForConstructors;
}
public static KotlinJvmSignatureExtensionInformation readInformationFromMessage(
FileFacade fileFacadeMetadata, InternalOptions options) {
return readPackageDataFromMessage(fileFacadeMetadata, options);
}
public static KotlinJvmSignatureExtensionInformation readInformationFromMessage(
MultiFileClassPart classPart, InternalOptions options) {
return readPackageDataFromMessage(classPart, options);
}
private static KotlinJvmSignatureExtensionInformation readPackageDataFromMessage(
Object object, InternalOptions options) {
try {
Pair<?, ProtoBuf.Package> kotlinPairData =
ReflectionHelper.performReflection(
object,
ReflectionHelper.builder()
.readField("packageData$delegate")
.setSetAccessible(true)
.done()
.readMethod("getValue")
.setSetAccessible(true)
.done()
.build());
return builder().visit(kotlinPairData.getSecond()).build();
} catch (Exception e) {
options.warningReadingKotlinMetadataReflective();
return empty();
}
}
public static KotlinJvmSignatureExtensionInformation readInformationFromMessage(
SyntheticClass syntheticClass, InternalOptions options) {
try {
Pair<?, ProtoBuf.Function> kotlinPairData =
ReflectionHelper.performReflection(
syntheticClass,
ReflectionHelper.builder()
.readField("functionData$delegate")
.setSetAccessible(true)
.done()
.readMethod("getValue")
.setSetAccessible(true)
.done()
.build());
if (kotlinPairData == null) {
return empty();
}
return builder().visit(kotlinPairData.getSecond(), 0).build();
} catch (Exception e) {
options.warningReadingKotlinMetadataReflective();
return empty();
}
}
public static KotlinJvmSignatureExtensionInformation readInformationFromMessage(
KotlinClassMetadata.Class kMetadata, InternalOptions options) {
try {
Pair<?, ProtoBuf.Class> kotlinPairData =
ReflectionHelper.performReflection(
kMetadata,
ReflectionHelper.builder()
.readField("classData$delegate")
.setSetAccessible(true)
.done()
.readMethod("getValue")
.setSetAccessible(true)
.done()
.build());
return builder().visit(kotlinPairData.getSecond()).build();
} catch (Exception e) {
options.warningReadingKotlinMetadataReflective();
return empty();
}
}
public boolean hasJvmMethodSignatureExtensionForFunction(int index) {
return !noExtensionIndicesForFunctions.contains(index);
}
public boolean hasJvmMethodSignatureExtensionForConstructor(int index) {
return !noExtensionIndicesForConstructors.contains(index);
}
public static KotlinJvmSignatureExtensionInformationBuilder builder() {
return new KotlinJvmSignatureExtensionInformationBuilder();
}
public static KotlinJvmSignatureExtensionInformation empty() {
return EMPTY;
}
private static class KotlinJvmSignatureExtensionInformationBuilder {
private final Set<Integer> noExtensionIndicesForFunctions = new HashSet<>();
private final Set<Integer> noExtensionIndicesForConstructors = new HashSet<>();
private KotlinJvmSignatureExtensionInformation build() {
return new KotlinJvmSignatureExtensionInformation(
noExtensionIndicesForFunctions, noExtensionIndicesForConstructors);
}
private KotlinJvmSignatureExtensionInformationBuilder visit(ProtoBuf.Class clazz) {
visitFunctions(clazz.getFunctionList());
visitConstructors(clazz.getConstructorList());
return this;
}
private KotlinJvmSignatureExtensionInformationBuilder visit(ProtoBuf.Package pkg) {
visitFunctions(pkg.getFunctionList());
return this;
}
private void visitFunctions(List<ProtoBuf.Function> functions) {
ListUtils.forEachWithIndex(functions, this::visit);
}
public KotlinJvmSignatureExtensionInformationBuilder visit(
ProtoBuf.Function function, int index) {
if (!function.hasExtension(JvmProtoBuf.methodSignature)) {
noExtensionIndicesForFunctions.add(index);
}
return this;
}
private void visitConstructors(List<ProtoBuf.Constructor> constructors) {
ListUtils.forEachWithIndex(
constructors,
(constructor, index) -> {
if (!constructor.hasExtension(JvmProtoBuf.constructorSignature)) {
noExtensionIndicesForConstructors.add(index);
}
});
}
}
}