JavaScriptCore/runtime/JSString.cpp
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());
        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();
        }
    }
}
// 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.)
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.)
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());
    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());
        throwOutOfMemoryError(exec);
        return;
    }
    UChar* position = buffer + m_length;
    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);
            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);
            if (workQueue.isEmpty()) {
                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;
            }
            currentFiber = workQueue.last();
            workQueue.removeLast();
        }
    }
}
void JSString :: resolveRope ( ExecState * exec ) const { ASSERT ( isRope ( ) ) ; 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 ( ) ) ; throwOutOfMemoryError ( exec ) ; return ; } UChar * position = buffer + m_length ; 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 ) ; 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 ) ; if ( workQueue . isEmpty ( ) ) { 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 ; } currentFiber = workQueue . last ( ) ; workQueue . removeLast ( ) ; } } }
Overview: this methods converts a JSString from holding a string in rope form
down to a simple UString representation.
Overview : this methods converts a JSString from holding a string in rope form down to a simple UString representation .
// Allocate the buffer to hold the final string, position initially points to the end. // Start with the current RopeImpl. // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber' // (we will be working backwards over the rope). // Was this the last item in the work queue? // Create a string from the UChar buffer, clear the rope RefPtr. // No! - set the next item up to process.