diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
commit | 32761a6cee1d0dee366b885b7b9c777e67885688 (patch) | |
tree | d6bec92bebfb216f4126356e55518842c2f476a1 /Source/JavaScriptCore/runtime/JSString.cpp | |
parent | a4e969f4965059196ca948db781e52f7cfebf19e (diff) | |
download | WebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz |
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSString.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSString.cpp | 339 |
1 files changed, 99 insertions, 240 deletions
diff --git a/Source/JavaScriptCore/runtime/JSString.cpp b/Source/JavaScriptCore/runtime/JSString.cpp index ad8a67a45..3e4e3ffa1 100644 --- a/Source/JavaScriptCore/runtime/JSString.cpp +++ b/Source/JavaScriptCore/runtime/JSString.cpp @@ -1,7 +1,7 @@ /* * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2004, 2007, 2008, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2007, 2008 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -26,19 +26,13 @@ #include "JSGlobalObject.h" #include "JSGlobalObjectFunctions.h" #include "JSObject.h" -#include "JSCInlines.h" +#include "Operations.h" #include "StringObject.h" #include "StringPrototype.h" -#include "StrongInlines.h" namespace JSC { -const ClassInfo JSString::s_info = { "string", 0, 0, CREATE_METHOD_TABLE(JSString) }; - -Structure* JSString::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) -{ - return Structure::create(vm, globalObject, proto, TypeInfo(StringType, StructureFlags), info()); -} +const ClassInfo JSString::s_info = { "string", 0, 0, 0, CREATE_METHOD_TABLE(JSString) }; void JSRopeString::RopeBuilder::expand() { @@ -56,226 +50,98 @@ void JSString::destroy(JSCell* cell) thisObject->JSString::~JSString(); } -void JSString::dumpToStream(const JSCell* cell, PrintStream& out) -{ - const JSString* thisObject = jsCast<const JSString*>(cell); - out.printf("<%p, %s, [%u], ", thisObject, thisObject->className(), thisObject->length()); - if (thisObject->isRope()) - out.printf("[rope]"); - else { - WTF::StringImpl* ourImpl = thisObject->m_value.impl(); - if (ourImpl->is8Bit()) - out.printf("[8 %p]", ourImpl->characters8()); - else - out.printf("[16 %p]", ourImpl->characters16()); - } - out.printf(">"); -} - -size_t JSString::estimatedSize(JSCell* cell) -{ - JSString* thisObject = jsCast<JSString*>(cell); - if (thisObject->isRope()) - return Base::estimatedSize(cell); - return Base::estimatedSize(cell) + thisObject->m_value.impl()->costDuringGC(); -} - void JSString::visitChildren(JSCell* cell, SlotVisitor& visitor) { JSString* thisObject = jsCast<JSString*>(cell); Base::visitChildren(thisObject, visitor); + MARK_LOG_MESSAGE1("[%u]: ", thisObject->length()); + +#if ENABLE(OBJECT_MARK_LOGGING) + if (!thisObject->isRope()) { + WTF::StringImpl* ourImpl = thisObject->m_value.impl(); + if (ourImpl->is8Bit()) + MARK_LOG_MESSAGE1("[8 %p]", ourImpl->characters8()); + else + MARK_LOG_MESSAGE1("[16 %p]", ourImpl->characters16()); + } else + MARK_LOG_MESSAGE0("[rope]: "); +#endif + if (thisObject->isRope()) static_cast<JSRopeString*>(thisObject)->visitFibers(visitor); else { StringImpl* impl = thisObject->m_value.impl(); ASSERT(impl); - visitor.reportExtraMemoryVisited(impl->costDuringGC()); + visitor.reportExtraMemoryUsage(thisObject, impl->costDuringGC()); } } void JSRopeString::visitFibers(SlotVisitor& visitor) { - if (isSubstring()) { - visitor.append(&substringBase()); - return; - } - for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) - visitor.append(&fiber(i)); -} - -static const unsigned maxLengthForOnStackResolve = 2048; - -void JSRopeString::resolveRopeInternal8(LChar* buffer) const -{ - if (isSubstring()) { - StringImpl::copyChars( - buffer, substringBase()->m_value.characters8() + substringOffset(), m_length); - return; - } - - resolveRopeInternal8NoSubstring(buffer); -} - -void JSRopeString::resolveRopeInternal8NoSubstring(LChar* buffer) const -{ - for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) { - if (fiber(i)->isRope()) { - resolveRopeSlowCase8(buffer); - return; - } - } - - LChar* position = buffer; - for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) { - const StringImpl& fiberString = *fiber(i)->m_value.impl(); - unsigned length = fiberString.length(); - StringImpl::copyChars(position, fiberString.characters8(), length); - position += length; - } - ASSERT((buffer + m_length) == position); -} - -void JSRopeString::resolveRopeInternal16(UChar* buffer) const -{ - if (isSubstring()) { - StringImpl::copyChars( - buffer, substringBase()->m_value.characters16() + substringOffset(), m_length); - return; - } - - resolveRopeInternal16NoSubstring(buffer); -} - -void JSRopeString::resolveRopeInternal16NoSubstring(UChar* buffer) const -{ - for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) { - if (fiber(i)->isRope()) { - resolveRopeSlowCase(buffer); - return; - } - } - - UChar* position = buffer; - for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) { - const StringImpl& fiberString = *fiber(i)->m_value.impl(); - unsigned length = fiberString.length(); - if (fiberString.is8Bit()) - StringImpl::copyChars(position, fiberString.characters8(), length); - else - StringImpl::copyChars(position, fiberString.characters16(), length); - position += length; - } - ASSERT((buffer + m_length) == position); -} - -void JSRopeString::resolveRopeToAtomicString(ExecState* exec) const -{ - if (m_length > maxLengthForOnStackResolve) { - resolveRope(exec); - m_value = AtomicString(m_value); - setIs8Bit(m_value.impl()->is8Bit()); - return; - } - - if (is8Bit()) { - LChar buffer[maxLengthForOnStackResolve]; - resolveRopeInternal8(buffer); - m_value = AtomicString(buffer, m_length); - setIs8Bit(m_value.impl()->is8Bit()); - } else { - UChar buffer[maxLengthForOnStackResolve]; - resolveRopeInternal16(buffer); - m_value = AtomicString(buffer, m_length); - setIs8Bit(m_value.impl()->is8Bit()); - } - - clearFibers(); - - // If we resolved a string that didn't previously exist, notify the heap that we've grown. - if (m_value.impl()->hasOneRef()) - Heap::heap(this)->reportExtraMemoryAllocated(m_value.impl()->cost()); -} - -void JSRopeString::clearFibers() const -{ - for (size_t i = 0; i < s_maxInternalRopeLength; ++i) - u[i].number = 0; -} - -RefPtr<AtomicStringImpl> JSRopeString::resolveRopeToExistingAtomicString(ExecState* exec) const -{ - if (m_length > maxLengthForOnStackResolve) { - resolveRope(exec); - if (RefPtr<AtomicStringImpl> existingAtomicString = AtomicStringImpl::lookUp(m_value.impl())) { - m_value = *existingAtomicString; - setIs8Bit(m_value.impl()->is8Bit()); - clearFibers(); - return existingAtomicString; - } - return nullptr; - } - - if (is8Bit()) { - LChar buffer[maxLengthForOnStackResolve]; - resolveRopeInternal8(buffer); - if (RefPtr<AtomicStringImpl> existingAtomicString = AtomicStringImpl::lookUp(buffer, m_length)) { - m_value = *existingAtomicString; - setIs8Bit(m_value.impl()->is8Bit()); - clearFibers(); - return existingAtomicString; - } - } else { - UChar buffer[maxLengthForOnStackResolve]; - resolveRopeInternal16(buffer); - if (RefPtr<AtomicStringImpl> existingAtomicString = AtomicStringImpl::lookUp(buffer, m_length)) { - m_value = *existingAtomicString; - setIs8Bit(m_value.impl()->is8Bit()); - clearFibers(); - return existingAtomicString; - } - } - - return nullptr; + 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 (isSubstring()) { - ASSERT(!substringBase()->isRope()); - m_value = substringBase()->m_value.substringSharingImpl(substringOffset(), m_length); - substringBase().clear(); - return; - } - + if (is8Bit()) { LChar* buffer; if (RefPtr<StringImpl> newImpl = StringImpl::tryCreateUninitialized(m_length, buffer)) { - Heap::heap(this)->reportExtraMemoryAllocated(newImpl->cost()); + Heap::heap(this)->reportExtraMemoryCost(newImpl->cost()); m_value = newImpl.release(); } else { outOfMemory(exec); return; } - resolveRopeInternal8NoSubstring(buffer); - clearFibers(); + + for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) { + if (m_fibers[i]->isRope()) + return resolveRopeSlowCase8(buffer); + } + + LChar* position = buffer; + for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) { + StringImpl* string = m_fibers[i]->m_value.impl(); + unsigned length = string->length(); + StringImpl::copyChars(position, string->characters8(), length); + position += length; + m_fibers[i].clear(); + } + ASSERT((buffer + m_length) == position); ASSERT(!isRope()); + return; } UChar* buffer; if (RefPtr<StringImpl> newImpl = StringImpl::tryCreateUninitialized(m_length, buffer)) { - Heap::heap(this)->reportExtraMemoryAllocated(newImpl->cost()); + Heap::heap(this)->reportExtraMemoryCost(newImpl->cost()); m_value = newImpl.release(); } else { outOfMemory(exec); return; } - resolveRopeInternal16NoSubstring(buffer); - clearFibers(); + for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) { + if (m_fibers[i]->isRope()) + return resolveRopeSlowCase(buffer); + } + + UChar* position = buffer; + for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) { + StringImpl* string = m_fibers[i]->m_value.impl(); + unsigned length = string->length(); + if (string->is8Bit()) + StringImpl::copyChars(position, string->characters8(), length); + else + StringImpl::copyChars(position, string->characters16(), length); + position += length; + m_fibers[i].clear(); + } + ASSERT((buffer + m_length) == position); ASSERT(!isRope()); } @@ -294,35 +160,31 @@ void JSRopeString::resolveRopeSlowCase8(LChar* buffer) const LChar* position = buffer + m_length; // We will be working backwards over the rope. Vector<JSString*, 32, UnsafeVectorOverflow> workQueue; // Putting strings into a Vector is only OK because there are no GC points in this method. - for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) - workQueue.append(fiber(i).get()); + for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) { + workQueue.append(m_fibers[i].get()); + // Clearing here works only because there are no GC points in this method. + m_fibers[i].clear(); + } while (!workQueue.isEmpty()) { JSString* currentFiber = workQueue.last(); workQueue.removeLast(); - const LChar* characters; - if (currentFiber->isRope()) { JSRopeString* currentFiberAsRope = static_cast<JSRopeString*>(currentFiber); - if (!currentFiberAsRope->isSubstring()) { - for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->fiber(i); ++i) - workQueue.append(currentFiberAsRope->fiber(i).get()); - continue; - } - ASSERT(!currentFiberAsRope->substringBase()->isRope()); - characters = - currentFiberAsRope->substringBase()->m_value.characters8() + - currentFiberAsRope->substringOffset(); - } else - characters = currentFiber->m_value.characters8(); - - unsigned length = currentFiber->length(); + for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->m_fibers[i]; ++i) + workQueue.append(currentFiberAsRope->m_fibers[i].get()); + continue; + } + + StringImpl* string = static_cast<StringImpl*>(currentFiber->m_value.impl()); + unsigned length = string->length(); position -= length; - StringImpl::copyChars(position, characters, length); + StringImpl::copyChars(position, string->characters8(), length); } ASSERT(buffer == position); + ASSERT(!isRope()); } void JSRopeString::resolveRopeSlowCase(UChar* buffer) const @@ -330,8 +192,8 @@ void JSRopeString::resolveRopeSlowCase(UChar* buffer) const UChar* position = buffer + m_length; // We will be working backwards over the rope. Vector<JSString*, 32, UnsafeVectorOverflow> workQueue; // These strings are kept alive by the parent rope, so using a Vector is OK. - for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) - workQueue.append(fiber(i).get()); + for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) + workQueue.append(m_fibers[i].get()); while (!workQueue.isEmpty()) { JSString* currentFiber = workQueue.last(); @@ -339,21 +201,8 @@ void JSRopeString::resolveRopeSlowCase(UChar* buffer) const if (currentFiber->isRope()) { JSRopeString* currentFiberAsRope = static_cast<JSRopeString*>(currentFiber); - if (currentFiberAsRope->isSubstring()) { - ASSERT(!currentFiberAsRope->substringBase()->isRope()); - StringImpl* string = static_cast<StringImpl*>( - currentFiberAsRope->substringBase()->m_value.impl()); - unsigned offset = currentFiberAsRope->substringOffset(); - unsigned length = currentFiberAsRope->length(); - position -= length; - if (string->is8Bit()) - StringImpl::copyChars(position, string->characters8() + offset, length); - else - StringImpl::copyChars(position, string->characters16() + offset, length); - continue; - } - for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->fiber(i); ++i) - workQueue.append(currentFiberAsRope->fiber(i).get()); + for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->m_fibers[i]; ++i) + workQueue.append(currentFiberAsRope->m_fibers[i].get()); continue; } @@ -367,17 +216,31 @@ void JSRopeString::resolveRopeSlowCase(UChar* buffer) const } ASSERT(buffer == position); + ASSERT(!isRope()); } void JSRopeString::outOfMemory(ExecState* exec) const { - clearFibers(); + for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) + m_fibers[i].clear(); ASSERT(isRope()); ASSERT(m_value.isNull()); if (exec) throwOutOfMemoryError(exec); } +JSString* JSRopeString::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 jsEmptyString(exec); + ASSERT(!isRope()); + RELEASE_ASSERT(i < m_value.length()); + return jsSingleCharacterSubstring(exec, m_value, i); +} + JSValue JSString::toPrimitive(ExecState*, PreferredPrimitiveType) const { return const_cast<JSString*>(this); @@ -386,13 +249,18 @@ JSValue JSString::toPrimitive(ExecState*, PreferredPrimitiveType) const bool JSString::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) const { result = this; - number = jsToNumber(unsafeView(*exec)); + number = jsToNumber(value(exec)); return false; } +bool JSString::toBoolean() const +{ + return m_length; +} + double JSString::toNumber(ExecState* exec) const { - return jsToNumber(unsafeView(*exec)); + return jsToNumber(value(exec)); } inline StringObject* StringObject::create(VM& vm, JSGlobalObject* globalObject, JSString* string) @@ -421,23 +289,14 @@ bool JSString::getStringPropertyDescriptor(ExecState* exec, PropertyName propert return true; } - Optional<uint32_t> index = parseIndex(propertyName); - if (index && index.value() < m_length) { - descriptor.setDescriptor(getIndex(exec, index.value()), DontDelete | ReadOnly); + unsigned i = propertyName.asIndex(); + if (i < m_length) { + ASSERT(i != PropertyName::NotAnIndex); // No need for an explicit check, the above test would always fail! + descriptor.setDescriptor(getIndex(exec, i), DontDelete | ReadOnly); return true; } return false; } -JSString* jsStringWithCacheSlowCase(VM& vm, StringImpl& stringImpl) -{ - if (JSString* string = vm.stringCache.get(&stringImpl)) - return string; - - JSString* string = jsString(&vm, String(stringImpl)); - vm.lastCachedString.set(vm, string); - return string; -} - } // namespace JSC |