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:
@@ -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
|
||||
Reference in New Issue
Block a user