Memory wasted in JSString for non-rope strings
https://bugs.webkit.org/show_bug.cgi?id=84907
Reviewed by Geoffrey Garen.
Split JSString into two classes, JSString as a base class that does not
include the fibers of a Rope, and a subclass JSRopeString that has the
rope functionality. Both classes "share" the same ClassInfo. Added
a bool to JSString to indicate that the string was allocated as a JSRopeString
to properly handle visiting the fiber children when the rope is resolved and
the JSRopeString appears as a JSString. Didn't change the interface of JSString
to require any JIT changes.
As part of this change, removed "cellSize" from ClassInfo since both classes
share the same ClassInfo, but have different sizes. The only use I could find
for cellSize was an ASSERT in allocateCell().
This appears to be neutral on performance tests.
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: Changed JSString::resolveRope
to JSRopeString::resolveRope
* runtime/ClassInfo.h:
(JSC):
(ClassInfo):
* runtime/JSCell.h:
(JSC::allocateCell):
* runtime/JSString.cpp:
(JSC::JSRopeString::RopeBuilder::expand):
(JSC::JSString::visitChildren):
(JSC):
(JSC::JSRopeString::visitFibers):
(JSC::JSRopeString::resolveRope):
(JSC::JSRopeString::resolveRopeSlowCase8):
(JSC::JSRopeString::resolveRopeSlowCase):
(JSC::JSRopeString::outOfMemory):
(JSC::JSRopeString::getIndexSlowCase):
* runtime/JSString.h:
(JSC):
(JSString):
(JSC::JSString::finishCreation):
(JSC::JSString::create):
(JSC::JSString::isRope):
(JSC::JSString::is8Bit):
(JSRopeString):
(RopeBuilder):
(JSC::JSRopeString::RopeBuilder::RopeBuilder):
(JSC::JSRopeString::RopeBuilder::append):
(JSC::JSRopeString::RopeBuilder::release):
(JSC::JSRopeString::RopeBuilder::length):
(JSC::JSRopeString::JSRopeString):
(JSC::JSRopeString::finishCreation):
(JSC::JSRopeString::createNull):
(JSC::JSRopeString::create):
(JSC::JSString::value):
(JSC::JSString::tryGetValue):
(JSC::JSString::getIndex):
(JSC::jsStringBuilder):
* runtime/Operations.h:
(JSC::jsString):
(JSC::jsStringFromArguments):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@115516 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/runtime/JSString.cpp b/Source/JavaScriptCore/runtime/JSString.cpp
index e84ce36..904cc4d 100644
--- a/Source/JavaScriptCore/runtime/JSString.cpp
+++ b/Source/JavaScriptCore/runtime/JSString.cpp
@@ -36,9 +36,9 @@
const ClassInfo JSString::s_info = { "string", 0, 0, 0, CREATE_METHOD_TABLE(JSString) };
-void JSString::RopeBuilder::expand()
+void JSRopeString::RopeBuilder::expand()
{
- ASSERT(m_index == JSString::s_maxInternalRopeLength);
+ ASSERT(m_index == JSRopeString::s_maxInternalRopeLength);
JSString* jsString = m_jsString;
m_jsString = jsStringBuilder(&m_globalData);
m_index = 0;
@@ -55,11 +55,18 @@
{
JSString* thisObject = jsCast<JSString*>(cell);
Base::visitChildren(thisObject, visitor);
- for (size_t i = 0; i < s_maxInternalRopeLength && thisObject->m_fibers[i]; ++i)
- visitor.append(&thisObject->m_fibers[i]);
+
+ if (thisObject->isRope())
+ static_cast<JSRopeString*>(thisObject)->visitFibers(visitor);
}
-void JSString::resolveRope(ExecState* exec) const
+void JSRopeString::visitFibers(SlotVisitor& visitor)
+{
+ for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i)
+ visitor.append(&m_fibers[i]);
+}
+
+void JSRopeString::resolveRope(ExecState* exec) const
{
ASSERT(isRope());
@@ -128,7 +135,7 @@
// Vector before performing any concatenation, but by working backwards we likely
// only fill the queue with the number of substrings at any given level in a
// rope-of-ropes.)
-void JSString::resolveRopeSlowCase8(LChar* buffer) const
+void JSRopeString::resolveRopeSlowCase8(LChar* buffer) const
{
LChar* position = buffer + m_length; // We will be working backwards over the rope.
Vector<JSString*, 32> workQueue; // Putting strings into a Vector is only OK because there are no GC points in this method.
@@ -144,8 +151,9 @@
workQueue.removeLast();
if (currentFiber->isRope()) {
- for (size_t i = 0; i < s_maxInternalRopeLength && currentFiber->m_fibers[i]; ++i)
- workQueue.append(currentFiber->m_fibers[i].get());
+ JSRopeString* currentFiberAsRope = static_cast<JSRopeString*>(currentFiber);
+ for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->m_fibers[i]; ++i)
+ workQueue.append(currentFiberAsRope->m_fibers[i].get());
continue;
}
@@ -159,7 +167,7 @@
ASSERT(!isRope());
}
-void JSString::resolveRopeSlowCase(UChar* buffer) const
+void JSRopeString::resolveRopeSlowCase(UChar* buffer) const
{
UChar* position = buffer + m_length; // We will be working backwards over the rope.
Vector<JSString*, 32> workQueue; // These strings are kept alive by the parent rope, so using a Vector is OK.
@@ -172,8 +180,9 @@
workQueue.removeLast();
if (currentFiber->isRope()) {
- for (size_t i = 0; i < s_maxInternalRopeLength && currentFiber->m_fibers[i]; ++i)
- workQueue.append(currentFiber->m_fibers[i].get());
+ JSRopeString* currentFiberAsRope = static_cast<JSRopeString*>(currentFiber);
+ for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->m_fibers[i]; ++i)
+ workQueue.append(currentFiberAsRope->m_fibers[i].get());
continue;
}
@@ -187,7 +196,7 @@
ASSERT(!isRope());
}
-void JSString::outOfMemory(ExecState* exec) const
+void JSRopeString::outOfMemory(ExecState* exec) const
{
for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i)
m_fibers[i].clear();
@@ -197,7 +206,7 @@
throwOutOfMemoryError(exec);
}
-JSString* JSString::getIndexSlowCase(ExecState* exec, unsigned i)
+JSString* JSRopeString::getIndexSlowCase(ExecState* exec, unsigned i)
{
ASSERT(isRope());
resolveRope(exec);