Changeset 54843 in webkit


Ignore:
Timestamp:
Feb 16, 2010 4:01:58 PM (14 years ago)
Author:
barraclough@apple.com
Message:

https://bugs.webkit.org/show_bug.cgi?id=34964
Leaks tool reports false memory leaks due to Rope implementation.

Reviewed by Oliver Hunt.

JavaScriptCore:

A rope is a recursive data structure where each node in the rope holds a set of
pointers, each of which may reference either a string (in UStringImpl form) or
another rope node. A low bit in each pointer is used to distinguish between
rope & string elements, in a fashion similar to the recently-removed
PtrAndFlags class (see https://bugs.webkit.org/show_bug.cgi?id=33731 ). Again,
this causes a problem for Leaks – refactor to remove the magic pointer
mangling.

Move Rope out from JSString.h and rename to URopeImpl, to match UStringImpl.
Give UStringImpl and URopeImpl a common parent class, UStringOrRopeImpl.
Repurpose an otherwise invalid permutation to flags (static & should report
memory cost) to identify ropes.

This allows us to change the rope's fibers to interrogate the object rather
than storing a bool within the low bits of the pointer (or in some cases the
use of a common parent class removes the need to determine the type at all -
there is a common interface to ref or get the length of either ropes or strings).

  • API/JSClassRef.cpp:

(OpaqueJSClass::OpaqueJSClass):
(OpaqueJSClassContextData::OpaqueJSClassContextData):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::keyForCharacterSwitch):

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::privateExecute):

  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • runtime/ArrayPrototype.cpp:

(JSC::arrayProtoFuncToString):

  • runtime/Identifier.cpp:

(JSC::Identifier::equal):
(JSC::Identifier::addSlowCase):

  • runtime/JSString.cpp:

(JSC::JSString::resolveRope):

  • runtime/JSString.h:

(JSC::):
(JSC::RopeBuilder::JSString):
(JSC::RopeBuilder::~JSString):
(JSC::RopeBuilder::appendStringInConstruct):
(JSC::RopeBuilder::appendValueInConstructAndIncrementLength):
(JSC::RopeBuilder::JSStringFinalizerStruct::JSStringFinalizerStruct):
(JSC::RopeBuilder::JSStringFinalizerStruct::):

  • runtime/UString.cpp:

(JSC::UString::toStrictUInt32):
(JSC::equal):

  • runtime/UString.h:

(JSC::UString::isEmpty):
(JSC::UString::size):

  • runtime/UStringImpl.cpp:

(JSC::URopeImpl::derefFibersNonRecursive):
(JSC::URopeImpl::destructNonRecursive):

  • runtime/UStringImpl.h:

(JSC::UStringOrRopeImpl::isRope):
(JSC::UStringOrRopeImpl::length):
(JSC::UStringOrRopeImpl::ref):
(JSC::UStringOrRopeImpl::):
(JSC::UStringOrRopeImpl::operator new):
(JSC::UStringOrRopeImpl::UStringOrRopeImpl):
(JSC::UStringImpl::adopt):
(JSC::UStringImpl::createUninitialized):
(JSC::UStringImpl::tryCreateUninitialized):
(JSC::UStringImpl::data):
(JSC::UStringImpl::cost):
(JSC::UStringImpl::deref):
(JSC::UStringImpl::UStringImpl):
(JSC::UStringImpl::):
(JSC::URopeImpl::tryCreateUninitialized):
(JSC::URopeImpl::initializeFiber):
(JSC::URopeImpl::fiberCount):
(JSC::URopeImpl::fibers):
(JSC::URopeImpl::deref):
(JSC::URopeImpl::URopeImpl):
(JSC::URopeImpl::hasOneRef):
(JSC::UStringOrRopeImpl::deref):

WebCore:

Renamed cUStringImpl::size() to UStringImpl::size()UStringImpl::length()
(matches WebCore::StringImpl).

  • bridge/jni/jsc/JavaStringJSC.h:

(JSC::Bindings::JavaStringImpl::length):

  • platform/text/AtomicString.cpp:

(WebCore::AtomicString::add):
(WebCore::AtomicString::find):

Location:
trunk
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/API/JSClassRef.cpp

    r54554 r54843  
    8383                // Use a local variable here to sidestep an RVCT compiler bug.
    8484                StaticValueEntry* entry = new StaticValueEntry(staticValue->getProperty, staticValue->setProperty, staticValue->attributes);
    85                 m_staticValues->add(valueName.rep()->ref(), entry);
     85                UStringImpl* impl = valueName.rep();
     86                impl->ref();
     87                m_staticValues->add(impl, entry);
    8688            }
    8789            ++staticValue;
     
    9698                // Use a local variable here to sidestep an RVCT compiler bug.
    9799                StaticFunctionEntry* entry = new StaticFunctionEntry(staticFunction->callAsFunction, staticFunction->attributes);
    98                 m_staticFunctions->add(functionName.rep()->ref(), entry);
     100                UStringImpl* impl = functionName.rep();
     101                impl->ref();
     102                m_staticFunctions->add(impl, entry);
    99103            }
    100104            ++staticFunction;
     
    168172            // Use a local variable here to sidestep an RVCT compiler bug.
    169173            StaticValueEntry* entry = new StaticValueEntry(it->second->getProperty, it->second->setProperty, it->second->attributes);
    170             staticValues->add(UString::Rep::create(it->first->data(), it->first->size()), entry);
     174            staticValues->add(UString::Rep::create(it->first->data(), it->first->length()), entry);
    171175        }
    172176    } else
     
    180184            // Use a local variable here to sidestep an RVCT compiler bug.
    181185            StaticFunctionEntry* entry = new StaticFunctionEntry(it->second->callAsFunction, it->second->attributes);
    182             staticFunctions->add(UString::Rep::create(it->first->data(), it->first->size()), entry);
     186            staticFunctions->add(UString::Rep::create(it->first->data(), it->first->length()), entry);
    183187        }
    184188           
  • trunk/JavaScriptCore/ChangeLog

    r54809 r54843  
     12010-02-16  Gavin Barraclough  <barraclough@apple.com>
     2
     3        Reviewed by Oliver Hunt.
     4
     5        https://bugs.webkit.org/show_bug.cgi?id=34964
     6        Leaks tool reports false memory leaks due to Rope implementation.
     7
     8        A rope is a recursive data structure where each node in the rope holds a set of
     9        pointers, each of which may reference either a string (in UStringImpl form) or
     10        another rope node.  A low bit in each pointer is used to distinguish between
     11        rope & string elements, in a fashion similar to the recently-removed
     12        PtrAndFlags class (see https://bugs.webkit.org/show_bug.cgi?id=33731 ).  Again,
     13        this causes a problem for Leaks – refactor to remove the magic pointer
     14        mangling.
     15
     16        Move Rope out from JSString.h and rename to URopeImpl, to match UStringImpl.
     17        Give UStringImpl and URopeImpl a common parent class, UStringOrRopeImpl.
     18        Repurpose an otherwise invalid permutation to flags (static & should report
     19        memory cost) to identify ropes.
     20
     21        This allows us to change the rope's fibers to interrogate the object rather
     22        than storing a bool within the low bits of the pointer (or in some cases the
     23        use of a common parent class removes the need to determine the type at all -
     24        there is a common interface to ref or get the length of either ropes or strings).
     25
     26        * API/JSClassRef.cpp:
     27        (OpaqueJSClass::OpaqueJSClass):
     28        (OpaqueJSClassContextData::OpaqueJSClassContextData):
     29        * bytecompiler/BytecodeGenerator.cpp:
     30        (JSC::keyForCharacterSwitch):
     31        * interpreter/Interpreter.cpp:
     32        (JSC::Interpreter::privateExecute):
     33        * jit/JITStubs.cpp:
     34        (JSC::DEFINE_STUB_FUNCTION):
     35        * runtime/ArrayPrototype.cpp:
     36        (JSC::arrayProtoFuncToString):
     37        * runtime/Identifier.cpp:
     38        (JSC::Identifier::equal):
     39        (JSC::Identifier::addSlowCase):
     40        * runtime/JSString.cpp:
     41        (JSC::JSString::resolveRope):
     42        * runtime/JSString.h:
     43        (JSC::):
     44        (JSC::RopeBuilder::JSString):
     45        (JSC::RopeBuilder::~JSString):
     46        (JSC::RopeBuilder::appendStringInConstruct):
     47        (JSC::RopeBuilder::appendValueInConstructAndIncrementLength):
     48        (JSC::RopeBuilder::JSStringFinalizerStruct::JSStringFinalizerStruct):
     49        (JSC::RopeBuilder::JSStringFinalizerStruct::):
     50        * runtime/UString.cpp:
     51        (JSC::UString::toStrictUInt32):
     52        (JSC::equal):
     53        * runtime/UString.h:
     54        (JSC::UString::isEmpty):
     55        (JSC::UString::size):
     56        * runtime/UStringImpl.cpp:
     57        (JSC::URopeImpl::derefFibersNonRecursive):
     58        (JSC::URopeImpl::destructNonRecursive):
     59        * runtime/UStringImpl.h:
     60        (JSC::UStringOrRopeImpl::isRope):
     61        (JSC::UStringOrRopeImpl::length):
     62        (JSC::UStringOrRopeImpl::ref):
     63        (JSC::UStringOrRopeImpl::):
     64        (JSC::UStringOrRopeImpl::operator new):
     65        (JSC::UStringOrRopeImpl::UStringOrRopeImpl):
     66        (JSC::UStringImpl::adopt):
     67        (JSC::UStringImpl::createUninitialized):
     68        (JSC::UStringImpl::tryCreateUninitialized):
     69        (JSC::UStringImpl::data):
     70        (JSC::UStringImpl::cost):
     71        (JSC::UStringImpl::deref):
     72        (JSC::UStringImpl::UStringImpl):
     73        (JSC::UStringImpl::):
     74        (JSC::URopeImpl::tryCreateUninitialized):
     75        (JSC::URopeImpl::initializeFiber):
     76        (JSC::URopeImpl::fiberCount):
     77        (JSC::URopeImpl::fibers):
     78        (JSC::URopeImpl::deref):
     79        (JSC::URopeImpl::URopeImpl):
     80        (JSC::URopeImpl::hasOneRef):
     81        (JSC::UStringOrRopeImpl::deref):
     82
    1832010-02-15  Gabor Loki  <loki@webkit.org>
    284
  • trunk/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r51801 r54843  
    19411941    ASSERT(node->isString());
    19421942    UString::Rep* clause = static_cast<StringNode*>(node)->value().ustring().rep();
    1943     ASSERT(clause->size() == 1);
     1943    ASSERT(clause->length() == 1);
    19441944   
    19451945    int32_t key = clause->data()[0];
  • trunk/JavaScriptCore/interpreter/Interpreter.cpp

    r53516 r54843  
    29252925        else {
    29262926            UString::Rep* value = asString(scrutinee)->value(callFrame).rep();
    2927             if (value->size() != 1)
     2927            if (value->length() != 1)
    29282928                vPC += defaultOffset;
    29292929            else
  • trunk/JavaScriptCore/jit/JITStubs.cpp

    r54809 r54843  
    30243024    if (scrutinee.isString()) {
    30253025        UString::Rep* value = asString(scrutinee)->value(callFrame).rep();
    3026         if (value->size() == 1)
     3026        if (value->length() == 1)
    30273027            result = codeBlock->characterSwitchJumpTable(tableIndex).ctiForValue(value->data()[0]).executableAddress();
    30283028    }
  • trunk/JavaScriptCore/runtime/ArrayPrototype.cpp

    r54571 r54843  
    202202            buffer.append(',');
    203203        if (RefPtr<UString::Rep> rep = strBuffer[i])
    204             buffer.append(rep->data(), rep->size());
     204            buffer.append(rep->data(), rep->length());
    205205    }
    206206    ASSERT(buffer.size() == totalSize);
  • trunk/JavaScriptCore/runtime/Identifier.cpp

    r54789 r54843  
    8080bool Identifier::equal(const UString::Rep* r, const char* s)
    8181{
    82     int length = r->size();
     82    int length = r->length();
    8383    const UChar* d = r->data();
    8484    for (int i = 0; i != length; ++i)
     
    9090bool Identifier::equal(const UString::Rep* r, const UChar* s, unsigned length)
    9191{
    92     if (r->size() != length)
     92    if (r->length() != length)
    9393        return false;
    9494    const UChar* d = r->data();
     
    210210{
    211211    ASSERT(!r->isIdentifier());
    212     if (r->size() == 1) {
     212    if (r->length() == 1) {
    213213        UChar c = r->data()[0];
    214214        if (c <= 0xFF)
     
    221221            }
    222222    }
    223     if (!r->size()) {
     223    if (!r->length()) {
    224224        UString::Rep::empty().hash();
    225225        return &UString::Rep::empty();
  • trunk/JavaScriptCore/runtime/JSString.cpp

    r54804 r54843  
    3131
    3232namespace JSC {
    33 
    34 void Rope::destructNonRecursive()
    35 {
    36     Vector<Rope*, 32> workQueue;
    37     Rope* rope = this;
    38 
    39     while (true) {
    40         unsigned length = rope->fiberCount();
    41         for (unsigned i = 0; i < length; ++i) {
    42             Fiber& fiber = rope->fibers(i);
    43             if (fiber.isString())
    44                 fiber.string()->deref();
    45             else {
    46                 Rope* nextRope = fiber.rope();
    47                 if (nextRope->hasOneRef())
    48                     workQueue.append(nextRope);
    49                 else
    50                     nextRope->deref();
    51             }
    52         }
    53         if (rope != this)
    54             fastFree(rope);
    55 
    56         if (workQueue.isEmpty())
    57             return;
    58 
    59         rope = workQueue.last();
    60         workQueue.removeLast();
    61     }
    62 }
    63 
    64 Rope::~Rope()
    65 {
    66     destructNonRecursive();
    67 }
    6833
    6934// Overview: this methods converts a JSString from holding a string in rope form
     
    7338// (since appending to the string is likely more common) - and as such resolving
    7439// in this fashion should minimize work queue size.  (If we built the queue forwards
    75 // we would likely have to place all of the constituent UString::Reps into the
     40// we would likely have to place all of the constituent UStringImpls into the
    7641// Vector before performing any concatenation, but by working backwards we likely
    7742// only fill the queue with the number of substrings at any given level in a
     
    8752    else {
    8853        for (unsigned i = 0; i < m_fiberCount; ++i) {
    89             m_fibers[i].deref();
    90             m_fibers[i] = static_cast<void*>(0);
     54            m_other.m_fibers[i]->deref();
     55            m_other.m_fibers[i] = 0;
    9156        }
    9257        m_fiberCount = 0;
     
    10267    Rope::Fiber currentFiber;
    10368    for (unsigned i = 0; i < (m_fiberCount - 1); ++i)
    104         workQueue.append(m_fibers[i]);
    105     currentFiber = m_fibers[m_fiberCount - 1];
     69        workQueue.append(m_other.m_fibers[i]);
     70    currentFiber = m_other.m_fibers[m_fiberCount - 1];
    10671    while (true) {
    107         if (currentFiber.isRope()) {
    108             Rope* rope = currentFiber.rope();
     72        if (currentFiber->isRope()) {
     73            Rope* rope = static_cast<URopeImpl*>(currentFiber);
    10974            // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber'
    11075            // (we will be working backwards over the rope).
     
    11479            currentFiber = rope->fibers(fiberCountMinusOne);
    11580        } else {
    116             UString::Rep* string = currentFiber.string();
    117             unsigned length = string->size();
     81            UStringImpl* string = static_cast<UStringImpl*>(currentFiber);
     82            unsigned length = string->length();
    11883            position -= length;
    11984            UStringImpl::copyChars(position, string->data(), length);
     
    12489                ASSERT(buffer == position);
    12590                for (unsigned i = 0; i < m_fiberCount; ++i) {
    126                     m_fibers[i].deref();
    127                     m_fibers[i] = static_cast<void*>(0);
     91                    m_other.m_fibers[i]->deref();
     92                    m_other.m_fibers[i] = 0;
    12893                }
    12994                m_fiberCount = 0;
  • trunk/JavaScriptCore/runtime/JSString.h

    r54804 r54843  
    3333namespace JSC {
    3434
    35     // FIXME: this class is on its way out into a different header.
    36     class Rope : public RefCounted<Rope> {
    37     public:
    38         // A Rope is composed from a set of smaller strings called Fibers.
    39         // Each Fiber in a rope is either UString::Rep or another Rope.
    40         class Fiber {
    41         public:
    42             Fiber() : m_value(0) {}
    43             Fiber(UString::Rep* string) : m_value(reinterpret_cast<intptr_t>(string)) {}
    44             Fiber(Rope* rope) : m_value(reinterpret_cast<intptr_t>(rope) | 1) {}
    45 
    46             Fiber(void* nonFiber) : m_value(reinterpret_cast<intptr_t>(nonFiber)) {}
    47 
    48             void deref()
    49             {
    50                 if (isRope())
    51                     rope()->deref();
    52                 else
    53                     string()->deref();
    54             }
    55 
    56             Fiber& ref()
    57             {
    58                 if (isString())
    59                     string()->ref();
    60                 else
    61                     rope()->ref();
    62                 return *this;
    63             }
    64 
    65             unsigned refAndGetLength()
    66             {
    67                 if (isString()) {
    68                     UString::Rep* rep = string();
    69                     return rep->ref()->size();
    70                 } else {
    71                     Rope* r = rope();
    72                     r->ref();
    73                     return r->length();
    74                 }
    75             }
    76 
    77             bool isRope() { return m_value & 1; }
    78             Rope* rope() { return reinterpret_cast<Rope*>(m_value & ~1); }
    79             bool isString() { return !isRope(); }
    80             UString::Rep* string() { return reinterpret_cast<UString::Rep*>(m_value); }
    81 
    82             void* nonFiber() { return reinterpret_cast<void*>(m_value); }
    83         private:
    84             intptr_t m_value;
    85         };
    86 
    87         // Creates a Rope comprising of 'fiberCount' Fibers.
    88         // The Rope is constructed in an uninitialized state - initialize must be called for each Fiber in the Rope.
    89         static PassRefPtr<Rope> tryCreateUninitialized(unsigned fiberCount)
    90         {
    91             void* allocation;
    92             if (tryFastMalloc(sizeof(Rope) + (fiberCount - 1) * sizeof(Fiber)).getValue(allocation))
    93                 return adoptRef(new (allocation) Rope(fiberCount));
    94             return 0;
    95         }
    96 
    97         ~Rope();
    98         void destructNonRecursive();
    99 
    100         void initializeFiber(unsigned &index, Fiber& fiber)
    101         {
    102             m_fibers[index++] = fiber;
    103             m_length += fiber.refAndGetLength();
    104         }
    105         void initializeFiber(unsigned &index, UStringImpl* impl)
    106         {
    107             m_fibers[index++] = Fiber(impl);
    108             m_length += impl->ref()->size();
    109         }
    110 
    111         unsigned fiberCount() { return m_fiberCount; }
    112         unsigned length() { return m_length; }
    113         Fiber& fibers(unsigned index) { return m_fibers[index]; }
    114 
    115     private:
    116         Rope(unsigned fiberCount) : m_fiberCount(fiberCount), m_length(0) {}
    117         void* operator new(size_t, void* inPlace) { return inPlace; }
    118        
    119         unsigned m_fiberCount;
    120         unsigned m_length;
    121         Fiber m_fibers[1];
    122     };
    123 
    12435    class JSString;
    12536
     
    15667        friend class JIT;
    15768        friend class JSGlobalData;
     69
     70        typedef URopeImpl Rope;
    15871
    15972        class RopeBuilder {
     
    18194                if (jsString->isRope()) {
    18295                    for (unsigned i = 0; i < jsString->m_fiberCount; ++i)
    183                         append(jsString->m_fibers[i]);
     96                        append(jsString->m_other.m_fibers[i]);
    18497                } else
    18598                    append(jsString->string());
     
    216129        JSString(JSGlobalData* globalData, PassRefPtr<UString::Rep> value, HasOtherOwnerType)
    217130            : JSCell(globalData->stringStructure.get())
    218             , m_length(value->size())
     131            , m_length(value->length())
    219132            , m_value(value)
    220133            , m_fiberCount(0)
     
    226139            , m_fiberCount(1)
    227140        {
    228             m_fibers[0] = rope.releaseRef();
     141            m_other.m_fibers[0] = rope.releaseRef();
    229142        }
    230143        // This constructor constructs a new string by concatenating s1 & s2.
     
    290203        {
    291204            // nasty hack because we can't union non-POD types
    292             m_fibers[0] = reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(finalizer));
    293             m_fibers[1] = context;
     205            m_other.m_finalizerCallback = finalizer;
     206            m_other.m_finalizerContext = context;
    294207            Heap::heap(this)->reportExtraMemoryCost(value.cost());
    295208        }
     
    299212            ASSERT(vptr() == JSGlobalData::jsStringVPtr);
    300213            for (unsigned i = 0; i < m_fiberCount; ++i)
    301                 m_fibers[i].deref();
    302 
    303             if (!m_fiberCount && m_fibers[0].nonFiber()) {
    304                 JSStringFinalizerCallback finalizer = reinterpret_cast<JSStringFinalizerCallback>(m_fibers[0].nonFiber());
    305                 finalizer(this, m_fibers[1].nonFiber());
    306             }
     214                m_other.m_fibers[i]->deref();
     215
     216            if (!m_fiberCount && m_other.m_finalizerCallback)
     217                m_other.m_finalizerCallback(this, m_other.m_finalizerContext);
    307218        }
    308219
     
    343254        void appendStringInConstruct(unsigned& index, const UString& string)
    344255        {
    345             m_fibers[index++] = Rope::Fiber(string.rep()->ref());
     256            UStringImpl* impl = string.rep();
     257            impl->ref();
     258            m_other.m_fibers[index++] = impl;
    346259        }
    347260
     
    349262        {
    350263            if (jsString->isRope()) {
    351                 for (unsigned i = 0; i < jsString->m_fiberCount; ++i)
    352                     m_fibers[index++] = jsString->m_fibers[i].ref();
     264                for (unsigned i = 0; i < jsString->m_fiberCount; ++i) {
     265                    Rope::Fiber fiber = jsString->m_other.m_fibers[i];
     266                    fiber->ref();
     267                    m_other.m_fibers[index++] = fiber;
     268                }
    353269            } else
    354270                appendStringInConstruct(index, jsString->string());
     
    365281            } else {
    366282                UString u(v.toString(exec));
    367                 m_fibers[index++] = Rope::Fiber(u.rep()->ref());
     283                UStringImpl* impl = u.rep();
     284                impl->ref();
     285                m_other.m_fibers[index++] = impl;
    368286                m_length += u.size();
    369287            }
     
    392310        mutable UString m_value;
    393311        mutable unsigned m_fiberCount;
    394         mutable Rope::Fiber m_fibers[s_maxInternalRopeLength];
     312        // This structure exists to support a temporary workaround for a GC issue.
     313        struct JSStringFinalizerStruct {
     314            JSStringFinalizerStruct() : m_finalizerCallback(0) {}
     315            union {
     316                mutable Rope::Fiber m_fibers[s_maxInternalRopeLength];
     317                struct {
     318                    JSStringFinalizerCallback m_finalizerCallback;
     319                    void* m_finalizerContext;
     320                };
     321            };
     322        } m_other;
    395323
    396324        bool isRope() const { return m_fiberCount; }
  • trunk/JavaScriptCore/runtime/UString.cpp

    r54789 r54843  
    496496
    497497    // Empty string is not OK.
    498     unsigned len = m_rep->size();
     498    unsigned len = m_rep->length();
    499499    if (len == 0)
    500500        return 0;
     
    713713bool equal(const UString::Rep* r, const UString::Rep* b)
    714714{
    715     unsigned length = r->size();
    716     if (length != b->size())
     715    unsigned length = r->length();
     716    if (length != b->length())
    717717        return false;
    718718    const UChar* d = r->data();
  • trunk/JavaScriptCore/runtime/UString.h

    r54795 r54843  
    133133
    134134        bool isNull() const { return m_rep == s_nullRep; }
    135         bool isEmpty() const { return !m_rep->size(); }
     135        bool isEmpty() const { return !m_rep->length(); }
    136136
    137137        bool is8Bit() const;
    138138
    139         unsigned size() const { return m_rep->size(); }
     139        unsigned size() const { return m_rep->length(); }
    140140
    141141        UChar operator[](unsigned pos) const;
  • trunk/JavaScriptCore/runtime/UStringImpl.cpp

    r54789 r54843  
    119119}
    120120
     121void URopeImpl::derefFibersNonRecursive(Vector<URopeImpl*, 32>& workQueue)
     122{
     123    unsigned length = fiberCount();
     124    for (unsigned i = 0; i < length; ++i) {
     125        Fiber& fiber = fibers(i);
     126        if (fiber->isRope()) {
     127            URopeImpl* nextRope = static_cast<URopeImpl*>(fiber);
     128            if (nextRope->hasOneRef())
     129                workQueue.append(nextRope);
     130            else
     131                nextRope->deref();
     132        } else
     133            static_cast<UStringImpl*>(fiber)->deref();
     134    }
    121135}
     136
     137void URopeImpl::destructNonRecursive()
     138{
     139    Vector<URopeImpl*, 32> workQueue;
     140
     141    derefFibersNonRecursive(workQueue);
     142    delete this;
     143
     144    while (!workQueue.isEmpty()) {
     145        URopeImpl* rope = workQueue.last();
     146        workQueue.removeLast();
     147        rope->derefFibersNonRecursive(workQueue);
     148        delete rope;
     149    }
     150}
     151
     152} // namespace JSC
  • trunk/JavaScriptCore/runtime/UStringImpl.h

    r54789 r54843  
    4141typedef CrossThreadRefCounted<OwnFastMallocPtr<UChar> > SharedUChar;
    4242
    43 class UStringImpl : Noncopyable {
     43class UStringOrRopeImpl : public Noncopyable {
     44public:
     45    bool isRope() { return (m_refCountAndFlags & s_refCountIsRope) == s_refCountIsRope; }
     46    unsigned length() const { return m_length; }
     47
     48    void ref() { m_refCountAndFlags += s_refCountIncrement; }
     49    inline void deref();
     50
     51protected:
     52    enum BufferOwnership {
     53        BufferInternal,
     54        BufferOwned,
     55        BufferSubstring,
     56        BufferShared,
     57    };
     58
     59    using Noncopyable::operator new;
     60    void* operator new(size_t, void* inPlace) { return inPlace; }
     61
     62    // For SmallStringStorage, which allocates an array and uses an in-place new.
     63    UStringOrRopeImpl() { }
     64
     65    UStringOrRopeImpl(unsigned length, BufferOwnership ownership)
     66        : m_refCountAndFlags(s_refCountIncrement | s_refCountFlagShouldReportedCost | ownership)
     67        , m_length(length)
     68    {
     69        ASSERT(!isRope());
     70    }
     71
     72    enum StaticStringConstructType { ConstructStaticString };
     73    UStringOrRopeImpl(unsigned length, StaticStringConstructType)
     74        : m_refCountAndFlags(s_refCountFlagStatic | BufferOwned)
     75        , m_length(length)
     76    {
     77        ASSERT(!isRope());
     78    }
     79
     80    enum RopeConstructType { ConstructRope };
     81    UStringOrRopeImpl(RopeConstructType)
     82        : m_refCountAndFlags(s_refCountIncrement | s_refCountIsRope)
     83        , m_length(0)
     84    {
     85        ASSERT(isRope());
     86    }
     87
     88    // The bottom 5 bits hold flags, the top 27 bits hold the ref count.
     89    // When dereferencing UStringImpls we check for the ref count AND the
     90    // static bit both being zero - static strings are never deleted.
     91    static const unsigned s_refCountMask = 0xFFFFFFE0;
     92    static const unsigned s_refCountIncrement = 0x20;
     93    static const unsigned s_refCountFlagStatic = 0x10;
     94    static const unsigned s_refCountFlagShouldReportedCost = 0x8;
     95    static const unsigned s_refCountFlagIsIdentifier = 0x4;
     96    static const unsigned s_refCountMaskBufferOwnership = 0x3;
     97    // Use an otherwise invalid permutation of flags (static & shouldReportedCost -
     98    // static strings do not set shouldReportedCost in the constructor, and this bit
     99    // is only ever cleared, not set) to identify objects that are ropes.
     100    static const unsigned s_refCountIsRope = s_refCountFlagStatic | s_refCountFlagShouldReportedCost;
     101
     102    unsigned m_refCountAndFlags;
     103    unsigned m_length;
     104};
     105
     106class UStringImpl : public UStringOrRopeImpl {
    44107public:
    45108    template<size_t inlineCapacity>
     
    48111        if (unsigned length = vector.size()) {
    49112            ASSERT(vector.data());
    50             return adoptRef(new UStringImpl(vector.releaseBuffer(), length, BufferOwned));
     113            return adoptRef(new UStringImpl(vector.releaseBuffer(), length));
    51114        }
    52115        return &empty();
     
    80143        UStringImpl* resultImpl = static_cast<UStringImpl*>(fastMalloc(sizeof(UChar) * length + sizeof(UStringImpl)));
    81144        output = reinterpret_cast<UChar*>(resultImpl + 1);
    82         return adoptRef(new(resultImpl) UStringImpl(output, length, BufferInternal));
     145        return adoptRef(new(resultImpl) UStringImpl(length));
    83146    }
    84147
     
    96159            return 0;
    97160        output = reinterpret_cast<UChar*>(resultImpl + 1);
    98         return adoptRef(new(resultImpl) UStringImpl(output, length, BufferInternal));
     161        return adoptRef(new(resultImpl) UStringImpl(length));
    99162    }
    100163
    101164    SharedUChar* sharedBuffer();
    102165    UChar* data() const { return m_data; }
    103     unsigned size() const { return m_length; }
    104166    size_t cost()
    105167    {
     
    108170            return m_bufferSubstring->cost();
    109171
    110         if (m_refCountAndFlags & s_refCountFlagHasReportedCost)
    111             return 0;
    112         m_refCountAndFlags |= s_refCountFlagHasReportedCost;
    113         return m_length;
     172        if (m_refCountAndFlags & s_refCountFlagShouldReportedCost) {
     173            m_refCountAndFlags &= ~s_refCountFlagShouldReportedCost;
     174            return m_length;
     175        }
     176        return 0;
    114177    }
    115178    unsigned hash() const { if (!m_hash) m_hash = computeHash(data(), m_length); return m_hash; }
     
    125188    }
    126189
    127     UStringImpl* ref() { m_refCountAndFlags += s_refCountIncrement; return this; }
    128     ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & s_refCountMask)) delete this; }
     190    ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & (s_refCountMask | s_refCountFlagStatic))) delete this; }
    129191
    130192    static void copyChars(UChar* destination, const UChar* source, unsigned numCharacters)
     
    152214
    153215private:
    154     enum BufferOwnership {
    155         BufferInternal,
    156         BufferOwned,
    157         BufferSubstring,
    158         BufferShared,
    159     };
    160 
    161216    // For SmallStringStorage, which allocates an array and uses an in-place new.
    162217    UStringImpl() { }
    163218
    164     // Used to construct normal strings with an internal or external buffer.
    165     UStringImpl(UChar* data, unsigned length, BufferOwnership ownership)
    166         : m_data(data)
     219    // Used to construct normal strings with an internal buffer.
     220    UStringImpl(unsigned length)
     221        : UStringOrRopeImpl(length, BufferInternal)
     222        , m_data(reinterpret_cast<UChar*>(this + 1))
    167223        , m_buffer(0)
    168         , m_length(length)
    169         , m_refCountAndFlags(s_refCountIncrement | ownership)
    170         , m_hash(0)
    171     {
    172         ASSERT((ownership == BufferInternal) || (ownership == BufferOwned));
     224        , m_hash(0)
     225    {
     226        checkConsistency();
     227    }
     228
     229    // Used to construct normal strings with an external buffer.
     230    UStringImpl(UChar* data, unsigned length)
     231        : UStringOrRopeImpl(length, BufferOwned)
     232        , m_data(data)
     233        , m_buffer(0)
     234        , m_hash(0)
     235    {
    173236        checkConsistency();
    174237    }
     
    177240    // This means that the static string will never be destroyed, which is important because
    178241    // static strings will be shared across threads & ref-counted in a non-threadsafe manner.
    179     enum StaticStringConstructType { ConstructStaticString };
    180242    UStringImpl(UChar* data, unsigned length, StaticStringConstructType)
    181         : m_data(data)
     243        : UStringOrRopeImpl(length, ConstructStaticString)
     244        , m_data(data)
    182245        , m_buffer(0)
    183         , m_length(length)
    184         , m_refCountAndFlags(s_refCountFlagStatic | BufferOwned)
    185246        , m_hash(0)
    186247    {
     
    190251    // Used to create new strings that are a substring of an existing string.
    191252    UStringImpl(UChar* data, unsigned length, PassRefPtr<UStringImpl> base)
    192         : m_data(data)
     253        : UStringOrRopeImpl(length, BufferSubstring)
     254        , m_data(data)
    193255        , m_bufferSubstring(base.releaseRef())
    194         , m_length(length)
    195         , m_refCountAndFlags(s_refCountIncrement | BufferSubstring)
    196256        , m_hash(0)
    197257    {
     
    199259        // that all pointers will be at least 8-byte aligned, we cannot guarantee that of
    200260        // UStringImpls that are not heap allocated.
    201         ASSERT(m_bufferSubstring->size());
     261        ASSERT(m_bufferSubstring->length());
    202262        ASSERT(!m_bufferSubstring->isStatic());
    203263        checkConsistency();
     
    206266    // Used to construct new strings sharing an existing shared buffer.
    207267    UStringImpl(UChar* data, unsigned length, PassRefPtr<SharedUChar> sharedBuffer)
    208         : m_data(data)
     268        : UStringOrRopeImpl(length, BufferShared)
     269        , m_data(data)
    209270        , m_bufferShared(sharedBuffer.releaseRef())
    210         , m_length(length)
    211         , m_refCountAndFlags(s_refCountIncrement | BufferShared)
    212         , m_hash(0)
    213     {
    214         checkConsistency();
    215     }
    216 
    217     using Noncopyable::operator new;
    218     void* operator new(size_t, void* inPlace) { return inPlace; }
     271        , m_hash(0)
     272    {
     273        checkConsistency();
     274    }
    219275
    220276    ~UStringImpl();
     
    223279    static const unsigned s_minLengthToShare = 10;
    224280    static const unsigned s_copyCharsInlineCutOff = 20;
    225     // We initialize and increment/decrement the refCount for all normal (non-static) strings by the value 2.
    226     // We initialize static strings with an odd number (specifically, 1), such that the refCount cannot reach zero.
    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;
    233281
    234282    UStringImpl* bufferOwnerString() { return (bufferOwnership() == BufferSubstring) ? m_bufferSubstring :  this; }
     
    245293        SharedUChar* m_bufferShared;
    246294    };
    247     unsigned m_length;
    248     unsigned m_refCountAndFlags;
    249295    mutable unsigned m_hash;
    250296
     
    253299    friend class JIT;
    254300    friend class SmallStringsStorage;
     301    friend class UStringOrRopeImpl;
    255302    friend void initializeUString();
    256303};
    257304
     305class URopeImpl : public UStringOrRopeImpl {
     306public:
     307    // A URopeImpl is composed from a set of smaller strings called Fibers.
     308    // Each Fiber in a rope is either UStringImpl or another URopeImpl.
     309    typedef UStringOrRopeImpl* Fiber;
     310
     311    // Creates a URopeImpl comprising of 'fiberCount' Fibers.
     312    // The URopeImpl is constructed in an uninitialized state - initialize must be called for each Fiber in the URopeImpl.
     313    static PassRefPtr<URopeImpl> tryCreateUninitialized(unsigned fiberCount)
     314    {
     315        void* allocation;
     316        if (tryFastMalloc(sizeof(URopeImpl) + (fiberCount - 1) * sizeof(Fiber)).getValue(allocation))
     317            return adoptRef(new (allocation) URopeImpl(fiberCount));
     318        return 0;
     319    }
     320
     321    void initializeFiber(unsigned &index, Fiber fiber)
     322    {
     323        m_fibers[index++] = fiber;
     324        fiber->ref();
     325        m_length += fiber->length();
     326    }
     327
     328    unsigned fiberCount() { return m_fiberCount; }
     329    Fiber& fibers(unsigned index) { return m_fibers[index]; }
     330
     331    ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & s_refCountMask)) destructNonRecursive(); }
     332
     333private:
     334    URopeImpl(unsigned fiberCount) : UStringOrRopeImpl(ConstructRope), m_fiberCount(fiberCount) {}
     335
     336    void destructNonRecursive();
     337    void derefFibersNonRecursive(Vector<URopeImpl*, 32>& workQueue);
     338
     339    bool hasOneRef() { return (m_refCountAndFlags & s_refCountMask) == s_refCountIncrement; }
     340
     341    unsigned m_fiberCount;
     342    Fiber m_fibers[1];
     343};
     344
     345inline void UStringOrRopeImpl::deref()
     346{
     347    m_refCountAndFlags -= s_refCountIncrement;
     348    if (!(m_refCountAndFlags & s_refCountMask)) {
     349        if (isRope())
     350            delete static_cast<URopeImpl*>(this);
     351        else if (!s_refCountFlagStatic)
     352            delete static_cast<UStringImpl*>(this);
     353    }
     354}
     355
    258356bool equal(const UStringImpl*, const UStringImpl*);
    259357
  • trunk/WebCore/ChangeLog

    r54841 r54843  
     12010-02-16  Gavin Barraclough  <barraclough@apple.com>
     2
     3        Reviewed by Oliver Hunt.
     4
     5        https://bugs.webkit.org/show_bug.cgi?id=34964
     6        Leaks tool reports false memory leaks due to Rope implementation.
     7
     8        Renamed cUStringImpl::size() to UStringImpl::size()UStringImpl::length()
     9        (matches WebCore::StringImpl).
     10
     11        * bridge/jni/jsc/JavaStringJSC.h:
     12        (JSC::Bindings::JavaStringImpl::length):
     13        * platform/text/AtomicString.cpp:
     14        (WebCore::AtomicString::add):
     15        (WebCore::AtomicString::find):
     16
    1172010-02-15  Jon Honeycutt  <jhoneycutt@apple.com>
    218
  • trunk/WebCore/bridge/jni/jsc/JavaStringJSC.h

    r53497 r54843  
    7070    }
    7171    const jchar* uchars() const { return (const jchar*)m_rep->data(); }
    72     int length() const { return m_rep->size(); }
     72    int length() const { return m_rep->length(); }
    7373    UString uString() const { return UString(m_rep); }
    7474
  • trunk/WebCore/platform/text/AtomicString.cpp

    r53429 r54843  
    249249
    250250    UString::Rep* string = identifier.ustring().rep();
    251     unsigned length = string->size();
     251    unsigned length = string->length();
    252252    if (!length)
    253253        return StringImpl::empty();
     
    266266
    267267    UString::Rep* string = ustring.rep();
    268     unsigned length = string->size();
     268    unsigned length = string->length();
    269269    if (!length)
    270270        return StringImpl::empty();
     
    283283
    284284    UString::Rep* string = identifier.ustring().rep();
    285     unsigned length = string->size();
     285    unsigned length = string->length();
    286286    if (!length)
    287287        return static_cast<AtomicStringImpl*>(StringImpl::empty());
Note: See TracChangeset for help on using the changeset viewer.