Changeset 57912 in webkit for trunk/JavaScriptCore/runtime/RopeImpl.h
- Timestamp:
- Apr 20, 2010, 1:33:56 PM (15 years ago)
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/runtime/RopeImpl.h
r57903 r57912 1 1 /* 2 * Copyright (C) 2009 Apple Inc. All rights reserved.2 * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 24 24 */ 25 25 26 #ifndef UStringImpl_h27 #define UStringImpl_h26 #ifndef RopeImpl_h 27 #define RopeImpl_h 28 28 29 #include <limits> 30 #include <wtf/CrossThreadRefCounted.h> 31 #include <wtf/OwnFastMallocPtr.h> 32 #include <wtf/PossiblyNull.h> 33 #include <wtf/StringHashFunctions.h> 34 #include <wtf/Vector.h> 35 #include <wtf/unicode/Unicode.h> 29 #include "UStringImpl.h" 36 30 37 31 namespace JSC { 38 32 39 class IdentifierTable; 33 class RopeImpl : public UStringImplBase { 34 public: 35 // A RopeImpl is composed from a set of smaller strings called Fibers. 36 // Each Fiber in a rope is either UStringImpl or another RopeImpl. 37 typedef UStringImplBase* Fiber; 40 38 41 typedef OwnFastMallocPtr<const UChar> SharableUChar; 42 typedef CrossThreadRefCounted<SharableUChar> SharedUChar; 43 44 class UStringOrRopeImpl : public Noncopyable { 45 public: 46 bool isRope() { return (m_refCountAndFlags & s_refCountIsRope) == s_refCountIsRope; } 47 unsigned length() const { return m_length; } 48 49 void ref() { m_refCountAndFlags += s_refCountIncrement; } 50 inline void deref(); 51 52 protected: 53 enum BufferOwnership { 54 BufferInternal, 55 BufferOwned, 56 BufferSubstring, 57 BufferShared, 58 }; 59 60 using Noncopyable::operator new; 61 void* operator new(size_t, void* inPlace) { return inPlace; } 62 63 // For SmallStringStorage, which allocates an array and uses an in-place new. 64 UStringOrRopeImpl() { } 65 66 UStringOrRopeImpl(unsigned length, BufferOwnership ownership) 67 : m_refCountAndFlags(s_refCountIncrement | s_refCountFlagShouldReportedCost | ownership) 68 , m_length(length) 69 { 70 ASSERT(!isRope()); 71 } 72 73 enum StaticStringConstructType { ConstructStaticString }; 74 UStringOrRopeImpl(unsigned length, StaticStringConstructType) 75 : m_refCountAndFlags(s_refCountFlagStatic | s_refCountFlagIsIdentifier | BufferOwned) 76 , m_length(length) 77 { 78 ASSERT(!isRope()); 79 } 80 81 enum RopeConstructType { ConstructRope }; 82 UStringOrRopeImpl(RopeConstructType) 83 : m_refCountAndFlags(s_refCountIncrement | s_refCountIsRope) 84 , m_length(0) 85 { 86 ASSERT(isRope()); 87 } 88 89 // The bottom 5 bits hold flags, the top 27 bits hold the ref count. 90 // When dereferencing UStringImpls we check for the ref count AND the 91 // static bit both being zero - static strings are never deleted. 92 static const unsigned s_refCountMask = 0xFFFFFFE0; 93 static const unsigned s_refCountIncrement = 0x20; 94 static const unsigned s_refCountFlagStatic = 0x10; 95 static const unsigned s_refCountFlagShouldReportedCost = 0x8; 96 static const unsigned s_refCountFlagIsIdentifier = 0x4; 97 static const unsigned s_refCountMaskBufferOwnership = 0x3; 98 // Use an otherwise invalid permutation of flags (static & shouldReportedCost - 99 // static strings do not set shouldReportedCost in the constructor, and this bit 100 // is only ever cleared, not set) to identify objects that are ropes. 101 static const unsigned s_refCountIsRope = s_refCountFlagStatic | s_refCountFlagShouldReportedCost; 102 103 unsigned m_refCountAndFlags; 104 unsigned m_length; 105 }; 106 107 class UStringImpl : public UStringOrRopeImpl { 108 friend struct CStringTranslator; 109 friend struct UCharBufferTranslator; 110 friend class JIT; 111 friend class SmallStringsStorage; 112 friend class UStringOrRopeImpl; 113 friend void initializeUString(); 114 private: 115 // For SmallStringStorage, which allocates an array and uses an in-place new. 116 UStringImpl() { } 117 118 // Used to construct static strings, which have an special refCount that can never hit zero. 119 // This means that the static string will never be destroyed, which is important because 120 // static strings will be shared across threads & ref-counted in a non-threadsafe manner. 121 UStringImpl(const UChar* characters, unsigned length, StaticStringConstructType) 122 : UStringOrRopeImpl(length, ConstructStaticString) 123 , m_data(characters) 124 , m_buffer(0) 125 , m_hash(0) 126 { 127 hash(); 128 } 129 130 // Create a normal string with internal storage (BufferInternal) 131 UStringImpl(unsigned length) 132 : UStringOrRopeImpl(length, BufferInternal) 133 , m_data(reinterpret_cast<UChar*>(this + 1)) 134 , m_buffer(0) 135 , m_hash(0) 136 { 137 ASSERT(m_data); 138 ASSERT(m_length); 139 } 140 141 // Create a UStringImpl adopting ownership of the provided buffer (BufferOwned) 142 UStringImpl(const UChar* characters, unsigned length) 143 : UStringOrRopeImpl(length, BufferOwned) 144 , m_data(characters) 145 , m_buffer(0) 146 , m_hash(0) 147 { 148 ASSERT(m_data); 149 ASSERT(m_length); 150 } 151 152 // Used to create new strings that are a substring of an existing UStringImpl (BufferSubstring) 153 UStringImpl(const UChar* characters, unsigned length, PassRefPtr<UStringImpl> base) 154 : UStringOrRopeImpl(length, BufferSubstring) 155 , m_data(characters) 156 , m_substringBuffer(base.releaseRef()) 157 , m_hash(0) 158 { 159 ASSERT(m_data); 160 ASSERT(m_length); 161 ASSERT(m_substringBuffer->bufferOwnership() != BufferSubstring); 162 } 163 164 // Used to construct new strings sharing an existing SharedUChar (BufferShared) 165 UStringImpl(const UChar* characters, unsigned length, PassRefPtr<SharedUChar> sharedBuffer) 166 : UStringOrRopeImpl(length, BufferShared) 167 , m_data(characters) 168 , m_sharedBuffer(sharedBuffer.releaseRef()) 169 , m_hash(0) 170 { 171 ASSERT(m_data); 172 ASSERT(m_length); 173 } 174 175 // For use only by Identifier's XXXTranslator helpers. 176 void setHash(unsigned hash) 177 { 178 ASSERT(!isStatic()); 179 ASSERT(!m_hash); 180 ASSERT(hash == computeHash(m_data, m_length)); 181 m_hash = hash; 182 } 183 184 public: 185 ~UStringImpl(); 186 187 static PassRefPtr<UStringImpl> create(const UChar*, unsigned length); 188 static PassRefPtr<UStringImpl> create(const char*, unsigned length); 189 static PassRefPtr<UStringImpl> create(const char*); 190 static PassRefPtr<UStringImpl> create(const UChar*, unsigned length, PassRefPtr<SharedUChar>); 191 static PassRefPtr<UStringImpl> create(PassRefPtr<UStringImpl> rep, unsigned offset, unsigned length) 192 { 193 ASSERT(rep); 194 ASSERT(length <= rep->length()); 195 196 if (!length) 197 return empty(); 198 199 UStringImpl* ownerRep = (rep->bufferOwnership() == BufferSubstring) ? rep->m_substringBuffer : rep.get(); 200 return adoptRef(new UStringImpl(rep->m_data + offset, length, ownerRep)); 201 } 202 203 static PassRefPtr<UStringImpl> createUninitialized(unsigned length, UChar*& output); 204 static PassRefPtr<UStringImpl> tryCreateUninitialized(unsigned length, UChar*& output) 205 { 206 if (!length) { 207 output = 0; 208 return empty(); 209 } 210 211 if (length > ((std::numeric_limits<size_t>::max() - sizeof(UStringImpl)) / sizeof(UChar))) 212 return 0; 213 UStringImpl* resultImpl; 214 if (!tryFastMalloc(sizeof(UChar) * length + sizeof(UStringImpl)).getValue(resultImpl)) 215 return 0; 216 output = reinterpret_cast<UChar*>(resultImpl + 1); 217 return adoptRef(new(resultImpl) UStringImpl(length)); 218 } 219 220 template<size_t inlineCapacity> 221 static PassRefPtr<UStringImpl> adopt(Vector<UChar, inlineCapacity>& vector) 222 { 223 if (size_t size = vector.size()) { 224 ASSERT(vector.data()); 225 return adoptRef(new UStringImpl(vector.releaseBuffer(), size)); 226 } 227 return empty(); 228 } 229 230 SharedUChar* sharedBuffer(); 231 const UChar* characters() const { return m_data; } 232 233 size_t cost() 234 { 235 // For substrings, return the cost of the base string. 236 if (bufferOwnership() == BufferSubstring) 237 return m_substringBuffer->cost(); 238 239 if (m_refCountAndFlags & s_refCountFlagShouldReportedCost) { 240 m_refCountAndFlags &= ~s_refCountFlagShouldReportedCost; 241 return m_length; 242 } 243 return 0; 244 } 245 246 bool isIdentifier() const { return m_refCountAndFlags & s_refCountFlagIsIdentifier; } 247 void setIsIdentifier(bool isIdentifier) 248 { 249 ASSERT(!isStatic()); 250 if (isIdentifier) 251 m_refCountAndFlags |= s_refCountFlagIsIdentifier; 252 else 253 m_refCountAndFlags &= ~s_refCountFlagIsIdentifier; 254 } 255 256 unsigned hash() const { if (!m_hash) m_hash = computeHash(m_data, m_length); return m_hash; } 257 unsigned existingHash() const { ASSERT(m_hash); return m_hash; } 258 static unsigned computeHash(const UChar* data, unsigned length) { return WTF::stringHash(data, length); } 259 static unsigned computeHash(const char* data, unsigned length) { return WTF::stringHash(data, length); } 260 static unsigned computeHash(const char* data) { return WTF::stringHash(data); } 261 262 ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & (s_refCountMask | s_refCountFlagStatic))) delete this; } 263 264 static UStringImpl* empty(); 265 266 static void copyChars(UChar* destination, const UChar* source, unsigned numCharacters) 267 { 268 if (numCharacters <= s_copyCharsInlineCutOff) { 269 for (unsigned i = 0; i < numCharacters; ++i) 270 destination[i] = source[i]; 271 } else 272 memcpy(destination, source, numCharacters * sizeof(UChar)); 273 } 274 275 private: 276 // This number must be at least 2 to avoid sharing empty, null as well as 1 character strings from SmallStrings. 277 static const unsigned s_copyCharsInlineCutOff = 20; 278 279 BufferOwnership bufferOwnership() const { return static_cast<BufferOwnership>(m_refCountAndFlags & s_refCountMaskBufferOwnership); } 280 bool isStatic() const { return m_refCountAndFlags & s_refCountFlagStatic; } 281 282 const UChar* m_data; 283 union { 284 void* m_buffer; 285 UStringImpl* m_substringBuffer; 286 SharedUChar* m_sharedBuffer; 287 }; 288 mutable unsigned m_hash; 289 }; 290 291 class URopeImpl : public UStringOrRopeImpl { 292 friend class UStringOrRopeImpl; 293 public: 294 // A URopeImpl is composed from a set of smaller strings called Fibers. 295 // Each Fiber in a rope is either UStringImpl or another URopeImpl. 296 typedef UStringOrRopeImpl* Fiber; 297 298 // Creates a URopeImpl comprising of 'fiberCount' Fibers. 299 // The URopeImpl is constructed in an uninitialized state - initialize must be called for each Fiber in the URopeImpl. 300 static PassRefPtr<URopeImpl> tryCreateUninitialized(unsigned fiberCount) 39 // Creates a RopeImpl comprising of 'fiberCount' Fibers. 40 // The RopeImpl is constructed in an uninitialized state - initialize must be called for each Fiber in the RopeImpl. 41 static PassRefPtr<RopeImpl> tryCreateUninitialized(unsigned fiberCount) 301 42 { 302 43 void* allocation; 303 if (tryFastMalloc(sizeof( URopeImpl) + (fiberCount - 1) * sizeof(Fiber)).getValue(allocation))304 return adoptRef(new (allocation) URopeImpl(fiberCount));44 if (tryFastMalloc(sizeof(RopeImpl) + (fiberCount - 1) * sizeof(Fiber)).getValue(allocation)) 45 return adoptRef(new (allocation) RopeImpl(fiberCount)); 305 46 return 0; 306 47 } … … 318 59 ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & s_refCountMask)) destructNonRecursive(); } 319 60 61 static bool isRope(Fiber fiber) 62 { 63 return !fiber->isStringImpl(); 64 } 65 66 static void deref(Fiber fiber) 67 { 68 if (isRope(fiber)) 69 static_cast<RopeImpl*>(fiber)->deref(); 70 else 71 static_cast<UStringImpl*>(fiber)->deref(); 72 } 73 320 74 private: 321 URopeImpl(unsigned fiberCount) : UStringOrRopeImpl(ConstructRope), m_fiberCount(fiberCount) {}75 RopeImpl(unsigned fiberCount) : UStringImplBase(ConstructNonStringImpl), m_fiberCount(fiberCount) {} 322 76 323 77 void destructNonRecursive(); 324 void derefFibersNonRecursive(Vector< URopeImpl*, 32>& workQueue);78 void derefFibersNonRecursive(Vector<RopeImpl*, 32>& workQueue); 325 79 326 80 bool hasOneRef() { return (m_refCountAndFlags & s_refCountMask) == s_refCountIncrement; } … … 330 84 }; 331 85 332 inline void UStringOrRopeImpl::deref()333 {334 if (isRope())335 static_cast<URopeImpl*>(this)->deref();336 else337 static_cast<UStringImpl*>(this)->deref();338 }339 340 bool equal(const UStringImpl*, const UStringImpl*);341 342 86 } 343 87
Note:
See TracChangeset
for help on using the changeset viewer.