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:
parent
6270b797bc
commit
46b3582f48
@ -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_);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)));
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user