Changeset 73433 in webkit for trunk/JavaScriptCore/runtime


Ignore:
Timestamp:
Dec 7, 2010, 3:11:08 AM (14 years ago)
Author:
Antti Koivisto
Message:

https://bugs.webkit.org/show_bug.cgi?id=50412
http://www.wunderground.com/US/CA/Hayward.html causes big memory spike during page loading

Reviewed by Gavin Barraclough.

Creating a substring caused the original string be flattened if it was in the rope form. This could use
significant amount of memory by reducing buffer sharing between strings.

Add a rope specific substring function that constructs the substring by reusing the rope fibers
instead of flattening the rope.

No change observed in SunSpider.

  • runtime/JSString.cpp:

(JSC::JSString::substringFromRope):

  • runtime/JSString.h:

(JSC::jsSubstring):

  • runtime/StringPrototype.cpp:

(JSC::stringProtoFuncSubstr):
(JSC::stringProtoFuncSubstring):

Location:
trunk/JavaScriptCore/runtime
Files:
3 edited

Legend:

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

    r70496 r73433  
    3232
    3333namespace JSC {
     34   
     35static const unsigned substringFromRopeCutoff = 4;
    3436
    3537// Overview: this methods converts a JSString from holding a string in rope form
     
    106108    }
    107109}
     110   
     111// This function construsts a substring out of a rope without flattening by reusing the existing fibers.
     112// This can reduce memory usage substantially. Since traversing ropes is slow the function will revert
     113// back to flattening if the rope turns out to be long.
     114JSString* JSString::substringFromRope(ExecState* exec, unsigned substringStart, unsigned substringLength)
     115{
     116    ASSERT(isRope());
     117    ASSERT(substringLength);
     118   
     119    JSGlobalData* globalData = &exec->globalData();
     120
     121    UString substringFibers[3];
     122   
     123    unsigned fiberCount = 0;
     124    unsigned substringFiberCount = 0;
     125    unsigned substringEnd = substringStart + substringLength;
     126    unsigned fiberEnd = 0;
     127
     128    RopeIterator end;
     129    for (RopeIterator it(m_other.m_fibers.data(), m_fiberCount); it != end; ++it) {
     130        ++fiberCount;
     131        StringImpl* fiberString = *it;
     132        unsigned fiberStart = fiberEnd;
     133        fiberEnd = fiberStart + fiberString->length();
     134        if (fiberEnd <= substringStart)
     135            continue;
     136        unsigned copyStart = std::max(substringStart, fiberStart);
     137        unsigned copyEnd = std::min(substringEnd, fiberEnd);
     138        if (copyStart == fiberStart && copyEnd == fiberEnd)
     139            substringFibers[substringFiberCount++] = UString(fiberString);
     140        else
     141            substringFibers[substringFiberCount++] = UString(StringImpl::create(fiberString, copyStart - fiberStart, copyEnd - copyStart));
     142        if (fiberEnd >= substringEnd)
     143            break;
     144        if (fiberCount > substringFromRopeCutoff || substringFiberCount >= 3) {
     145            // This turned out to be a really inefficient rope. Just flatten it.
     146            resolveRope(exec);
     147            return jsSubstring(&exec->globalData(), m_value, substringStart, substringLength);
     148        }
     149    }
     150    ASSERT(substringFiberCount && substringFiberCount <= 3);
     151
     152    if (substringLength == 1) {
     153        ASSERT(substringFiberCount == 1);
     154        UChar c = substringFibers[0].characters()[0];
     155        if (c <= 0xFF)
     156            return globalData->smallStrings.singleCharacterString(globalData, c);
     157    }
     158    if (substringFiberCount == 1)
     159        return new (globalData) JSString(globalData, substringFibers[0]);
     160    if (substringFiberCount == 2)
     161        return new (globalData) JSString(globalData, substringFibers[0], substringFibers[1]);
     162    return new (globalData) JSString(globalData, substringFibers[0], substringFibers[1], substringFibers[2]);
     163}
    108164
    109165JSValue JSString::replaceCharacter(ExecState* exec, UChar character, const UString& replacement)
  • trunk/JavaScriptCore/runtime/JSString.h

    r71375 r73433  
    357357
    358358        void resolveRope(ExecState*) const;
     359        JSString* substringFromRope(ExecState*, unsigned offset, unsigned length);
    359360
    360361        void appendStringInConstruct(unsigned& index, const UString& string)
     
    436437        friend JSValue jsString(ExecState* exec, JSValue thisValue);
    437438        friend JSString* jsStringWithFinalizer(ExecState*, const UString&, JSStringFinalizerCallback callback, void* context);
     439        friend JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length);
    438440    };
    439441
     
    519521        JSGlobalData* globalData = &exec->globalData();
    520522        return fixupVPtr(globalData, new (globalData) JSString(globalData, s, callback, context));
     523    }
     524   
     525    inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length)
     526    {
     527        ASSERT(offset <= static_cast<unsigned>(s->length()));
     528        ASSERT(length <= static_cast<unsigned>(s->length()));
     529        ASSERT(offset + length <= static_cast<unsigned>(s->length()));
     530        JSGlobalData* globalData = &exec->globalData();
     531        if (!length)
     532            return globalData->smallStrings.emptyString(globalData);
     533        if (s->isRope())
     534            return s->substringFromRope(exec, offset, length);
     535        return jsSubstring(globalData, s->m_value, offset, length);
    521536    }
    522537
  • trunk/JavaScriptCore/runtime/StringPrototype.cpp

    r70703 r73433  
    773773    if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
    774774        return throwVMTypeError(exec);
    775     UString s = thisValue.toThisString(exec);
    776     int len = s.length();
     775    unsigned len;
     776    JSString* jsString = 0;
     777    UString uString;
     778    if (thisValue.isString()) {
     779        jsString = static_cast<JSString*>(thisValue.asCell());
     780        len = jsString->length();
     781    } else {
     782        uString = thisValue.toThisObject(exec)->toString(exec);
     783        len = uString.length();
     784    }
    777785
    778786    JSValue a0 = exec->argument(0);
     
    790798    if (start + length > len)
    791799        length = len - start;
    792     return JSValue::encode(jsSubstring(exec, s, static_cast<unsigned>(start), static_cast<unsigned>(length)));
     800    unsigned substringStart = static_cast<unsigned>(start);
     801    unsigned substringLength = static_cast<unsigned>(length);
     802    if (jsString)
     803        return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
     804    return JSValue::encode(jsSubstring(exec, uString, substringStart, substringLength));
    793805}
    794806
     
    798810    if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
    799811        return throwVMTypeError(exec);
    800     UString s = thisValue.toThisString(exec);
    801     int len = s.length();
     812    int len;
     813    JSString* jsString = 0;
     814    UString uString;
     815    if (thisValue.isString()) {
     816        jsString = static_cast<JSString*>(thisValue.asCell());
     817        len = jsString->length();
     818    } else {
     819        uString = thisValue.toThisObject(exec)->toString(exec);
     820        len = uString.length();
     821    }
    802822
    803823    JSValue a0 = exec->argument(0);
     
    824844        start = temp;
    825845    }
    826     return JSValue::encode(jsSubstring(exec, s, static_cast<unsigned>(start), static_cast<unsigned>(end) - static_cast<unsigned>(start)));
     846    unsigned substringStart = static_cast<unsigned>(start);
     847    unsigned substringLength = static_cast<unsigned>(end) - substringStart;
     848    if (jsString)
     849        return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
     850    return JSValue::encode(jsSubstring(exec, uString, substringStart, substringLength));
    827851}
    828852
Note: See TracChangeset for help on using the changeset viewer.