Make incremental marking clear ICs.

This extends the existing clearing of ICs during GC to incremental
marking in order to prevent cross-context retention that would last
until the next non-incremental GC.

R=erik.corry@gmail.com
TEST=cctest/test-heap/IncrementalMarkingClears[Mono,Poly]morhpicIC

Review URL: https://chromiumcodereview.appspot.com/10831123

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12259 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mstarzinger@chromium.org 2012-08-06 10:35:48 +00:00
parent e0954ca592
commit 81a43b5607
7 changed files with 167 additions and 36 deletions

View File

@ -789,7 +789,7 @@ void JavaScriptFrame::PrintTop(FILE* file,
ROBUST_STRING_TRAVERSAL);
PrintF(file, " at %s:%d", *c_script_name, line);
} else {
PrintF(file, "at <unknown>:%d", line);
PrintF(file, " at <unknown>:%d", line);
}
} else {
PrintF(file, " at <unknown>:<unknown>");

View File

@ -175,18 +175,6 @@ class IncrementalMarkingMarkingVisitor
table_.Register(kVisitJSRegExp, &VisitJSRegExp);
}
static inline void VisitCodeTarget(Heap* heap, RelocInfo* rinfo) {
ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
if (FLAG_cleanup_code_caches_at_gc && target->is_inline_cache_stub()
&& (target->ic_age() != heap->global_ic_age())) {
IC::Clear(rinfo->pc());
target = Code::GetCodeFromTargetAddress(rinfo->target_address());
}
heap->mark_compact_collector()->RecordRelocSlot(rinfo, Code::cast(target));
MarkObject(heap, target);
}
static void VisitJSWeakMap(Map* map, HeapObject* object) {
Heap* heap = map->GetHeap();
VisitPointers(heap,

View File

@ -64,7 +64,6 @@ MarkCompactCollector::MarkCompactCollector() : // NOLINT
abort_incremental_marking_(false),
compacting_(false),
was_marked_incrementally_(false),
flush_monomorphic_ics_(false),
tracer_(NULL),
migration_slots_buffer_(NULL),
heap_(NULL),
@ -768,12 +767,6 @@ void MarkCompactCollector::AbortCompaction() {
void MarkCompactCollector::Prepare(GCTracer* tracer) {
was_marked_incrementally_ = heap()->incremental_marking()->IsMarking();
// Monomorphic ICs are preserved when possible, but need to be flushed
// when they might be keeping a Context alive, or when the heap is about
// to be serialized.
flush_monomorphic_ics_ =
heap()->isolate()->context_exit_happened() || Serializer::enabled();
// Rather than passing the tracer around we stash it in a static member
// variable.
tracer_ = tracer;
@ -1078,20 +1071,6 @@ class MarkCompactMarkingVisitor
heap->mark_compact_collector()->MarkObject(object, mark);
}
static inline void VisitCodeTarget(Heap* heap, RelocInfo* rinfo) {
ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
if (FLAG_cleanup_code_caches_at_gc && target->is_inline_cache_stub()
&& (target->ic_state() == MEGAMORPHIC ||
heap->mark_compact_collector()->flush_monomorphic_ics_ ||
target->ic_age() != heap->global_ic_age())) {
IC::Clear(rinfo->pc());
target = Code::GetCodeFromTargetAddress(rinfo->target_address());
}
heap->mark_compact_collector()->RecordRelocSlot(rinfo, target);
MarkObject(heap, target);
}
// Mark object pointed to by p.
INLINE(static void MarkObjectByPointer(MarkCompactCollector* collector,
Object** anchor_slot,

View File

@ -612,8 +612,6 @@ class MarkCompactCollector {
bool was_marked_incrementally_;
bool flush_monomorphic_ics_;
// A pointer to the current stack-allocated GC tracer object during a full
// collection (NULL before and after).
GCTracer* tracer_;

View File

@ -208,6 +208,26 @@ void StaticMarkingVisitor<StaticVisitor>::VisitDebugTarget(
}
template<typename StaticVisitor>
void StaticMarkingVisitor<StaticVisitor>::VisitCodeTarget(
Heap* heap, RelocInfo* rinfo) {
ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
// Monomorphic ICs are preserved when possible, but need to be flushed
// when they might be keeping a Context alive, or when the heap is about
// to be serialized.
if (FLAG_cleanup_code_caches_at_gc && target->is_inline_cache_stub()
&& (target->ic_state() == MEGAMORPHIC || Serializer::enabled() ||
heap->isolate()->context_exit_happened() ||
target->ic_age() != heap->global_ic_age())) {
IC::Clear(rinfo->pc());
target = Code::GetCodeFromTargetAddress(rinfo->target_address());
}
heap->mark_compact_collector()->RecordRelocSlot(rinfo, target);
StaticVisitor::MarkObject(heap, target);
}
template<typename StaticVisitor>
void StaticMarkingVisitor<StaticVisitor>::VisitGlobalContext(
Map* map, HeapObject* object) {

View File

@ -390,6 +390,7 @@ class StaticMarkingVisitor : public StaticVisitorBase {
static inline void VisitEmbeddedPointer(Heap* heap, RelocInfo* rinfo);
static inline void VisitGlobalPropertyCell(Heap* heap, RelocInfo* rinfo);
static inline void VisitDebugTarget(Heap* heap, RelocInfo* rinfo);
static inline void VisitCodeTarget(Heap* heap, RelocInfo* rinfo);
static inline void VisitExternalReference(RelocInfo* rinfo) { }
static inline void VisitRuntimeEntry(RelocInfo* rinfo) { }

View File

@ -2081,3 +2081,148 @@ TEST(IncrementalMarkingClearsTypeFeedbackCells) {
CHECK(cells->Cell(0)->value()->IsTheHole());
CHECK(cells->Cell(1)->value()->IsTheHole());
}
static Code* FindFirstIC(Code* code, Code::Kind kind) {
int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
for (RelocIterator it(code, mask); !it.done(); it.next()) {
RelocInfo* info = it.rinfo();
Code* target = Code::GetCodeFromTargetAddress(info->target_address());
if (target->is_inline_cache_stub() && target->kind() == kind) {
return target;
}
}
return NULL;
}
TEST(IncrementalMarkingPreservesMonomorhpicIC) {
if (i::FLAG_always_opt) return;
InitializeVM();
v8::HandleScope scope;
// Prepare function f that contains a monomorphic IC for object
// originating from the same global context.
CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
"function f(o) { return o.x; } f(obj); f(obj);");
Handle<JSFunction> f =
v8::Utils::OpenHandle(
*v8::Handle<v8::Function>::Cast(
v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
CHECK(ic_before->ic_state() == MONOMORPHIC);
// Fire context dispose notification.
v8::V8::ContextDisposedNotification();
// Go through all incremental marking steps in one swoop.
IncrementalMarking* marking = HEAP->incremental_marking();
CHECK(marking->IsStopped());
marking->Start();
CHECK(marking->IsMarking());
while (!marking->IsComplete()) {
marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
}
CHECK(marking->IsComplete());
HEAP->CollectAllGarbage(Heap::kNoGCFlags);
Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
CHECK(ic_after->ic_state() == MONOMORPHIC);
}
TEST(IncrementalMarkingClearsMonomorhpicIC) {
if (i::FLAG_always_opt) return;
InitializeVM();
v8::HandleScope scope;
v8::Local<v8::Value> obj1;
{
LocalContext env;
CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
obj1 = env->Global()->Get(v8_str("obj"));
}
// Prepare function f that contains a monomorphic IC for object
// originating from a different global context.
v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
Handle<JSFunction> f =
v8::Utils::OpenHandle(
*v8::Handle<v8::Function>::Cast(
v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
CHECK(ic_before->ic_state() == MONOMORPHIC);
// Fire context dispose notification.
v8::V8::ContextDisposedNotification();
// Go through all incremental marking steps in one swoop.
IncrementalMarking* marking = HEAP->incremental_marking();
CHECK(marking->IsStopped());
marking->Start();
CHECK(marking->IsMarking());
while (!marking->IsComplete()) {
marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
}
CHECK(marking->IsComplete());
HEAP->CollectAllGarbage(Heap::kNoGCFlags);
Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
CHECK(ic_after->ic_state() == UNINITIALIZED);
}
TEST(IncrementalMarkingClearsPolymorhpicIC) {
if (i::FLAG_always_opt) return;
InitializeVM();
v8::HandleScope scope;
v8::Local<v8::Value> obj1, obj2;
{
LocalContext env;
CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
obj1 = env->Global()->Get(v8_str("obj"));
}
{
LocalContext env;
CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
obj2 = env->Global()->Get(v8_str("obj"));
}
// Prepare function f that contains a polymorphic IC for objects
// originating from two different global contexts.
v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
v8::Context::GetCurrent()->Global()->Set(v8_str("obj2"), obj2);
CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
Handle<JSFunction> f =
v8::Utils::OpenHandle(
*v8::Handle<v8::Function>::Cast(
v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
CHECK(ic_before->ic_state() == MEGAMORPHIC);
// Fire context dispose notification.
v8::V8::ContextDisposedNotification();
// Go through all incremental marking steps in one swoop.
IncrementalMarking* marking = HEAP->incremental_marking();
CHECK(marking->IsStopped());
marking->Start();
CHECK(marking->IsMarking());
while (!marking->IsComplete()) {
marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
}
CHECK(marking->IsComplete());
HEAP->CollectAllGarbage(Heap::kNoGCFlags);
Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
CHECK(ic_after->ic_state() == UNINITIALIZED);
}