Don't pre-allocate one OOME per thread.
There's no associated stack trace, so we can share one between all
threads, saving a little memory and thread start-up time. Speaking
of stack traces: dump the stack to the log at the point where we
realize we're not going to be able to throw an exception with a
stack, so the developer has _something_ to work with.
Change-Id: I2246d291855bd9b9ee13f2be5b1ce14f669e9410
diff --git a/src/runtime.cc b/src/runtime.cc
index 1a66951..dda8f62 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -63,6 +63,7 @@
class_linker_(NULL),
signal_catcher_(NULL),
java_vm_(NULL),
+ pre_allocated_OutOfMemoryError_(NULL),
jni_stub_array_(NULL),
abstract_method_error_stub_array_(NULL),
resolution_method_(NULL),
@@ -82,7 +83,7 @@
resolution_stub_array_[i] = NULL;
}
for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
- callee_save_method_[i] = NULL;
+ callee_save_methods_[i] = NULL;
}
}
@@ -549,11 +550,18 @@
CHECK(host_prefix_.empty()) << host_prefix_;
- // Relocate the OatFiles (ELF images)
+ // Relocate the OatFiles (ELF images).
class_linker_->RelocateExecutable();
- // Restore main thread state to kNative as expected by native code
- Thread::Current()->SetState(kNative);
+ // Restore main thread state to kNative as expected by native code.
+ Thread* self = Thread::Current();
+ self->SetState(kNative);
+
+ // Pre-allocate an OutOfMemoryError for the double-OOME case.
+ self->ThrowNewException("Ljava/lang/OutOfMemoryError;",
+ "OutOfMemoryError thrown while trying to throw OutOfMemoryError; no stack available");
+ pre_allocated_OutOfMemoryError_ = self->GetException();
+ self->ClearException();
started_ = true;
@@ -571,7 +579,7 @@
CreateSystemClassLoader();
- Thread::Current()->GetJniEnv()->locals.AssertEmpty();
+ self->GetJniEnv()->locals.AssertEmpty();
VLOG(startup) << "Runtime::Start exiting";
@@ -851,6 +859,9 @@
intern_table_->VisitRoots(visitor, arg);
java_vm_->VisitRoots(visitor, arg);
thread_list_->VisitRoots(visitor, arg);
+ if (pre_allocated_OutOfMemoryError_ != NULL) {
+ visitor(pre_allocated_OutOfMemoryError_, arg);
+ }
visitor(jni_stub_array_, arg);
visitor(abstract_method_error_stub_array_, arg);
for (int i = 0; i < Runtime::kLastTrampolineMethodType; i++) {
@@ -858,7 +869,7 @@
}
visitor(resolution_method_, arg);
for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
- visitor(callee_save_method_[i], arg);
+ visitor(callee_save_methods_[i], arg);
}
}
@@ -943,7 +954,7 @@
void Runtime::SetCalleeSaveMethod(Method* method, CalleeSaveType type) {
DCHECK_LT(static_cast<int>(type), static_cast<int>(kLastCalleeSaveType));
- callee_save_method_[type] = method;
+ callee_save_methods_[type] = method;
}
void Runtime::EnableMethodTracing(Trace* tracer) {
diff --git a/src/runtime.h b/src/runtime.h
index d80f1c9..9181f1f 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -48,6 +48,7 @@
class SignalCatcher;
class String;
class ThreadList;
+class Throwable;
class Trace;
class Runtime {
@@ -172,14 +173,18 @@
return java_vm_;
}
- const std::vector<std::string>& GetProperties() const {
- return properties_;
- }
-
MonitorList* GetMonitorList() const {
return monitor_list_;
}
+ Throwable* GetPreAllocatedOutOfMemoryError() {
+ return pre_allocated_OutOfMemoryError_;
+ }
+
+ const std::vector<std::string>& GetProperties() const {
+ return properties_;
+ }
+
ThreadList* GetThreadList() const {
return thread_list_;
}
@@ -255,12 +260,12 @@
};
bool HasCalleeSaveMethod(CalleeSaveType type) const {
- return callee_save_method_[type] != NULL;
+ return callee_save_methods_[type] != NULL;
}
Method* GetCalleeSaveMethod(CalleeSaveType type) const {
CHECK(HasCalleeSaveMethod(type));
- return callee_save_method_[type];
+ return callee_save_methods_[type];
}
void SetCalleeSaveMethod(Method* method, CalleeSaveType type);
@@ -359,13 +364,15 @@
JavaVMExt* java_vm_;
+ Throwable* pre_allocated_OutOfMemoryError_;
+
ByteArray* jni_stub_array_;
ByteArray* abstract_method_error_stub_array_;
ByteArray* resolution_stub_array_[kLastTrampolineMethodType];
- Method* callee_save_method_[kLastCalleeSaveType];
+ Method* callee_save_methods_[kLastCalleeSaveType];
Method* resolution_method_;
diff --git a/src/thread.cc b/src/thread.cc
index f6b9a44..b263039 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -339,17 +339,10 @@
DecodeField(WellKnownClasses::java_lang_Thread_priority)->SetInt(peer_, thread_priority);
peer_thread_name.reset(GetThreadName());
}
- // thread_name may have been null, so don't trust this to be non-null
+ // 'thread_name' may have been null, so don't trust 'peer_thread_name' to be non-null.
if (peer_thread_name.get() != NULL) {
SetThreadName(peer_thread_name->ToModifiedUtf8().c_str());
}
-
- // Pre-allocate an OutOfMemoryError for the double-OOME case.
- ThrowNewException("Ljava/lang/OutOfMemoryError;",
- "OutOfMemoryError thrown while trying to throw OutOfMemoryError; no stack available");
- ScopedLocalRef<jthrowable> exception(env, env->ExceptionOccurred());
- env->ExceptionClear();
- pre_allocated_OutOfMemoryError_ = Decode<Throwable*>(env, exception.get());
}
void Thread::SetThreadName(const char* name) {
@@ -842,7 +835,6 @@
class_loader_override_(NULL),
long_jump_context_(NULL),
throwing_OutOfMemoryError_(false),
- pre_allocated_OutOfMemoryError_(NULL),
debug_invoke_req_(new DebugInvokeReq),
trace_stack_(new std::vector<TraceStackFrame>),
name_(new std::string(kThreadNameDuringStartup)) {
@@ -1487,12 +1479,12 @@
throwing_OutOfMemoryError_ = true;
ThrowNewException("Ljava/lang/OutOfMemoryError;", NULL);
} else {
- SetException(pre_allocated_OutOfMemoryError_);
+ Dump(LOG(ERROR)); // The pre-allocated OOME has no stack, so help out and log one.
+ SetException(Runtime::Current()->GetPreAllocatedOutOfMemoryError());
}
throwing_OutOfMemoryError_ = false;
}
-
Thread* Thread::CurrentFromGdb() {
return Thread::Current();
}
@@ -1887,9 +1879,6 @@
if (peer_ != NULL) {
visitor(peer_, arg);
}
- if (pre_allocated_OutOfMemoryError_ != NULL) {
- visitor(pre_allocated_OutOfMemoryError_, arg);
- }
if (class_loader_override_ != NULL) {
visitor(class_loader_override_, arg);
}
diff --git a/src/thread.h b/src/thread.h
index 6a2b27e..ef539c0 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -628,8 +628,6 @@
// A boolean telling us whether we're recursively throwing OOME.
uint32_t throwing_OutOfMemoryError_;
- Throwable* pre_allocated_OutOfMemoryError_;
-
// JDWP invoke-during-breakpoint support.
DebugInvokeReq* debug_invoke_req_;
diff --git a/src/utils.cc b/src/utils.cc
index 87c8704..084456d 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -958,7 +958,7 @@
os << prefix << "(unwind_backtrace_thread failed for thread " << tid << ")\n";
return;
} else if (frame_count == 0) {
- os << prefix << "(no native stack frames)\n";
+ os << prefix << "(no native stack frames for thread " << tid << ")\n";
return;
}