Ignore:
Timestamp:
Dec 21, 2009, 4:38:24 PM (15 years ago)
Author:
[email protected]
Message:

https://bugs.webkit.org/show_bug.cgi?id=32831
Replace UString::Rep implementation, following introduction of ropes to JSC.

Reviewed by Darin Adler.

JavaScriptCore:

  • Remove redundant overcapacity mechanisms.
  • Reduce memory cost of Rep's.
  • Add an inline storage mechanism akin to that in WebCore's StringImpl.

~1% Sunspider progression.

(JSC::JSString::resolveRope):

  • runtime/SmallStrings.cpp:

(JSC::SmallStringsStorage::SmallStringsStorage):

  • runtime/UString.cpp:

(JSC::initializeUString):
(JSC::createRep):
(JSC::UString::createFromUTF8):
(JSC::UString::createUninitialized):
(JSC::UString::spliceSubstringsWithSeparators):
(JSC::UString::replaceRange):
(JSC::UString::ascii):
(JSC::UString::operator=):
(JSC::UString::toStrictUInt32):
(JSC::equal):

  • runtime/UString.h:

(JSC::UString::isEmpty):
(JSC::UString::cost):
(JSC::makeString):

  • runtime/UStringImpl.cpp: Added.

(JSC::UStringImpl::baseSharedBuffer):
(JSC::UStringImpl::sharedBuffer):
(JSC::UStringImpl::destroy):
(JSC::UStringImpl::computeHash):

  • runtime/UStringImpl.h: Added.

(JSC::UntypedPtrAndBitfield::UntypedPtrAndBitfield):
(JSC::UntypedPtrAndBitfield::asPtr):
(JSC::UntypedPtrAndBitfield::operator&=):
(JSC::UntypedPtrAndBitfield::operator|=):
(JSC::UntypedPtrAndBitfield::operator&):
(JSC::UStringImpl::create):
(JSC::UStringImpl::createCopying):
(JSC::UStringImpl::createUninitialized):
(JSC::UStringImpl::data):
(JSC::UStringImpl::size):
(JSC::UStringImpl::cost):
(JSC::UStringImpl::hash):
(JSC::UStringImpl::computedHash):
(JSC::UStringImpl::setHash):
(JSC::UStringImpl::identifierTable):
(JSC::UStringImpl::setIdentifierTable):
(JSC::UStringImpl::ref):
(JSC::UStringImpl::deref):
(JSC::UStringImpl::allocChars):
(JSC::UStringImpl::copyChars):
(JSC::UStringImpl::computeHash):
(JSC::UStringImpl::null):
(JSC::UStringImpl::empty):
(JSC::UStringImpl::checkConsistency):
(JSC::UStringImpl::):
(JSC::UStringImpl::UStringImpl):
(JSC::UStringImpl::operator new):
(JSC::UStringImpl::bufferOwnerString):
(JSC::UStringImpl::bufferOwnership):
(JSC::UStringImpl::isStatic):

JavaScriptGlue:

  • ForwardingHeaders/wtf/PossiblyNull.h: Added.
    • add forwarding header.

WebCore:

  • ForwardingHeaders/runtime/UStringImpl.h: Added.
    • add forwarding header.
  • platform/text/StringImpl.cpp:

(WebCore::StringImpl::ustring):

  • order of arguments to UString::Rep constructor for shared strings changed.
File:
1 edited

Legend:

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

    r52346 r52463  
    2525
    2626#include "Collector.h"
     27#include "UStringImpl.h"
    2728#include <stdint.h>
    2829#include <string.h>
     
    4142    using WTF::PlacementNewAdopt;
    4243
    43     class IdentifierTable;
    44  
    4544    class CString {
    4645    public:
     
    7271    };
    7372
     73    bool operator==(const CString&, const CString&);
     74
    7475    typedef Vector<char, 32> CStringBuffer;
    7576
     
    7879
    7980    public:
    80         typedef CrossThreadRefCounted<OwnFastMallocPtr<UChar> > SharedUChar;
    81         struct BaseString;
    82         struct Rep : Noncopyable {
    83             friend class JIT;
    84 
    85             static PassRefPtr<Rep> create(UChar* buffer, int length)
    86             {
    87                 return adoptRef(new BaseString(buffer, length));
    88             }
    89 
    90             static PassRefPtr<Rep> createEmptyBuffer(size_t size)
    91             {
    92                 // Guard against integer overflow
    93                 if (size < (std::numeric_limits<size_t>::max() / sizeof(UChar))) {
    94                     void* buf = 0;
    95                     if (tryFastMalloc(size * sizeof(UChar)).getValue(buf))
    96                         return adoptRef(new BaseString(static_cast<UChar*>(buf), 0, size));
    97                 }
    98                 return adoptRef(new BaseString(0, 0, 0));
    99             }
    100 
    101             static PassRefPtr<Rep> createCopying(const UChar*, int);
    102             static PassRefPtr<Rep> create(PassRefPtr<Rep> base, int offset, int length);
    103 
    104             // Constructs a string from a UTF-8 string, using strict conversion (see comments in UTF8.h).
    105             // Returns UString::Rep::null for null input or conversion failure.
    106             static PassRefPtr<Rep> createFromUTF8(const char*);
    107 
    108             // Uses SharedUChar to have joint ownership over the UChar*.
    109             static PassRefPtr<Rep> create(UChar*, int, PassRefPtr<SharedUChar>);
    110 
    111             SharedUChar* sharedBuffer();
    112             void destroy();
    113 
    114             bool baseIsSelf() const { return m_identifierTableAndFlags.isFlagSet(BaseStringFlag); }
    115             UChar* data() const;
    116             int size() const { return len; }
    117 
    118             unsigned hash() const { if (_hash == 0) _hash = computeHash(data(), len); return _hash; }
    119             unsigned computedHash() const { ASSERT(_hash); return _hash; } // fast path for Identifiers
    120             void setHash(unsigned hash) { ASSERT(hash == computeHash(data(), len)); _hash = hash; } // fast path for Identifiers
    121 
    122             static unsigned computeHash(const UChar*, int length);
    123             static unsigned computeHash(const char*, int length);
    124             static unsigned computeHash(const char* s) { return computeHash(s, strlen(s)); }
    125 
    126             IdentifierTable* identifierTable() const { return m_identifierTableAndFlags.get(); }
    127             void setIdentifierTable(IdentifierTable* table) { ASSERT(!isStatic()); m_identifierTableAndFlags.set(table); }
    128 
    129             bool isStatic() const { return m_identifierTableAndFlags.isFlagSet(StaticFlag); }
    130             void setStatic(bool);
    131             void setBaseString(PassRefPtr<BaseString>);
    132             BaseString* baseString();
    133             const BaseString* baseString() const;
    134 
    135             Rep* ref() { ++rc; return this; }
    136             ALWAYS_INLINE void deref() { if (--rc == 0) destroy(); }
    137 
    138             void checkConsistency() const;
    139             enum UStringFlags {
    140                 StaticFlag,
    141                 BaseStringFlag
    142             };
    143 
    144             // unshared data
    145             int offset;
    146             int len;
    147             int rc; // For null and empty static strings, this field does not reflect a correct count, because ref/deref are not thread-safe. A special case in destroy() guarantees that these do not get deleted.
    148             mutable unsigned _hash;
    149             PtrAndFlags<IdentifierTable, UStringFlags> m_identifierTableAndFlags;
    150 
    151             static BaseString& null() { return *nullBaseString; }
    152             static BaseString& empty() { return *emptyBaseString; }
    153 
    154             bool reserveCapacity(int capacity);
    155 
    156         protected:
    157             // Constructor for use by BaseString subclass; they use the union with m_baseString for another purpose.
    158             Rep(int length)
    159                 : offset(0)
    160                 , len(length)
    161                 , rc(1)
    162                 , _hash(0)
    163                 , m_baseString(0)
    164             {
    165             }
    166 
    167             Rep(PassRefPtr<BaseString> base, int offsetInBase, int length)
    168                 : offset(offsetInBase)
    169                 , len(length)
    170                 , rc(1)
    171                 , _hash(0)
    172                 , m_baseString(base.releaseRef())
    173             {
    174                 checkConsistency();
    175             }
    176 
    177             union {
    178                 // If !baseIsSelf()
    179                 BaseString* m_baseString;
    180                 // If baseIsSelf()
    181                 SharedUChar* m_sharedBuffer;
    182             };
    183 
    184         private:
    185             // For SmallStringStorage which allocates an array and does initialization manually.
    186             Rep() { }
    187 
    188             friend class SmallStringsStorage;
    189             friend void initializeUString();
    190             JS_EXPORTDATA static BaseString* nullBaseString;
    191             JS_EXPORTDATA static BaseString* emptyBaseString;
    192         };
    193 
    194 
    195         struct BaseString : public Rep {
    196             bool isShared() { return rc != 1 || isBufferReadOnly(); }
    197             void setSharedBuffer(PassRefPtr<SharedUChar>);
    198 
    199             bool isBufferReadOnly()
    200             {
    201                 if (!m_sharedBuffer)
    202                     return false;
    203                 return slowIsBufferReadOnly();
    204             }
    205 
    206             // potentially shared data.
    207             UChar* buf;
    208             int preCapacity;
    209             int usedPreCapacity;
    210             int capacity;
    211             int usedCapacity;
    212 
    213             size_t reportedCost;
    214 
    215         private:
    216             BaseString(UChar* buffer, int length, int additionalCapacity = 0)
    217                 : Rep(length)
    218                 , buf(buffer)
    219                 , preCapacity(0)
    220                 , usedPreCapacity(0)
    221                 , capacity(length + additionalCapacity)
    222                 , usedCapacity(length)
    223                 , reportedCost(0)
    224             {
    225                 m_identifierTableAndFlags.setFlag(BaseStringFlag);
    226                 checkConsistency();
    227             }
    228 
    229             SharedUChar* sharedBuffer();
    230             bool slowIsBufferReadOnly();
    231 
    232             friend struct Rep;
    233             friend class SmallStringsStorage;
    234             friend void initializeUString();
    235         };
    236 
     81        typedef UStringImpl Rep;
     82   
    23783    public:
     84        // UString constructors passed char*s assume ISO Latin-1 encoding; for UTF8 use 'createFromUTF8', below.
    23885        UString();
    239         // Constructor for null-terminated ASCII string.
    240         UString(const char*);
    241         // Constructor for non-null-terminated ASCII string.
     86        UString(const char*); // Constructor for null-terminated string.
    24287        UString(const char*, int length);
    24388        UString(const UChar*, int length);
     
    261106        static UString createNonCopying(UChar* c, int length);
    262107        static UString createFromUTF8(const char*);
     108        static UString createUninitialized(unsigned length, UChar*& output);
    263109
    264110        static UString from(int);
     
    287133
    288134        UString replaceRange(int rangeStart, int RangeEnd, const UString& replacement) const;
    289 
    290         UString& append(const UString&);
    291         UString& append(const char*);
    292         UString& append(UChar);
    293         UString& append(char c) { return append(static_cast<UChar>(static_cast<unsigned char>(c))); }
    294         UString& append(const UChar*, int size);
    295135
    296136        bool getCString(CStringBuffer&) const;
     
    312152        UString& operator=(const char*c);
    313153
    314         UString& operator+=(const UString& s) { return append(s); }
    315         UString& operator+=(const char* s) { return append(s); }
    316 
    317154        const UChar* data() const { return m_rep->data(); }
    318155
    319         bool isNull() const { return (m_rep == &Rep::null()); }
    320         bool isEmpty() const { return (!m_rep->len); }
     156        bool isNull() const { return m_rep == &Rep::null(); }
     157        bool isEmpty() const { return !m_rep->size(); }
    321158
    322159        bool is8Bit() const;
     
    354191        }
    355192
    356         size_t cost() const;
    357 
    358         // Attempt to grow this string such that it can grow to a total length of 'capacity'
    359         // without reallocation.  This may fail a number of reasons - if the BasicString is
    360         // shared and another string is using part of the capacity beyond our end point, if
    361         // the realloc fails, or if this string is empty and has no storage.
    362         //
    363         // This method returns a boolean indicating success.
    364         bool reserveCapacity(int capacity)
    365         {
    366             return m_rep->reserveCapacity(capacity);
    367         }
     193        size_t cost() const { return m_rep->cost(); }
    368194
    369195    private:
    370         void expandCapacity(int requiredLength);
    371         void expandPreCapacity(int requiredPreCap);
    372196        void makeNull();
    373197
     
    377201        friend void initializeUString();
    378202        friend bool operator==(const UString&, const UString&);
    379         friend PassRefPtr<Rep> concatenate(Rep*, Rep*); // returns 0 if out of memory
    380     };
    381     PassRefPtr<UString::Rep> concatenate(UString::Rep*, UString::Rep*);
    382     PassRefPtr<UString::Rep> concatenate(UString::Rep*, int);
    383     PassRefPtr<UString::Rep> concatenate(UString::Rep*, double);
     203    };
    384204
    385205    inline bool operator==(const UString& s1, const UString& s2)
     
    429249    }
    430250
    431     bool operator==(const CString&, const CString&);
    432 
    433     inline UString operator+(const UString& s1, const UString& s2)
    434     {
    435         RefPtr<UString::Rep> result = concatenate(s1.rep(), s2.rep());
    436         return UString(result ? result.release() : UString::nullRep());
    437     }
    438 
    439251    int compare(const UString&, const UString&);
    440 
    441     bool equal(const UString::Rep*, const UString::Rep*);
    442 
    443     inline PassRefPtr<UString::Rep> UString::Rep::create(PassRefPtr<UString::Rep> rep, int offset, int length)
    444     {
    445         ASSERT(rep);
    446         rep->checkConsistency();
    447 
    448         int repOffset = rep->offset;
    449 
    450         PassRefPtr<BaseString> base = rep->baseString();
    451 
    452         ASSERT(-(offset + repOffset) <= base->usedPreCapacity);
    453         ASSERT(offset + repOffset + length <= base->usedCapacity);
    454 
    455         // Steal the single reference this Rep was created with.
    456         return adoptRef(new Rep(base, repOffset + offset, length));
    457     }
    458 
    459     inline UChar* UString::Rep::data() const
    460     {
    461         const BaseString* base = baseString();
    462         return base->buf + base->preCapacity + offset;
    463     }
    464 
    465     inline void UString::Rep::setStatic(bool v)
    466     {
    467         ASSERT(!identifierTable());
    468         if (v)
    469             m_identifierTableAndFlags.setFlag(StaticFlag);
    470         else
    471             m_identifierTableAndFlags.clearFlag(StaticFlag);
    472     }
    473 
    474     inline void UString::Rep::setBaseString(PassRefPtr<BaseString> base)
    475     {
    476         ASSERT(base != this);
    477         ASSERT(!baseIsSelf());
    478         m_baseString = base.releaseRef();
    479     }
    480 
    481     inline UString::BaseString* UString::Rep::baseString()
    482     {
    483         return !baseIsSelf() ? m_baseString : reinterpret_cast<BaseString*>(this) ;
    484     }
    485 
    486     inline const UString::BaseString* UString::Rep::baseString() const
    487     {
    488         return const_cast<Rep*>(this)->baseString();
    489     }
    490 
    491 #ifdef NDEBUG
    492     inline void UString::Rep::checkConsistency() const
    493     {
    494     }
    495 #endif
    496252
    497253    inline UString::UString()
     
    517273    static const int minShareSize = Heap::minExtraCost / sizeof(UChar);
    518274
    519     inline size_t UString::cost() const
    520     {
    521         BaseString* base = m_rep->baseString();
    522         size_t capacity = (base->capacity + base->preCapacity) * sizeof(UChar);
    523         size_t reportedCost = base->reportedCost;
    524         ASSERT(capacity >= reportedCost);
    525 
    526         size_t capacityDelta = capacity - reportedCost;
    527 
    528         if (capacityDelta < static_cast<size_t>(minShareSize))
    529             return 0;
    530 
    531         base->reportedCost = capacity;
    532 
    533         return capacityDelta;
    534     }
    535 
    536275    struct IdentifierRepHash : PtrHash<RefPtr<JSC::UString::Rep> > {
    537276        static unsigned hash(const RefPtr<JSC::UString::Rep>& key) { return key->computedHash(); }
     
    619358        UChar* buffer;
    620359        unsigned length = adapter1.length() + adapter2.length();
    621         if (!tryFastMalloc(length * sizeof(UChar)).getValue(buffer))
    622             return UString();
    623 
    624         UChar* result = buffer;
    625         adapter1.writeTo(result);
    626         result += adapter1.length();
    627         adapter2.writeTo(result);
    628 
    629         return UString::createNonCopying(buffer, length);
     360        UString resultString = UString::createUninitialized(length, buffer);
     361        if (!buffer)
     362            return UString();
     363
     364        UChar* result = buffer;
     365        adapter1.writeTo(result);
     366        result += adapter1.length();
     367        adapter2.writeTo(result);
     368
     369        return resultString;
    630370    }
    631371
     
    639379        UChar* buffer;
    640380        unsigned length = adapter1.length() + adapter2.length() + adapter3.length();
    641         if (!tryFastMalloc(length * sizeof(UChar)).getValue(buffer))
     381        UString resultString = UString::createUninitialized(length, buffer);
     382        if (!buffer)
    642383            return UString();
    643384
     
    649390        adapter3.writeTo(result);
    650391
    651         return UString::createNonCopying(buffer, length);
     392        return resultString;
    652393    }
    653394
     
    662403        UChar* buffer;
    663404        unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length();
    664         if (!tryFastMalloc(length * sizeof(UChar)).getValue(buffer))
     405        UString resultString = UString::createUninitialized(length, buffer);
     406        if (!buffer)
    665407            return UString();
    666408
     
    674416        adapter4.writeTo(result);
    675417
    676         return UString::createNonCopying(buffer, length);
     418        return resultString;
    677419    }
    678420
     
    688430        UChar* buffer;
    689431        unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length();
    690         if (!tryFastMalloc(length * sizeof(UChar)).getValue(buffer))
     432        UString resultString = UString::createUninitialized(length, buffer);
     433        if (!buffer)
    691434            return UString();
    692435
     
    702445        adapter5.writeTo(result);
    703446
    704         return UString::createNonCopying(buffer, length);
     447        return resultString;
    705448    }
    706449
     
    717460        UChar* buffer;
    718461        unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length() + adapter6.length();
    719         if (!tryFastMalloc(length * sizeof(UChar)).getValue(buffer))
     462        UString resultString = UString::createUninitialized(length, buffer);
     463        if (!buffer)
    720464            return UString();
    721465
     
    733477        adapter6.writeTo(result);
    734478
    735         return UString::createNonCopying(buffer, length);
     479        return resultString;
    736480    }
    737481
     
    749493        UChar* buffer;
    750494        unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length() + adapter6.length() + adapter7.length();
    751         if (!tryFastMalloc(length * sizeof(UChar)).getValue(buffer))
     495        UString resultString = UString::createUninitialized(length, buffer);
     496        if (!buffer)
    752497            return UString();
    753498
     
    767512        adapter7.writeTo(result);
    768513
    769         return UString::createNonCopying(buffer, length);
     514        return resultString;
    770515    }
    771516
     
    784529        UChar* buffer;
    785530        unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length() + adapter6.length() + adapter7.length() + adapter8.length();
    786         if (!tryFastMalloc(length * sizeof(UChar)).getValue(buffer))
     531        UString resultString = UString::createUninitialized(length, buffer);
     532        if (!buffer)
    787533            return UString();
    788534
     
    804550        adapter8.writeTo(result);
    805551
    806         return UString::createNonCopying(buffer, length);
     552        return resultString;
    807553    }
    808554
Note: See TracChangeset for help on using the changeset viewer.