Commit ecbb53aa authored by Skylot's avatar Skylot

core: fixed 'this' attribute propagation for move insn (#345)

parent ffe739b7
...@@ -102,16 +102,11 @@ public class NameGen { ...@@ -102,16 +102,11 @@ public class NameGen {
if (fallback) { if (fallback) {
return getFallbackName(arg); return getFallbackName(arg);
} }
String name = arg.getName(); if (arg.isThis()) {
String varName; return RegisterArg.THIS_ARG_NAME;
if (name != null) {
if ("this".equals(name)) {
return name;
}
varName = name;
} else {
varName = guessName(arg);
} }
String name = arg.getName();
String varName = name != null ? name : guessName(arg);
if (NameMapper.isReserved(varName)) { if (NameMapper.isReserved(varName)) {
return varName + "R"; return varName + "R";
} }
......
...@@ -140,7 +140,6 @@ public abstract class InsnArg extends Typed { ...@@ -140,7 +140,6 @@ public abstract class InsnArg extends Typed {
} }
public boolean isThis() { public boolean isThis() {
// must be implemented in RegisterArg return contains(AFlag.THIS);
return false;
} }
} }
...@@ -4,7 +4,6 @@ import java.util.Objects; ...@@ -4,7 +4,6 @@ import java.util.Objects;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.InsnType;
import jadx.core.dex.instructions.PhiInsn; import jadx.core.dex.instructions.PhiInsn;
import jadx.core.dex.nodes.DexNode; import jadx.core.dex.nodes.DexNode;
...@@ -13,6 +12,8 @@ import jadx.core.utils.InsnUtils; ...@@ -13,6 +12,8 @@ import jadx.core.utils.InsnUtils;
public class RegisterArg extends InsnArg implements Named { public class RegisterArg extends InsnArg implements Named {
public static final String THIS_ARG_NAME = "this";
protected final int regNum; protected final int regNum;
// not null after SSATransform pass // not null after SSATransform pass
private SSAVar sVar; private SSAVar sVar;
...@@ -44,6 +45,9 @@ public class RegisterArg extends InsnArg implements Named { ...@@ -44,6 +45,9 @@ public class RegisterArg extends InsnArg implements Named {
} }
public String getName() { public String getName() {
if (isThis()) {
return THIS_ARG_NAME;
}
if (sVar == null) { if (sVar == null) {
return null; return null;
} }
...@@ -117,22 +121,6 @@ public class RegisterArg extends InsnArg implements Named { ...@@ -117,22 +121,6 @@ public class RegisterArg extends InsnArg implements Named {
return InsnUtils.getConstValueByInsn(dex, parInsn); return InsnUtils.getConstValueByInsn(dex, parInsn);
} }
@Override
public boolean isThis() {
if (contains(AFlag.THIS)) {
return true;
}
// maybe it was moved from 'this' register
InsnNode ai = getAssignInsn();
if (ai != null && ai.getType() == InsnType.MOVE) {
InsnArg arg = ai.getArg(0);
if (arg != this) {
return arg.isThis();
}
}
return false;
}
public InsnNode getAssignInsn() { public InsnNode getAssignInsn() {
if (sVar == null) { if (sVar == null) {
return null; return null;
...@@ -188,6 +176,9 @@ public class RegisterArg extends InsnArg implements Named { ...@@ -188,6 +176,9 @@ public class RegisterArg extends InsnArg implements Named {
} }
sb.append(" "); sb.append(" ");
sb.append(type); sb.append(type);
if (!isAttrStorageEmpty()) {
sb.append(' ').append(getAttributesString());
}
sb.append(")"); sb.append(")");
return sb.toString(); return sb.toString();
} }
......
...@@ -4,8 +4,6 @@ import org.jetbrains.annotations.NotNull; ...@@ -4,8 +4,6 @@ import org.jetbrains.annotations.NotNull;
public class TypeImmutableArg extends RegisterArg { public class TypeImmutableArg extends RegisterArg {
public static final String THIS_ARG_NAME = "this";
public TypeImmutableArg(int rn, ArgType type) { public TypeImmutableArg(int rn, ArgType type) {
super(rn, type); super(rn, type);
} }
...@@ -21,18 +19,7 @@ public class TypeImmutableArg extends RegisterArg { ...@@ -21,18 +19,7 @@ public class TypeImmutableArg extends RegisterArg {
} }
@Override @Override
public String getName() {
if (isThis()) {
return THIS_ARG_NAME;
}
return super.getName();
}
@Override
void setSVar(@NotNull SSAVar sVar) { void setSVar(@NotNull SSAVar sVar) {
if (isThis()) {
sVar.setName(THIS_ARG_NAME);
}
sVar.setTypeImmutable(type); sVar.setTypeImmutable(type);
super.setSVar(sVar); super.setSVar(sVar);
} }
......
...@@ -89,8 +89,7 @@ public class CodeShrinker extends AbstractVisitor { ...@@ -89,8 +89,7 @@ public class CodeShrinker extends AbstractVisitor {
} }
public WrapInfo checkInline(int assignPos, RegisterArg arg) { public WrapInfo checkInline(int assignPos, RegisterArg arg) {
if (!arg.isThis() if (assignPos >= inlineBorder || !canMove(assignPos, inlineBorder)) {
&& (assignPos >= inlineBorder || !canMove(assignPos, inlineBorder))) {
return null; return null;
} }
inlineBorder = assignPos; inlineBorder = assignPos;
...@@ -214,9 +213,9 @@ public class CodeShrinker extends AbstractVisitor { ...@@ -214,9 +213,9 @@ public class CodeShrinker extends AbstractVisitor {
// continue; // continue;
// } // }
SSAVar sVar = arg.getSVar(); SSAVar sVar = arg.getSVar();
// allow inline only one use arg or 'this' // allow inline only one use arg
if (sVar == null if (sVar == null
|| sVar.getVariableUseCount() != 1 && !arg.isThis() || sVar.getVariableUseCount() != 1
|| sVar.contains(AFlag.DONT_INLINE)) { || sVar.contains(AFlag.DONT_INLINE)) {
continue; continue;
} }
......
...@@ -53,7 +53,7 @@ public class SSATransform extends AbstractVisitor { ...@@ -53,7 +53,7 @@ public class SSATransform extends AbstractVisitor {
fixLastAssignInTry(mth); fixLastAssignInTry(mth);
removeBlockerInsns(mth); removeBlockerInsns(mth);
markThisArg(mth); markThisArgs(mth.getThisArg());
boolean repeatFix; boolean repeatFix;
int k = 0; int k = 0;
...@@ -407,10 +407,30 @@ public class SSATransform extends AbstractVisitor { ...@@ -407,10 +407,30 @@ public class SSATransform extends AbstractVisitor {
return true; return true;
} }
private static void markThisArg(MethodNode mth) { private static void markThisArgs(RegisterArg thisArg) {
RegisterArg thisArg = mth.getThisArg();
if (thisArg != null) { if (thisArg != null) {
thisArg.getSVar().getUseList().forEach(arg -> arg.add(AFlag.THIS)); markOneArgAsThis(thisArg);
thisArg.getSVar().getUseList().forEach(SSATransform::markOneArgAsThis);
}
}
private static void markOneArgAsThis(RegisterArg arg) {
if (arg == null) {
return;
}
arg.add(AFlag.THIS);
arg.setName(RegisterArg.THIS_ARG_NAME);
// mark all moved 'this'
InsnNode parentInsn = arg.getParentInsn();
if (parentInsn != null
&& parentInsn.getType() == InsnType.MOVE
&& parentInsn.getArg(0) == arg) {
RegisterArg resArg = parentInsn.getResult();
if (resArg.getRegNum() != arg.getRegNum()
&& !resArg.getSVar().isUsedInPhi()) {
markThisArgs(resArg);
parentInsn.add(AFlag.SKIP);
}
} }
} }
} }
package jadx.tests.integration.usethis;
import java.util.Random;
import org.junit.Test;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;
import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.junit.Assert.assertThat;
public class TestDontInlineThis extends IntegrationTest {
public static class TestCls {
public int field = new Random().nextInt();
private TestCls test() {
TestCls res;
if (field == 7) {
res = this;
} else {
res = new TestCls();
}
res.method();
return res;
}
private void method() {
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
assertThat(code, containsOne("TestDontInlineThis$TestCls res"));
assertThat(code, containsOne("res = this;"));
assertThat(code, containsOne("res = new TestDontInlineThis$TestCls();"));
}
}
package jadx.tests.integration.usethis;
import java.util.Objects;
import org.junit.Test;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;
import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
public class TestInlineThis2 extends IntegrationTest {
public static class TestCls {
public int field;
private void test() {
TestCls thisVar = this;
if (Objects.isNull(thisVar)) {
System.out.println("null");
}
thisVar.method();
thisVar.field = 123;
}
private void method() {
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
assertThat(code, not(containsString("thisVar")));
assertThat(code, not(containsString("thisVar.method()")));
assertThat(code, not(containsString("thisVar.field")));
assertThat(code, not(containsString("= this")));
assertThat(code, containsOne("if (Objects.isNull(this)) {"));
assertThat(code, containsOne("this.field = 123;"));
assertThat(code, containsOne("method();"));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment