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 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 =
@@ -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
@@ -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) +
@@ -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.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
@@ -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
)
})
})
}
}
@@ -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)
}
})
@@ -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<IrConstructor>()
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)
}
})