Revision: 13361
Author: [email protected]
Date: Fri Jan 11 05:13:11 2013
Log: Fix shared function info code replacement.
This fixes a corner case when the unoptimized code for a shared function
info is replaced while the function is enqueued as a flushing candidate.
Since the link field is stored within the code object, the candidates
list got destroyed.
[email protected]
BUG=v8:169209
TEST=cctest/test-heap/Regress169209
Review URL: https://codereview.chromium.org/11818052
http://code.google.com/p/v8/source/detail?r=13361
Modified:
/branches/bleeding_edge/src/compiler.cc
/branches/bleeding_edge/src/mark-compact.cc
/branches/bleeding_edge/src/mark-compact.h
/branches/bleeding_edge/src/objects-inl.h
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/test/cctest/test-heap.cc
=======================================
--- /branches/bleeding_edge/src/compiler.cc Wed Jan 9 02:30:54 2013
+++ /branches/bleeding_edge/src/compiler.cc Fri Jan 11 05:13:11 2013
@@ -739,7 +739,7 @@
Handle<ScopeInfo> scope_info =
ScopeInfo::Create(info->scope(), info->zone());
shared->set_scope_info(*scope_info);
- shared->set_code(*code);
+ shared->ReplaceCode(*code);
if (!function.is_null()) {
function->ReplaceCode(*code);
ASSERT(!function->IsOptimized());
=======================================
--- /branches/bleeding_edge/src/mark-compact.cc Mon Jan 7 07:02:56 2013
+++ /branches/bleeding_edge/src/mark-compact.cc Fri Jan 11 05:13:11 2013
@@ -885,8 +885,8 @@
if (!code_mark.Get()) {
shared->set_code(lazy_compile);
candidate->set_code(lazy_compile);
- } else if (code == lazy_compile) {
- candidate->set_code(lazy_compile);
+ } else {
+ candidate->set_code(code);
}
// We are in the middle of a GC cycle so the write barrier in the code
@@ -933,6 +933,34 @@
shared_function_info_candidates_head_ = NULL;
}
+
+
+void CodeFlusher::EvictCandidate(SharedFunctionInfo* shared_info) {
+ // The function is no longer a candidate, make sure it gets visited
+ // again so that previous flushing decisions are revisited.
+ isolate_->heap()->incremental_marking()->RecordWrites(shared_info);
+
+ SharedFunctionInfo* candidate = shared_function_info_candidates_head_;
+ SharedFunctionInfo* next_candidate;
+ if (candidate == shared_info) {
+ next_candidate = GetNextCandidate(shared_info);
+ shared_function_info_candidates_head_ = next_candidate;
+ ClearNextCandidate(shared_info);
+ } else {
+ while (candidate != NULL) {
+ next_candidate = GetNextCandidate(candidate);
+
+ if (next_candidate == shared_info) {
+ next_candidate = GetNextCandidate(shared_info);
+ SetNextCandidate(candidate, next_candidate);
+ ClearNextCandidate(shared_info);
+ break;
+ }
+
+ candidate = next_candidate;
+ }
+ }
+}
void CodeFlusher::EvictCandidate(JSFunction* function) {
@@ -957,6 +985,7 @@
next_candidate = GetNextCandidate(function);
SetNextCandidate(candidate, next_candidate);
ClearNextCandidate(function, undefined);
+ break;
}
candidate = next_candidate;
=======================================
--- /branches/bleeding_edge/src/mark-compact.h Tue Dec 4 02:23:43 2012
+++ /branches/bleeding_edge/src/mark-compact.h Fri Jan 11 05:13:11 2013
@@ -434,6 +434,7 @@
}
}
+ void EvictCandidate(SharedFunctionInfo* shared_info);
void EvictCandidate(JSFunction* function);
void ProcessCandidates() {
=======================================
--- /branches/bleeding_edge/src/objects-inl.h Thu Jan 10 06:15:12 2013
+++ /branches/bleeding_edge/src/objects-inl.h Fri Jan 11 05:13:11 2013
@@ -4378,6 +4378,19 @@
WRITE_FIELD(this, kCodeOffset, value);
CONDITIONAL_WRITE_BARRIER(value->GetHeap(), this, kCodeOffset, value,
mode);
}
+
+
+void SharedFunctionInfo::ReplaceCode(Code* value) {
+ // If the GC metadata field is already used then the function was
+ // enqueued as a code flushing candidate and we remove it now.
+ if (code()->gc_metadata() != NULL) {
+ CodeFlusher* flusher =
GetHeap()->mark_compact_collector()->code_flusher();
+ flusher->EvictCandidate(this);
+ }
+
+ ASSERT(code()->gc_metadata() == NULL && value->gc_metadata() == NULL);
+ set_code(value);
+}
ScopeInfo* SharedFunctionInfo::scope_info() {
=======================================
--- /branches/bleeding_edge/src/objects.cc Thu Jan 10 06:15:12 2013
+++ /branches/bleeding_edge/src/objects.cc Fri Jan 11 05:13:11 2013
@@ -8292,7 +8292,7 @@
// old code, we have to replace it. We should try to avoid this
// altogether because it flushes valuable type feedback by
// effectively resetting all IC state.
- set_code(recompiled);
+ ReplaceCode(recompiled);
}
ASSERT(has_deoptimization_support());
}
=======================================
--- /branches/bleeding_edge/src/objects.h Thu Jan 10 06:15:12 2013
+++ /branches/bleeding_edge/src/objects.h Fri Jan 11 05:13:11 2013
@@ -5393,6 +5393,7 @@
// [code]: Function code.
DECL_ACCESSORS(code, Code)
+ inline void ReplaceCode(Code* code);
// [optimized_code_map]: Map from native context to optimized code
// and a shared literals array or Smi 0 if none.
=======================================
--- /branches/bleeding_edge/src/runtime.cc Wed Jan 9 07:47:53 2013
+++ /branches/bleeding_edge/src/runtime.cc Fri Jan 11 05:13:11 2013
@@ -2147,7 +2147,7 @@
// target function to undefined. SetCode is only used for built-in
// constructors like String, Array, and Object, and some web code
// doesn't like seeing source code for constructors.
- target_shared->set_code(source_shared->code());
+ target_shared->ReplaceCode(source_shared->code());
target_shared->set_scope_info(source_shared->scope_info());
target_shared->set_length(source_shared->length());
target_shared->set_formal_parameter_count(
=======================================
--- /branches/bleeding_edge/test/cctest/test-heap.cc Wed Jan 9 02:30:54
2013
+++ /branches/bleeding_edge/test/cctest/test-heap.cc Fri Jan 11 05:13:11
2013
@@ -2627,3 +2627,74 @@
// 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.
+#ifdef DEBUG
+ FLAG_stop_at = "f";
+#endif
+ CompileRun("%OptimizeFunctionOnNextCall(g);"
+ "g(false);");
+
+ // Finish garbage collection cycle.
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+ CHECK(shared1->code()->gc_metadata() == NULL);
+}
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev