summaryrefslogtreecommitdiff
path: root/src/3rdparty/webkit/JavaScriptCore/runtime/UStringImpl.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/webkit/JavaScriptCore/runtime/UStringImpl.h')
-rw-r--r--src/3rdparty/webkit/JavaScriptCore/runtime/UStringImpl.h344
1 files changed, 344 insertions, 0 deletions
diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/UStringImpl.h b/src/3rdparty/webkit/JavaScriptCore/runtime/UStringImpl.h
new file mode 100644
index 0000000000..4dccb25267
--- /dev/null
+++ b/src/3rdparty/webkit/JavaScriptCore/runtime/UStringImpl.h
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UStringImpl_h
+#define UStringImpl_h
+
+#include <limits>
+#include <wtf/CrossThreadRefCounted.h>
+#include <wtf/OwnFastMallocPtr.h>
+#include <wtf/PossiblyNull.h>
+#include <wtf/StringHashFunctions.h>
+#include <wtf/Vector.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace JSC {
+
+class IdentifierTable;
+
+typedef OwnFastMallocPtr<const UChar> SharableUChar;
+typedef CrossThreadRefCounted<SharableUChar> SharedUChar;
+
+class UStringOrRopeImpl : public Noncopyable {
+public:
+ bool isRope() { return (m_refCountAndFlags & s_refCountIsRope) == s_refCountIsRope; }
+ unsigned length() const { return m_length; }
+
+ void ref() { m_refCountAndFlags += s_refCountIncrement; }
+ inline void deref();
+
+protected:
+ enum BufferOwnership {
+ BufferInternal,
+ BufferOwned,
+ BufferSubstring,
+ BufferShared,
+ };
+
+ using Noncopyable::operator new;
+ void* operator new(size_t, void* inPlace) { return inPlace; }
+
+ // For SmallStringStorage, which allocates an array and uses an in-place new.
+ UStringOrRopeImpl() { }
+
+ UStringOrRopeImpl(unsigned length, BufferOwnership ownership)
+ : m_refCountAndFlags(s_refCountIncrement | s_refCountFlagShouldReportedCost | ownership)
+ , m_length(length)
+ {
+ ASSERT(!isRope());
+ }
+
+ enum StaticStringConstructType { ConstructStaticString };
+ UStringOrRopeImpl(unsigned length, StaticStringConstructType)
+ : m_refCountAndFlags(s_refCountFlagStatic | s_refCountFlagIsIdentifier | BufferOwned)
+ , m_length(length)
+ {
+ ASSERT(!isRope());
+ }
+
+ enum RopeConstructType { ConstructRope };
+ UStringOrRopeImpl(RopeConstructType)
+ : m_refCountAndFlags(s_refCountIncrement | s_refCountIsRope)
+ , m_length(0)
+ {
+ ASSERT(isRope());
+ }
+
+ // The bottom 5 bits hold flags, the top 27 bits hold the ref count.
+ // When dereferencing UStringImpls we check for the ref count AND the
+ // static bit both being zero - static strings are never deleted.
+ static const unsigned s_refCountMask = 0xFFFFFFE0;
+ static const unsigned s_refCountIncrement = 0x20;
+ static const unsigned s_refCountFlagStatic = 0x10;
+ static const unsigned s_refCountFlagShouldReportedCost = 0x8;
+ static const unsigned s_refCountFlagIsIdentifier = 0x4;
+ static const unsigned s_refCountMaskBufferOwnership = 0x3;
+ // Use an otherwise invalid permutation of flags (static & shouldReportedCost -
+ // static strings do not set shouldReportedCost in the constructor, and this bit
+ // is only ever cleared, not set) to identify objects that are ropes.
+ static const unsigned s_refCountIsRope = s_refCountFlagStatic | s_refCountFlagShouldReportedCost;
+
+ unsigned m_refCountAndFlags;
+ unsigned m_length;
+};
+
+class UStringImpl : public UStringOrRopeImpl {
+ friend class CStringTranslator;
+ friend class UCharBufferTranslator;
+ friend class JIT;
+ friend class SmallStringsStorage;
+ friend class UStringOrRopeImpl;
+ friend void initializeUString();
+private:
+ // For SmallStringStorage, which allocates an array and uses an in-place new.
+ UStringImpl() { }
+
+ // Used to construct static strings, which have an special refCount that can never hit zero.
+ // This means that the static string will never be destroyed, which is important because
+ // static strings will be shared across threads & ref-counted in a non-threadsafe manner.
+ UStringImpl(const UChar* characters, unsigned length, StaticStringConstructType)
+ : UStringOrRopeImpl(length, ConstructStaticString)
+ , m_data(characters)
+ , m_buffer(0)
+ , m_hash(0)
+ {
+ hash();
+ }
+
+ // Create a normal string with internal storage (BufferInternal)
+ UStringImpl(unsigned length)
+ : UStringOrRopeImpl(length, BufferInternal)
+ , m_data(reinterpret_cast<UChar*>(this + 1))
+ , m_buffer(0)
+ , m_hash(0)
+ {
+ ASSERT(m_data);
+ ASSERT(m_length);
+ }
+
+ // Create a UStringImpl adopting ownership of the provided buffer (BufferOwned)
+ UStringImpl(const UChar* characters, unsigned length)
+ : UStringOrRopeImpl(length, BufferOwned)
+ , m_data(characters)
+ , m_buffer(0)
+ , m_hash(0)
+ {
+ ASSERT(m_data);
+ ASSERT(m_length);
+ }
+
+ // Used to create new strings that are a substring of an existing UStringImpl (BufferSubstring)
+ UStringImpl(const UChar* characters, unsigned length, PassRefPtr<UStringImpl> base)
+ : UStringOrRopeImpl(length, BufferSubstring)
+ , m_data(characters)
+ , m_substringBuffer(base.releaseRef())
+ , m_hash(0)
+ {
+ ASSERT(m_data);
+ ASSERT(m_length);
+ ASSERT(m_substringBuffer->bufferOwnership() != BufferSubstring);
+ }
+
+ // Used to construct new strings sharing an existing SharedUChar (BufferShared)
+ UStringImpl(const UChar* characters, unsigned length, PassRefPtr<SharedUChar> sharedBuffer)
+ : UStringOrRopeImpl(length, BufferShared)
+ , m_data(characters)
+ , m_sharedBuffer(sharedBuffer.releaseRef())
+ , m_hash(0)
+ {
+ ASSERT(m_data);
+ ASSERT(m_length);
+ }
+
+ // For use only by Identifier's XXXTranslator helpers.
+ void setHash(unsigned hash)
+ {
+ ASSERT(!isStatic());
+ ASSERT(!m_hash);
+ ASSERT(hash == computeHash(m_data, m_length));
+ m_hash = hash;
+ }
+
+public:
+ ~UStringImpl();
+
+ static PassRefPtr<UStringImpl> create(const UChar*, unsigned length);
+ static PassRefPtr<UStringImpl> create(const char*, unsigned length);
+ static PassRefPtr<UStringImpl> create(const char*);
+ static PassRefPtr<UStringImpl> create(PassRefPtr<SharedUChar>, const UChar*, unsigned length);
+ static PassRefPtr<UStringImpl> create(PassRefPtr<UStringImpl> rep, unsigned offset, unsigned length)
+ {
+ ASSERT(rep);
+ ASSERT(length <= rep->length());
+
+ if (!length)
+ return empty();
+
+ UStringImpl* ownerRep = (rep->bufferOwnership() == BufferSubstring) ? rep->m_substringBuffer : rep.get();
+ return adoptRef(new UStringImpl(rep->m_data + offset, length, ownerRep));
+ }
+
+ static PassRefPtr<UStringImpl> createUninitialized(unsigned length, UChar*& output);
+ static PassRefPtr<UStringImpl> tryCreateUninitialized(unsigned length, UChar*& output)
+ {
+ if (!length) {
+ output = 0;
+ return empty();
+ }
+
+ if (length > ((std::numeric_limits<size_t>::max() - sizeof(UStringImpl)) / sizeof(UChar)))
+ return 0;
+ UStringImpl* resultImpl;
+ if (!tryFastMalloc(sizeof(UChar) * length + sizeof(UStringImpl)).getValue(resultImpl))
+ return 0;
+ output = reinterpret_cast<UChar*>(resultImpl + 1);
+ return adoptRef(new(resultImpl) UStringImpl(length));
+ }
+
+ template<size_t inlineCapacity>
+ static PassRefPtr<UStringImpl> adopt(Vector<UChar, inlineCapacity>& vector)
+ {
+ if (size_t size = vector.size()) {
+ ASSERT(vector.data());
+ return adoptRef(new UStringImpl(vector.releaseBuffer(), size));
+ }
+ return empty();
+ }
+
+ SharedUChar* sharedBuffer();
+ const UChar* characters() const { return m_data; }
+
+ size_t cost()
+ {
+ // For substrings, return the cost of the base string.
+ if (bufferOwnership() == BufferSubstring)
+ return m_substringBuffer->cost();
+
+ if (m_refCountAndFlags & s_refCountFlagShouldReportedCost) {
+ m_refCountAndFlags &= ~s_refCountFlagShouldReportedCost;
+ return m_length;
+ }
+ return 0;
+ }
+
+ bool isIdentifier() const { return m_refCountAndFlags & s_refCountFlagIsIdentifier; }
+ void setIsIdentifier(bool isIdentifier)
+ {
+ ASSERT(!isStatic());
+ if (isIdentifier)
+ m_refCountAndFlags |= s_refCountFlagIsIdentifier;
+ else
+ m_refCountAndFlags &= ~s_refCountFlagIsIdentifier;
+ }
+
+ unsigned hash() const { if (!m_hash) m_hash = computeHash(m_data, m_length); return m_hash; }
+ unsigned existingHash() const { ASSERT(m_hash); return m_hash; }
+ static unsigned computeHash(const UChar* data, unsigned length) { return WTF::stringHash(data, length); }
+ static unsigned computeHash(const char* data, unsigned length) { return WTF::stringHash(data, length); }
+ static unsigned computeHash(const char* data) { return WTF::stringHash(data); }
+
+ ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & (s_refCountMask | s_refCountFlagStatic))) delete this; }
+
+ static UStringImpl* empty();
+
+ static void copyChars(UChar* destination, const UChar* source, unsigned numCharacters)
+ {
+ if (numCharacters <= s_copyCharsInlineCutOff) {
+ for (unsigned i = 0; i < numCharacters; ++i)
+ destination[i] = source[i];
+ } else
+ memcpy(destination, source, numCharacters * sizeof(UChar));
+ }
+
+private:
+ // This number must be at least 2 to avoid sharing empty, null as well as 1 character strings from SmallStrings.
+ static const unsigned s_copyCharsInlineCutOff = 20;
+
+ BufferOwnership bufferOwnership() const { return static_cast<BufferOwnership>(m_refCountAndFlags & s_refCountMaskBufferOwnership); }
+ bool isStatic() const { return m_refCountAndFlags & s_refCountFlagStatic; }
+
+ const UChar* m_data;
+ union {
+ void* m_buffer;
+ UStringImpl* m_substringBuffer;
+ SharedUChar* m_sharedBuffer;
+ };
+ mutable unsigned m_hash;
+};
+
+class URopeImpl : public UStringOrRopeImpl {
+ friend class UStringOrRopeImpl;
+public:
+ // A URopeImpl is composed from a set of smaller strings called Fibers.
+ // Each Fiber in a rope is either UStringImpl or another URopeImpl.
+ typedef UStringOrRopeImpl* Fiber;
+
+ // Creates a URopeImpl comprising of 'fiberCount' Fibers.
+ // The URopeImpl is constructed in an uninitialized state - initialize must be called for each Fiber in the URopeImpl.
+ static PassRefPtr<URopeImpl> tryCreateUninitialized(unsigned fiberCount)
+ {
+ void* allocation;
+ if (tryFastMalloc(sizeof(URopeImpl) + (fiberCount - 1) * sizeof(Fiber)).getValue(allocation))
+ return adoptRef(new (allocation) URopeImpl(fiberCount));
+ return 0;
+ }
+
+ void initializeFiber(unsigned &index, Fiber fiber)
+ {
+ m_fibers[index++] = fiber;
+ fiber->ref();
+ m_length += fiber->length();
+ }
+
+ unsigned fiberCount() { return m_fiberCount; }
+ Fiber& fibers(unsigned index) { return m_fibers[index]; }
+
+ ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & s_refCountMask)) destructNonRecursive(); }
+
+private:
+ URopeImpl(unsigned fiberCount) : UStringOrRopeImpl(ConstructRope), m_fiberCount(fiberCount) {}
+
+ void destructNonRecursive();
+ void derefFibersNonRecursive(Vector<URopeImpl*, 32>& workQueue);
+
+ bool hasOneRef() { return (m_refCountAndFlags & s_refCountMask) == s_refCountIncrement; }
+
+ unsigned m_fiberCount;
+ Fiber m_fibers[1];
+};
+
+inline void UStringOrRopeImpl::deref()
+{
+ if (isRope())
+ static_cast<URopeImpl*>(this)->deref();
+ else
+ static_cast<UStringImpl*>(this)->deref();
+}
+
+bool equal(const UStringImpl*, const UStringImpl*);
+
+}
+
+#endif