ENTER_V8(isolate);
DCHECK(start >= 0 && length >= -1);
i::Handle<i::String> str = Utils::OpenHandle(string);
- isolate->string_tracker()->RecordWrite(str);
if (options & String::HINT_MANY_WRITES_EXPECTED) {
// Flatten the string for efficiency. This applies whether we are
// using StringCharacterStream or Get(i) to access the characters.
return false; // Already an external string.
}
ENTER_V8(isolate);
- if (isolate->string_tracker()->IsFreshUnusedString(obj)) {
- return false;
- }
if (isolate->heap()->IsInGCPostProcessing()) {
return false;
}
return false; // Already an external string.
}
ENTER_V8(isolate);
- if (isolate->string_tracker()->IsFreshUnusedString(obj)) {
- return false;
- }
if (isolate->heap()->IsInGCPostProcessing()) {
return false;
}
i::Handle<i::String> obj = Utils::OpenHandle(this);
i::Isolate* isolate = obj->GetIsolate();
- if (isolate->string_tracker()->IsFreshUnusedString(obj)) return false;
+ // Old space strings should be externalized.
+ if (!isolate->heap()->new_space()->Contains(*obj)) return true;
int size = obj->Size(); // Byte size of the original string.
- if (size < i::ExternalString::kShortSize) return false;
+ if (size <= i::ExternalString::kShortSize) return false;
i::StringShape shape(*obj);
return !shape.IsExternal();
}
namespace internal {
-// Tracks string usage to help make better decisions when
-// externalizing strings.
-//
-// Implementation note: internally this class only tracks fresh
-// strings and keeps a single use counter for them.
-class StringTracker {
- public:
- // Records that the given string's characters were copied to some
- // external buffer. If this happens often we should honor
- // externalization requests for the string.
- void RecordWrite(Handle<String> string) {
- Address address = reinterpret_cast<Address>(*string);
- Address top = isolate_->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 the recorded usage
- // history.
- inline bool IsFreshUnusedString(Handle<String> string) {
- Address address = reinterpret_cast<Address>(*string);
- Address top = isolate_->heap()->NewSpaceTop();
- return IsFreshString(address, top) && IsUseCountLow(top);
- }
-
- private:
- StringTracker() : use_count_(0), last_top_(NULL), isolate_(NULL) { }
-
- static inline bool IsFreshString(Address string, Address top) {
- return top - kFreshnessLimit <= string && string <= top;
- }
-
- inline bool IsUseCountLow(Address top) {
- if (last_top_ != top) return true;
- return use_count_ < kUseLimit;
- }
-
- inline void IncrementUseCount(Address top) {
- if (last_top_ != top) {
- use_count_ = 0;
- last_top_ = top;
- }
- ++use_count_;
- }
-
- // Single use counter shared by all fresh strings.
- int use_count_;
-
- // Last new space top when the use count above was valid.
- Address last_top_;
-
- Isolate* isolate_;
-
- // 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;
-
- friend class Isolate;
-
- DISALLOW_COPY_AND_ASSIGN(StringTracker);
-};
-
class DeferredHandles {
public:
eternal_handles_(NULL),
thread_manager_(NULL),
has_installed_extensions_(false),
- string_tracker_(NULL),
regexp_stack_(NULL),
date_cache_(NULL),
call_descriptor_data_(NULL),
delete thread_manager_;
thread_manager_ = NULL;
- delete string_tracker_;
- string_tracker_ = NULL;
-
delete memory_allocator_;
memory_allocator_ = NULL;
delete code_range_;
FOR_EACH_ISOLATE_ADDRESS_NAME(ASSIGN_ELEMENT)
#undef ASSIGN_ELEMENT
- string_tracker_ = new StringTracker();
- string_tracker_->isolate_ = this;
compilation_cache_ = new CompilationCache(this);
keyed_lookup_cache_ = new KeyedLookupCache();
context_slot_cache_ = new ContextSlotCache();
ThreadManager* thread_manager() { return thread_manager_; }
- StringTracker* string_tracker() { return string_tracker_; }
-
unibrow::Mapping<unibrow::Ecma262UnCanonicalize>* jsregexp_uncanonicalize() {
return &jsregexp_uncanonicalize_;
}
RuntimeState runtime_state_;
Builtins builtins_;
bool has_installed_extensions_;
- StringTracker* string_tracker_;
unibrow::Mapping<unibrow::Ecma262UnCanonicalize> jsregexp_uncanonicalize_;
unibrow::Mapping<unibrow::CanonicalizationRange> jsregexp_canonrange_;
unibrow::Mapping<unibrow::Ecma262Canonicalize>
String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
i::DeleteArray(two_byte_string);
- // We should refuse to externalize newly created small string.
+ // We should refuse to externalize small strings.
CHECK(!small_string->CanMakeExternal());
// Trigger GCs so that the newly allocated string moves to old gen.
CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
i::DeleteArray(two_byte_string);
- // We should refuse externalizing newly created small string.
- CHECK(!small_string->CanMakeExternal());
- for (int i = 0; i < 100; i++) {
- String::Value value(small_string);
- }
- // Frequently used strings should be accepted.
- CHECK(small_string->CanMakeExternal());
-
const int buf_size = 10 * 1024;
char* buf = i::NewArray<char>(buf_size);
memset(buf, 'a', buf_size);
CcTest::heap()->CollectGarbage(i::NEW_SPACE);
Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
- // We should refuse to externalize newly created small string.
+ // We should refuse to externalize small strings.
CHECK(!small_string->CanMakeExternal());
// Trigger GCs so that the newly allocated string moves to old gen.
CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
// Old space strings should be accepted.
CHECK(small_string->CanMakeExternal());
- small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
- // We should refuse externalizing newly created small string.
- CHECK(!small_string->CanMakeExternal());
- for (int i = 0; i < 100; i++) {
- String::Value value(small_string);
- }
- // Frequently used strings should be accepted.
- CHECK(small_string->CanMakeExternal());
-
const int buf_size = 10 * 1024;
char* buf = i::NewArray<char>(buf_size);
memset(buf, 'a', buf_size);