Changeset 184346 in webkit


Ignore:
Timestamp:
May 14, 2015 12:07:30 PM (9 years ago)
Author:
akling@apple.com
Message:

String.prototype.split() should create efficient substrings.
<https://webkit.org/b/144985>
<rdar://problem/20949344>

Reviewed by Geoffrey Garen.

Teach split() how to make substring JSStrings instead of relying on StringImpl's
substring sharing mechanism. The optimization works by deferring the construction
of a StringImpl until the substring's value is actually needed.

This knocks ~2MB off of theverge.com by avoiding the extra StringImpl allocations.
Out of ~70000 substrings created by split(), only ~2000 of them get reified.

  • runtime/StringPrototype.cpp:

(JSC::jsSubstring):
(JSC::splitStringByOneCharacterImpl):
(JSC::stringProtoFuncSplit):

Location:
trunk/Source/JavaScriptCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r184344 r184346  
     12015-05-14  Andreas Kling  <akling@apple.com>
     2
     3        String.prototype.split() should create efficient substrings.
     4        <https://webkit.org/b/144985>
     5        <rdar://problem/20949344>
     6
     7        Reviewed by Geoffrey Garen.
     8
     9        Teach split() how to make substring JSStrings instead of relying on StringImpl's
     10        substring sharing mechanism. The optimization works by deferring the construction
     11        of a StringImpl until the substring's value is actually needed.
     12
     13        This knocks ~2MB off of theverge.com by avoiding the extra StringImpl allocations.
     14        Out of ~70000 substrings created by split(), only ~2000 of them get reified.
     15
     16        * runtime/StringPrototype.cpp:
     17        (JSC::jsSubstring):
     18        (JSC::splitStringByOneCharacterImpl):
     19        (JSC::stringProtoFuncSplit):
     20
    1212015-05-14  Yusuke Suzuki  <utatane.tea@gmail.com>
    222
  • trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp

    r183694 r184346  
    176176}
    177177
     178// Helper that tries to use the JSString substring sharing mechanism if 'originalValue' is a JSString.
     179static inline JSString* jsSubstring(ExecState* exec, JSValue originalValue, const String& string, unsigned offset, unsigned length)
     180{
     181    if (originalValue.isString()) {
     182        ASSERT(asString(originalValue)->value(exec) == string);
     183        return jsSubstring(exec, asString(originalValue), offset, length);
     184    }
     185    return jsSubstring(exec, string, offset, length);
     186}
     187
    178188static NEVER_INLINE String substituteBackreferencesSlow(StringView replacement, StringView source, const int* ovector, RegExp* reg, size_t i)
    179189{
     
    10541064// Return true in case of early return (resultLength got to limitLength).
    10551065template<typename CharacterType>
    1056 static ALWAYS_INLINE bool splitStringByOneCharacterImpl(ExecState* exec, JSArray* result, const String& input, StringImpl* string, UChar separatorCharacter, size_t& position, unsigned& resultLength, unsigned limitLength)
     1066static ALWAYS_INLINE bool splitStringByOneCharacterImpl(ExecState* exec, JSArray* result, JSValue originalValue, const String& input, StringImpl* string, UChar separatorCharacter, size_t& position, unsigned& resultLength, unsigned limitLength)
    10571067{
    10581068    // 12. Let q = p.
     
    10681078        // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
    10691079        //    Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
    1070         result->putDirectIndex(exec, resultLength, jsSubstring(exec, input, position, matchPosition - position));
     1080        result->putDirectIndex(exec, resultLength, jsSubstring(exec, originalValue, input, position, matchPosition - position));
    10711081        // 3. Increment lengthA by 1.
    10721082        // 4. If lengthA == lim, return A.
     
    11741184            // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
    11751185            //    Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
    1176             result->putDirectIndex(exec, resultLength, jsSubstring(exec, input, position, matchPosition - position));
     1186            result->putDirectIndex(exec, resultLength, jsSubstring(exec, thisValue, input, position, matchPosition - position));
    11771187
    11781188            // 3. Increment lengthA by 1.
     
    11941204                //   true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
    11951205                int sub = ovector[i * 2];
    1196                 result->putDirectIndex(exec, resultLength, sub < 0 ? jsUndefined() : jsSubstring(exec, input, sub, ovector[i * 2 + 1] - sub));
     1206                result->putDirectIndex(exec, resultLength, sub < 0 ? jsUndefined() : jsSubstring(exec, thisValue, input, sub, ovector[i * 2 + 1] - sub));
    11971207                // c Increment lengthA by 1.
    11981208                // d If lengthA == lim, return A.
     
    12591269
    12601270            if (stringImpl->is8Bit()) {
    1261                 if (splitStringByOneCharacterImpl<LChar>(exec, result, input, stringImpl, separatorCharacter, position, resultLength, limit))
     1271                if (splitStringByOneCharacterImpl<LChar>(exec, result, thisValue, input, stringImpl, separatorCharacter, position, resultLength, limit))
    12621272                    return JSValue::encode(result);
    12631273            } else {
    1264                 if (splitStringByOneCharacterImpl<UChar>(exec, result, input, stringImpl, separatorCharacter, position, resultLength, limit))
     1274                if (splitStringByOneCharacterImpl<UChar>(exec, result, thisValue, input, stringImpl, separatorCharacter, position, resultLength, limit))
    12651275                    return JSValue::encode(result);
    12661276            }
     
    12771287                // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
    12781288                //    Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
    1279                 result->putDirectIndex(exec, resultLength, jsSubstring(exec, input, position, matchPosition - position));
     1289                result->putDirectIndex(exec, resultLength, jsSubstring(exec, thisValue, input, position, matchPosition - position));
    12801290                // 3. Increment lengthA by 1.
    12811291                // 4. If lengthA == lim, return A.
     
    12941304    // 15. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA), Property Descriptor
    12951305    //     {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
    1296     result->putDirectIndex(exec, resultLength++, jsSubstring(exec, input, position, input.length() - position));
     1306    result->putDirectIndex(exec, resultLength++, jsSubstring(exec, thisValue, input, position, input.length() - position));
    12971307
    12981308    // 16. Return A.
Note: See TracChangeset for help on using the changeset viewer.