fix: improve inlining synthetic accessors (PR #2243)

* fix: fix inlining synthetic accessors

* add test, undo changes in InsnNode

---------

Co-authored-by: Skylot <118523+skylot@users.noreply.github.com>
This commit is contained in:
pubiqq
2024-08-08 22:27:08 +03:00
committed by GitHub
parent 1b08779536
commit 60fb458024
6 changed files with 136 additions and 13 deletions
@@ -95,6 +95,10 @@ public class InsnNode extends LineAttrNode {
return arguments;
}
public List<InsnArg> getArgList() {
return arguments;
}
public int getArgsCount() {
return arguments.size();
}
@@ -20,6 +20,7 @@ import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.utils.BlockUtils;
import jadx.core.utils.ListUtils;
import jadx.core.utils.exceptions.JadxException;
@JadxVisitor(
@@ -42,18 +43,22 @@ public class MarkMethodsForInline extends AbstractVisitor {
*/
@Nullable
public static MethodInlineAttr process(MethodNode mth) {
MethodInlineAttr mia = mth.get(AType.METHOD_INLINE);
if (mia != null) {
return mia;
}
if (mth.contains(AFlag.METHOD_CANDIDATE_FOR_INLINE)) {
if (mth.getBasicBlocks() == null) {
return null;
try {
MethodInlineAttr mia = mth.get(AType.METHOD_INLINE);
if (mia != null) {
return mia;
}
MethodInlineAttr inlined = inlineMth(mth);
if (inlined != null) {
return inlined;
if (mth.contains(AFlag.METHOD_CANDIDATE_FOR_INLINE)) {
if (mth.getBasicBlocks() == null) {
return null;
}
MethodInlineAttr inlined = inlineMth(mth);
if (inlined != null) {
return inlined;
}
}
} catch (Exception e) {
mth.addWarnComment("Method inline analysis failed", e);
}
return MethodInlineAttr.inlineNotNeeded(mth);
}
@@ -113,9 +118,12 @@ public class MarkMethodsForInline extends AbstractVisitor {
&& firstInsn.getArg(0).isSameVar(mthRegs.get(0));
case INVOKE:
return !mthRegs.isEmpty()
&& firstInsn.getArg(0).isSameVar(mthRegs.get(0))
&& retInsn.getArg(0).isSameVar(firstInsn.getResult());
if (!retInsn.getArg(0).isSameVar(firstInsn.getResult())) {
return false;
}
return ListUtils.orderedEquals(
mth.getArgRegs(), firstInsn.getArgList(),
(mthArg, insnArg) -> insnArg.isSameVar(mthArg));
default:
return false;
}
@@ -4,11 +4,13 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -30,6 +32,25 @@ public class ListUtils {
return first.containsAll(second);
}
public static <T, U> boolean orderedEquals(List<T> list1, List<U> list2, BiPredicate<T, U> comparer) {
if (list1 == list2) {
return true;
}
if (list1.size() != list2.size()) {
return false;
}
final Iterator<T> iter1 = list1.iterator();
final Iterator<U> iter2 = list2.iterator();
while (iter1.hasNext() && iter2.hasNext()) {
final T item1 = iter1.next();
final U item2 = iter2.next();
if (!comparer.test(item1, item2)) {
return false;
}
}
return !iter1.hasNext() && !iter2.hasNext();
}
public static <T, R> List<R> map(Collection<T> list, Function<T, R> mapFunc) {
if (list == null || list.isEmpty()) {
return Collections.emptyList();
@@ -0,0 +1,23 @@
package jadx.tests.integration.inline;
import java.util.List;
import org.junit.jupiter.api.Test;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.SmaliTest;
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
public class TestSyntheticClassInline extends SmaliTest {
@Test
public void test() {
List<ClassNode> classes = loadFromSmaliFiles();
assertThat(searchCls(classes, "inline.A"))
.code()
.containsOne("static Supplier<Long> test(final long x1, final long x2) {")
.containsOne("return new Supplier() {")
.containsOne("return A.lambda$test$0(x1, x2);");
}
}
@@ -0,0 +1,42 @@
.class Linline/A;
.super Ljava/lang/Object;
.source "TestJavaClass.java"
.method constructor <init>()V
.registers 1
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
.method static synthetic lambda$test$0(JJ)Ljava/lang/Long;
.registers 8
.param p0, "x1" # J
.param p2, "x2" # J
invoke-static {}, Ljava/lang/System;->currentTimeMillis()J
move-result-wide v0
.local v0, "y1":J
add-long v2, p0, v0
add-long/2addr v2, p2
invoke-static {v2, v3}, Ljava/lang/Long;->valueOf(J)Ljava/lang/Long;
move-result-object v2
return-object v2
.end method
.method static test(JJ)Ljava/util/function/Supplier;
.registers 5
.param p0, "x1" # J
.param p2, "x2" # J
.annotation system Ldalvik/annotation/Signature;
value = {
"(JJ)",
"Ljava/util/function/Supplier<",
"Ljava/lang/Long;",
">;"
}
.end annotation
new-instance v0, Linline/A$$ExternalSyntheticLambda0;
invoke-direct {v0, p0, p1, p2, p3}, Linline/A$$ExternalSyntheticLambda0;-><init>(JJ)V
return-object v0
.end method
@@ -0,0 +1,25 @@
.class public final synthetic Linline/A$$ExternalSyntheticLambda0;
.super Ljava/lang/Object;
.source "D8$$SyntheticClass"
.implements Ljava/util/function/Supplier;
.field public final synthetic f$0:J
.field public final synthetic f$1:J
.method public synthetic constructor <init>(JJ)V
.registers 5
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
iput-wide p1, p0, Linline/A$$ExternalSyntheticLambda0;->f$0:J
iput-wide p3, p0, Linline/A$$ExternalSyntheticLambda0;->f$1:J
return-void
.end method
.method public final get()Ljava/lang/Object;
.registers 5
iget-wide v0, p0, Linline/A$$ExternalSyntheticLambda0;->f$0:J
iget-wide v2, p0, Linline/A$$ExternalSyntheticLambda0;->f$1:J
invoke-static {v0, v1, v2, v3}, Linline/A;->lambda$test$0(JJ)Ljava/lang/Long;
move-result-object v0
return-object v0
.end method