Changeset 54843 in webkit for trunk/JavaScriptCore/runtime
- Timestamp:
- Feb 16, 2010, 4:01:58 PM (15 years ago)
- Location:
- trunk/JavaScriptCore/runtime
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/runtime/ArrayPrototype.cpp
r54571 r54843 202 202 buffer.append(','); 203 203 if (RefPtr<UString::Rep> rep = strBuffer[i]) 204 buffer.append(rep->data(), rep-> size());204 buffer.append(rep->data(), rep->length()); 205 205 } 206 206 ASSERT(buffer.size() == totalSize); -
trunk/JavaScriptCore/runtime/Identifier.cpp
r54789 r54843 80 80 bool Identifier::equal(const UString::Rep* r, const char* s) 81 81 { 82 int length = r-> size();82 int length = r->length(); 83 83 const UChar* d = r->data(); 84 84 for (int i = 0; i != length; ++i) … … 90 90 bool Identifier::equal(const UString::Rep* r, const UChar* s, unsigned length) 91 91 { 92 if (r-> size() != length)92 if (r->length() != length) 93 93 return false; 94 94 const UChar* d = r->data(); … … 210 210 { 211 211 ASSERT(!r->isIdentifier()); 212 if (r-> size() == 1) {212 if (r->length() == 1) { 213 213 UChar c = r->data()[0]; 214 214 if (c <= 0xFF) … … 221 221 } 222 222 } 223 if (!r-> size()) {223 if (!r->length()) { 224 224 UString::Rep::empty().hash(); 225 225 return &UString::Rep::empty(); -
trunk/JavaScriptCore/runtime/JSString.cpp
r54804 r54843 31 31 32 32 namespace JSC { 33 34 void Rope::destructNonRecursive()35 {36 Vector<Rope*, 32> workQueue;37 Rope* rope = this;38 39 while (true) {40 unsigned length = rope->fiberCount();41 for (unsigned i = 0; i < length; ++i) {42 Fiber& fiber = rope->fibers(i);43 if (fiber.isString())44 fiber.string()->deref();45 else {46 Rope* nextRope = fiber.rope();47 if (nextRope->hasOneRef())48 workQueue.append(nextRope);49 else50 nextRope->deref();51 }52 }53 if (rope != this)54 fastFree(rope);55 56 if (workQueue.isEmpty())57 return;58 59 rope = workQueue.last();60 workQueue.removeLast();61 }62 }63 64 Rope::~Rope()65 {66 destructNonRecursive();67 }68 33 69 34 // Overview: this methods converts a JSString from holding a string in rope form … … 73 38 // (since appending to the string is likely more common) - and as such resolving 74 39 // in this fashion should minimize work queue size. (If we built the queue forwards 75 // we would likely have to place all of the constituent UString ::Reps into the40 // we would likely have to place all of the constituent UStringImpls into the 76 41 // Vector before performing any concatenation, but by working backwards we likely 77 42 // only fill the queue with the number of substrings at any given level in a … … 87 52 else { 88 53 for (unsigned i = 0; i < m_fiberCount; ++i) { 89 m_ fibers[i].deref();90 m_ fibers[i] = static_cast<void*>(0);54 m_other.m_fibers[i]->deref(); 55 m_other.m_fibers[i] = 0; 91 56 } 92 57 m_fiberCount = 0; … … 102 67 Rope::Fiber currentFiber; 103 68 for (unsigned i = 0; i < (m_fiberCount - 1); ++i) 104 workQueue.append(m_ fibers[i]);105 currentFiber = m_ fibers[m_fiberCount - 1];69 workQueue.append(m_other.m_fibers[i]); 70 currentFiber = m_other.m_fibers[m_fiberCount - 1]; 106 71 while (true) { 107 if (currentFiber .isRope()) {108 Rope* rope = currentFiber.rope();72 if (currentFiber->isRope()) { 73 Rope* rope = static_cast<URopeImpl*>(currentFiber); 109 74 // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber' 110 75 // (we will be working backwards over the rope). … … 114 79 currentFiber = rope->fibers(fiberCountMinusOne); 115 80 } else { 116 UString ::Rep* string = currentFiber.string();117 unsigned length = string-> size();81 UStringImpl* string = static_cast<UStringImpl*>(currentFiber); 82 unsigned length = string->length(); 118 83 position -= length; 119 84 UStringImpl::copyChars(position, string->data(), length); … … 124 89 ASSERT(buffer == position); 125 90 for (unsigned i = 0; i < m_fiberCount; ++i) { 126 m_ fibers[i].deref();127 m_ fibers[i] = static_cast<void*>(0);91 m_other.m_fibers[i]->deref(); 92 m_other.m_fibers[i] = 0; 128 93 } 129 94 m_fiberCount = 0; -
trunk/JavaScriptCore/runtime/JSString.h
r54804 r54843 33 33 namespace JSC { 34 34 35 // FIXME: this class is on its way out into a different header.36 class Rope : public RefCounted<Rope> {37 public:38 // A Rope is composed from a set of smaller strings called Fibers.39 // Each Fiber in a rope is either UString::Rep or another Rope.40 class Fiber {41 public:42 Fiber() : m_value(0) {}43 Fiber(UString::Rep* string) : m_value(reinterpret_cast<intptr_t>(string)) {}44 Fiber(Rope* rope) : m_value(reinterpret_cast<intptr_t>(rope) | 1) {}45 46 Fiber(void* nonFiber) : m_value(reinterpret_cast<intptr_t>(nonFiber)) {}47 48 void deref()49 {50 if (isRope())51 rope()->deref();52 else53 string()->deref();54 }55 56 Fiber& ref()57 {58 if (isString())59 string()->ref();60 else61 rope()->ref();62 return *this;63 }64 65 unsigned refAndGetLength()66 {67 if (isString()) {68 UString::Rep* rep = string();69 return rep->ref()->size();70 } else {71 Rope* r = rope();72 r->ref();73 return r->length();74 }75 }76 77 bool isRope() { return m_value & 1; }78 Rope* rope() { return reinterpret_cast<Rope*>(m_value & ~1); }79 bool isString() { return !isRope(); }80 UString::Rep* string() { return reinterpret_cast<UString::Rep*>(m_value); }81 82 void* nonFiber() { return reinterpret_cast<void*>(m_value); }83 private:84 intptr_t m_value;85 };86 87 // Creates a Rope comprising of 'fiberCount' Fibers.88 // The Rope is constructed in an uninitialized state - initialize must be called for each Fiber in the Rope.89 static PassRefPtr<Rope> tryCreateUninitialized(unsigned fiberCount)90 {91 void* allocation;92 if (tryFastMalloc(sizeof(Rope) + (fiberCount - 1) * sizeof(Fiber)).getValue(allocation))93 return adoptRef(new (allocation) Rope(fiberCount));94 return 0;95 }96 97 ~Rope();98 void destructNonRecursive();99 100 void initializeFiber(unsigned &index, Fiber& fiber)101 {102 m_fibers[index++] = fiber;103 m_length += fiber.refAndGetLength();104 }105 void initializeFiber(unsigned &index, UStringImpl* impl)106 {107 m_fibers[index++] = Fiber(impl);108 m_length += impl->ref()->size();109 }110 111 unsigned fiberCount() { return m_fiberCount; }112 unsigned length() { return m_length; }113 Fiber& fibers(unsigned index) { return m_fibers[index]; }114 115 private:116 Rope(unsigned fiberCount) : m_fiberCount(fiberCount), m_length(0) {}117 void* operator new(size_t, void* inPlace) { return inPlace; }118 119 unsigned m_fiberCount;120 unsigned m_length;121 Fiber m_fibers[1];122 };123 124 35 class JSString; 125 36 … … 156 67 friend class JIT; 157 68 friend class JSGlobalData; 69 70 typedef URopeImpl Rope; 158 71 159 72 class RopeBuilder { … … 181 94 if (jsString->isRope()) { 182 95 for (unsigned i = 0; i < jsString->m_fiberCount; ++i) 183 append(jsString->m_ fibers[i]);96 append(jsString->m_other.m_fibers[i]); 184 97 } else 185 98 append(jsString->string()); … … 216 129 JSString(JSGlobalData* globalData, PassRefPtr<UString::Rep> value, HasOtherOwnerType) 217 130 : JSCell(globalData->stringStructure.get()) 218 , m_length(value-> size())131 , m_length(value->length()) 219 132 , m_value(value) 220 133 , m_fiberCount(0) … … 226 139 , m_fiberCount(1) 227 140 { 228 m_ fibers[0] = rope.releaseRef();141 m_other.m_fibers[0] = rope.releaseRef(); 229 142 } 230 143 // This constructor constructs a new string by concatenating s1 & s2. … … 290 203 { 291 204 // nasty hack because we can't union non-POD types 292 m_ fibers[0] = reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(finalizer));293 m_ fibers[1]= context;205 m_other.m_finalizerCallback = finalizer; 206 m_other.m_finalizerContext = context; 294 207 Heap::heap(this)->reportExtraMemoryCost(value.cost()); 295 208 } … … 299 212 ASSERT(vptr() == JSGlobalData::jsStringVPtr); 300 213 for (unsigned i = 0; i < m_fiberCount; ++i) 301 m_fibers[i].deref(); 302 303 if (!m_fiberCount && m_fibers[0].nonFiber()) { 304 JSStringFinalizerCallback finalizer = reinterpret_cast<JSStringFinalizerCallback>(m_fibers[0].nonFiber()); 305 finalizer(this, m_fibers[1].nonFiber()); 306 } 214 m_other.m_fibers[i]->deref(); 215 216 if (!m_fiberCount && m_other.m_finalizerCallback) 217 m_other.m_finalizerCallback(this, m_other.m_finalizerContext); 307 218 } 308 219 … … 343 254 void appendStringInConstruct(unsigned& index, const UString& string) 344 255 { 345 m_fibers[index++] = Rope::Fiber(string.rep()->ref()); 256 UStringImpl* impl = string.rep(); 257 impl->ref(); 258 m_other.m_fibers[index++] = impl; 346 259 } 347 260 … … 349 262 { 350 263 if (jsString->isRope()) { 351 for (unsigned i = 0; i < jsString->m_fiberCount; ++i) 352 m_fibers[index++] = jsString->m_fibers[i].ref(); 264 for (unsigned i = 0; i < jsString->m_fiberCount; ++i) { 265 Rope::Fiber fiber = jsString->m_other.m_fibers[i]; 266 fiber->ref(); 267 m_other.m_fibers[index++] = fiber; 268 } 353 269 } else 354 270 appendStringInConstruct(index, jsString->string()); … … 365 281 } else { 366 282 UString u(v.toString(exec)); 367 m_fibers[index++] = Rope::Fiber(u.rep()->ref()); 283 UStringImpl* impl = u.rep(); 284 impl->ref(); 285 m_other.m_fibers[index++] = impl; 368 286 m_length += u.size(); 369 287 } … … 392 310 mutable UString m_value; 393 311 mutable unsigned m_fiberCount; 394 mutable Rope::Fiber m_fibers[s_maxInternalRopeLength]; 312 // This structure exists to support a temporary workaround for a GC issue. 313 struct JSStringFinalizerStruct { 314 JSStringFinalizerStruct() : m_finalizerCallback(0) {} 315 union { 316 mutable Rope::Fiber m_fibers[s_maxInternalRopeLength]; 317 struct { 318 JSStringFinalizerCallback m_finalizerCallback; 319 void* m_finalizerContext; 320 }; 321 }; 322 } m_other; 395 323 396 324 bool isRope() const { return m_fiberCount; } -
trunk/JavaScriptCore/runtime/UString.cpp
r54789 r54843 496 496 497 497 // Empty string is not OK. 498 unsigned len = m_rep-> size();498 unsigned len = m_rep->length(); 499 499 if (len == 0) 500 500 return 0; … … 713 713 bool equal(const UString::Rep* r, const UString::Rep* b) 714 714 { 715 unsigned length = r-> size();716 if (length != b-> size())715 unsigned length = r->length(); 716 if (length != b->length()) 717 717 return false; 718 718 const UChar* d = r->data(); -
trunk/JavaScriptCore/runtime/UString.h
r54795 r54843 133 133 134 134 bool isNull() const { return m_rep == s_nullRep; } 135 bool isEmpty() const { return !m_rep-> size(); }135 bool isEmpty() const { return !m_rep->length(); } 136 136 137 137 bool is8Bit() const; 138 138 139 unsigned size() const { return m_rep-> size(); }139 unsigned size() const { return m_rep->length(); } 140 140 141 141 UChar operator[](unsigned pos) const; -
trunk/JavaScriptCore/runtime/UStringImpl.cpp
r54789 r54843 119 119 } 120 120 121 void URopeImpl::derefFibersNonRecursive(Vector<URopeImpl*, 32>& workQueue) 122 { 123 unsigned length = fiberCount(); 124 for (unsigned i = 0; i < length; ++i) { 125 Fiber& fiber = fibers(i); 126 if (fiber->isRope()) { 127 URopeImpl* nextRope = static_cast<URopeImpl*>(fiber); 128 if (nextRope->hasOneRef()) 129 workQueue.append(nextRope); 130 else 131 nextRope->deref(); 132 } else 133 static_cast<UStringImpl*>(fiber)->deref(); 134 } 121 135 } 136 137 void URopeImpl::destructNonRecursive() 138 { 139 Vector<URopeImpl*, 32> workQueue; 140 141 derefFibersNonRecursive(workQueue); 142 delete this; 143 144 while (!workQueue.isEmpty()) { 145 URopeImpl* rope = workQueue.last(); 146 workQueue.removeLast(); 147 rope->derefFibersNonRecursive(workQueue); 148 delete rope; 149 } 150 } 151 152 } // namespace JSC -
trunk/JavaScriptCore/runtime/UStringImpl.h
r54789 r54843 41 41 typedef CrossThreadRefCounted<OwnFastMallocPtr<UChar> > SharedUChar; 42 42 43 class UStringImpl : Noncopyable { 43 class UStringOrRopeImpl : public Noncopyable { 44 public: 45 bool isRope() { return (m_refCountAndFlags & s_refCountIsRope) == s_refCountIsRope; } 46 unsigned length() const { return m_length; } 47 48 void ref() { m_refCountAndFlags += s_refCountIncrement; } 49 inline void deref(); 50 51 protected: 52 enum BufferOwnership { 53 BufferInternal, 54 BufferOwned, 55 BufferSubstring, 56 BufferShared, 57 }; 58 59 using Noncopyable::operator new; 60 void* operator new(size_t, void* inPlace) { return inPlace; } 61 62 // For SmallStringStorage, which allocates an array and uses an in-place new. 63 UStringOrRopeImpl() { } 64 65 UStringOrRopeImpl(unsigned length, BufferOwnership ownership) 66 : m_refCountAndFlags(s_refCountIncrement | s_refCountFlagShouldReportedCost | ownership) 67 , m_length(length) 68 { 69 ASSERT(!isRope()); 70 } 71 72 enum StaticStringConstructType { ConstructStaticString }; 73 UStringOrRopeImpl(unsigned length, StaticStringConstructType) 74 : m_refCountAndFlags(s_refCountFlagStatic | BufferOwned) 75 , m_length(length) 76 { 77 ASSERT(!isRope()); 78 } 79 80 enum RopeConstructType { ConstructRope }; 81 UStringOrRopeImpl(RopeConstructType) 82 : m_refCountAndFlags(s_refCountIncrement | s_refCountIsRope) 83 , m_length(0) 84 { 85 ASSERT(isRope()); 86 } 87 88 // The bottom 5 bits hold flags, the top 27 bits hold the ref count. 89 // When dereferencing UStringImpls we check for the ref count AND the 90 // static bit both being zero - static strings are never deleted. 91 static const unsigned s_refCountMask = 0xFFFFFFE0; 92 static const unsigned s_refCountIncrement = 0x20; 93 static const unsigned s_refCountFlagStatic = 0x10; 94 static const unsigned s_refCountFlagShouldReportedCost = 0x8; 95 static const unsigned s_refCountFlagIsIdentifier = 0x4; 96 static const unsigned s_refCountMaskBufferOwnership = 0x3; 97 // Use an otherwise invalid permutation of flags (static & shouldReportedCost - 98 // static strings do not set shouldReportedCost in the constructor, and this bit 99 // is only ever cleared, not set) to identify objects that are ropes. 100 static const unsigned s_refCountIsRope = s_refCountFlagStatic | s_refCountFlagShouldReportedCost; 101 102 unsigned m_refCountAndFlags; 103 unsigned m_length; 104 }; 105 106 class UStringImpl : public UStringOrRopeImpl { 44 107 public: 45 108 template<size_t inlineCapacity> … … 48 111 if (unsigned length = vector.size()) { 49 112 ASSERT(vector.data()); 50 return adoptRef(new UStringImpl(vector.releaseBuffer(), length , BufferOwned));113 return adoptRef(new UStringImpl(vector.releaseBuffer(), length)); 51 114 } 52 115 return &empty(); … … 80 143 UStringImpl* resultImpl = static_cast<UStringImpl*>(fastMalloc(sizeof(UChar) * length + sizeof(UStringImpl))); 81 144 output = reinterpret_cast<UChar*>(resultImpl + 1); 82 return adoptRef(new(resultImpl) UStringImpl( output, length, BufferInternal));145 return adoptRef(new(resultImpl) UStringImpl(length)); 83 146 } 84 147 … … 96 159 return 0; 97 160 output = reinterpret_cast<UChar*>(resultImpl + 1); 98 return adoptRef(new(resultImpl) UStringImpl( output, length, BufferInternal));161 return adoptRef(new(resultImpl) UStringImpl(length)); 99 162 } 100 163 101 164 SharedUChar* sharedBuffer(); 102 165 UChar* data() const { return m_data; } 103 unsigned size() const { return m_length; }104 166 size_t cost() 105 167 { … … 108 170 return m_bufferSubstring->cost(); 109 171 110 if (m_refCountAndFlags & s_refCountFlagHasReportedCost) 111 return 0; 112 m_refCountAndFlags |= s_refCountFlagHasReportedCost; 113 return m_length; 172 if (m_refCountAndFlags & s_refCountFlagShouldReportedCost) { 173 m_refCountAndFlags &= ~s_refCountFlagShouldReportedCost; 174 return m_length; 175 } 176 return 0; 114 177 } 115 178 unsigned hash() const { if (!m_hash) m_hash = computeHash(data(), m_length); return m_hash; } … … 125 188 } 126 189 127 UStringImpl* ref() { m_refCountAndFlags += s_refCountIncrement; return this; } 128 ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & s_refCountMask)) delete this; } 190 ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & (s_refCountMask | s_refCountFlagStatic))) delete this; } 129 191 130 192 static void copyChars(UChar* destination, const UChar* source, unsigned numCharacters) … … 152 214 153 215 private: 154 enum BufferOwnership {155 BufferInternal,156 BufferOwned,157 BufferSubstring,158 BufferShared,159 };160 161 216 // For SmallStringStorage, which allocates an array and uses an in-place new. 162 217 UStringImpl() { } 163 218 164 // Used to construct normal strings with an internal or external buffer. 165 UStringImpl(UChar* data, unsigned length, BufferOwnership ownership) 166 : m_data(data) 219 // Used to construct normal strings with an internal buffer. 220 UStringImpl(unsigned length) 221 : UStringOrRopeImpl(length, BufferInternal) 222 , m_data(reinterpret_cast<UChar*>(this + 1)) 167 223 , m_buffer(0) 168 , m_length(length) 169 , m_refCountAndFlags(s_refCountIncrement | ownership) 170 , m_hash(0) 171 { 172 ASSERT((ownership == BufferInternal) || (ownership == BufferOwned)); 224 , m_hash(0) 225 { 226 checkConsistency(); 227 } 228 229 // Used to construct normal strings with an external buffer. 230 UStringImpl(UChar* data, unsigned length) 231 : UStringOrRopeImpl(length, BufferOwned) 232 , m_data(data) 233 , m_buffer(0) 234 , m_hash(0) 235 { 173 236 checkConsistency(); 174 237 } … … 177 240 // This means that the static string will never be destroyed, which is important because 178 241 // static strings will be shared across threads & ref-counted in a non-threadsafe manner. 179 enum StaticStringConstructType { ConstructStaticString };180 242 UStringImpl(UChar* data, unsigned length, StaticStringConstructType) 181 : m_data(data) 243 : UStringOrRopeImpl(length, ConstructStaticString) 244 , m_data(data) 182 245 , m_buffer(0) 183 , m_length(length)184 , m_refCountAndFlags(s_refCountFlagStatic | BufferOwned)185 246 , m_hash(0) 186 247 { … … 190 251 // Used to create new strings that are a substring of an existing string. 191 252 UStringImpl(UChar* data, unsigned length, PassRefPtr<UStringImpl> base) 192 : m_data(data) 253 : UStringOrRopeImpl(length, BufferSubstring) 254 , m_data(data) 193 255 , m_bufferSubstring(base.releaseRef()) 194 , m_length(length)195 , m_refCountAndFlags(s_refCountIncrement | BufferSubstring)196 256 , m_hash(0) 197 257 { … … 199 259 // that all pointers will be at least 8-byte aligned, we cannot guarantee that of 200 260 // UStringImpls that are not heap allocated. 201 ASSERT(m_bufferSubstring-> size());261 ASSERT(m_bufferSubstring->length()); 202 262 ASSERT(!m_bufferSubstring->isStatic()); 203 263 checkConsistency(); … … 206 266 // Used to construct new strings sharing an existing shared buffer. 207 267 UStringImpl(UChar* data, unsigned length, PassRefPtr<SharedUChar> sharedBuffer) 208 : m_data(data) 268 : UStringOrRopeImpl(length, BufferShared) 269 , m_data(data) 209 270 , m_bufferShared(sharedBuffer.releaseRef()) 210 , m_length(length) 211 , m_refCountAndFlags(s_refCountIncrement | BufferShared) 212 , m_hash(0) 213 { 214 checkConsistency(); 215 } 216 217 using Noncopyable::operator new; 218 void* operator new(size_t, void* inPlace) { return inPlace; } 271 , m_hash(0) 272 { 273 checkConsistency(); 274 } 219 275 220 276 ~UStringImpl(); … … 223 279 static const unsigned s_minLengthToShare = 10; 224 280 static const unsigned s_copyCharsInlineCutOff = 20; 225 // We initialize and increment/decrement the refCount for all normal (non-static) strings by the value 2.226 // We initialize static strings with an odd number (specifically, 1), such that the refCount cannot reach zero.227 static const unsigned s_refCountMask = 0xFFFFFFF0;228 static const unsigned s_refCountIncrement = 0x20;229 static const unsigned s_refCountFlagStatic = 0x10;230 static const unsigned s_refCountFlagHasReportedCost = 0x8;231 static const unsigned s_refCountFlagIsIdentifier = 0x4;232 static const unsigned s_refCountMaskBufferOwnership = 0x3;233 281 234 282 UStringImpl* bufferOwnerString() { return (bufferOwnership() == BufferSubstring) ? m_bufferSubstring : this; } … … 245 293 SharedUChar* m_bufferShared; 246 294 }; 247 unsigned m_length;248 unsigned m_refCountAndFlags;249 295 mutable unsigned m_hash; 250 296 … … 253 299 friend class JIT; 254 300 friend class SmallStringsStorage; 301 friend class UStringOrRopeImpl; 255 302 friend void initializeUString(); 256 303 }; 257 304 305 class URopeImpl : public UStringOrRopeImpl { 306 public: 307 // A URopeImpl is composed from a set of smaller strings called Fibers. 308 // Each Fiber in a rope is either UStringImpl or another URopeImpl. 309 typedef UStringOrRopeImpl* Fiber; 310 311 // Creates a URopeImpl comprising of 'fiberCount' Fibers. 312 // The URopeImpl is constructed in an uninitialized state - initialize must be called for each Fiber in the URopeImpl. 313 static PassRefPtr<URopeImpl> tryCreateUninitialized(unsigned fiberCount) 314 { 315 void* allocation; 316 if (tryFastMalloc(sizeof(URopeImpl) + (fiberCount - 1) * sizeof(Fiber)).getValue(allocation)) 317 return adoptRef(new (allocation) URopeImpl(fiberCount)); 318 return 0; 319 } 320 321 void initializeFiber(unsigned &index, Fiber fiber) 322 { 323 m_fibers[index++] = fiber; 324 fiber->ref(); 325 m_length += fiber->length(); 326 } 327 328 unsigned fiberCount() { return m_fiberCount; } 329 Fiber& fibers(unsigned index) { return m_fibers[index]; } 330 331 ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & s_refCountMask)) destructNonRecursive(); } 332 333 private: 334 URopeImpl(unsigned fiberCount) : UStringOrRopeImpl(ConstructRope), m_fiberCount(fiberCount) {} 335 336 void destructNonRecursive(); 337 void derefFibersNonRecursive(Vector<URopeImpl*, 32>& workQueue); 338 339 bool hasOneRef() { return (m_refCountAndFlags & s_refCountMask) == s_refCountIncrement; } 340 341 unsigned m_fiberCount; 342 Fiber m_fibers[1]; 343 }; 344 345 inline void UStringOrRopeImpl::deref() 346 { 347 m_refCountAndFlags -= s_refCountIncrement; 348 if (!(m_refCountAndFlags & s_refCountMask)) { 349 if (isRope()) 350 delete static_cast<URopeImpl*>(this); 351 else if (!s_refCountFlagStatic) 352 delete static_cast<UStringImpl*>(this); 353 } 354 } 355 258 356 bool equal(const UStringImpl*, const UStringImpl*); 259 357
Note:
See TracChangeset
for help on using the changeset viewer.