heckej / proguard

ProGuard, Java optimizer and obfuscator with additional optimisations for Kotlin lambda's
https://www.guardsquare.com/en/products/proguard
GNU General Public License v2.0
2 stars 0 forks source link

Fix incomplete instruction replacement in enclosing method of lambda #11

Closed heckej closed 2 years ago

heckej commented 2 years ago

Context

Currently only lambda's with an empty closure are merged. One of the assumptions is that such a lambda always contains a public static field named INSTANCE:

getstatic       #40    // Field app/AppKt$main$lambda1$1.INSTANCE:Lapp/AppKt$main$lambda1$1;
checkcast     #42                 // class kotlin/jvm/functions/Function1

to which an instance of the lambda is assigned in the static constructor of the lambda class.

Problem

In some cases, it appears that some lambda's are not 'instantiated' in their enclosing class by referring to a static INSTANCE field. Instead, the lambda is explicitly instantiated:

new                   #54    // androidx/compose/foundation/layout/BoxScopeInstance$matchParentSize$$inlined$debugInspectorInfo$1
dup
invokespecial    #55    // androidx/compose/foundation/layout/BoxScopeInstance$matchParentSize$$inlined$debugInspectorInfo$1.<init>()V
checkcast kotlin/jvm/functions/Function1

It turns out that the lambda merger only replaces the lambda class reference for the <init>()V constructor. However, also the reference for the new operation should be updated.

Proposed solution

Use an InstructionSequenceReplacer to define the patterns that must be replaced and the instructions by which they should be replaced. The patterns that must be replaced, are the ones mentioned above.

Testing

TODO: find a way to test this

heckej commented 2 years ago

Issue solved by commit 5ff72b15a853132debdd6e12c9cb91ceca6bcfb9