Index: test/cctest/test-heap.cc |
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc |
index 4ca1a68f4bfa9a83c4806538a0a4a678cf09b336..eb9ebb721eef4ac3287c942842c9038744ba4c4a 100644 |
--- a/test/cctest/test-heap.cc |
+++ b/test/cctest/test-heap.cc |
@@ -2627,3 +2627,72 @@ TEST(Regress165495) { |
// Unoptimized code is missing and the deoptimizer will go ballistic. |
CompileRun("var g = mkClosure(); g('bozo');"); |
} |
+ |
+ |
+TEST(Regress169209) { |
+ i::FLAG_allow_natives_syntax = true; |
+ i::FLAG_flush_code_incrementally = true; |
+ InitializeVM(); |
+ v8::HandleScope scope; |
+ |
+ // Perform one initial GC to enable code flushing. |
+ HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); |
+ |
+ // Prepare a shared function info eligible for code flushing for which |
+ // the unoptimized code will be replaced during optimization. |
+ Handle<SharedFunctionInfo> shared1; |
+ { |
+ HandleScope inner_scope; |
+ CompileRun("function f() { return 'foobar'; }" |
+ "function g(x) { if (x) f(); }" |
+ "f();" |
+ "g(false);" |
+ "g(false);"); |
+ |
+ Handle<JSFunction> f = |
+ v8::Utils::OpenHandle( |
+ *v8::Handle<v8::Function>::Cast( |
+ v8::Context::GetCurrent()->Global()->Get(v8_str("f")))); |
+ CHECK(f->is_compiled()); |
+ const int kAgingThreshold = 6; |
+ for (int i = 0; i < kAgingThreshold; i++) { |
+ f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2)); |
+ } |
+ |
+ shared1 = inner_scope.CloseAndEscape(handle(f->shared(), ISOLATE)); |
+ } |
+ |
+ // Prepare a shared function info eligible for code flushing that will |
+ // represent the dangling tail of the candidate list. |
+ Handle<SharedFunctionInfo> shared2; |
+ { |
+ HandleScope inner_scope; |
+ CompileRun("function flushMe() { return 0; }" |
+ "flushMe(1);"); |
+ |
+ Handle<JSFunction> f = |
+ v8::Utils::OpenHandle( |
+ *v8::Handle<v8::Function>::Cast( |
+ v8::Context::GetCurrent()->Global()->Get(v8_str("flushMe")))); |
+ CHECK(f->is_compiled()); |
+ const int kAgingThreshold = 6; |
+ for (int i = 0; i < kAgingThreshold; i++) { |
+ f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2)); |
+ } |
+ |
+ shared2 = inner_scope.CloseAndEscape(handle(f->shared(), ISOLATE)); |
+ } |
+ |
+ // Simulate incremental marking and collect code flushing candidates. |
+ SimulateIncrementalMarking(); |
+ CHECK(shared1->code()->gc_metadata() != NULL); |
+ |
+ // Optimize function and make sure the unoptimized code is replaced. |
+ FLAG_stop_at = "f"; |
+ CompileRun("%OptimizeFunctionOnNextCall(g);" |
+ "g(false);"); |
+ |
+ // Finish garbage collection cycle. |
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
+ CHECK(shared1->code()->gc_metadata() == NULL); |
+} |