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",