From 3db3f5bf7fc5861aeef78fe5f0b56947caf7d236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steven=20Sch=C3=A4fer?= Date: Fri, 27 Sep 2019 13:20:15 +0200 Subject: [PATCH] JVM IR: Don't compute signatures in CallableReferenceLowering --- .../kotlin/backend/jvm/JvmSymbols.kt | 10 ++++ .../jvm/codegen/MethodSignatureMapper.kt | 12 ++--- .../jvm/intrinsics/IrIntrinsicMethods.kt | 3 +- .../backend/jvm/intrinsics/SignatureString.kt | 38 ++++++++++++++ .../kotlin/backend/jvm/ir/IrUtils.kt | 5 +- .../jvm/lower/CallableReferenceLowering.kt | 31 ++++-------- ...eDeclarationsThatWouldBeInlinedLowering.kt | 8 +-- .../jvm/lower/SyntheticAccessorLowering.kt | 49 +++++++++++++------ 8 files changed, 108 insertions(+), 48 deletions(-) create mode 100644 compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/SignatureString.kt diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt index e419c0cfa93..e944b1d0b10 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt @@ -427,6 +427,16 @@ class JvmSymbols( } val systemArraycopy: IrSimpleFunctionSymbol = systemClass.functionByName("arraycopy") + + val signatureStringIntrinsic: IrSimpleFunctionSymbol = + buildFun { + name = Name.special("") + origin = IrDeclarationOrigin.IR_BUILTINS_STUB + }.apply { + parent = kotlinJvmInternalPackage + addValueParameter("v", irBuiltIns.anyNType) + returnType = irBuiltIns.stringType + }.symbol } private fun IrClassSymbol.functionByName(name: String): IrSimpleFunctionSymbol = diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt index 12e6f438161..1122c2e4f61 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt @@ -30,8 +30,11 @@ import org.jetbrains.kotlin.ir.expressions.IrConst 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.java.BuiltinMethodsWithSpecialGenericSignature +import org.jetbrains.kotlin.load.java.JvmAbi 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.forceSingleValueParameterBoxing import org.jetbrains.kotlin.load.kotlin.getJvmModuleNameForDeserializedDescriptor @@ -216,13 +219,6 @@ class MethodSignatureMapper(private val context: JvmBackendContext) { 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) { val kind = when (parameter.origin) { JvmLoweredDeclarationOrigin.FIELD_FOR_OUTER_THIS -> JvmMethodParameterKind.OUTER diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt index 52df309f957..42542672376 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt @@ -96,7 +96,8 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) { irBuiltIns.checkNotNullSymbol.toKey()!! to IrCheckNotNull, irBuiltIns.andandSymbol.toKey()!! to AndAnd, irBuiltIns.ororSymbol.toKey()!! to OrOr, - symbols.unsafeCoerceIntrinsic.toKey()!! to UnsafeCoerce + symbols.unsafeCoerceIntrinsic.toKey()!! to UnsafeCoerce, + symbols.signatureStringIntrinsic.toKey()!! to SignatureString ) + numberConversionMethods() + unaryFunForPrimitives("plus", UnaryPlus) + diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/SignatureString.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/SignatureString.kt new file mode 100644 index 00000000000..42c1f046e59 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/SignatureString.kt @@ -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) + } + } + } +} diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt index 91fd0a48516..c2c009687fe 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt @@ -17,7 +17,7 @@ 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.expressions.IrStatementOrigin import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol @@ -99,6 +99,9 @@ fun IrType.getArrayElementType(irBuiltIns: IrBuiltIns): IrType = else irBuiltIns.primitiveArrayElementTypes.getValue(this.classOrNull!!) +val IrStatementOrigin?.isLambda + get() = this == IrStatementOrigin.LAMBDA || this == IrStatementOrigin.ANONYMOUS_FUNCTION + val IrConstructor.shouldBeHidden: Boolean get() = !Visibilities.isPrivate(visibility) && !constructedClass.isInline && hasMangledParameters diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt index c82e2c539e3..555062ca5f1 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt @@ -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.irArray 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.Visibilities 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.expressions.* 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.types.* 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.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, @@ -378,24 +377,14 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext) get() = (metadata as? MetadataSource.Function)?.descriptor?.name ?: name private fun createGetSignatureMethod(superFunction: IrSimpleFunction): IrSimpleFunction = buildOverride(superFunction).apply { - val codegenContext = context - body = context.createIrBuilder(symbol, startOffset, endOffset).run { - // TODO do not use descriptors - val declaration = codegenContext.referenceFunction( - DescriptorUtils.unwrapFakeOverride(irFunctionReference.symbol.descriptor).original - ).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)) + body = context.createJvmIrBuilder(symbol, startOffset, endOffset).run { + irExprBody(irCall(backendContext.ir.symbols.signatureStringIntrinsic).apply { + putValueArgument(0, with(irFunctionReference) { + IrFunctionReferenceImpl( + startOffset, endOffset, type, symbol, descriptor, typeArgumentsCount, valueArgumentsCount, origin + ) + }) + }) } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/RemoveDeclarationsThatWouldBeInlinedLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/RemoveDeclarationsThatWouldBeInlinedLowering.kt index e5fc95b2251..a1b6b300860 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/RemoveDeclarationsThatWouldBeInlinedLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/RemoveDeclarationsThatWouldBeInlinedLowering.kt @@ -8,13 +8,13 @@ package org.jetbrains.kotlin.backend.jvm.lower import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase 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.IrStatement import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.expressions.IrFunctionReference -import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin import org.jetbrains.kotlin.ir.visitors.* internal val removeDeclarationsThatWouldBeInlined = makeIrFilePhase( @@ -36,8 +36,10 @@ private class RemoveDeclarationsThatWouldBeInlinedLowering(val context: JvmBacke override fun visitElement(element: IrElement) = element.acceptChildrenVoid(this) override fun visitFunctionReference(expression: IrFunctionReference) { - assert(expression.origin == IrStatementOrigin.LAMBDA || expression.origin == IrStatementOrigin.ANONYMOUS_FUNCTION) - loweredLambdasToDelete.add(expression.symbol.owner) + if (expression.origin.isLambda) { + loweredLambdasToDelete.add(expression.symbol.owner) + } + expression.acceptChildrenVoid(this) } }) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt index 090e66936fd..115c81f245c 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt @@ -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.JvmLoweredDeclarationOrigin 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.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter 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.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.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.load.java.JavaVisibilities 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) // Unconditionally add bridges for hidden constructors - irFile.acceptChildrenVoid(object: IrElementVisitorVoid { - override fun visitElement(element: IrElement) = element.acceptChildrenVoid(this) + irFile.transformChildrenVoid(object: IrElementTransformerVoid() { + private val hiddenDeclarations = mutableSetOf() - private fun handleConstructor(declaration: IrConstructor) { - if (!declaration.shouldBeHidden) - return + private fun handleConstructor(declaration: IrConstructor): IrConstructorSymbol? { + if (declaration.shouldBeHidden) { + 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 -> // 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 @@ -71,17 +75,34 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle declaration.annotations.clear() declaration.valueParameters.forEach { it.annotations.clear() } }.symbol - } + } as IrConstructorSymbol } - override fun visitConstructor(declaration: IrConstructor) { + override fun visitConstructor(declaration: IrConstructor): IrStatement { handleConstructor(declaration) - super.visitConstructor(declaration) + return super.visitConstructor(declaration) } - override fun visitConstructorCall(expression: IrConstructorCall) { + override fun visitConstructorCall(expression: IrConstructorCall): IrExpression { 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) } })