Changeset 55878 in webkit
- Timestamp:
- Mar 11, 2010 7:14:17 PM (14 years ago)
- Location:
- trunk
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/ChangeLog
r55871 r55878 1 2010-03-11 Gavin Barraclough <barraclough@apple.com> 2 3 Reviewed by Oliver Hunt. 4 5 https://bugs.webkit.org/show_bug.cgi?id=36041 6 Remove unnecessary differences in common code between WebCore::StringImpl & JSC::UStringImpl 7 8 Much of the code in WebCore::StringImpl and JSC::UStringImpl is now very similar, 9 but has trivial and unnecessary formatting differences, such as the exact wording 10 of comments, missing ASSERTs, functions implemented in the .h vs .cpp etc. 11 12 * runtime/Identifier.cpp: 13 (JSC::Identifier::add): UStringImpl::empty() now automatically hashes, uas per WebCore strings. 14 (JSC::Identifier::addSlowCase): UStringImpl::empty() now automatically hashes, uas per WebCore strings. 15 * runtime/UStringImpl.cpp: 16 (JSC::UStringImpl::~UStringImpl): Only call bufferOwnership() once, add missing ASSERTs. 17 (JSC::UStringImpl::createUninitialized): Move from .h, not commonly called, no need to inline. 18 (JSC::UStringImpl::create): Move from .h, not commonly called, no need to inline. 19 (JSC::UStringImpl::sharedBuffer): Rewritten to more closely match WebCore implementation, remove need for separate baseSharedBuffer() method. 20 * runtime/UStringImpl.h: 21 (JSC::UStringImpl::UStringImpl): Automatically hash static strings, ASSERT m_data & m_length are non-null/non-zero in non-static strings. 22 (JSC::UStringImpl::setHash): Add missing ASSERT. 23 (JSC::UStringImpl::create): Moved to .cpp / added missing check for empty string creation. 24 (JSC::UStringImpl::adopt): Vector.size() returns size_t, not unsigned. 25 (JSC::UStringImpl::cost): Renamed m_bufferSubstring -> m_substringBuffer 26 (JSC::UStringImpl::hash): Reordered in file. 27 (JSC::UStringImpl::existingHash): Reordered in file. 28 (JSC::UStringImpl::computeHash): Reordered in file, renamed parameter. 29 (JSC::UStringImpl::checkConsistency): rewrote ASSERT. 30 (JSC::UStringImpl::bufferOwnership): Return type should be BufferOwnership. 31 (JSC::UStringImpl::): Moved friends to head of class. 32 1 33 2010-03-11 Mark Rowe <mrowe@apple.com> 2 34 -
trunk/JavaScriptCore/JavaScriptCore.exp
r55825 r55878 108 108 __ZN3JSC11UStringImpl12sharedBufferEv 109 109 __ZN3JSC11UStringImpl5emptyEv 110 __ZN3JSC11UStringImpl6createEN3WTF10PassRefPtrINS1_21CrossThreadRefCountedINS1_16OwnFastMallocPtrIKtEEEEEEPS5_j 110 111 __ZN3JSC11UStringImplD1Ev 111 112 __ZN3JSC11checkSyntaxEPNS_9ExecStateERKNS_10SourceCodeE -
trunk/JavaScriptCore/runtime/Identifier.cpp
r55833 r55878 44 44 (*iter)->setIsIdentifier(false); 45 45 } 46 46 47 47 std::pair<HashSet<UString::Rep*>::iterator, bool> add(UString::Rep* value) 48 48 { … … 130 130 return rep; 131 131 } 132 if (!c[0]) { 133 UString::Rep::empty()->hash(); 132 if (!c[0]) 134 133 return UString::Rep::empty(); 135 }136 134 if (!c[1]) 137 135 return add(globalData, globalData->smallStrings.singleCharacterStringRep(static_cast<unsigned char>(c[0]))); … … 194 192 return add(globalData, globalData->smallStrings.singleCharacterStringRep(c)); 195 193 } 196 if (!length) { 197 UString::Rep::empty()->hash(); 194 if (!length) 198 195 return UString::Rep::empty(); 199 }200 196 UCharBuffer buf = {s, length}; 201 197 pair<HashSet<UString::Rep*>::iterator, bool> addResult = globalData->identifierTable->add<UCharBuffer, UCharBufferTranslator>(buf); … … 225 221 } 226 222 } 227 if (!r->length()) { 228 UString::Rep::empty()->hash(); 223 if (!r->length()) 229 224 return UString::Rep::empty(); 230 }231 225 return *globalData->identifierTable->add(r).first; 232 226 } -
trunk/JavaScriptCore/runtime/UStringImpl.cpp
r55825 r55878 37 37 namespace JSC { 38 38 39 static const unsigned minLengthToShare = 20; 40 41 UStringImpl::~UStringImpl() 42 { 43 ASSERT(!isStatic()); 44 checkConsistency(); 45 46 if (isIdentifier()) 47 Identifier::remove(this); 48 49 BufferOwnership ownership = bufferOwnership(); 50 if (ownership != BufferInternal) { 51 if (ownership == BufferOwned) { 52 ASSERT(!m_sharedBuffer); 53 ASSERT(m_data); 54 fastFree(const_cast<UChar*>(m_data)); 55 } else if (ownership == BufferSubstring) { 56 ASSERT(m_substringBuffer); 57 m_substringBuffer->deref(); 58 } else { 59 ASSERT(ownership == BufferShared); 60 ASSERT(m_sharedBuffer); 61 m_sharedBuffer->deref(); 62 } 63 } 64 } 65 39 66 UStringImpl* UStringImpl::empty() 40 67 { … … 44 71 DEFINE_STATIC_LOCAL(UStringImpl, emptyString, (invalidNonNullUCharPtr, 0, ConstructStaticString)); 45 72 return &emptyString; 73 } 74 75 PassRefPtr<UStringImpl> UStringImpl::createUninitialized(unsigned length, UChar*& data) 76 { 77 if (!length) { 78 data = 0; 79 return empty(); 80 } 81 82 // Allocate a single buffer large enough to contain the StringImpl 83 // struct as well as the data which it contains. This removes one 84 // heap allocation from this call. 85 if (length > ((std::numeric_limits<size_t>::max() - sizeof(UStringImpl)) / sizeof(UChar))) 86 CRASH(); 87 size_t size = sizeof(UStringImpl) + length * sizeof(UChar); 88 UStringImpl* string = static_cast<UStringImpl*>(fastMalloc(size)); 89 90 data = reinterpret_cast<UChar*>(string + 1); 91 return adoptRef(new (string) UStringImpl(length)); 46 92 } 47 93 … … 78 124 } 79 125 80 SharedUChar* UStringImpl::baseSharedBuffer()126 PassRefPtr<UStringImpl> UStringImpl::create(PassRefPtr<SharedUChar> sharedBuffer, const UChar* buffer, unsigned length) 81 127 { 82 ASSERT((bufferOwnership() == BufferShared) 83 || ((bufferOwnership() == BufferOwned) && !m_buffer)); 84 85 if (bufferOwnership() != BufferShared) { 86 m_refCountAndFlags = (m_refCountAndFlags & ~s_refCountMaskBufferOwnership) | BufferShared; 87 m_bufferShared = SharedUChar::create(new SharableUChar(m_data)).releaseRef(); 88 } 89 90 return m_bufferShared; 128 if (!length) 129 return empty(); 130 return adoptRef(new UStringImpl(buffer, length, sharedBuffer)); 91 131 } 92 132 93 133 SharedUChar* UStringImpl::sharedBuffer() 94 134 { 95 if (m_length < s_minLengthToShare)135 if (m_length < minLengthToShare) 96 136 return 0; 137 // All static strings are smaller that the minimim length to share. 97 138 ASSERT(!isStatic()); 98 139 99 UStringImpl* owner = bufferOwnerString(); 100 if (owner->bufferOwnership() == BufferInternal) 140 BufferOwnership ownership = bufferOwnership(); 141 142 if (ownership == BufferInternal) 101 143 return 0; 144 if (ownership == BufferSubstring) 145 return m_substringBuffer->sharedBuffer(); 146 if (ownership == BufferOwned) { 147 ASSERT(!m_sharedBuffer); 148 m_sharedBuffer = SharedUChar::create(new SharableUChar(m_data)).releaseRef(); 149 m_refCountAndFlags = (m_refCountAndFlags & ~s_refCountMaskBufferOwnership) | BufferShared; 150 } 102 151 103 return owner->baseSharedBuffer(); 104 } 105 106 UStringImpl::~UStringImpl() 107 { 108 ASSERT(!isStatic()); 109 checkConsistency(); 110 111 if (isIdentifier()) 112 Identifier::remove(this); 113 114 if (bufferOwnership() != BufferInternal) { 115 if (bufferOwnership() == BufferOwned) 116 fastFree(const_cast<UChar*>(m_data)); 117 else if (bufferOwnership() == BufferSubstring) 118 m_bufferSubstring->deref(); 119 else { 120 ASSERT(bufferOwnership() == BufferShared); 121 m_bufferShared->deref(); 122 } 123 } 152 ASSERT(bufferOwnership() == BufferShared); 153 ASSERT(m_sharedBuffer); 154 return m_sharedBuffer; 124 155 } 125 156 -
trunk/JavaScriptCore/runtime/UStringImpl.h
r55833 r55878 106 106 107 107 class UStringImpl : public UStringOrRopeImpl { 108 friend class CStringTranslator; 109 friend class 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 checkConsistency(); 129 } 130 131 // Create a normal string with internal storage (BufferInternal) 132 UStringImpl(unsigned length) 133 : UStringOrRopeImpl(length, BufferInternal) 134 , m_data(reinterpret_cast<UChar*>(this + 1)) 135 , m_buffer(0) 136 , m_hash(0) 137 { 138 ASSERT(m_data); 139 ASSERT(m_length); 140 checkConsistency(); 141 } 142 143 // Create a UStringImpl adopting ownership of the provided buffer (BufferOwned) 144 UStringImpl(const UChar* characters, unsigned length) 145 : UStringOrRopeImpl(length, BufferOwned) 146 , m_data(characters) 147 , m_buffer(0) 148 , m_hash(0) 149 { 150 ASSERT(m_data); 151 ASSERT(m_length); 152 checkConsistency(); 153 } 154 155 // Used to create new strings that are a substring of an existing UStringImpl (BufferSubstring) 156 UStringImpl(const UChar* characters, unsigned length, PassRefPtr<UStringImpl> base) 157 : UStringOrRopeImpl(length, BufferSubstring) 158 , m_data(characters) 159 , m_substringBuffer(base.releaseRef()) 160 , m_hash(0) 161 { 162 ASSERT(m_data); 163 ASSERT(m_length); 164 checkConsistency(); 165 } 166 167 // Used to construct new strings sharing an existing SharedUChar (BufferShared) 168 UStringImpl(const UChar* characters, unsigned length, PassRefPtr<SharedUChar> sharedBuffer) 169 : UStringOrRopeImpl(length, BufferShared) 170 , m_data(characters) 171 , m_sharedBuffer(sharedBuffer.releaseRef()) 172 , m_hash(0) 173 { 174 ASSERT(m_data); 175 ASSERT(m_length); 176 checkConsistency(); 177 } 178 179 // For use only by Identifier's XXXTranslator helpers. 180 void setHash(unsigned hash) 181 { 182 ASSERT(!m_hash); 183 ASSERT(hash == computeHash(m_data, m_length)); 184 m_hash = hash; 185 } 186 108 187 public: 109 template<size_t inlineCapacity> 110 static PassRefPtr<UStringImpl> adopt(Vector<UChar, inlineCapacity>& vector) 111 { 112 if (unsigned length = vector.size()) { 113 ASSERT(vector.data()); 114 return adoptRef(new UStringImpl(vector.releaseBuffer(), length)); 115 } 116 return empty(); 117 } 118 119 static PassRefPtr<UStringImpl> create(const UChar* buffer, unsigned length); 120 static PassRefPtr<UStringImpl> create(const char* c, unsigned length); 121 static PassRefPtr<UStringImpl> create(const char* c); 122 188 ~UStringImpl(); 189 190 static PassRefPtr<UStringImpl> create(const UChar*, unsigned length); 191 static PassRefPtr<UStringImpl> create(const char*, unsigned length); 192 static PassRefPtr<UStringImpl> create(const char*); 193 static PassRefPtr<UStringImpl> create(PassRefPtr<SharedUChar>, const UChar*, unsigned length); 123 194 static PassRefPtr<UStringImpl> create(PassRefPtr<UStringImpl> rep, unsigned offset, unsigned length) 124 195 { 196 if (!length) 197 return empty(); 125 198 ASSERT(rep); 126 199 rep->checkConsistency(); 127 return adoptRef(new UStringImpl(rep->m_data + offset, length, rep->bufferOwnerString())); 128 } 129 130 static PassRefPtr<UStringImpl> create(PassRefPtr<SharedUChar> sharedBuffer, const UChar* buffer, unsigned length) 131 { 132 return adoptRef(new UStringImpl(buffer, length, sharedBuffer)); 133 } 134 135 static PassRefPtr<UStringImpl> createUninitialized(unsigned length, UChar*& output) 136 { 137 if (!length) { 138 output = 0; 139 return empty(); 140 } 141 142 if (length > ((std::numeric_limits<size_t>::max() - sizeof(UStringImpl)) / sizeof(UChar))) 143 CRASH(); 144 UStringImpl* resultImpl = static_cast<UStringImpl*>(fastMalloc(sizeof(UChar) * length + sizeof(UStringImpl))); 145 output = reinterpret_cast<UChar*>(resultImpl + 1); 146 return adoptRef(new(resultImpl) UStringImpl(length)); 147 } 148 200 UStringImpl* ownerRep = (rep->bufferOwnership() == BufferSubstring) ? rep->m_substringBuffer : rep.get(); 201 return adoptRef(new UStringImpl(rep->m_data + offset, length, ownerRep)); 202 } 203 204 static PassRefPtr<UStringImpl> createUninitialized(unsigned length, UChar*& output); 149 205 static PassRefPtr<UStringImpl> tryCreateUninitialized(unsigned length, UChar*& output) 150 206 { … … 163 219 } 164 220 221 template<size_t inlineCapacity> 222 static PassRefPtr<UStringImpl> adopt(Vector<UChar, inlineCapacity>& vector) 223 { 224 if (size_t size = vector.size()) { 225 ASSERT(vector.data()); 226 return adoptRef(new UStringImpl(vector.releaseBuffer(), size)); 227 } 228 return empty(); 229 } 230 165 231 SharedUChar* sharedBuffer(); 166 232 const UChar* characters() const { return m_data; } 233 167 234 size_t cost() 168 235 { 169 236 // For substrings, return the cost of the base string. 170 237 if (bufferOwnership() == BufferSubstring) 171 return m_ bufferSubstring->cost();238 return m_substringBuffer->cost(); 172 239 173 240 if (m_refCountAndFlags & s_refCountFlagShouldReportedCost) { … … 177 244 return 0; 178 245 } 179 unsigned hash() const { if (!m_hash) m_hash = computeHash(m_data, m_length); return m_hash; } 180 unsigned existingHash() const { ASSERT(m_hash); return m_hash; } // fast path for Identifiers 181 void setHash(unsigned hash) { ASSERT(hash == computeHash(m_data, m_length)); m_hash = hash; } // fast path for Identifiers 246 182 247 bool isIdentifier() const { return m_refCountAndFlags & s_refCountFlagIsIdentifier; } 183 248 void setIsIdentifier(bool isIdentifier) … … 189 254 } 190 255 256 // SYNC SYNC SYNC 257 // SYNC SYNC SYNC 258 // SYNC SYNC SYNC 259 // SYNC SYNC SYNC 260 // SYNC SYNC SYNC 261 262 unsigned hash() const { if (!m_hash) m_hash = computeHash(m_data, m_length); return m_hash; } 263 unsigned existingHash() const { ASSERT(m_hash); return m_hash; } 264 static unsigned computeHash(const UChar* data, unsigned length) { return WTF::stringHash(data, length); } 265 static unsigned computeHash(const char* data, unsigned length) { return WTF::stringHash(data, length); } 266 static unsigned computeHash(const char* data) { return WTF::stringHash(data); } 267 191 268 ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & (s_refCountMask | s_refCountFlagStatic))) delete this; } 269 270 static UStringImpl* empty(); 192 271 193 272 static void copyChars(UChar* destination, const UChar* source, unsigned numCharacters) … … 200 279 } 201 280 202 static unsigned computeHash(const UChar* s, unsigned length) { return WTF::stringHash(s, length); }203 static unsigned computeHash(const char* s, unsigned length) { return WTF::stringHash(s, length); }204 static unsigned computeHash(const char* s) { return WTF::stringHash(s); }205 206 static UStringImpl* empty();207 208 281 ALWAYS_INLINE void checkConsistency() const 209 282 { 210 283 // There is no recursion of substrings. 211 ASSERT( bufferOwnerString()->bufferOwnership() != BufferSubstring);284 ASSERT((bufferOwnership() != BufferSubstring) || (m_substringBuffer->bufferOwnership() != BufferSubstring)); 212 285 // Static strings cannot be put in identifier tables, because they are globally shared. 213 286 ASSERT(!isStatic() || !isIdentifier()); … … 215 288 216 289 private: 217 // For SmallStringStorage, which allocates an array and uses an in-place new.218 UStringImpl() { }219 220 // Used to construct normal strings with an internal buffer.221 UStringImpl(unsigned length)222 : UStringOrRopeImpl(length, BufferInternal)223 , m_data(reinterpret_cast<UChar*>(this + 1))224 , m_buffer(0)225 , m_hash(0)226 {227 checkConsistency();228 }229 230 // Used to construct normal strings with an external buffer.231 UStringImpl(const UChar* data, unsigned length)232 : UStringOrRopeImpl(length, BufferOwned)233 , m_data(data)234 , m_buffer(0)235 , m_hash(0)236 {237 checkConsistency();238 }239 240 // Used to construct static strings, which have an special refCount that can never hit zero.241 // This means that the static string will never be destroyed, which is important because242 // static strings will be shared across threads & ref-counted in a non-threadsafe manner.243 UStringImpl(const UChar* data, unsigned length, StaticStringConstructType)244 : UStringOrRopeImpl(length, ConstructStaticString)245 , m_data(data)246 , m_buffer(0)247 , m_hash(0)248 {249 checkConsistency();250 }251 252 // Used to create new strings that are a substring of an existing string.253 UStringImpl(const UChar* data, unsigned length, PassRefPtr<UStringImpl> base)254 : UStringOrRopeImpl(length, BufferSubstring)255 , m_data(data)256 , m_bufferSubstring(base.releaseRef())257 , m_hash(0)258 {259 // Do use static strings as a base for substrings; UntypedPtrAndBitfield assumes260 // that all pointers will be at least 8-byte aligned, we cannot guarantee that of261 // UStringImpls that are not heap allocated.262 ASSERT(m_bufferSubstring->length());263 ASSERT(!m_bufferSubstring->isStatic());264 checkConsistency();265 }266 267 // Used to construct new strings sharing an existing shared buffer.268 UStringImpl(const UChar* data, unsigned length, PassRefPtr<SharedUChar> sharedBuffer)269 : UStringOrRopeImpl(length, BufferShared)270 , m_data(data)271 , m_bufferShared(sharedBuffer.releaseRef())272 , m_hash(0)273 {274 checkConsistency();275 }276 277 ~UStringImpl();278 279 290 // This number must be at least 2 to avoid sharing empty, null as well as 1 character strings from SmallStrings. 280 static const unsigned s_minLengthToShare = 10;281 291 static const unsigned s_copyCharsInlineCutOff = 20; 282 292 283 UStringImpl* bufferOwnerString() { return (bufferOwnership() == BufferSubstring) ? m_bufferSubstring : this; } 284 const UStringImpl* bufferOwnerString() const { return (bufferOwnership() == BufferSubstring) ? m_bufferSubstring : this; } 285 SharedUChar* baseSharedBuffer(); 286 unsigned bufferOwnership() const { return m_refCountAndFlags & s_refCountMaskBufferOwnership; } 293 BufferOwnership bufferOwnership() const { return static_cast<BufferOwnership>(m_refCountAndFlags & s_refCountMaskBufferOwnership); } 287 294 bool isStatic() const { return m_refCountAndFlags & s_refCountFlagStatic; } 288 295 … … 291 298 union { 292 299 void* m_buffer; 293 UStringImpl* m_ bufferSubstring;294 SharedUChar* m_ bufferShared;300 UStringImpl* m_substringBuffer; 301 SharedUChar* m_sharedBuffer; 295 302 }; 296 303 mutable unsigned m_hash; 297 298 friend class JIT; 299 friend class SmallStringsStorage; 304 }; 305 306 class URopeImpl : public UStringOrRopeImpl { 300 307 friend class UStringOrRopeImpl; 301 friend void initializeUString();302 };303 304 class URopeImpl : public UStringOrRopeImpl {305 308 public: 306 309 // A URopeImpl is composed from a set of smaller strings called Fibers. … … 340 343 unsigned m_fiberCount; 341 344 Fiber m_fibers[1]; 342 343 friend class UStringOrRopeImpl;344 345 }; 345 346 -
trunk/WebCore/ChangeLog
r55871 r55878 1 2010-03-11 Gavin Barraclough <barraclough@apple.com> 2 3 Reviewed by Oliver Hunt. 4 5 https://bugs.webkit.org/show_bug.cgi?id=36041 6 Remove unnecessary differences in common code between WebCore::StringImpl & JSC::UStringImpl 7 8 Much of the code in WebCore::StringImpl and JSC::UStringImpl is now very similar, 9 but has trivial and unnecessary formatting differences, such as the exact wording 10 of comments, missing ASSERTs, functions implemented in the .h vs .cpp etc. 11 12 * platform/text/StringImpl.cpp: 13 (WebCore::StringImpl::empty): Reordered in file, made empty()->characters() return a non-null value to match JSC. 14 (WebCore::StringImpl::createUninitialized): Added overflow check. 15 (WebCore::StringImpl::create): Reordered in file. 16 (WebCore::StringImpl::sharedBuffer): Reordered in file. 17 * platform/text/StringImpl.h: 18 (WebCore::StringImpl::): Remove ThreadGlobalData as friend, move SharableUChar & SharedUChar to WebCore namespace. 19 (WebCore::StringImpl::StringImpl): Made static constructor method (used to create empty string) take arguments, to match JSC & prevent accidental use. 20 (WebCore::StringImpl::setHash): Added missing ASSERT. 21 (WebCore::StringImpl::adopt): Make adpot work with Vectors with a non-zero inline capacity. 22 (WebCore::StringImpl::characters): Mark as const to match JSC. 23 (WebCore::StringImpl::hash): Use !m_hash instead of m_hash == 0. 24 (WebCore::StringImpl::computeHash): Remove redundant 'inline'. 25 1 26 2010-03-11 Mark Rowe <mrowe@apple.com> 2 27 -
trunk/WebCore/platform/text/StringImpl.cpp
r55832 r55878 34 34 #include "TextBreakIterator.h" 35 35 #include "TextEncoding.h" 36 #include "ThreadGlobalData.h"37 36 #include <runtime/UString.h> 38 37 #include <wtf/dtoa.h> … … 47 46 48 47 static const unsigned minLengthToShare = 20; 49 50 static inline UChar* newUCharVector(unsigned n)51 {52 return static_cast<UChar*>(fastMalloc(sizeof(UChar) * n));53 }54 55 // This constructor is used only to create the empty string.56 StringImpl::StringImpl()57 : m_data(0)58 , m_sharedBuffer(0)59 , m_length(0)60 , m_refCountAndFlags(s_refCountFlagStatic | BufferInternal)61 , m_hash(0)62 {63 // Ensure that the hash is computed so that AtomicStringHash can call existingHash()64 // with impunity. The empty string is special because it is never entered into65 // AtomicString's HashKey, but still needs to compare correctly.66 hash();67 }68 69 inline StringImpl::StringImpl(unsigned length)70 : m_data(reinterpret_cast<const UChar*>(this + 1))71 , m_sharedBuffer(0)72 , m_length(length)73 , m_refCountAndFlags(s_refCountIncrement | BufferInternal)74 , m_hash(0)75 {76 ASSERT(m_data);77 ASSERT(m_length);78 }79 80 inline StringImpl::StringImpl(const UChar* characters, unsigned length)81 : m_data(characters)82 , m_sharedBuffer(0)83 , m_length(length)84 , m_refCountAndFlags(s_refCountIncrement | BufferOwned)85 , m_hash(0)86 {87 ASSERT(m_data);88 ASSERT(m_length);89 }90 91 inline StringImpl::StringImpl(const UChar* characters, unsigned length, PassRefPtr<SharedUChar> sharedBuffer)92 : m_data(characters)93 , m_sharedBuffer(sharedBuffer.releaseRef())94 , m_length(length)95 , m_refCountAndFlags(s_refCountIncrement | BufferShared)96 , m_hash(0)97 {98 ASSERT(m_data);99 ASSERT(m_length);100 }101 48 102 49 StringImpl::~StringImpl() … … 121 68 StringImpl* StringImpl::empty() 122 69 { 123 DEFINE_STATIC_LOCAL(StringImpl, emptyString, ()); 70 // A non-null pointer at an invalid address (in page zero) so that if it were to be accessed we 71 // should catch the error with fault (however it should be impossible to access, since length is zero). 72 static const UChar* invalidNonNullUCharPtr = reinterpret_cast<UChar*>(static_cast<intptr_t>(1)); 73 DEFINE_STATIC_LOCAL(StringImpl, emptyString, (invalidNonNullUCharPtr, 0, ConstructStaticString)); 124 74 return &emptyString; 75 } 76 77 PassRefPtr<StringImpl> StringImpl::createUninitialized(unsigned length, UChar*& data) 78 { 79 if (!length) { 80 data = 0; 81 return empty(); 82 } 83 84 // Allocate a single buffer large enough to contain the StringImpl 85 // struct as well as the data which it contains. This removes one 86 // heap allocation from this call. 87 if (length > ((std::numeric_limits<size_t>::max() - sizeof(StringImpl)) / sizeof(UChar))) 88 CRASH(); 89 size_t size = sizeof(StringImpl) + length * sizeof(UChar); 90 StringImpl* string = static_cast<StringImpl*>(fastMalloc(size)); 91 92 data = reinterpret_cast<UChar*>(string + 1); 93 return adoptRef(new (string) StringImpl(length)); 94 } 95 96 PassRefPtr<StringImpl> StringImpl::create(const UChar* characters, unsigned length) 97 { 98 if (!characters || !length) 99 return empty(); 100 101 UChar* data; 102 PassRefPtr<StringImpl> string = createUninitialized(length, data); 103 memcpy(data, characters, length * sizeof(UChar)); 104 return string; 105 } 106 107 PassRefPtr<StringImpl> StringImpl::create(const char* characters, unsigned length) 108 { 109 if (!characters || !length) 110 return empty(); 111 112 UChar* data; 113 PassRefPtr<StringImpl> string = createUninitialized(length, data); 114 for (unsigned i = 0; i != length; ++i) { 115 unsigned char c = characters[i]; 116 data[i] = c; 117 } 118 return string; 119 } 120 121 PassRefPtr<StringImpl> StringImpl::create(const char* string) 122 { 123 if (!string) 124 return empty(); 125 return create(string, strlen(string)); 126 } 127 128 SharedUChar* StringImpl::sharedBuffer() 129 { 130 if (m_length < minLengthToShare) 131 return 0; 132 133 BufferOwnership ownership = bufferOwnership(); 134 135 if (ownership == BufferInternal) 136 return 0; 137 if (ownership == BufferOwned) { 138 ASSERT(!m_sharedBuffer); 139 m_sharedBuffer = SharedUChar::create(new SharableUChar(m_data)).releaseRef(); 140 m_refCountAndFlags = (m_refCountAndFlags & ~s_refCountMaskBufferOwnership) | BufferShared; 141 } 142 143 ASSERT(bufferOwnership() == BufferShared); 144 ASSERT(m_sharedBuffer); 145 return m_sharedBuffer; 125 146 } 126 147 … … 914 935 } 915 936 916 PassRefPtr<StringImpl> StringImpl::adopt(Vector<UChar>& vector)917 {918 size_t size = vector.size();919 if (size == 0)920 return empty();921 return adoptRef(new StringImpl(vector.releaseBuffer(), size));922 }923 924 PassRefPtr<StringImpl> StringImpl::createUninitialized(unsigned length, UChar*& data)925 {926 if (!length) {927 data = 0;928 return empty();929 }930 931 // Allocate a single buffer large enough to contain the StringImpl932 // struct as well as the data which it contains. This removes one933 // heap allocation from this call.934 size_t size = sizeof(StringImpl) + length * sizeof(UChar);935 StringImpl* string = static_cast<StringImpl*>(fastMalloc(size));936 data = reinterpret_cast<UChar*>(string + 1);937 string = new (string) StringImpl(length);938 return adoptRef(string);939 }940 941 PassRefPtr<StringImpl> StringImpl::create(const UChar* characters, unsigned length)942 {943 if (!characters || !length)944 return empty();945 946 UChar* data;947 PassRefPtr<StringImpl> string = createUninitialized(length, data);948 memcpy(data, characters, length * sizeof(UChar));949 return string;950 }951 952 PassRefPtr<StringImpl> StringImpl::create(const char* characters, unsigned length)953 {954 if (!characters || !length)955 return empty();956 957 UChar* data;958 PassRefPtr<StringImpl> string = createUninitialized(length, data);959 for (unsigned i = 0; i != length; ++i) {960 unsigned char c = characters[i];961 data[i] = c;962 }963 return string;964 }965 966 PassRefPtr<StringImpl> StringImpl::create(const char* string)967 {968 if (!string)969 return empty();970 return create(string, strlen(string));971 }972 973 937 #if USE(JSC) 974 938 PassRefPtr<StringImpl> StringImpl::create(const JSC::UString& str) … … 1018 982 } 1019 983 1020 StringImpl::SharedUChar* StringImpl::sharedBuffer()1021 {1022 if (m_length < minLengthToShare)1023 return 0;1024 1025 BufferOwnership ownership = bufferOwnership();1026 1027 if (ownership == BufferInternal)1028 return 0;1029 1030 if (ownership == BufferOwned) {1031 ASSERT(!m_sharedBuffer);1032 m_sharedBuffer = SharedUChar::create(new SharableUChar(const_cast<UChar*>(m_data))).releaseRef();1033 m_refCountAndFlags = (m_refCountAndFlags & ~s_refCountMaskBufferOwnership) | BufferShared;1034 }1035 1036 ASSERT(bufferOwnership() == BufferShared);1037 ASSERT(m_sharedBuffer);1038 return m_sharedBuffer;1039 }1040 1041 984 } // namespace WebCore -
trunk/WebCore/platform/text/StringImpl.h
r55825 r55878 57 57 enum TextCaseSensitivity { TextCaseSensitive, TextCaseInsensitive }; 58 58 59 typedef OwnFastMallocPtr<const UChar> SharableUChar; 60 typedef CrossThreadRefCounted<SharableUChar> SharedUChar; 59 61 typedef bool (*CharacterMatchFunctionPtr)(UChar); 60 62 … … 64 66 friend struct UCharBufferTranslator; 65 67 private: 66 friend class ThreadGlobalData;67 68 68 enum BufferOwnership { 69 69 BufferInternal, … … 72 72 }; 73 73 74 typedef OwnFastMallocPtr<const UChar> SharableUChar; 75 typedef CrossThreadRefCounted<SharableUChar> SharedUChar; 76 77 // Used to create the empty string (""), automatically hashes. 78 StringImpl(); 79 // Create a StringImpl with internal storage (BufferInternal) 80 StringImpl(unsigned length); 74 // Used to construct static strings, which have an special refCount that can never hit zero. 75 // This means that the static string will never be destroyed, which is important because 76 // static strings will be shared across threads & ref-counted in a non-threadsafe manner. 77 enum StaticStringConstructType { ConstructStaticString }; 78 StringImpl(const UChar* characters, unsigned length, StaticStringConstructType) 79 : m_data(characters) 80 , m_sharedBuffer(0) 81 , m_length(length) 82 , m_refCountAndFlags(s_refCountFlagStatic | BufferInternal) 83 , m_hash(0) 84 { 85 // Ensure that the hash is computed so that AtomicStringHash can call existingHash() 86 // with impunity. The empty string is special because it is never entered into 87 // AtomicString's HashKey, but still needs to compare correctly. 88 hash(); 89 } 90 91 // Create a normal string with internal storage (BufferInternal) 92 StringImpl(unsigned length) 93 : m_data(reinterpret_cast<const UChar*>(this + 1)) 94 , m_sharedBuffer(0) 95 , m_length(length) 96 , m_refCountAndFlags(s_refCountIncrement | BufferInternal) 97 , m_hash(0) 98 { 99 ASSERT(m_data); 100 ASSERT(m_length); 101 } 102 81 103 // Create a StringImpl adopting ownership of the provided buffer (BufferOwned) 82 StringImpl(const UChar*, unsigned length); 83 // Create a StringImpl using a shared buffer (BufferShared) 84 StringImpl(const UChar*, unsigned length, PassRefPtr<SharedUChar>); 104 StringImpl(const UChar* characters, unsigned length) 105 : m_data(characters) 106 , m_sharedBuffer(0) 107 , m_length(length) 108 , m_refCountAndFlags(s_refCountIncrement | BufferOwned) 109 , m_hash(0) 110 { 111 ASSERT(m_data); 112 ASSERT(m_length); 113 } 114 115 // Used to construct new strings sharing an existing SharedUChar (BufferShared) 116 StringImpl(const UChar* characters, unsigned length, PassRefPtr<SharedUChar> sharedBuffer) 117 : m_data(characters) 118 , m_sharedBuffer(sharedBuffer.releaseRef()) 119 , m_length(length) 120 , m_refCountAndFlags(s_refCountIncrement | BufferShared) 121 , m_hash(0) 122 { 123 ASSERT(m_data); 124 ASSERT(m_length); 125 } 85 126 86 127 // For use only by AtomicString's XXXTranslator helpers. 87 void setHash(unsigned hash) { ASSERT(!m_hash); m_hash = hash; } 88 128 void setHash(unsigned hash) 129 { 130 ASSERT(!m_hash); 131 ASSERT(hash == computeHash(m_data, m_length)); 132 m_hash = hash; 133 } 134 89 135 public: 90 136 ~StringImpl(); … … 93 139 static PassRefPtr<StringImpl> create(const char*, unsigned length); 94 140 static PassRefPtr<StringImpl> create(const char*); 95 static PassRefPtr<StringImpl> createUninitialized(unsigned length, UChar*& data);96 97 static PassRefPtr<StringImpl> createWithTerminatingNullCharacter(const StringImpl&);98 99 static PassRefPtr<StringImpl> createStrippingNullCharacters(const UChar*, unsigned length);100 static PassRefPtr<StringImpl> adopt(StringBuffer&);101 static PassRefPtr<StringImpl> adopt(Vector<UChar>&);102 141 #if USE(JSC) 103 142 static PassRefPtr<StringImpl> create(const JSC::UString&); … … 105 144 #endif 106 145 146 static PassRefPtr<StringImpl> createUninitialized(unsigned length, UChar*& data); 147 static PassRefPtr<StringImpl> createWithTerminatingNullCharacter(const StringImpl&); 148 static PassRefPtr<StringImpl> createStrippingNullCharacters(const UChar*, unsigned length); 149 150 template<size_t inlineCapacity> 151 static PassRefPtr<StringImpl> adopt(Vector<UChar, inlineCapacity>& vector) 152 { 153 if (size_t size = vector.size()) { 154 ASSERT(vector.data()); 155 return adoptRef(new StringImpl(vector.releaseBuffer(), size)); 156 } 157 return empty(); 158 } 159 static PassRefPtr<StringImpl> adopt(StringBuffer&); 160 107 161 SharedUChar* sharedBuffer(); 108 const UChar* characters() { return m_data; }162 const UChar* characters() const { return m_data; } 109 163 unsigned length() { return m_length; } 110 164 … … 114 168 void setInTable() { m_refCountAndFlags |= s_refCountFlagInTable; } 115 169 116 unsigned hash() { if (m_hash == 0) m_hash = computeHash(m_data, m_length); return m_hash; } 170 // SYNC SYNC SYNC 171 // SYNC SYNC SYNC 172 // SYNC SYNC SYNC 173 // SYNC SYNC SYNC 174 // SYNC SYNC SYNC 175 176 unsigned hash() const { if (!m_hash) m_hash = computeHash(m_data, m_length); return m_hash; } 117 177 unsigned existingHash() const { ASSERT(m_hash); return m_hash; } 118 inlinestatic unsigned computeHash(const UChar* data, unsigned length) { return WTF::stringHash(data, length); }119 inlinestatic unsigned computeHash(const char* data) { return WTF::stringHash(data); }178 static unsigned computeHash(const UChar* data, unsigned length) { return WTF::stringHash(data, length); } 179 static unsigned computeHash(const char* data) { return WTF::stringHash(data); } 120 180 121 181 StringImpl* ref() { m_refCountAndFlags += s_refCountIncrement; return this; } 122 182 ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & (s_refCountMask | s_refCountFlagStatic))) delete this; } 123 183 ALWAYS_INLINE bool hasOneRef() const { return (m_refCountAndFlags & (s_refCountMask | s_refCountFlagStatic)) == s_refCountIncrement; } 184 185 static StringImpl* empty(); 124 186 125 187 // Returns a StringImpl suitable for use on another thread. … … 179 241 PassRefPtr<StringImpl> replace(unsigned index, unsigned len, StringImpl*); 180 242 181 static StringImpl* empty();182 183 243 Vector<char> ascii(); 184 244 … … 198 258 static PassRefPtr<StringImpl> createStrippingNullCharactersSlowCase(const UChar*, unsigned length); 199 259 200 // The StringImpl struct and its data may be allocated within a single heap block.201 // In this case, the m_data pointer is an "internal buffer", and does not need to be deallocated.202 260 BufferOwnership bufferOwnership() const { return static_cast<BufferOwnership>(m_refCountAndFlags & s_refCountMaskBufferOwnership); } 203 261
Note: See TracChangeset
for help on using the changeset viewer.