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