Fix one crash on deoptimization.

When a full fragment deoptimization (using the deoptimization exception)
happens on a call stack fragment which only has:
art_quick_invoke_stub -> art_quick_to_interpreter_bridge

We do not create a shadow frame. This wasn't expected by
Thread::DeoptimizeWithDeoptimizationException.

Test: 844-exception2
Change-Id: I55377356302fe5d9519af557bf3c0da97e893dc1
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 3369e5d..39f679a 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -4685,25 +4685,29 @@
 void Thread::DeoptimizeWithDeoptimizationException(JValue* result) {
   DCHECK_EQ(GetException(), Thread::GetDeoptimizationException());
   ClearException();
-  ShadowFrame* shadow_frame = MaybePopDeoptimizedStackedShadowFrame();
-  DCHECK_NE(shadow_frame, nullptr);
   ObjPtr<mirror::Throwable> pending_exception;
   bool from_code = false;
   DeoptimizationMethodType method_type;
   PopDeoptimizationContext(result, &pending_exception, &from_code, &method_type);
   SetTopOfStack(nullptr);
-  SetTopOfShadowStack(shadow_frame);
 
   // Restore the exception that was pending before deoptimization then interpret the
   // deoptimized frames.
   if (pending_exception != nullptr) {
     SetException(pending_exception);
   }
-  interpreter::EnterInterpreterFromDeoptimize(this,
-                                              shadow_frame,
-                                              result,
-                                              from_code,
-                                              method_type);
+
+  ShadowFrame* shadow_frame = MaybePopDeoptimizedStackedShadowFrame();
+  // We may not have a shadow frame if we deoptimized at the return of the
+  // quick_to_interpreter_bridge which got directly called by art_quick_invoke_stub.
+  if (shadow_frame != nullptr) {
+    SetTopOfShadowStack(shadow_frame);
+    interpreter::EnterInterpreterFromDeoptimize(this,
+                                                shadow_frame,
+                                                result,
+                                                from_code,
+                                                method_type);
+  }
 }
 
 void Thread::SetAsyncException(ObjPtr<mirror::Throwable> new_exception) {
diff --git a/test/844-exception2/expected-stderr.txt b/test/844-exception2/expected-stderr.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/844-exception2/expected-stderr.txt
diff --git a/test/844-exception2/expected-stdout.txt b/test/844-exception2/expected-stdout.txt
new file mode 100644
index 0000000..7ddf8e3
--- /dev/null
+++ b/test/844-exception2/expected-stdout.txt
@@ -0,0 +1,2 @@
+JNI_OnLoad called
+Caught exception
diff --git a/test/844-exception2/info.txt b/test/844-exception2/info.txt
new file mode 100644
index 0000000..641dc72
--- /dev/null
+++ b/test/844-exception2/info.txt
@@ -0,0 +1,2 @@
+Regression test for Thread::DeoptimizeWithDeoptimizationException which always
+expected to have a shadow frame to execute.
diff --git a/test/844-exception2/src/Main.java b/test/844-exception2/src/Main.java
new file mode 100644
index 0000000..400b337
--- /dev/null
+++ b/test/844-exception2/src/Main.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+  public static class Inner {
+    // Use a <clinit> method to ensure we execute in the
+    // interpreter.
+    static {
+      Main.callMethodThatThrows();
+    }
+  }
+
+  public static void main(String[] args) throws Exception {
+    System.loadLibrary(args[0]);
+    // Disables use of nterp.
+    Main.setAsyncExceptionsThrown();
+
+    Thread.currentThread().setUncaughtExceptionHandler((th, e) -> {
+      System.out.println("Caught exception");
+      // Exit the test gracefully.
+      System.exit(0);
+    });
+    // This will throw at `callMethodThatThrows` and trigger deoptimization checks which we used
+    // to crash on.
+    new Inner();
+  }
+
+  public static void callMethodThatThrows() {
+    // Ensures we get deoptimization requests.
+    Main.forceInterpreterOnThread();
+    throw new Error("");
+  }
+
+  public static native void forceInterpreterOnThread();
+  public static native void setAsyncExceptionsThrown();
+
+}
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 5e40eed..82b3a3d 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -1165,6 +1165,7 @@
                   "836-32768classes",
                   "837-deopt",
                   "844-exception",
+                  "844-exception2",
                   "999-redefine-hiddenapi",
                   "1000-non-moving-space-stress",
                   "1001-app-image-regions",