JVM IR: Fix inline class constructor ABI (KT-37013, KT-37015)
This commit is contained in:
committed by
Dmitry Petrov
parent
b93c49afae
commit
846fc13519
+31
-13
@@ -53,10 +53,15 @@ open class DefaultArgumentStubGenerator(
|
||||
}
|
||||
|
||||
private fun lower(irFunction: IrFunction): List<IrFunction>? {
|
||||
val visibility = defaultArgumentStubVisibility(irFunction)
|
||||
val newIrFunction =
|
||||
irFunction.generateDefaultsFunction(context, skipInlineMethods, skipExternalMethods, forceSetOverrideSymbols, visibility)
|
||||
?: return null
|
||||
irFunction.generateDefaultsFunction(
|
||||
context,
|
||||
skipInlineMethods,
|
||||
skipExternalMethods,
|
||||
forceSetOverrideSymbols,
|
||||
defaultArgumentStubVisibility(irFunction),
|
||||
useConstructorMarker(irFunction)
|
||||
) ?: return null
|
||||
if (newIrFunction.isFakeOverride) {
|
||||
return listOf(irFunction, newIrFunction)
|
||||
}
|
||||
@@ -185,7 +190,8 @@ open class DefaultArgumentStubGenerator(
|
||||
|
||||
protected open fun IrBlockBodyBuilder.generateSuperCallHandlerCheckIfNeeded(
|
||||
irFunction: IrFunction,
|
||||
newIrFunction: IrFunction) {
|
||||
newIrFunction: IrFunction
|
||||
) {
|
||||
//NO-OP Stub
|
||||
}
|
||||
|
||||
@@ -202,6 +208,8 @@ open class DefaultArgumentStubGenerator(
|
||||
|
||||
protected open fun defaultArgumentStubVisibility(function: IrFunction) = Visibilities.PUBLIC
|
||||
|
||||
protected open fun useConstructorMarker(function: IrFunction) = function is IrConstructor
|
||||
|
||||
private fun log(msg: () -> String) = context.log { "DEFAULT-REPLACER: ${msg()}" }
|
||||
}
|
||||
|
||||
@@ -310,15 +318,20 @@ open class DefaultParameterInjector(
|
||||
val startOffset = expression.startOffset
|
||||
val endOffset = expression.endOffset
|
||||
val declaration = expression.symbol.owner
|
||||
val visibility = defaultArgumentStubVisibility(declaration)
|
||||
|
||||
// We *have* to find the actual function here since on the JVM, a default stub for a function implemented
|
||||
// in an interface does not leave an abstract method after being moved to DefaultImpls (see InterfaceLowering).
|
||||
// Calling the fake override on an implementation of that interface would then result in a call to a method
|
||||
// that does not actually exist as DefaultImpls is not part of the inheritance hierarchy.
|
||||
val stubFunction = declaration.findBaseFunctionWithDefaultArguments(skipInline, skipExternalMethods)
|
||||
?.generateDefaultsFunction(context, skipInline, skipExternalMethods, forceSetOverrideSymbols, visibility)
|
||||
?: return null
|
||||
?.generateDefaultsFunction(
|
||||
context,
|
||||
skipInline,
|
||||
skipExternalMethods,
|
||||
forceSetOverrideSymbols,
|
||||
defaultArgumentStubVisibility(declaration),
|
||||
useConstructorMarker(declaration)
|
||||
) ?: return null
|
||||
|
||||
log { "$declaration -> $stubFunction" }
|
||||
|
||||
@@ -367,6 +380,8 @@ open class DefaultParameterInjector(
|
||||
|
||||
protected open fun defaultArgumentStubVisibility(function: IrFunction) = Visibilities.PUBLIC
|
||||
|
||||
protected open fun useConstructorMarker(function: IrFunction) = function is IrConstructor
|
||||
|
||||
private fun log(msg: () -> String) = context.log { "DEFAULT-INJECTOR: ${msg()}" }
|
||||
}
|
||||
|
||||
@@ -416,7 +431,8 @@ private fun IrFunction.generateDefaultsFunction(
|
||||
skipInlineMethods: Boolean,
|
||||
skipExternalMethods: Boolean,
|
||||
forceSetOverrideSymbols: Boolean,
|
||||
visibility: Visibility
|
||||
visibility: Visibility,
|
||||
useConstructorMarker: Boolean
|
||||
): IrFunction? {
|
||||
if (skipInlineMethods && isInline) return null
|
||||
if (skipExternalMethods && isExternalOrInheritedFromExternal()) return null
|
||||
@@ -425,7 +441,7 @@ private fun IrFunction.generateDefaultsFunction(
|
||||
if (this is IrSimpleFunction) {
|
||||
// If this is an override of a function with default arguments, produce a fake override of a default stub.
|
||||
if (overriddenSymbols.any { it.owner.findBaseFunctionWithDefaultArguments(skipInlineMethods, skipExternalMethods) != null })
|
||||
return generateDefaultsFunctionImpl(context, IrDeclarationOrigin.FAKE_OVERRIDE, visibility, isFakeOverride = true).also {
|
||||
return generateDefaultsFunctionImpl(context, IrDeclarationOrigin.FAKE_OVERRIDE, visibility, true, useConstructorMarker).also {
|
||||
context.mapping.defaultArgumentsDispatchFunction[this] = it
|
||||
context.mapping.defaultArgumentsOriginalFunction[it] = this
|
||||
|
||||
@@ -436,7 +452,8 @@ private fun IrFunction.generateDefaultsFunction(
|
||||
skipInlineMethods,
|
||||
skipExternalMethods,
|
||||
forceSetOverrideSymbols,
|
||||
visibility
|
||||
visibility,
|
||||
useConstructorMarker
|
||||
)?.symbol as IrSimpleFunctionSymbol?
|
||||
}
|
||||
}
|
||||
@@ -454,7 +471,7 @@ private fun IrFunction.generateDefaultsFunction(
|
||||
// binaries, it's way too late to fix it. Hence the workaround.
|
||||
if (valueParameters.any { it.defaultValue != null }) {
|
||||
return generateDefaultsFunctionImpl(
|
||||
context, IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER, visibility, isFakeOverride = false
|
||||
context, IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER, visibility, false, useConstructorMarker
|
||||
).also {
|
||||
context.mapping.defaultArgumentsDispatchFunction[this] = it
|
||||
context.mapping.defaultArgumentsOriginalFunction[it] = this
|
||||
@@ -467,7 +484,8 @@ private fun IrFunction.generateDefaultsFunctionImpl(
|
||||
context: CommonBackendContext,
|
||||
newOrigin: IrDeclarationOrigin,
|
||||
newVisibility: Visibility,
|
||||
isFakeOverride: Boolean
|
||||
isFakeOverride: Boolean,
|
||||
useConstructorMarker: Boolean
|
||||
): IrFunction {
|
||||
val newFunction = when (this) {
|
||||
is IrConstructor ->
|
||||
@@ -515,7 +533,7 @@ private fun IrFunction.generateDefaultsFunctionImpl(
|
||||
for (i in 0 until (valueParameters.size + 31) / 32) {
|
||||
newFunction.addValueParameter("mask$i".synthesizedString, context.irBuiltIns.intType, IrDeclarationOrigin.MASK_FOR_DEFAULT_FUNCTION)
|
||||
}
|
||||
if (this is IrConstructor) {
|
||||
if (useConstructorMarker) {
|
||||
val markerType = context.ir.symbols.defaultConstructorMarker.defaultType.makeNullable()
|
||||
newFunction.addValueParameter("marker".synthesizedString, markerType, IrDeclarationOrigin.DEFAULT_CONSTRUCTOR_MARKER)
|
||||
} else if (context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()) {
|
||||
|
||||
@@ -31,6 +31,7 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin {
|
||||
object SYNTHETIC_INLINE_CLASS_MEMBER : IrDeclarationOriginImpl("SYNTHETIC_INLINE_CLASS_MEMBER", isSynthetic = true)
|
||||
object INLINE_CLASS_GENERATED_IMPL_METHOD : IrDeclarationOriginImpl("INLINE_CLASS_GENERATED_IMPL_METHOD")
|
||||
object STATIC_INLINE_CLASS_REPLACEMENT : IrDeclarationOriginImpl("STATIC_INLINE_CLASS_REPLACEMENT")
|
||||
object STATIC_INLINE_CLASS_CONSTRUCTOR : IrDeclarationOriginImpl("STATIC_INLINE_CLASS_CONSTRUCTOR")
|
||||
object GENERATED_ASSERTION_ENABLED_FIELD : IrDeclarationOriginImpl("GENERATED_ASSERTION_ENABLED_FIELD", isSynthetic = true)
|
||||
object GENERATED_EXTENDED_MAIN : IrDeclarationOriginImpl("GENERATED_EXTENDED_MAIN", isSynthetic = true)
|
||||
object SUSPEND_IMPL_STATIC_FUNCTION : IrDeclarationOriginImpl("SUSPEND_IMPL_STATIC_FUNCTION", isSynthetic = true)
|
||||
|
||||
+3
-2
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.lower.LocalDeclarationsLowering
|
||||
import org.jetbrains.kotlin.backend.common.lower.allOverridden
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isStaticInlineClassReplacement
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.suspendFunctionOriginal
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineTransformerMethodVisitor
|
||||
@@ -119,9 +120,9 @@ private fun IrFunction.isBridgeToSuspendImplMethod(): Boolean =
|
||||
}
|
||||
|
||||
private fun IrFunction.isStaticInlineClassReplacementDelegatingCall(): Boolean =
|
||||
this is IrAttributeContainer && origin != JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT &&
|
||||
this is IrAttributeContainer && !isStaticInlineClassReplacement &&
|
||||
parentAsClass.declarations.find { it is IrAttributeContainer && it.attributeOwnerId == attributeOwnerId && it !== this }
|
||||
?.origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT
|
||||
?.isStaticInlineClassReplacement == true
|
||||
|
||||
internal fun IrFunction.shouldContainSuspendMarkers(): Boolean = !isInvokeSuspendOfContinuation() &&
|
||||
// These are tail-call bridges and do not require any bytecode modifications.
|
||||
|
||||
+6
-2
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.getJvmNameFromAnnotation
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isCompiledToJvmDefault
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isStaticInlineClassReplacement
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.suspendFunctionOriginal
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
@@ -35,7 +36,10 @@ import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.load.java.*
|
||||
import org.jetbrains.kotlin.load.kotlin.*
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
|
||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
||||
import org.jetbrains.kotlin.load.kotlin.forceSingleValueParameterBoxing
|
||||
import org.jetbrains.kotlin.load.kotlin.signatures
|
||||
import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull
|
||||
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
@@ -314,7 +318,7 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
|
||||
// remapped name or signature and forward to the actually declared method.
|
||||
if (caller.origin == IrDeclarationOrigin.BRIDGE || caller.origin == IrDeclarationOrigin.BRIDGE_SPECIAL) return null
|
||||
// Do not remap calls to static replacements of inline class methods, since they have completely different signatures.
|
||||
if (callee.origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT) return null
|
||||
if (callee.isStaticInlineClassReplacement) return null
|
||||
val overriddenSpecialBuiltinFunction = callee.descriptor.original.getOverriddenBuiltinReflectingJvmDescriptor()
|
||||
if (overriddenSpecialBuiltinFunction != null && !superCall) {
|
||||
return mapSignatureSkipGeneric(context.referenceFunction(overriddenSpecialBuiltinFunction.original).owner)
|
||||
|
||||
@@ -343,3 +343,7 @@ fun IrProperty.needsAccessor(accessor: IrSimpleFunction): Boolean = when {
|
||||
// We do not produce default accessors for private fields
|
||||
else -> accessor.origin != IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR || !Visibilities.isPrivate(accessor.visibility)
|
||||
}
|
||||
|
||||
val IrDeclaration.isStaticInlineClassReplacement: Boolean
|
||||
get() = origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT
|
||||
|| origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_CONSTRUCTOR
|
||||
|
||||
+2
-1
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.*
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.defaultValue
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isStaticInlineClassReplacement
|
||||
import org.jetbrains.kotlin.backend.jvm.localDeclarationsPhase
|
||||
import org.jetbrains.kotlin.codegen.coroutines.*
|
||||
import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
|
||||
@@ -640,7 +641,7 @@ private fun IrFunction.suspendFunctionViewOrStub(context: JvmBackendContext): Ir
|
||||
}
|
||||
|
||||
internal fun IrFunction.suspendFunctionOriginal(): IrFunction =
|
||||
if (this is IrSimpleFunction && isSuspend && origin != JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT)
|
||||
if (this is IrSimpleFunction && isSuspend && !isStaticInlineClassReplacement)
|
||||
attributeOwnerId as IrFunction
|
||||
else this
|
||||
|
||||
|
||||
+4
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.common.lower.irIfThen
|
||||
import org.jetbrains.kotlin.backend.common.lower.irNot
|
||||
import org.jetbrains.kotlin.backend.common.lower.irThrow
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.getJvmVisibilityOfDefaultArgumentStub
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -48,6 +49,9 @@ class JvmDefaultArgumentStubGenerator(override val context: JvmBackendContext) :
|
||||
|
||||
override fun defaultArgumentStubVisibility(function: IrFunction) = function.getJvmVisibilityOfDefaultArgumentStub()
|
||||
|
||||
override fun useConstructorMarker(function: IrFunction): Boolean =
|
||||
function is IrConstructor || function.origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_CONSTRUCTOR
|
||||
|
||||
override fun IrBlockBodyBuilder.generateSuperCallHandlerCheckIfNeeded(
|
||||
irFunction: IrFunction,
|
||||
newIrFunction: IrFunction
|
||||
|
||||
+5
@@ -7,8 +7,10 @@ package org.jetbrains.kotlin.backend.jvm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.lower.DefaultParameterInjector
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.defaultValue
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.getJvmVisibilityOfDefaultArgumentStub
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
@@ -27,4 +29,7 @@ class JvmDefaultParameterInjector(context: JvmBackendContext) :
|
||||
}
|
||||
|
||||
override fun defaultArgumentStubVisibility(function: IrFunction) = function.getJvmVisibilityOfDefaultArgumentStub()
|
||||
|
||||
override fun useConstructorMarker(function: IrFunction): Boolean =
|
||||
function is IrConstructor || function.origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_CONSTRUCTOR
|
||||
}
|
||||
|
||||
+14
-5
@@ -10,8 +10,10 @@ import org.jetbrains.kotlin.backend.common.ir.copyTypeParameters
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
|
||||
import org.jetbrains.kotlin.backend.common.ir.createDispatchReceiverParameter
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isStaticInlineClassReplacement
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi.mangledNameFor
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFunWithDescriptorForInlining
|
||||
@@ -45,7 +47,7 @@ class MemoizedInlineClassReplacements(private val mangleReturnTypes: Boolean) {
|
||||
// Don't mangle anonymous or synthetic functions
|
||||
it.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA ||
|
||||
it.origin == IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR ||
|
||||
it.origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT ||
|
||||
it.isStaticInlineClassReplacement ||
|
||||
it.origin.isSynthetic ||
|
||||
it.isInlineClassFieldGetter -> null
|
||||
|
||||
@@ -181,10 +183,17 @@ class MemoizedInlineClassReplacements(private val mangleReturnTypes: Boolean) {
|
||||
body: IrFunctionImpl.() -> Unit
|
||||
) = buildFunWithDescriptorForInlining(function.descriptor) {
|
||||
updateFrom(function)
|
||||
origin = if (function.origin == IrDeclarationOrigin.GENERATED_INLINE_CLASS_MEMBER) {
|
||||
JvmLoweredDeclarationOrigin.INLINE_CLASS_GENERATED_IMPL_METHOD
|
||||
} else {
|
||||
replacementOrigin
|
||||
if (function is IrConstructor) {
|
||||
// The [updateFrom] call will set the modality to FINAL for constructors, while the JVM backend would use OPEN here.
|
||||
modality = Modality.OPEN
|
||||
}
|
||||
origin = when {
|
||||
function.origin == IrDeclarationOrigin.GENERATED_INLINE_CLASS_MEMBER ->
|
||||
JvmLoweredDeclarationOrigin.INLINE_CLASS_GENERATED_IMPL_METHOD
|
||||
function is IrConstructor && function.constructedClass.isInline ->
|
||||
JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_CONSTRUCTOR
|
||||
else ->
|
||||
replacementOrigin
|
||||
}
|
||||
if (noFakeOverride) {
|
||||
isFakeOverride = false
|
||||
|
||||
+3
-6
@@ -1,13 +1,10 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
// This tests both KT-37013 and KT-37015.
|
||||
|
||||
inline class A(val x: Int = 0)
|
||||
|
||||
// 0 <init>\(\)V
|
||||
// 1 private synthetic <init>\(I\)V
|
||||
// 1 public final static synthetic box-impl\(I\)LA;
|
||||
|
||||
// JVM_TEMPLATES
|
||||
// 1 public static constructor-impl\(I\)I
|
||||
// 1 public static synthetic constructor-impl\$default\(IILkotlin/jvm/internal/DefaultConstructorMarker;\)I
|
||||
|
||||
// JVM_IR_TEMPLATES
|
||||
// 1 public final static constructor-impl\(I\)I
|
||||
// 1 public static synthetic constructor-impl\$default\(IILjava/lang/Object;\)I
|
||||
|
||||
Reference in New Issue
Block a user