JVM IR: Don't compute signatures in CallableReferenceLowering

This commit is contained in:
Steven Schäfer
2019-09-27 13:20:15 +02:00
committed by Alexander Udalov
parent 417c570243
commit 3db3f5bf7f
8 changed files with 108 additions and 48 deletions
@@ -427,6 +427,16 @@ class JvmSymbols(
} }
val systemArraycopy: IrSimpleFunctionSymbol = systemClass.functionByName("arraycopy") val systemArraycopy: IrSimpleFunctionSymbol = systemClass.functionByName("arraycopy")
val signatureStringIntrinsic: IrSimpleFunctionSymbol =
buildFun {
name = Name.special("<signature-string>")
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
}.apply {
parent = kotlinJvmInternalPackage
addValueParameter("v", irBuiltIns.anyNType)
returnType = irBuiltIns.stringType
}.symbol
} }
private fun IrClassSymbol.functionByName(name: String): IrSimpleFunctionSymbol = private fun IrClassSymbol.functionByName(name: String): IrSimpleFunctionSymbol =
@@ -30,8 +30,11 @@ import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.load.java.* import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.load.java.getJvmMethodNameIfSpecial
import org.jetbrains.kotlin.load.java.getOverriddenBuiltinReflectingJvmDescriptor
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.load.kotlin.forceSingleValueParameterBoxing import org.jetbrains.kotlin.load.kotlin.forceSingleValueParameterBoxing
import org.jetbrains.kotlin.load.kotlin.getJvmModuleNameForDeserializedDescriptor import org.jetbrains.kotlin.load.kotlin.getJvmModuleNameForDeserializedDescriptor
@@ -216,13 +219,6 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
writeParameter(sw, JvmMethodParameterKind.RECEIVER, receiverParameter.type, function) writeParameter(sw, JvmMethodParameterKind.RECEIVER, receiverParameter.type, function)
} }
// This is needed because mapSignature is currently invoked in CallableReferenceLowering before InnerClassesLowering where
// this parameter is transformed to a normal value parameter.
// TODO: do not call mapSignature in CallableReferenceLowering
if (function is IrConstructor && function.dispatchReceiverParameter != null) {
writeParameter(sw, JvmMethodParameterKind.VALUE, function.dispatchReceiverParameter!!.type, function)
}
for (parameter in function.valueParameters) { for (parameter in function.valueParameters) {
val kind = when (parameter.origin) { val kind = when (parameter.origin) {
JvmLoweredDeclarationOrigin.FIELD_FOR_OUTER_THIS -> JvmMethodParameterKind.OUTER JvmLoweredDeclarationOrigin.FIELD_FOR_OUTER_THIS -> JvmMethodParameterKind.OUTER
@@ -96,7 +96,8 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
irBuiltIns.checkNotNullSymbol.toKey()!! to IrCheckNotNull, irBuiltIns.checkNotNullSymbol.toKey()!! to IrCheckNotNull,
irBuiltIns.andandSymbol.toKey()!! to AndAnd, irBuiltIns.andandSymbol.toKey()!! to AndAnd,
irBuiltIns.ororSymbol.toKey()!! to OrOr, irBuiltIns.ororSymbol.toKey()!! to OrOr,
symbols.unsafeCoerceIntrinsic.toKey()!! to UnsafeCoerce symbols.unsafeCoerceIntrinsic.toKey()!! to UnsafeCoerce,
symbols.signatureStringIntrinsic.toKey()!! to SignatureString
) + ) +
numberConversionMethods() + numberConversionMethods() +
unaryFunForPrimitives("plus", UnaryPlus) + unaryFunForPrimitives("plus", UnaryPlus) +
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.jvm.intrinsics
import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo
import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen
import org.jetbrains.kotlin.backend.jvm.codegen.PromisedValue
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
/**
* Computes the JVM signature of a given IrFunction. The function is passed as an IrFunctionReference
* to the single argument of the intrinsic.
*/
object SignatureString : IntrinsicMethod() {
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? {
val function = (expression.getValueArgument(0) as IrFunctionReference).symbol.owner
// TODO do not use descriptors
val declaration = codegen.context.referenceFunction(
DescriptorUtils.unwrapFakeOverride(function.descriptor).original
).owner
val method = codegen.context.methodSignatureMapper.mapAsmMethod(declaration)
val descriptor = method.name + method.descriptor
return object : PromisedValue(codegen, AsmTypes.JAVA_STRING_TYPE, codegen.context.irBuiltIns.stringType) {
override fun materialize() {
codegen.mv.aconst(descriptor)
}
}
}
}
@@ -17,7 +17,7 @@ import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
import org.jetbrains.kotlin.ir.builders.Scope import org.jetbrains.kotlin.ir.builders.Scope
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
@@ -99,6 +99,9 @@ fun IrType.getArrayElementType(irBuiltIns: IrBuiltIns): IrType =
else else
irBuiltIns.primitiveArrayElementTypes.getValue(this.classOrNull!!) irBuiltIns.primitiveArrayElementTypes.getValue(this.classOrNull!!)
val IrStatementOrigin?.isLambda
get() = this == IrStatementOrigin.LAMBDA || this == IrStatementOrigin.ANONYMOUS_FUNCTION
val IrConstructor.shouldBeHidden: Boolean val IrConstructor.shouldBeHidden: Boolean
get() = !Visibilities.isPrivate(visibility) && !constructedClass.isInline && hasMangledParameters get() = !Visibilities.isPrivate(visibility) && !constructedClass.isInline && hasMangledParameters
@@ -19,7 +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.createJvmIrBuilder
import org.jetbrains.kotlin.backend.jvm.ir.irArray import org.jetbrains.kotlin.backend.jvm.ir.irArray
import org.jetbrains.kotlin.backend.jvm.ir.isInlineParameter import org.jetbrains.kotlin.backend.jvm.ir.isInlineParameter
import org.jetbrains.kotlin.backend.jvm.ir.shouldBeHidden import org.jetbrains.kotlin.backend.jvm.ir.isLambda
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.ir.builders.declarations.buildClass
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
@@ -40,8 +41,6 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.org.objectweb.asm.Type
internal val callableReferencePhase = makeIrFilePhase( internal val callableReferencePhase = makeIrFilePhase(
::CallableReferenceLowering, ::CallableReferenceLowering,
@@ -378,24 +377,14 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext)
get() = (metadata as? MetadataSource.Function)?.descriptor?.name ?: name get() = (metadata as? MetadataSource.Function)?.descriptor?.name ?: name
private fun createGetSignatureMethod(superFunction: IrSimpleFunction): IrSimpleFunction = buildOverride(superFunction).apply { private fun createGetSignatureMethod(superFunction: IrSimpleFunction): IrSimpleFunction = buildOverride(superFunction).apply {
val codegenContext = context body = context.createJvmIrBuilder(symbol, startOffset, endOffset).run {
body = context.createIrBuilder(symbol, startOffset, endOffset).run { irExprBody(irCall(backendContext.ir.symbols.signatureStringIntrinsic).apply {
// TODO do not use descriptors putValueArgument(0, with(irFunctionReference) {
val declaration = codegenContext.referenceFunction( IrFunctionReferenceImpl(
DescriptorUtils.unwrapFakeOverride(irFunctionReference.symbol.descriptor).original startOffset, endOffset, type, symbol, descriptor, typeArgumentsCount, valueArgumentsCount, origin
).owner )
val method = codegenContext.methodSignatureMapper.mapAsmMethod(declaration) })
// 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))
} }
} }
@@ -8,13 +8,13 @@ package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass
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.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.isLambda
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.ir.visitors.*
internal val removeDeclarationsThatWouldBeInlined = makeIrFilePhase( internal val removeDeclarationsThatWouldBeInlined = makeIrFilePhase(
@@ -36,8 +36,10 @@ private class RemoveDeclarationsThatWouldBeInlinedLowering(val context: JvmBacke
override fun visitElement(element: IrElement) = element.acceptChildrenVoid(this) override fun visitElement(element: IrElement) = element.acceptChildrenVoid(this)
override fun visitFunctionReference(expression: IrFunctionReference) { override fun visitFunctionReference(expression: IrFunctionReference) {
assert(expression.origin == IrStatementOrigin.LAMBDA || expression.origin == IrStatementOrigin.ANONYMOUS_FUNCTION) if (expression.origin.isLambda) {
loweredLambdasToDelete.add(expression.symbol.owner) loweredLambdasToDelete.add(expression.symbol.owner)
}
expression.acceptChildrenVoid(this) expression.acceptChildrenVoid(this)
} }
}) })
@@ -14,11 +14,13 @@ import org.jetbrains.kotlin.backend.common.ir.remapTypeParameters
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.intrinsics.receiverAndArgs import org.jetbrains.kotlin.backend.jvm.intrinsics.receiverAndArgs
import org.jetbrains.kotlin.backend.jvm.ir.isLambda
import org.jetbrains.kotlin.backend.jvm.ir.shouldBeHidden import org.jetbrains.kotlin.backend.jvm.ir.shouldBeHidden
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
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.declarations.addValueParameter import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
@@ -33,8 +35,7 @@ import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.isSubtypeOfClass import org.jetbrains.kotlin.ir.types.isSubtypeOfClass
import org.jetbrains.kotlin.ir.types.makeNullable import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.load.java.JavaVisibilities import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
@@ -49,16 +50,19 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
inlineLambdaToCallSite.putAll(InlineReferenceLocator.scan(context, irFile).lambdaToCallSite) inlineLambdaToCallSite.putAll(InlineReferenceLocator.scan(context, irFile).lambdaToCallSite)
// Unconditionally add bridges for hidden constructors // Unconditionally add bridges for hidden constructors
irFile.acceptChildrenVoid(object: IrElementVisitorVoid { irFile.transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitElement(element: IrElement) = element.acceptChildrenVoid(this) private val hiddenDeclarations = mutableSetOf<IrConstructor>()
private fun handleConstructor(declaration: IrConstructor) { private fun handleConstructor(declaration: IrConstructor): IrConstructorSymbol? {
if (!declaration.shouldBeHidden) if (declaration.shouldBeHidden) {
return declaration.visibility = Visibilities.PRIVATE
hiddenDeclarations += declaration
}
declaration.visibility = Visibilities.PRIVATE if (declaration !in hiddenDeclarations)
return null
functionMap.computeIfAbsent(declaration.symbol) { return functionMap.getOrPut(declaration.symbol) {
declaration.makeConstructorAccessor().also { accessor -> declaration.makeConstructorAccessor().also { accessor ->
// There's a special case in the JVM backend for serializing the metadata of hidden // 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 // constructors - we serialize the descriptor of the original constructor, but the
@@ -71,17 +75,34 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
declaration.annotations.clear() declaration.annotations.clear()
declaration.valueParameters.forEach { it.annotations.clear() } declaration.valueParameters.forEach { it.annotations.clear() }
}.symbol }.symbol
} } as IrConstructorSymbol
} }
override fun visitConstructor(declaration: IrConstructor) { override fun visitConstructor(declaration: IrConstructor): IrStatement {
handleConstructor(declaration) handleConstructor(declaration)
super.visitConstructor(declaration) return super.visitConstructor(declaration)
} }
override fun visitConstructorCall(expression: IrConstructorCall) { override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
handleConstructor(expression.symbol.owner) handleConstructor(expression.symbol.owner)
super.visitConstructorCall(expression) return super.visitConstructorCall(expression)
}
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
val function = expression.symbol.owner
if (!expression.origin.isLambda && function is IrConstructor) {
handleConstructor(function)?.let { accessor ->
expression.transformChildrenVoid()
return IrFunctionReferenceImpl(
expression.startOffset, expression.endOffset, expression.type,
accessor, accessor.descriptor, accessor.owner.typeParameters.size,
accessor.owner.valueParameters.size, expression.origin
)
}
}
return super.visitFunctionReference(expression)
} }
}) })