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() {