Skip to content

Commit

Permalink
Do not inline methods from interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
tvoc-gs authored and dimitrisAnyfantakis committed Sep 21, 2023
1 parent 9a7a97d commit 8bb7cc0
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,14 @@ public void visitProgramMethod(ProgramClass programClass, ProgramMethod programM
AccessConstants.STATIC |
AccessConstants.FINAL)) != 0 &&

DEBUG("Interface?") &&

// Methods in interfaces should not be inlined since this can potentially
// lead to other methods in the interface needing broadened visibility,
// which can lead to either compilation errors during output writing
// or various issues at runtime.
(programClass.getAccessFlags() & AccessConstants.INTERFACE) == 0 &&

DEBUG("Synchronized?") &&

// Only inline the method if it is not synchronized, etc.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,60 @@ class MethodInlinerTest : FreeSpec({
}
}
}

"Given a method calling another method in an interface" - {
val (programClassPool, _) = ClassPoolBuilder.fromSource(
JavaSource(
"Foo.java",
"""interface Foo {
default void f1() {
f2();
}

static void f2() {
StringBuilder sb = new StringBuilder();
sb.append(System.currentTimeMillis());
System.out.println(sb.toString());
}
}"""
)
)

val clazz = programClassPool.getClass("Foo") as ProgramClass
val method = clazz.findMethod("f1", "()V") as ProgramMethod
val codeAttr = method.attributes.filterIsInstance<CodeAttribute>()[0]

val lengthBefore = codeAttr.u4codeLength

// Initialize optimization info (used when inlining).
val optimizationInfoInitializer: ClassVisitor = MultiClassVisitor(
ProgramClassOptimizationInfoSetter(),
AllMethodVisitor(
ProgramMemberOptimizationInfoSetter()
)
)

programClassPool.classesAccept(optimizationInfoInitializer)

// Create a mock method inliner which always returns true.
val methodInliner = object : MethodInliner(false, true, true) {
override fun shouldInline(clazz: Clazz?, method: Method?, codeAttribute: CodeAttribute?): Boolean = true
}

"Then the interface method is not inlined" {
programClassPool.classesAccept(
AllMethodVisitor(
AllAttributeVisitor(
methodInliner
)
)
)

val lengthAfter = codeAttr.u4codeLength

lengthAfter shouldBeExactly lengthBefore
}
}
})

private fun printProgramMethodInstructions(
Expand Down
1 change: 1 addition & 0 deletions docs/md/manual/releasenotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- Fix "NoClassDefFoundError: Failed resolution of: Lorg/apache/logging/log4j/LogManager" when using GSON optimization or `-addconfigurationdebugging`. (#326)
- Don't drop Record attribute for records with no components. (proguard-core#118)
- Fix potential duplication class when name obfuscating Kotlin multi-file facades.
- Do not inline interface methods to avoid compilation errors during output writing due to an interface method being made package visible.

## Version 7.3.2

Expand Down

0 comments on commit 8bb7cc0

Please sign in to comment.