--- a/src/3rdparty/webkit/JavaScriptCore/runtime/JSString.cpp Wed Jun 23 19:07:03 2010 +0300
+++ b/src/3rdparty/webkit/JavaScriptCore/runtime/JSString.cpp Tue Jul 06 15:10:48 2010 +0300
@@ -25,41 +25,127 @@
#include "JSGlobalObject.h"
#include "JSObject.h"
+#include "Operations.h"
#include "StringObject.h"
#include "StringPrototype.h"
namespace JSC {
+// 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
+// backwards, since we want to avoid recursion, we expect that the tree structure
+// representing the rope is likely imbalanced with more nodes down the left side
+// (since appending to the string is likely more common) - and as such resolving
+// in this fashion should minimize work queue size. (If we built the queue forwards
+// we would likely have to place all of the constituent UStringImpls into the
+// 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::resolveRope(ExecState* exec) const
+{
+ ASSERT(isRope());
+
+ // Allocate the buffer to hold the final string, position initially points to the end.
+ UChar* buffer;
+ if (PassRefPtr<UStringImpl> newImpl = UStringImpl::tryCreateUninitialized(m_length, buffer))
+ m_value = newImpl;
+ else {
+ for (unsigned i = 0; i < m_fiberCount; ++i) {
+ m_other.m_fibers[i]->deref();
+ m_other.m_fibers[i] = 0;
+ }
+ m_fiberCount = 0;
+ ASSERT(!isRope());
+ ASSERT(m_value == UString());
+ throwOutOfMemoryError(exec);
+ return;
+ }
+ UChar* position = buffer + m_length;
+
+ // Start with the current Rope.
+ Vector<Rope::Fiber, 32> workQueue;
+ Rope::Fiber currentFiber;
+ for (unsigned i = 0; i < (m_fiberCount - 1); ++i)
+ workQueue.append(m_other.m_fibers[i]);
+ currentFiber = m_other.m_fibers[m_fiberCount - 1];
+ while (true) {
+ if (currentFiber->isRope()) {
+ Rope* rope = static_cast<URopeImpl*>(currentFiber);
+ // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber'
+ // (we will be working backwards over the rope).
+ unsigned fiberCountMinusOne = rope->fiberCount() - 1;
+ for (unsigned i = 0; i < fiberCountMinusOne; ++i)
+ workQueue.append(rope->fibers(i));
+ currentFiber = rope->fibers(fiberCountMinusOne);
+ } else {
+ UStringImpl* string = static_cast<UStringImpl*>(currentFiber);
+ unsigned length = string->length();
+ position -= length;
+ UStringImpl::copyChars(position, string->characters(), length);
+
+ // Was this the last item in the work queue?
+ if (workQueue.isEmpty()) {
+ // Create a string from the UChar buffer, clear the rope RefPtr.
+ ASSERT(buffer == position);
+ for (unsigned i = 0; i < m_fiberCount; ++i) {
+ m_other.m_fibers[i]->deref();
+ m_other.m_fibers[i] = 0;
+ }
+ m_fiberCount = 0;
+
+ ASSERT(!isRope());
+ return;
+ }
+
+ // No! - set the next item up to process.
+ currentFiber = workQueue.last();
+ workQueue.removeLast();
+ }
+ }
+}
+
+JSString* JSString::getIndexSlowCase(ExecState* exec, unsigned i)
+{
+ ASSERT(isRope());
+ resolveRope(exec);
+ // Return a safe no-value result, this should never be used, since the excetion will be thrown.
+ if (exec->exception())
+ return jsString(exec, "");
+ ASSERT(!isRope());
+ ASSERT(i < m_value.size());
+ return jsSingleCharacterSubstring(exec, m_value, i);
+}
+
JSValue JSString::toPrimitive(ExecState*, PreferredPrimitiveType) const
{
return const_cast<JSString*>(this);
}
-bool JSString::getPrimitiveNumber(ExecState*, double& number, JSValue& value)
+bool JSString::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result)
{
- value = this;
- number = m_value.toDouble();
+ result = this;
+ number = value(exec).toDouble();
return false;
}
bool JSString::toBoolean(ExecState*) const
{
- return !m_value.isEmpty();
+ return m_length;
}
-double JSString::toNumber(ExecState*) const
+double JSString::toNumber(ExecState* exec) const
{
- return m_value.toDouble();
+ return value(exec).toDouble();
}
-UString JSString::toString(ExecState*) const
+UString JSString::toString(ExecState* exec) const
{
- return m_value;
+ return value(exec);
}
-UString JSString::toThisString(ExecState*) const
+UString JSString::toThisString(ExecState* exec) const
{
- return m_value;
+ return value(exec);
}
JSString* JSString::toThisJSString(ExecState*)
@@ -106,14 +192,14 @@
bool JSString::getStringPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
if (propertyName == exec->propertyNames().length) {
- descriptor.setDescriptor(jsNumber(exec, m_value.size()), DontEnum | DontDelete | ReadOnly);
+ descriptor.setDescriptor(jsNumber(exec, m_length), DontEnum | DontDelete | ReadOnly);
return true;
}
bool isStrictUInt32;
unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
- if (isStrictUInt32 && i < static_cast<unsigned>(m_value.size())) {
- descriptor.setDescriptor(jsSingleCharacterSubstring(exec, m_value, i), DontDelete | ReadOnly);
+ if (isStrictUInt32 && i < m_length) {
+ descriptor.setDescriptor(getIndex(exec, i), DontDelete | ReadOnly);
return true;
}