Create stack traces in unstarted runtimes.
Use to diagnose failed initialization in dex2oat of boot (-verbose:compiler).
Fix identity hashCode, ArtMethod.getMethodName, IntegralToString.convertInt and
use of Void when called from a unstarted runtime.
Change-Id: I2d536174b59e2e5f19519f93fc6b5916652fb6cd
diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc
index d393a13..6874fe5 100644
--- a/runtime/mirror/throwable.cc
+++ b/runtime/mirror/throwable.cc
@@ -24,6 +24,7 @@
#include "object_array.h"
#include "object_array-inl.h"
#include "object_utils.h"
+#include "stack_trace_element.h"
#include "utils.h"
#include "well_known_classes.h"
@@ -53,6 +54,15 @@
}
}
+void Throwable::SetStackState(Object* state) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ CHECK(state != nullptr);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ SetFieldObjectVolatile<true>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_state_), state);
+ } else {
+ SetFieldObjectVolatile<false>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_state_), state);
+ }
+}
+
bool Throwable::IsCheckedException() {
if (InstanceOf(WellKnownClasses::ToClass(WellKnownClasses::java_lang_Error))) {
return false;
@@ -70,24 +80,49 @@
result += "\n";
Object* stack_state = GetStackState();
// check stack state isn't missing or corrupt
- if (stack_state != NULL && stack_state->IsObjectArray()) {
+ if (stack_state != nullptr && stack_state->IsObjectArray()) {
// Decode the internal stack trace into the depth and method trace
ObjectArray<Object>* method_trace = down_cast<ObjectArray<Object>*>(stack_state);
int32_t depth = method_trace->GetLength() - 1;
IntArray* pc_trace = down_cast<IntArray*>(method_trace->Get(depth));
MethodHelper mh;
- for (int32_t i = 0; i < depth; ++i) {
- ArtMethod* method = down_cast<ArtMethod*>(method_trace->Get(i));
- mh.ChangeMethod(method);
- uint32_t dex_pc = pc_trace->Get(i);
- int32_t line_number = mh.GetLineNumFromDexPC(dex_pc);
- const char* source_file = mh.GetDeclaringClassSourceFile();
- result += StringPrintf(" at %s (%s:%d)\n", PrettyMethod(method, true).c_str(),
- source_file, line_number);
+ if (depth == 0) {
+ result += "(Throwable with empty stack trace)";
+ } else {
+ for (int32_t i = 0; i < depth; ++i) {
+ ArtMethod* method = down_cast<ArtMethod*>(method_trace->Get(i));
+ mh.ChangeMethod(method);
+ uint32_t dex_pc = pc_trace->Get(i);
+ int32_t line_number = mh.GetLineNumFromDexPC(dex_pc);
+ const char* source_file = mh.GetDeclaringClassSourceFile();
+ result += StringPrintf(" at %s (%s:%d)\n", PrettyMethod(method, true).c_str(),
+ source_file, line_number);
+ }
+ }
+ } else {
+ Object* stack_trace = GetStackTrace();
+ if (stack_trace != nullptr && stack_trace->IsObjectArray()) {
+ CHECK_EQ(stack_trace->GetClass()->GetComponentType(),
+ StackTraceElement::GetStackTraceElement());
+ ObjectArray<StackTraceElement>* ste_array =
+ down_cast<ObjectArray<StackTraceElement>*>(stack_trace);
+ if (ste_array->GetLength() == 0) {
+ result += "(Throwable with empty stack trace)";
+ } else {
+ for (int32_t i = 0; i < ste_array->GetLength(); ++i) {
+ StackTraceElement* ste = ste_array->Get(i);
+ result += StringPrintf(" at %s (%s:%d)\n",
+ ste->GetMethodName()->ToModifiedUtf8().c_str(),
+ ste->GetFileName()->ToModifiedUtf8().c_str(),
+ ste->GetLineNumber());
+ }
+ }
+ } else {
+ result += "(Throwable with no stack trace)";
}
}
Throwable* cause = GetFieldObject<Throwable>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_));
- if (cause != NULL && cause != this) { // Constructor makes cause == this by default.
+ if (cause != nullptr && cause != this) { // Constructor makes cause == this by default.
result += "Caused by: ";
result += cause->Dump();
}