Introduce experimental kotlin.concurrent.Volatile annotation KT-55268, KT-55609

Use this annotation in tests to ensure it works the same at least on JVM
This commit is contained in:
Ilya Gorbunov
2022-12-21 22:43:20 +01:00
parent 58d6d7b9ad
commit e2d96da396
10 changed files with 176 additions and 9 deletions
@@ -1,5 +1,8 @@
// TARGET_BACKEND: JVM
// due to KT-55615
// IGNORE_BACKEND_K2: JVM_IR
// WITH_STDLIB
// FULL_JDK
@@ -12,6 +15,8 @@ class CustomDelegate {
class C {
@Volatile var vol = 1
@OptIn(ExperimentalStdlibApi::class)
@kotlin.concurrent.Volatile var vol2 = 1
@Transient val tra = 1
@delegate:Transient val del: String by CustomDelegate()
@@ -38,6 +43,7 @@ fun box(): String {
val c = C::class.java
if (c.getDeclaredField("vol").getModifiers() and Modifier.VOLATILE == 0) return "Fail: volatile"
if (c.getDeclaredField("vol2").getModifiers() and Modifier.VOLATILE == 0) return "Fail: volatile from kotlin.concurrent"
if (c.getDeclaredField("tra").getModifiers() and Modifier.TRANSIENT == 0) return "Fail: transient"
if (c.getDeclaredField("del\$delegate").getModifiers() and Modifier.TRANSIENT == 0) return "Fail: delegate transient"
@@ -1,10 +1,13 @@
@Volatile var vol = 1
@OptIn(ExperimentalStdlibApi::class)
@kotlin.concurrent.Volatile var vol2 = 1
@Transient val tra = 1
@Strictfp fun str() {}
@Synchronized fun sync() {}
// 0 kotlin/jvm/Volatile
// 0 kotlin/concurrent/Volatile
// 0 kotlin/jvm/Transient
// 0 kotlin/jvm/Strictfp
// 0 kotlin/jvm/Synchronized
@@ -0,0 +1,35 @@
// !DIAGNOSTICS: -UNUSED_ANONYMOUS_PARAMETER
import kotlin.jvm.Volatile as JvmVolatile
import kotlin.concurrent.Volatile
import kotlin.properties.Delegates
@OptIn(ExperimentalStdlibApi::class)
class ConcurrentVolatile {
@Volatile val x = 0
// ok
@Volatile var y = 1
@delegate:Volatile var z: String by Delegates.observable("?") { prop, old, new -> old.hashCode() }
@field:Volatile val w = 2
@Volatile
var noBacking: String
get() = ""
set(value) {}
}
class JvmVolatile {
<!VOLATILE_ON_VALUE!>@JvmVolatile<!> val x = 0
// ok
@JvmVolatile var y = 1
<!VOLATILE_ON_DELEGATE!>@delegate:JvmVolatile<!> var z: String by Delegates.observable("?") { prop, old, new -> old.hashCode() }
<!VOLATILE_ON_VALUE!>@field:JvmVolatile<!> val w = 2
<!WRONG_ANNOTATION_TARGET!>@JvmVolatile<!>
var noBacking: String
get() = ""
set(value) {}
}
@@ -1,9 +1,10 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_ANONYMOUS_PARAMETER
import kotlin.jvm.Volatile
import kotlin.jvm.Volatile as JvmVolatile
import kotlin.concurrent.Volatile
import kotlin.properties.Delegates
class My {
@OptIn(ExperimentalStdlibApi::class)
class ConcurrentVolatile {
<!VOLATILE_ON_VALUE!>@Volatile<!> val x = 0
// ok
@Volatile var y = 1
@@ -11,4 +12,24 @@ class My {
<!VOLATILE_ON_DELEGATE!>@delegate:Volatile<!> var z: String by Delegates.observable("?") { prop, old, new -> old.hashCode() }
<!VOLATILE_ON_VALUE!>@field:Volatile<!> val w = 2
<!WRONG_ANNOTATION_TARGET!>@Volatile<!>
var noBacking: String
get() = ""
set(value) {}
}
class JvmVolatile {
<!VOLATILE_ON_VALUE!>@JvmVolatile<!> val x = 0
// ok
@JvmVolatile var y = 1
<!VOLATILE_ON_DELEGATE!>@delegate:JvmVolatile<!> var z: String by Delegates.observable("?") { prop, old, new -> old.hashCode() }
<!VOLATILE_ON_VALUE!>@field:JvmVolatile<!> val w = 2
<!WRONG_ANNOTATION_TARGET!>@JvmVolatile<!>
var noBacking: String
get() = ""
set(value) {}
}
@@ -1,7 +1,20 @@
package
public final class My {
public constructor My()
@kotlin.OptIn(markerClass = {kotlin.ExperimentalStdlibApi::class}) public final class ConcurrentVolatile {
public constructor ConcurrentVolatile()
@field:kotlin.concurrent.Volatile /* = kotlin.jvm.Volatile */ public final var noBacking: kotlin.String
@field:kotlin.concurrent.Volatile /* = kotlin.jvm.Volatile */ public final val w: kotlin.Int = 2
@field:kotlin.concurrent.Volatile /* = kotlin.jvm.Volatile */ public final val x: kotlin.Int = 0
@field:kotlin.concurrent.Volatile /* = kotlin.jvm.Volatile */ public final var y: kotlin.Int
@delegate:kotlin.concurrent.Volatile /* = kotlin.jvm.Volatile */ public final var z: kotlin.String
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class JvmVolatile {
public constructor JvmVolatile()
@field:kotlin.jvm.Volatile public final var noBacking: kotlin.String
@field:kotlin.jvm.Volatile public final val w: kotlin.Int = 2
@field:kotlin.jvm.Volatile public final val x: kotlin.Int = 0
@field:kotlin.jvm.Volatile public final var y: kotlin.Int
@@ -0,0 +1,27 @@
/*
* Copyright 2010-2022 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 kotlin.concurrent
import kotlin.internal.RequireKotlin
import kotlin.internal.RequireKotlinVersionKind
/**
* Marks the backing field of the annotated `var` property as `volatile`, meaning that reads and writes to this field
* are atomic and writes are always made visible to other threads. If another thread reads the value of this field (e.g. through its accessor),
* it sees not only that value, but all side effects that led to writing that value.
*
* Note that only _backing field_ operations are atomic when the field is annotated with `Volatile`.
* For example, if the property getter or setter make several operations with the backing field,
* a _property_ operation, i.e. reading or setting it through these accessors, is not guaranteed to be atomic.
*/
@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.SOURCE)
@MustBeDocumented
@SinceKotlin("1.8")
@RequireKotlin(version = "1.8.20", versionKind = RequireKotlinVersionKind.COMPILER_VERSION)
@ExperimentalStdlibApi
public actual annotation class Volatile
@@ -122,8 +122,16 @@ public expect annotation class JvmInline()
public expect annotation class JvmRecord()
/**
* Marks the JVM backing field of the annotated property as `volatile`, meaning that writes to this field
* are immediately made visible to other threads.
* Marks the JVM backing field of the annotated `var` property as `volatile`, meaning that reads and writes to this field
* are atomic and writes are always made visible to other threads. If another thread reads the value of this field (e.g. through its accessor),
* it sees not only that value, but all side effects that led to writing that value.
*
* This annotation has effect only in Kotlin/JVM. It's recommended to use [kotlin.concurrent.Volatile] annotation instead
* in multiplatform projects.
*
* Note that only _backing field_ operations are atomic when the field is annotated with `Volatile`.
* For example, if the property getter or setter make several operations with the backing field,
* a _property_ operation, i.e. reading or setting it through these accessors, is not guaranteed to be atomic.
*/
@Target(FIELD)
@MustBeDocumented
@@ -8,8 +8,13 @@ package kotlin.jvm
import kotlin.annotation.AnnotationTarget.*
/**
* Marks the JVM backing field of the annotated property as `volatile`, meaning that writes to this field
* are immediately made visible to other threads.
* Marks the JVM backing field of the annotated `var` property as `volatile`, meaning that reads and writes to this field
* are atomic and writes are always made visible to other threads. If another thread reads the value of this field (e.g. through its accessor),
* it sees not only that value, but all side effects that led to writing that value.
*
* Note that only _backing field_ operations are atomic when the field is annotated with `Volatile`.
* For example, if the property getter or setter make several operations with the backing field,
* a _property_ operation, i.e. reading or setting it through these accessors, is not guaranteed to be atomic.
*/
@Target(FIELD)
@Retention(AnnotationRetention.SOURCE)
@@ -0,0 +1,19 @@
/*
* Copyright 2010-2022 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 kotlin.concurrent
/**
* Marks the JVM backing field of the annotated `var` property as `volatile`, meaning that reads and writes to this field
* are atomic and writes are always made visible to other threads. If another thread reads the value of this field (e.g. through its accessor),
* it sees not only that value, but all side effects that led to writing that value.
*
* Note that only _backing field_ operations are atomic when the field is annotated with `Volatile`.
* For example, if the property getter or setter make several operations with the backing field,
* a _property_ operation, i.e. reading or setting it through these accessors, is not guaranteed to be atomic.
*/
@SinceKotlin("1.8")
@ExperimentalStdlibApi
public actual typealias Volatile = kotlin.jvm.Volatile
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2022 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 kotlin.concurrent
import kotlin.internal.RequireKotlin
import kotlin.internal.RequireKotlinVersionKind
/**
* Marks the backing field of the annotated `var` property as `volatile`, meaning that reads and writes to this field
* are atomic and writes are always made visible to other threads. If another thread reads the value of this field (e.g. through its accessor),
* it sees not only that value, but all side effects that led to writing that value.
*
* This annotation has effect in Kotlin/JVM and Kotlin/Native.
*
* Note that only _backing field_ operations are atomic when the field is annotated with `Volatile`.
* For example, if the property getter or setter make several operations with the backing field,
* a _property_ operation, i.e. reading or setting it through these accessors, is not guaranteed to be atomic.
*/
@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.SOURCE)
@MustBeDocumented
@OptionalExpectation
@SinceKotlin("1.8")
@RequireKotlin(version = "1.8.20", versionKind = RequireKotlinVersionKind.COMPILER_VERSION)
@ExperimentalStdlibApi
public expect annotation class Volatile()