Title: [184346] trunk/Source/_javascript_Core
Revision
184346
Author
akl...@apple.com
Date
2015-05-14 12:07:30 -0700 (Thu, 14 May 2015)

Log 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):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (184345 => 184346)


--- trunk/Source/_javascript_Core/ChangeLog	2015-05-14 18:17:39 UTC (rev 184345)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-05-14 19:07:30 UTC (rev 184346)
@@ -1,3 +1,23 @@
+2015-05-14  Andreas Kling  <akl...@apple.com>
+
+        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):
+
 2015-05-14  Yusuke Suzuki  <utatane....@gmail.com>
 
         Change the status of ES6 tagged templates to Done in features.json

Modified: trunk/Source/_javascript_Core/runtime/StringPrototype.cpp (184345 => 184346)


--- trunk/Source/_javascript_Core/runtime/StringPrototype.cpp	2015-05-14 18:17:39 UTC (rev 184345)
+++ trunk/Source/_javascript_Core/runtime/StringPrototype.cpp	2015-05-14 19:07:30 UTC (rev 184346)
@@ -175,6 +175,16 @@
     return jsString(exec, string);
 }
 
+// Helper that tries to use the JSString substring sharing mechanism if 'originalValue' is a JSString.
+static inline JSString* jsSubstring(ExecState* exec, JSValue originalValue, const String& string, unsigned offset, unsigned length)
+{
+    if (originalValue.isString()) {
+        ASSERT(asString(originalValue)->value(exec) == string);
+        return jsSubstring(exec, asString(originalValue), offset, length);
+    }
+    return jsSubstring(exec, string, offset, length);
+}
+
 static NEVER_INLINE String substituteBackreferencesSlow(StringView replacement, StringView source, const int* ovector, RegExp* reg, size_t i)
 {
     StringBuilder substitutedReplacement;
@@ -1053,7 +1063,7 @@
 
 // Return true in case of early return (resultLength got to limitLength).
 template<typename CharacterType>
-static ALWAYS_INLINE bool splitStringByOneCharacterImpl(ExecState* exec, JSArray* result, const String& input, StringImpl* string, UChar separatorCharacter, size_t& position, unsigned& resultLength, unsigned limitLength)
+static ALWAYS_INLINE bool splitStringByOneCharacterImpl(ExecState* exec, JSArray* result, JSValue originalValue, const String& input, StringImpl* string, UChar separatorCharacter, size_t& position, unsigned& resultLength, unsigned limitLength)
 {
     // 12. Let q = p.
     size_t matchPosition;
@@ -1067,7 +1077,7 @@
         //    through q (exclusive).
         // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
         //    Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
-        result->putDirectIndex(exec, resultLength, jsSubstring(exec, input, position, matchPosition - position));
+        result->putDirectIndex(exec, resultLength, jsSubstring(exec, originalValue, input, position, matchPosition - position));
         // 3. Increment lengthA by 1.
         // 4. If lengthA == lim, return A.
         if (++resultLength == limitLength)
@@ -1173,7 +1183,7 @@
             //    through q (exclusive).
             // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
             //    Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
-            result->putDirectIndex(exec, resultLength, jsSubstring(exec, input, position, matchPosition - position));
+            result->putDirectIndex(exec, resultLength, jsSubstring(exec, thisValue, input, position, matchPosition - position));
 
             // 3. Increment lengthA by 1.
             // 4. If lengthA == lim, return A.
@@ -1193,7 +1203,7 @@
                 //   ToString(lengthA), Property Descriptor {[[Value]]: cap[i], [[Writable]]:
                 //   true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
                 int sub = ovector[i * 2];
-                result->putDirectIndex(exec, resultLength, sub < 0 ? jsUndefined() : jsSubstring(exec, input, sub, ovector[i * 2 + 1] - sub));
+                result->putDirectIndex(exec, resultLength, sub < 0 ? jsUndefined() : jsSubstring(exec, thisValue, input, sub, ovector[i * 2 + 1] - sub));
                 // c Increment lengthA by 1.
                 // d If lengthA == lim, return A.
                 if (++resultLength == limit)
@@ -1258,10 +1268,10 @@
                 separatorCharacter = separatorImpl->characters16()[0];
 
             if (stringImpl->is8Bit()) {
-                if (splitStringByOneCharacterImpl<LChar>(exec, result, input, stringImpl, separatorCharacter, position, resultLength, limit))
+                if (splitStringByOneCharacterImpl<LChar>(exec, result, thisValue, input, stringImpl, separatorCharacter, position, resultLength, limit))
                     return JSValue::encode(result);
             } else {
-                if (splitStringByOneCharacterImpl<UChar>(exec, result, input, stringImpl, separatorCharacter, position, resultLength, limit))
+                if (splitStringByOneCharacterImpl<UChar>(exec, result, thisValue, input, stringImpl, separatorCharacter, position, resultLength, limit))
                     return JSValue::encode(result);
             }
         } else {
@@ -1276,7 +1286,7 @@
                 //    through q (exclusive).
                 // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
                 //    Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
-                result->putDirectIndex(exec, resultLength, jsSubstring(exec, input, position, matchPosition - position));
+                result->putDirectIndex(exec, resultLength, jsSubstring(exec, thisValue, input, position, matchPosition - position));
                 // 3. Increment lengthA by 1.
                 // 4. If lengthA == lim, return A.
                 if (++resultLength == limit)
@@ -1293,7 +1303,7 @@
     //     through s (exclusive).
     // 15. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA), Property Descriptor
     //     {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
-    result->putDirectIndex(exec, resultLength++, jsSubstring(exec, input, position, input.length() - position));
+    result->putDirectIndex(exec, resultLength++, jsSubstring(exec, thisValue, input, position, input.length() - position));
 
     // 16. Return A.
     return JSValue::encode(result);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to