Index: src/heap.cc |
=================================================================== |
--- src/heap.cc (revision 4799) |
+++ src/heap.cc (working copy) |
@@ -605,6 +605,9 @@ |
EnsureFromSpaceIsCommitted(); |
if (collector == MARK_COMPACTOR) { |
+ // Flush all potentially unused code. |
+ FlushCode(); |
+ |
// Perform mark-sweep with optional compaction. |
MarkCompact(tracer); |
@@ -2183,6 +2186,85 @@ |
} |
+// The StackVisitor is used to traverse all the archived threads to see if |
+// there are activations on any of the stacks corresponding to the code. |
+class FlushingStackVisitor : public ThreadVisitor { |
+ public: |
+ explicit FlushingStackVisitor(Code* code) : found_(false), code_(code) {} |
+ |
+ void VisitThread(ThreadLocalTop* top) { |
+ // If we already found the code in a previous traversed thread we return. |
+ if (found_) return; |
+ |
+ for (StackFrameIterator it(top); !it.done(); it.Advance()) { |
+ if (code_->contains(it.frame()->pc())) { |
+ found_ = true; |
+ return; |
+ } |
+ } |
+ } |
+ bool FoundCode() {return found_;} |
+ |
+ private: |
+ bool found_; |
+ Code* code_; |
+}; |
+ |
+ |
+static void FlushCodeForFunction(SharedFunctionInfo* function_info) { |
+ // The function must be compiled and have the source code available, |
+ // to be able to recompile it in case we need the function again. |
+ if (!(function_info->is_compiled() && function_info->HasSourceCode())) return; |
+ |
+ // We never flush code for Api functions. |
+ if (function_info->IsApiFunction()) return; |
+ |
+ // Only flush code for functions. |
+ if (!function_info->code()->kind() == Code::FUNCTION) return; |
+ |
+ // Function must be lazy compilable. |
+ if (!function_info->allows_lazy_compilation()) return; |
+ |
+ // If this is a full script wrapped in a function we do no flush the code. |
+ if (function_info->is_toplevel()) return; |
+ |
+ // If this function is in the compilation cache we do not flush the code. |
+ if (CompilationCache::HasFunction(function_info)) return; |
+ |
+ // Make sure we are not referencing the code from the stack. |
+ for (StackFrameIterator it; !it.done(); it.Advance()) { |
+ if (function_info->code()->contains(it.frame()->pc())) return; |
+ } |
+ // Iterate the archived stacks in all threads to check if |
+ // the code is referenced. |
+ FlushingStackVisitor threadvisitor(function_info->code()); |
+ ThreadManager::IterateArchivedThreads(&threadvisitor); |
+ if (threadvisitor.FoundCode()) return; |
+ |
+ HandleScope scope; |
+ // Compute the lazy compilable version of the code. |
+ function_info->set_code(*ComputeLazyCompile(function_info->length())); |
+} |
+ |
+ |
+void Heap::FlushCode() { |
+ // Do not flush code if the debugger is loaded or there are breakpoints. |
+ if (Debug::IsLoaded() || Debug::has_break_points()) return; |
+ HeapObjectIterator it(old_pointer_space()); |
+ for (HeapObject* obj = it.next(); obj != NULL; obj = it.next()) { |
+ if (obj->IsJSFunction()) { |
+ JSFunction* jsfunction = JSFunction::cast(obj); |
+ |
+ // The function must have a valid context and not be a builtin. |
+ if (jsfunction->unchecked_context()->IsContext() && |
+ !jsfunction->IsBuiltin()) { |
+ FlushCodeForFunction(jsfunction->shared()); |
+ } |
+ } |
+ } |
+} |
+ |
+ |
Object* Heap::CreateCode(const CodeDesc& desc, |
ZoneScopeInfo* sinfo, |
Code::Flags flags, |