Modified: trunk/Source/_javascript_Core/runtime/JSString.cpp (115515 => 115516)
--- trunk/Source/_javascript_Core/runtime/JSString.cpp 2012-04-27 23:48:57 UTC (rev 115515)
+++ trunk/Source/_javascript_Core/runtime/JSString.cpp 2012-04-27 23:51:17 UTC (rev 115516)
@@ -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,12 +55,19 @@
{
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());
if (is8Bit()) {
@@ -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);
Modified: trunk/Source/_javascript_Core/runtime/JSString.h (115515 => 115516)
--- trunk/Source/_javascript_Core/runtime/JSString.h 2012-04-27 23:48:57 UTC (rev 115515)
+++ trunk/Source/_javascript_Core/runtime/JSString.h 2012-04-27 23:51:17 UTC (rev 115516)
@@ -32,6 +32,7 @@
namespace JSC {
class JSString;
+ class JSRopeString;
class LLIntOffsetsExtractor;
JSString* jsEmptyString(JSGlobalData*);
@@ -58,55 +59,20 @@
JSString* jsOwnedString(JSGlobalData*, const UString&);
JSString* jsOwnedString(ExecState*, const UString&);
- JSString* jsStringBuilder(JSGlobalData*);
+ JSRopeString* jsStringBuilder(JSGlobalData*);
class JSString : public JSCell {
public:
friend class JIT;
friend class JSGlobalData;
friend class SpecializedThunkJIT;
+ friend class JSRopeString;
friend struct ThunkHelpers;
- friend JSString* jsStringBuilder(JSGlobalData*);
typedef JSCell Base;
static void destroy(JSCell*);
- class RopeBuilder {
- public:
- RopeBuilder(JSGlobalData& globalData)
- : m_globalData(globalData)
- , m_jsString(jsStringBuilder(&globalData))
- , m_index(0)
- {
- }
-
- void append(JSString* jsString)
- {
- if (m_index == JSString::s_maxInternalRopeLength)
- expand();
- m_jsString->m_fibers[m_index++].set(m_globalData, m_jsString, jsString);
- m_jsString->m_length += jsString->m_length;
- m_jsString->m_is8Bit = m_jsString->m_is8Bit && jsString->m_is8Bit;
- }
-
- JSString* release()
- {
- JSString* tmp = m_jsString;
- m_jsString = 0;
- return tmp;
- }
-
- unsigned length() { return m_jsString->m_length; }
-
- private:
- void expand();
-
- JSGlobalData& m_globalData;
- JSString* m_jsString;
- size_t m_index;
- };
-
private:
JSString(JSGlobalData& globalData, PassRefPtr<StringImpl> value)
: JSCell(globalData, globalData.stringStructure.get())
@@ -119,13 +85,6 @@
{
}
- void finishCreation(JSGlobalData& globalData)
- {
- Base::finishCreation(globalData);
- m_length = 0;
- m_is8Bit = true;
- }
-
void finishCreation(JSGlobalData& globalData, size_t length)
{
ASSERT(!m_value.isNull());
@@ -143,32 +102,14 @@
Heap::heap(this)->reportExtraMemoryCost(cost);
}
- void finishCreation(JSGlobalData& globalData, JSString* s1, JSString* s2)
+ protected:
+ void finishCreation(JSGlobalData& globalData)
{
Base::finishCreation(globalData);
- m_length = s1->length() + s2->length();
- m_is8Bit = (s1->is8Bit() && s2->is8Bit());
- m_fibers[0].set(globalData, this, s1);
- m_fibers[1].set(globalData, this, s2);
+ m_length = 0;
+ m_is8Bit = true;
}
-
- void finishCreation(JSGlobalData& globalData, JSString* s1, JSString* s2, JSString* s3)
- {
- Base::finishCreation(globalData);
- m_length = s1->length() + s2->length() + s3->length();
- m_is8Bit = (s1->is8Bit() && s2->is8Bit() && s3->is8Bit());
- m_fibers[0].set(globalData, this, s1);
- m_fibers[1].set(globalData, this, s2);
- m_fibers[2].set(globalData, this, s3);
- }
-
- static JSString* createNull(JSGlobalData& globalData)
- {
- JSString* newString = new (NotNull, allocateCell<JSString>(globalData.heap)) JSString(globalData);
- newString->finishCreation(globalData);
- return newString;
- }
-
+
public:
static JSString* create(JSGlobalData& globalData, PassRefPtr<StringImpl> value)
{
@@ -179,18 +120,6 @@
newString->finishCreation(globalData, length, cost);
return newString;
}
- static JSString* create(JSGlobalData& globalData, JSString* s1, JSString* s2)
- {
- JSString* newString = new (NotNull, allocateCell<JSString>(globalData.heap)) JSString(globalData);
- newString->finishCreation(globalData, s1, s2);
- return newString;
- }
- static JSString* create(JSGlobalData& globalData, JSString* s1, JSString* s2, JSString* s3)
- {
- JSString* newString = new (NotNull, allocateCell<JSString>(globalData.heap)) JSString(globalData);
- newString->finishCreation(globalData, s1, s2, s3);
- return newString;
- }
static JSString* createHasOtherOwner(JSGlobalData& globalData, PassRefPtr<StringImpl> value)
{
ASSERT(value);
@@ -200,18 +129,8 @@
return newString;
}
- const UString& value(ExecState* exec) const
- {
- if (isRope())
- resolveRope(exec);
- return m_value;
- }
- const UString& tryGetValue() const
- {
- if (isRope())
- resolveRope(0);
- return m_value;
- }
+ const UString& value(ExecState*) const;
+ const UString& tryGetValue() const;
unsigned length() { return m_length; }
JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
@@ -226,7 +145,6 @@
bool canGetIndex(unsigned i) { return i < m_length; }
JSString* getIndex(ExecState*, unsigned);
- JSString* getIndexSlowCase(ExecState*, unsigned);
static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
{
@@ -240,38 +158,139 @@
static void visitChildren(JSCell*, SlotVisitor&);
+ protected:
+ bool isRope() const { return m_value.isNull(); }
+ bool is8Bit() const { return m_is8Bit; }
+
+ // A string is represented either by a UString or a rope of fibers.
+ bool m_is8Bit : 1;
+ unsigned m_length;
+ mutable UString m_value;
+
private:
friend class LLIntOffsetsExtractor;
- JS_EXPORT_PRIVATE void resolveRope(ExecState*) const;
- void resolveRopeSlowCase8(LChar*) const;
- void resolveRopeSlowCase(UChar*) const;
- void outOfMemory(ExecState*) const;
-
static JSObject* toThisObject(JSCell*, ExecState*);
// Actually getPropertySlot, not getOwnPropertySlot (see JSCell).
static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&);
static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
- static const unsigned s_maxInternalRopeLength = 3;
-
- // A string is represented either by a UString or a rope of fibers.
- bool m_is8Bit : 1;
- unsigned m_length;
- mutable UString m_value;
- mutable FixedArray<WriteBarrier<JSString>, s_maxInternalRopeLength> m_fibers;
-
- bool isRope() const { return m_value.isNull(); }
- bool is8Bit() const { return m_is8Bit; }
UString& string() { ASSERT(!isRope()); return m_value; }
friend JSValue jsString(ExecState*, JSString*, JSString*);
- friend JSValue jsString(ExecState*, Register*, unsigned count);
- friend JSValue jsStringFromArguments(ExecState*, JSValue thisValue);
friend JSString* jsSubstring(ExecState*, JSString*, unsigned offset, unsigned length);
};
+ class JSRopeString : public JSString {
+ friend class JSString;
+
+ friend JSRopeString* jsStringBuilder(JSGlobalData*);
+
+ class RopeBuilder {
+ public:
+ RopeBuilder(JSGlobalData& globalData)
+ : m_globalData(globalData)
+ , m_jsString(jsStringBuilder(&globalData))
+ , m_index(0)
+ {
+ }
+
+ void append(JSString* jsString)
+ {
+ if (m_index == JSRopeString::s_maxInternalRopeLength)
+ expand();
+ m_jsString->m_fibers[m_index++].set(m_globalData, m_jsString, jsString);
+ m_jsString->m_length += jsString->m_length;
+ m_jsString->m_is8Bit = m_jsString->m_is8Bit && jsString->m_is8Bit;
+ }
+
+ JSRopeString* release()
+ {
+ JSRopeString* tmp = m_jsString;
+ m_jsString = 0;
+ return tmp;
+ }
+
+ unsigned length() { return m_jsString->m_length; }
+
+ private:
+ void expand();
+
+ JSGlobalData& m_globalData;
+ JSRopeString* m_jsString;
+ size_t m_index;
+ };
+
+ private:
+ JSRopeString(JSGlobalData& globalData)
+ : JSString(globalData)
+ {
+ }
+
+ void finishCreation(JSGlobalData& globalData, JSString* s1, JSString* s2)
+ {
+ Base::finishCreation(globalData);
+ m_length = s1->length() + s2->length();
+ m_is8Bit = (s1->is8Bit() && s2->is8Bit());
+ m_fibers[0].set(globalData, this, s1);
+ m_fibers[1].set(globalData, this, s2);
+ }
+
+ void finishCreation(JSGlobalData& globalData, JSString* s1, JSString* s2, JSString* s3)
+ {
+ Base::finishCreation(globalData);
+ m_length = s1->length() + s2->length() + s3->length();
+ m_is8Bit = (s1->is8Bit() && s2->is8Bit() && s3->is8Bit());
+ m_fibers[0].set(globalData, this, s1);
+ m_fibers[1].set(globalData, this, s2);
+ m_fibers[2].set(globalData, this, s3);
+ }
+
+ void finishCreation(JSGlobalData& globalData)
+ {
+ JSString::finishCreation(globalData);
+ }
+
+ static JSRopeString* createNull(JSGlobalData& globalData)
+ {
+ JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(globalData.heap)) JSRopeString(globalData);
+ newString->finishCreation(globalData);
+ return newString;
+ }
+
+ public:
+ static JSString* create(JSGlobalData& globalData, JSString* s1, JSString* s2)
+ {
+ JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(globalData.heap)) JSRopeString(globalData);
+ newString->finishCreation(globalData, s1, s2);
+ return newString;
+ }
+ static JSString* create(JSGlobalData& globalData, JSString* s1, JSString* s2, JSString* s3)
+ {
+ JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(globalData.heap)) JSRopeString(globalData);
+ newString->finishCreation(globalData, s1, s2, s3);
+ return newString;
+ }
+
+ void visitFibers(SlotVisitor&);
+
+ private:
+ friend JSValue jsString(ExecState*, Register*, unsigned);
+ friend JSValue jsStringFromArguments(ExecState*, JSValue);
+
+ JS_EXPORT_PRIVATE void resolveRope(ExecState*) const;
+ void resolveRopeSlowCase8(LChar*) const;
+ void resolveRopeSlowCase(UChar*) const;
+ void outOfMemory(ExecState*) const;
+
+ JSString* getIndexSlowCase(ExecState*, unsigned);
+
+ static const unsigned s_maxInternalRopeLength = 3;
+
+ mutable FixedArray<WriteBarrier<JSString>, s_maxInternalRopeLength> m_fibers;
+ };
+
JSString* asString(JSValue);
inline JSString* asString(JSValue value)
@@ -316,11 +335,25 @@
return JSString::create(*globalData, s.impl());
}
+ inline const UString& JSString::value(ExecState* exec) const
+ {
+ if (isRope())
+ static_cast<const JSRopeString*>(this)->resolveRope(exec);
+ return m_value;
+ }
+
+ inline const UString& JSString::tryGetValue() const
+ {
+ if (isRope())
+ static_cast<const JSRopeString*>(this)->resolveRope(0);
+ return m_value;
+ }
+
inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
{
ASSERT(canGetIndex(i));
if (isRope())
- return getIndexSlowCase(exec, i);
+ return static_cast<JSRopeString*>(this)->getIndexSlowCase(exec, i);
ASSERT(i < m_value.length());
return jsSingleCharacterSubstring(exec, m_value, i);
}
@@ -392,9 +425,9 @@
return JSString::createHasOtherOwner(*globalData, s.impl());
}
- inline JSString* jsStringBuilder(JSGlobalData* globalData)
+ inline JSRopeString* jsStringBuilder(JSGlobalData* globalData)
{
- return JSString::createNull(*globalData);
+ return JSRopeString::createNull(*globalData);
}
inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); }
Modified: trunk/Source/_javascript_Core/runtime/Operations.h (115515 => 115516)
--- trunk/Source/_javascript_Core/runtime/Operations.h 2012-04-27 23:48:57 UTC (rev 115515)
+++ trunk/Source/_javascript_Core/runtime/Operations.h 2012-04-27 23:51:17 UTC (rev 115516)
@@ -47,7 +47,7 @@
if ((length1 + length2) < length1)
return throwOutOfMemoryError(exec);
- return JSString::create(globalData, s1, s2);
+ return JSRopeString::create(globalData, s1, s2);
}
ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, const UString& u2, const UString& u3)
@@ -69,13 +69,13 @@
if ((length1 + length2 + length3) < length3)
return throwOutOfMemoryError(exec);
- return JSString::create(exec->globalData(), jsString(globalData, u1), jsString(globalData, u2), jsString(globalData, u3));
+ return JSRopeString::create(exec->globalData(), jsString(globalData, u1), jsString(globalData, u2), jsString(globalData, u3));
}
ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count)
{
JSGlobalData* globalData = &exec->globalData();
- JSString::RopeBuilder ropeBuilder(*globalData);
+ JSRopeString::RopeBuilder ropeBuilder(*globalData);
unsigned oldLength = 0;
@@ -93,7 +93,7 @@
ALWAYS_INLINE JSValue jsStringFromArguments(ExecState* exec, JSValue thisValue)
{
JSGlobalData* globalData = &exec->globalData();
- JSString::RopeBuilder ropeBuilder(*globalData);
+ JSRopeString::RopeBuilder ropeBuilder(*globalData);
ropeBuilder.append(thisValue.toString(exec));
unsigned oldLength = 0;