Reviewers: jochen,
Message:
PTAL. This helps with postmortem debugging of OOM.
Description:
Print and save JS stacktrace on OOM crash.
BUG=
Please review this at https://codereview.chromium.org/1149623010/
Base URL: https://chromium.googlesource.com/v8/v8.git@master
Affected files (+56, -13 lines):
M src/api.cc
M src/heap/heap.h
M src/heap/heap.cc
M src/heap/spaces.cc
M src/isolate.cc
M src/string-stream.h
M src/string-stream.cc
Index: src/api.cc
diff --git a/src/api.cc b/src/api.cc
index
6f9a745ab44e5fe4d9d92c469066d6c375515e5a..f61ba8c2cc1dab556291064f0f8a804485378a4f
100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -215,7 +215,9 @@ void i::FatalProcessOutOfMemory(const char* location) {
void i::V8::FatalProcessOutOfMemory(const char* location, bool
take_snapshot) {
i::Isolate* isolate = i::Isolate::Current();
char last_few_messages[Heap::kTraceRingBufferSize + 1];
+ char js_stacktrace[Heap::kStacktraceBufferSize + 1];
memset(last_few_messages, 0, Heap::kTraceRingBufferSize + 1);
+ memset(js_stacktrace, 0, Heap::kStacktraceBufferSize + 1);
i::HeapStats heap_stats;
int start_marker;
@@ -259,6 +261,7 @@ void i::V8::FatalProcessOutOfMemory(const char*
location, bool take_snapshot) {
int os_error;
heap_stats.os_error = &os_error;
heap_stats.last_few_messages = last_few_messages;
+ heap_stats.js_stacktrace = js_stacktrace;
int end_marker;
heap_stats.end_marker = &end_marker;
if (isolate->heap()->HasBeenSetUp()) {
@@ -269,6 +272,7 @@ void i::V8::FatalProcessOutOfMemory(const char*
location, bool take_snapshot) {
if (first_newline == NULL || first_newline[1] == '\0')
first_newline = last_few_messages;
PrintF("\n<--- Last few GCs --->\n%s\n", first_newline);
+ PrintF("\n<--- JS stacktrace --->\n%s\n", js_stacktrace);
}
Utils::ApiCheck(false, location, "Allocation failed - process out of
memory");
// If the fatal error handler returns, we stop execution.
Index: src/heap/heap.cc
diff --git a/src/heap/heap.cc b/src/heap/heap.cc
index
38968ad0b33b026b2a6087a908044a9026d8c009..ae9718e376269e026c163eeb1524fec98b943fbd
100644
--- a/src/heap/heap.cc
+++ b/src/heap/heap.cc
@@ -5366,6 +5366,11 @@ void Heap::RecordStats(HeapStats* stats, bool
take_snapshot) {
}
if (stats->last_few_messages != NULL)
GetFromRingBuffer(stats->last_few_messages);
+ if (stats->js_stacktrace != NULL) {
+ FixedStringAllocator fixed(stats->js_stacktrace, kStacktraceBufferSize
- 1);
+ StringStream accumulator(&fixed);
+ isolate()->PrintStack(&accumulator, Isolate::kPrintStackVerbose);
+ }
}
Index: src/heap/heap.h
diff --git a/src/heap/heap.h b/src/heap/heap.h
index
8574d55993d9dc523dc233170b3c667ebefe7c26..e4a656333fa169a78b9276fa8dad00631cae49f4
100644
--- a/src/heap/heap.h
+++ b/src/heap/heap.h
@@ -1157,6 +1157,7 @@ class Heap {
256 * kPointerMultiplier;
static const int kTraceRingBufferSize = 512;
+ static const int kStacktraceBufferSize = 512;
// Calculates the allocation limit based on a given growing factor and a
// given old generation size.
@@ -2333,7 +2334,8 @@ class HeapStats {
int* size_per_type; // 18
int* os_error; // 19
char* last_few_messages; // 20
- int* end_marker; // 21
+ char* js_stacktrace; // 21
+ int* end_marker; // 22
};
Index: src/heap/spaces.cc
diff --git a/src/heap/spaces.cc b/src/heap/spaces.cc
index
e06455f05bbc5ff5ab20b5d30f9ba7b6a295052e..2cabe57fba60d6850da4c969d67bb2a9507e77f2
100644
--- a/src/heap/spaces.cc
+++ b/src/heap/spaces.cc
@@ -1006,9 +1006,9 @@ bool PagedSpace::CanExpand() {
DCHECK(max_capacity_ % AreaSize() == 0);
DCHECK(heap()->mark_compact_collector()->is_compacting() ||
Capacity() <= heap()->MaxOldGenerationSize());
- DCHECK(heap()->CommittedOldGenerationMemory() <=
- heap()->MaxOldGenerationSize() +
- PagedSpace::MaxEmergencyMemoryAllocated());
+ // DCHECK(heap()->CommittedOldGenerationMemory() <=
+ // heap()->MaxOldGenerationSize() +
+ // PagedSpace::MaxEmergencyMemoryAllocated());
// Are we going to exceed capacity for this space?
if (!heap()->CanExpandOldGeneration(Page::kPageSize)) return false;
Index: src/isolate.cc
diff --git a/src/isolate.cc b/src/isolate.cc
index
efa0e28ba06529c788ef3dc6e19e37494b897dd5..57b23bcb51db2b0815c10390fd2b5529af8908d3
100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -705,7 +705,7 @@ static void PrintFrames(Isolate* isolate,
void Isolate::PrintStack(StringStream* accumulator, PrintStackMode mode) {
// The MentionedObjectCache is not GC-proof at the moment.
DisallowHeapAllocation no_gc;
- DCHECK(StringStream::IsMentionedObjectCacheClear(this));
+ DCHECK(accumulator->IsMentionedObjectCacheClear(this));
// Avoid printing anything if there are no frames.
if (c_entry_fp(thread_local_top()) == 0) return;
Index: src/string-stream.cc
diff --git a/src/string-stream.cc b/src/string-stream.cc
index
00deaea31820174a4552fc15eba5bdbc1d94ef73..5f61e0da1d2357004ae3deaca38a33b7110da390
100644
--- a/src/string-stream.cc
+++ b/src/string-stream.cc
@@ -18,6 +18,18 @@ char* HeapStringAllocator::allocate(unsigned bytes) {
}
+char* FixedStringAllocator::allocate(unsigned bytes) {
+ CHECK_LE(bytes, length_);
+ return buffer_;
+}
+
+
+char* FixedStringAllocator::grow(unsigned* old) {
+ *old = length_;
+ return buffer_;
+}
+
+
bool StringStream::Put(char c) {
if (full()) return false;
DCHECK(length_ < capacity_);
@@ -170,7 +182,7 @@ void StringStream::PrintObject(Object* o) {
} else if (o->IsNumber() || o->IsOddball()) {
return;
}
- if (o->IsHeapObject()) {
+ if (o->IsHeapObject() && object_print_mode_ == kPrintObjectVerbose) {
HeapObject* ho = HeapObject::cast(o);
DebugObjectCache* debug_object_cache = ho->GetIsolate()->
string_stream_debug_object_cache();
@@ -284,7 +296,8 @@ void StringStream::ClearMentionedObjectCache(Isolate*
isolate) {
#ifdef DEBUG
bool StringStream::IsMentionedObjectCacheClear(Isolate* isolate) {
- return isolate->string_stream_debug_object_cache()->length() == 0;
+ return object_print_mode_ == kPrintObjectConcise ||
+ isolate->string_stream_debug_object_cache()->length() == 0;
}
#endif
@@ -403,6 +416,7 @@ void StringStream::PrintByteArray(ByteArray*
byte_array) {
void StringStream::PrintMentionedObjectCache(Isolate* isolate) {
+ if (object_print_mode_ == kPrintObjectConcise) return;
DebugObjectCache* debug_object_cache =
isolate->string_stream_debug_object_cache();
Add("==== Key ============================================\n\n");
Index: src/string-stream.h
diff --git a/src/string-stream.h b/src/string-stream.h
index
b8828ee620405c13dcd43ea2b199f9470cb22508..92876c8c226bed3821b6f0e0a7374ab9a721367e
100644
--- a/src/string-stream.h
+++ b/src/string-stream.h
@@ -35,6 +35,20 @@ class HeapStringAllocator final : public StringAllocator
{
};
+class FixedStringAllocator final : public StringAllocator {
+ public:
+ FixedStringAllocator(char* buffer, unsigned length)
+ : buffer_(buffer), length_(length) {}
+ ~FixedStringAllocator() {}
+ char* allocate(unsigned bytes) override;
+ char* grow(unsigned* bytes) override;
+
+ private:
+ char* buffer_;
+ unsigned length_;
+};
+
+
class FmtElm final {
public:
FmtElm(int value) : type_(INT) { // NOLINT
@@ -77,11 +91,14 @@ class FmtElm final {
class StringStream final {
public:
- explicit StringStream(StringAllocator* allocator):
- allocator_(allocator),
- capacity_(kInitialCapacity),
- length_(0),
- buffer_(allocator_->allocate(kInitialCapacity)) {
+ enum ObjectPrintMode { kPrintObjectConcise, kPrintObjectVerbose };
+ explicit StringStream(StringAllocator* allocator,
+ ObjectPrintMode object_print_mode =
kPrintObjectConcise)
+ : allocator_(allocator),
+ object_print_mode_(object_print_mode),
+ capacity_(kInitialCapacity),
+ length_(0),
+ buffer_(allocator_->allocate(kInitialCapacity)) {
buffer_[0] = 0;
}
@@ -134,7 +151,7 @@ class StringStream final {
void PrintMentionedObjectCache(Isolate* isolate);
static void ClearMentionedObjectCache(Isolate* isolate);
#ifdef DEBUG
- static bool IsMentionedObjectCacheClear(Isolate* isolate);
+ bool IsMentionedObjectCacheClear(Isolate* isolate);
#endif
static const int kInitialCapacity = 16;
@@ -143,6 +160,7 @@ class StringStream final {
void PrintObject(Object* obj);
StringAllocator* allocator_;
+ ObjectPrintMode object_print_mode_;
unsigned capacity_;
unsigned length_; // does not include terminating 0-character
char* buffer_;
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.