fix: allow to inline variables around 'monitor-exit' in synchronized block
This commit is contained in:
@@ -21,6 +21,7 @@ import jadx.core.dex.visitors.ModVisitor;
|
||||
import jadx.core.utils.BlockUtils;
|
||||
import jadx.core.utils.InsnList;
|
||||
import jadx.core.utils.InsnRemover;
|
||||
import jadx.core.utils.RegionUtils;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
@JadxVisitor(
|
||||
@@ -109,7 +110,7 @@ public class CodeShrinkVisitor extends AbstractVisitor {
|
||||
BlockNode assignBlock = BlockUtils.getBlockByInsn(mth, assignInsn);
|
||||
if (assignBlock != null
|
||||
&& assignInsn != arg.getParentInsn()
|
||||
&& canMoveBetweenBlocks(assignInsn, assignBlock, block, argsInfo.getInsn())) {
|
||||
&& canMoveBetweenBlocks(mth, assignInsn, assignBlock, block, argsInfo.getInsn())) {
|
||||
if (assignInline) {
|
||||
assignInline(mth, arg, assignInsn, assignBlock);
|
||||
} else {
|
||||
@@ -150,7 +151,7 @@ public class CodeShrinkVisitor extends AbstractVisitor {
|
||||
return replaced;
|
||||
}
|
||||
|
||||
private static boolean canMoveBetweenBlocks(InsnNode assignInsn, BlockNode assignBlock,
|
||||
private static boolean canMoveBetweenBlocks(MethodNode mth, InsnNode assignInsn, BlockNode assignBlock,
|
||||
BlockNode useBlock, InsnNode useInsn) {
|
||||
if (!BlockUtils.isPathExists(assignBlock, useBlock)) {
|
||||
return false;
|
||||
@@ -176,8 +177,12 @@ public class CodeShrinkVisitor extends AbstractVisitor {
|
||||
for (BlockNode block : pathsBlocks) {
|
||||
if (block.contains(AFlag.DONT_GENERATE)) {
|
||||
if (BlockUtils.checkLastInsnType(block, InsnType.MONITOR_EXIT)) {
|
||||
// don't move from synchronized block
|
||||
return false;
|
||||
if (RegionUtils.isBlocksInSameRegion(mth, assignBlock, useBlock)) {
|
||||
// allow move inside same synchronized region
|
||||
} else {
|
||||
// don't move from synchronized block
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// skip checks for not generated blocks
|
||||
continue;
|
||||
|
||||
@@ -19,6 +19,8 @@ import jadx.core.dex.nodes.IBranchRegion;
|
||||
import jadx.core.dex.nodes.IContainer;
|
||||
import jadx.core.dex.nodes.IRegion;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.regions.Region;
|
||||
import jadx.core.dex.trycatch.CatchAttr;
|
||||
import jadx.core.dex.trycatch.ExceptionHandler;
|
||||
import jadx.core.dex.trycatch.TryCatchBlock;
|
||||
@@ -329,6 +331,26 @@ public class RegionUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if two blocks in same region on same level
|
||||
* TODO: Add 'region' annotation to all blocks to speed up checks
|
||||
*/
|
||||
public static boolean isBlocksInSameRegion(MethodNode mth, BlockNode firstBlock, BlockNode secondBlock) {
|
||||
Region region = mth.getRegion();
|
||||
if (region == null) {
|
||||
return false;
|
||||
}
|
||||
IContainer firstContainer = getBlockContainer(region, firstBlock);
|
||||
if (firstContainer instanceof IRegion) {
|
||||
if (firstContainer instanceof IBranchRegion) {
|
||||
return false;
|
||||
}
|
||||
List<IContainer> subBlocks = ((IRegion) firstContainer).getSubBlocks();
|
||||
return subBlocks.contains(secondBlock);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isDominatedBy(BlockNode dom, IContainer cont) {
|
||||
if (dom == cont) {
|
||||
return true;
|
||||
|
||||
@@ -26,6 +26,8 @@ public class TestSynchronized4 extends SmaliTest {
|
||||
public void test() {
|
||||
assertThat(getClassNodeFromSmali())
|
||||
.code()
|
||||
.containsOne("synchronized (this.obj) {");
|
||||
.containsOne("synchronized (this.obj) {")
|
||||
.containsOne("return call(this.obj, i);")
|
||||
.containsOne("return getField() == null;");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user