~ Track read-writes of attributeOwnerId
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrElementBase.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrElementBase.kt
index 9460a53..e016605 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrElementBase.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrElementBase.kt
@@ -18,7 +18,7 @@
import org.jetbrains.kotlin.ir.visitors.IrTransformer
import org.jetbrains.kotlin.ir.visitors.IrVisitor
-import java.util.IdentityHashMap
+import java.util.*
abstract class IrElementBase : IrElement {
/**
@@ -41,7 +41,22 @@
}
- final override var attributeOwnerId: IrElement = this
+ private var lastWrite_attributeOwnerId: List<StackTraceElement>? = null
+ private var _attributeOwnerId: IrElement? = null
+ final override var attributeOwnerId: IrElement
+ get() {
+ if (_attributeOwnerId !== null) {
+ LocationTracker.recordReadStackTrace(LocationTracker.attributeOwnerId, lastWrite_attributeOwnerId, 1)
+ }
+ return _attributeOwnerId ?: this
+ }
+ set(rawValue) {
+ val value = if (rawValue === this) null else rawValue
+ if (value !== _attributeOwnerId) {
+ lastWrite_attributeOwnerId = LocationTracker.recordWriteStackTrace(1)
+ _attributeOwnerId = value
+ }
+ }
/**
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/LocationTracker.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/LocationTracker.kt
new file mode 100644
index 0000000..6a87832
--- /dev/null
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/LocationTracker.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2010-2024 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 org.jetbrains.kotlin.ir
+
+typealias LocationTracker_Registry = MutableMap<List<StackTraceElement>, MutableSet<List<StackTraceElement>>>
+
+object LocationTracker {
+ init {
+ registerHook()
+ }
+
+ fun initialize() {}
+
+ val attributeOwnerId: LocationTracker_Registry = hashMapOf()
+
+ private fun registerHook() {
+ Runtime.getRuntime().addShutdownHook(Thread {
+ listOf(
+ ::attributeOwnerId,
+ ).forEach { prop ->
+ val name = prop.name
+ print("\n")
+ println("!!! $name")
+ prop.get().forEach { (readLocation, writeLocations) ->
+ print("READ: ")
+ printStackTrace(readLocation)
+ /*writeLocations.forEach { stack ->
+ print("WRITE: ")
+ printStackTrace(stack)
+ }*/
+ print("\n")
+ }
+ }
+ })
+ }
+
+ private fun printStackTrace(stack: List<StackTraceElement>) {
+ stack.firstOrNull()?.let { println(it) }
+ println(stack.drop(1).joinToString("\n") { " $it" })
+ }
+
+ fun recordWriteStackTrace(framesToSkip: Int = 0): List<StackTraceElement> {
+ var countAbove = 0
+ val stack = Throwable().stackTrace
+ .drop(framesToSkip + 1)
+ .takeWhile { frame ->
+ countAbove == 0 && (
+ frame.className.startsWith("org.jetbrains.kotlin.ir")
+ && !frame.className.startsWith("org.jetbrains.kotlin.ir.backend")
+ ) || countAbove++ < 1
+ }
+ .filter { it.className != "org.jetbrains.kotlin.ir.util.DeepCopyIrTreeWithSymbols" }
+ .distinct()
+ return stack
+ }
+
+ fun recordReadStackTrace(registry: LocationTracker_Registry, lastWriteStackTrace: List<StackTraceElement>?, framesToSkip: Int = 0) {
+ var stack = Throwable().stackTrace.toList()
+ if (stack[framesToSkip + 1].let {
+ it.className == "org.jetbrains.kotlin.ir.declarations.IrDeclarationsKt"
+ && it.methodName.removeSuffix("\$default") == "copyAttributes"
+ }
+ ) return
+
+ var countAbove = 0
+ stack = stack
+ .drop(framesToSkip + 1)
+ .groupBy { it.className + it.methodName.removeSuffix("\$default") }.map { it.value[0] }
+ .takeWhile { frame ->
+ countAbove == 0 && (
+ frame.className.startsWith("org.jetbrains.kotlin.ir")
+ && !frame.className.startsWith("org.jetbrains.kotlin.ir.backend")
+ ) || countAbove++ < 1
+ }
+ .takeWhile {
+ !it.className.startsWith("org.jetbrains.kotlin.ir.visitors.") &&
+ !(it.className.startsWith("org.jetbrains.kotlin.ir.") && (it.methodName == "accept" || it.methodName == "transform"))
+ }
+ .distinct()
+
+ if (lastWriteStackTrace != null) {
+ val set = registry.computeIfAbsent(stack) { hashSetOf() }
+ set += lastWriteStackTrace
+ }
+ }
+}
\ No newline at end of file