void RopeImpl::destructNonRecursive() { Vector<RopeImpl*, 32> workQueue; derefFibersNonRecursive(workQueue); delete this; while (!workQueue.isEmpty()) { RopeImpl* rope = workQueue.last(); workQueue.removeLast(); rope->derefFibersNonRecursive(workQueue); delete rope; } }
void RopeImpl::derefFibersNonRecursive(Vector<RopeImpl*, 32>& workQueue) { unsigned fiberCount = this->fiberCount(); for (unsigned i = 0; i < fiberCount; ++i) { Fiber& fiber = m_fibers[i]; if (isRope(fiber)) { RopeImpl* nextRope = static_cast<RopeImpl*>(fiber); if (nextRope->hasOneRef()) workQueue.append(nextRope); else nextRope->deref(); } else static_cast<UStringImpl*>(fiber)->deref(); } }
// Overview: this methods converts a TiString from holding a string in rope form // down to a simple UString representation. It does so by building up the string // backwards, since we want to avoid recursion, we expect that the tree structure // representing the rope is likely imbalanced with more nodes down the left side // (since appending to the string is likely more common) - and as such resolving // in this fashion should minimize work queue size. (If we built the queue forwards // we would likely have to place all of the constituent StringImpls into the // Vector before performing any concatenation, but by working backwards we likely // only fill the queue with the number of substrings at any given level in a // rope-of-ropes.) void TiString::resolveRopeSlowCase(TiExcState* exec, UChar* buffer) const { UNUSED_PARAM(exec); UChar* position = buffer + m_length; // Start with the current RopeImpl. Vector<RopeImpl::Fiber, 32> workQueue; RopeImpl::Fiber currentFiber; for (unsigned i = 0; i < (m_fiberCount - 1); ++i) workQueue.append(m_fibers[i]); currentFiber = m_fibers[m_fiberCount - 1]; while (true) { if (RopeImpl::isRope(currentFiber)) { RopeImpl* rope = static_cast<RopeImpl*>(currentFiber); // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber' // (we will be working backwards over the rope). unsigned fiberCountMinusOne = rope->fiberCount() - 1; for (unsigned i = 0; i < fiberCountMinusOne; ++i) workQueue.append(rope->fibers()[i]); currentFiber = rope->fibers()[fiberCountMinusOne]; } else { StringImpl* string = static_cast<StringImpl*>(currentFiber); unsigned length = string->length(); position -= length; StringImpl::copyChars(position, string->characters(), length); // Was this the last item in the work queue? if (workQueue.isEmpty()) { // Create a string from the UChar buffer, clear the rope RefPtr. ASSERT(buffer == position); for (unsigned i = 0; i < m_fiberCount; ++i) { RopeImpl::deref(m_fibers[i]); m_fibers[i] = 0; } m_fiberCount = 0; ASSERT(!isRope()); return; } // No! - set the next item up to process. currentFiber = workQueue.last(); workQueue.removeLast(); } } }
// Overview: this methods converts a JSString from holding a string in rope form // down to a simple UString representation. It does so by building up the string // backwards, since we want to avoid recursion, we expect that the tree structure // representing the rope is likely imbalanced with more nodes down the left side // (since appending to the string is likely more common) - and as such resolving // in this fashion should minimize work queue size. (If we built the queue forwards // we would likely have to place all of the constituent UStringImpls into the // Vector before performing any concatenation, but by working backwards we likely // only fill the queue with the number of substrings at any given level in a // rope-of-ropes.) void JSString::resolveRope(ExecState* exec) const { ASSERT(isRope()); // Allocate the buffer to hold the final string, position initially points to the end. UChar* buffer; if (PassRefPtr<UStringImpl> newImpl = UStringImpl::tryCreateUninitialized(m_length, buffer)) m_value = newImpl; else { for (unsigned i = 0; i < m_fiberCount; ++i) { RopeImpl::deref(m_other.m_fibers[i]); m_other.m_fibers[i] = 0; } m_fiberCount = 0; ASSERT(!isRope()); ASSERT(m_value == UString()); if (exec) throwOutOfMemoryError(exec); return; } UChar* position = buffer + m_length; // Start with the current RopeImpl. Vector<RopeImpl::Fiber, 32> workQueue; RopeImpl::Fiber currentFiber; for (unsigned i = 0; i < (m_fiberCount - 1); ++i) workQueue.append(m_other.m_fibers[i]); currentFiber = m_other.m_fibers[m_fiberCount - 1]; while (true) { if (RopeImpl::isRope(currentFiber)) { RopeImpl* rope = static_cast<RopeImpl*>(currentFiber); // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber' // (we will be working backwards over the rope). unsigned fiberCountMinusOne = rope->fiberCount() - 1; for (unsigned i = 0; i < fiberCountMinusOne; ++i) workQueue.append(rope->fibers()[i]); currentFiber = rope->fibers()[fiberCountMinusOne]; } else { UStringImpl* string = static_cast<UStringImpl*>(currentFiber); unsigned length = string->length(); position -= length; UStringImpl::copyChars(position, string->characters(), length); // Was this the last item in the work queue? if (workQueue.isEmpty()) { // Create a string from the UChar buffer, clear the rope RefPtr. ASSERT(buffer == position); for (unsigned i = 0; i < m_fiberCount; ++i) { RopeImpl::deref(m_other.m_fibers[i]); m_other.m_fibers[i] = 0; } m_fiberCount = 0; ASSERT(!isRope()); return; } // No! - set the next item up to process. currentFiber = workQueue.last(); workQueue.removeLast(); } } }