Fix exception handling during deoptimization
When interpreting a deoptimized shadow frame, we may start with a
pending exception thrown by a previous deoptimized shadow frame (from
a previous invoke). Therefore, we need to handle it before executing
any instruction, otherwise we execute incorrect code.
Because we need the DEX pc of the throwing instruction to find a
matching catch handler, we initialize deoptimized shadow frames with
the current DEX pc at the time the stack is deoptimized.
When we are about to interpret a deoptimized shadow frame, we need to
update the shadow frame with the DEX pc of the next instruction to
interpret. There are three cases:
- if there is no pending exception, this is the instruction following
the current one.
- if there is a pending exception and we found a matching catch
handler, this is the first instruction of this handler.
- if there is a pending exception but there is no matching catch
handler, we do not execute the deoptimized shadow frame and continue
to its caller.
The verifier now fails when a method starts with a move-exception
instruction. Indeed we cannot start executing a method with a pending
exception.
Bug: 19057915
Bug: 19041195
Bug: 18607595
Change-Id: I355ac81e6ac098edc7e3cc8c13dbfa24a2969ab2
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index 2eda850..b23896d 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -50,25 +50,33 @@
// Create the test cases.
testCases = new LinkedList<TestCase>();
testCases.add(new TestCase("PackedSwitch", "PackedSwitch", "packedSwitch",
- new Object[]{123}, null, 123));
+ new Object[]{123}, null, 123));
testCases.add(new TestCase("b/17790197", "B17790197", "getInt", null, null, 100));
- testCases.add(new TestCase("b/17978759", "B17978759", "test", null, new VerifyError(), null));
+ testCases.add(new TestCase("b/17978759", "B17978759", "test", null, new VerifyError(),
+ null));
testCases.add(new TestCase("FloatBadArgReg", "FloatBadArgReg", "getInt",
- new Object[]{100}, null, 100));
+ new Object[]{100}, null, 100));
testCases.add(new TestCase("negLong", "negLong", "negLong", null, null, 122142L));
testCases.add(new TestCase("sameFieldNames", "sameFieldNames", "getInt", null, null, 7));
testCases.add(new TestCase("b/18380491", "B18380491ConcreteClass", "foo",
- new Object[]{42}, null, 42));
+ new Object[]{42}, null, 42));
testCases.add(new TestCase("invoke-super abstract", "B18380491ConcreteClass", "foo",
- new Object[]{0}, new AbstractMethodError(), null));
- testCases.add(new TestCase("BadCaseInOpRegRegReg", "BadCaseInOpRegRegReg", "getInt", null, null, 2));
+ new Object[]{0}, new AbstractMethodError(), null));
+ testCases.add(new TestCase("BadCaseInOpRegRegReg", "BadCaseInOpRegRegReg", "getInt", null,
+ null, 2));
testCases.add(new TestCase("CmpLong", "CmpLong", "run", null, null, 0));
- testCases.add(new TestCase("FloatIntConstPassing", "FloatIntConstPassing", "run", null, null, 2));
+ testCases.add(new TestCase("FloatIntConstPassing", "FloatIntConstPassing", "run", null,
+ null, 2));
testCases.add(new TestCase("b/18718277", "B18718277", "getInt", null, null, 0));
- testCases.add(new TestCase("b/18800943 (1)", "B18800943_1", "n_a", null, new VerifyError(), 0));
- testCases.add(new TestCase("b/18800943 (2)", "B18800943_2", "n_a", null, new VerifyError(), 0));
- testCases.add(new TestCase("MoveExc", "MoveExc", "run", null, new ArithmeticException(), null));
+ testCases.add(new TestCase("b/18800943 (1)", "B18800943_1", "n_a", null, new VerifyError(),
+ 0));
+ testCases.add(new TestCase("b/18800943 (2)", "B18800943_2", "n_a", null, new VerifyError(),
+ 0));
+ testCases.add(new TestCase("MoveExc", "MoveExc", "run", null, new ArithmeticException(),
+ null));
+ testCases.add(new TestCase("MoveExceptionOnEntry", "MoveExceptionOnEntry",
+ "moveExceptionOnEntry", new Object[]{0}, new VerifyError(), null));
}
public void runTests() {