Fix code flusher to process weak function links.

This fixes a corner case where weak function links of the code flushing
candidates list were destroyed by scavenges that happened during
incremental marking. Now those weak function links are updated while
scavenging happens.

R=ulan@chromium.org
TEST=cctest/test-heap/TestCodeFlushingIncrementalScavenge

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12825 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mstarzinger@chromium.org 2012-10-26 09:44:34 +00:00
parent f6ed7f5e23
commit 014f00fa51
5 changed files with 95 additions and 1 deletions

View File

@ -1327,6 +1327,12 @@ void Heap::Scavenge() {
}
}
// Copy objects reachable from the code flushing candidates list.
MarkCompactCollector* collector = mark_compact_collector();
if (collector->is_code_flushing_enabled()) {
collector->code_flusher()->IteratePointersToFromSpace(&scavenge_visitor);
}
// Scavenge object reachable from the native contexts list directly.
scavenge_visitor.VisitPointer(BitCast<Object**>(&native_contexts_list_));
@ -5542,6 +5548,7 @@ bool Heap::LookupSymbolIfExists(String* string, String** symbol) {
return symbol_table()->LookupSymbolIfExists(string, symbol);
}
void Heap::ZapFromSpace() {
NewSpacePageIterator it(new_space_.FromSpaceStart(),
new_space_.FromSpaceEnd());

View File

@ -952,6 +952,21 @@ void CodeFlusher::EvictCandidate(JSFunction* function) {
}
void CodeFlusher::IteratePointersToFromSpace(ObjectVisitor* v) {
Heap* heap = isolate_->heap();
JSFunction** slot = &jsfunction_candidates_head_;
JSFunction* candidate = jsfunction_candidates_head_;
while (candidate != NULL) {
if (heap->InFromSpace(candidate)) {
v->VisitPointer(reinterpret_cast<Object**>(slot));
}
candidate = GetNextCandidate(*slot);
slot = GetNextCandidateSlot(*slot);
}
}
MarkCompactCollector::~MarkCompactCollector() {
if (code_flusher_ != NULL) {
delete code_flusher_;

View File

@ -441,10 +441,17 @@ class CodeFlusher {
ProcessJSFunctionCandidates();
}
void IteratePointersToFromSpace(ObjectVisitor* v);
private:
void ProcessJSFunctionCandidates();
void ProcessSharedFunctionInfoCandidates();
static JSFunction** GetNextCandidateSlot(JSFunction* candidate) {
return reinterpret_cast<JSFunction**>(
HeapObject::RawField(candidate, JSFunction::kNextFunctionLinkOffset));
}
static JSFunction* GetNextCandidate(JSFunction* candidate) {
Object* next_candidate = candidate->next_function_link();
return reinterpret_cast<JSFunction*>(next_candidate);

View File

@ -499,7 +499,8 @@ void JSFunction::JSFunctionVerify() {
VerifyObjectField(kPrototypeOrInitialMapOffset);
VerifyObjectField(kNextFunctionLinkOffset);
CHECK(code()->IsCode());
CHECK(next_function_link()->IsUndefined() ||
CHECK(next_function_link() == NULL ||
next_function_link()->IsUndefined() ||
next_function_link()->IsJSFunction());
}

View File

@ -1069,6 +1069,70 @@ TEST(TestCodeFlushingIncremental) {
}
TEST(TestCodeFlushingIncrementalScavenge) {
// If we do not flush code this test is invalid.
if (!FLAG_flush_code) return;
i::FLAG_allow_natives_syntax = true;
InitializeVM();
v8::HandleScope scope;
const char* source = "var foo = function() {"
" var x = 42;"
" var y = 42;"
" var z = x + y;"
"};"
"foo();"
"var bar = function() {"
" var x = 23;"
"};"
"bar();";
Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo");
Handle<String> bar_name = FACTORY->LookupAsciiSymbol("bar");
// Perfrom one initial GC to enable code flushing.
HEAP->CollectAllGarbage(Heap::kNoGCFlags);
// This compile will add the code to the compilation cache.
{ v8::HandleScope scope;
CompileRun(source);
}
// Check functions are compiled.
Object* func_value = Isolate::Current()->context()->global_object()->
GetProperty(*foo_name)->ToObjectChecked();
CHECK(func_value->IsJSFunction());
Handle<JSFunction> function(JSFunction::cast(func_value));
CHECK(function->shared()->is_compiled());
Object* func_value2 = Isolate::Current()->context()->global_object()->
GetProperty(*bar_name)->ToObjectChecked();
CHECK(func_value2->IsJSFunction());
Handle<JSFunction> function2(JSFunction::cast(func_value2));
CHECK(function2->shared()->is_compiled());
// Clear references to functions so that one of them can die.
{ v8::HandleScope scope;
CompileRun("foo = 0; bar = 0;");
}
// Bump the code age so that flushing is triggered while the function
// object is still located in new-space.
const int kAgingThreshold = 6;
function->shared()->set_code_age(kAgingThreshold);
function2->shared()->set_code_age(kAgingThreshold);
// Simulate incremental marking so that the functions are enqueued as
// code flushing candidates. Then kill one of the functions. Finally
// perform a scavenge while incremental marking is still running.
SimulateIncrementalMarking();
*function2.location() = NULL;
HEAP->CollectGarbage(NEW_SPACE, "test scavenge while marking");
// Simulate one final GC to make sure the candidate queue is sane.
HEAP->CollectAllGarbage(Heap::kNoGCFlags);
CHECK(!function->shared()->is_compiled() || function->IsOptimized());
CHECK(!function->is_compiled() || function->IsOptimized());
}
// Count the number of native contexts in the weak list of native contexts.
int CountNativeContexts() {
int count = 0;