Support calling methods annotated with PolymorphicSignature
#KT-14416 Fixed #KT-26165 Fixed
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
// !LANGUAGE: +PolymorphicSignature
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// FULL_JDK
|
||||
// SKIP_JDK6
|
||||
// WITH_RUNTIME
|
||||
|
||||
import java.lang.invoke.MethodHandles
|
||||
import java.lang.invoke.MethodType
|
||||
import java.lang.invoke.WrongMethodTypeException
|
||||
|
||||
interface I {
|
||||
fun get(): String
|
||||
}
|
||||
|
||||
class C {
|
||||
fun run(i: I): String = i.get()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val mh = MethodHandles.lookup().findVirtual(
|
||||
C::class.java, "run",
|
||||
MethodType.methodType(String::class.java, I::class.java)
|
||||
)
|
||||
|
||||
try {
|
||||
return mh.invokeExact(C(), object : I {
|
||||
override fun get(): String = "Fail"
|
||||
}) as String
|
||||
} catch (e: WrongMethodTypeException) {
|
||||
// OK
|
||||
}
|
||||
|
||||
return mh.invoke(C(), object : I {
|
||||
override fun get(): String = "OK"
|
||||
}) as String
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// !LANGUAGE: +PolymorphicSignature
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// FULL_JDK
|
||||
// SKIP_JDK6
|
||||
// WITH_RUNTIME
|
||||
|
||||
import java.lang.invoke.MethodHandles
|
||||
import java.lang.invoke.MethodType
|
||||
|
||||
open class Base
|
||||
class Derived : Base() {
|
||||
override fun toString() = "!"
|
||||
}
|
||||
|
||||
class C {
|
||||
fun foo(s: String, d: Double?, x: Base): String = "$s$d$x"
|
||||
}
|
||||
|
||||
@Target(AnnotationTarget.EXPRESSION)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class IrrelevantAnnotation
|
||||
|
||||
fun box(): String {
|
||||
val mh = MethodHandles.lookup().findVirtual(
|
||||
C::class.java, "foo",
|
||||
MethodType.methodType(String::class.java, String::class.java, Double::class.javaObjectType, Base::class.java)
|
||||
)
|
||||
|
||||
val result1: String = mh.invoke(C(), "Hello", 0.01, Derived()) as String
|
||||
if (result1 != "Hello0.01!") return "Fail 1: $result1"
|
||||
|
||||
// Check parenthesized/annotated expressions + invoke via "()"
|
||||
val result2 = (@IrrelevantAnnotation() ((mh(C(), (("Hello")), 0.01, Derived())))) as String
|
||||
if (result1 != result2) return "Fail 2: $result1 != $result2"
|
||||
|
||||
// Check deep qualified expressions
|
||||
val o = object {
|
||||
val p = object {
|
||||
val handle = mh
|
||||
}
|
||||
}
|
||||
val result3 = (o.p).handle.invoke(C(), "Hello", 0.01, Derived()) as String
|
||||
if (result1 != result3) return "Fail 3: $result1 != $result3"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// !LANGUAGE: +PolymorphicSignature
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// FULL_JDK
|
||||
// SKIP_JDK6
|
||||
// WITH_RUNTIME
|
||||
|
||||
import java.lang.invoke.MethodHandles
|
||||
import java.lang.invoke.MethodType
|
||||
|
||||
class C {
|
||||
fun foo(s: String, d: Double, x: Int): String = "$s$d$x"
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val mh = MethodHandles.lookup().findVirtual(
|
||||
C::class.java, "foo",
|
||||
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
|
||||
return if (result == "Hello0.0142") "OK" else "Fail: $result"
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// !LANGUAGE: +PolymorphicSignature
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// FULL_JDK
|
||||
// SKIP_JDK6
|
||||
// WITH_REFLECT
|
||||
|
||||
import java.lang.invoke.MethodHandles
|
||||
import kotlin.reflect.jvm.javaMethod
|
||||
|
||||
inline class Z(val s: String)
|
||||
|
||||
fun foo(z: Z): String = z.s
|
||||
|
||||
fun box(): String {
|
||||
val mh = MethodHandles.lookup().unreflect(::foo.javaMethod!!)
|
||||
|
||||
// TODO: it's unclear whether this should throw or not, see KT-28214.
|
||||
val r1 = mh.invokeExact(Z("OK")) as String
|
||||
if (r1 != "OK") return "Fail r1: $r1"
|
||||
|
||||
return mh.invokeExact("OK") as String
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// !LANGUAGE: +PolymorphicSignature
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// FULL_JDK
|
||||
// SKIP_JDK6
|
||||
// WITH_RUNTIME
|
||||
|
||||
import java.lang.invoke.MethodHandles
|
||||
import java.lang.invoke.MethodType
|
||||
import java.lang.invoke.WrongMethodTypeException
|
||||
|
||||
fun foo(vararg args: Any?): Any? = args[0]
|
||||
|
||||
fun box(): String {
|
||||
val mh = MethodHandles.lookup().findStatic(
|
||||
object {}::class.java.enclosingClass, "foo",
|
||||
MethodType.methodType(Any::class.java, Array<Any>::class.java)
|
||||
)
|
||||
|
||||
val args = arrayOf("aaa", 1)
|
||||
|
||||
val r1 = mh.invokeExact(args)
|
||||
if (r1 != "aaa") return "Fail 1: $r1"
|
||||
|
||||
val r2 = mh.invokeExact(*args)
|
||||
if (r2 != "aaa") return "Fail 2: $r2"
|
||||
|
||||
val r3 = mh.invokeExact(arrayOf(args) as Array<*>)
|
||||
if (r3 !is Array<*> || !r3.contentEquals(args)) return "Fail 3: $r3"
|
||||
|
||||
try {
|
||||
mh.invokeExact(arrayOf(args))
|
||||
return "Fail 4"
|
||||
} catch (e: WrongMethodTypeException) {
|
||||
// OK
|
||||
}
|
||||
|
||||
val r5 = mh.invoke(args)
|
||||
if (r5 != "aaa") return "Fail 5: $r5"
|
||||
|
||||
val r6 = mh.invoke(*args)
|
||||
if (r6 != "aaa") return "Fail 6: $r6"
|
||||
|
||||
val r7 = mh.invoke(arrayOf(args) as Array<*>)
|
||||
if (r7 !is Array<*> || !r7.contentEquals(args)) return "Fail 7: $r7"
|
||||
|
||||
val r8 = mh.invoke(arrayOf(args))
|
||||
if (r8 !is Array<*> || !r8.contentEquals(args)) return "Fail 8: $r8"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// FULL_JDK
|
||||
// SKIP_JDK6
|
||||
// WITH_RUNTIME
|
||||
|
||||
import java.lang.invoke.MethodHandles
|
||||
import java.lang.invoke.MethodType
|
||||
import java.lang.invoke.WrongMethodTypeException
|
||||
|
||||
fun foo(vararg args: Any?): Any? = args[0]
|
||||
|
||||
fun box(): String {
|
||||
val mh = MethodHandles.lookup().findStatic(
|
||||
object {}::class.java.enclosingClass, "foo",
|
||||
MethodType.methodType(Any::class.java, Array<Any>::class.java)
|
||||
)
|
||||
|
||||
val args = arrayOf("aaa", 1)
|
||||
|
||||
// Note that before PolymorphicSignature was supported in the compiler, this call (and some subsequent calls) made little sense
|
||||
// because the vararg was always wrapped in another array. But it compiled and worked somehow, and this test checks its behavior.
|
||||
val r1 = mh.invokeExact(args)
|
||||
if (r1 !is Array<*> || !r1.contentEquals(args)) return "Fail 1: $r1"
|
||||
|
||||
val r2 = mh.invokeExact(*args)
|
||||
if (r2 != "aaa") return "Fail 2: $r2"
|
||||
|
||||
val r3 = mh.invokeExact(arrayOf(args) as Array<*>)
|
||||
if (r3 !is Array<*> || r3[0] !is Array<*> || !(r3[0] as Array<*>).contentEquals(args)) return "Fail 3: $r3"
|
||||
|
||||
val r4 = mh.invokeExact(arrayOf(args))
|
||||
if (r4 !is Array<*> || r4[0] !is Array<*> || !(r4[0] as Array<*>).contentEquals(args)) return "Fail 4: $r4"
|
||||
|
||||
val r5 = mh.invoke(args)
|
||||
if (r5 !is Array<*> || !r5.contentEquals(args)) return "Fail 5: $r5"
|
||||
|
||||
val r6 = mh.invoke(*args)
|
||||
if (r6 != "aaa") return "Fail 6: $r6"
|
||||
|
||||
val r7 = mh.invoke(arrayOf(args) as Array<*>)
|
||||
if (r7 !is Array<*> || r7[0] !is Array<*> || !(r7[0] as Array<*>).contentEquals(args)) return "Fail 7: $r7"
|
||||
|
||||
val r8 = mh.invoke(arrayOf(args))
|
||||
if (r8 !is Array<*> || r8[0] !is Array<*> || !(r8[0] as Array<*>).contentEquals(args)) return "Fail 8: $r8"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// !LANGUAGE: +PolymorphicSignature
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// FULL_JDK
|
||||
// SKIP_JDK6
|
||||
// WITH_RUNTIME
|
||||
|
||||
import java.lang.invoke.MethodHandles
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
fun box(): String {
|
||||
val handle = MethodHandles.arrayElementVarHandle(ByteArray::class.java)
|
||||
val array = ByteArray(10)
|
||||
|
||||
val index = 0
|
||||
|
||||
// Check that we don't consider non-Object return type of a signature-polymorphic method to be polymorphic.
|
||||
handle.weakCompareAndSetPlain(array, index, 0.toByte(), 21.toByte()) as Comparable<*>
|
||||
|
||||
val oldValue = 42.toByte()
|
||||
val newValue = (-74).toByte()
|
||||
|
||||
thread {
|
||||
Thread.sleep(400L)
|
||||
|
||||
handle.setVolatile(array, index, oldValue)
|
||||
}
|
||||
|
||||
while (!handle.compareAndSet(array, index, oldValue, newValue)) {
|
||||
Thread.sleep(10L)
|
||||
}
|
||||
|
||||
return if (handle.getVolatile(array, index) == newValue) "OK" else "Fail"
|
||||
}
|
||||
|
||||
fun main() {
|
||||
box().let { if (it != "OK") throw AssertionError(it) }
|
||||
}
|
||||
Reference in New Issue
Block a user