Ignore:
Timestamp:
May 25, 2009, 9:21:32 PM (16 years ago)
Author:
[email protected]
Message:

JavaScriptCore:

2009-05-25 David Levin <[email protected]>

Reviewed by Maciej Stachowiak and Oliver Hunt.

https://bugs.webkit.org/show_bug.cgi?id=25126
Allow the buffer underlying UString to be shared.

In order to not grow the underlying size of any structure,
there is a union in the Rep string which holds

+ m_sharedBuffer -- a pointer to the shared ref counted buffer

if the class is BaseString and the buffer is being shared OR

+ m_baseString -- the BaseString if the class is only UString::Rep

but not a UString::BaseString

Ideally, m_sharedBuffer would be a RefPtr, but it cannot be because
it is in a union.

No change in sunspider perf.

  • JavaScriptCore.vcproj/WTF/WTF.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • runtime/UString.cpp: (JSC::UString::Rep::share): (JSC::UString::Rep::destroy): (JSC::UString::BaseString::sharedBuffer): (JSC::UString::BaseString::setSharedBuffer): (JSC::UString::BaseString::slowIsBufferReadOnly): (JSC::expandCapacity): (JSC::UString::Rep::reserveCapacity): (JSC::UString::expandPreCapacity): (JSC::concatenate): (JSC::UString::append):
  • runtime/UString.h: (JSC::UString::Rep::Rep): (JSC::UString::Rep::): (JSC::UString::BaseString::isShared): (JSC::UString::BaseString::isBufferReadOnly): (JSC::UString::Rep::baseString):
  • wtf/CrossThreadRefCounted.h: (WTF::CrossThreadRefCounted::isShared):
  • wtf/OwnFastMallocPtr.h: Added. (WTF::OwnFastMallocPtr::OwnFastMallocPtr): (WTF::OwnFastMallocPtr::~OwnFastMallocPtr): (WTF::OwnFastMallocPtr::get): (WTF::OwnFastMallocPtr::release):

JavaScriptGlue:

2009-05-25 David Levin <[email protected]>

Reviewed by Maciej Stachowiak and Oliver Hunt.

https://bugs.webkit.org/show_bug.cgi?id=25126

Added forwarding headers.

  • ForwardingHeaders/wtf/CrossThreadRefCounted.h: Added.
  • ForwardingHeaders/wtf/OwnFastMallocPtr.h: Added.

WebCore:

2009-05-25 David Levin <[email protected]>

Reviewed by Maciej Stachowiak and Oliver Hunt.

Added forwarding headers.

  • ForwardingHeaders/wtf/CrossThreadRefCounted.h: Added.
  • ForwardingHeaders/wtf/OwnFastMallocPtr.h: Added.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/runtime/UString.cpp

    r43856 r44145  
    11/*
    22 *  Copyright (C) 1999-2000 Harri Porten ([email protected])
    3  *  Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
     3 *  Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
    44 *  Copyright (C) 2007 Cameron Zwarich ([email protected])
    5  *  Copyright (c) 2009, Google Inc. All rights reserved.
     5 *  Copyright (C) 2009 Google Inc. All rights reserved.
    66 *
    77 *  This library is free software; you can redistribute it and/or
     
    233233}
    234234
     235PassRefPtr<UString::Rep> UString::Rep::share(UChar* string, int length, PassRefPtr<UString::SharedUChar> sharedBuffer)
     236{
     237    PassRefPtr<UString::Rep> rep = create(string, length);
     238    rep->baseString()->setSharedBuffer(sharedBuffer);
     239    rep->checkConsistency();
     240    return rep;
     241}
     242
    235243void UString::Rep::destroy()
    236244{
     
    242250        if (identifierTable())
    243251            Identifier::remove(this);
     252
    244253        UString::BaseString* base = baseString();
    245         if (base == this)
    246             fastFree(base->buf);
    247         else
     254        if (base == this) {
     255            if (m_sharedBuffer)
     256                m_sharedBuffer->deref();
     257            else
     258                fastFree(base->buf);
     259        } else
    248260            base->deref();
    249261
     
    368380}
    369381#endif
     382
     383UString::SharedUChar* UString::BaseString::sharedBuffer()
     384{
     385    // Don't share empty, null and 1 character strings from SmallStrings.
     386    if (len <= 1)
     387        return 0;
     388
     389    if (!m_sharedBuffer)
     390        setSharedBuffer(SharedUChar::create(new OwnFastMallocPtr<UChar>(buf)));
     391    return m_sharedBuffer;
     392}
     393
     394void UString::BaseString::setSharedBuffer(PassRefPtr<UString::SharedUChar> sharedBuffer)
     395{
     396    // The manual steps below are because m_sharedBuffer can't be a RefPtr. m_sharedBuffer
     397    // is in a union with another variable to avoid making BaseString any larger.
     398    if (m_sharedBuffer)
     399        m_sharedBuffer->deref();
     400    m_sharedBuffer = sharedBuffer.releaseRef();
     401}
     402
     403bool UString::BaseString::slowIsBufferReadOnly()
     404{
     405    // The buffer may not be modified as soon as the underlying data has been shared with another class.
     406    if (m_sharedBuffer->isShared())
     407        return true;
     408
     409    // At this point, we know it that the underlying buffer isn't shared outside of this base class,
     410    // so get rid of m_sharedBuffer.
     411    OwnPtr<OwnFastMallocPtr<UChar> > mallocPtr(m_sharedBuffer->release());
     412    UChar* unsharedBuf = const_cast<UChar*>(mallocPtr->release());
     413    setSharedBuffer(0);
     414    preCapacity += (buf - unsharedBuf);
     415    buf = unsharedBuf;
     416    return false;
     417}
    370418
    371419// Put these early so they can be inlined.
     
    418466{
    419467    rep->checkConsistency();
     468    ASSERT(!rep->baseString()->isBufferReadOnly());
    420469
    421470    UString::BaseString* base = rep->baseString();
     
    443492    // If the BaseString is shared with another string that is using more capacity than this
    444493    // string is, then growing the buffer won't help.
    445     if (!m_baseString->buf || !m_baseString->capacity || (offset + len) != m_baseString->usedCapacity)
     494    // If the BaseString's buffer is readonly, then it isn't allowed to grow.
     495    UString::BaseString* base = baseString();
     496    if (!base->buf || !base->capacity || (offset + len) != base->usedCapacity || base->isBufferReadOnly())
    446497        return false;
    447498   
    448499    // If there is already sufficient capacity, no need to grow!
    449     if (capacity <= m_baseString->capacity)
     500    if (capacity <= base->capacity)
    450501        return true;
    451502
    452503    checkConsistency();
    453504
    454     size_t newCapacity = expandedSize(capacity, m_baseString->preCapacity);
    455     UChar* oldBuf = m_baseString->buf;
    456     m_baseString->buf = reallocChars(m_baseString->buf, newCapacity);
    457     if (!m_baseString->buf) {
    458         m_baseString->buf = oldBuf;
     505    size_t newCapacity = expandedSize(capacity, base->preCapacity);
     506    UChar* oldBuf = base->buf;
     507    base->buf = reallocChars(base->buf, newCapacity);
     508    if (!base->buf) {
     509        base->buf = oldBuf;
    459510        return false;
    460511    }
    461     m_baseString->capacity = newCapacity - m_baseString->preCapacity;
     512    base->capacity = newCapacity - base->preCapacity;
    462513
    463514    checkConsistency();
     
    474525{
    475526    m_rep->checkConsistency();
     527    ASSERT(!m_rep->baseString()->isBufferReadOnly());
    476528
    477529    BaseString* base = m_rep->baseString();
     
    586638            rep->_hash = 0;
    587639        }
    588     } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize) {
     640    } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize && !base->isBufferReadOnly()) {
    589641        // this reaches the end of the buffer - extend it if it's long enough to append to
    590642        if (!expandCapacity(rep.get(), newCapacityWithOverflowCheck(thisOffset, length)))
     
    595647        }
    596648    } else {
    597         // this is shared with someone using more capacity, gotta make a whole new string
     649        // This is shared in some way that prevents us from modifying base, so we must make a whole new string.
    598650        size_t newCapacity = expandedSize(length, 0);
    599651        UChar* d = allocChars(newCapacity);
     
    641693            rep->_hash = 0;
    642694        }
    643     } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize) {
     695    } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize && !base->isBufferReadOnly()) {
    644696        // this string reaches the end of the buffer - extend it
    645697        expandCapacity(rep.get(), newCapacityWithOverflowCheck(thisOffset, length));
     
    651703        }
    652704    } else {
    653         // this is shared with someone using more capacity, gotta make a whole new string
     705        // This is shared in some way that prevents us from modifying base, so we must make a whole new string.
    654706        size_t newCapacity = expandedSize(length, 0);
    655707        UChar* d = allocChars(newCapacity);
     
    682734
    683735    UString::BaseString* aBase = a->baseString();
    684     if (bSize == 1 && aOffset + aSize == aBase->usedCapacity && aOffset + aSize < aBase->capacity) {
     736    if (bSize == 1 && aOffset + aSize == aBase->usedCapacity && aOffset + aSize < aBase->capacity && !aBase->isBufferReadOnly()) {
    685737        // b is a single character (common fast case)
    686738        ++aBase->usedCapacity;
     
    701753    UString::BaseString* bBase = b->baseString();
    702754    if (aOffset + aSize == aBase->usedCapacity && aSize >= minShareSize && 4 * aSize >= bSize
    703         && (-bOffset != bBase->usedPreCapacity || aSize >= bSize)) {
     755        && (-bOffset != bBase->usedPreCapacity || aSize >= bSize) && !aBase->isBufferReadOnly()) {
    704756        // - a reaches the end of its buffer so it qualifies for shared append
    705757        // - also, it's at least a quarter the length of b - appending to a much shorter
     
    721773    }
    722774
    723     if (-bOffset == bBase->usedPreCapacity && bSize >= minShareSize && 4 * bSize >= aSize) {
     775    if (-bOffset == bBase->usedPreCapacity && bSize >= minShareSize && 4 * bSize >= aSize && !bBase->isBufferReadOnly()) {
    724776        // - b reaches the beginning of its buffer so it qualifies for shared prepend
    725777        // - also, it's at least a quarter the length of a - prepending to a much shorter
     
    10841136            m_rep->_hash = 0;
    10851137        }
    1086     } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize) {
     1138    } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize && !base->isBufferReadOnly()) {
    10871139        // this reaches the end of the buffer - extend it if it's long enough to append to
    10881140        expandCapacity(newCapacityWithOverflowCheck(thisOffset, length));
     
    10921144        }
    10931145    } else {
    1094         // this is shared with someone using more capacity, gotta make a whole new string
     1146        // This is shared in some way that prevents us from modifying base, so we must make a whole new string.
    10951147        size_t newCapacity = expandedSize(length, 0);
    10961148        UChar* d = allocChars(newCapacity);
     
    11641216            m_rep->_hash = 0;
    11651217        }
    1166     } else if (thisOffset + length == base->usedCapacity && length >= minShareSize) {
     1218    } else if (thisOffset + length == base->usedCapacity && length >= minShareSize && !base->isBufferReadOnly()) {
    11671219        // this reaches the end of the string - extend it and share
    11681220        expandCapacity(newCapacityWithOverflowCheck(thisOffset, length, true));
     
    11731225        }
    11741226    } else {
    1175         // this is shared with someone using more capacity, gotta make a whole new string
     1227        // This is shared in some way that prevents us from modifying base, so we must make a whole new string.
    11761228        size_t newCapacity = expandedSize(length + 1, 0);
    11771229        UChar* d = allocChars(newCapacity);
Note: See TracChangeset for help on using the changeset viewer.