Reland "Check shape and class type before parsing metadata for lambdas"
This reverts commit b1c97136907e130b6756db143c0f50e6f6b273f2.
Change-Id: Ic95a04869c9e07e6aec74a81c6ebade4fe16620e
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
index bfabd6c..7f4c47d 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
@@ -33,6 +33,8 @@
public final class KotlinClassMetadataReader {
+ private static final int SYNTHETIC_CLASS_KIND = 3;
+
public static KotlinClassLevelInfo getKotlinInfo(
DexClass clazz, AppView<?> appView, Consumer<DexEncodedMethod> keepByteCode) {
DexAnnotation meta =
@@ -75,16 +77,25 @@
public static boolean isLambda(AppView<?> appView, DexClass clazz) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
Kotlin kotlin = dexItemFactory.kotlin;
+ Flavour flavour = getFlavour(clazz, kotlin);
+ if (flavour == Flavour.Unclassified) {
+ return false;
+ }
DexAnnotation metadataAnnotation =
clazz.annotations().getFirstMatching(dexItemFactory.kotlinMetadataType);
- if (metadataAnnotation != null) {
- KotlinClassMetadata kMetadata = toKotlinClassMetadata(kotlin, metadataAnnotation.annotation);
+ if (metadataAnnotation == null) {
+ return false;
+ }
+ Map<DexString, DexAnnotationElement> elementMap = toElementMap(metadataAnnotation.annotation);
+ if (getKind(kotlin, elementMap) == SYNTHETIC_CLASS_KIND) {
+ KotlinClassMetadata kMetadata = toKotlinClassMetadata(kotlin, elementMap);
if (kMetadata instanceof SyntheticClass) {
- SyntheticClass syntheticClass = (SyntheticClass) kMetadata;
- return syntheticClass.isLambda()
- && getFlavour(syntheticClass, clazz, kotlin) != Flavour.Unclassified;
+ return ((SyntheticClass) kMetadata).isLambda();
}
}
+ assert toKotlinClassMetadata(kotlin, elementMap) instanceof SyntheticClass
+ == (getKind(kotlin, elementMap) == SYNTHETIC_CLASS_KIND)
+ : "Synthetic class kinds should agree";
return false;
}
@@ -98,16 +109,21 @@
public static KotlinClassMetadata toKotlinClassMetadata(
Kotlin kotlin, DexEncodedAnnotation metadataAnnotation) {
+ return toKotlinClassMetadata(kotlin, toElementMap(metadataAnnotation));
+ }
+
+ private static Map<DexString, DexAnnotationElement> toElementMap(
+ DexEncodedAnnotation metadataAnnotation) {
Map<DexString, DexAnnotationElement> elementMap = new IdentityHashMap<>();
for (DexAnnotationElement element : metadataAnnotation.elements) {
elementMap.put(element.name, element);
}
+ return elementMap;
+ }
- DexAnnotationElement kind = elementMap.get(kotlin.metadata.kind);
- if (kind == null) {
- throw new MetadataError("element 'k' is missing.");
- }
- Integer k = (Integer) kind.value.getBoxedValue();
+ private static KotlinClassMetadata toKotlinClassMetadata(
+ Kotlin kotlin, Map<DexString, DexAnnotationElement> elementMap) {
+ int k = getKind(kotlin, elementMap);
DexAnnotationElement metadataVersion = elementMap.get(kotlin.metadata.metadataVersion);
int[] mv = metadataVersion == null ? null : getUnboxedIntArray(metadataVersion.value, "mv");
DexAnnotationElement bytecodeVersion = elementMap.get(kotlin.metadata.bytecodeVersion);
@@ -127,6 +143,14 @@
return KotlinClassMetadata.read(header);
}
+ private static int getKind(Kotlin kotlin, Map<DexString, DexAnnotationElement> elementMap) {
+ DexAnnotationElement kind = elementMap.get(kotlin.metadata.kind);
+ if (kind == null) {
+ throw new MetadataError("element 'k' is missing.");
+ }
+ return (Integer) kind.value.getBoxedValue();
+ }
+
public static KotlinClassLevelInfo createKotlinInfo(
Kotlin kotlin,
DexClass clazz,
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java
index 08e95b3..ee55f8b 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.utils.Pair;
import kotlinx.metadata.KmLambda;
import kotlinx.metadata.jvm.KotlinClassHeader;
-import kotlinx.metadata.jvm.KotlinClassMetadata;
import kotlinx.metadata.jvm.KotlinClassMetadata.SyntheticClass;
import kotlinx.metadata.jvm.KotlinClassMetadata.SyntheticClass.Writer;
@@ -55,7 +54,7 @@
? KotlinLambdaInfo.create(
clazz, lambda, appView.dexItemFactory(), appView.reporter(), extensionInformation)
: null,
- getFlavour(syntheticClass, clazz, kotlin),
+ getFlavour(clazz, kotlin),
packageName,
metadataVersion);
}
@@ -64,14 +63,6 @@
return lambda != null && flavour != Flavour.Unclassified;
}
- public boolean isKotlinStyleLambda() {
- return flavour == Flavour.KotlinStyleLambda;
- }
-
- public boolean isJavaStyleLambda() {
- return flavour == Flavour.JavaStyleLambda;
- }
-
@Override
public boolean isSyntheticClass() {
return true;
@@ -112,23 +103,17 @@
return metadataVersion;
}
- public static Flavour getFlavour(
- KotlinClassMetadata.SyntheticClass metadata, DexClass clazz, Kotlin kotlin) {
- // Returns KotlinStyleLambda if the given clazz is a Kotlin-style lambda:
- // a class that
- // 1) is recognized as lambda in its Kotlin metadata;
- // 2) directly extends kotlin.jvm.internal.Lambda
- if (metadata.isLambda() && clazz.superType == kotlin.functional.lambdaType) {
+ public static Flavour getFlavour(DexClass clazz, Kotlin kotlin) {
+ // Returns KotlinStyleLambda if the given clazz has shape of a Kotlin-style lambda:
+ // a class that directly extends kotlin.jvm.internal.Lambda
+ if (clazz.superType == kotlin.functional.lambdaType) {
return Flavour.KotlinStyleLambda;
}
- // Returns JavaStyleLambda if the given clazz is a Java-style lambda:
+ // Returns JavaStyleLambda if the given clazz has shape of a Java-style lambda:
// a class that
- // 1) is recognized as lambda in its Kotlin metadata;
- // 2) doesn't extend any other class;
- // 3) directly implements only one Java SAM.
- if (metadata.isLambda()
- && clazz.superType == kotlin.factory.objectType
- && clazz.interfaces.size() == 1) {
+ // 1) doesn't extend any other class;
+ // 2) directly implements only one Java SAM.
+ if (clazz.superType == kotlin.factory.objectType && clazz.interfaces.size() == 1) {
return Flavour.JavaStyleLambda;
}
return Flavour.Unclassified;