Index: test/cctest/test-heap.cc |
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc |
index 94748cbf202d48cff84a1e78fd1aaf112319286c..cca17d1142edcf196cffd42d1f50a7b8c82ea491 100644 |
--- a/test/cctest/test-heap.cc |
+++ b/test/cctest/test-heap.cc |
@@ -2077,3 +2077,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); |
+} |