[K/N] Any.isFrozen is now always false when freezing is disabled

This commit is contained in:
Pavel Kunyavskiy
2022-01-19 16:15:20 +03:00
committed by Space
parent 35ef8cc6da
commit 3798920183
20 changed files with 116 additions and 50 deletions
@@ -11,22 +11,23 @@ package org.jetbrains.kotlin.backend.konan
*
* If [enableFreezeAtRuntime] is false then `Any.freeze()` and `checkIfFrozen(ref: Any?)` are no-op.
* [freezeImplicit] enabled freezing for @Frozen types and @SharedImmutable globals (i.e. implicit calls to `Any.freeze()`).
* If [enableFreezeChecks] is false, than `Any.isFrozen() will always return false, and no [InvalidMutabilityException] can be thrown
*/
enum class Freezing(val enableFreezeAtRuntime: Boolean, val freezeImplicit: Boolean) {
enum class Freezing(val enableFreezeAtRuntime: Boolean, val freezeImplicit: Boolean, val enableFreezeChecks: Boolean) {
/**
* Enable freezing in `Any.freeze()` as well as for @Frozen types and @SharedImmutable globals.
*/
Full(true, true),
Full(true, true, true),
/**
* Enable freezing only in explicit calls to `Any.freeze()`.
*/
ExplicitOnly(true, false),
ExplicitOnly(true, false, true),
/**
* No freezing at all.
*/
Disabled(false, false);
Disabled(false, false, false);
companion object {
// Users might depend on runtime guarantees of freezing, so it should be enabled by default.
@@ -2742,6 +2742,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
overrideRuntimeGlobal("Kotlin_destroyRuntimeMode", Int32(context.config.destroyRuntimeMode.value))
overrideRuntimeGlobal("Kotlin_workerExceptionHandling", Int32(context.config.workerExceptionHandling.value))
overrideRuntimeGlobal("Kotlin_freezingEnabled", Int32(if (context.config.freezing.enableFreezeAtRuntime) 1 else 0))
overrideRuntimeGlobal("Kotlin_freezingChecksEnabled", Int32(if (context.config.freezing.enableFreezeChecks) 1 else 0))
overrideRuntimeGlobal("Kotlin_gcSchedulerType", Int32(context.config.gcSchedulerType.value))
val getSourceInfoFunctionName = when (context.config.sourceInfoType) {
SourceInfoType.NOOP -> null
@@ -1152,52 +1152,68 @@ standaloneTest("worker_threadlocal_no_leak") {
source = "runtime/workers/worker_threadlocal_no_leak.kt"
}
task freeze0(type: KonanLocalTest) {
standaloneTest("freeze0") {
enabled = (project.testTarget != 'wasm32') // No workers on WASM.
useGoldenData = true
flags = ["-Xbinary=freezing=full", "-tr"]
source = "runtime/workers/freeze0.kt"
testLogger = KonanTest.Logger.SILENT
}
task freeze1(type: KonanLocalTest) {
standaloneTest("freeze1") {
enabled = (project.testTarget != 'wasm32') // No exceptions on WASM.
useGoldenData = true
flags = ["-Xbinary=freezing=full", "-tr"]
source = "runtime/workers/freeze1.kt"
testLogger = KonanTest.Logger.SILENT
}
task freeze_stress(type: KonanLocalTest) {
standaloneTest("freeze_stress") {
enabled = (project.testTarget != 'wasm32') // No exceptions on WASM.
useGoldenData = true
flags = ["-Xbinary=freezing=full", "-tr"]
source = "runtime/workers/freeze_stress.kt"
testLogger = KonanTest.Logger.SILENT
}
task freeze2(type: KonanLocalTest) {
standaloneTest("freeze2") {
enabled = (project.testTarget != 'wasm32') // No exceptions on WASM.
useGoldenData = true
flags = ["-Xbinary=freezing=full", "-tr"]
source = "runtime/workers/freeze2.kt"
testLogger = KonanTest.Logger.SILENT
}
task freeze3(type: KonanLocalTest) {
standaloneTest("freeze3") {
enabled = (project.testTarget != 'wasm32') // No exceptions on WASM.
useGoldenData = true
flags = ["-Xbinary=freezing=full", "-tr"]
source = "runtime/workers/freeze3.kt"
testLogger = KonanTest.Logger.SILENT
}
task freeze4(type: KonanLocalTest) {
standaloneTest("freeze4") {
enabled = (project.testTarget != 'wasm32') // No exceptions on WASM.
useGoldenData = true
flags = ["-Xbinary=freezing=full", "-tr"]
source = "runtime/workers/freeze4.kt"
testLogger = KonanTest.Logger.SILENT
}
task freeze5(type: KonanLocalTest) {
standaloneTest("freeze5") {
useGoldenData = true
flags = ["-Xbinary=freezing=full", "-tr"]
source = "runtime/workers/freeze5.kt"
testLogger = KonanTest.Logger.SILENT
}
task freeze6(type: KonanLocalTest) {
standaloneTest("freeze6") {
enabled = (project.testTarget != 'wasm32') && // No exceptions on WASM.
!isNoopGC
useGoldenData = true
flags = ["-Xbinary=freezing=full", "-tr"]
source = "runtime/workers/freeze6.kt"
testLogger = KonanTest.Logger.SILENT
}
task atomic0(type: KonanLocalTest) {
@@ -15,17 +15,18 @@ private class NSObjectImpl : NSObject() {
assertFalse(obj.isFrozen)
obj.x = 222
obj.freeze()
assertTrue(obj.isFrozen)
runInWorker {
val obj1 = array.objectAtIndex(0) as NSObjectImpl
assertFailsWith<InvalidMutabilityException> {
obj1.x = 333
if (Platform.isFreezingEnabled) {
obj.freeze()
assertTrue(obj.isFrozen)
runInWorker {
val obj1 = array.objectAtIndex(0) as NSObjectImpl
assertFailsWith<InvalidMutabilityException> {
obj1.x = 333
}
}
assertEquals(222, obj.x)
}
assertEquals(222, obj.x)
// TODO: test [obj release] etc.
}
@@ -2627,6 +2627,7 @@ __attribute__((swift_name("ValuesKt")))
+ (KtTripleVals<id> * _Nullable)getValue3:(id _Nullable)receiver __attribute__((swift_name("getValue3(_:)")));
+ (KtTripleVals<id> * _Nullable)getValueOrNull3:(id _Nullable)receiver __attribute__((swift_name("getValueOrNull3(_:)")));
+ (BOOL)isFrozenObj:(id)obj __attribute__((swift_name("isFrozen(obj:)")));
+ (BOOL)isFreezingEnabled __attribute__((swift_name("isFreezingEnabled()")));
+ (id)kotlinLambdaBlock:(id (^)(id))block __attribute__((swift_name("kotlinLambda(block:)")));
+ (int64_t)multiplyInt:(int32_t)int_ long:(int64_t)long_ __attribute__((swift_name("multiply(int:long:)")));
@@ -2569,6 +2569,7 @@ __attribute__((swift_name("ValuesKt")))
+ (KtTripleVals<id> * _Nullable)getValue3:(id _Nullable)receiver __attribute__((swift_name("getValue3(_:)")));
+ (KtTripleVals<id> * _Nullable)getValueOrNull3:(id _Nullable)receiver __attribute__((swift_name("getValueOrNull3(_:)")));
+ (BOOL)isFrozenObj:(id)obj __attribute__((swift_name("isFrozen(obj:)")));
+ (BOOL)isFreezingEnabled __attribute__((swift_name("isFreezingEnabled()")));
+ (id)kotlinLambdaBlock:(id (^)(id))block __attribute__((swift_name("kotlinLambda(block:)")));
+ (int64_t)multiplyInt:(int32_t)int_ long:(int64_t)long_ __attribute__((swift_name("multiply(int:long:)")));
@@ -2569,6 +2569,7 @@ __attribute__((swift_name("ValuesKt")))
+ (KtTripleVals * _Nullable)getValue3:(id _Nullable)receiver __attribute__((swift_name("getValue3(_:)")));
+ (KtTripleVals * _Nullable)getValueOrNull3:(id _Nullable)receiver __attribute__((swift_name("getValueOrNull3(_:)")));
+ (BOOL)isFrozenObj:(id)obj __attribute__((swift_name("isFrozen(obj:)")));
+ (BOOL)isFreezingEnabled __attribute__((swift_name("isFreezingEnabled()")));
+ (id)kotlinLambdaBlock:(id (^)(id))block __attribute__((swift_name("kotlinLambda(block:)")));
+ (int64_t)multiplyInt:(int32_t)int_ long:(int64_t)long_ __attribute__((swift_name("multiply(int:long:)")));
@@ -250,6 +250,7 @@ fun IC3.getValue3() = value
fun IC3?.getValueOrNull3() = this?.value
fun isFrozen(obj: Any): Boolean = obj.isFrozen
fun isFreezingEnabled() = Platform.isFreezingEnabled
fun kotlinLambda(block: (Any) -> Any): Any = block
fun multiply(int: Int, long: Long) = int * long
@@ -590,6 +590,9 @@ class TestSharedIImpl : NSObject, I {
}
func testShared() throws {
if !ValuesKt.isFreezingEnabled() {
return;
}
func assertFrozen(_ obj: AnyObject) throws {
try assertTrue(ValuesKt.isFrozen(obj: obj), "isFrozen(\(obj))")
}
@@ -50,24 +50,26 @@ import kotlin.native.concurrent.*
}
expect(0) { results.size }
array.freeze()
assertFailsWith<InvalidMutabilityException> {
array.setShortAt(0, 2.toShort())
}
assertFailsWith<InvalidMutabilityException> {
array.setCharAt(0, 'a')
}
assertFailsWith<InvalidMutabilityException> {
array.setIntAt(0, 2)
}
assertFailsWith<InvalidMutabilityException> {
array.setLongAt(0, 2)
}
assertFailsWith<InvalidMutabilityException> {
array.setFloatAt(0, 1.0f)
}
assertFailsWith<InvalidMutabilityException> {
array.setDoubleAt(0, 1.0)
if (Platform.isFreezingEnabled) {
array.freeze()
assertFailsWith<InvalidMutabilityException> {
array.setShortAt(0, 2.toShort())
}
assertFailsWith<InvalidMutabilityException> {
array.setCharAt(0, 'a')
}
assertFailsWith<InvalidMutabilityException> {
array.setIntAt(0, 2)
}
assertFailsWith<InvalidMutabilityException> {
array.setLongAt(0, 2)
}
assertFailsWith<InvalidMutabilityException> {
array.setFloatAt(0, 1.0f)
}
assertFailsWith<InvalidMutabilityException> {
array.setDoubleAt(0, 1.0)
}
}
println("OK")
}
@@ -9,6 +9,7 @@ import kotlin.test.*
import kotlin.native.concurrent.*
import kotlin.native.internal.GC
import kotlin.native.*
import kotlin.native.ref.WeakReference
import kotlin.text.Regex
@@ -600,6 +601,7 @@ fun createCyclicGarbageFrozen(): Triple<AtomicReference<WorkerBoundReference<B1>
@Test
fun doesNotCollectCyclicGarbageFrozen() {
if (!Platform.isFreezingEnabled) return
val (ref1Owner, ref1Weak, ref2Weak) = createCyclicGarbageFrozen()
ref1Owner.value = null
@@ -630,6 +632,7 @@ fun createCrossThreadCyclicGarbageFrozen(
@Test
fun doesNotCollectCrossThreadCyclicGarbageFrozen() {
if (!Platform.isFreezingEnabled) return
val worker = Worker.start()
val (ref1Owner, ref1Weak, ref2Weak) = createCrossThreadCyclicGarbageFrozen(worker)
@@ -674,6 +677,7 @@ fun dispose(refOwner: AtomicReference<WorkerBoundReference<C1>?>) {
@Test
fun doesNotCollectCyclicGarbageWithAtomicsFrozen() {
if (!Platform.isFreezingEnabled) return
val (ref1Owner, ref1Weak, ref2Weak) = createCyclicGarbageWithAtomicsFrozen()
ref1Owner.value = null
@@ -723,6 +727,7 @@ fun createCrossThreadCyclicGarbageWithAtomicsFrozen(
@Test
fun doesNotCollectCrossThreadCyclicGarbageWithAtomicsFrozen() {
if (!Platform.isFreezingEnabled) return
val worker = Worker.start()
val (ref1Owner, ref1Weak, ref2Weak) = createCrossThreadCyclicGarbageWithAtomicsFrozen(worker)
@@ -835,6 +840,7 @@ fun testDoubleFreeze() {
@Test
fun testDoubleFreezeWithFreezeBlocker() {
if (!Platform.isFreezingEnabled) return
val ref = WorkerBoundReference(A(3))
val wrapper = Wrapper(ref)
wrapper.ensureNeverFrozen()
@@ -93,10 +93,12 @@ fun test4() {
ref.compareAndSwap(null, Data(2))
assertEquals(2, ref.value!!.value)
}
run {
val ref = AtomicReference<Data?>(null).freeze()
assertFailsWith<InvalidMutabilityException> {
ref.compareAndSwap(null, Data(2))
if (Platform.isFreezingEnabled) {
run {
val ref = AtomicReference<Data?>(null).freeze()
assertFailsWith<InvalidMutabilityException> {
ref.compareAndSwap(null, Data(2))
}
}
}
}
@@ -137,11 +139,13 @@ fun test7() {
ref.value = Array(1) { "po" }
assertEquals(ref.value[0], "po")
ref.freeze()
assertFailsWith<InvalidMutabilityException> {
ref.value = Array(1) { "no" }
}
assertFailsWith<InvalidMutabilityException> {
ref.value[0] = "go"
if (Platform.isFreezingEnabled) {
assertFailsWith<InvalidMutabilityException> {
ref.value = Array(1) { "no" }
}
assertFailsWith<InvalidMutabilityException> {
ref.value[0] = "go"
}
}
ref.value = Array(1) { "so" }.freeze()
assertEquals(ref.value[0], "so")
@@ -81,9 +81,11 @@ private val checkedLazyModes =
@Test fun runTest3() {
for (mode in checkedLazyModes) {
assertFailsWith<InvalidMutabilityException> {
println(Lazy(mode).freezer)
if (Platform.isFreezingEnabled) {
for (mode in checkedLazyModes) {
assertFailsWith<InvalidMutabilityException> {
println(Lazy(mode).freezer)
}
}
}
}