18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
2e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * Copyright (C) 2008, 2010 Apple Inc. All Rights Reserved.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    documentation and/or other materials provided with the distribution.
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SmallStrings.h"
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "JSGlobalObject.h"
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "JSString.h"
31635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <wtf/Noncopyable.h>
32e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke#include <wtf/PassOwnPtr.h>
33635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace JSC {
35e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke
362fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic inline bool isMarked(JSCell* string)
378a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block{
382fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    return string && Heap::isMarked(string);
398a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block}
408a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
41ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdochclass SmallStringsStorage {
42ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    WTF_MAKE_NONCOPYABLE(SmallStringsStorage); WTF_MAKE_FAST_ALLOCATED;
438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectpublic:
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SmallStringsStorage();
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
462bde8e466a4451c7319e3a072d118917957d6554Steve Block    StringImpl* rep(unsigned char character)
472bde8e466a4451c7319e3a072d118917957d6554Steve Block    {
482bde8e466a4451c7319e3a072d118917957d6554Steve Block        return m_reps[character].get();
492bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectprivate:
522bde8e466a4451c7319e3a072d118917957d6554Steve Block    static const unsigned singleCharacterStringCount = maxSingleCharacterString + 1;
532bde8e466a4451c7319e3a072d118917957d6554Steve Block
542bde8e466a4451c7319e3a072d118917957d6554Steve Block    RefPtr<StringImpl> m_reps[singleCharacterStringCount];
558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project};
568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectSmallStringsStorage::SmallStringsStorage()
588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
59d0825bca7fe65beaee391d30da42e937db621564Steve Block    UChar* characterBuffer = 0;
602bde8e466a4451c7319e3a072d118917957d6554Steve Block    RefPtr<StringImpl> baseString = StringImpl::createUninitialized(singleCharacterStringCount, characterBuffer);
612bde8e466a4451c7319e3a072d118917957d6554Steve Block    for (unsigned i = 0; i < singleCharacterStringCount; ++i) {
62d0825bca7fe65beaee391d30da42e937db621564Steve Block        characterBuffer[i] = i;
63f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        m_reps[i] = StringImpl::create(baseString, i, 1);
64635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectSmallStrings::SmallStrings()
688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
692bde8e466a4451c7319e3a072d118917957d6554Steve Block    COMPILE_ASSERT(singleCharacterStringCount == sizeof(m_singleCharacterStrings) / sizeof(m_singleCharacterStrings[0]), IsNumCharactersConstInSyncWithClassUsage);
708a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    clear();
718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectSmallStrings::~SmallStrings()
748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
772bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid SmallStrings::markChildren(HeapRootMarker& heapRootMarker)
788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
798a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    /*
808a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block       Our hypothesis is that small strings are very common. So, we cache them
818a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block       to avoid GC churn. However, in cases where this hypothesis turns out to
828a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block       be false -- including the degenerate case where all JavaScript execution
838a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block       has terminated -- we don't want to waste memory.
848a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
858a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block       To test our hypothesis, we check if any small string has been marked. If
868a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block       so, it's probably reasonable to mark the rest. If not, we clear the cache.
878a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block     */
888a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
892bde8e466a4451c7319e3a072d118917957d6554Steve Block    bool isAnyStringMarked = isMarked(m_emptyString);
902bde8e466a4451c7319e3a072d118917957d6554Steve Block    for (unsigned i = 0; i < singleCharacterStringCount && !isAnyStringMarked; ++i)
912bde8e466a4451c7319e3a072d118917957d6554Steve Block        isAnyStringMarked = isMarked(m_singleCharacterStrings[i]);
928a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
938a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    if (!isAnyStringMarked) {
948a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        clear();
958a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        return;
968a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    }
978a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
98231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (m_emptyString)
992bde8e466a4451c7319e3a072d118917957d6554Steve Block        heapRootMarker.mark(&m_emptyString);
1002bde8e466a4451c7319e3a072d118917957d6554Steve Block    for (unsigned i = 0; i < singleCharacterStringCount; ++i) {
101231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if (m_singleCharacterStrings[i])
1022bde8e466a4451c7319e3a072d118917957d6554Steve Block            heapRootMarker.mark(&m_singleCharacterStrings[i]);
1038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
105635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
1068a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Blockvoid SmallStrings::clear()
1078a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block{
1088a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    m_emptyString = 0;
1092bde8e466a4451c7319e3a072d118917957d6554Steve Block    for (unsigned i = 0; i < singleCharacterStringCount; ++i)
1108a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block        m_singleCharacterStrings[i] = 0;
1118a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block}
1128a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block
113635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectunsigned SmallStrings::count() const
114635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
115635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    unsigned count = 0;
116635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_emptyString)
117635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        ++count;
1182bde8e466a4451c7319e3a072d118917957d6554Steve Block    for (unsigned i = 0; i < singleCharacterStringCount; ++i) {
119635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (m_singleCharacterStrings[i])
120635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            ++count;
121635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
122635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return count;
123635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
124635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid SmallStrings::createEmptyString(JSGlobalData* globalData)
1268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(!m_emptyString);
1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_emptyString = new (globalData) JSString(globalData, "", JSString::HasOtherOwner);
1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid SmallStrings::createSingleCharacterString(JSGlobalData* globalData, unsigned char character)
1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_storage)
134e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke        m_storage = adoptPtr(new SmallStringsStorage);
1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(!m_singleCharacterStrings[character]);
136f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    m_singleCharacterStrings[character] = new (globalData) JSString(globalData, PassRefPtr<StringImpl>(m_storage->rep(character)), JSString::HasOtherOwner);
1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
139f486d19d62f1bc33246748b14b14a9dfa617b57fIain MerrickStringImpl* SmallStrings::singleCharacterStringRep(unsigned char character)
1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_storage)
142e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke        m_storage = adoptPtr(new SmallStringsStorage);
1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_storage->rep(character);
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
146635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} // namespace JSC
147