/* * Copyright 2010-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license * that can be found in the LICENSE file. */ import Foundation import benchmark private let REPEAT_COUNT = 10000 private class ReferenceWrapper { private weak var weakRef: KotlinData? private var strongRef: KotlinData? init() { let data = KotlinData(x: Int32.random(in: 1 ... 1000)) self.strongRef = data self.weakRef = data } // This function must not be inlined. We must ensure `weakRef` is accessed at each loop iteration. @inline(never) func value() -> Int32 { let ref: KotlinData? = self.weakRef if ref == nil { return 0 } return ref!.x } func dispose() { self.strongRef = nil } func stress() -> Int32 { var counter: Int32 = 0 for _ in 1...REPEAT_COUNT { counter += self.value() } return counter } } private func deadReferenceWrapper() -> ReferenceWrapper { let ref = ReferenceWrapper() ref.dispose() GCKt.collect() return ref } class WeakRefBenchmark { private let weight = (0..<10_000).map { _ in ReferenceWrapper() } private let aliveRef = ReferenceWrapper() private let deadRef = deadReferenceWrapper() // Access alive reference. func aliveReference() { let counter = aliveRef.stress() if counter == 0 { fatalError() } } // Access dead reference. func deadReference() { let counter = deadRef.stress() if counter != 0 { fatalError() } } // Access reference that is nulled out in the middle. func dyingReference() { let ref = ReferenceWrapper() ref.dispose() GCKt.schedule() let counter = ref.stress() Blackhole.companion.consume(value: counter) } func clean() { weight.forEach { $0.dispose() } } }