Index: src/mark-compact.cc |
diff --git a/src/mark-compact.cc b/src/mark-compact.cc |
index 2704f51f0adf83ed3d90a1de4dcb14ce0e189c4a..c55f39566618f05720399d15b02986a7771b9299 100644 |
--- a/src/mark-compact.cc |
+++ b/src/mark-compact.cc |
@@ -857,133 +857,69 @@ void MarkCompactCollector::Finish() { |
// and continue with marking. This process repeats until all reachable |
// objects have been marked. |
-class CodeFlusher { |
- public: |
- explicit CodeFlusher(Isolate* isolate) |
- : isolate_(isolate), |
- jsfunction_candidates_head_(NULL), |
- shared_function_info_candidates_head_(NULL) {} |
- |
- void AddCandidate(SharedFunctionInfo* shared_info) { |
- SetNextCandidate(shared_info, shared_function_info_candidates_head_); |
- shared_function_info_candidates_head_ = shared_info; |
- } |
+void CodeFlusher::ProcessJSFunctionCandidates() { |
+ Code* lazy_compile = isolate_->builtins()->builtin(Builtins::kLazyCompile); |
- void AddCandidate(JSFunction* function) { |
- ASSERT(function->code() == function->shared()->code()); |
+ JSFunction* candidate = jsfunction_candidates_head_; |
+ JSFunction* next_candidate; |
+ while (candidate != NULL) { |
+ next_candidate = GetNextCandidate(candidate); |
- SetNextCandidate(function, jsfunction_candidates_head_); |
- jsfunction_candidates_head_ = function; |
- } |
- |
- void ProcessCandidates() { |
- ProcessSharedFunctionInfoCandidates(); |
- ProcessJSFunctionCandidates(); |
- } |
+ SharedFunctionInfo* shared = candidate->shared(); |
- private: |
- void ProcessJSFunctionCandidates() { |
- Code* lazy_compile = isolate_->builtins()->builtin(Builtins::kLazyCompile); |
- |
- JSFunction* candidate = jsfunction_candidates_head_; |
- JSFunction* next_candidate; |
- while (candidate != NULL) { |
- next_candidate = GetNextCandidate(candidate); |
- |
- SharedFunctionInfo* shared = candidate->shared(); |
- |
- Code* code = shared->code(); |
- MarkBit code_mark = Marking::MarkBitFrom(code); |
- if (!code_mark.Get()) { |
- shared->set_code(lazy_compile); |
- candidate->set_code(lazy_compile); |
- } else { |
- candidate->set_code(shared->code()); |
- } |
- |
- // We are in the middle of a GC cycle so the write barrier in the code |
- // setter did not record the slot update and we have to do that manually. |
- Address slot = candidate->address() + JSFunction::kCodeEntryOffset; |
- Code* target = Code::cast(Code::GetObjectFromEntryAddress(slot)); |
- isolate_->heap()->mark_compact_collector()-> |
- RecordCodeEntrySlot(slot, target); |
- |
- RecordSharedFunctionInfoCodeSlot(shared); |
- |
- candidate = next_candidate; |
+ Code* code = shared->code(); |
+ MarkBit code_mark = Marking::MarkBitFrom(code); |
+ if (!code_mark.Get()) { |
+ shared->set_code(lazy_compile); |
+ candidate->set_code(lazy_compile); |
+ } else { |
+ candidate->set_code(shared->code()); |
} |
- jsfunction_candidates_head_ = NULL; |
- } |
- |
- |
- void ProcessSharedFunctionInfoCandidates() { |
- Code* lazy_compile = isolate_->builtins()->builtin(Builtins::kLazyCompile); |
- |
- SharedFunctionInfo* candidate = shared_function_info_candidates_head_; |
- SharedFunctionInfo* next_candidate; |
- while (candidate != NULL) { |
- next_candidate = GetNextCandidate(candidate); |
- SetNextCandidate(candidate, NULL); |
- |
- Code* code = candidate->code(); |
- MarkBit code_mark = Marking::MarkBitFrom(code); |
- if (!code_mark.Get()) { |
- candidate->set_code(lazy_compile); |
- } |
- |
- RecordSharedFunctionInfoCodeSlot(candidate); |
+ // We are in the middle of a GC cycle so the write barrier in the code |
+ // setter did not record the slot update and we have to do that manually. |
+ Address slot = candidate->address() + JSFunction::kCodeEntryOffset; |
+ Code* target = Code::cast(Code::GetObjectFromEntryAddress(slot)); |
+ isolate_->heap()->mark_compact_collector()-> |
+ RecordCodeEntrySlot(slot, target); |
- candidate = next_candidate; |
- } |
+ Object** shared_code_slot = |
+ HeapObject::RawField(shared, SharedFunctionInfo::kCodeOffset); |
+ isolate_->heap()->mark_compact_collector()-> |
+ RecordSlot(shared_code_slot, shared_code_slot, *shared_code_slot); |
- shared_function_info_candidates_head_ = NULL; |
+ candidate = next_candidate; |
} |
- void RecordSharedFunctionInfoCodeSlot(SharedFunctionInfo* shared) { |
- Object** slot = HeapObject::RawField(shared, |
- SharedFunctionInfo::kCodeOffset); |
- isolate_->heap()->mark_compact_collector()-> |
- RecordSlot(slot, slot, HeapObject::cast(*slot)); |
- } |
+ jsfunction_candidates_head_ = NULL; |
+} |
- static JSFunction** GetNextCandidateField(JSFunction* candidate) { |
- return reinterpret_cast<JSFunction**>( |
- candidate->address() + JSFunction::kCodeEntryOffset); |
- } |
- static JSFunction* GetNextCandidate(JSFunction* candidate) { |
- return *GetNextCandidateField(candidate); |
- } |
+void CodeFlusher::ProcessSharedFunctionInfoCandidates() { |
+ Code* lazy_compile = isolate_->builtins()->builtin(Builtins::kLazyCompile); |
- static void SetNextCandidate(JSFunction* candidate, |
- JSFunction* next_candidate) { |
- *GetNextCandidateField(candidate) = next_candidate; |
- } |
+ SharedFunctionInfo* candidate = shared_function_info_candidates_head_; |
+ SharedFunctionInfo* next_candidate; |
+ while (candidate != NULL) { |
+ next_candidate = GetNextCandidate(candidate); |
+ SetNextCandidate(candidate, NULL); |
- static SharedFunctionInfo** GetNextCandidateField( |
- SharedFunctionInfo* candidate) { |
Code* code = candidate->code(); |
- return reinterpret_cast<SharedFunctionInfo**>( |
- code->address() + Code::kGCMetadataOffset); |
- } |
+ MarkBit code_mark = Marking::MarkBitFrom(code); |
+ if (!code_mark.Get()) { |
+ candidate->set_code(lazy_compile); |
+ } |
- static SharedFunctionInfo* GetNextCandidate(SharedFunctionInfo* candidate) { |
- return reinterpret_cast<SharedFunctionInfo*>( |
- candidate->code()->gc_metadata()); |
- } |
+ Object** code_slot = |
+ HeapObject::RawField(candidate, SharedFunctionInfo::kCodeOffset); |
+ isolate_->heap()->mark_compact_collector()-> |
+ RecordSlot(code_slot, code_slot, *code_slot); |
- static void SetNextCandidate(SharedFunctionInfo* candidate, |
- SharedFunctionInfo* next_candidate) { |
- candidate->code()->set_gc_metadata(next_candidate); |
+ candidate = next_candidate; |
} |
- Isolate* isolate_; |
- JSFunction* jsfunction_candidates_head_; |
- SharedFunctionInfo* shared_function_info_candidates_head_; |
- |
- DISALLOW_COPY_AND_ASSIGN(CodeFlusher); |
-}; |
+ shared_function_info_candidates_head_ = NULL; |
+} |
MarkCompactCollector::~MarkCompactCollector() { |
@@ -1163,6 +1099,11 @@ class MarkCompactMarkingVisitor |
return true; |
} |
+ INLINE(static void BeforeVisitingSharedFunctionInfo(HeapObject* object)) { |
+ SharedFunctionInfo* shared = SharedFunctionInfo::cast(object); |
+ shared->BeforeVisitingPointers(); |
+ } |
+ |
static void VisitJSWeakMap(Map* map, HeapObject* object) { |
MarkCompactCollector* collector = map->GetHeap()->mark_compact_collector(); |
JSWeakMap* weak_map = reinterpret_cast<JSWeakMap*>(object); |
@@ -1206,123 +1147,8 @@ class MarkCompactMarkingVisitor |
// Code flushing support. |
- // How many collections newly compiled code object will survive before being |
- // flushed. |
- static const int kCodeAgeThreshold = 5; |
- |
static const int kRegExpCodeThreshold = 5; |
- inline static bool HasSourceCode(Heap* heap, SharedFunctionInfo* info) { |
- Object* undefined = heap->undefined_value(); |
- return (info->script() != undefined) && |
- (reinterpret_cast<Script*>(info->script())->source() != undefined); |
- } |
- |
- |
- inline static bool IsCompiled(JSFunction* function) { |
- return function->code() != |
- function->GetIsolate()->builtins()->builtin(Builtins::kLazyCompile); |
- } |
- |
- inline static bool IsCompiled(SharedFunctionInfo* function) { |
- return function->code() != |
- function->GetIsolate()->builtins()->builtin(Builtins::kLazyCompile); |
- } |
- |
- inline static bool IsFlushable(Heap* heap, JSFunction* function) { |
- SharedFunctionInfo* shared_info = function->unchecked_shared(); |
- |
- // Code is either on stack, in compilation cache or referenced |
- // by optimized version of function. |
- MarkBit code_mark = Marking::MarkBitFrom(function->code()); |
- if (code_mark.Get()) { |
- if (!Marking::MarkBitFrom(shared_info).Get()) { |
- shared_info->set_code_age(0); |
- } |
- return false; |
- } |
- |
- // We do not flush code for optimized functions. |
- if (function->code() != shared_info->code()) { |
- return false; |
- } |
- |
- return IsFlushable(heap, shared_info); |
- } |
- |
- inline static bool IsFlushable(Heap* heap, SharedFunctionInfo* shared_info) { |
- // Code is either on stack, in compilation cache or referenced |
- // by optimized version of function. |
- MarkBit code_mark = |
- Marking::MarkBitFrom(shared_info->code()); |
- if (code_mark.Get()) { |
- return false; |
- } |
- |
- // 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(heap, shared_info))) { |
- return false; |
- } |
- |
- // We never flush code for Api functions. |
- Object* function_data = shared_info->function_data(); |
- if (function_data->IsFunctionTemplateInfo()) { |
- return false; |
- } |
- |
- // Only flush code for functions. |
- if (shared_info->code()->kind() != Code::FUNCTION) { |
- return false; |
- } |
- |
- // Function must be lazy compilable. |
- if (!shared_info->allows_lazy_compilation()) { |
- return false; |
- } |
- |
- // If this is a full script wrapped in a function we do no flush the code. |
- if (shared_info->is_toplevel()) { |
- return false; |
- } |
- |
- // Age this shared function info. |
- if (shared_info->code_age() < kCodeAgeThreshold) { |
- shared_info->set_code_age(shared_info->code_age() + 1); |
- return false; |
- } |
- |
- return true; |
- } |
- |
- |
- static bool FlushCodeForFunction(Heap* heap, JSFunction* function) { |
- if (!IsFlushable(heap, function)) return false; |
- |
- // This function's code looks flushable. But we have to postpone the |
- // decision until we see all functions that point to the same |
- // SharedFunctionInfo because some of them might be optimized. |
- // That would make the nonoptimized version of the code nonflushable, |
- // because it is required for bailing out from optimized code. |
- heap->mark_compact_collector()->code_flusher()->AddCandidate(function); |
- return true; |
- } |
- |
- static inline bool IsValidNotBuiltinContext(Object* ctx) { |
- return ctx->IsContext() && |
- !Context::cast(ctx)->global_object()->IsJSBuiltinsObject(); |
- } |
- |
- |
- static void VisitSharedFunctionInfoGeneric(Map* map, HeapObject* object) { |
- SharedFunctionInfo::cast(object)->BeforeVisitingPointers(); |
- |
- FixedBodyVisitor<MarkCompactMarkingVisitor, |
- SharedFunctionInfo::BodyDescriptor, |
- void>::Visit(map, object); |
- } |
- |
- |
static void UpdateRegExpCodeAgeAndFlush(Heap* heap, |
JSRegExp* re, |
bool is_ascii) { |
@@ -1396,143 +1222,6 @@ class MarkCompactMarkingVisitor |
VisitJSRegExp(map, object); |
} |
- |
- static void VisitSharedFunctionInfoAndFlushCode(Map* map, |
- HeapObject* object) { |
- Heap* heap = map->GetHeap(); |
- SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(object); |
- if (shared->ic_age() != heap->global_ic_age()) { |
- shared->ResetForNewContext(heap->global_ic_age()); |
- } |
- |
- MarkCompactCollector* collector = map->GetHeap()->mark_compact_collector(); |
- if (!collector->is_code_flushing_enabled()) { |
- VisitSharedFunctionInfoGeneric(map, object); |
- return; |
- } |
- VisitSharedFunctionInfoAndFlushCodeGeneric(map, object, false); |
- } |
- |
- |
- static void VisitSharedFunctionInfoAndFlushCodeGeneric( |
- Map* map, HeapObject* object, bool known_flush_code_candidate) { |
- Heap* heap = map->GetHeap(); |
- SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(object); |
- |
- shared->BeforeVisitingPointers(); |
- |
- if (!known_flush_code_candidate) { |
- known_flush_code_candidate = IsFlushable(heap, shared); |
- if (known_flush_code_candidate) { |
- heap->mark_compact_collector()->code_flusher()->AddCandidate(shared); |
- } |
- } |
- |
- VisitSharedFunctionInfoFields(heap, object, known_flush_code_candidate); |
- } |
- |
- |
- static void VisitJSFunctionAndFlushCode(Map* map, HeapObject* object) { |
- Heap* heap = map->GetHeap(); |
- MarkCompactCollector* collector = heap->mark_compact_collector(); |
- if (!collector->is_code_flushing_enabled()) { |
- VisitJSFunction(map, object); |
- return; |
- } |
- |
- JSFunction* jsfunction = reinterpret_cast<JSFunction*>(object); |
- // The function must have a valid context and not be a builtin. |
- bool flush_code_candidate = false; |
- if (IsValidNotBuiltinContext(jsfunction->unchecked_context())) { |
- flush_code_candidate = FlushCodeForFunction(heap, jsfunction); |
- } |
- |
- if (!flush_code_candidate) { |
- Code* code = jsfunction->shared()->code(); |
- MarkBit code_mark = Marking::MarkBitFrom(code); |
- collector->MarkObject(code, code_mark); |
- |
- if (jsfunction->code()->kind() == Code::OPTIMIZED_FUNCTION) { |
- collector->MarkInlinedFunctionsCode(jsfunction->code()); |
- } |
- } |
- |
- VisitJSFunctionFields(map, |
- reinterpret_cast<JSFunction*>(object), |
- flush_code_candidate); |
- } |
- |
- |
- static void VisitJSFunction(Map* map, HeapObject* object) { |
- VisitJSFunctionFields(map, |
- reinterpret_cast<JSFunction*>(object), |
- false); |
- } |
- |
- |
- static inline void VisitJSFunctionFields(Map* map, |
- JSFunction* object, |
- bool flush_code_candidate) { |
- Heap* heap = map->GetHeap(); |
- |
- Object** start_slot = |
- HeapObject::RawField(object, JSFunction::kPropertiesOffset); |
- Object** end_slot = |
- HeapObject::RawField(object, JSFunction::kCodeEntryOffset); |
- VisitPointers(heap, start_slot, start_slot, end_slot); |
- |
- if (!flush_code_candidate) { |
- VisitCodeEntry(heap, object->address() + JSFunction::kCodeEntryOffset); |
- } else { |
- // Don't visit code object. |
- |
- // Visit shared function info to avoid double checking of its |
- // flushability. |
- SharedFunctionInfo* shared_info = object->unchecked_shared(); |
- MarkBit shared_info_mark = Marking::MarkBitFrom(shared_info); |
- if (!shared_info_mark.Get()) { |
- Map* shared_info_map = shared_info->map(); |
- MarkBit shared_info_map_mark = |
- Marking::MarkBitFrom(shared_info_map); |
- heap->mark_compact_collector()->SetMark(shared_info, shared_info_mark); |
- heap->mark_compact_collector()->MarkObject(shared_info_map, |
- shared_info_map_mark); |
- VisitSharedFunctionInfoAndFlushCodeGeneric(shared_info_map, |
- shared_info, |
- true); |
- } |
- } |
- |
- start_slot = |
- HeapObject::RawField(object, |
- JSFunction::kCodeEntryOffset + kPointerSize); |
- end_slot = |
- HeapObject::RawField(object, JSFunction::kNonWeakFieldsEndOffset); |
- VisitPointers(heap, start_slot, start_slot, end_slot); |
- } |
- |
- |
- static void VisitSharedFunctionInfoFields(Heap* heap, |
- HeapObject* object, |
- bool flush_code_candidate) { |
- VisitPointer(heap, |
- HeapObject::RawField(object, SharedFunctionInfo::kNameOffset)); |
- |
- if (!flush_code_candidate) { |
- VisitPointer(heap, |
- HeapObject::RawField(object, |
- SharedFunctionInfo::kCodeOffset)); |
- } |
- |
- Object** start_slot = |
- HeapObject::RawField(object, |
- SharedFunctionInfo::kOptimizedCodeMapOffset); |
- Object** end_slot = |
- HeapObject::RawField(object, SharedFunctionInfo::kSize); |
- |
- VisitPointers(heap, start_slot, start_slot, end_slot); |
- } |
- |
static VisitorDispatchTable<Callback> non_count_table_; |
}; |
@@ -1690,12 +1379,6 @@ class MarkCompactMarkingVisitor::ObjectStatsTracker< |
void MarkCompactMarkingVisitor::Initialize() { |
StaticMarkingVisitor<MarkCompactMarkingVisitor>::Initialize(); |
- table_.Register(kVisitSharedFunctionInfo, |
- &VisitSharedFunctionInfoAndFlushCode); |
- |
- table_.Register(kVisitJSFunction, |
- &VisitJSFunctionAndFlushCode); |
- |
table_.Register(kVisitJSRegExp, |
&VisitRegExpAndFlushCode); |
@@ -1774,26 +1457,6 @@ class SharedFunctionInfoMarkingVisitor : public ObjectVisitor { |
}; |
-void MarkCompactCollector::MarkInlinedFunctionsCode(Code* code) { |
- // For optimized functions we should retain both non-optimized version |
- // of its code and non-optimized version of all inlined functions. |
- // This is required to support bailing out from inlined code. |
- DeoptimizationInputData* data = |
- DeoptimizationInputData::cast(code->deoptimization_data()); |
- |
- FixedArray* literals = data->LiteralArray(); |
- |
- for (int i = 0, count = data->InlinedFunctionCount()->value(); |
- i < count; |
- i++) { |
- JSFunction* inlined = JSFunction::cast(literals->get(i)); |
- Code* inlined_code = inlined->shared()->code(); |
- MarkBit inlined_code_mark = Marking::MarkBitFrom(inlined_code); |
- MarkObject(inlined_code, inlined_code_mark); |
- } |
-} |
- |
- |
void MarkCompactCollector::PrepareThreadForCodeFlushing(Isolate* isolate, |
ThreadLocalTop* top) { |
for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) { |
@@ -1806,7 +1469,8 @@ void MarkCompactCollector::PrepareThreadForCodeFlushing(Isolate* isolate, |
MarkBit code_mark = Marking::MarkBitFrom(code); |
MarkObject(code, code_mark); |
if (frame->is_optimized()) { |
- MarkInlinedFunctionsCode(frame->LookupCode()); |
+ MarkCompactMarkingVisitor::MarkInlinedFunctionsCode(heap(), |
+ frame->LookupCode()); |
} |
} |
} |