Skip to content

Commit e16f5a8

Browse files
mazhukinevgeniySpace Team
authored andcommitted
[IC] Update inline function snapshotting
This is a more robust version with extra tests and better support for non-lambda local classes ^KT-75883
1 parent 5f12d8b commit e16f5a8

File tree

13 files changed

+248
-74
lines changed

13 files changed

+248
-74
lines changed

build-common/src/org/jetbrains/kotlin/incremental/impl/ExtraClassInfoGenerator.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,16 @@ open class ExtraClassInfoGenerator() {
2525
return classNode
2626
}
2727

28-
protected open fun calculateInlineMethodHash(methodSignature: JvmMemberSignature.Method, ownMethodHash: Long): Long {
28+
/**
29+
* @param methodSignature well-typed method signature. doesn't include the containing class' internal name
30+
* @param inlinedClassPrefix - includes class internal name and method name. example value is "com/bar/OuterClass$InnerClass$calculate"
31+
* @param ownMethodHash - a basic intuition is that it's based on bytecode and debug info
32+
*/
33+
protected open fun calculateInlineMethodHash(
34+
methodSignature: JvmMemberSignature.Method,
35+
inlinedClassPrefix: String,
36+
ownMethodHash: Long
37+
): Long {
2938
return ownMethodHash
3039
}
3140

@@ -89,8 +98,9 @@ open class ExtraClassInfoGenerator() {
8998
// class metadata (also in the source file), but not in the bytecode. However, we can safely ignore those
9099
// inline functions/accessors because they are not declared in the bytecode and therefore can't be referenced.
91100
val methodSignature = JvmMemberSignature.Method(name = methodNode.name, desc = methodNode.desc)
101+
val innerClassPrefix = "${classNode.name}\$${methodNode.name}"
92102
var methodHash = snapshotMethod(methodNode, classNode.version)
93-
inlineFunctionsAndAccessors[methodSignature]!! to calculateInlineMethodHash(methodSignature, methodHash)
103+
inlineFunctionsAndAccessors[methodSignature]!! to calculateInlineMethodHash(methodSignature, innerClassPrefix, methodHash)
94104
}
95105

96106
return ExtraInfo(classSnapshotExcludingMembers, constantSnapshots, inlineFunctionOrAccessorSnapshots)

build-common/src/org/jetbrains/kotlin/incremental/impl/InstanceOwnerRecordingClassVisitor.kt

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,26 @@ class InstanceOwnerRecordingClassVisitor(
3232

3333
return object : MethodVisitor(Opcodes.ASM9, super.visitMethod(access, name, descriptor, signature, exceptions)) {
3434
override fun visitFieldInsn(opcode: Int, owner: String?, name: String?, descriptor: String?) {
35-
if (owner != null && opcode == Opcodes.GETSTATIC && name == "INSTANCE") {
36-
val jvmClassName = JvmClassName.byInternalName(owner)
37-
methodToUsedClassesMap?.getOrPut(methodSignature) { mutableSetOf() }?.add(jvmClassName)
38-
allUsedClassesSet?.add(jvmClassName)
35+
if (opcode == Opcodes.GETSTATIC && name == "INSTANCE" && owner?.contains("$") == true) {
36+
storeUsage(owner)
3937
}
4038
super.visitFieldInsn(opcode, owner, name, descriptor)
4139
}
40+
41+
override fun visitTypeInsn(opcode: Int, type: String?) {
42+
if (opcode == Opcodes.NEW && type?.contains("$") == true) {
43+
// here we might be instantiating a class from another inline function in the same module
44+
// better safe than sorry, so:
45+
storeUsage(type)
46+
}
47+
super.visitTypeInsn(opcode, type)
48+
}
49+
50+
private fun storeUsage(internalName: String) {
51+
val jvmClassName = JvmClassName.byInternalName(internalName)
52+
methodToUsedClassesMap?.getOrPut(methodSignature) { mutableSetOf() }?.add(jvmClassName)
53+
allUsedClassesSet?.add(jvmClassName)
54+
}
4255
}
4356
}
4457
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
val result = calculateA()
2+
3+
fun main(args: Array<String>) {
4+
println(result)
5+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
inline fun calculateA(): Int {
2+
return calculateB()
3+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
inline fun calculateB(): Int {
2+
val calculator = object {
3+
fun calc(): Int = 42
4+
}
5+
return calculator.calc()
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
inline fun calculateB(): Int {
2+
val calculator = object {
3+
fun calc(): Int = 42 + 3
4+
}
5+
return calculator.calc()
6+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
val result = calculateA()
2+
3+
fun main(args: Array<String>) {
4+
println(result)
5+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
inline fun calculateA(): Int {
2+
return calculateB()
3+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
interface NiceType {
2+
fun calc(): Int
3+
}
4+
5+
inline fun calculateB(): Int {
6+
val calculator = object : NiceType {
7+
override fun calc(): Int = 42
8+
}
9+
return calculator.calc()
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
interface NiceType {
2+
fun calc(): Int
3+
}
4+
5+
inline fun calculateB(): Int {
6+
val calculator = object : NiceType {
7+
override fun calc(): Int = 42 + 3
8+
}
9+
return calculator.calc()
10+
}

0 commit comments

Comments
 (0)