[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-10851-g50815da

antti at apple.com antti at apple.com
Wed Dec 22 18:06:44 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 6261f1f0ee860da14711942ac1b029aeac3b1a03
Author: antti at apple.com <antti at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Tue Dec 7 11:11:08 2010 +0000

    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):
    
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@73433 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog
index fbdc41a..146797f 100644
--- a/JavaScriptCore/ChangeLog
+++ b/JavaScriptCore/ChangeLog
@@ -1,3 +1,26 @@
+2010-12-07  Antti Koivisto  <antti at apple.com>
+
+        Reviewed by Gavin Barraclough.
+
+        https://bugs.webkit.org/show_bug.cgi?id=50412
+        http://www.wunderground.com/US/CA/Hayward.html causes big memory spike during page loading 
+        
+        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):
+
 2010-12-06  Geoffrey Garen  <ggaren at apple.com>
 
         Reviewed by Gavin Barraclough.
diff --git a/JavaScriptCore/runtime/JSString.cpp b/JavaScriptCore/runtime/JSString.cpp
index 340a898..ba28139 100644
--- a/JavaScriptCore/runtime/JSString.cpp
+++ b/JavaScriptCore/runtime/JSString.cpp
@@ -31,6 +31,8 @@
 #include "StringPrototype.h"
 
 namespace JSC {
+    
+static const unsigned substringFromRopeCutoff = 4;
 
 // 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
@@ -105,6 +107,60 @@ void JSString::resolveRope(ExecState* exec) const
         }
     }
 }
+    
+// This function construsts a substring out of a rope without flattening by reusing the existing fibers.
+// This can reduce memory usage substantially. Since traversing ropes is slow the function will revert 
+// back to flattening if the rope turns out to be long.
+JSString* JSString::substringFromRope(ExecState* exec, unsigned substringStart, unsigned substringLength)
+{
+    ASSERT(isRope());
+    ASSERT(substringLength);
+    
+    JSGlobalData* globalData = &exec->globalData();
+
+    UString substringFibers[3];
+    
+    unsigned fiberCount = 0;
+    unsigned substringFiberCount = 0;
+    unsigned substringEnd = substringStart + substringLength;
+    unsigned fiberEnd = 0;
+
+    RopeIterator end;
+    for (RopeIterator it(m_other.m_fibers.data(), m_fiberCount); it != end; ++it) {
+        ++fiberCount;
+        StringImpl* fiberString = *it;
+        unsigned fiberStart = fiberEnd;
+        fiberEnd = fiberStart + fiberString->length();
+        if (fiberEnd <= substringStart)
+            continue;
+        unsigned copyStart = std::max(substringStart, fiberStart);
+        unsigned copyEnd = std::min(substringEnd, fiberEnd);
+        if (copyStart == fiberStart && copyEnd == fiberEnd)
+            substringFibers[substringFiberCount++] = UString(fiberString);
+        else
+            substringFibers[substringFiberCount++] = UString(StringImpl::create(fiberString, copyStart - fiberStart, copyEnd - copyStart));
+        if (fiberEnd >= substringEnd)
+            break;
+        if (fiberCount > substringFromRopeCutoff || substringFiberCount >= 3) {
+            // This turned out to be a really inefficient rope. Just flatten it.
+            resolveRope(exec);
+            return jsSubstring(&exec->globalData(), m_value, substringStart, substringLength);
+        }
+    }
+    ASSERT(substringFiberCount && substringFiberCount <= 3);
+
+    if (substringLength == 1) {
+        ASSERT(substringFiberCount == 1);
+        UChar c = substringFibers[0].characters()[0];
+        if (c <= 0xFF)
+            return globalData->smallStrings.singleCharacterString(globalData, c);
+    }
+    if (substringFiberCount == 1)
+        return new (globalData) JSString(globalData, substringFibers[0]);
+    if (substringFiberCount == 2)
+        return new (globalData) JSString(globalData, substringFibers[0], substringFibers[1]);
+    return new (globalData) JSString(globalData, substringFibers[0], substringFibers[1], substringFibers[2]);
+}
 
 JSValue JSString::replaceCharacter(ExecState* exec, UChar character, const UString& replacement)
 {
diff --git a/JavaScriptCore/runtime/JSString.h b/JavaScriptCore/runtime/JSString.h
index 51b9f2d..fefffde 100644
--- a/JavaScriptCore/runtime/JSString.h
+++ b/JavaScriptCore/runtime/JSString.h
@@ -356,6 +356,7 @@ namespace JSC {
         }
 
         void resolveRope(ExecState*) const;
+        JSString* substringFromRope(ExecState*, unsigned offset, unsigned length);
 
         void appendStringInConstruct(unsigned& index, const UString& string)
         {
@@ -435,6 +436,7 @@ namespace JSC {
         friend JSValue jsString(ExecState* exec, Register* strings, unsigned count);
         friend JSValue jsString(ExecState* exec, JSValue thisValue);
         friend JSString* jsStringWithFinalizer(ExecState*, const UString&, JSStringFinalizerCallback callback, void* context);
+        friend JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length);
     };
 
     JSString* asString(JSValue);
@@ -519,6 +521,19 @@ namespace JSC {
         JSGlobalData* globalData = &exec->globalData();
         return fixupVPtr(globalData, new (globalData) JSString(globalData, s, callback, context));
     }
+    
+    inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length)
+    {
+        ASSERT(offset <= static_cast<unsigned>(s->length()));
+        ASSERT(length <= static_cast<unsigned>(s->length()));
+        ASSERT(offset + length <= static_cast<unsigned>(s->length()));
+        JSGlobalData* globalData = &exec->globalData();
+        if (!length)
+            return globalData->smallStrings.emptyString(globalData);
+        if (s->isRope())
+            return s->substringFromRope(exec, offset, length);
+        return jsSubstring(globalData, s->m_value, offset, length);
+    }
 
     inline JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length)
     {
diff --git a/JavaScriptCore/runtime/StringPrototype.cpp b/JavaScriptCore/runtime/StringPrototype.cpp
index b5ea8fa..8b3d056 100644
--- a/JavaScriptCore/runtime/StringPrototype.cpp
+++ b/JavaScriptCore/runtime/StringPrototype.cpp
@@ -772,8 +772,16 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec)
     JSValue thisValue = exec->hostThisValue();
     if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
         return throwVMTypeError(exec);
-    UString s = thisValue.toThisString(exec);
-    int len = s.length();
+    unsigned len;
+    JSString* jsString = 0;
+    UString uString;
+    if (thisValue.isString()) {
+        jsString = static_cast<JSString*>(thisValue.asCell());
+        len = jsString->length();
+    } else {
+        uString = thisValue.toThisObject(exec)->toString(exec);
+        len = uString.length();
+    }
 
     JSValue a0 = exec->argument(0);
     JSValue a1 = exec->argument(1);
@@ -789,7 +797,11 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec)
     }
     if (start + length > len)
         length = len - start;
-    return JSValue::encode(jsSubstring(exec, s, static_cast<unsigned>(start), static_cast<unsigned>(length)));
+    unsigned substringStart = static_cast<unsigned>(start);
+    unsigned substringLength = static_cast<unsigned>(length);
+    if (jsString)
+        return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
+    return JSValue::encode(jsSubstring(exec, uString, substringStart, substringLength));
 }
 
 EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec)
@@ -797,8 +809,16 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec)
     JSValue thisValue = exec->hostThisValue();
     if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
         return throwVMTypeError(exec);
-    UString s = thisValue.toThisString(exec);
-    int len = s.length();
+    int len;
+    JSString* jsString = 0;
+    UString uString;
+    if (thisValue.isString()) {
+        jsString = static_cast<JSString*>(thisValue.asCell());
+        len = jsString->length();
+    } else {
+        uString = thisValue.toThisObject(exec)->toString(exec);
+        len = uString.length();
+    }
 
     JSValue a0 = exec->argument(0);
     JSValue a1 = exec->argument(1);
@@ -823,7 +843,11 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec)
         end = start;
         start = temp;
     }
-    return JSValue::encode(jsSubstring(exec, s, static_cast<unsigned>(start), static_cast<unsigned>(end) - static_cast<unsigned>(start)));
+    unsigned substringStart = static_cast<unsigned>(start);
+    unsigned substringLength = static_cast<unsigned>(end) - substringStart;
+    if (jsString)
+        return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
+    return JSValue::encode(jsSubstring(exec, uString, substringStart, substringLength));
 }
 
 EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec)

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list