JVM_IR: implement -Xpolymorphic-signature
This commit is contained in:
@@ -48,4 +48,5 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin {
|
|||||||
object SUSPEND_FUNCTION_VIEW : IrDeclarationOriginImpl("SUSPEND_FUNCTION_VIEW")
|
object SUSPEND_FUNCTION_VIEW : IrDeclarationOriginImpl("SUSPEND_FUNCTION_VIEW")
|
||||||
object SUSPEND_IMPL_STATIC_FUNCTION : IrDeclarationOriginImpl("SUSPEND_IMPL_STATIC_FUNCTION", isSynthetic = true)
|
object SUSPEND_IMPL_STATIC_FUNCTION : IrDeclarationOriginImpl("SUSPEND_IMPL_STATIC_FUNCTION", isSynthetic = true)
|
||||||
object INTERFACE_COMPANION_PRIVATE_INSTANCE : IrDeclarationOriginImpl("INTERFACE_COMPANION_PRIVATE_INSTANCE", isSynthetic = true)
|
object INTERFACE_COMPANION_PRIVATE_INSTANCE : IrDeclarationOriginImpl("INTERFACE_COMPANION_PRIVATE_INSTANCE", isSynthetic = true)
|
||||||
|
object POLYMORPHIC_SIGNATURE_INSTANTIATION : IrDeclarationOriginImpl("POLYMORPHIC_SIGNATURE_INSTANTIATION", isSynthetic = true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -231,6 +231,7 @@ private val jvmFilePhases =
|
|||||||
inventNamesForLocalClassesPhase then
|
inventNamesForLocalClassesPhase then
|
||||||
kCallableNamePropertyPhase then
|
kCallableNamePropertyPhase then
|
||||||
annotationPhase then
|
annotationPhase then
|
||||||
|
polymorphicSignaturePhase then
|
||||||
varargPhase then
|
varargPhase then
|
||||||
arrayConstructorPhase then
|
arrayConstructorPhase then
|
||||||
checkNotNullPhase then
|
checkNotNullPhase then
|
||||||
|
|||||||
+90
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* 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.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
|
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
|
||||||
|
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.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
|
import org.jetbrains.kotlin.ir.types.isNullableAny
|
||||||
|
import org.jetbrains.kotlin.ir.util.dump
|
||||||
|
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
|
internal val polymorphicSignaturePhase = makeIrFilePhase(
|
||||||
|
::PolymorphicSignatureLowering,
|
||||||
|
name = "PolymorphicSignature",
|
||||||
|
description = "Replace polymorphic methods with fake ones according to types at the call site"
|
||||||
|
)
|
||||||
|
|
||||||
|
private val polymorphicSignatureAnnotation = FqName("java.lang.invoke.MethodHandle.PolymorphicSignature")
|
||||||
|
|
||||||
|
class PolymorphicSignatureLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
|
||||||
|
override fun lower(irFile: IrFile) {
|
||||||
|
if (context.state.languageVersionSettings.supportsFeature(LanguageFeature.PolymorphicSignature))
|
||||||
|
irFile.transformChildrenVoid()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrTypeOperatorCall.isCast(): Boolean =
|
||||||
|
operator != IrTypeOperator.INSTANCEOF && operator != IrTypeOperator.NOT_INSTANCEOF
|
||||||
|
|
||||||
|
// If the return type is Any?, then it is also polymorphic (e.g. MethodHandle.invokeExact
|
||||||
|
// has polymorphic return type, while VarHandle.compareAndSet does not).
|
||||||
|
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression =
|
||||||
|
(expression.argument as? IrCall)?.takeIf { expression.isCast() && it.type.isNullableAny() }?.transform(expression.typeOperand)
|
||||||
|
?: super.visitTypeOperator(expression)
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression =
|
||||||
|
expression.transform(null) ?: super.visitCall(expression)
|
||||||
|
|
||||||
|
private fun IrCall.transform(castReturnType: IrType?): IrCall? {
|
||||||
|
val function = symbol.owner as? IrSimpleFunction ?: return null
|
||||||
|
if (!function.hasAnnotation(polymorphicSignatureAnnotation))
|
||||||
|
return null
|
||||||
|
assert(function.valueParameters.singleOrNull()?.varargElementType != null) {
|
||||||
|
"@PolymorphicSignature methods should only have a single vararg argument: ${dump()}"
|
||||||
|
}
|
||||||
|
|
||||||
|
val values = (getValueArgument(0) as IrVararg?)?.elements?.map {
|
||||||
|
when (it) {
|
||||||
|
is IrExpression -> it
|
||||||
|
is IrSpreadElement -> it.expression // `*xs` acts as `xs` (for compatibility?)
|
||||||
|
else -> throw AssertionError("unknown IrVarargElement: $it")
|
||||||
|
}
|
||||||
|
} ?: listOf()
|
||||||
|
val fakeFunction = buildFun {
|
||||||
|
updateFrom(function)
|
||||||
|
name = function.name
|
||||||
|
origin = JvmLoweredDeclarationOrigin.POLYMORPHIC_SIGNATURE_INSTANTIATION
|
||||||
|
returnType = castReturnType ?: function.returnType
|
||||||
|
}.apply {
|
||||||
|
parent = function.parent
|
||||||
|
copyTypeParametersFrom(function)
|
||||||
|
dispatchReceiverParameter = function.dispatchReceiverParameter
|
||||||
|
extensionReceiverParameter = function.extensionReceiverParameter
|
||||||
|
for ((i, value) in values.withIndex()) {
|
||||||
|
addValueParameter("\$$i", value.type, JvmLoweredDeclarationOrigin.POLYMORPHIC_SIGNATURE_INSTANTIATION)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return IrCallImpl(startOffset, endOffset, fakeFunction.returnType, fakeFunction.symbol, origin, superQualifierSymbol).apply {
|
||||||
|
copyTypeArgumentsFrom(this@transform)
|
||||||
|
dispatchReceiver = this@transform.dispatchReceiver
|
||||||
|
extensionReceiver = this@transform.extensionReceiver
|
||||||
|
values.forEachIndexed(::putValueArgument)
|
||||||
|
transformChildrenVoid()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -29,7 +29,8 @@ import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
|||||||
val varargPhase = makeIrFilePhase(
|
val varargPhase = makeIrFilePhase(
|
||||||
::VarargLowering,
|
::VarargLowering,
|
||||||
name = "VarargLowering",
|
name = "VarargLowering",
|
||||||
description = "Replace varargs with array arguments and lower arrayOf calls"
|
description = "Replace varargs with array arguments and lower arrayOf calls",
|
||||||
|
prerequisite = setOf(polymorphicSignaturePhase)
|
||||||
)
|
)
|
||||||
|
|
||||||
private class VarargLowering(val context: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoidWithContext() {
|
private class VarargLowering(val context: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoidWithContext() {
|
||||||
|
|||||||
+2
-1
@@ -50,7 +50,8 @@ class MemoizedInlineClassReplacements {
|
|||||||
!it.hasMangledParameters ||
|
!it.hasMangledParameters ||
|
||||||
it.isSyntheticInlineClassMember ||
|
it.isSyntheticInlineClassMember ||
|
||||||
it.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA ||
|
it.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA ||
|
||||||
it.origin == IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR -> null
|
it.origin == IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR ||
|
||||||
|
it.origin == JvmLoweredDeclarationOrigin.POLYMORPHIC_SIGNATURE_INSTANTIATION -> null
|
||||||
it.hasMethodReplacement -> createMethodReplacement(it)
|
it.hasMethodReplacement -> createMethodReplacement(it)
|
||||||
it.hasStaticReplacement -> createStaticReplacement(it)
|
it.hasStaticReplacement -> createStaticReplacement(it)
|
||||||
else -> null
|
else -> null
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// !LANGUAGE: +PolymorphicSignature
|
// !LANGUAGE: +PolymorphicSignature
|
||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// FULL_JDK
|
// FULL_JDK
|
||||||
// SKIP_JDK6
|
// SKIP_JDK6
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// !LANGUAGE: +PolymorphicSignature
|
// !LANGUAGE: +PolymorphicSignature
|
||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// FULL_JDK
|
// FULL_JDK
|
||||||
// SKIP_JDK6
|
// SKIP_JDK6
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// !LANGUAGE: +PolymorphicSignature
|
// !LANGUAGE: +PolymorphicSignature
|
||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// FULL_JDK
|
// FULL_JDK
|
||||||
// SKIP_JDK6
|
// SKIP_JDK6
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
@@ -11,6 +10,11 @@ import java.lang.invoke.MethodType
|
|||||||
|
|
||||||
class C {
|
class C {
|
||||||
fun foo(s: String, d: Double, x: Int): String = "$s$d$x"
|
fun foo(s: String, d: Double, x: Int): String = "$s$d$x"
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun bar(): Any = "OK"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
@@ -19,5 +23,9 @@ fun box(): String {
|
|||||||
MethodType.methodType(String::class.java, String::class.java, Double::class.java, Int::class.java)
|
MethodType.methodType(String::class.java, String::class.java, Double::class.java, Int::class.java)
|
||||||
)
|
)
|
||||||
val result: String = mh.invokeExact(C(), "Hello", 0.01, 42) as String
|
val result: String = mh.invokeExact(C(), "Hello", 0.01, 42) as String
|
||||||
return if (result == "Hello0.0142") "OK" else "Fail: $result"
|
if (result != "Hello0.0142") return "Fail 1: $result"
|
||||||
|
|
||||||
|
val mh2 = MethodHandles.lookup().findStatic(C::class.java, "bar", MethodType.methodType(Object::class.java))
|
||||||
|
val result2 = mh2.invokeExact() is String
|
||||||
|
return if (result2) "OK" else "Fail 2"
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -1,7 +1,6 @@
|
|||||||
// !LANGUAGE: +PolymorphicSignature
|
// !LANGUAGE: +PolymorphicSignature
|
||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// FULL_JDK
|
// FULL_JDK
|
||||||
// SKIP_JDK6
|
// SKIP_JDK6
|
||||||
// WITH_REFLECT
|
// WITH_REFLECT
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// !LANGUAGE: +PolymorphicSignature
|
// !LANGUAGE: +PolymorphicSignature
|
||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// FULL_JDK
|
// FULL_JDK
|
||||||
// SKIP_JDK6
|
// SKIP_JDK6
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|||||||
Reference in New Issue
Block a user