Index: src/api.cc |
diff --git a/src/api.cc b/src/api.cc |
index bd5fdd81dc5274c98e4ad6795957f5c06f1c1d0b..c7b645e767d0788ccc1ac3e8e2e30015a6274247 100644 |
--- a/src/api.cc |
+++ b/src/api.cc |
@@ -2458,6 +2458,69 @@ Handle<Value> Function::GetName() const { |
} |
+namespace { |
+ |
+// Tracks string usage to help make better decisions when |
+// externalizing strings. |
+class StringTracker { |
+ public: |
+ // Records that the given string's characters were copied to some |
Mads Ager (chromium)
2010/02/16 08:16:19
Could you update the comments in this class to mak
Vitaly Repeshko
2010/02/16 18:56:42
Done.
|
+ // external buffer. If this happens often we should honor |
+ // externalization requests for the string. |
+ static void RecordWrite(i::Handle<i::String> string) { |
+ i::Address address = reinterpret_cast<i::Address>(*string); |
+ i::Address top = i::Heap::NewSpaceTop(); |
+ if (IsFreshString(address, top)) { |
+ IncrementUseCount(top); |
+ } |
+ } |
+ |
+ // Estimates freshness and use frequency of the given string based |
+ // on how close it is to the new space top and its recorded usage |
+ // history. |
+ static inline bool IsFreshUnusedString(i::Handle<i::String> string) { |
+ i::Address address = reinterpret_cast<i::Address>(*string); |
+ i::Address top = i::Heap::NewSpaceTop(); |
+ return IsFreshString(address, top) && IsUseCountLow(top); |
+ } |
+ |
+ private: |
+ static inline bool IsFreshString(i::Address string, i::Address top) { |
+ return top - kFreshnessLimit <= string && string <= top; |
+ } |
+ |
+ static inline bool IsUseCountLow(i::Address top) { |
+ if (last_top_ != top) return true; |
+ return use_count_ < kUseLimit; |
+ } |
+ |
+ static inline void IncrementUseCount(i::Address top) { |
+ if (last_top_ != top) { |
+ use_count_ = 0; |
+ last_top_ = top; |
+ } |
+ ++use_count_; |
+ } |
+ |
+ // How close to the new space top a fresh string has to be. |
+ static const int kFreshnessLimit = 1024; |
+ |
+ // The number of uses required to consider a string useful. |
+ static const int kUseLimit = 32; |
+ |
+ // Single use counter shared by all fresh strings. |
+ static int use_count_; |
+ |
+ // Last new space top when the use count above was valid. |
+ static i::Address last_top_; |
+}; |
+ |
+int StringTracker::use_count_ = 0; |
+i::Address StringTracker::last_top_ = NULL; |
+ |
+} // namespace |
+ |
+ |
int String::Length() const { |
if (IsDeadCheck("v8::String::Length()")) return 0; |
return Utils::OpenHandle(this)->length(); |
@@ -2475,6 +2538,7 @@ int String::WriteUtf8(char* buffer, int capacity) const { |
LOG_API("String::WriteUtf8"); |
ENTER_V8; |
i::Handle<i::String> str = Utils::OpenHandle(this); |
+ StringTracker::RecordWrite(str); |
write_input_buffer.Reset(0, *str); |
int len = str->length(); |
// Encode the first K - 3 bytes directly into the buffer since we |
@@ -2518,6 +2582,7 @@ int String::WriteAscii(char* buffer, int start, int length) const { |
ENTER_V8; |
ASSERT(start >= 0 && length >= -1); |
i::Handle<i::String> str = Utils::OpenHandle(this); |
+ StringTracker::RecordWrite(str); |
// Flatten the string for efficiency. This applies whether we are |
// using StringInputBuffer or Get(i) to access the characters. |
str->TryFlattenIfNotFlat(); |
@@ -2544,6 +2609,7 @@ int String::Write(uint16_t* buffer, int start, int length) const { |
ENTER_V8; |
ASSERT(start >= 0 && length >= -1); |
i::Handle<i::String> str = Utils::OpenHandle(this); |
+ StringTracker::RecordWrite(str); |
int end = length; |
if ( (length == -1) || (length > str->length() - start) ) |
end = str->length() - start; |
@@ -3111,6 +3177,7 @@ bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) { |
if (this->IsExternal()) return false; // Already an external string. |
ENTER_V8; |
i::Handle<i::String> obj = Utils::OpenHandle(this); |
+ if (StringTracker::IsFreshUnusedString(obj)) return false; |
bool result = obj->MakeExternal(resource); |
if (result && !obj->IsSymbol()) { |
i::ExternalStringTable::AddString(*obj); |
@@ -3136,6 +3203,7 @@ bool v8::String::MakeExternal( |
if (this->IsExternal()) return false; // Already an external string. |
ENTER_V8; |
i::Handle<i::String> obj = Utils::OpenHandle(this); |
+ if (StringTracker::IsFreshUnusedString(obj)) return false; |
bool result = obj->MakeExternal(resource); |
if (result && !obj->IsSymbol()) { |
i::ExternalStringTable::AddString(*obj); |
@@ -3147,6 +3215,7 @@ bool v8::String::MakeExternal( |
bool v8::String::CanMakeExternal() { |
if (IsDeadCheck("v8::String::CanMakeExternal()")) return false; |
i::Handle<i::String> obj = Utils::OpenHandle(this); |
+ if (StringTracker::IsFreshUnusedString(obj)) return false; |
int size = obj->Size(); // Byte size of the original string. |
if (size < i::ExternalString::kSize) |
return false; |