Issue with VarHandle


#1

I have a issue usung VarHandle, someone can help me to fix this test code?
Thank you.

import java.lang.invoke.MethodHandles
import java.lang.invoke.VarHandle

class Test {
    private var s: String? = null

    fun getS(): String? {
        return vh.get(this) as String?
    }

    fun setS(s: String) {
        vh.set(this, s)
    }

    companion object {
        private var vh: VarHandle = MethodHandles.lookup().findVarHandle(Test::class.java, "s", String::class.java)
    }
}

fun main(args: Array<String>) {
    val t = Test()
    t.setS("OK")
    println(t.getS())

}

Result using Kotlin 1.3.11 on JDK 11

Exception in thread "main" java.lang.invoke.WrongMethodTypeException: cannot convert MethodHandle(VarHandle,Test,String)void to (VarHandle,Object[])void
	at java.base/java.lang.invoke.MethodHandle.asTypeUncached(MethodHandle.java:861)
	at java.base/java.lang.invoke.MethodHandle.asType(MethodHandle.java:847)
	at java.base/java.lang.invoke.VarHandleGuards.guard_L_V(VarHandleGuards.java:374)
	at Test.setS(Test.kt:12)
	at TestKt.main(Test.kt:22)

#2

Issue founded

https://youtrack.jetbrains.com/issue/KT-14416


#3

Could you please try the 1.3.20 EAP with -XXLanguage:+PolymorphicSignature (as described in the issue you’ve linked) and see if the code works correctly?


#4

Using the above example, I got the error

$ ./gradlew run
w: ATTENTION!
This build uses unsafe internal compiler arguments:

-XXLanguage:+PolymorphicSignature

This mode is not recommended for production use,
as no stability/compatibility guarantees are given on
compiler or generated code. Use it at your own risk!

e: java.lang.UnsupportedOperationException: This feature requires ASM7
        at org.jetbrains.org.objectweb.asm.ClassVisitor.visitNestMember(ClassVisitor.java:236)
        at org.jetbrains.org.objectweb.asm.ClassReader.accept(ClassReader.java:652)
        at org.jetbrains.org.objectweb.asm.ClassReader.accept(ClassReader.java:392)
        at org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass.<init>(BinaryJavaClass.kt:76)
        at org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass.<init>(BinaryJavaClass.kt:40)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinCliJavaFileManagerImpl.findClass(KotlinCliJavaFileManagerImpl.kt:104)
        at org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade$CliFinder.findClass(KotlinJavaPsiFacade.java:387)
        at org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade.findClass(KotlinJavaPsiFacade.java:122)
        at org.jetbrains.kotlin.load.java.JavaClassFinderImpl.findClass(JavaClassFinderImpl.kt:36)
        at org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageScope$classes$1.invoke(LazyJavaPackageScope.kt:71)
        at org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageScope$classes$1.invoke(LazyJavaPackageScope.kt:39)
        at org.jetbrains.kotlin.storage.LockBasedStorageManager$MapBasedMemoizedFunction.invoke(LockBasedStorageManager.java:448)
        at org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageScope.findClassifier(LazyJavaPackageScope.kt:131)
        at org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageScope.getContributedClassifier(LazyJavaPackageScope.kt:121)
        at org.jetbrains.kotlin.load.java.lazy.descriptors.JvmPackageScope.getContributedClassifier(JvmPackageScope.kt:52)
        at org.jetbrains.kotlin.resolve.scopes.ChainedMemberScope.getContributedClassifier(ChainedMemberScope.kt:33)
        at org.jetbrains.kotlin.resolve.scopes.AbstractScopeAdapter.getContributedClassifier(AbstractScopeAdapter.kt:44)
        at org.jetbrains.kotlin.resolve.LazyExplicitImportScope.getContributedClassifier(LazyExplicitImportScope.kt:42)
        at org.jetbrains.kotlin.resolve.lazy.LazyImportScope$getClassifier$1.invoke(LazyImportScope.kt:260)
        at org.jetbrains.kotlin.resolve.lazy.LazyImportScope$getClassifier$1.invoke(LazyImportScope.kt:229)
        at org.jetbrains.kotlin.resolve.lazy.LazyImportResolver$selectSingleFromImports$1.invoke(LazyImportScope.kt:111)
        at org.jetbrains.kotlin.resolve.lazy.LazyImportResolver$selectSingleFromImports$2.invoke(LazyImportScope.kt:117)
        at org.jetbrains.kotlin.resolve.lazy.LazyImportResolver$selectSingleFromImports$2.invoke(LazyImportScope.kt:87)
        at org.jetbrains.kotlin.storage.LockBasedStorageManager.compute(LockBasedStorageManager.java:231)
        at org.jetbrains.kotlin.resolve.lazy.LazyImportResolver.selectSingleFromImports(LazyImportScope.kt:117)
        at org.jetbrains.kotlin.resolve.lazy.LazyImportScope.getClassifier(LazyImportScope.kt:259)
        at org.jetbrains.kotlin.resolve.lazy.LazyImportScope.getContributedClassifier(LazyImportScope.kt:255)
        at org.jetbrains.kotlin.resolve.scopes.ResolutionScope$DefaultImpls.getContributedClassifierIncludeDeprecated(ResolutionScope.kt:40)
        at org.jetbrains.kotlin.resolve.scopes.HierarchicalScope$DefaultImpls.getContributedClassifierIncludeDeprecated(Scopes.kt)
        at org.jetbrains.kotlin.resolve.scopes.ImportingScope$DefaultImpls.getContributedClassifierIncludeDeprecated(Scopes.kt)
        at org.jetbrains.kotlin.resolve.lazy.LazyImportScope.getContributedClassifierIncludeDeprecated(LazyImportScope.kt:229)
        at org.jetbrains.kotlin.resolve.scopes.utils.ScopeUtilsKt.findFirstClassifierWithDeprecationStatus(ScopeUtils.kt:118)
        at org.jetbrains.kotlin.resolve.QualifiedExpressionResolver.findClassifierAndReportDeprecationIfNeeded(QualifiedExpressionResolver.kt:75)
        at org.jetbrains.kotlin.resolve.QualifiedExpressionResolver.resolveDescriptorForType(QualifiedExpressionResolver.kt:99)
        at org.jetbrains.kotlin.resolve.TypeResolver.resolveDescriptorForType(TypeResolver.kt:880)
        at org.jetbrains.kotlin.resolve.TypeResolver$resolveTypeElement$1.visitUserType(TypeResolver.kt:204)
        at org.jetbrains.kotlin.psi.KtVisitorVoid.visitUserType(KtVisitorVoid.java:923)
        at org.jetbrains.kotlin.psi.KtVisitorVoid.visitUserType(KtVisitorVoid.java:21)
        at org.jetbrains.kotlin.psi.KtUserType.accept(KtUserType.java:42)
        at org.jetbrains.kotlin.psi.KtElementImplStub.accept(KtElementImplStub.java:60)
        at org.jetbrains.kotlin.resolve.TypeResolver.resolveTypeElement(TypeResolver.kt:202)
        at org.jetbrains.kotlin.resolve.TypeResolver.resolvePossiblyBareType(TypeResolver.kt:123)
        at org.jetbrains.kotlin.resolve.TypeResolver.resolveType(TypeResolver.kt:107)
        at org.jetbrains.kotlin.resolve.TypeResolver.resolveType(TypeResolver.kt:78)
        at org.jetbrains.kotlin.resolve.VariableTypeAndInitializerResolver.resolveTypeNullable(VariableTypeAndInitializerResolver.kt:69)
        at org.jetbrains.kotlin.resolve.DescriptorResolver.resolveAsPropertyDescriptor(DescriptorResolver.java:954)
        at org.jetbrains.kotlin.resolve.DescriptorResolver.resolvePropertyDescriptor(DescriptorResolver.java:841)
        at org.jetbrains.kotlin.resolve.lazy.descriptors.AbstractLazyMemberScope.doGetProperties(AbstractLazyMemberScope.kt:132)
        at org.jetbrains.kotlin.resolve.lazy.descriptors.AbstractLazyMemberScope.access$doGetProperties(AbstractLazyMemberScope.kt:38)
        at org.jetbrains.kotlin.resolve.lazy.descriptors.AbstractLazyMemberScope$propertyDescriptors$1.invoke(AbstractLazyMemberScope.kt:52)
        at org.jetbrains.kotlin.resolve.lazy.descriptors.AbstractLazyMemberScope$propertyDescriptors$1.invoke(AbstractLazyMemberScope.kt:38)
        at org.jetbrains.kotlin.storage.LockBasedStorageManager$MapBasedMemoizedFunction.invoke(LockBasedStorageManager.java:448)
        at org.jetbrains.kotlin.storage.LockBasedStorageManager$MapBasedMemoizedFunctionToNotNull.invoke(LockBasedStorageManager.java:523)
        at org.jetbrains.kotlin.resolve.lazy.descriptors.AbstractLazyMemberScope.getContributedVariables(AbstractLazyMemberScope.kt:124)
        at org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassMemberScope.getContributedVariables(LazyClassMemberScope.kt:325)
        at org.jetbrains.kotlin.resolve.lazy.LazyDeclarationResolver$resolveToDescriptor$1.visitProperty(LazyDeclarationResolver.kt:182)
        at org.jetbrains.kotlin.resolve.lazy.LazyDeclarationResolver$resolveToDescriptor$1.visitProperty(LazyDeclarationResolver.kt:94)
        at org.jetbrains.kotlin.psi.KtProperty.accept(KtProperty.java:58)
        at org.jetbrains.kotlin.resolve.lazy.LazyDeclarationResolver.resolveToDescriptor(LazyDeclarationResolver.kt:94)
        at org.jetbrains.kotlin.resolve.lazy.LazyDeclarationResolver.resolveToDescriptor(LazyDeclarationResolver.kt:91)
        at org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer.createPropertyDescriptors(LazyTopDownAnalyzer.kt:274)
        at org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer.analyzeDeclarations(LazyTopDownAnalyzer.kt:207)
        at org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer.analyzeDeclarations$default(LazyTopDownAnalyzer.kt:61)
        at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.kt:110)
        at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration$default(TopDownAnalyzerFacadeForJVM.kt:82)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:384)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:70)
        at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.kt:107)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze(KotlinToJVMBytecodeCompiler.kt:375)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:123)
        at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:159)
        at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:57)
        at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.java:96)
        at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.java:52)
        at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:93)
        at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:357)
        at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:99)
        at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileIncrementally(IncrementalCompilerRunner.kt:222)
        at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.access$compileIncrementally(IncrementalCompilerRunner.kt:37)
        at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner$compile$2.invoke(IncrementalCompilerRunner.kt:88)
        at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:100)
        at org.jetbrains.kotlin.daemon.CompileServiceImpl.execIncrementalCompiler(CompileServiceImpl.kt:590)
        at org.jetbrains.kotlin.daemon.CompileServiceImpl.access$execIncrementalCompiler(CompileServiceImpl.kt:102)
        at org.jetbrains.kotlin.daemon.CompileServiceImpl$compile$$inlined$ifAlive$lambda$2.invoke(CompileServiceImpl.kt:455)
        at org.jetbrains.kotlin.daemon.CompileServiceImpl$compile$$inlined$ifAlive$lambda$2.invoke(CompileServiceImpl.kt:102)
        at org.jetbrains.kotlin.daemon.CompileServiceImpl$doCompile$$inlined$ifAlive$lambda$2.invoke(CompileServiceImpl.kt:1013)
        at org.jetbrains.kotlin.daemon.CompileServiceImpl$doCompile$$inlined$ifAlive$lambda$2.invoke(CompileServiceImpl.kt:102)
        at org.jetbrains.kotlin.daemon.common.DummyProfiler.withMeasure(PerfUtils.kt:137)
        at org.jetbrains.kotlin.daemon.CompileServiceImpl.checkedCompile(CompileServiceImpl.kt:1055)
        at org.jetbrains.kotlin.daemon.CompileServiceImpl.doCompile(CompileServiceImpl.kt:1012)
        at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:454)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:359)
        at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
        at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
        at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:562)
        at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:796)
        at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:677)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:676)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.base/java.lang.Thread.run(Thread.java:834)

> Task :compileKotlin FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':compileKotlin'.
> Internal compiler error. See log for more details

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/5.1/userguide/command_line_interface.html#sec:command_line_warnings

BUILD FAILED in 2s

Build script

buildscript {
    ext.kotlin_version = '1.3.20-eap-25'

    repositories {
        maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
        mavenCentral()
    }

    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

apply plugin: 'kotlin'
apply plugin: 'application'

mainClassName = "TestKt"

repositories {
    maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
    jcenter()
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    compile 'org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.0.0'
}

compileKotlin {
    kotlinOptions {
        jvmTarget = "1.8"
        freeCompilerArgs = ["-XXLanguage:+PolymorphicSignature"]
    }
}

wrapper {
    gradleVersion = '5.1'
}

Java version

$ java -version
openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment (build 11.0.1+13-Ubuntu-3ubuntu118.04ppa1)
OpenJDK 64-Bit Server VM (build 11.0.1+13-Ubuntu-3ubuntu118.04ppa1, mixed mode, sharing

#5

OK, thanks. This is a known problem, reported as KT-28798 and fixed in the next EAP which is due very soon. Let’s wait for that and then see if the VarHandle issue is fixed.


#6

Hi @udalov
I tested this and works

import java.lang.invoke.MethodHandles
import java.lang.invoke.VarHandle

class Test {
    @Volatile
    private var _s = ""

    var s: String
        get() = vh.get(this) as String
        set(value) {
            // workaround field = "x"
            vh.set(this, value)
        }

    companion object {
        private var vh: VarHandle = MethodHandles.lookup().findVarHandle(Test::class.java, "_s", String::class.java)
    }
}

fun main(args: Array<String>) {
    val t = Test()
    t.s = "OK"
    println(t.s)
}

but I have to declare a support variable _s, do you have a better solution to fix:

import java.lang.invoke.MethodHandles
import java.lang.invoke.VarHandle

class Test {
    @Volatile
    var s: String = ""
        get() = vh.get(this) as String
        set(value) {
            // workaround field = "x"
            vh.set(this, value)
        }

    companion object {
        private var vh: VarHandle = MethodHandles.lookup().findVarHandle(Test::class.java, "s", String::class.java)
    }
}

fun main(args: Array<String>) {
    val t = Test()
    t.s = "OK"
    println(t.s)
}

#7

I’m not sure if there’s a better way to declare a property with both a backing field and accessors. An alternative approach would be to reference its field via field anywhere in its accessors, but I doubt that it’s a lot better:

@Volatile
var s: String = ""
    get() {
        @Suppress("UNUSED_EXPRESSION")
        field // "Unused" expression to force backing field for this property

        return vh.get(this) as String
    }
    set(value) {
        vh.set(this, value)
    }

#8

Accessing to a volatile field imposes an acquire barrier.
Thank you for support, I take a look to AtomicFU.