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:
parent
f6ed7f5e23
commit
014f00fa51
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user