X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/9dae56ea45a0f5f8136a5c93d6f3a7f99399ca73..14957cd040308e3eeec43d26bae5d76da13fcd85:/runtime/SmallStrings.cpp?ds=inline diff --git a/runtime/SmallStrings.cpp b/runtime/SmallStrings.cpp index 6c73df2..8741e9b 100644 --- a/runtime/SmallStrings.cpp +++ b/runtime/SmallStrings.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2010 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,76 +28,86 @@ #include "JSGlobalObject.h" #include "JSString.h" - #include +#include namespace JSC { -static const unsigned numCharactersToStore = 0x100; -class SmallStringsStorage : Noncopyable { +static inline bool isMarked(JSCell* string) +{ + return string && Heap::isMarked(string); +} + +class SmallStringsStorage { + WTF_MAKE_NONCOPYABLE(SmallStringsStorage); WTF_MAKE_FAST_ALLOCATED; public: SmallStringsStorage(); - UString::Rep* rep(unsigned char character) { return &m_reps[character]; } + StringImpl* rep(unsigned char character) + { + return m_reps[character].get(); + } private: - UChar m_characters[numCharactersToStore]; - UString::BaseString m_base; - UString::Rep m_reps[numCharactersToStore]; + static const unsigned singleCharacterStringCount = maxSingleCharacterString + 1; + + RefPtr m_reps[singleCharacterStringCount]; }; SmallStringsStorage::SmallStringsStorage() { - for (unsigned i = 0; i < numCharactersToStore; ++i) - m_characters[i] = i; - - m_base.rc = numCharactersToStore + 1; - m_base.buf = m_characters; - m_base.len = numCharactersToStore; - m_base.offset = 0; - m_base._hash = 0; - m_base.m_baseString = 0; - m_base.preCapacity = 0; - m_base.usedPreCapacity = 0; - m_base.reportedCost = 0; - - // make sure UString doesn't try to reuse the buffer by pretending we have one more character in it - m_base.usedCapacity = numCharactersToStore + 1; - m_base.capacity = numCharactersToStore + 1; - m_base.checkConsistency(); - - memset(&m_reps, 0, sizeof(m_reps)); - for (unsigned i = 0; i < numCharactersToStore; ++i) { - m_reps[i].offset = i; - m_reps[i].len = 1; - m_reps[i].rc = 1; - m_reps[i].setBaseString(&m_base); - m_reps[i].checkConsistency(); + UChar* characterBuffer = 0; + RefPtr baseString = StringImpl::createUninitialized(singleCharacterStringCount, characterBuffer); + for (unsigned i = 0; i < singleCharacterStringCount; ++i) { + characterBuffer[i] = i; + m_reps[i] = StringImpl::create(baseString, i, 1); } } SmallStrings::SmallStrings() - : m_emptyString(0) - , m_storage(0) { - COMPILE_ASSERT(numCharactersToStore == sizeof(m_singleCharacterStrings) / sizeof(m_singleCharacterStrings[0]), IsNumCharactersConstInSyncWithClassUsage); - - for (unsigned i = 0; i < numCharactersToStore; ++i) - m_singleCharacterStrings[i] = 0; + COMPILE_ASSERT(singleCharacterStringCount == sizeof(m_singleCharacterStrings) / sizeof(m_singleCharacterStrings[0]), IsNumCharactersConstInSyncWithClassUsage); + clear(); } SmallStrings::~SmallStrings() { } -void SmallStrings::mark() +void SmallStrings::visitChildren(HeapRootVisitor& heapRootMarker) { - if (m_emptyString && !m_emptyString->marked()) - m_emptyString->mark(); - for (unsigned i = 0; i < numCharactersToStore; ++i) { - if (m_singleCharacterStrings[i] && !m_singleCharacterStrings[i]->marked()) - m_singleCharacterStrings[i]->mark(); + /* + Our hypothesis is that small strings are very common. So, we cache them + to avoid GC churn. However, in cases where this hypothesis turns out to + be false -- including the degenerate case where all JavaScript execution + has terminated -- we don't want to waste memory. + + To test our hypothesis, we check if any small string has been marked. If + so, it's probably reasonable to mark the rest. If not, we clear the cache. + */ + + bool isAnyStringMarked = isMarked(m_emptyString); + for (unsigned i = 0; i < singleCharacterStringCount && !isAnyStringMarked; ++i) + isAnyStringMarked = isMarked(m_singleCharacterStrings[i]); + + if (!isAnyStringMarked) { + clear(); + return; } + + if (m_emptyString) + heapRootMarker.mark(&m_emptyString); + for (unsigned i = 0; i < singleCharacterStringCount; ++i) { + if (m_singleCharacterStrings[i]) + heapRootMarker.mark(&m_singleCharacterStrings[i]); + } +} + +void SmallStrings::clear() +{ + m_emptyString = 0; + for (unsigned i = 0; i < singleCharacterStringCount; ++i) + m_singleCharacterStrings[i] = 0; } unsigned SmallStrings::count() const @@ -105,7 +115,7 @@ unsigned SmallStrings::count() const unsigned count = 0; if (m_emptyString) ++count; - for (unsigned i = 0; i < numCharactersToStore; ++i) { + for (unsigned i = 0; i < singleCharacterStringCount; ++i) { if (m_singleCharacterStrings[i]) ++count; } @@ -121,15 +131,15 @@ void SmallStrings::createEmptyString(JSGlobalData* globalData) void SmallStrings::createSingleCharacterString(JSGlobalData* globalData, unsigned char character) { if (!m_storage) - m_storage.set(new SmallStringsStorage); + m_storage = adoptPtr(new SmallStringsStorage); ASSERT(!m_singleCharacterStrings[character]); - m_singleCharacterStrings[character] = new (globalData) JSString(globalData, m_storage->rep(character), JSString::HasOtherOwner); + m_singleCharacterStrings[character] = new (globalData) JSString(globalData, PassRefPtr(m_storage->rep(character)), JSString::HasOtherOwner); } -UString::Rep* SmallStrings::singleCharacterStringRep(unsigned char character) +StringImpl* SmallStrings::singleCharacterStringRep(unsigned char character) { if (!m_storage) - m_storage.set(new SmallStringsStorage); + m_storage = adoptPtr(new SmallStringsStorage); return m_storage->rep(character); }