diff options
Diffstat (limited to 'src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.cpp')
-rw-r--r-- | src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.cpp | 191 |
1 files changed, 122 insertions, 69 deletions
diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.cpp index a30f729..1e23a15 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSString.cpp @@ -25,41 +25,150 @@ #include "JSGlobalObject.h" #include "JSObject.h" +#include "Operations.h" #include "StringObject.h" #include "StringPrototype.h" namespace JSC { +void JSString::Rope::destructNonRecursive() +{ + Vector<Rope*, 32> workQueue; + Rope* rope = this; + + while (true) { + unsigned length = rope->ropeLength(); + for (unsigned i = 0; i < length; ++i) { + Fiber& fiber = rope->fibers(i); + if (fiber.isString()) + fiber.string()->deref(); + else { + Rope* nextRope = fiber.rope(); + if (nextRope->hasOneRef()) + workQueue.append(nextRope); + else + nextRope->deref(); + } + } + if (rope != this) + fastFree(rope); + + if (workQueue.isEmpty()) + return; + + rope = workQueue.last(); + workQueue.removeLast(); + } +} + +JSString::Rope::~Rope() +{ + destructNonRecursive(); +} + +// 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 UString::Reps 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_stringLength, buffer)) + m_value = newImpl; + else { + for (unsigned i = 0; i < m_ropeLength; ++i) { + m_fibers[i].deref(); + m_fibers[i] = static_cast<void*>(0); + } + m_ropeLength = 0; + ASSERT(!isRope()); + ASSERT(m_value == UString()); + throwOutOfMemoryError(exec); + return; + } + UChar* position = buffer + m_stringLength; + + // Start with the current Rope. + Vector<Rope::Fiber, 32> workQueue; + Rope::Fiber currentFiber; + for (unsigned i = 0; i < (m_ropeLength - 1); ++i) + workQueue.append(m_fibers[i]); + currentFiber = m_fibers[m_ropeLength - 1]; + while (true) { + if (currentFiber.isRope()) { + Rope* rope = currentFiber.rope(); + // 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 ropeLengthMinusOne = rope->ropeLength() - 1; + for (unsigned i = 0; i < ropeLengthMinusOne; ++i) + workQueue.append(rope->fibers(i)); + currentFiber = rope->fibers(ropeLengthMinusOne); + } else { + UString::Rep* string = currentFiber.string(); + unsigned length = string->size(); + position -= length; + UStringImpl::copyChars(position, string->data(), 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_ropeLength; ++i) { + m_fibers[i].deref(); + m_fibers[i] = static_cast<void*>(0); + } + m_ropeLength = 0; + + ASSERT(!isRope()); + return; + } + + // No! - set the next item up to process. + currentFiber = workQueue.last(); + workQueue.removeLast(); + } + } +} + 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_stringLength; } -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 +215,14 @@ bool JSString::getOwnPropertySlot(ExecState* exec, const Identifier& propertyNam 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_stringLength), 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_stringLength) { + descriptor.setDescriptor(jsSingleCharacterSubstring(exec, value(exec), i), DontDelete | ReadOnly); return true; } @@ -139,60 +248,4 @@ bool JSString::getOwnPropertySlot(ExecState* exec, unsigned propertyName, Proper return JSString::getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot); } -bool JSString::getStringPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const -{ - if (propertyName == exec->propertyNames().length) { - attributes = DontEnum | DontDelete | ReadOnly; - return true; - } - bool isStrictUInt32; - unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); - if (isStrictUInt32 && i < static_cast<unsigned>(m_value.size())) { - attributes = DontDelete | ReadOnly; - return true; - } - return false; -} - -JSString* jsString(JSGlobalData* globalData, const UString& s) -{ - int size = s.size(); - if (!size) - return globalData->smallStrings.emptyString(globalData); - if (size == 1) { - UChar c = s.data()[0]; - if (c <= 0xFF) - return globalData->smallStrings.singleCharacterString(globalData, c); - } - return new (globalData) JSString(globalData, s); -} - -JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length) -{ - ASSERT(offset <= static_cast<unsigned>(s.size())); - ASSERT(length <= static_cast<unsigned>(s.size())); - ASSERT(offset + length <= static_cast<unsigned>(s.size())); - if (!length) - return globalData->smallStrings.emptyString(globalData); - if (length == 1) { - UChar c = s.data()[offset]; - if (c <= 0xFF) - return globalData->smallStrings.singleCharacterString(globalData, c); - } - return new (globalData) JSString(globalData, UString::Rep::create(s.rep(), offset, length)); -} - -JSString* jsOwnedString(JSGlobalData* globalData, const UString& s) -{ - int size = s.size(); - if (!size) - return globalData->smallStrings.emptyString(globalData); - if (size == 1) { - UChar c = s.data()[0]; - if (c <= 0xFF) - return globalData->smallStrings.singleCharacterString(globalData, c); - } - return new (globalData) JSString(globalData, s, JSString::HasOtherOwner); -} - } // namespace JSC |