Reland: Preprocess structured stack trace on GC to get rid of code reference.

BUG=v8:2340
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#28102}
This commit is contained in:
yangguo 2015-04-28 04:13:22 -07:00 committed by Commit bot
parent 6270b797bc
commit 46b3582f48
9 changed files with 83 additions and 5 deletions

View File

@ -644,6 +644,10 @@ class Factory final {
isolate()->heap()->set_string_table(*table);
}
inline void set_weak_stack_trace_list(Handle<WeakFixedArray> list) {
isolate()->heap()->set_weak_stack_trace_list(*list);
}
Handle<String> hidden_string() {
return Handle<String>(&isolate()->heap()->hidden_string_);
}

View File

@ -706,6 +706,32 @@ void Heap::GarbageCollectionEpilogue() {
}
void Heap::PreprocessStackTraces() {
if (!weak_stack_trace_list()->IsWeakFixedArray()) return;
WeakFixedArray* array = WeakFixedArray::cast(weak_stack_trace_list());
int length = array->Length();
for (int i = 0; i < length; i++) {
if (array->IsEmptySlot(i)) continue;
FixedArray* elements = FixedArray::cast(array->Get(i));
for (int j = 1; j < elements->length(); j += 4) {
Object* maybe_code = elements->get(j + 2);
// If GC happens while adding a stack trace to the weak fixed array,
// which has been copied into a larger backing store, we may run into
// a stack trace that has already been preprocessed. Guard against this.
if (!maybe_code->IsCode()) break;
Code* code = Code::cast(maybe_code);
int offset = Smi::cast(elements->get(j + 3))->value();
Address pc = code->address() + offset;
int pos = code->SourcePosition(pc);
elements->set(j + 2, Smi::FromInt(pos));
}
}
// We must not compact the weak fixed list here, as we may be in the middle
// of writing to it, when the GC triggered. Instead, we reset the root value.
set_weak_stack_trace_list(Smi::FromInt(0));
}
void Heap::HandleGCRequest() {
if (incremental_marking()->request_type() ==
IncrementalMarking::COMPLETE_MARKING) {
@ -1272,6 +1298,8 @@ void Heap::MarkCompactEpilogue() {
isolate_->counters()->objs_since_last_full()->Set(0);
incremental_marking()->Epilogue();
PreprocessStackTraces();
}
@ -3082,6 +3110,8 @@ void Heap::CreateInitialObjects() {
cell->set_value(Smi::FromInt(Isolate::kArrayProtectorValid));
set_array_protector(*cell);
set_weak_stack_trace_list(Smi::FromInt(0));
set_allocation_sites_scratchpad(
*factory->NewFixedArray(kAllocationSiteScratchpadSize, TENURED));
InitializeAllocationSitesScratchpad();
@ -3118,6 +3148,7 @@ bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) {
case kDetachedContextsRootIndex:
case kWeakObjectToCodeTableRootIndex:
case kRetainedMapsRootIndex:
case kWeakStackTraceListRootIndex:
// Smi values
#define SMI_ENTRY(type, name, Name) case k##Name##RootIndex:
SMI_ROOT_LIST(SMI_ENTRY)

View File

@ -186,7 +186,8 @@ namespace internal {
V(FixedArray, detached_contexts, DetachedContexts) \
V(ArrayList, retained_maps, RetainedMaps) \
V(WeakHashTable, weak_object_to_code_table, WeakObjectToCodeTable) \
V(PropertyCell, array_protector, ArrayProtector)
V(PropertyCell, array_protector, ArrayProtector) \
V(Object, weak_stack_trace_list, WeakStackTraceList)
// Entries in this list are limited to Smis and are not visited during GC.
#define SMI_ROOT_LIST(V) \
@ -1742,6 +1743,8 @@ class Heap {
void GarbageCollectionPrologue();
void GarbageCollectionEpilogue();
void PreprocessStackTraces();
// Pretenuring decisions are made based on feedback collected during new
// space evacuation. Note that between feedback collection and calling this
// method object in old space must not move.

View File

@ -407,8 +407,14 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object,
}
}
elements->set(0, Smi::FromInt(sloppy_frames));
elements->Shrink(cursor);
Handle<JSArray> result = factory()->NewJSArrayWithElements(elements);
result->set_length(Smi::FromInt(cursor));
// Queue this structured stack trace for preprocessing on GC.
Handle<Object> old_weak_list(heap()->weak_stack_trace_list(), this);
Handle<WeakFixedArray> new_weak_list =
WeakFixedArray::Add(old_weak_list, elements);
factory()->set_weak_stack_trace_list(new_weak_list);
return result;
}

View File

@ -998,7 +998,7 @@ function GetStackFrames(raw_stack) {
var fun = raw_stack[i + 1];
var code = raw_stack[i + 2];
var pc = raw_stack[i + 3];
var pos = %FunctionGetPositionForOffset(code, pc);
var pos = %_IsSmi(code) ? code : %FunctionGetPositionForOffset(code, pc);
sloppy_frames--;
frames.push(new CallSite(recv, fun, pos, (sloppy_frames < 0)));
}

View File

@ -2356,7 +2356,7 @@ bool WeakFixedArray::IsEmptySlot(int index) const {
}
void WeakFixedArray::clear(int index) {
void WeakFixedArray::Clear(int index) {
FixedArray::cast(this)->set(index + kFirstIndex, Smi::FromInt(0));
}

View File

@ -8348,7 +8348,7 @@ bool WeakFixedArray::Remove(Handle<HeapObject> value) {
int first_index = last_used_index();
for (int i = first_index;;) {
if (Get(i) == *value) {
clear(i);
Clear(i);
// Users of WeakFixedArray should make sure that there are no duplicates,
// they can use Add(..., kAddIfNotFound) if necessary.
return true;

View File

@ -2632,8 +2632,10 @@ class WeakFixedArray : public FixedArray {
void Compact();
inline Object* Get(int index) const;
inline void Clear(int index);
inline int Length() const;
inline bool IsEmptySlot(int index) const;
static Object* Empty() { return Smi::FromInt(0); }
DECLARE_CAST(WeakFixedArray)
@ -2648,7 +2650,6 @@ class WeakFixedArray : public FixedArray {
static void Set(Handle<WeakFixedArray> array, int index,
Handle<HeapObject> value);
inline void clear(int index);
inline bool IsEmptySlot(int index) const;
inline int last_used_index() const;
inline void set_last_used_index(int index);

View File

@ -5379,3 +5379,36 @@ TEST(WeakFixedArray) {
array->Compact();
WeakFixedArray::Add(array, number);
}
TEST(PreprocessStackTrace) {
// Do not automatically trigger early GC.
FLAG_gc_interval = -1;
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
v8::TryCatch try_catch;
CompileRun("throw new Error();");
CHECK(try_catch.HasCaught());
Isolate* isolate = CcTest::i_isolate();
Handle<Object> exception = v8::Utils::OpenHandle(*try_catch.Exception());
Handle<Name> key = isolate->factory()->stack_trace_symbol();
Handle<Object> stack_trace =
JSObject::GetProperty(exception, key).ToHandleChecked();
Handle<Object> code =
Object::GetElement(isolate, stack_trace, 3).ToHandleChecked();
CHECK(code->IsCode());
isolate->heap()->CollectAllAvailableGarbage("stack trace preprocessing");
Handle<Object> pos =
Object::GetElement(isolate, stack_trace, 3).ToHandleChecked();
CHECK(pos->IsSmi());
Handle<JSArray> stack_trace_array = Handle<JSArray>::cast(stack_trace);
int array_length = Smi::cast(stack_trace_array->length())->value();
for (int i = 0; i < array_length; i++) {
Handle<Object> element =
Object::GetElement(isolate, stack_trace, i).ToHandleChecked();
CHECK(!element->IsCode());
}
}