summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
author Elliott Hughes <enh@google.com> 2011-10-06 18:56:27 -0700
committer Elliott Hughes <enh@google.com> 2011-10-06 18:56:27 -0700
commit418dfe7849f45535b5388a91bd7a16cfc20a612b (patch)
tree60af35d2d9352910c782d2ce90f63a4d89d4a516 /src
parent1cb0a1dfc32531c79a968aeac26ccb5525862497 (diff)
Enable AllocWithGrowth and OutOfMemoryError throwing.
Also fix a bug where we weren't correcting the pc for the first stack frame. Change-Id: Ic4196987eac85eff2f6d14171b19b4f5890b6c4d
Diffstat (limited to 'src')
-rw-r--r--src/heap.cc34
-rw-r--r--src/jni_internal.cc5
-rw-r--r--src/object.cc5
-rw-r--r--src/thread.cc30
-rw-r--r--src/thread.h5
5 files changed, 43 insertions, 36 deletions
diff --git a/src/heap.cc b/src/heap.cc
index eae772f2c4..65bc4c02ed 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -150,18 +150,22 @@ void Heap::Destroy() {
live_bitmap_ = NULL;
}
-Object* Heap::AllocObject(Class* klass, size_t num_bytes) {
- ScopedHeapLock lock;
- DCHECK(klass == NULL
- || klass->GetDescriptor() == NULL
- || (klass->IsClassClass() && num_bytes >= sizeof(Class))
- || (klass->IsVariableSize() || klass->GetObjectSize() == num_bytes));
- DCHECK(num_bytes >= sizeof(Object));
- Object* obj = AllocateLocked(num_bytes);
- if (obj != NULL) {
- obj->SetClass(klass);
+Object* Heap::AllocObject(Class* klass, size_t byte_count) {
+ {
+ ScopedHeapLock lock;
+ DCHECK(klass == NULL || klass->GetDescriptor() == NULL ||
+ (klass->IsClassClass() && byte_count >= sizeof(Class)) ||
+ (klass->IsVariableSize() || klass->GetObjectSize() == byte_count));
+ DCHECK_GE(byte_count, sizeof(Object));
+ Object* obj = AllocateLocked(byte_count);
+ if (obj != NULL) {
+ obj->SetClass(klass);
+ return obj;
+ }
}
- return obj;
+
+ Thread::Current()->ThrowOutOfMemoryError(klass, byte_count);
+ return NULL;
}
bool Heap::IsHeapAddress(const Object* obj) {
@@ -340,21 +344,21 @@ Object* Heap::AllocateLocked(Space* space, size_t size) {
++Runtime::Current()->GetStats()->gc_for_alloc_count;
++Thread::Current()->GetStats()->gc_for_alloc_count;
}
- LOG(INFO) << "GC_FOR_ALLOC: TODO: test";
+ LOG(INFO) << "GC_FOR_ALLOC: AllocWithoutGrowth: TODO: test";
CollectGarbageInternal();
ptr = space->AllocWithoutGrowth(size);
if (ptr != NULL) {
return ptr;
}
- UNIMPLEMENTED(FATAL) << "No AllocWithGrowth, use larger -Xms -Xmx";
+ LOG(INFO) << "GC_FOR_ALLOC: AllocWithGrowth: TODO: test";
// Even that didn't work; this is an exceptional state.
// Try harder, growing the heap if necessary.
ptr = space->AllocWithGrowth(size);
if (ptr != NULL) {
//size_t new_footprint = dvmHeapSourceGetIdealFootprint();
size_t new_footprint = space->GetMaxAllowedFootprint();
- // TODO: may want to grow a little bit more so that the amount of
+ // OLD-TODO: may want to grow a little bit more so that the amount of
// free space is equal to the old free space + the
// utilization slop for the new allocation.
LOG(INFO) << "Grow heap (frag case) to " << new_footprint / MB
@@ -368,7 +372,7 @@ Object* Heap::AllocateLocked(Space* space, size_t size) {
// spec requires that all SoftReferences have been collected and
// cleared before throwing an OOME.
- // TODO: wait for the finalizers from the previous GC to finish
+ // OLD-TODO: wait for the finalizers from the previous GC to finish
LOG(INFO) << "Forcing collection of SoftReferences for "
<< size << "-byte allocation";
CollectGarbageInternal();
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index bc1de521aa..f9d536b250 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -1803,10 +1803,7 @@ class JNI {
String* s = Decode<String*>(ts, java_string);
size_t byte_count = s->GetUtfLength();
char* bytes = new char[byte_count + 1];
- if (bytes == NULL) {
- ts.Self()->ThrowOutOfMemoryError();
- return NULL;
- }
+ CHECK(bytes != NULL); // bionic aborts anyway.
const uint16_t* chars = s->GetCharArray()->GetData() + s->GetOffset();
ConvertUtf16ToModifiedUtf8(bytes, chars, s->GetLength());
bytes[byte_count] = '\0';
diff --git a/src/object.cc b/src/object.cc
index 342599e174..1f64faa3f7 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -1239,11 +1239,6 @@ Array* Array::Alloc(Class* array_class, int32_t component_count, size_t componen
DCHECK(array->IsArrayInstance());
array->SetLength(component_count);
}
-
- // TODO: throw OutOfMemoryError. (here or in Heap::AllocObject?)
- CHECK(array != NULL) << PrettyClass(array_class)
- << " component_count=" << component_count
- << " component_size=" << component_size;
return array;
}
diff --git a/src/thread.cc b/src/thread.cc
index a481aa6856..16b8b67a41 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -696,7 +696,8 @@ Thread::Thread()
exception_(NULL),
suspend_count_(0),
class_loader_override_(NULL),
- long_jump_context_(NULL) {
+ long_jump_context_(NULL),
+ throwing_OOME_(false) {
CHECK((sizeof(Thread) % 4) == 0) << sizeof(Thread);
}
@@ -967,14 +968,14 @@ void Thread::WalkStack(StackVisitor* visitor) const {
while (frame.GetSP() != 0) {
for ( ; frame.GetMethod() != 0; frame.Next()) {
- DCHECK(frame.GetMethod()->IsWithinCode(pc));
- visitor->VisitFrame(frame, pc);
- pc = frame.GetReturnPC();
// Move the PC back 2 bytes as a call will frequently terminate the
// decoding of a particular instruction and we want to make sure we
// get the Dex PC of the instruction with the call and not the
// instruction following.
- pc -= 2;
+ if (pc > 0) { pc -= 2; }
+ DCHECK(frame.GetMethod()->IsWithinCode(pc));
+ visitor->VisitFrame(frame, pc);
+ pc = frame.GetReturnPC();
}
if (record == NULL) {
break;
@@ -992,14 +993,14 @@ void Thread::WalkStackUntilUpCall(StackVisitor* visitor, bool include_upcall) co
if (frame.GetSP() != 0) {
for ( ; frame.GetMethod() != 0; frame.Next()) {
- DCHECK(frame.GetMethod()->IsWithinCode(pc));
- visitor->VisitFrame(frame, pc);
- pc = frame.GetReturnPC();
// Move the PC back 2 bytes as a call will frequently terminate the
// decoding of a particular instruction and we want to make sure we
// get the Dex PC of the instruction with the call and not the
// instruction following.
- pc -= 2;
+ if (pc > 0) { pc -= 2; }
+ DCHECK(frame.GetMethod()->IsWithinCode(pc));
+ visitor->VisitFrame(frame, pc);
+ pc = frame.GetReturnPC();
}
if (include_upcall) {
visitor->VisitFrame(frame, pc);
@@ -1110,8 +1111,15 @@ void Thread::ThrowNewException(const char* exception_class_descriptor, const cha
env->DeleteLocalRef(exception_class);
}
-void Thread::ThrowOutOfMemoryError() {
- UNIMPLEMENTED(FATAL);
+void Thread::ThrowOutOfMemoryError(Class* c, size_t byte_count) {
+ if (!throwing_OOME_) {
+ throwing_OOME_ = true;
+ ThrowNewException("Ljava/lang/OutOfMemoryError;", NULL);
+ LOG(ERROR) << "Failed to allocate a " << PrettyDescriptor(c->GetDescriptor()) << " (" << byte_count << " bytes)";
+ } else {
+ UNIMPLEMENTED(FATAL) << "throw one i prepared earlier...";
+ }
+ throwing_OOME_ = false;
}
class CatchBlockStackVisitor : public Thread::StackVisitor {
diff --git a/src/thread.h b/src/thread.h
index 7bd6855cad..c898a76650 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -285,7 +285,7 @@ class PACKED Thread {
void ThrowNewExceptionV(const char* exception_class_descriptor, const char* fmt, va_list ap);
// This exception is special, because we need to pre-allocate an instance.
- void ThrowOutOfMemoryError();
+ void ThrowOutOfMemoryError(Class* c, size_t byte_count);
Frame FindExceptionHandler(void* throw_pc, void** handler_pc);
@@ -573,6 +573,9 @@ class PACKED Thread {
// Thread local, lazily allocated, long jump context. Used to deliver exceptions.
Context* long_jump_context_;
+ // A boolean telling us whether we're recursively throwing OOME.
+ uint32_t throwing_OOME_;
+
// TLS key used to retrieve the VM thread object.
static pthread_key_t pthread_key_self_;