diff --git a/src/frames.cc b/src/frames.cc index c801123671..9fb1820265 100644 --- a/src/frames.cc +++ b/src/frames.cc @@ -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 :%d", line); + PrintF(file, " at :%d", line); } } else { PrintF(file, " at :"); diff --git a/src/incremental-marking.cc b/src/incremental-marking.cc index 1be7aff6c8..f41a31d6a7 100644 --- a/src/incremental-marking.cc +++ b/src/incremental-marking.cc @@ -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, diff --git a/src/mark-compact.cc b/src/mark-compact.cc index f9ea3e6faa..cf4c2f2521 100644 --- a/src/mark-compact.cc +++ b/src/mark-compact.cc @@ -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, diff --git a/src/mark-compact.h b/src/mark-compact.h index b94355bf45..f4915519aa 100644 --- a/src/mark-compact.h +++ b/src/mark-compact.h @@ -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_; diff --git a/src/objects-visiting-inl.h b/src/objects-visiting-inl.h index 61fcbec3ab..f2b0e243e3 100644 --- a/src/objects-visiting-inl.h +++ b/src/objects-visiting-inl.h @@ -208,6 +208,26 @@ void StaticMarkingVisitor::VisitDebugTarget( } +template +void StaticMarkingVisitor::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 void StaticMarkingVisitor::VisitGlobalContext( Map* map, HeapObject* object) { diff --git a/src/objects-visiting.h b/src/objects-visiting.h index 67b3af8d59..d19e76895d 100644 --- a/src/objects-visiting.h +++ b/src/objects-visiting.h @@ -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) { } diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc index 89ac13f5c0..f6b78b8cbd 100644 --- a/test/cctest/test-heap.cc +++ b/test/cctest/test-heap.cc @@ -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 f = + v8::Utils::OpenHandle( + *v8::Handle::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 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 f = + v8::Utils::OpenHandle( + *v8::Handle::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 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 f = + v8::Utils::OpenHandle( + *v8::Handle::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); +}