Commit 25981994 authored by ulan's avatar ulan Committed by Commit bot

Print and save JS stacktrace on OOM crash.

BUG=

Review URL: https://codereview.chromium.org/1149623010

Cr-Commit-Position: refs/heads/master@{#28818}
parent 5cefb367
...@@ -215,7 +215,9 @@ void i::FatalProcessOutOfMemory(const char* location) { ...@@ -215,7 +215,9 @@ void i::FatalProcessOutOfMemory(const char* location) {
void i::V8::FatalProcessOutOfMemory(const char* location, bool take_snapshot) { void i::V8::FatalProcessOutOfMemory(const char* location, bool take_snapshot) {
i::Isolate* isolate = i::Isolate::Current(); i::Isolate* isolate = i::Isolate::Current();
char last_few_messages[Heap::kTraceRingBufferSize + 1]; char last_few_messages[Heap::kTraceRingBufferSize + 1];
char js_stacktrace[Heap::kStacktraceBufferSize + 1];
memset(last_few_messages, 0, Heap::kTraceRingBufferSize + 1); memset(last_few_messages, 0, Heap::kTraceRingBufferSize + 1);
memset(js_stacktrace, 0, Heap::kStacktraceBufferSize + 1);
i::HeapStats heap_stats; i::HeapStats heap_stats;
int start_marker; int start_marker;
...@@ -259,6 +261,7 @@ void i::V8::FatalProcessOutOfMemory(const char* location, bool take_snapshot) { ...@@ -259,6 +261,7 @@ void i::V8::FatalProcessOutOfMemory(const char* location, bool take_snapshot) {
int os_error; int os_error;
heap_stats.os_error = &os_error; heap_stats.os_error = &os_error;
heap_stats.last_few_messages = last_few_messages; heap_stats.last_few_messages = last_few_messages;
heap_stats.js_stacktrace = js_stacktrace;
int end_marker; int end_marker;
heap_stats.end_marker = &end_marker; heap_stats.end_marker = &end_marker;
if (isolate->heap()->HasBeenSetUp()) { if (isolate->heap()->HasBeenSetUp()) {
...@@ -269,6 +272,7 @@ void i::V8::FatalProcessOutOfMemory(const char* location, bool take_snapshot) { ...@@ -269,6 +272,7 @@ void i::V8::FatalProcessOutOfMemory(const char* location, bool take_snapshot) {
if (first_newline == NULL || first_newline[1] == '\0') if (first_newline == NULL || first_newline[1] == '\0')
first_newline = last_few_messages; first_newline = last_few_messages;
PrintF("\n<--- Last few GCs --->\n%s\n", first_newline); 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"); Utils::ApiCheck(false, location, "Allocation failed - process out of memory");
// If the fatal error handler returns, we stop execution. // If the fatal error handler returns, we stop execution.
......
...@@ -5258,6 +5258,11 @@ void Heap::RecordStats(HeapStats* stats, bool take_snapshot) { ...@@ -5258,6 +5258,11 @@ void Heap::RecordStats(HeapStats* stats, bool take_snapshot) {
} }
if (stats->last_few_messages != NULL) if (stats->last_few_messages != NULL)
GetFromRingBuffer(stats->last_few_messages); 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);
}
} }
......
...@@ -1155,6 +1155,7 @@ class Heap { ...@@ -1155,6 +1155,7 @@ class Heap {
256 * kPointerMultiplier; 256 * kPointerMultiplier;
static const int kTraceRingBufferSize = 512; static const int kTraceRingBufferSize = 512;
static const int kStacktraceBufferSize = 512;
// Calculates the allocation limit based on a given growing factor and a // Calculates the allocation limit based on a given growing factor and a
// given old generation size. // given old generation size.
...@@ -2316,7 +2317,8 @@ class HeapStats { ...@@ -2316,7 +2317,8 @@ class HeapStats {
int* size_per_type; // 18 int* size_per_type; // 18
int* os_error; // 19 int* os_error; // 19
char* last_few_messages; // 20 char* last_few_messages; // 20
int* end_marker; // 21 char* js_stacktrace; // 21
int* end_marker; // 22
}; };
......
...@@ -705,7 +705,7 @@ static void PrintFrames(Isolate* isolate, ...@@ -705,7 +705,7 @@ static void PrintFrames(Isolate* isolate,
void Isolate::PrintStack(StringStream* accumulator, PrintStackMode mode) { void Isolate::PrintStack(StringStream* accumulator, PrintStackMode mode) {
// The MentionedObjectCache is not GC-proof at the moment. // The MentionedObjectCache is not GC-proof at the moment.
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
DCHECK(StringStream::IsMentionedObjectCacheClear(this)); DCHECK(accumulator->IsMentionedObjectCacheClear(this));
// Avoid printing anything if there are no frames. // Avoid printing anything if there are no frames.
if (c_entry_fp(thread_local_top()) == 0) return; if (c_entry_fp(thread_local_top()) == 0) return;
......
...@@ -18,6 +18,18 @@ char* HeapStringAllocator::allocate(unsigned bytes) { ...@@ -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) { bool StringStream::Put(char c) {
if (full()) return false; if (full()) return false;
DCHECK(length_ < capacity_); DCHECK(length_ < capacity_);
...@@ -170,7 +182,7 @@ void StringStream::PrintObject(Object* o) { ...@@ -170,7 +182,7 @@ void StringStream::PrintObject(Object* o) {
} else if (o->IsNumber() || o->IsOddball()) { } else if (o->IsNumber() || o->IsOddball()) {
return; return;
} }
if (o->IsHeapObject()) { if (o->IsHeapObject() && object_print_mode_ == kPrintObjectVerbose) {
HeapObject* ho = HeapObject::cast(o); HeapObject* ho = HeapObject::cast(o);
DebugObjectCache* debug_object_cache = ho->GetIsolate()-> DebugObjectCache* debug_object_cache = ho->GetIsolate()->
string_stream_debug_object_cache(); string_stream_debug_object_cache();
...@@ -284,7 +296,8 @@ void StringStream::ClearMentionedObjectCache(Isolate* isolate) { ...@@ -284,7 +296,8 @@ void StringStream::ClearMentionedObjectCache(Isolate* isolate) {
#ifdef DEBUG #ifdef DEBUG
bool StringStream::IsMentionedObjectCacheClear(Isolate* isolate) { 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 #endif
...@@ -403,6 +416,7 @@ void StringStream::PrintByteArray(ByteArray* byte_array) { ...@@ -403,6 +416,7 @@ void StringStream::PrintByteArray(ByteArray* byte_array) {
void StringStream::PrintMentionedObjectCache(Isolate* isolate) { void StringStream::PrintMentionedObjectCache(Isolate* isolate) {
if (object_print_mode_ == kPrintObjectConcise) return;
DebugObjectCache* debug_object_cache = DebugObjectCache* debug_object_cache =
isolate->string_stream_debug_object_cache(); isolate->string_stream_debug_object_cache();
Add("==== Key ============================================\n\n"); Add("==== Key ============================================\n\n");
......
...@@ -35,6 +35,21 @@ class HeapStringAllocator final : public StringAllocator { ...@@ -35,6 +35,21 @@ class HeapStringAllocator final : public StringAllocator {
}; };
class FixedStringAllocator final : public StringAllocator {
public:
FixedStringAllocator(char* buffer, unsigned length)
: buffer_(buffer), length_(length) {}
~FixedStringAllocator() override{};
char* allocate(unsigned bytes) override;
char* grow(unsigned* bytes) override;
private:
char* buffer_;
unsigned length_;
DISALLOW_COPY_AND_ASSIGN(FixedStringAllocator);
};
class FmtElm final { class FmtElm final {
public: public:
FmtElm(int value) : type_(INT) { // NOLINT FmtElm(int value) : type_(INT) { // NOLINT
...@@ -77,11 +92,14 @@ class FmtElm final { ...@@ -77,11 +92,14 @@ class FmtElm final {
class StringStream final { class StringStream final {
public: public:
explicit StringStream(StringAllocator* allocator): enum ObjectPrintMode { kPrintObjectConcise, kPrintObjectVerbose };
allocator_(allocator), StringStream(StringAllocator* allocator,
capacity_(kInitialCapacity), ObjectPrintMode object_print_mode = kPrintObjectConcise)
length_(0), : allocator_(allocator),
buffer_(allocator_->allocate(kInitialCapacity)) { object_print_mode_(object_print_mode),
capacity_(kInitialCapacity),
length_(0),
buffer_(allocator_->allocate(kInitialCapacity)) {
buffer_[0] = 0; buffer_[0] = 0;
} }
...@@ -134,7 +152,7 @@ class StringStream final { ...@@ -134,7 +152,7 @@ class StringStream final {
void PrintMentionedObjectCache(Isolate* isolate); void PrintMentionedObjectCache(Isolate* isolate);
static void ClearMentionedObjectCache(Isolate* isolate); static void ClearMentionedObjectCache(Isolate* isolate);
#ifdef DEBUG #ifdef DEBUG
static bool IsMentionedObjectCacheClear(Isolate* isolate); bool IsMentionedObjectCacheClear(Isolate* isolate);
#endif #endif
static const int kInitialCapacity = 16; static const int kInitialCapacity = 16;
...@@ -143,6 +161,7 @@ class StringStream final { ...@@ -143,6 +161,7 @@ class StringStream final {
void PrintObject(Object* obj); void PrintObject(Object* obj);
StringAllocator* allocator_; StringAllocator* allocator_;
ObjectPrintMode object_print_mode_;
unsigned capacity_; unsigned capacity_;
unsigned length_; // does not include terminating 0-character unsigned length_; // does not include terminating 0-character
char* buffer_; char* buffer_;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment