Changeset 53392 in webkit


Ignore:
Timestamp:
Jan 17, 2010 11:36:45 PM (14 years ago)
Author:
barraclough@apple.com
Message:

https://bugs.webkit.org/show_bug.cgi?id=33731
Remove UntypedPtrAndBitfield from UStringImpl (akin to PtrAndFlags).

Reviewed by Oliver Hunt.

This break the OS X Leaks tool. Instead, free up some more bits from the refCount.

  • runtime/UStringImpl.cpp:

(JSC::UStringImpl::sharedBuffer):
(JSC::UStringImpl::~UStringImpl):

  • runtime/UStringImpl.h:

(JSC::UStringImpl::cost):
(JSC::UStringImpl::checkConsistency):
(JSC::UStringImpl::UStringImpl):
(JSC::UStringImpl::bufferOwnerString):
(JSC::UStringImpl::):

  • wtf/StringHashFunctions.h:

(WTF::stringHash):

Location:
trunk/JavaScriptCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r53391 r53392  
     12010-01-15  Gavin Barraclough  <barraclough@apple.com>
     2
     3        Reviewed by Oliver Hunt.
     4
     5        https://bugs.webkit.org/show_bug.cgi?id=33731
     6        Remove UntypedPtrAndBitfield from UStringImpl (akin to PtrAndFlags).
     7
     8        This break the OS X Leaks tool.  Instead, free up some more bits from the refCount.
     9
     10        * runtime/UStringImpl.cpp:
     11        (JSC::UStringImpl::sharedBuffer):
     12        (JSC::UStringImpl::~UStringImpl):
     13        * runtime/UStringImpl.h:
     14        (JSC::UStringImpl::cost):
     15        (JSC::UStringImpl::checkConsistency):
     16        (JSC::UStringImpl::UStringImpl):
     17        (JSC::UStringImpl::bufferOwnerString):
     18        (JSC::UStringImpl::):
     19        * wtf/StringHashFunctions.h:
     20        (WTF::stringHash):
     21
    1222010-01-15  Gavin Barraclough  <barraclough@apple.com>
    223
  • trunk/JavaScriptCore/runtime/UString.cpp

    r53320 r53392  
    349349UString UString::spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const
    350350{
    351     m_rep->checkConsistency();
    352 
    353351    if (rangeCount == 1 && separatorCount == 0) {
    354352        int thisSize = size();
     
    392390UString UString::replaceRange(int rangeStart, int rangeLength, const UString& replacement) const
    393391{
    394     m_rep->checkConsistency();
    395 
    396392    int replacementLength = replacement.size();
    397393    int totalLength = size() - rangeLength + replacementLength;
  • trunk/JavaScriptCore/runtime/UStringImpl.cpp

    r53221 r53392  
    3636namespace JSC {
    3737 
    38 SharedUChar* UStringImpl::baseSharedBuffer()
    39 {
    40     ASSERT((bufferOwnership() == BufferShared)
    41         || ((bufferOwnership() == BufferOwned) && !m_dataBuffer.asPtr<void*>()));
    42 
    43     if (bufferOwnership() != BufferShared)
    44         m_dataBuffer = UntypedPtrAndBitfield(SharedUChar::create(new OwnFastMallocPtr<UChar>(m_data)).releaseRef(), BufferShared);
    45 
    46     return m_dataBuffer.asPtr<SharedUChar*>();
    47 }
    48 
    4938SharedUChar* UStringImpl::sharedBuffer()
    5039{
    51     if (m_length < s_minLengthToShare)
    52         return 0;
    53     ASSERT(!isStatic());
    54 
    55     UStringImpl* owner = bufferOwnerString();
    56     if (owner->bufferOwnership() == BufferInternal)
     40    if (m_length < s_minLengthToShare || isStatic())
    5741        return 0;
    5842
    59     return owner->baseSharedBuffer();
     43    switch (bufferOwnership()) {
     44    case BufferInternal:
     45        return 0;
     46    case BufferOwned:
     47        m_bufferShared = SharedUChar::create(new OwnFastMallocPtr<UChar>(m_data)).releaseRef();
     48        m_refCountAndFlags &= ~s_refCountMaskBufferOwnership;
     49        m_refCountAndFlags |= BufferShared;
     50        return m_bufferShared;
     51    case BufferSubstring:
     52        return m_bufferSubstring->sharedBuffer();
     53    case BufferShared:
     54        return m_bufferShared;
     55    }
     56
     57    ASSERT_NOT_REACHED();
     58    return 0;
    6059}
    6160
     
    6362{
    6463    ASSERT(!isStatic());
    65     checkConsistency();
    6664
    6765    if (isIdentifier())
    6866        Identifier::remove(this);
    6967
    70     if (bufferOwnership() != BufferInternal) {
    71         if (bufferOwnership() == BufferOwned)
    72             fastFree(m_data);
    73         else if (bufferOwnership() == BufferSubstring)
    74             m_dataBuffer.asPtr<UStringImpl*>()->deref();
    75         else {
    76             ASSERT(bufferOwnership() == BufferShared);
    77             m_dataBuffer.asPtr<SharedUChar*>()->deref();
    78         }
     68    switch (bufferOwnership()) {
     69    case BufferInternal:
     70        return;
     71    case BufferOwned:
     72        fastFree(m_data);
     73        return;
     74    case BufferSubstring:
     75        m_bufferSubstring->deref();
     76        return;
     77    case BufferShared:
     78        m_bufferSubstring->deref();
    7979    }
    8080}
    8181
    82 }
     82} // namespace JSC
  • trunk/JavaScriptCore/runtime/UStringImpl.h

    r53323 r53392  
    4141typedef CrossThreadRefCounted<OwnFastMallocPtr<UChar> > SharedUChar;
    4242
    43 class UntypedPtrAndBitfield {
    44 public:
    45     UntypedPtrAndBitfield() {}
    46 
    47     UntypedPtrAndBitfield(void* ptrValue, uintptr_t bitValue)
    48         : m_value(reinterpret_cast<uintptr_t>(ptrValue) | bitValue)
    49 #ifndef NDEBUG
    50         , m_leaksPtr(ptrValue)
    51 #endif
    52     {
    53         ASSERT(ptrValue == asPtr<void*>());
    54         ASSERT((*this & ~s_alignmentMask) == bitValue);
    55     }
    56 
    57     template<typename T>
    58     T asPtr() const { return reinterpret_cast<T>(m_value & s_alignmentMask); }
    59 
    60     UntypedPtrAndBitfield& operator&=(uintptr_t bits)
    61     {
    62         m_value &= bits | s_alignmentMask;
    63         return *this;
    64     }
    65 
    66     UntypedPtrAndBitfield& operator|=(uintptr_t bits)
    67     {
    68         m_value |= bits & ~s_alignmentMask;
    69         return *this;
    70     }
    71 
    72     uintptr_t operator&(uintptr_t mask) const
    73     {
    74         return m_value & mask & ~s_alignmentMask;
    75     }
    76 
    77 private:
    78     static const uintptr_t s_alignmentMask = ~static_cast<uintptr_t>(0x7);
    79     uintptr_t m_value;
    80 #ifndef NDEBUG
    81         void* m_leaksPtr; // Only used to allow tools like leaks on OSX to detect that the memory is referenced.
    82 #endif
    83 };
    84 
    8543class UStringImpl : Noncopyable {
    8644public:
     
    10664    {
    10765        ASSERT(rep);
    108         rep->checkConsistency();
    109         return adoptRef(new UStringImpl(rep->m_data + offset, length, rep->bufferOwnerString()));
     66        if (rep->bufferOwnership() == BufferSubstring)
     67            return adoptRef(new UStringImpl(rep->m_data + offset, length, rep->m_bufferSubstring));
     68        return adoptRef(new UStringImpl(rep->m_data + offset, length, rep));
    11069    }
    11170
     
    152111        // For substrings, return the cost of the base string.
    153112        if (bufferOwnership() == BufferSubstring)
    154             return m_dataBuffer.asPtr<UStringImpl*>()->cost();
    155 
    156         if (m_dataBuffer & s_reportedCostBit)
     113            return m_bufferSubstring->cost();
     114        if (m_refCountAndFlags & s_refCountFlagHasReportedCost)
    157115            return 0;
    158         m_dataBuffer |= s_reportedCostBit;
     116        ASSERT(!isStatic());
     117        m_refCountAndFlags |= s_refCountFlagHasReportedCost;
    159118        return m_length;
    160119    }
     
    162121    unsigned existingHash() const { ASSERT(m_hash); return m_hash; } // fast path for Identifiers
    163122    void setHash(unsigned hash) { ASSERT(hash == computeHash(data(), m_length)); m_hash = hash; } // fast path for Identifiers
    164     bool isIdentifier() const { return m_isIdentifier; }
    165     void setIsIdentifier(bool isIdentifier) { m_isIdentifier = isIdentifier; }
    166 
    167     UStringImpl* ref() { m_refCount += s_refCountIncrement; return this; }
    168     ALWAYS_INLINE void deref() { if (!(m_refCount -= s_refCountIncrement)) delete this; }
     123    bool isIdentifier() const { return m_refCountAndFlags & s_refCountFlagIsIdentifier; }
     124    void setIsIdentifier(bool isIdentifier)
     125    {
     126        ASSERT(!isStatic());
     127        if (isIdentifier)
     128            m_refCountAndFlags |= s_refCountFlagIsIdentifier;
     129        else
     130            m_refCountAndFlags &= ~s_refCountFlagIsIdentifier;
     131    }
     132
     133    UStringImpl* ref() { m_refCountAndFlags += s_refCountIncrement; return this; }
     134    ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & s_refCountMask)) delete this; }
    169135
    170136    static void copyChars(UChar* destination, const UChar* source, unsigned numCharacters)
     
    183149    static UStringImpl& null() { return *s_null; }
    184150    static UStringImpl& empty() { return *s_empty; }
    185 
    186     ALWAYS_INLINE void checkConsistency() const
    187     {
    188         // There is no recursion of substrings.
    189         ASSERT(bufferOwnerString()->bufferOwnership() != BufferSubstring);
    190         // Static strings cannot be put in identifier tables, because they are globally shared.
    191         ASSERT(!isStatic() || !isIdentifier());
    192     }
    193151
    194152private:
     
    206164    UStringImpl(UChar* data, int length, BufferOwnership ownership)
    207165        : m_data(data)
    208         , m_length(length)
    209         , m_refCount(s_refCountIncrement)
    210         , m_hash(0)
    211         , m_isIdentifier(false)
    212         , m_dataBuffer(0, ownership)
     166        , m_buffer(0)
     167        , m_length(length)
     168        , m_refCountAndFlags(s_refCountIncrement | ownership)
     169        , m_hash(0)
    213170    {
    214171        ASSERT((ownership == BufferInternal) || (ownership == BufferOwned));
    215         checkConsistency();
    216172    }
    217173
     
    222178    UStringImpl(UChar* data, int length, StaticStringConstructType)
    223179        : m_data(data)
    224         , m_length(length)
    225         , m_refCount(s_staticRefCountInitialValue)
    226         , m_hash(0)
    227         , m_isIdentifier(false)
    228         , m_dataBuffer(0, BufferOwned)
    229     {
    230         checkConsistency();
     180        , m_buffer(0)
     181        , m_length(length)
     182        , m_refCountAndFlags(s_refCountFlagStatic | s_refCountFlagHasReportedCost | BufferOwned)
     183        , m_hash(0)
     184    {
    231185    }
    232186
     
    234188    UStringImpl(UChar* data, int length, PassRefPtr<UStringImpl> base)
    235189        : m_data(data)
    236         , m_length(length)
    237         , m_refCount(s_refCountIncrement)
    238         , m_hash(0)
    239         , m_isIdentifier(false)
    240         , m_dataBuffer(base.releaseRef(), BufferSubstring)
     190        , m_bufferSubstring(base.releaseRef())
     191        , m_length(length)
     192        , m_refCountAndFlags(s_refCountIncrement | BufferSubstring)
     193        , m_hash(0)
    241194    {
    242195        // Do use static strings as a base for substrings; UntypedPtrAndBitfield assumes
    243196        // that all pointers will be at least 8-byte aligned, we cannot guarantee that of
    244197        // UStringImpls that are not heap allocated.
    245         ASSERT(m_dataBuffer.asPtr<UStringImpl*>()->size());
    246         ASSERT(!m_dataBuffer.asPtr<UStringImpl*>()->isStatic());
    247         checkConsistency();
     198        ASSERT(m_bufferSubstring->size());
     199        ASSERT(!m_bufferSubstring->isStatic());
     200        ASSERT(m_bufferSubstring->bufferOwnership() != BufferSubstring);
    248201    }
    249202
     
    251204    UStringImpl(UChar* data, int length, PassRefPtr<SharedUChar> sharedBuffer)
    252205        : m_data(data)
    253         , m_length(length)
    254         , m_refCount(s_refCountIncrement)
    255         , m_hash(0)
    256         , m_isIdentifier(false)
    257         , m_dataBuffer(sharedBuffer.releaseRef(), BufferShared)
    258     {
    259         checkConsistency();
     206        , m_bufferShared(sharedBuffer.releaseRef())
     207        , m_length(length)
     208        , m_refCountAndFlags(s_refCountIncrement | BufferShared)
     209        , m_hash(0)
     210    {
    260211    }
    261212
     
    266217
    267218    // This number must be at least 2 to avoid sharing empty, null as well as 1 character strings from SmallStrings.
    268     static const int s_minLengthToShare = 10;
     219    static const unsigned s_minLengthToShare = 10;
    269220    static const unsigned s_copyCharsInlineCutOff = 20;
    270     static const uintptr_t s_bufferOwnershipMask = 3;
    271     static const uintptr_t s_reportedCostBit = 4;
     221
     222    bool isStatic() const { return m_refCountAndFlags & s_refCountFlagStatic; }
     223    BufferOwnership bufferOwnership() const { return static_cast<BufferOwnership>(m_refCountAndFlags & s_refCountMaskBufferOwnership); }
     224
    272225    // We initialize and increment/decrement the refCount for all normal (non-static) strings by the value 2.
    273226    // We initialize static strings with an odd number (specifically, 1), such that the refCount cannot reach zero.
    274     static const int s_refCountIncrement = 2;
    275     static const int s_staticRefCountInitialValue = 1;
    276 
    277     UStringImpl* bufferOwnerString() { return (bufferOwnership() == BufferSubstring) ? m_dataBuffer.asPtr<UStringImpl*>() :  this; }
    278     const UStringImpl* bufferOwnerString() const { return (bufferOwnership() == BufferSubstring) ? m_dataBuffer.asPtr<UStringImpl*>() :  this; }
    279     SharedUChar* baseSharedBuffer();
    280     unsigned bufferOwnership() const { return m_dataBuffer & s_bufferOwnershipMask; }
    281     bool isStatic() const { return m_refCount & 1; }
    282 
    283     // unshared data
     227    static const unsigned s_refCountMask = 0xFFFFFFF0;
     228    static const unsigned s_refCountIncrement = 0x20;
     229    static const unsigned s_refCountFlagStatic = 0x10;
     230    static const unsigned s_refCountFlagHasReportedCost = 0x8;
     231    static const unsigned s_refCountFlagIsIdentifier = 0x4;
     232    static const unsigned s_refCountMaskBufferOwnership = 0x3;
     233
    284234    UChar* m_data;
    285     int m_length;
    286     unsigned m_refCount;
    287     mutable unsigned m_hash : 31;
    288     mutable unsigned m_isIdentifier : 1;
    289     UntypedPtrAndBitfield m_dataBuffer;
     235    union {
     236        void* m_buffer;
     237        UStringImpl* m_bufferSubstring;
     238        SharedUChar* m_bufferShared;
     239    };
     240    unsigned m_length;
     241    unsigned m_refCountAndFlags;
     242    mutable unsigned m_hash;
    290243
    291244    JS_EXPORTDATA static UStringImpl* s_null;
  • trunk/JavaScriptCore/wtf/StringHashFunctions.h

    r52856 r53392  
    6161    hash ^= hash << 10;
    6262
    63     hash &= 0x7fffffff;
    64 
    6563    // this avoids ever returning a hash code of 0, since that is used to
    6664    // signal "hash not computed yet", using a value that is likely to be
    6765    // effectively the same as 0 when the low bits are masked
    6866    if (hash == 0)
    69         hash = 0x40000000;
     67        hash = 0x80000000;
    7068
    7169    return hash;
     
    10199    hash ^= hash << 10;
    102100
    103     hash &= 0x7fffffff;
    104 
    105101    // this avoids ever returning a hash code of 0, since that is used to
    106102    // signal "hash not computed yet", using a value that is likely to be
    107103    // effectively the same as 0 when the low bits are masked
    108104    if (hash == 0)
    109         hash = 0x40000000;
     105        hash = 0x80000000;
    110106
    111107    return hash;
     
    142138    hash ^= hash << 10;
    143139
    144     hash &= 0x7fffffff;
    145 
    146140    // This avoids ever returning a hash code of 0, since that is used to
    147141    // signal "hash not computed yet", using a value that is likely to be
    148142    // effectively the same as 0 when the low bits are masked.
    149143    if (hash == 0)
    150         hash = 0x40000000;
     144        hash = 0x80000000;
    151145
    152146    return hash;
Note: See TracChangeset for help on using the changeset viewer.