[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