This commit is contained in:
@@ -107,6 +107,10 @@ public class MethodProcessorRunnable implements Runnable {
|
|||||||
|
|
||||||
if (ExceptionDeobfuscator.hasObfuscatedExceptions(graph)) {
|
if (ExceptionDeobfuscator.hasObfuscatedExceptions(graph)) {
|
||||||
DecompilerContext.getLogger().writeMessage("Heavily obfuscated exception ranges found!", IFernflowerLogger.Severity.WARN);
|
DecompilerContext.getLogger().writeMessage("Heavily obfuscated exception ranges found!", IFernflowerLogger.Severity.WARN);
|
||||||
|
if(!ExceptionDeobfuscator.handleMultipleEntryExceptionRanges(graph)) {
|
||||||
|
DecompilerContext.getLogger().writeMessage("Found multiple entry exception ranges which could not be splitted", IFernflowerLogger.Severity.WARN);
|
||||||
|
}
|
||||||
|
ExceptionDeobfuscator.insertDummyExceptionHandlerBlocks(graph, cl.getBytecodeVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
RootStatement root = DomHelper.parseGraph(graph);
|
RootStatement root = DomHelper.parseGraph(graph);
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ public class SimplifyExprentsHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// expr++ and expr--
|
// expr++ and expr--
|
||||||
if (isIPPorIMM(current, next)) {
|
if (isIPPorIMM(current, next) || isIPPorIMM2(current, next)) {
|
||||||
list.remove(index + 1);
|
list.remove(index + 1);
|
||||||
res = true;
|
res = true;
|
||||||
continue;
|
continue;
|
||||||
@@ -458,6 +458,48 @@ public class SimplifyExprentsHelper {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isIPPorIMM2(Exprent first, Exprent second) {
|
||||||
|
|
||||||
|
if (first.type != Exprent.EXPRENT_ASSIGNMENT || second.type != Exprent.EXPRENT_ASSIGNMENT) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AssignmentExprent af = (AssignmentExprent)first;
|
||||||
|
AssignmentExprent as = (AssignmentExprent)second;
|
||||||
|
|
||||||
|
if(as.getRight().type != Exprent.EXPRENT_FUNCTION) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionExprent func = (FunctionExprent)as.getRight();
|
||||||
|
|
||||||
|
if(func.getFuncType() != FunctionExprent.FUNCTION_ADD && func.getFuncType() != FunctionExprent.FUNCTION_SUB) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Exprent econd = func.getLstOperands().get(0);
|
||||||
|
Exprent econst = func.getLstOperands().get(1);
|
||||||
|
|
||||||
|
if(econst.type != Exprent.EXPRENT_CONST && econd.type == Exprent.EXPRENT_CONST && func.getFuncType() == FunctionExprent.FUNCTION_ADD) {
|
||||||
|
econd = econst;
|
||||||
|
econst = func.getLstOperands().get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(econst.type == Exprent.EXPRENT_CONST && ((ConstExprent)econst).hasValueOne()) {
|
||||||
|
if(af.getLeft().equals(econd) && af.getRight().equals(as.getLeft()) && (af.getLeft().getExprentUse() & Exprent.MULTIPLE_USES) != 0) {
|
||||||
|
int type = func.getFuncType() == FunctionExprent.FUNCTION_ADD ? FunctionExprent.FUNCTION_IPP : FunctionExprent.FUNCTION_IMM;
|
||||||
|
|
||||||
|
FunctionExprent ret = new FunctionExprent(type, af.getRight(), func.bytecode);
|
||||||
|
ret.setImplicitType(VarType.VARTYPE_INT);
|
||||||
|
|
||||||
|
af.setRight(ret);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isMonitorExit(Exprent first) {
|
private static boolean isMonitorExit(Exprent first) {
|
||||||
if (first.type == Exprent.EXPRENT_MONITOR) {
|
if (first.type == Exprent.EXPRENT_MONITOR) {
|
||||||
MonitorExprent expr = (MonitorExprent)first;
|
MonitorExprent expr = (MonitorExprent)first;
|
||||||
|
|||||||
@@ -134,8 +134,9 @@ public class DominatorTreeExceptionFilter {
|
|||||||
exit = childid;
|
exit = childid;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// exit = map.containsKey(handler)?-1:mapChild.get(handler); FIXME: Eclipse bug?
|
// after replacing 'new Integer(-1)' with '-1' Eclipse throws a NullPointerException on the following line
|
||||||
exit = map.containsKey(handler) ? -1 : mapChild.get(handler);
|
// could be a bug in Eclipse or some obscure specification glitch, FIXME: needs further investigation
|
||||||
|
exit = map.containsKey(handler) ? new Integer(-1) : mapChild.get(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exit != null) {
|
if (exit != null) {
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import org.jetbrains.java.decompiler.code.SimpleInstructionSequence;
|
|||||||
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
|
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
|
||||||
import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph;
|
import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph;
|
||||||
import org.jetbrains.java.decompiler.code.cfg.ExceptionRangeCFG;
|
import org.jetbrains.java.decompiler.code.cfg.ExceptionRangeCFG;
|
||||||
|
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
||||||
|
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.decompose.GenericDominatorEngine;
|
import org.jetbrains.java.decompiler.modules.decompiler.decompose.GenericDominatorEngine;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraph;
|
import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraph;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraphNode;
|
import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraphNode;
|
||||||
@@ -233,7 +235,7 @@ public class ExceptionDeobfuscator {
|
|||||||
|
|
||||||
if (rangeList.contains(handler)) { // TODO: better removing strategy
|
if (rangeList.contains(handler)) { // TODO: better removing strategy
|
||||||
|
|
||||||
List<BasicBlock> lstRemBlocks = getReachableBlocksRestricted(range, engine);
|
List<BasicBlock> lstRemBlocks = getReachableBlocksRestricted(range.getHandler(), range, engine);
|
||||||
|
|
||||||
if (lstRemBlocks.size() < rangeList.size() || rangeList.size() == 1) {
|
if (lstRemBlocks.size() < rangeList.size() || rangeList.size() == 1) {
|
||||||
for (BasicBlock block : lstRemBlocks) {
|
for (BasicBlock block : lstRemBlocks) {
|
||||||
@@ -249,22 +251,21 @@ public class ExceptionDeobfuscator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<BasicBlock> getReachableBlocksRestricted(ExceptionRangeCFG range, GenericDominatorEngine engine) {
|
private static List<BasicBlock> getReachableBlocksRestricted(BasicBlock start, ExceptionRangeCFG range, GenericDominatorEngine engine) {
|
||||||
|
|
||||||
List<BasicBlock> lstRes = new ArrayList<>();
|
List<BasicBlock> lstRes = new ArrayList<>();
|
||||||
|
|
||||||
LinkedList<BasicBlock> stack = new LinkedList<>();
|
LinkedList<BasicBlock> stack = new LinkedList<>();
|
||||||
Set<BasicBlock> setVisited = new HashSet<>();
|
Set<BasicBlock> setVisited = new HashSet<>();
|
||||||
|
|
||||||
BasicBlock handler = range.getHandler();
|
stack.addFirst(start);
|
||||||
stack.addFirst(handler);
|
|
||||||
|
|
||||||
while (!stack.isEmpty()) {
|
while (!stack.isEmpty()) {
|
||||||
BasicBlock block = stack.removeFirst();
|
BasicBlock block = stack.removeFirst();
|
||||||
|
|
||||||
setVisited.add(block);
|
setVisited.add(block);
|
||||||
|
|
||||||
if (range.getProtectedRange().contains(block) && engine.isDominator(block, handler)) {
|
if (range.getProtectedRange().contains(block) && engine.isDominator(block, start)) {
|
||||||
lstRes.add(block);
|
lstRes.add(block);
|
||||||
|
|
||||||
List<BasicBlock> lstSuccs = new ArrayList<>(block.getSuccs());
|
List<BasicBlock> lstSuccs = new ArrayList<>(block.getSuccs());
|
||||||
@@ -308,4 +309,139 @@ public class ExceptionDeobfuscator {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean handleMultipleEntryExceptionRanges(ControlFlowGraph graph) {
|
||||||
|
|
||||||
|
GenericDominatorEngine engine = new GenericDominatorEngine(new IGraph() {
|
||||||
|
public List<? extends IGraphNode> getReversePostOrderList() {
|
||||||
|
return graph.getReversePostOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<? extends IGraphNode> getRoots() {
|
||||||
|
return new HashSet<>(Collections.singletonList(graph.getFirst()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
engine.initialize();
|
||||||
|
|
||||||
|
boolean found = false;
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
found = false;
|
||||||
|
boolean splitted = false;
|
||||||
|
|
||||||
|
for(ExceptionRangeCFG range : graph.getExceptions()) {
|
||||||
|
Set<BasicBlock> setEntries = getRangeEntries(range);
|
||||||
|
|
||||||
|
if(setEntries.size() > 1) { // multiple-entry protected range
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
if(splitExceptionRange(range, setEntries, graph, engine)) {
|
||||||
|
splitted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!splitted) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return !found;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<BasicBlock> getRangeEntries(ExceptionRangeCFG range) {
|
||||||
|
|
||||||
|
Set<BasicBlock> setEntries = new HashSet<>();
|
||||||
|
Set<BasicBlock> setRange= new HashSet<>(range.getProtectedRange());
|
||||||
|
|
||||||
|
for(BasicBlock block : range.getProtectedRange()) {
|
||||||
|
Set<BasicBlock> setPreds = new HashSet<>(block.getPreds());
|
||||||
|
setPreds.removeAll(setRange);
|
||||||
|
|
||||||
|
if (!setPreds.isEmpty()) {
|
||||||
|
setEntries.add(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return setEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean splitExceptionRange(ExceptionRangeCFG range, Set<BasicBlock> setEntries, ControlFlowGraph graph, GenericDominatorEngine engine) {
|
||||||
|
|
||||||
|
for(BasicBlock entry : setEntries) {
|
||||||
|
List<BasicBlock> lstSubrangeBlocks = getReachableBlocksRestricted(entry, range, engine);
|
||||||
|
if(!lstSubrangeBlocks.isEmpty() && lstSubrangeBlocks.size() < range.getProtectedRange().size()) {
|
||||||
|
// add new range
|
||||||
|
ExceptionRangeCFG subRange = new ExceptionRangeCFG(lstSubrangeBlocks, range.getHandler(), range.getExceptionTypes());
|
||||||
|
graph.getExceptions().add(subRange);
|
||||||
|
// shrink the original range
|
||||||
|
range.getProtectedRange().removeAll(lstSubrangeBlocks);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// should not happen
|
||||||
|
DecompilerContext.getLogger().writeMessage("Inconsistency found while splitting protected range", IFernflowerLogger.Severity.WARN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void insertDummyExceptionHandlerBlocks(ControlFlowGraph graph, int bytecode_version) {
|
||||||
|
|
||||||
|
Map<BasicBlock, Set<ExceptionRangeCFG>> mapRanges = new HashMap<>();
|
||||||
|
for (ExceptionRangeCFG range : graph.getExceptions()) {
|
||||||
|
mapRanges.computeIfAbsent(range.getHandler(), k -> new HashSet<>()).add(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Entry<BasicBlock, Set<ExceptionRangeCFG>> ent : mapRanges.entrySet()) {
|
||||||
|
BasicBlock handler = ent.getKey();
|
||||||
|
Set<ExceptionRangeCFG> ranges = ent.getValue();
|
||||||
|
|
||||||
|
if(ranges.size() == 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(ExceptionRangeCFG range : ranges) {
|
||||||
|
|
||||||
|
// add some dummy instructions to prevent optimizing away the empty block
|
||||||
|
SimpleInstructionSequence seq = new SimpleInstructionSequence();
|
||||||
|
seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}), -1);
|
||||||
|
seq.addInstruction(Instruction.create(CodeConstants.opc_pop, false, CodeConstants.GROUP_GENERAL, bytecode_version, null), -1);
|
||||||
|
|
||||||
|
BasicBlock dummyBlock = new BasicBlock(++graph.last_id);
|
||||||
|
dummyBlock.setSeq(seq);
|
||||||
|
|
||||||
|
graph.getBlocks().addWithKey(dummyBlock, dummyBlock.id);
|
||||||
|
|
||||||
|
// only exception predecessors from this range considered
|
||||||
|
List<BasicBlock> lstPredExceptions = new ArrayList<>(handler.getPredExceptions());
|
||||||
|
lstPredExceptions.retainAll(range.getProtectedRange());
|
||||||
|
|
||||||
|
// replace predecessors
|
||||||
|
for (BasicBlock pred : lstPredExceptions) {
|
||||||
|
pred.replaceSuccessor(handler, dummyBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace handler
|
||||||
|
range.setHandler(dummyBlock);
|
||||||
|
// add common exception edges
|
||||||
|
Set<BasicBlock> commonHandlers = new HashSet<>(handler.getSuccExceptions());
|
||||||
|
for(BasicBlock pred : lstPredExceptions) {
|
||||||
|
commonHandlers.retainAll(pred.getSuccExceptions());
|
||||||
|
}
|
||||||
|
// TODO: more sanity checks?
|
||||||
|
for(BasicBlock commonHandler : commonHandlers) {
|
||||||
|
ExceptionRangeCFG commonRange = graph.getExceptionRange(commonHandler, handler);
|
||||||
|
|
||||||
|
dummyBlock.addSuccessorException(commonHandler);
|
||||||
|
commonRange.getProtectedRange().add(dummyBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
dummyBlock.addSuccessor(handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,7 @@ public class FieldExprent extends Exprent {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getExprentUse() {
|
public int getExprentUse() {
|
||||||
return instance == null ? Exprent.MULTIPLE_USES : instance.getExprentUse() & Exprent.MULTIPLE_USES;
|
return 0; // multiple references to a field considered dangerous in a multithreaded environment, thus no Exprent.MULTIPLE_USES set here
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ public class SingleClassesTest {
|
|||||||
@Test public void testPrivateEmptyConstructor() { doTest("pkg/TestPrivateEmptyConstructor"); }
|
@Test public void testPrivateEmptyConstructor() { doTest("pkg/TestPrivateEmptyConstructor"); }
|
||||||
@Test public void testSynchronizedUnprotected() { doTest("pkg/TestSynchronizedUnprotected"); }
|
@Test public void testSynchronizedUnprotected() { doTest("pkg/TestSynchronizedUnprotected"); }
|
||||||
@Test public void testInterfaceSuper() { doTest("pkg/TestInterfaceSuper"); }
|
@Test public void testInterfaceSuper() { doTest("pkg/TestInterfaceSuper"); }
|
||||||
|
@Test public void testFieldSingleAccess() { doTest("pkg/TestFieldSingleAccess"); }
|
||||||
|
|
||||||
// TODO: fix all below
|
// TODO: fix all below
|
||||||
//@Test public void testPackageInfo() { doTest("pkg/package-info"); }
|
//@Test public void testPackageInfo() { doTest("pkg/package-info"); }
|
||||||
@@ -124,6 +125,7 @@ public class SingleClassesTest {
|
|||||||
@Test public void testGroovyTrait() { doTest("pkg/TestGroovyTrait"); }
|
@Test public void testGroovyTrait() { doTest("pkg/TestGroovyTrait"); }
|
||||||
@Test public void testPrivateClasses() { doTest("pkg/PrivateClasses"); }
|
@Test public void testPrivateClasses() { doTest("pkg/PrivateClasses"); }
|
||||||
@Test public void testSuspendLambda() { doTest("pkg/TestSuspendLambdaKt"); }
|
@Test public void testSuspendLambda() { doTest("pkg/TestSuspendLambdaKt"); }
|
||||||
|
@Test public void testNamedSuspendFun2Kt() { doTest("pkg/TestNamedSuspendFun2Kt"); }
|
||||||
|
|
||||||
private void doTest(String testFile, String... companionFiles) {
|
private void doTest(String testFile, String... companionFiles) {
|
||||||
ConsoleDecompiler decompiler = fixture.getDecompiler();
|
ConsoleDecompiler decompiler = fixture.getDecompiler();
|
||||||
|
|||||||
BIN
testData/classes/pkg/TestFieldSingleAccess.class
Normal file
BIN
testData/classes/pkg/TestFieldSingleAccess.class
Normal file
Binary file not shown.
BIN
testData/classes/pkg/TestNamedSuspendFun2Kt$foo2$1.class
Normal file
BIN
testData/classes/pkg/TestNamedSuspendFun2Kt$foo2$1.class
Normal file
Binary file not shown.
BIN
testData/classes/pkg/TestNamedSuspendFun2Kt.class
Normal file
BIN
testData/classes/pkg/TestNamedSuspendFun2Kt.class
Normal file
Binary file not shown.
40
testData/results/TestFieldSingleAccess.dec
Normal file
40
testData/results/TestFieldSingleAccess.dec
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package pkg;
|
||||||
|
|
||||||
|
public final class TestFieldSingleAccess {
|
||||||
|
public Integer field;
|
||||||
|
|
||||||
|
public final void test() {
|
||||||
|
Integer var10000 = this.field;
|
||||||
|
if (var10000 != null) {
|
||||||
|
System.out.println(var10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void test1() {
|
||||||
|
synchronized(this.field) {
|
||||||
|
System.out.println('1');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class 'pkg/TestFieldSingleAccess' {
|
||||||
|
method 'test ()V' {
|
||||||
|
1 6
|
||||||
|
5 7
|
||||||
|
8 8
|
||||||
|
c 8
|
||||||
|
f 11
|
||||||
|
}
|
||||||
|
|
||||||
|
method 'test1 ()V' {
|
||||||
|
1 14
|
||||||
|
6 14
|
||||||
|
7 15
|
||||||
|
a 15
|
||||||
|
c 15
|
||||||
|
19 17
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Lines mapping:
|
||||||
@@ -3,7 +3,6 @@ public class TestMethodReferenceSameName {
|
|||||||
|
|
||||||
private void foo() {
|
private void foo() {
|
||||||
TestMethodReferenceSameName.R1 var10000 = this.r;// 5
|
TestMethodReferenceSameName.R1 var10000 = this.r;// 5
|
||||||
this.r.getClass();
|
|
||||||
(var10000::foo).run();
|
(var10000::foo).run();
|
||||||
}// 6
|
}// 6
|
||||||
|
|
||||||
@@ -16,19 +15,18 @@ public class TestMethodReferenceSameName {
|
|||||||
class 'TestMethodReferenceSameName' {
|
class 'TestMethodReferenceSameName' {
|
||||||
method 'foo ()V' {
|
method 'foo ()V' {
|
||||||
1 4
|
1 4
|
||||||
5 5
|
e 5
|
||||||
e 6
|
13 6
|
||||||
13 7
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class 'TestMethodReferenceSameName$R1' {
|
class 'TestMethodReferenceSameName$R1' {
|
||||||
method 'foo ()V' {
|
method 'foo ()V' {
|
||||||
0 11
|
0 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Lines mapping:
|
Lines mapping:
|
||||||
5 <-> 5
|
5 <-> 5
|
||||||
6 <-> 8
|
6 <-> 7
|
||||||
9 <-> 12
|
9 <-> 11
|
||||||
|
|||||||
301
testData/results/TestNamedSuspendFun2Kt.dec
Normal file
301
testData/results/TestNamedSuspendFun2Kt.dec
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
import kotlin.Metadata;
|
||||||
|
import kotlin.SuccessOrFailure.Failure;
|
||||||
|
import kotlin.coroutines.Continuation;
|
||||||
|
import kotlin.coroutines.intrinsics.IntrinsicsKt;
|
||||||
|
import kotlin.coroutines.jvm.internal.ContinuationImpl;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
@Metadata(
|
||||||
|
mv = {1, 1, 11},
|
||||||
|
bv = {1, 0, 2},
|
||||||
|
k = 2,
|
||||||
|
xi = 2,
|
||||||
|
d1 = {"\u0000\n\n\u0000\n\u0002\u0010\b\n\u0002\b\u0002\u001a\u0011\u0010\u0000\u001a\u00020\u0001H\u0086@ø\u0001\u0000¢\u0006\u0002\u0010\u0002\u001a\u0011\u0010\u0003\u001a\u00020\u0001H\u0086@ø\u0001\u0000¢\u0006\u0002\u0010\u0002\u0082\u0002\u0004\n\u0002\b\u0019"},
|
||||||
|
d2 = {"bar", "", "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", "foo2"}
|
||||||
|
)
|
||||||
|
public final class TestNamedSuspendFun2Kt {
|
||||||
|
@Nullable
|
||||||
|
public static final Object foo2(@NotNull Continuation<? super Integer> var0) {
|
||||||
|
@Metadata(
|
||||||
|
mv = {1, 1, 11},
|
||||||
|
bv = {1, 0, 2},
|
||||||
|
k = 3,
|
||||||
|
xi = 2,
|
||||||
|
d1 = {"\u0000\u0010\n\u0000\n\u0002\u0010\u0000\n\u0000\n\u0002\u0018\u0002\n\u0002\u0010\b\u0010\u0000\u001a\u0004\u0018\u00010\u00012\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003H\u0086@ø\u0001\u0000"},
|
||||||
|
d2 = {"foo2", "", "continuation", "Lkotlin/coroutines/Continuation;", ""}
|
||||||
|
)
|
||||||
|
final class NamelessClass_1 extends ContinuationImpl {
|
||||||
|
int label;
|
||||||
|
int I$0;
|
||||||
|
Object L$0;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public final Object invokeSuspend(@NotNull Object result) {
|
||||||
|
this.data = result;
|
||||||
|
this.label |= -2147483648;
|
||||||
|
return TestNamedSuspendFun2Kt.foo2(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
NamelessClass_1(Continuation var1) {
|
||||||
|
super(var1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NamelessClass_1 var3;
|
||||||
|
label463: {
|
||||||
|
if (var0 instanceof NamelessClass_1) {
|
||||||
|
var3 = (NamelessClass_1)var0;
|
||||||
|
if ((var3.getLabel() & -2147483648) != 0) {
|
||||||
|
var3.setLabel(var3.getLabel() - -2147483648);
|
||||||
|
break label463;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var3 = new NamelessClass_1(var0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object var4;
|
||||||
|
int x;
|
||||||
|
label491: {
|
||||||
|
Throwable var1;
|
||||||
|
Throwable var10000;
|
||||||
|
label472: {
|
||||||
|
Object var2 = var3.data;
|
||||||
|
var4 = IntrinsicsKt.getCOROUTINE_SUSPENDED();// 2
|
||||||
|
boolean var10001;
|
||||||
|
Object var22;
|
||||||
|
switch(var3.label) {
|
||||||
|
case 0:
|
||||||
|
if (var2 instanceof Failure) {
|
||||||
|
throw ((Failure)var2).exception;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
try {
|
||||||
|
if (var2 instanceof Failure) {
|
||||||
|
throw ((Failure)var2).exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
var22 = var2;
|
||||||
|
} catch (Throwable var19) {
|
||||||
|
var10000 = var19;
|
||||||
|
var10001 = false;
|
||||||
|
break label472;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
x = ((Number)var22).intValue();// 6
|
||||||
|
if (x == 0) {
|
||||||
|
break label491;
|
||||||
|
}
|
||||||
|
} catch (Throwable var17) {
|
||||||
|
var10000 = var17;
|
||||||
|
var10001 = false;
|
||||||
|
break label472;
|
||||||
|
}
|
||||||
|
|
||||||
|
var3.label = 3;
|
||||||
|
if (bar(var3) == var4) {
|
||||||
|
return var4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
x = var3.I$0;
|
||||||
|
if (var2 instanceof Failure) {
|
||||||
|
throw ((Failure)var2).exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;// 11
|
||||||
|
case 3:
|
||||||
|
if (var2 instanceof Failure) {
|
||||||
|
throw ((Failure)var2).exception;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
var1 = (Throwable)var3.L$0;
|
||||||
|
if (var2 instanceof Failure) {
|
||||||
|
throw ((Failure)var2).exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw var1;// 9
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
var3.label = 1;// 5
|
||||||
|
var22 = bar(var3);
|
||||||
|
} catch (Throwable var18) {
|
||||||
|
var10000 = var18;
|
||||||
|
var10001 = false;
|
||||||
|
break label472;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (var22 == var4) {
|
||||||
|
return var4;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
x = ((Number)var22).intValue();
|
||||||
|
if (x == 0) {
|
||||||
|
break label491;
|
||||||
|
}
|
||||||
|
} catch (Throwable var20) {
|
||||||
|
var10000 = var20;
|
||||||
|
var10001 = false;
|
||||||
|
break label472;
|
||||||
|
}
|
||||||
|
|
||||||
|
var3.label = 3;
|
||||||
|
} while(bar(var3) != var4);
|
||||||
|
|
||||||
|
return var4;
|
||||||
|
}
|
||||||
|
|
||||||
|
var1 = var10000;
|
||||||
|
var3.L$0 = var1;
|
||||||
|
var3.label = 4;
|
||||||
|
if (bar(var3) == var4) {// 8
|
||||||
|
return var4;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw var1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var3.I$0 = x;
|
||||||
|
var3.label = 2;
|
||||||
|
if (bar(var3) == var4) {
|
||||||
|
return var4;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static final Object bar(@NotNull Continuation<? super Integer> var0) {
|
||||||
|
return 0;// 14
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class 'TestNamedSuspendFun2Kt$foo2$1' {
|
||||||
|
method 'invokeSuspend (Ljava/lang/Object;)Ljava/lang/Object;' {
|
||||||
|
2 34
|
||||||
|
a 35
|
||||||
|
d 35
|
||||||
|
11 36
|
||||||
|
14 36
|
||||||
|
}
|
||||||
|
|
||||||
|
method '<init> (Lkotlin/coroutines/Continuation;)V' {
|
||||||
|
2 40
|
||||||
|
5 41
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class 'TestNamedSuspendFun2Kt' {
|
||||||
|
method 'foo2 (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;' {
|
||||||
|
1 46
|
||||||
|
4 46
|
||||||
|
8 47
|
||||||
|
b 47
|
||||||
|
d 48
|
||||||
|
10 48
|
||||||
|
12 48
|
||||||
|
13 48
|
||||||
|
18 49
|
||||||
|
1b 49
|
||||||
|
1d 49
|
||||||
|
1e 49
|
||||||
|
21 50
|
||||||
|
2c 54
|
||||||
|
2e 63
|
||||||
|
31 63
|
||||||
|
32 64
|
||||||
|
35 64
|
||||||
|
38 67
|
||||||
|
3b 67
|
||||||
|
5e 69
|
||||||
|
61 69
|
||||||
|
64 70
|
||||||
|
67 70
|
||||||
|
6a 70
|
||||||
|
6f 127
|
||||||
|
70 127
|
||||||
|
73 128
|
||||||
|
79 135
|
||||||
|
7e 136
|
||||||
|
81 75
|
||||||
|
84 75
|
||||||
|
87 76
|
||||||
|
8a 76
|
||||||
|
8d 76
|
||||||
|
90 87
|
||||||
|
93 87
|
||||||
|
96 87
|
||||||
|
98 88
|
||||||
|
9e 166
|
||||||
|
a2 167
|
||||||
|
a3 167
|
||||||
|
a6 168
|
||||||
|
ac 168
|
||||||
|
b1 169
|
||||||
|
b3 103
|
||||||
|
b6 103
|
||||||
|
b9 104
|
||||||
|
bc 104
|
||||||
|
bf 105
|
||||||
|
c2 105
|
||||||
|
c5 105
|
||||||
|
c9 108
|
||||||
|
ce 97
|
||||||
|
cf 97
|
||||||
|
d2 98
|
||||||
|
d8 98
|
||||||
|
dd 99
|
||||||
|
e0 110
|
||||||
|
e3 110
|
||||||
|
e6 111
|
||||||
|
e9 111
|
||||||
|
ec 111
|
||||||
|
f3 156
|
||||||
|
f7 157
|
||||||
|
fb 158
|
||||||
|
fc 158
|
||||||
|
ff 159
|
||||||
|
105 159
|
||||||
|
10a 160
|
||||||
|
10c 115
|
||||||
|
10f 115
|
||||||
|
112 115
|
||||||
|
115 116
|
||||||
|
118 116
|
||||||
|
11b 117
|
||||||
|
11e 117
|
||||||
|
121 117
|
||||||
|
126 120
|
||||||
|
12a 108
|
||||||
|
12b 108
|
||||||
|
133 122
|
||||||
|
138 122
|
||||||
|
}
|
||||||
|
|
||||||
|
method 'bar (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;' {
|
||||||
|
0 177
|
||||||
|
1 177
|
||||||
|
4 177
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Lines mapping:
|
||||||
|
2 <-> 65
|
||||||
|
5 <-> 128
|
||||||
|
6 <-> 88
|
||||||
|
8 <-> 160
|
||||||
|
9 <-> 121
|
||||||
|
11 <-> 109
|
||||||
|
14 <-> 178
|
||||||
|
Not mapped:
|
||||||
|
3
|
||||||
|
4
|
||||||
67
testData/src/pkg/TestFieldSingleAccess.jasm
Normal file
67
testData/src/pkg/TestFieldSingleAccess.jasm
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* This code can be assembled with <a href="https://wiki.openjdk.java.net/display/CodeTools/asmtools">asmtools</a>
|
||||||
|
* using <code>asmtools jasm -g *.jasm</code> command line.
|
||||||
|
*/
|
||||||
|
package pkg;
|
||||||
|
|
||||||
|
super public final class TestFieldSingleAccess
|
||||||
|
version 52:0
|
||||||
|
{
|
||||||
|
|
||||||
|
public Field field:"Ljava/lang/Integer;";
|
||||||
|
|
||||||
|
public Method "<init>":"()V"
|
||||||
|
stack 1 locals 1
|
||||||
|
{
|
||||||
|
aload_0;
|
||||||
|
invokespecial Method java/lang/Object."<init>":"()V";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Method test:"()V"
|
||||||
|
stack 2 locals 1
|
||||||
|
{
|
||||||
|
aload_0;
|
||||||
|
getfield Field field:"Ljava/lang/Integer;";
|
||||||
|
dup;
|
||||||
|
ifnull L17;
|
||||||
|
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
|
||||||
|
swap;
|
||||||
|
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/Object;)V";
|
||||||
|
L17: stack_frame_type same;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Method test1:"()V"
|
||||||
|
stack 2 locals 3
|
||||||
|
{
|
||||||
|
aload_0;
|
||||||
|
getfield Field field:"Ljava/lang/Integer;";
|
||||||
|
dup;
|
||||||
|
astore_1;
|
||||||
|
monitorenter;
|
||||||
|
try t0;
|
||||||
|
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
|
||||||
|
bipush 49;
|
||||||
|
invokevirtual Method java/io/PrintStream.println:"(C)V";
|
||||||
|
aload_1;
|
||||||
|
monitorexit;
|
||||||
|
endtry t0;
|
||||||
|
goto L25;
|
||||||
|
catch t0 #0;
|
||||||
|
catch t1 #0;
|
||||||
|
try t1;
|
||||||
|
stack_frame_type full;
|
||||||
|
locals_map class TestFieldSingleAccess, class java/lang/Object;
|
||||||
|
stack_map class java/lang/Throwable;
|
||||||
|
astore_2;
|
||||||
|
aload_1;
|
||||||
|
monitorexit;
|
||||||
|
endtry t1;
|
||||||
|
aload_2;
|
||||||
|
athrow;
|
||||||
|
L25: stack_frame_type chop1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end Class TestFieldSingleAccess
|
||||||
14
testData/src/pkg/TestNamedSuspendFun2.kt
Normal file
14
testData/src/pkg/TestNamedSuspendFun2.kt
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
suspend fun foo2(): Int {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
val x = bar()
|
||||||
|
if (x == 0) break
|
||||||
|
} finally {
|
||||||
|
bar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun bar(): Int = 0
|
||||||
Reference in New Issue
Block a user