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) {
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.
......
......@@ -5258,6 +5258,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);
}
}
......
......@@ -1155,6 +1155,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.
......@@ -2316,7 +2317,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
};
......
......@@ -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;
......
......@@ -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");
......
......@@ -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 {
public:
FmtElm(int value) : type_(INT) { // NOLINT
......@@ -77,11 +92,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 };
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 +152,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 +161,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_;
......
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