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
parent f6ed7f5e
......@@ -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());
......
......@@ -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_;
......
......@@ -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);
......
......@@ -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());
}
......
......@@ -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;
......
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