Ignore:
Timestamp:
Feb 16, 2010, 4:01:58 PM (15 years ago)
Author:
[email protected]
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):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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; }
Note: See TracChangeset for help on using the changeset viewer.