Ignore:
Timestamp:
May 11, 2010, 11:42:46 AM (15 years ago)
Author:
[email protected]
Message:

Start using ropes in String.prototype.replace.

Reviewed by Oliver Hunt and Darin Adler.

1%-1.5% speedup on SunSpider.

  • runtime/JSString.cpp:

(JSC::JSString::resolveRope): Updated for RopeImpl refactoring.

(JSC::JSString::replaceCharacter): Added a replaceCharacter function, which creates
a rope for the resulting replacement.

  • runtime/JSString.h: A few changes here:

(JSC::):
(JSC::RopeBuilder::RopeIterator::RopeIterator):
(JSC::RopeBuilder::RopeIterator::operator++):
(JSC::RopeBuilder::RopeIterator::operator*):
(JSC::RopeBuilder::RopeIterator::operator!=):
(JSC::RopeBuilder::RopeIterator::WorkItem::WorkItem):
(JSC::RopeBuilder::RopeIterator::WorkItem::operator!=):
(JSC::RopeBuilder::RopeIterator::skipRopes): Created a RopeIterator abstraction.
We use this to do a substring find without having to resolve the rope.
(We could use this iterator when resolving ropes, too, but resolving
ropes backwards is usually more efficient.)

(JSC::RopeBuilder::JSString): Added constructors for 2 & 3 UStrings.

(JSC::RopeBuilder::appendValueInConstructAndIncrementLength):
(JSC::RopeBuilder::size): Updated for RopeImpl refactoring.

  • runtime/Operations.h: Updated for RopeImpl refactoring.

(JSC::jsString): Added jsString functions for 2 & 3 UStrings.

  • runtime/RopeImpl.cpp:

(JSC::RopeImpl::derefFibersNonRecursive):

  • runtime/RopeImpl.h:

(JSC::RopeImpl::initializeFiber):
(JSC::RopeImpl::size):
(JSC::RopeImpl::fibers):
(JSC::RopeImpl::deref):
(JSC::RopeImpl::RopeImpl): A little refactoring to make this patch easier:
Moved statics to the top of the class; put multi-statement functions on
multiple lines; renamed "fiberCount" to "size" to match other collections;
changed the "fibers" accessor to return the fibers buffer, instead of an
item in the buffer, to make iteration easier.

  • runtime/StringPrototype.cpp:

(JSC::stringProtoFuncReplace): Don't resolve a rope unless we need to. Do
use our new replaceCharacter function if possible. Do use a rope to
represent splicing three strings together.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/runtime/JSString.h

    r58286 r59161  
    112112        };
    113113
     114        class RopeIterator {
     115            public:
     116                RopeIterator() { }
     117
     118                RopeIterator(RopeImpl::Fiber* fibers, size_t fiberCount)
     119                {
     120                    ASSERT(fiberCount);
     121                    m_workQueue.append(WorkItem(fibers, fiberCount));
     122                    skipRopes();
     123                }
     124
     125                RopeIterator& operator++()
     126                {
     127                    WorkItem& item = m_workQueue.last();
     128                    ASSERT(!RopeImpl::isRope(item.fibers[item.i]));
     129                    if (++item.i == item.fiberCount)
     130                        m_workQueue.removeLast();
     131                    skipRopes();
     132                    return *this;
     133                }
     134
     135                UStringImpl* operator*()
     136                {
     137                    WorkItem& item = m_workQueue.last();
     138                    RopeImpl::Fiber fiber = item.fibers[item.i];
     139                    ASSERT(!RopeImpl::isRope(fiber));
     140                    return static_cast<UStringImpl*>(fiber);
     141                }
     142
     143                bool operator!=(const RopeIterator& other) const
     144                {
     145                    return m_workQueue != other.m_workQueue;
     146                }
     147
     148            private:
     149                struct WorkItem {
     150                    WorkItem(RopeImpl::Fiber* fibers, size_t fiberCount)
     151                        : fibers(fibers)
     152                        , fiberCount(fiberCount)
     153                        , i(0)
     154                    {
     155                    }
     156
     157                    bool operator!=(const WorkItem& other) const
     158                    {
     159                        return fibers != other.fibers || fiberCount != other.fiberCount || i != other.i;
     160                    }
     161
     162                    RopeImpl::Fiber* fibers;
     163                    size_t fiberCount;
     164                    size_t i;
     165                };
     166
     167                void skipRopes()
     168                {
     169                    if (m_workQueue.isEmpty())
     170                        return;
     171
     172                    while (1) {
     173                        WorkItem& item = m_workQueue.last();
     174                        RopeImpl::Fiber fiber = item.fibers[item.i];
     175                        if (!RopeImpl::isRope(fiber))
     176                            break;
     177                        RopeImpl* rope = static_cast<RopeImpl*>(fiber);
     178                        if (++item.i == item.fiberCount)
     179                            m_workQueue.removeLast();
     180                        m_workQueue.append(WorkItem(rope->fibers(), rope->fiberCount()));
     181                    }
     182                }
     183
     184                Vector<WorkItem, 16> m_workQueue;
     185        };
     186
    114187        ALWAYS_INLINE JSString(JSGlobalData* globalData, const UString& value)
    115188            : JSCell(globalData->stringStructure.get())
     
    131204            ASSERT(!m_value.isNull());
    132205        }
    133         JSString(JSGlobalData* globalData, PassRefPtr<UString::Rep> value, HasOtherOwnerType)
     206        JSString(JSGlobalData* globalData, PassRefPtr<UStringImpl> value, HasOtherOwnerType)
    134207            : JSCell(globalData->stringStructure.get())
    135208            , m_length(value->length())
     
    201274        }
    202275
     276        // This constructor constructs a new string by concatenating u1 & u2.
     277        JSString(JSGlobalData* globalData, const UString& u1, const UString& u2)
     278            : JSCell(globalData->stringStructure.get())
     279            , m_length(u1.size() + u2.size())
     280            , m_fiberCount(2)
     281        {
     282            unsigned index = 0;
     283            appendStringInConstruct(index, u1);
     284            appendStringInConstruct(index, u2);
     285            ASSERT(index <= s_maxInternalRopeLength);
     286        }
     287
     288        // This constructor constructs a new string by concatenating u1, u2 & u3.
     289        JSString(JSGlobalData* globalData, const UString& u1, const UString& u2, const UString& u3)
     290            : JSCell(globalData->stringStructure.get())
     291            , m_length(u1.size() + u2.size() + u3.size())
     292            , m_fiberCount(s_maxInternalRopeLength)
     293        {
     294            unsigned index = 0;
     295            appendStringInConstruct(index, u1);
     296            appendStringInConstruct(index, u2);
     297            appendStringInConstruct(index, u3);
     298            ASSERT(index <= s_maxInternalRopeLength);
     299        }
     300
    203301        JSString(JSGlobalData* globalData, const UString& value, JSStringFinalizerCallback finalizer, void* context)
    204302            : JSCell(globalData->stringStructure.get())
     
    246344        JSString* getIndex(ExecState*, unsigned);
    247345        JSString* getIndexSlowCase(ExecState*, unsigned);
     346
     347        JSValue replaceCharacter(ExecState*, UChar, const UString& replacement);
    248348
    249349        static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion), AnonymousSlotCount); }
     
    283383                ASSERT(asCell(v)->isString());
    284384                JSString* s = static_cast<JSString*>(asCell(v));
    285                 ASSERT(s->fiberCount() == 1);
     385                ASSERT(s->size() == 1);
    286386                appendStringInConstruct(index, s);
    287387                m_length += s->length();
     
    329429        bool isRope() const { return m_fiberCount; }
    330430        UString& string() { ASSERT(!isRope()); return m_value; }
    331         unsigned fiberCount() { return m_fiberCount ? m_fiberCount : 1; }
     431        unsigned size() { return m_fiberCount ? m_fiberCount : 1; }
    332432
    333433        friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2);
     
    376476        if (c <= 0xFF)
    377477            return globalData->smallStrings.singleCharacterString(globalData, c);
    378         return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, 1))));
     478        return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UStringImpl::create(s.rep(), offset, 1))));
    379479    }
    380480
     
    434534                return globalData->smallStrings.singleCharacterString(globalData, c);
    435535        }
    436         return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, length)), JSString::HasOtherOwner));
     536        return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UStringImpl::create(s.rep(), offset, length)), JSString::HasOtherOwner));
    437537    }
    438538
Note: See TracChangeset for help on using the changeset viewer.