JVM IR: Hide constructors with inline class parameters
This commit is contained in:
committed by
Alexander Udalov
parent
bdd5705a30
commit
9389d88232
+3
-3
@@ -127,7 +127,7 @@ fun IrFunctionBuilder.buildFun(originalDescriptor: FunctionDescriptor? = null):
|
||||
}
|
||||
}
|
||||
|
||||
fun IrFunctionBuilder.buildConstructor(): IrConstructor {
|
||||
fun IrFunctionBuilder.buildConstructor(): IrConstructorImpl {
|
||||
val wrappedDescriptor = WrappedClassConstructorDescriptor()
|
||||
return IrConstructorImpl(
|
||||
startOffset, endOffset, origin,
|
||||
@@ -179,13 +179,13 @@ fun IrDeclarationContainer.addFunction(
|
||||
}
|
||||
}
|
||||
|
||||
inline fun buildConstructor(builder: IrFunctionBuilder.() -> Unit): IrConstructor =
|
||||
inline fun buildConstructor(builder: IrFunctionBuilder.() -> Unit): IrConstructorImpl =
|
||||
IrFunctionBuilder().run {
|
||||
builder()
|
||||
buildConstructor()
|
||||
}
|
||||
|
||||
inline fun IrClass.addConstructor(builder: IrFunctionBuilder.() -> Unit = {}): IrConstructor =
|
||||
inline fun IrClass.addConstructor(builder: IrFunctionBuilder.() -> Unit = {}): IrConstructorImpl =
|
||||
buildConstructor {
|
||||
builder()
|
||||
returnType = defaultType
|
||||
|
||||
-36
@@ -188,18 +188,6 @@ private fun IrDeclarationWithVisibility.specialCaseVisibility(kind: OwnerKind?):
|
||||
return Opcodes.ACC_PRIVATE
|
||||
}
|
||||
|
||||
// if (kind !== OwnerKind.ERASED_INLINE_CLASS &&
|
||||
// memberDescriptor is ConstructorDescriptor &&
|
||||
// memberDescriptor !is AccessorForConstructorDescriptor &&
|
||||
// shouldHideConstructorDueToInlineClassTypeValueParameters(memberDescriptor)
|
||||
// ) {
|
||||
if (kind !== OwnerKind.ERASED_INLINE_CLASS &&
|
||||
this is IrConstructor &&
|
||||
shouldHideDueToInlineClassTypeValueParameters()
|
||||
) {
|
||||
return Opcodes.ACC_PRIVATE
|
||||
}
|
||||
|
||||
// if (memberDescriptor.isEffectivelyInlineOnly()) {
|
||||
if (isEffectivelyInlineOnly()) {
|
||||
return Opcodes.ACC_PRIVATE
|
||||
@@ -286,30 +274,6 @@ private fun IrDeclarationWithVisibility.specialCaseVisibility(kind: OwnerKind?):
|
||||
return null
|
||||
}
|
||||
|
||||
/* From inlineClassManglingRules.kt */
|
||||
fun IrConstructor.shouldHideDueToInlineClassTypeValueParameters() =
|
||||
!Visibilities.isPrivate(visibility) &&
|
||||
!parentAsClass.isInline &&
|
||||
parentAsClass.modality !== Modality.SEALED &&
|
||||
valueParameters.any { it.type.requiresFunctionNameMangling() }
|
||||
|
||||
fun IrType.requiresFunctionNameMangling(): Boolean =
|
||||
isInlineClassThatRequiresMangling() || isTypeParameterWithUpperBoundThatRequiresMangling()
|
||||
|
||||
fun IrType.isInlineClassThatRequiresMangling() =
|
||||
safeAs<IrSimpleType>()?.classifier?.owner?.safeAs<IrClass>()?.let {
|
||||
it.isInline && !it.isDontMangleClass()
|
||||
} ?: false
|
||||
|
||||
fun IrClass.isDontMangleClass() =
|
||||
fqNameWhenAvailable != DescriptorUtils.RESULT_FQ_NAME
|
||||
|
||||
fun IrType.isTypeParameterWithUpperBoundThatRequiresMangling() =
|
||||
safeAs<IrSimpleType>()?.classifier?.owner.safeAs<IrTypeParameter>()?.let { param ->
|
||||
param.superTypes.any { it.requiresFunctionNameMangling() }
|
||||
} ?: false
|
||||
|
||||
|
||||
/* Borrowed from InlineUtil. */
|
||||
private tailrec fun isInlineOrContainedInInline(declaration: IrDeclaration?): Boolean = when {
|
||||
declaration === null -> false
|
||||
|
||||
@@ -9,12 +9,15 @@ import org.jetbrains.kotlin.backend.common.lower.IrLoweringContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmSymbols
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.hasMangledParameters
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
||||
import org.jetbrains.kotlin.ir.builders.Scope
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
@@ -96,6 +99,9 @@ fun IrType.getArrayElementType(irBuiltIns: IrBuiltIns): IrType =
|
||||
else
|
||||
irBuiltIns.primitiveArrayElementTypes.getValue(this.classOrNull!!)
|
||||
|
||||
val IrConstructor.shouldBeHidden: Boolean
|
||||
get() = !Visibilities.isPrivate(visibility) && !constructedClass.isInline && hasMangledParameters
|
||||
|
||||
// An IR builder with a reference to the JvmBackendContext
|
||||
class JvmIrBuilder(
|
||||
val backendContext: JvmBackendContext,
|
||||
|
||||
+13
-1
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.irArray
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isInlineParameter
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.shouldBeHidden
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
@@ -40,6 +41,7 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
|
||||
internal val callableReferencePhase = makeIrFilePhase(
|
||||
::CallableReferenceLowering,
|
||||
@@ -383,7 +385,17 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext)
|
||||
DescriptorUtils.unwrapFakeOverride(irFunctionReference.symbol.descriptor).original
|
||||
).owner
|
||||
val method = codegenContext.methodSignatureMapper.mapAsmMethod(declaration)
|
||||
irExprBody(irString(method.name + method.descriptor))
|
||||
// HACK: When referencing a constructor taking inline class parameters, we will actually
|
||||
// end up calling a public bridge method with an additional argument.
|
||||
// TODO: Don't compute signatures in CallableReferenceLowering
|
||||
val descriptor = if (declaration is IrConstructor && declaration.shouldBeHidden) {
|
||||
val marker =
|
||||
codegenContext.typeMapper.mapType(codegenContext.ir.symbols.defaultConstructorMarker.owner.defaultType)
|
||||
Type.getMethodDescriptor(method.returnType, *method.argumentTypes, marker)
|
||||
} else {
|
||||
method.descriptor
|
||||
}
|
||||
irExprBody(irString(method.name + descriptor))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+44
-2
@@ -11,10 +11,10 @@ import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyValueParametersToStatic
|
||||
import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
|
||||
import org.jetbrains.kotlin.backend.common.ir.remapTypeParameters
|
||||
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.intrinsics.receiverAndArgs
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.shouldBeHidden
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
@@ -32,10 +33,13 @@ import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.types.isSubtypeOfClass
|
||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.load.java.JavaVisibilities
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass {
|
||||
private val pendingTransformations = mutableListOf<Function0<Unit>>()
|
||||
@@ -43,6 +47,44 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
inlineLambdaToCallSite.putAll(InlineReferenceLocator.scan(context, irFile).lambdaToCallSite)
|
||||
|
||||
// Unconditionally add bridges for hidden constructors
|
||||
irFile.acceptChildrenVoid(object: IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) = element.acceptChildrenVoid(this)
|
||||
|
||||
private fun handleConstructor(declaration: IrConstructor) {
|
||||
if (!declaration.shouldBeHidden)
|
||||
return
|
||||
|
||||
declaration.visibility = Visibilities.PRIVATE
|
||||
|
||||
functionMap.computeIfAbsent(declaration.symbol) {
|
||||
declaration.makeConstructorAccessor().also { accessor ->
|
||||
// There's a special case in the JVM backend for serializing the metadata of hidden
|
||||
// constructors - we serialize the descriptor of the original constructor, but the
|
||||
// signature of the bridge. We implement this special case in the JVM IR backend by
|
||||
// attaching the metadata directly to the bridge. We also have to move all annotations
|
||||
// to the bridge method. Parameter annotations are already moved by the copyTo method.
|
||||
accessor.metadata = declaration.metadata
|
||||
declaration.safeAs<IrConstructorImpl>()?.metadata = null
|
||||
accessor.annotations += declaration.annotations
|
||||
declaration.annotations.clear()
|
||||
declaration.valueParameters.forEach { it.annotations.clear() }
|
||||
}.symbol
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitConstructor(declaration: IrConstructor) {
|
||||
handleConstructor(declaration)
|
||||
super.visitConstructor(declaration)
|
||||
}
|
||||
|
||||
override fun visitConstructorCall(expression: IrConstructorCall) {
|
||||
handleConstructor(expression.symbol.owner)
|
||||
super.visitConstructorCall(expression)
|
||||
}
|
||||
})
|
||||
|
||||
irFile.transformChildrenVoid(this)
|
||||
pendingTransformations.forEach { it() }
|
||||
}
|
||||
@@ -108,7 +150,7 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
|
||||
classes.lastOrNull { parent is IrClass && it.isSubclassOf(parent) } ?: classes.last()
|
||||
} else parent
|
||||
|
||||
private fun IrConstructor.makeConstructorAccessor(): IrConstructor {
|
||||
private fun IrConstructor.makeConstructorAccessor(): IrConstructorImpl {
|
||||
val source = this
|
||||
|
||||
return buildConstructor {
|
||||
|
||||
+7
-2
@@ -91,15 +91,20 @@ object InlineClassAbi {
|
||||
}
|
||||
}
|
||||
|
||||
internal val IrType.requiresMangling: Boolean
|
||||
private val IrType.requiresMangling: Boolean
|
||||
get() {
|
||||
val irClass = erasedUpperBound
|
||||
return irClass.isInline && irClass.fqNameWhenAvailable != DescriptorUtils.RESULT_FQ_NAME
|
||||
}
|
||||
|
||||
internal val IrFunction.fullValueParameterList: List<IrValueParameter>
|
||||
private val IrFunction.fullValueParameterList: List<IrValueParameter>
|
||||
get() = listOfNotNull(extensionReceiverParameter) + valueParameters
|
||||
|
||||
internal val IrFunction.hasMangledParameters: Boolean
|
||||
get() = dispatchReceiverParameter?.type?.getClass()?.isInline == true ||
|
||||
fullValueParameterList.any { it.type.requiresMangling } ||
|
||||
(this is IrConstructor && constructedClass.isInline)
|
||||
|
||||
internal val IrClass.inlineClassFieldName: Name
|
||||
get() = primaryConstructor!!.valueParameters.single().name
|
||||
|
||||
|
||||
-6
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.getClass
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
|
||||
import org.jetbrains.kotlin.ir.util.constructedClass
|
||||
@@ -57,11 +56,6 @@ class MemoizedInlineClassReplacements {
|
||||
}
|
||||
}
|
||||
|
||||
private val IrFunction.hasMangledParameters: Boolean
|
||||
get() = dispatchReceiverParameter?.type?.getClass()?.isInline == true ||
|
||||
fullValueParameterList.any { it.type.requiresMangling } ||
|
||||
(this is IrConstructor && constructedClass.isInline)
|
||||
|
||||
private val IrFunction.hasStaticReplacement: Boolean
|
||||
get() = origin != IrDeclarationOrigin.FAKE_OVERRIDE &&
|
||||
(this is IrSimpleFunction || this is IrConstructor && constructedClass.isInline)
|
||||
|
||||
@@ -17,12 +17,15 @@
|
||||
package org.jetbrains.kotlin.ir.declarations
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
|
||||
|
||||
interface IrConstructor : IrFunction, IrSymbolDeclaration<IrConstructorSymbol> {
|
||||
override val descriptor: ClassConstructorDescriptor
|
||||
|
||||
override var visibility: Visibility
|
||||
|
||||
val isPrimary: Boolean
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ abstract class IrFunctionBase(
|
||||
endOffset: Int,
|
||||
origin: IrDeclarationOrigin,
|
||||
override val name: Name,
|
||||
override val visibility: Visibility,
|
||||
override var visibility: Visibility,
|
||||
override val isInline: Boolean,
|
||||
override val isExternal: Boolean,
|
||||
returnType: IrType
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ abstract class IrLazyFunctionBase(
|
||||
endOffset: Int,
|
||||
origin: IrDeclarationOrigin,
|
||||
override val name: Name,
|
||||
override val visibility: Visibility,
|
||||
override var visibility: Visibility,
|
||||
override val isInline: Boolean,
|
||||
override val isExternal: Boolean,
|
||||
stubGenerator: DeclarationStubGenerator,
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR, JS, NATIVE
|
||||
// WITH_REFLECT
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_REFLECT
|
||||
import kotlin.reflect.full.primaryConstructor
|
||||
|
||||
Reference in New Issue
Block a user