Index: src/mark-compact.cc |
=================================================================== |
--- src/mark-compact.cc (revision 8501) |
+++ src/mark-compact.cc (working copy) |
@@ -424,6 +424,9 @@ |
table_.Register(kVisitJSFunction, |
&VisitJSFunctionAndFlushCode); |
+ table_.Register(kVisitJSRegExp, |
+ &VisitRegExpAndFlushCode); |
+ |
table_.Register(kVisitPropertyCell, |
&FixedBodyVisitor<StaticMarkingVisitor, |
JSGlobalPropertyCell::BodyDescriptor, |
@@ -564,6 +567,8 @@ |
// flushed. |
static const int kCodeAgeThreshold = 5; |
+ static const int kRegExpCodeThreshold = 5; |
+ |
inline static bool HasSourceCode(Heap* heap, SharedFunctionInfo* info) { |
Object* undefined = heap->raw_unchecked_undefined_value(); |
return (info->script() != undefined) && |
@@ -700,6 +705,68 @@ |
} |
+ static void UpdateRegExpCodeAgeAndFlush(Heap* heap, |
+ JSRegExp* re, |
+ bool is_ascii) { |
+ // Make sure that the fixed array is in fact initialized on the RegExp. |
+ // We could potentially trigger a GC when initializing the RegExp. |
+ if (SafeMap(re->data())->instance_type() != FIXED_ARRAY_TYPE) return; |
+ |
+ // Make sure this is a RegExp that actually contains code. |
+ if (re->TypeTagUnchecked() != JSRegExp::IRREGEXP) return; |
+ |
+ Object* code = re->DataAtUnchecked(JSRegExp::code_index(is_ascii)); |
+ if (!code->IsSmi() && SafeMap(code)->instance_type() == CODE_TYPE) { |
+ // Save a copy that can be reinstated if we need the code again. |
+ re->SetDataAtUnchecked(JSRegExp::saved_code_index(is_ascii), |
+ code, |
+ heap); |
+ // Set a number in the 0-255 range to guarantee no smi overflow. |
+ re->SetDataAtUnchecked(JSRegExp::code_index(is_ascii), |
+ Smi::FromInt(heap->sweep_generation() & 0xff), |
+ heap); |
+ } else if (code->IsSmi()) { |
+ int value = Smi::cast(code)->value(); |
+ // The regexp has not been compiled yet or there was a compilation error. |
+ if (value == JSRegExp::kUninitializedValue || |
+ value == JSRegExp::kCompilationErrorValue) { |
+ return; |
+ } |
+ |
+ // Check if we should flush now. |
+ if (value == ((heap->sweep_generation() - kRegExpCodeThreshold) & 0xff)) { |
+ re->SetDataAtUnchecked(JSRegExp::code_index(is_ascii), |
+ Smi::FromInt(JSRegExp::kUninitializedValue), |
+ heap); |
+ re->SetDataAtUnchecked(JSRegExp::saved_code_index(is_ascii), |
+ Smi::FromInt(JSRegExp::kUninitializedValue), |
+ heap); |
+ } |
+ } |
+ } |
+ |
+ |
+ // Works by setting the current sweep_generation (as a smi) in the |
+ // code object place in the data array of the RegExp and keeps a copy |
+ // around that can be reinstated if we reuse the RegExp before flushing. |
+ // If we did not use the code for kRegExpCodeThreshold mark sweep GCs |
+ // we flush the code. |
+ static void VisitRegExpAndFlushCode(Map* map, HeapObject* object) { |
+ Heap* heap = map->heap(); |
+ MarkCompactCollector* collector = heap->mark_compact_collector(); |
+ if (!collector->is_code_flushing_enabled()) { |
+ VisitJSRegExpFields(map, object); |
+ return; |
+ } |
+ JSRegExp* re = reinterpret_cast<JSRegExp*>(object); |
+ // Flush code or set age on both ascii and two byte code. |
+ UpdateRegExpCodeAgeAndFlush(heap, re, true); |
+ UpdateRegExpCodeAgeAndFlush(heap, re, false); |
+ // Visit the fields of the RegExp, including the updated FixedArray. |
+ VisitJSRegExpFields(map, object); |
+ } |
+ |
+ |
static void VisitSharedFunctionInfoAndFlushCode(Map* map, |
HeapObject* object) { |
MarkCompactCollector* collector = map->heap()->mark_compact_collector(); |
@@ -830,7 +897,16 @@ |
// Don't visit the next function list field as it is a weak reference. |
} |
+ static inline void VisitJSRegExpFields(Map* map, |
+ HeapObject* object) { |
+ int last_property_offset = |
+ JSRegExp::kSize + kPointerSize * map->inobject_properties(); |
+ VisitPointers(map->heap(), |
+ SLOT_ADDR(object, JSRegExp::kPropertiesOffset), |
+ SLOT_ADDR(object, last_property_offset)); |
+ } |
+ |
static void VisitSharedFunctionInfoFields(Heap* heap, |
HeapObject* object, |
bool flush_code_candidate) { |