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:
parent
e0954ca592
commit
81a43b5607
@ -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>");
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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_;
|
||||
|
@ -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) {
|
||||
|
@ -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) { }
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user