Changeset 57912 in webkit for trunk/JavaScriptCore
- Timestamp:
- Apr 20, 2010, 1:33:56 PM (15 years ago)
- Location:
- trunk/JavaScriptCore
- Files:
-
- 9 edited
- 2 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/ChangeLog
r57908 r57912 6 6 7 7 * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: 8 9 2010-04-20 Gavin Barraclough <[email protected]> 10 11 Reviewed by Geoff Garen. 12 13 Bug 37869 - Move URopeImpl to its own .h/.cpp 14 15 Currently Ropes are implemented by the class URopeImpl, which is defined in 16 UStringImpl.h, and then typedefed to the name JSString::Rope. Remove the 17 typedef, and rename all uses of URopeImpl and JSString::Rope to just RopeImpl. 18 19 Move RopeImpl to its own header, and remove all remaining references to ropes 20 from UStringImpl (rename UStringOrRopeImpl to UStringImplBase, rename or move 21 the isRope & deref methods from UStringOrRopeImpl). 22 23 * JavaScriptCore.xcodeproj/project.pbxproj: 24 * runtime/JSString.cpp: 25 (JSC::JSString::resolveRope): 26 * runtime/JSString.h: 27 (JSC::): 28 (JSC::RopeBuilder::JSString): 29 (JSC::RopeBuilder::~JSString): 30 (JSC::RopeBuilder::appendStringInConstruct): 31 (JSC::RopeBuilder::JSStringFinalizerStruct::): 32 * runtime/RopeImpl.cpp: Copied from JavaScriptCore/runtime/UStringImpl.cpp. 33 (JSC::RopeImpl::derefFibersNonRecursive): 34 (JSC::RopeImpl::destructNonRecursive): 35 * runtime/RopeImpl.h: Copied from JavaScriptCore/runtime/UStringImpl.h. 36 (JSC::RopeImpl::tryCreateUninitialized): 37 (JSC::RopeImpl::isRope): 38 (JSC::RopeImpl::deref): 39 (JSC::RopeImpl::RopeImpl): 40 * runtime/UStringImpl.cpp: 41 * runtime/UStringImpl.h: 42 (JSC::UStringImplBase::isInvalid): 43 (JSC::UStringImplBase::ref): 44 (JSC::UStringImplBase::UStringImplBase): 45 (JSC::UStringImplBase::): 46 (JSC::UStringImpl::UStringImpl): 8 47 9 48 2010-04-20 Gavin Barraclough <[email protected]> -
trunk/JavaScriptCore/GNUmakefile.am
r57904 r57912 499 499 JavaScriptCore/runtime/RegExpPrototype.cpp \ 500 500 JavaScriptCore/runtime/RegExpPrototype.h \ 501 JavaScriptCore/runtime/RopeImpl.cpp \ 502 JavaScriptCore/runtime/RopeImpl.h \ 501 503 JavaScriptCore/runtime/ScopeChain.cpp \ 502 504 JavaScriptCore/runtime/ScopeChain.h \ -
trunk/JavaScriptCore/JavaScriptCore.pro
r57904 r57912 178 178 runtime/RegExpObject.cpp \ 179 179 runtime/RegExpPrototype.cpp \ 180 runtime/RopeImpl.cpp \ 180 181 runtime/ScopeChain.cpp \ 181 182 runtime/SmallStrings.cpp \ -
trunk/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
r57192 r57912 1139 1139 <File 1140 1140 RelativePath="..\..\runtime\RegExpPrototype.h" 1141 > 1142 </File> 1143 <File 1144 RelativePath="..\..\runtime\RopeImpl.cpp" 1145 > 1146 </File> 1147 <File 1148 RelativePath="..\..\runtime\RopeImpl.h" 1141 1149 > 1142 1150 </File> -
trunk/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r57904 r57912 215 215 86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86ADD1430FDDEA980006EEC2 /* ARMv7Assembler.h */; }; 216 216 86ADD1460FDDEA980006EEC2 /* MacroAssemblerARMv7.h in Headers */ = {isa = PBXBuildFile; fileRef = 86ADD1440FDDEA980006EEC2 /* MacroAssemblerARMv7.h */; }; 217 86B99AB8117E391E00DF5A90 /* RopeImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86B99AB6117E391E00DF5A90 /* RopeImpl.cpp */; }; 218 86B99AB9117E391E00DF5A90 /* RopeImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 86B99AB7117E391E00DF5A90 /* RopeImpl.h */; settings = {ATTRIBUTES = (Private, ); }; }; 217 219 86C36EEA0EE1289D00B3DF59 /* MacroAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C36EE90EE1289D00B3DF59 /* MacroAssembler.h */; }; 218 220 86CA032E1038E8440028A609 /* Executable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86CA032D1038E8440028A609 /* Executable.cpp */; }; … … 754 756 86ADD1430FDDEA980006EEC2 /* ARMv7Assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARMv7Assembler.h; sourceTree = "<group>"; }; 755 757 86ADD1440FDDEA980006EEC2 /* MacroAssemblerARMv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssemblerARMv7.h; sourceTree = "<group>"; }; 758 86B99AB6117E391E00DF5A90 /* RopeImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RopeImpl.cpp; sourceTree = "<group>"; }; 759 86B99AB7117E391E00DF5A90 /* RopeImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RopeImpl.h; sourceTree = "<group>"; }; 756 760 86C36EE90EE1289D00B3DF59 /* MacroAssembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssembler.h; sourceTree = "<group>"; }; 757 761 86CA032D1038E8440028A609 /* Executable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Executable.cpp; sourceTree = "<group>"; }; … … 1625 1629 BCD202BF0E1706A7002C7E82 /* RegExpPrototype.cpp */, 1626 1630 BCD202C00E1706A7002C7E82 /* RegExpPrototype.h */, 1631 86B99AB6117E391E00DF5A90 /* RopeImpl.cpp */, 1632 86B99AB7117E391E00DF5A90 /* RopeImpl.h */, 1627 1633 9374D3A8038D9D74008635CE /* ScopeChain.cpp */, 1628 1634 9374D3A7038D9D74008635CE /* ScopeChain.h */, … … 2074 2080 868BFA18117CF19900B908B1 /* WTFString.h in Headers */, 2075 2081 868BFA60117D048200B908B1 /* StaticConstructors.h in Headers */, 2082 86B99AB9117E391E00DF5A90 /* RopeImpl.h in Headers */, 2076 2083 ); 2077 2084 runOnlyForDeploymentPostprocessing = 0; … … 2521 2528 868BFA0E117CEFD100B908B1 /* StringImpl.cpp in Sources */, 2522 2529 868BFA17117CF19900B908B1 /* WTFString.cpp in Sources */, 2530 86B99AB8117E391E00DF5A90 /* RopeImpl.cpp in Sources */, 2523 2531 ); 2524 2532 runOnlyForDeploymentPostprocessing = 0; -
trunk/JavaScriptCore/runtime/JSString.cpp
r57019 r57912 52 52 else { 53 53 for (unsigned i = 0; i < m_fiberCount; ++i) { 54 m_other.m_fibers[i]->deref();54 RopeImpl::deref(m_other.m_fibers[i]); 55 55 m_other.m_fibers[i] = 0; 56 56 } … … 63 63 UChar* position = buffer + m_length; 64 64 65 // Start with the current Rope .66 Vector<Rope ::Fiber, 32> workQueue;67 Rope ::Fiber currentFiber;65 // Start with the current RopeImpl. 66 Vector<RopeImpl::Fiber, 32> workQueue; 67 RopeImpl::Fiber currentFiber; 68 68 for (unsigned i = 0; i < (m_fiberCount - 1); ++i) 69 69 workQueue.append(m_other.m_fibers[i]); 70 70 currentFiber = m_other.m_fibers[m_fiberCount - 1]; 71 71 while (true) { 72 if ( currentFiber->isRope()) {73 Rope * rope = static_cast<URopeImpl*>(currentFiber);72 if (RopeImpl::isRope(currentFiber)) { 73 RopeImpl* rope = static_cast<RopeImpl*>(currentFiber); 74 74 // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber' 75 75 // (we will be working backwards over the rope). … … 89 89 ASSERT(buffer == position); 90 90 for (unsigned i = 0; i < m_fiberCount; ++i) { 91 m_other.m_fibers[i]->deref();91 RopeImpl::deref(m_other.m_fibers[i]); 92 92 m_other.m_fibers[i] = 0; 93 93 } -
trunk/JavaScriptCore/runtime/JSString.h
r57055 r57912 30 30 #include "PropertyDescriptor.h" 31 31 #include "PropertySlot.h" 32 #include "RopeImpl.h" 32 33 33 34 namespace JSC { … … 67 68 friend class JSGlobalData; 68 69 69 typedef URopeImpl Rope;70 71 70 class RopeBuilder { 72 71 public: 73 72 RopeBuilder(unsigned fiberCount) 74 73 : m_index(0) 75 , m_rope(Rope ::tryCreateUninitialized(fiberCount))74 , m_rope(RopeImpl::tryCreateUninitialized(fiberCount)) 76 75 { 77 76 } … … 79 78 bool isOutOfMemory() { return !m_rope; } 80 79 81 void append(Rope ::Fiber& fiber)80 void append(RopeImpl::Fiber& fiber) 82 81 { 83 82 ASSERT(m_rope); … … 98 97 } 99 98 100 PassRefPtr<Rope > release()99 PassRefPtr<RopeImpl> release() 101 100 { 102 101 ASSERT(m_index == m_rope->fiberCount()); … … 108 107 private: 109 108 unsigned m_index; 110 RefPtr<Rope > m_rope;109 RefPtr<RopeImpl> m_rope; 111 110 }; 112 111 … … 138 137 ASSERT(!m_value.isNull()); 139 138 } 140 JSString(JSGlobalData* globalData, PassRefPtr<Rope > rope)139 JSString(JSGlobalData* globalData, PassRefPtr<RopeImpl> rope) 141 140 : JSCell(globalData->stringStructure.get()) 142 141 , m_length(rope->length()) … … 217 216 ASSERT(vptr() == JSGlobalData::jsStringVPtr); 218 217 for (unsigned i = 0; i < m_fiberCount; ++i) 219 m_other.m_fibers[i]->deref();218 RopeImpl::deref(m_other.m_fibers[i]); 220 219 221 220 if (!m_fiberCount && m_other.m_finalizerCallback) … … 269 268 if (jsString->isRope()) { 270 269 for (unsigned i = 0; i < jsString->m_fiberCount; ++i) { 271 Rope ::Fiber fiber = jsString->m_other.m_fibers[i];270 RopeImpl::Fiber fiber = jsString->m_other.m_fibers[i]; 272 271 fiber->ref(); 273 272 m_other.m_fibers[index++] = fiber; … … 310 309 static const unsigned s_maxInternalRopeLength = 3; 311 310 312 // A string is represented either by a UString or a Rope .311 // A string is represented either by a UString or a RopeImpl. 313 312 unsigned m_length; 314 313 mutable UString m_value; … … 318 317 JSStringFinalizerStruct() : m_finalizerCallback(0) {} 319 318 union { 320 mutable Rope ::Fiber m_fibers[s_maxInternalRopeLength];319 mutable RopeImpl::Fiber m_fibers[s_maxInternalRopeLength]; 321 320 struct { 322 321 JSStringFinalizerCallback m_finalizerCallback; -
trunk/JavaScriptCore/runtime/RopeImpl.cpp
r57903 r57912 25 25 26 26 #include "config.h" 27 #include "UStringImpl.h" 28 29 #include "Identifier.h" 30 #include "StdLibExtras.h" 31 #include "UString.h" 32 #include <wtf/unicode/UTF8.h> 33 34 using namespace WTF::Unicode; 35 using namespace std; 27 #include "RopeImpl.h" 36 28 37 29 namespace JSC { 38 30 39 static const unsigned minLengthToShare = 20; 40 41 UStringImpl::~UStringImpl() 42 { 43 ASSERT(!isStatic()); 44 45 if (isIdentifier()) 46 Identifier::remove(this); 47 48 BufferOwnership ownership = bufferOwnership(); 49 if (ownership != BufferInternal) { 50 if (ownership == BufferOwned) { 51 ASSERT(!m_sharedBuffer); 52 ASSERT(m_data); 53 fastFree(const_cast<UChar*>(m_data)); 54 } else if (ownership == BufferSubstring) { 55 ASSERT(m_substringBuffer); 56 m_substringBuffer->deref(); 57 } else { 58 ASSERT(ownership == BufferShared); 59 ASSERT(m_sharedBuffer); 60 m_sharedBuffer->deref(); 61 } 62 } 63 } 64 65 UStringImpl* UStringImpl::empty() 66 { 67 // FIXME: This works around a bug in our port of PCRE, that a regular expression 68 // run on the empty string may still perform a read from the first element, and 69 // as such we need this to be a valid pointer. No code should ever be reading 70 // from a zero length string, so this should be able to be a non-null pointer 71 // into the zero-page. 72 // Replace this with 'reinterpret_cast<UChar*>(static_cast<intptr_t>(1))' once 73 // PCRE goes away. 74 static UChar emptyUCharData = 0; 75 DEFINE_STATIC_LOCAL(UStringImpl, emptyString, (&emptyUCharData, 0, ConstructStaticString)); 76 return &emptyString; 77 } 78 79 PassRefPtr<UStringImpl> UStringImpl::createUninitialized(unsigned length, UChar*& data) 80 { 81 if (!length) { 82 data = 0; 83 return empty(); 84 } 85 86 // Allocate a single buffer large enough to contain the StringImpl 87 // struct as well as the data which it contains. This removes one 88 // heap allocation from this call. 89 if (length > ((std::numeric_limits<size_t>::max() - sizeof(UStringImpl)) / sizeof(UChar))) 90 CRASH(); 91 size_t size = sizeof(UStringImpl) + length * sizeof(UChar); 92 UStringImpl* string = static_cast<UStringImpl*>(fastMalloc(size)); 93 94 data = reinterpret_cast<UChar*>(string + 1); 95 return adoptRef(new (string) UStringImpl(length)); 96 } 97 98 PassRefPtr<UStringImpl> UStringImpl::create(const UChar* characters, unsigned length) 99 { 100 if (!characters || !length) 101 return empty(); 102 103 UChar* data; 104 PassRefPtr<UStringImpl> string = createUninitialized(length, data); 105 memcpy(data, characters, length * sizeof(UChar)); 106 return string; 107 } 108 109 PassRefPtr<UStringImpl> UStringImpl::create(const char* characters, unsigned length) 110 { 111 if (!characters || !length) 112 return empty(); 113 114 UChar* data; 115 PassRefPtr<UStringImpl> string = createUninitialized(length, data); 116 for (unsigned i = 0; i != length; ++i) { 117 unsigned char c = characters[i]; 118 data[i] = c; 119 } 120 return string; 121 } 122 123 PassRefPtr<UStringImpl> UStringImpl::create(const char* string) 124 { 125 if (!string) 126 return empty(); 127 return create(string, strlen(string)); 128 } 129 130 PassRefPtr<UStringImpl> UStringImpl::create(const UChar* buffer, unsigned length, PassRefPtr<SharedUChar> sharedBuffer) 131 { 132 if (!length) 133 return empty(); 134 return adoptRef(new UStringImpl(buffer, length, sharedBuffer)); 135 } 136 137 SharedUChar* UStringImpl::sharedBuffer() 138 { 139 if (m_length < minLengthToShare) 140 return 0; 141 // All static strings are smaller that the minimim length to share. 142 ASSERT(!isStatic()); 143 144 BufferOwnership ownership = bufferOwnership(); 145 146 if (ownership == BufferInternal) 147 return 0; 148 if (ownership == BufferSubstring) 149 return m_substringBuffer->sharedBuffer(); 150 if (ownership == BufferOwned) { 151 ASSERT(!m_sharedBuffer); 152 m_sharedBuffer = SharedUChar::create(new SharableUChar(m_data)).releaseRef(); 153 m_refCountAndFlags = (m_refCountAndFlags & ~s_refCountMaskBufferOwnership) | BufferShared; 154 } 155 156 ASSERT(bufferOwnership() == BufferShared); 157 ASSERT(m_sharedBuffer); 158 return m_sharedBuffer; 159 } 160 161 void URopeImpl::derefFibersNonRecursive(Vector<URopeImpl*, 32>& workQueue) 31 void RopeImpl::derefFibersNonRecursive(Vector<RopeImpl*, 32>& workQueue) 162 32 { 163 33 unsigned length = fiberCount(); 164 34 for (unsigned i = 0; i < length; ++i) { 165 35 Fiber& fiber = fibers(i); 166 if ( fiber->isRope()) {167 URopeImpl* nextRope = static_cast<URopeImpl*>(fiber);36 if (isRope(fiber)) { 37 RopeImpl* nextRope = static_cast<RopeImpl*>(fiber); 168 38 if (nextRope->hasOneRef()) 169 39 workQueue.append(nextRope); … … 175 45 } 176 46 177 void URopeImpl::destructNonRecursive()47 void RopeImpl::destructNonRecursive() 178 48 { 179 Vector< URopeImpl*, 32> workQueue;49 Vector<RopeImpl*, 32> workQueue; 180 50 181 51 derefFibersNonRecursive(workQueue); … … 183 53 184 54 while (!workQueue.isEmpty()) { 185 URopeImpl* rope = workQueue.last();55 RopeImpl* rope = workQueue.last(); 186 56 workQueue.removeLast(); 187 57 rope->derefFibersNonRecursive(workQueue); -
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 -
trunk/JavaScriptCore/runtime/UStringImpl.cpp
r57748 r57912 159 159 } 160 160 161 void URopeImpl::derefFibersNonRecursive(Vector<URopeImpl*, 32>& workQueue)162 {163 unsigned length = fiberCount();164 for (unsigned i = 0; i < length; ++i) {165 Fiber& fiber = fibers(i);166 if (fiber->isRope()) {167 URopeImpl* nextRope = static_cast<URopeImpl*>(fiber);168 if (nextRope->hasOneRef())169 workQueue.append(nextRope);170 else171 nextRope->deref();172 } else173 static_cast<UStringImpl*>(fiber)->deref();174 }175 }176 177 void URopeImpl::destructNonRecursive()178 {179 Vector<URopeImpl*, 32> workQueue;180 181 derefFibersNonRecursive(workQueue);182 delete this;183 184 while (!workQueue.isEmpty()) {185 URopeImpl* rope = workQueue.last();186 workQueue.removeLast();187 rope->derefFibersNonRecursive(workQueue);188 delete rope;189 }190 }191 192 161 } // namespace JSC -
trunk/JavaScriptCore/runtime/UStringImpl.h
r57851 r57912 42 42 typedef CrossThreadRefCounted<SharableUChar> SharedUChar; 43 43 44 class UString OrRopeImpl: public Noncopyable {44 class UStringImplBase : public Noncopyable { 45 45 public: 46 bool is Rope() { return (m_refCountAndFlags & s_refCountIsRope) == s_refCountIsRope; }46 bool isStringImpl() { return (m_refCountAndFlags & s_refCountInvalidForStringImpl) != s_refCountInvalidForStringImpl; } 47 47 unsigned length() const { return m_length; } 48 48 49 49 void ref() { m_refCountAndFlags += s_refCountIncrement; } 50 inline void deref();51 50 52 51 protected: … … 62 61 63 62 // For SmallStringStorage, which allocates an array and uses an in-place new. 64 UString OrRopeImpl() { }65 66 UString OrRopeImpl(unsigned length, BufferOwnership ownership)63 UStringImplBase() { } 64 65 UStringImplBase(unsigned length, BufferOwnership ownership) 67 66 : m_refCountAndFlags(s_refCountIncrement | s_refCountFlagShouldReportedCost | ownership) 68 67 , m_length(length) 69 68 { 70 ASSERT( !isRope());69 ASSERT(isStringImpl()); 71 70 } 72 71 73 72 enum StaticStringConstructType { ConstructStaticString }; 74 UString OrRopeImpl(unsigned length, StaticStringConstructType)73 UStringImplBase(unsigned length, StaticStringConstructType) 75 74 : m_refCountAndFlags(s_refCountFlagStatic | s_refCountFlagIsIdentifier | BufferOwned) 76 75 , m_length(length) 77 76 { 78 ASSERT(!isRope()); 79 } 80 81 enum RopeConstructType { ConstructRope }; 82 UStringOrRopeImpl(RopeConstructType) 83 : m_refCountAndFlags(s_refCountIncrement | s_refCountIsRope) 77 ASSERT(isStringImpl()); 78 } 79 80 // This constructor is not used when creating UStringImpl objects, 81 // and sets the flags into a state marking the object as such. 82 enum NonStringImplConstructType { ConstructNonStringImpl }; 83 UStringImplBase(NonStringImplConstructType) 84 : m_refCountAndFlags(s_refCountIncrement | s_refCountInvalidForStringImpl) 84 85 , m_length(0) 85 86 { 86 ASSERT( isRope());87 ASSERT(!isStringImpl()); 87 88 } 88 89 … … 96 97 static const unsigned s_refCountFlagIsIdentifier = 0x4; 97 98 static const unsigned s_refCountMaskBufferOwnership = 0x3; 98 // Use an otherwise invalid permutation of flags (static & shouldReportedCost -99 // s tatic strings do not set shouldReportedCost in the constructor, and this bit100 // is only ever cleared, not set) to identify objects that are ropes.101 static const unsigned s_refCountI sRope= s_refCountFlagStatic | s_refCountFlagShouldReportedCost;99 // An invalid permutation of flags (static & shouldReportedCost - static strings do not 100 // set shouldReportedCost in the constructor, and this bit is only ever cleared, not set). 101 // Used by "ConstructNonStringImpl" constructor, above. 102 static const unsigned s_refCountInvalidForStringImpl = s_refCountFlagStatic | s_refCountFlagShouldReportedCost; 102 103 103 104 unsigned m_refCountAndFlags; … … 105 106 }; 106 107 107 class UStringImpl : public UString OrRopeImpl{108 class UStringImpl : public UStringImplBase { 108 109 friend struct CStringTranslator; 109 110 friend struct UCharBufferTranslator; 110 111 friend class JIT; 111 112 friend class SmallStringsStorage; 112 friend class UStringOrRopeImpl;113 113 friend void initializeUString(); 114 114 private: … … 120 120 // static strings will be shared across threads & ref-counted in a non-threadsafe manner. 121 121 UStringImpl(const UChar* characters, unsigned length, StaticStringConstructType) 122 : UString OrRopeImpl(length, ConstructStaticString)122 : UStringImplBase(length, ConstructStaticString) 123 123 , m_data(characters) 124 124 , m_buffer(0) … … 130 130 // Create a normal string with internal storage (BufferInternal) 131 131 UStringImpl(unsigned length) 132 : UString OrRopeImpl(length, BufferInternal)132 : UStringImplBase(length, BufferInternal) 133 133 , m_data(reinterpret_cast<UChar*>(this + 1)) 134 134 , m_buffer(0) … … 141 141 // Create a UStringImpl adopting ownership of the provided buffer (BufferOwned) 142 142 UStringImpl(const UChar* characters, unsigned length) 143 : UString OrRopeImpl(length, BufferOwned)143 : UStringImplBase(length, BufferOwned) 144 144 , m_data(characters) 145 145 , m_buffer(0) … … 152 152 // Used to create new strings that are a substring of an existing UStringImpl (BufferSubstring) 153 153 UStringImpl(const UChar* characters, unsigned length, PassRefPtr<UStringImpl> base) 154 : UString OrRopeImpl(length, BufferSubstring)154 : UStringImplBase(length, BufferSubstring) 155 155 , m_data(characters) 156 156 , m_substringBuffer(base.releaseRef()) … … 164 164 // Used to construct new strings sharing an existing SharedUChar (BufferShared) 165 165 UStringImpl(const UChar* characters, unsigned length, PassRefPtr<SharedUChar> sharedBuffer) 166 : UString OrRopeImpl(length, BufferShared)166 : UStringImplBase(length, BufferShared) 167 167 , m_data(characters) 168 168 , m_sharedBuffer(sharedBuffer.releaseRef()) … … 289 289 }; 290 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) 301 { 302 void* allocation; 303 if (tryFastMalloc(sizeof(URopeImpl) + (fiberCount - 1) * sizeof(Fiber)).getValue(allocation)) 304 return adoptRef(new (allocation) URopeImpl(fiberCount)); 305 return 0; 306 } 307 308 void initializeFiber(unsigned &index, Fiber fiber) 309 { 310 m_fibers[index++] = fiber; 311 fiber->ref(); 312 m_length += fiber->length(); 313 } 314 315 unsigned fiberCount() { return m_fiberCount; } 316 Fiber& fibers(unsigned index) { return m_fibers[index]; } 317 318 ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & s_refCountMask)) destructNonRecursive(); } 319 320 private: 321 URopeImpl(unsigned fiberCount) : UStringOrRopeImpl(ConstructRope), m_fiberCount(fiberCount) {} 322 323 void destructNonRecursive(); 324 void derefFibersNonRecursive(Vector<URopeImpl*, 32>& workQueue); 325 326 bool hasOneRef() { return (m_refCountAndFlags & s_refCountMask) == s_refCountIncrement; } 327 328 unsigned m_fiberCount; 329 Fiber m_fibers[1]; 330 }; 331 332 inline void UStringOrRopeImpl::deref() 333 { 334 if (isRope()) 335 static_cast<URopeImpl*>(this)->deref(); 336 else 337 static_cast<UStringImpl*>(this)->deref(); 291 bool equal(const UStringImpl*, const UStringImpl*); 292 338 293 } 339 294 340 bool equal(const UStringImpl*, const UStringImpl*);341 342 }343 344 295 #endif
Note:
See TracChangeset
for help on using the changeset viewer.