JVM Metadata: Add a bit to mark anonymous objects in inline functions

Anonymous objects in the scope of an inline functions are copied to
all call-sites. This makes them part of the public ABI of a Kotlin
library.

We introduce a flag to mark all classes in the scope of an inline
function. When compiling with assertions enabled, we check that
this flag is set whenever we inline an anonymous object from another
module.
This commit is contained in:
Steven Schäfer
2020-10-22 14:07:56 +02:00
committed by Alexander Udalov
parent 254fc53b17
commit de9d2919a8
30 changed files with 181 additions and 58 deletions
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.psi.KtElement;
import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
import org.jetbrains.kotlin.resolve.scopes.MemberScope; import org.jetbrains.kotlin.resolve.scopes.MemberScope;
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver;
@@ -287,7 +288,9 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
if (builder == null) return; if (builder == null) return;
ProtoBuf.Function functionProto = builder.build(); ProtoBuf.Function functionProto = builder.build();
WriteAnnotationUtilKt.writeKotlinMetadata(v, state, KotlinClassHeader.Kind.SYNTHETIC_CLASS, 0, av -> { boolean publicAbi = InlineUtil.isInPublicInlineScope(frontendFunDescriptor);
WriteAnnotationUtilKt.writeKotlinMetadata(v, state, KotlinClassHeader.Kind.SYNTHETIC_CLASS, publicAbi, 0, av -> {
writeAnnotationData(av, serializer, functionProto); writeAnnotationData(av, serializer, functionProto);
return Unit.INSTANCE; return Unit.INSTANCE;
}); });
@@ -79,7 +79,7 @@ class CodeFragmentCodegen private constructor(
} }
override fun generateKotlinMetadataAnnotation() { override fun generateKotlinMetadataAnnotation() {
writeSyntheticClassMetadata(v, state) writeSyntheticClassMetadata(v, state, false)
} }
private fun genConstructor() { private fun genConstructor() {
@@ -43,6 +43,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
import org.jetbrains.kotlin.resolve.jvm.annotations.JvmAnnotationUtilKt; import org.jetbrains.kotlin.resolve.jvm.annotations.JvmAnnotationUtilKt;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
@@ -304,7 +305,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
protected void generateKotlinMetadataAnnotation() { protected void generateKotlinMetadataAnnotation() {
ProtoBuf.Class classProto = serializer.classProto(descriptor).build(); ProtoBuf.Class classProto = serializer.classProto(descriptor).build();
WriteAnnotationUtilKt.writeKotlinMetadata(v, state, KotlinClassHeader.Kind.CLASS, 0, av -> { boolean publicAbi = InlineUtil.isInPublicInlineScope(descriptor);
WriteAnnotationUtilKt.writeKotlinMetadata(v, state, KotlinClassHeader.Kind.CLASS, publicAbi, 0, av -> {
writeAnnotationData(av, serializer, classProto); writeAnnotationData(av, serializer, classProto);
return Unit.INSTANCE; return Unit.INSTANCE;
}); });
@@ -141,7 +141,7 @@ class InterfaceImplBodyCodegen(
override fun generateKotlinMetadataAnnotation() { override fun generateKotlinMetadataAnnotation() {
(v as InterfaceImplClassBuilder).stopCounting() (v as InterfaceImplClassBuilder).stopCounting()
writeSyntheticClassMetadata(v, state) writeSyntheticClassMetadata(v, state, false)
} }
override fun done() { override fun done() {
@@ -391,7 +391,7 @@ class MultifileClassCodegenImpl(
facadeClassType: Type, facadeClassType: Type,
kotlinPackageFqName: FqName kotlinPackageFqName: FqName
) { ) {
writeKotlinMetadata(classBuilder, state, KotlinClassHeader.Kind.MULTIFILE_CLASS, flags) { av -> writeKotlinMetadata(classBuilder, state, KotlinClassHeader.Kind.MULTIFILE_CLASS, false, flags) { av ->
val arv = av.visitArray(JvmAnnotationNames.METADATA_DATA_FIELD_NAME) val arv = av.visitArray(JvmAnnotationNames.METADATA_DATA_FIELD_NAME)
for (internalName in partInternalNames) { for (internalName in partInternalNames) {
arv.visit(null, internalName) arv.visit(null, internalName)
@@ -96,7 +96,7 @@ class MultifileClassPartCodegen(
val extraFlags = if (shouldGeneratePartHierarchy) JvmAnnotationNames.METADATA_MULTIFILE_PARTS_INHERIT_FLAG else 0 val extraFlags = if (shouldGeneratePartHierarchy) JvmAnnotationNames.METADATA_MULTIFILE_PARTS_INHERIT_FLAG else 0
writeKotlinMetadata(v, state, KotlinClassHeader.Kind.MULTIFILE_CLASS_PART, extraFlags) { av -> writeKotlinMetadata(v, state, KotlinClassHeader.Kind.MULTIFILE_CLASS_PART, false, extraFlags) { av ->
DescriptorAsmUtil.writeAnnotationData(av, serializer, packageProto) DescriptorAsmUtil.writeAnnotationData(av, serializer, packageProto)
av.visit(JvmAnnotationNames.METADATA_MULTIFILE_CLASS_NAME_FIELD_NAME, facadeClassType.internalName) av.visit(JvmAnnotationNames.METADATA_MULTIFILE_CLASS_NAME_FIELD_NAME, facadeClassType.internalName)
@@ -107,7 +107,7 @@ public class PackagePartCodegen extends MemberCodegen<KtFile> {
protected void generateKotlinMetadataAnnotation() { protected void generateKotlinMetadataAnnotation() {
Pair<DescriptorSerializer, ProtoBuf.Package> serializedPart = serializePackagePartMembers(this, packagePartType); Pair<DescriptorSerializer, ProtoBuf.Package> serializedPart = serializePackagePartMembers(this, packagePartType);
WriteAnnotationUtilKt.writeKotlinMetadata(v, state, KotlinClassHeader.Kind.FILE_FACADE, 0, av -> { WriteAnnotationUtilKt.writeKotlinMetadata(v, state, KotlinClassHeader.Kind.FILE_FACADE, false, 0, av -> {
writeAnnotationData(av, serializedPart.getFirst(), serializedPart.getSecond()); writeAnnotationData(av, serializedPart.getFirst(), serializedPart.getSecond());
FqName kotlinPackageFqName = element.getPackageFqName(); FqName kotlinPackageFqName = element.getPackageFqName();
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.PropertyImportedFromObject import org.jetbrains.kotlin.resolve.PropertyImportedFromObject
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.isUnderlyingPropertyOfInlineClass import org.jetbrains.kotlin.resolve.isUnderlyingPropertyOfInlineClass
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.* import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
@@ -209,7 +210,7 @@ class PropertyReferenceCodegen(
} }
override fun generateKotlinMetadataAnnotation() { override fun generateKotlinMetadataAnnotation() {
writeSyntheticClassMetadata(v, state) writeSyntheticClassMetadata(v, state, InlineUtil.isInPublicInlineScope(classDescriptor))
} }
fun putInstanceOnStack(receiverValue: StackValue?): StackValue { fun putInstanceOnStack(receiverValue: StackValue?): StackValue {
@@ -138,7 +138,7 @@ public class SamWrapperCodegen {
); );
cv.visitSource(file.getName(), null); cv.visitSource(file.getName(), null);
WriteAnnotationUtilKt.writeSyntheticClassMetadata(cv, state); WriteAnnotationUtilKt.writeSyntheticClassMetadata(cv, state, isInsideInline);
generateInnerClassInformation(file, asmType, cv); generateInnerClassInformation(file, asmType, cv);
@@ -69,7 +69,7 @@ class ScriptCodegen private constructor(
override fun generateKotlinMetadataAnnotation() { override fun generateKotlinMetadataAnnotation() {
val serializer = DescriptorSerializer.create(scriptDescriptor, JvmSerializerExtension(v.serializationBindings, state), null) val serializer = DescriptorSerializer.create(scriptDescriptor, JvmSerializerExtension(v.serializationBindings, state), null)
val classProto = serializer.classProto(scriptDescriptor).build() val classProto = serializer.classProto(scriptDescriptor).build()
writeKotlinMetadata(v, state, KotlinClassHeader.Kind.CLASS, JvmAnnotationNames.METADATA_SCRIPT_FLAG) { av -> writeKotlinMetadata(v, state, KotlinClassHeader.Kind.CLASS, false, JvmAnnotationNames.METADATA_SCRIPT_FLAG) { av ->
DescriptorAsmUtil.writeAnnotationData(av, serializer, classProto) DescriptorAsmUtil.writeAnnotationData(av, serializer, classProto)
} }
} }
@@ -1012,7 +1012,15 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
ClassDescriptor classDescriptor = (ClassDescriptor) type.getConstructor().getDeclarationDescriptor(); ClassDescriptor classDescriptor = (ClassDescriptor) type.getConstructor().getDeclarationDescriptor();
assert classDescriptor != null : "because it's enum"; assert classDescriptor != null : "because it's enum";
WhenByEnumsMapping mapping = new WhenByEnumsMapping(classDescriptor, currentClassName, fieldNumber); boolean isPublicAbi = false;
for (FunctionDescriptor descriptor : functionsStack) {
if (descriptor.isInline()) {
isPublicAbi = !DescriptorVisibilities.isPrivate(descriptor.getVisibility());
break;
}
}
WhenByEnumsMapping mapping = new WhenByEnumsMapping(classDescriptor, currentClassName, fieldNumber, isPublicAbi);
for (ConstantValue<?> constant : switchCodegenProvider.getAllConstants(expression)) { for (ConstantValue<?> constant : switchCodegenProvider.getAllConstants(expression)) {
if (constant instanceof NullValue) continue; if (constant instanceof NullValue) continue;
@@ -654,7 +654,7 @@ private fun generateLambdaForRunSuspend(
visitEnd() visitEnd()
} }
writeSyntheticClassMetadata(lambdaBuilder, state) writeSyntheticClassMetadata(lambdaBuilder, state, false)
lambdaBuilder.done() lambdaBuilder.done()
return lambdaBuilder.thisName return lambdaBuilder.thisName
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.indexOrMinusOne import org.jetbrains.kotlin.resolve.indexOrMinusOne
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.isInlineClassType import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
@@ -742,7 +743,8 @@ class CoroutineCodegenForNamedFunction private constructor(
} }
override fun generateKotlinMetadataAnnotation() { override fun generateKotlinMetadataAnnotation() {
writeKotlinMetadata(v, state, KotlinClassHeader.Kind.SYNTHETIC_CLASS, 0) { av -> val publicAbi = InlineUtil.isInPublicInlineScope(classDescriptor)
writeKotlinMetadata(v, state, KotlinClassHeader.Kind.SYNTHETIC_CLASS, publicAbi, 0) { av ->
val serializer = DescriptorSerializer.createForLambda(JvmSerializerExtension(v.serializationBindings, state)) val serializer = DescriptorSerializer.createForLambda(JvmSerializerExtension(v.serializationBindings, state))
val functionProto = val functionProto =
serializer.functionProto( serializer.functionProto(
@@ -118,6 +118,10 @@ class AnonymousObjectTransformer(
override fun visitEnd() {} override fun visitEnd() {}
}, ClassReader.SKIP_FRAMES) }, ClassReader.SKIP_FRAMES)
val header = metadataReader.createHeader()
assert(isSameModule || (header != null && isPublicAbi(header))) {
"Trying to inline an anonymous object which is not part of the public ABI: ${oldObjectType.className}"
}
// When regenerating objects in inline lambdas, keep the old SMAP and don't remap the line numbers to // When regenerating objects in inline lambdas, keep the old SMAP and don't remap the line numbers to
// save time. The result is effectively the same anyway. // save time. The result is effectively the same anyway.
@@ -198,7 +202,6 @@ class AnonymousObjectTransformer(
visitor.visitInnerClass(node.name, node.outerName, node.innerName, node.access) visitor.visitInnerClass(node.name, node.outerName, node.innerName, node.access)
} }
val header = metadataReader.createHeader()
if (header != null) { if (header != null) {
writeTransformedMetadata(header, classBuilder) writeTransformedMetadata(header, classBuilder)
} }
@@ -229,7 +232,9 @@ class AnonymousObjectTransformer(
} }
private fun writeTransformedMetadata(header: KotlinClassHeader, classBuilder: ClassBuilder) { private fun writeTransformedMetadata(header: KotlinClassHeader, classBuilder: ClassBuilder) {
writeKotlinMetadata(classBuilder, state, header.kind, header.extraInt) action@{ av -> // The transformed anonymous object becomes part of the public ABI if it is inside of a public inline function.
val publicAbi = inliningContext.callSiteInfo.isInPublicInlineScope
writeKotlinMetadata(classBuilder, state, header.kind, publicAbi, header.extraInt and JvmAnnotationNames.METADATA_PUBLIC_ABI_FLAG.inv()) action@{ av ->
val (newProto, newStringTable) = transformMetadata(header) ?: run { val (newProto, newStringTable) = transformMetadata(header) ?: run {
val data = header.data val data = header.data
val strings = header.strings val strings = header.strings
@@ -242,6 +247,11 @@ class AnonymousObjectTransformer(
} }
} }
private fun isPublicAbi(header: KotlinClassHeader): Boolean =
// The public abi flag was only introduced in metadata version 1.6.0, before then we have to skip this check.
!header.metadataVersion.isAtLeast(1, 6, 0) ||
header.extraInt and JvmAnnotationNames.METADATA_PUBLIC_ABI_FLAG != 0
private fun transformMetadata(header: KotlinClassHeader): Pair<MessageLite, JvmStringTable>? { private fun transformMetadata(header: KotlinClassHeader): Pair<MessageLite, JvmStringTable>? {
val data = header.data ?: return null val data = header.data ?: return null
val strings = header.strings ?: return null val strings = header.strings ?: return null
@@ -317,7 +327,7 @@ class AnonymousObjectTransformer(
InlineCallSiteInfo( InlineCallSiteInfo(
transformationInfo.oldClassName, transformationInfo.oldClassName,
Method(sourceNode.name, if (isConstructor) transformationInfo.newConstructorDescriptor else sourceNode.desc), Method(sourceNode.name, if (isConstructor) transformationInfo.newConstructorDescriptor else sourceNode.desc),
inliningContext.callSiteInfo.isInlineOrInsideInline, inliningContext.callSiteInfo.inlineScopeVisibility,
inliningContext.callSiteInfo.file, inliningContext.callSiteInfo.file,
inliningContext.callSiteInfo.lineNumber inliningContext.callSiteInfo.lineNumber
), ),
@@ -74,7 +74,7 @@ class PsiSourceCompilerForInline(
return InlineCallSiteInfo( return InlineCallSiteInfo(
parentCodegen.className, parentCodegen.className,
signature.asmMethod, signature.asmMethod,
context.functionDescriptor.isInlineOrInsideInline(), context.functionDescriptor.getInlineCallSiteVisibility(),
callElement.containingFile, callElement.containingFile,
CodegenUtil.getLineNumberForElement(callElement, false) ?: 0 CodegenUtil.getLineNumberForElement(callElement, false) ?: 0
) )
@@ -416,8 +416,11 @@ class PsiSourceCompilerForInline(
} }
fun DeclarationDescriptor.isInlineOrInsideInline(): Boolean = fun DeclarationDescriptor.isInlineOrInsideInline(): Boolean =
if (this is FunctionDescriptor && isInline) true getInlineCallSiteVisibility() != null
else containingDeclaration?.isInlineOrInsideInline() == true
fun DeclarationDescriptor.getInlineCallSiteVisibility(): DescriptorVisibility? =
if (this is FunctionDescriptor && isInline) visibility
else containingDeclaration?.getInlineCallSiteVisibility()
fun getDeclarationLabels(lambdaOrFun: PsiElement?, descriptor: DeclarationDescriptor): Set<String> { fun getDeclarationLabels(lambdaOrFun: PsiElement?, descriptor: DeclarationDescriptor): Set<String> {
val result = HashSet<String>() val result = HashSet<String>()
@@ -10,6 +10,8 @@ import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.incremental.components.LocationInfo import org.jetbrains.kotlin.incremental.components.LocationInfo
import org.jetbrains.kotlin.incremental.components.Position import org.jetbrains.kotlin.incremental.components.Position
import org.jetbrains.kotlin.incremental.components.ScopeKind import org.jetbrains.kotlin.incremental.components.ScopeKind
@@ -24,10 +26,16 @@ import org.jetbrains.org.objectweb.asm.tree.MethodNode
class InlineCallSiteInfo( class InlineCallSiteInfo(
val ownerClassName: String, val ownerClassName: String,
val method: Method, val method: Method,
val isInlineOrInsideInline: Boolean, val inlineScopeVisibility: DescriptorVisibility?,
val file: PsiFile?, val file: PsiFile?,
val lineNumber: Int val lineNumber: Int
) ) {
val isInlineOrInsideInline: Boolean
get() = inlineScopeVisibility != null
val isInPublicInlineScope: Boolean
get() = inlineScopeVisibility != null && !DescriptorVisibilities.isPrivate(inlineScopeVisibility)
}
interface SourceCompilerForInline { interface SourceCompilerForInline {
val state: GenerationState val state: GenerationState
@@ -57,7 +57,8 @@ public class MappingClassesForWhenByEnumCodegen {
generateFields(cb, mappings); generateFields(cb, mappings);
generateInitialization(cb, mappings); generateInitialization(cb, mappings);
WriteAnnotationUtilKt.writeSyntheticClassMetadata(cb, state); boolean publicAbi = mappings.stream().anyMatch(WhenByEnumsMapping::isPublicAbi);
WriteAnnotationUtilKt.writeSyntheticClassMetadata(cb, state, publicAbi);
cb.done(); cb.done();
} }
@@ -32,16 +32,19 @@ public class WhenByEnumsMapping {
private final String outerClassInternalNameForExpression; private final String outerClassInternalNameForExpression;
private final String mappingsClassInternalName; private final String mappingsClassInternalName;
private final int fieldNumber; private final int fieldNumber;
private final boolean isPublicAbi;
public WhenByEnumsMapping( public WhenByEnumsMapping(
@NotNull ClassDescriptor enumClassDescriptor, @NotNull ClassDescriptor enumClassDescriptor,
@NotNull String outerClassInternalNameForExpression, @NotNull String outerClassInternalNameForExpression,
int fieldNumber int fieldNumber,
boolean isPublicAbi
) { ) {
this.enumClassDescriptor = enumClassDescriptor; this.enumClassDescriptor = enumClassDescriptor;
this.outerClassInternalNameForExpression = outerClassInternalNameForExpression; this.outerClassInternalNameForExpression = outerClassInternalNameForExpression;
this.mappingsClassInternalName = outerClassInternalNameForExpression + MAPPINGS_CLASS_NAME_POSTFIX; this.mappingsClassInternalName = outerClassInternalNameForExpression + MAPPINGS_CLASS_NAME_POSTFIX;
this.fieldNumber = fieldNumber; this.fieldNumber = fieldNumber;
this.isPublicAbi = isPublicAbi;
} }
public int getIndexByEntry(@NotNull EnumValue value) { public int getIndexByEntry(@NotNull EnumValue value) {
@@ -80,6 +83,10 @@ public class WhenByEnumsMapping {
return mappingsClassInternalName; return mappingsClassInternalName;
} }
public boolean isPublicAbi() {
return isPublicAbi;
}
@NotNull @NotNull
public Iterable<Map.Entry<EnumValue, Integer>> enumValuesToIntMapping() { public Iterable<Map.Entry<EnumValue, Integer>> enumValuesToIntMapping() {
return map.entrySet(); return map.entrySet();
@@ -27,6 +27,7 @@ fun writeKotlinMetadata(
cb: ClassBuilder, cb: ClassBuilder,
state: GenerationState, state: GenerationState,
kind: KotlinClassHeader.Kind, kind: KotlinClassHeader.Kind,
publicAbi: Boolean,
extraFlags: Int, extraFlags: Int,
action: (AnnotationVisitor) -> Unit action: (AnnotationVisitor) -> Unit
) { ) {
@@ -43,6 +44,9 @@ fun writeKotlinMetadata(
if (state.languageVersionSettings.getFlag(JvmAnalysisFlags.strictMetadataVersionSemantics)) { if (state.languageVersionSettings.getFlag(JvmAnalysisFlags.strictMetadataVersionSemantics)) {
flags = flags or JvmAnnotationNames.METADATA_STRICT_VERSION_SEMANTICS_FLAG flags = flags or JvmAnnotationNames.METADATA_STRICT_VERSION_SEMANTICS_FLAG
} }
if (publicAbi) {
flags = flags or JvmAnnotationNames.METADATA_PUBLIC_ABI_FLAG
}
if (flags != 0) { if (flags != 0) {
av.visit(JvmAnnotationNames.METADATA_EXTRA_INT_FIELD_NAME, flags) av.visit(JvmAnnotationNames.METADATA_EXTRA_INT_FIELD_NAME, flags)
} }
@@ -50,8 +54,8 @@ fun writeKotlinMetadata(
av.visitEnd() av.visitEnd()
} }
fun writeSyntheticClassMetadata(cb: ClassBuilder, state: GenerationState) { fun writeSyntheticClassMetadata(cb: ClassBuilder, state: GenerationState, publicAbi: Boolean) {
writeKotlinMetadata(cb, state, KotlinClassHeader.Kind.SYNTHETIC_CLASS, 0) { _ -> writeKotlinMetadata(cb, state, KotlinClassHeader.Kind.SYNTHETIC_CLASS, publicAbi, 0) { _ ->
// Do nothing // Do nothing
} }
} }
@@ -74,6 +74,17 @@ public class InlineUtil {
return isInlineOrContainingInline(descriptor.getContainingDeclaration()); return isInlineOrContainingInline(descriptor.getContainingDeclaration());
} }
public static boolean isInPublicInlineScope(@Nullable DeclarationDescriptor descriptor) {
if (descriptor == null) return false;
if (isInline(descriptor)) {
if (!(descriptor instanceof DeclarationDescriptorWithVisibility))
return false;
DescriptorVisibility visibility = ((DeclarationDescriptorWithVisibility) descriptor).getVisibility();
return !DescriptorVisibilities.isPrivate(visibility);
}
return isInPublicInlineScope(descriptor.getContainingDeclaration());
}
public static boolean checkNonLocalReturnUsage( public static boolean checkNonLocalReturnUsage(
@NotNull DeclarationDescriptor fromFunction, @NotNull DeclarationDescriptor fromFunction,
@NotNull KtExpression startExpression, @NotNull KtExpression startExpression,
@@ -136,6 +136,8 @@ class JvmBackendContext(
val directInvokedLambdas = mutableListOf<IrAttributeContainer>() val directInvokedLambdas = mutableListOf<IrAttributeContainer>()
val publicAbiSymbols = mutableSetOf<IrClassSymbol>()
init { init {
state.mapInlineClass = { descriptor -> state.mapInlineClass = { descriptor ->
typeMapper.mapType(referenceClass(descriptor).defaultType) typeMapper.mapType(referenceClass(descriptor).defaultType)
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.jvm.codegen
import org.jetbrains.kotlin.backend.common.psi.PsiSourceManager import org.jetbrains.kotlin.backend.common.psi.PsiSourceManager
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.ir.isInPublicInlineScope
import org.jetbrains.kotlin.backend.jvm.ir.isSyntheticSingleton import org.jetbrains.kotlin.backend.jvm.ir.isSyntheticSingleton
import org.jetbrains.kotlin.backend.jvm.lower.MultifileFacadeFileEntry import org.jetbrains.kotlin.backend.jvm.lower.MultifileFacadeFileEntry
import org.jetbrains.kotlin.backend.jvm.lower.buildAssertionsDisabledField import org.jetbrains.kotlin.backend.jvm.lower.buildAssertionsDisabledField
@@ -258,7 +259,17 @@ class ClassCodegen private constructor(
extraFlags = extraFlags or JvmAnnotationNames.METADATA_SCRIPT_FLAG extraFlags = extraFlags or JvmAnnotationNames.METADATA_SCRIPT_FLAG
} }
writeKotlinMetadata(visitor, state, kind, extraFlags) { av -> // There are three kinds of classes which are regenerated during inlining.
// 1) Anonymous classes which are in the scope of an inline function.
// 2) SAM wrappers used in an inline function. These are identified by name, since they
// can be reused in different functions and are thus generated in the enclosing top-level
// class instead of inside of an inline function.
// 3) WhenMapping classes used from inline functions. These are collected in
// `JvmBackendContext.publicAbiSymbols` in `MappedEnumWhenLowering`.
val isPublicAbi = irClass.symbol in context.publicAbiSymbols || irClass.isInlineSamWrapper ||
type.isAnonymousClass && irClass.isInPublicInlineScope
writeKotlinMetadata(visitor, state, kind, isPublicAbi, extraFlags) { av ->
if (metadata != null) { if (metadata != null) {
metadataSerializer.serialize(metadata)?.let { (proto, stringTable) -> metadataSerializer.serialize(metadata)?.let { (proto, stringTable) ->
DescriptorAsmUtil.writeAnnotationData(av, proto, stringTable) DescriptorAsmUtil.writeAnnotationData(av, proto, stringTable)
@@ -454,6 +465,9 @@ class ClassCodegen private constructor(
private val IrClass.isAnonymousInnerClass: Boolean private val IrClass.isAnonymousInnerClass: Boolean
get() = isSamWrapper || name.isSpecial // NB '<Continuation>' is treated as anonymous inner class here get() = isSamWrapper || name.isSpecial // NB '<Continuation>' is treated as anonymous inner class here
private val IrClass.isInlineSamWrapper: Boolean
get() = isSamWrapper && visibility == DescriptorVisibilities.PUBLIC
private val IrClass.isSamWrapper: Boolean private val IrClass.isSamWrapper: Boolean
get() = origin == IrDeclarationOrigin.GENERATED_SAM_IMPLEMENTATION get() = origin == IrDeclarationOrigin.GENERATED_SAM_IMPLEMENTATION
@@ -579,3 +593,7 @@ private fun storeSerializedIr(av: AnnotationVisitor, serializedIr: ByteArray) {
} }
partsVisitor.visitEnd() partsVisitor.visitEnd()
} }
// From `isAnonymousClass` in inlineCodegenUtils.kt
private val Type.isAnonymousClass: Boolean
get() = internalName.substringAfterLast("$", "").toIntOrNull() != null
@@ -9,6 +9,7 @@ import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.backend.common.CodegenUtil import org.jetbrains.kotlin.backend.common.CodegenUtil
import org.jetbrains.kotlin.backend.common.ir.ir2string import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.jvm.ir.getKtFile import org.jetbrains.kotlin.backend.jvm.ir.getKtFile
import org.jetbrains.kotlin.backend.jvm.ir.inlineScopeVisibility
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.hasMangledReturnType import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.hasMangledReturnType
import org.jetbrains.kotlin.codegen.inline.* import org.jetbrains.kotlin.codegen.inline.*
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
@@ -16,7 +17,8 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
import org.jetbrains.kotlin.incremental.components.LocationInfo import org.jetbrains.kotlin.incremental.components.LocationInfo
import org.jetbrains.kotlin.incremental.components.Position import org.jetbrains.kotlin.incremental.components.Position
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.descriptors.toIrBasedDescriptor import org.jetbrains.kotlin.ir.descriptors.toIrBasedDescriptor
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrLoop import org.jetbrains.kotlin.ir.expressions.IrLoop
@@ -48,7 +50,7 @@ class IrSourceCompilerForInline(
return InlineCallSiteInfo( return InlineCallSiteInfo(
root.classCodegen.type.internalName, root.classCodegen.type.internalName,
root.signature.asmMethod, root.signature.asmMethod,
root.irFunction.isInlineOrInsideInline(), root.irFunction.inlineScopeVisibility,
root.irFunction.fileParent.getKtFile(), root.irFunction.fileParent.getKtFile(),
callElement.psiElement?.let { CodegenUtil.getLineNumberForElement(it, false) } ?: 0 callElement.psiElement?.let { CodegenUtil.getLineNumberForElement(it, false) } ?: 0
) )
@@ -131,12 +133,4 @@ class IrSourceCompilerForInline(
} }
} }
private tailrec fun IrDeclaration.isInlineOrInsideInline(): Boolean {
val original = (this as? IrAttributeContainer)?.attributeOwnerId as? IrDeclaration ?: this
if (original is IrSimpleFunction && original.isInline) return true
val parent = original.parent
if (parent !is IrDeclaration) return false
return parent.isInlineOrInsideInline()
}
internal fun IrLoop.nonLocalReturnLabel(forBreak: Boolean): String = "${label!!}\$${if (forBreak) "break" else "continue"}" internal fun IrLoop.nonLocalReturnLabel(forBreak: Boolean): String = "${label!!}\$${if (forBreak) "break" else "continue"}"
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
import org.jetbrains.kotlin.config.JvmDefaultMode import org.jetbrains.kotlin.config.JvmDefaultMode
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.descriptors.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.IrBuiltIns
@@ -48,6 +49,7 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_DEFAULT_FQ_NAME import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_DEFAULT_FQ_NAME
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_DEFAULT_NO_COMPATIBILITY_FQ_NAME import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_DEFAULT_NO_COMPATIBILITY_FQ_NAME
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
/** /**
* Perform as much type erasure as is significant for JVM signature generation. * Perform as much type erasure as is significant for JVM signature generation.
@@ -419,3 +421,25 @@ val IrClass.isSyntheticSingleton: Boolean
|| origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL || origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
|| origin == JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE) || origin == JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE)
&& primaryConstructor!!.valueParameters.isEmpty() && primaryConstructor!!.valueParameters.isEmpty()
// Map declarations to original declarations before lowering.
private val IrDeclaration.original: IrDeclaration
get() = (this as? IrAttributeContainer)?.attributeOwnerId as? IrDeclaration ?: this
// Declarations in the scope of an externally visible inline function are implicitly part of the
// public ABI of a Kotlin module. This function returns the visibility of a containing inline function
// (determined *before* lowering), or null if the given declaration is not in the scope of an inline function.
val IrDeclaration.inlineScopeVisibility: DescriptorVisibility?
get() {
var owner = original
while (true) {
if (owner is IrFunction && owner.isInline) {
return owner.visibility
}
owner = owner.parent.safeAs<IrDeclaration>()?.original ?: return null
}
}
// True for declarations which are in the scope of an externally visible inline function.
val IrDeclaration.isInPublicInlineScope: Boolean
get() = inlineScopeVisibility?.let(DescriptorVisibilities::isPrivate) == false
@@ -5,18 +5,20 @@
package org.jetbrains.kotlin.backend.jvm.lower package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.lower.EnumWhenLowering import org.jetbrains.kotlin.backend.common.lower.EnumWhenLowering
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.ir.isInPublicInlineScope
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.addField import org.jetbrains.kotlin.ir.builders.declarations.addField
import org.jetbrains.kotlin.ir.builders.declarations.buildClass import org.jetbrains.kotlin.ir.builders.declarations.buildClass
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrEnumEntry import org.jetbrains.kotlin.ir.declarations.IrEnumEntry
import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
@@ -25,6 +27,7 @@ import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal val enumWhenPhase = makeIrFilePhase( internal val enumWhenPhase = makeIrFilePhase(
::MappedEnumWhenLowering, ::MappedEnumWhenLowering,
@@ -57,7 +60,7 @@ internal val enumWhenPhase = makeIrFilePhase(
// The latter would not need to be recompiled if new entries were added before `X` // The latter would not need to be recompiled if new entries were added before `X`
// at the negligible cost of an additional initializer per run + one array read per call. // at the negligible cost of an additional initializer per run + one array read per call.
// //
private class MappedEnumWhenLowering(context: CommonBackendContext) : EnumWhenLowering(context) { private class MappedEnumWhenLowering(context: JvmBackendContext) : EnumWhenLowering(context) {
private val intArray = context.irBuiltIns.primitiveArrayForType.getValue(context.irBuiltIns.intType) private val intArray = context.irBuiltIns.primitiveArrayForType.getValue(context.irBuiltIns.intType)
private val intArrayConstructor = intArray.constructors.single { it.owner.valueParameters.size == 1 } private val intArrayConstructor = intArray.constructors.single { it.owner.valueParameters.size == 1 }
private val intArrayGet = intArray.functions.single { it.owner.name == OperatorNameConventions.GET } private val intArrayGet = intArray.functions.single { it.owner.name == OperatorNameConventions.GET }
@@ -68,8 +71,14 @@ private class MappedEnumWhenLowering(context: CommonBackendContext) : EnumWhenLo
// of the classes in which they are used. This field tracks which container is the innermost one. // of the classes in which they are used. This field tracks which container is the innermost one.
private var state: EnumMappingState? = null private var state: EnumMappingState? = null
private class EnumMappingClass(
val field: IrField,
val ordinals: MutableMap<IrEnumEntry, Int> = mutableMapOf(),
var isPublicAbi: Boolean = false,
)
private inner class EnumMappingState { private inner class EnumMappingState {
val mappings = mutableMapOf<IrClass /* enum */, Pair<MutableMap<IrEnumEntry, Int>, IrField>>() val mappings = mutableMapOf<IrClass /* enum */, EnumMappingClass>()
val mappingsClass by lazy { val mappingsClass by lazy {
context.irFactory.buildClass { context.irFactory.buildClass {
name = Name.identifier("WhenMappings") name = Name.identifier("WhenMappings")
@@ -79,39 +88,46 @@ private class MappedEnumWhenLowering(context: CommonBackendContext) : EnumWhenLo
} }
} }
fun getMappingForClass(enumClass: IrClass): Pair<MutableMap<IrEnumEntry, Int>, IrField> = fun getMappingForClass(enumClass: IrClass): EnumMappingClass =
mappings.getOrPut(enumClass) { mappings.getOrPut(enumClass) {
mutableMapOf<IrEnumEntry, Int>() to mappingsClass.addField { EnumMappingClass(mappingsClass.addField {
name = Name.identifier("\$EnumSwitchMapping\$${mappings.size}") name = Name.identifier("\$EnumSwitchMapping\$${mappings.size}")
type = intArray.defaultType type = intArray.defaultType
origin = JvmLoweredDeclarationOrigin.ENUM_MAPPINGS_FOR_WHEN origin = JvmLoweredDeclarationOrigin.ENUM_MAPPINGS_FOR_WHEN
isFinal = true isFinal = true
isStatic = true isStatic = true
} })
} }
val isPublicAbi: Boolean
get() = mappings.values.any { it.isPublicAbi }
} }
override fun mapConstEnumEntry(entry: IrEnumEntry): Int { override fun mapConstEnumEntry(entry: IrEnumEntry): Int {
val (mapping) = state!!.getMappingForClass(entry.parentAsClass) val mapping = state!!.getMappingForClass(entry.parentAsClass).ordinals
// Index 0 (default value for integers) is reserved for unknown ordinals. // Index 0 (default value for integers) is reserved for unknown ordinals.
return mapping.getOrPut(entry) { mapping.size + 1 } return mapping.getOrPut(entry) { mapping.size + 1 }
} }
override fun mapRuntimeEnumEntry(builder: IrBuilderWithScope, subject: IrExpression): IrExpression = override fun mapRuntimeEnumEntry(builder: IrBuilderWithScope, subject: IrExpression): IrExpression =
builder.irCall(intArrayGet).apply { builder.irCall(intArrayGet).apply {
val (_, field) = state!!.getMappingForClass(subject.type.getClass()!!) val mapping = state!!.getMappingForClass(subject.type.getClass()!!)
dispatchReceiver = builder.irGetField(null, field)
mapping.isPublicAbi = mapping.isPublicAbi ||
(builder.scope.scopeOwnerSymbol.owner.safeAs<IrDeclaration>()?.isInPublicInlineScope ?: false)
dispatchReceiver = builder.irGetField(null, mapping.field)
putValueArgument(0, super.mapRuntimeEnumEntry(builder, subject)) putValueArgument(0, super.mapRuntimeEnumEntry(builder, subject))
} }
override fun visitClassNew(declaration: IrClass): IrStatement { override fun visitClassNew(declaration: IrClass): IrStatement {
val oldState = state val oldState = state
state = EnumMappingState() val mappingState = EnumMappingState()
state = mappingState
super.visitClassNew(declaration) super.visitClassNew(declaration)
for ((enum, mappingAndField) in state!!.mappings) { for ((enum, mapping) in mappingState.mappings) {
val (mapping, field) = mappingAndField val builder = context.createIrBuilder(mappingState.mappingsClass.symbol)
val builder = context.createIrBuilder(state!!.mappingsClass.symbol)
val enumValues = enum.functions.single { val enumValues = enum.functions.single {
it.name.toString() == "values" it.name.toString() == "values"
&& it.dispatchReceiverParameter == null && it.dispatchReceiverParameter == null
@@ -120,10 +136,10 @@ private class MappedEnumWhenLowering(context: CommonBackendContext) : EnumWhenLo
&& it.returnType.isBoxedArray && it.returnType.isBoxedArray
&& it.returnType.getArrayElementType(context.irBuiltIns).classOrNull == enum.symbol && it.returnType.getArrayElementType(context.irBuiltIns).classOrNull == enum.symbol
} }
field.initializer = builder.irExprBody(builder.irBlock { mapping.field.initializer = builder.irExprBody(builder.irBlock {
val enumSize = irCall(refArraySize).apply { dispatchReceiver = irCall(enumValues) } val enumSize = irCall(refArraySize).apply { dispatchReceiver = irCall(enumValues) }
val result = irTemporary(irCall(intArrayConstructor).apply { putValueArgument(0, enumSize) }) val result = irTemporary(irCall(intArrayConstructor).apply { putValueArgument(0, enumSize) })
for ((entry, index) in mapping) { for ((entry, index) in mapping.ordinals) {
val runtimeEntry = IrGetEnumValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, enum.defaultType, entry.symbol) val runtimeEntry = IrGetEnumValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, enum.defaultType, entry.symbol)
+irCall(intArraySet).apply { +irCall(intArraySet).apply {
dispatchReceiver = irGet(result) dispatchReceiver = irGet(result)
@@ -135,8 +151,13 @@ private class MappedEnumWhenLowering(context: CommonBackendContext) : EnumWhenLo
}) })
} }
if (state!!.mappings.isNotEmpty()) { if (mappingState.mappings.isNotEmpty()) {
declaration.declarations += state!!.mappingsClass.apply { parent = declaration } declaration.declarations += mappingState.mappingsClass.apply {
parent = declaration
if (mappingState.isPublicAbi) {
(context as JvmBackendContext).publicAbiSymbols += symbol
}
}
} }
state = oldState state = oldState
return declaration return declaration
@@ -44,6 +44,7 @@ public final class JvmAnnotationNames {
public static final int METADATA_JVM_IR_FLAG = 1 << 4; public static final int METADATA_JVM_IR_FLAG = 1 << 4;
public static final int METADATA_JVM_IR_STABLE_ABI_FLAG = 1 << 5; public static final int METADATA_JVM_IR_STABLE_ABI_FLAG = 1 << 5;
public static final int METADATA_FIR_FLAG = 1 << 6; public static final int METADATA_FIR_FLAG = 1 << 6;
public static final int METADATA_PUBLIC_ABI_FLAG = 1 << 7;
public static final Name DEFAULT_ANNOTATION_MEMBER_NAME = Name.identifier("value"); public static final Name DEFAULT_ANNOTATION_MEMBER_NAME = Name.identifier("value");
@@ -76,6 +76,8 @@ public annotation class Metadata(
* * 5 - this class file has stable metadata and ABI. This is used only for class files compiled with JVM IR (see flag #4) or FIR (#6), * * 5 - this class file has stable metadata and ABI. This is used only for class files compiled with JVM IR (see flag #4) or FIR (#6),
* and prevents metadata incompatibility diagnostics from being reported where the class is used. * and prevents metadata incompatibility diagnostics from being reported where the class is used.
* * 6 - this class file is compiled with the new Kotlin compiler frontend (FIR). * * 6 - this class file is compiled with the new Kotlin compiler frontend (FIR).
* * 7 - this class is used in the scope of an inline function and implicitly part of the public ABI. Only valid from
* metadata version 1.6.0.
*/ */
@SinceKotlin("1.1") @SinceKotlin("1.1")
@get:JvmName("xi") @get:JvmName("xi")
@@ -28,12 +28,12 @@ import org.jetbrains.kotlin.codegen.writeSyntheticClassMetadata
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.incremental.components.NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.DescriptorFactory import org.jetbrains.kotlin.resolve.DescriptorFactory
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.LockBasedStorageManager
@@ -42,7 +42,6 @@ import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.org.objectweb.asm.Opcodes.* import org.jetbrains.org.objectweb.asm.Opcodes.*
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
import java.io.FileDescriptor
open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodegenExtension { open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodegenExtension {
@Deprecated( @Deprecated(
@@ -315,7 +314,7 @@ open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodeg
codegen.v.visitInnerClass(creatorAsmType.internalName, containerAsmType.internalName, "Creator", ACC_PUBLIC or ACC_STATIC) codegen.v.visitInnerClass(creatorAsmType.internalName, containerAsmType.internalName, "Creator", ACC_PUBLIC or ACC_STATIC)
codegenForCreator.v.visitInnerClass(creatorAsmType.internalName, containerAsmType.internalName, "Creator", ACC_PUBLIC or ACC_STATIC) codegenForCreator.v.visitInnerClass(creatorAsmType.internalName, containerAsmType.internalName, "Creator", ACC_PUBLIC or ACC_STATIC)
writeSyntheticClassMetadata(classBuilderForCreator, codegen.state) writeSyntheticClassMetadata(classBuilderForCreator, codegen.state, InlineUtil.isInPublicInlineScope(parcelableClass))
writeCreatorConstructor(codegenForCreator, creatorClass, creatorAsmType) writeCreatorConstructor(codegenForCreator, creatorClass, creatorAsmType)
writeNewArrayMethod(codegenForCreator, parcelableClass, parcelableCreatorClassType, creatorClass, parcelerObject) writeNewArrayMethod(codegenForCreator, parcelableClass, parcelableCreatorClassType, creatorClass, parcelerObject)
@@ -658,7 +658,7 @@ internal fun createSingletonLambda(
areturn(kSerializerType) areturn(kSerializerType)
} }
writeSyntheticClassMetadata(lambdaClassBuilder, lambdaCodegen.state) writeSyntheticClassMetadata(lambdaClassBuilder, lambdaCodegen.state, false)
lambdaClassBuilder.done() lambdaClassBuilder.done()
return lambdaType return lambdaType
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.resolve.DescriptorFactory
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
@@ -329,7 +330,7 @@ open class ParcelizeCodegenExtension : ParcelizeExtensionBase, ExpressionCodegen
codegen.v.visitInnerClass(creatorAsmType.internalName, containerAsmType.internalName, "Creator", ACC_PUBLIC or ACC_STATIC) codegen.v.visitInnerClass(creatorAsmType.internalName, containerAsmType.internalName, "Creator", ACC_PUBLIC or ACC_STATIC)
codegenForCreator.v.visitInnerClass(creatorAsmType.internalName, containerAsmType.internalName, "Creator", ACC_PUBLIC or ACC_STATIC) codegenForCreator.v.visitInnerClass(creatorAsmType.internalName, containerAsmType.internalName, "Creator", ACC_PUBLIC or ACC_STATIC)
writeSyntheticClassMetadata(classBuilderForCreator, codegen.state) writeSyntheticClassMetadata(classBuilderForCreator, codegen.state, InlineUtil.isInPublicInlineScope(parcelableClass))
writeCreatorConstructor(codegenForCreator, creatorClass, creatorAsmType) writeCreatorConstructor(codegenForCreator, creatorClass, creatorAsmType)
writeNewArrayMethod(codegenForCreator, parcelableClass, parcelableCreatorClassType, creatorClass, parcelerObject) writeNewArrayMethod(codegenForCreator, parcelableClass, parcelableCreatorClassType, creatorClass, parcelerObject)