Fix disabling of code flusher while marking.
This fixes a corner case when the code flusher is disabled while incremental marking is running. The list of candidates needs to be evicted to prevent list fragments without a head floating around. R=ulan@chromium.org BUG=chromium:159140 Review URL: https://codereview.chromium.org/11366136 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12894 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
63b5392717
commit
8e7ae24b40
@ -952,6 +952,34 @@ void CodeFlusher::EvictCandidate(JSFunction* function) {
|
||||
}
|
||||
|
||||
|
||||
void CodeFlusher::EvictJSFunctionCandidates() {
|
||||
Object* undefined = isolate_->heap()->undefined_value();
|
||||
|
||||
JSFunction* candidate = jsfunction_candidates_head_;
|
||||
JSFunction* next_candidate;
|
||||
while (candidate != NULL) {
|
||||
next_candidate = GetNextCandidate(candidate);
|
||||
ClearNextCandidate(candidate, undefined);
|
||||
candidate = next_candidate;
|
||||
}
|
||||
|
||||
jsfunction_candidates_head_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
void CodeFlusher::EvictSharedFunctionInfoCandidates() {
|
||||
SharedFunctionInfo* candidate = shared_function_info_candidates_head_;
|
||||
SharedFunctionInfo* next_candidate;
|
||||
while (candidate != NULL) {
|
||||
next_candidate = GetNextCandidate(candidate);
|
||||
ClearNextCandidate(candidate);
|
||||
candidate = next_candidate;
|
||||
}
|
||||
|
||||
shared_function_info_candidates_head_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
void CodeFlusher::IteratePointersToFromSpace(ObjectVisitor* v) {
|
||||
Heap* heap = isolate_->heap();
|
||||
|
||||
@ -3629,6 +3657,7 @@ void MarkCompactCollector::EnableCodeFlushing(bool enable) {
|
||||
code_flusher_ = new CodeFlusher(heap()->isolate());
|
||||
} else {
|
||||
if (code_flusher_ == NULL) return;
|
||||
code_flusher_->EvictAllCandidates();
|
||||
delete code_flusher_;
|
||||
code_flusher_ = NULL;
|
||||
}
|
||||
|
@ -441,11 +441,18 @@ class CodeFlusher {
|
||||
ProcessJSFunctionCandidates();
|
||||
}
|
||||
|
||||
void EvictAllCandidates() {
|
||||
EvictJSFunctionCandidates();
|
||||
EvictSharedFunctionInfoCandidates();
|
||||
}
|
||||
|
||||
void IteratePointersToFromSpace(ObjectVisitor* v);
|
||||
|
||||
private:
|
||||
void ProcessJSFunctionCandidates();
|
||||
void ProcessSharedFunctionInfoCandidates();
|
||||
void EvictJSFunctionCandidates();
|
||||
void EvictSharedFunctionInfoCandidates();
|
||||
|
||||
static JSFunction** GetNextCandidateSlot(JSFunction* candidate) {
|
||||
return reinterpret_cast<JSFunction**>(
|
||||
|
@ -1133,6 +1133,65 @@ TEST(TestCodeFlushingIncrementalScavenge) {
|
||||
}
|
||||
|
||||
|
||||
TEST(TestCodeFlushingIncrementalAbort) {
|
||||
// If we do not flush code this test is invalid.
|
||||
if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
InitializeVM();
|
||||
v8::HandleScope scope;
|
||||
const char* source = "function foo() {"
|
||||
" var x = 42;"
|
||||
" var y = 42;"
|
||||
" var z = x + y;"
|
||||
"};"
|
||||
"foo()";
|
||||
Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo");
|
||||
|
||||
// This compile will add the code to the compilation cache.
|
||||
{ v8::HandleScope scope;
|
||||
CompileRun(source);
|
||||
}
|
||||
|
||||
// Check function is 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());
|
||||
|
||||
// The code will survive at least two GCs.
|
||||
HEAP->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
HEAP->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
CHECK(function->shared()->is_compiled());
|
||||
|
||||
// Bump the code age so that flushing is triggered.
|
||||
const int kAgingThreshold = 6;
|
||||
function->shared()->set_code_age(kAgingThreshold);
|
||||
|
||||
// Simulate incremental marking so that the function is enqueued as
|
||||
// code flushing candidate.
|
||||
SimulateIncrementalMarking();
|
||||
|
||||
// Enable the debugger and add a breakpoint while incremental marking
|
||||
// is running so that incremental marking aborts and code flushing is
|
||||
// disabled.
|
||||
int position = 0;
|
||||
Handle<Object> breakpoint_object(Smi::FromInt(0));
|
||||
ISOLATE->debug()->SetBreakPoint(function, breakpoint_object, &position);
|
||||
ISOLATE->debug()->ClearAllBreakPoints();
|
||||
|
||||
// Force optimization now that code flushing is disabled.
|
||||
{ v8::HandleScope scope;
|
||||
CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
|
||||
}
|
||||
|
||||
// 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