Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(569)

Unified Diff: src/mark-compact.cc

Issue 3135026: Merge flush code phase into marking phase. (Closed)
Patch Set: returned checked casts Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/mark-compact.h ('k') | src/objects.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/mark-compact.cc
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 1a020e55d14031d2ee457f8d380a9ed3c5ca96a8..26dfbb8a657e6d0ce86e5a06ed8a3ba1cb85e593 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -27,6 +27,7 @@
#include "v8.h"
+#include "compilation-cache.h"
#include "execution.h"
#include "heap-profiler.h"
#include "global-handles.h"
@@ -252,6 +253,15 @@ class StaticMarkingVisitor : public StaticVisitorBase {
table_.GetVisitor(map)(map, obj);
}
+ static void EnableCodeFlushing(bool enabled) {
+ if (enabled) {
+ table_.Register(kVisitJSFunction, &VisitJSFunction);
+ } else {
+ table_.Register(kVisitJSFunction,
+ &JSObjectVisitor::VisitSpecialized<JSFunction::kSize>);
+ }
+ }
+
static void Initialize() {
table_.Register(kVisitShortcutCandidate,
&FixedBodyVisitor<StaticMarkingVisitor,
@@ -289,6 +299,8 @@ class StaticMarkingVisitor : public StaticVisitorBase {
table_.Register(kVisitCode, &VisitCode);
+ table_.Register(kVisitJSFunction, &VisitJSFunction);
+
table_.Register(kVisitPropertyCell,
&FixedBodyVisitor<StaticMarkingVisitor,
JSGlobalPropertyCell::BodyDescriptor,
@@ -405,6 +417,134 @@ class StaticMarkingVisitor : public StaticVisitorBase {
reinterpret_cast<Code*>(object)->CodeIterateBody<StaticMarkingVisitor>();
}
+ // Code flushing support.
+
+ // How many collections newly compiled code object will survive before being
+ // flushed.
+ static const int kCodeAgeThreshold = 5;
+
+ inline static bool HasSourceCode(SharedFunctionInfo* info) {
+ Object* undefined = Heap::raw_unchecked_undefined_value();
+ return (info->script() != undefined) &&
+ (reinterpret_cast<Script*>(info->script())->source() != undefined);
+ }
+
+
+ inline static bool IsCompiled(JSFunction* function) {
+ return
+ function->unchecked_code() != Builtins::builtin(Builtins::LazyCompile);
+ }
+
+
+ inline static bool IsCompiled(SharedFunctionInfo* function) {
+ return
+ function->unchecked_code() != Builtins::builtin(Builtins::LazyCompile);
+ }
+
+
+ static void FlushCodeForFunction(JSFunction* function) {
+ SharedFunctionInfo* shared_info = function->unchecked_shared();
+
+ if (shared_info->IsMarked()) return;
+
+ // Special handling if the function and shared info objects
+ // have different code objects.
+ if (function->unchecked_code() != shared_info->unchecked_code()) {
+ // If the shared function has been flushed but the function has not,
+ // we flush the function if possible.
+ if (!IsCompiled(shared_info) &&
+ IsCompiled(function) &&
+ !function->unchecked_code()->IsMarked()) {
+ function->set_code(shared_info->unchecked_code());
+ }
+ return;
+ }
+
+ // Code is either on stack or in compilation cache.
+ if (shared_info->unchecked_code()->IsMarked()) {
+ shared_info->set_code_age(0);
+ return;
+ }
+
+ // 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 (!(shared_info->is_compiled() && HasSourceCode(shared_info))) return;
+
+ // We never flush code for Api functions.
+ Object* function_data = shared_info->function_data();
+ if (function_data->IsHeapObject() &&
+ (SafeMap(function_data)->instance_type() ==
+ FUNCTION_TEMPLATE_INFO_TYPE)) {
+ return;
+ }
+
+ // Only flush code for functions.
+ if (shared_info->code()->kind() != Code::FUNCTION) return;
+
+ // Function must be lazy compilable.
+ if (!shared_info->allows_lazy_compilation()) return;
+
+ // If this is a full script wrapped in a function we do no flush the code.
+ if (shared_info->is_toplevel()) return;
+
+ // Age this shared function info.
+ if (shared_info->code_age() < kCodeAgeThreshold) {
+ shared_info->set_code_age(shared_info->code_age() + 1);
+ return;
+ }
+
+ // Compute the lazy compilable version of the code.
+ Code* code = Builtins::builtin(Builtins::LazyCompile);
+ shared_info->set_code(code);
+ function->set_code(code);
+ }
+
+
+ static inline Map* SafeMap(Object* obj) {
+ MapWord map_word = HeapObject::cast(obj)->map_word();
+ map_word.ClearMark();
+ map_word.ClearOverflow();
+ return map_word.ToMap();
+ }
+
+
+ static inline bool IsJSBuiltinsObject(Object* obj) {
+ return obj->IsHeapObject() &&
+ (SafeMap(obj)->instance_type() == JS_BUILTINS_OBJECT_TYPE);
+ }
+
+
+ static inline bool IsValidNotBuiltinContext(Object* ctx) {
+ if (!ctx->IsHeapObject()) return false;
+
+ Map* map = SafeMap(ctx);
+ if(!(map == Heap::raw_unchecked_context_map() ||
+ map == Heap::raw_unchecked_catch_context_map() ||
+ map == Heap::raw_unchecked_global_context_map())) {
+ return false;
+ }
+
+ Context* context = reinterpret_cast<Context*>(ctx);
+
+ if(IsJSBuiltinsObject(context->global())) {
+ return false;
+ }
+
+ return true;
+ }
+
+
+ static void VisitJSFunction(Map* map, HeapObject* object) {
+ JSFunction* jsfunction = reinterpret_cast<JSFunction*>(object);
+
+ // The function must have a valid context and not be a builtin.
+ if (IsValidNotBuiltinContext(jsfunction->unchecked_context())) {
+ FlushCodeForFunction(jsfunction);
+ }
+
+ JSObjectVisitor::VisitSpecialized<JSFunction::kSize>(map, object);
+ }
+
typedef void (*Callback)(Map* map, HeapObject* object);
static VisitorDispatchTable<Callback> table_;
@@ -435,6 +575,62 @@ class MarkingVisitor : public ObjectVisitor {
};
+class CodeMarkingVisitor : public ThreadVisitor {
+ public:
+ void VisitThread(ThreadLocalTop* top) {
+ for (StackFrameIterator it(top); !it.done(); it.Advance()) {
+ MarkCompactCollector::MarkObject(it.frame()->unchecked_code());
+ }
+ }
+};
+
+
+class SharedFunctionInfoMarkingVisitor : public ObjectVisitor {
+ public:
+ void VisitPointers(Object** start, Object** end) {
+ for (Object** p = start; p < end; p++) VisitPointer(p);
+ }
+
+ void VisitPointer(Object** slot) {
+ Object* obj = *slot;
+ if (obj->IsHeapObject()) {
+ MarkCompactCollector::MarkObject(HeapObject::cast(obj));
+ }
+ }
+};
+
+
+void MarkCompactCollector::PrepareForCodeFlushing() {
+ if (!FLAG_flush_code) {
+ StaticMarkingVisitor::EnableCodeFlushing(false);
+ return;
+ }
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ if (Debug::IsLoaded() || Debug::has_break_points()) {
+ StaticMarkingVisitor::EnableCodeFlushing(false);
+ return;
+ }
+#endif
+ StaticMarkingVisitor::EnableCodeFlushing(true);
+
+ // Make sure we are not referencing the code from the stack.
+ for (StackFrameIterator it; !it.done(); it.Advance()) {
+ MarkCompactCollector::MarkObject(it.frame()->unchecked_code());
+ }
+
+ // Iterate the archived stacks in all threads to check if
+ // the code is referenced.
+ CodeMarkingVisitor code_marking_visitor;
+ ThreadManager::IterateArchivedThreads(&code_marking_visitor);
+
+ SharedFunctionInfoMarkingVisitor visitor;
+ CompilationCache::IterateFunctions(&visitor);
+
+ MarkCompactCollector::ProcessMarkingStack();
+}
+
+
// Visitor class for marking heap roots.
class RootMarkingVisitor : public ObjectVisitor {
public:
@@ -793,6 +989,8 @@ void MarkCompactCollector::MarkLiveObjects() {
ASSERT(!marking_stack.overflowed());
+ PrepareForCodeFlushing();
+
RootMarkingVisitor root_visitor;
MarkRoots(&root_visitor);
« no previous file with comments | « src/mark-compact.h ('k') | src/objects.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698