Changeset 97827 in webkit


Ignore:
Timestamp:
Oct 18, 2011 7:54:29 PM (13 years ago)
Author:
ggaren@apple.com
Message:

Switched ropes from malloc memory to GC memory
https://bugs.webkit.org/show_bug.cgi?id=70364

Reviewed by Gavin Barraclough.

~1% SunSpider speedup. Neutral elsewhere. Removes one cause for strings
having C++ destructors.

  • heap/MarkStack.cpp:

(JSC::visitChildren): Call the JSString visitChildren function now,
since it's no longer a no-op.

  • runtime/JSString.cpp:

(JSC::JSString::~JSString): Moved this destructor out of line because
it's called virtually, so there's no value to inlining.

(JSC::JSString::RopeBuilder::expand): Switched RopeBuilder to be a thin
initializing wrapper around JSString. JSString now represents ropes
directly, rather than relying on an underlying malloc object.

(JSC::JSString::visitChildren): Visit our rope fibers, since they're GC
objects now.

(JSC::JSString::resolveRope):
(JSC::JSString::resolveRopeSlowCase):
(JSC::JSString::outOfMemory): Updated for operating on JSStrings instead
of malloc objects.

(JSC::JSString::replaceCharacter): Removed optimizations for substringing
ropes and replacing subsections of ropes. We want to reimplement versions
of these optimizations in the future, but this patch already has good
performance without them.

  • runtime/JSString.h:

(JSC::RopeBuilder::JSString):
(JSC::RopeBuilder::finishCreation):
(JSC::RopeBuilder::createNull):
(JSC::RopeBuilder::create):
(JSC::RopeBuilder::createHasOtherOwner):
(JSC::jsSingleCharacterString):
(JSC::jsSingleCharacterSubstring):
(JSC::jsNontrivialString):
(JSC::jsString):
(JSC::jsSubstring):
(JSC::jsOwnedString): Lots of mechanical changes here. The two important
things are: (1) The fibers in JSString::m_fibers are JSStrings now, not
malloc objects; (2) I simplified the JSString constructor interface to
only accept PassRefPtr<StringImpl>, instead of variations on that like
UString, reducing refcount churn.

  • runtime/JSValue.h:
  • runtime/JSValue.cpp:

(JSC::JSValue::toPrimitiveString): Updated this function to return a
JSString instead of a UString, since that's what clients want now.

  • runtime/Operations.cpp:

(JSC::jsAddSlowCase):

  • runtime/Operations.h:

(JSC::jsString):

  • runtime/SmallStrings.cpp:

(JSC::SmallStrings::createEmptyString): Updated for interface changes above.

  • runtime/StringConstructor.cpp:

(JSC::constructWithStringConstructor):

  • runtime/StringObject.h:

(JSC::StringObject::create): Don't create a new JSString if we already
have a JSString.

  • runtime/StringPrototype.cpp:

(JSC::stringProtoFuncConcat): Updated for interface changes above.

Location:
trunk/Source/JavaScriptCore
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r97826 r97827  
     12011-10-18  Geoffrey Garen  <ggaren@apple.com>
     2
     3        Switched ropes from malloc memory to GC memory
     4        https://bugs.webkit.org/show_bug.cgi?id=70364
     5
     6        Reviewed by Gavin Barraclough.
     7
     8        ~1% SunSpider speedup. Neutral elsewhere. Removes one cause for strings
     9        having C++ destructors.
     10
     11        * heap/MarkStack.cpp:
     12        (JSC::visitChildren): Call the JSString visitChildren function now,
     13        since it's no longer a no-op.
     14
     15        * runtime/JSString.cpp:
     16        (JSC::JSString::~JSString): Moved this destructor out of line because
     17        it's called virtually, so there's no value to inlining.
     18
     19        (JSC::JSString::RopeBuilder::expand): Switched RopeBuilder to be a thin
     20        initializing wrapper around JSString. JSString now represents ropes
     21        directly, rather than relying on an underlying malloc object.
     22
     23        (JSC::JSString::visitChildren): Visit our rope fibers, since they're GC
     24        objects now.
     25
     26        (JSC::JSString::resolveRope):
     27        (JSC::JSString::resolveRopeSlowCase):
     28        (JSC::JSString::outOfMemory): Updated for operating on JSStrings instead
     29        of malloc objects.
     30
     31        (JSC::JSString::replaceCharacter): Removed optimizations for substringing
     32        ropes and replacing subsections of ropes. We want to reimplement versions
     33        of these optimizations in the future, but this patch already has good
     34        performance without them.
     35
     36        * runtime/JSString.h:
     37        (JSC::RopeBuilder::JSString):
     38        (JSC::RopeBuilder::finishCreation):
     39        (JSC::RopeBuilder::createNull):
     40        (JSC::RopeBuilder::create):
     41        (JSC::RopeBuilder::createHasOtherOwner):
     42        (JSC::jsSingleCharacterString):
     43        (JSC::jsSingleCharacterSubstring):
     44        (JSC::jsNontrivialString):
     45        (JSC::jsString):
     46        (JSC::jsSubstring):
     47        (JSC::jsOwnedString): Lots of mechanical changes here. The two important
     48        things are: (1) The fibers in JSString::m_fibers are JSStrings now, not
     49        malloc objects; (2) I simplified the JSString constructor interface to
     50        only accept PassRefPtr<StringImpl>, instead of variations on that like
     51        UString, reducing refcount churn.
     52
     53        * runtime/JSValue.h:
     54        * runtime/JSValue.cpp:
     55        (JSC::JSValue::toPrimitiveString): Updated this function to return a
     56        JSString instead of a UString, since that's what clients want now.
     57
     58        * runtime/Operations.cpp:
     59        (JSC::jsAddSlowCase):
     60        * runtime/Operations.h:
     61        (JSC::jsString):
     62        * runtime/SmallStrings.cpp:
     63        (JSC::SmallStrings::createEmptyString): Updated for interface changes above.
     64
     65        * runtime/StringConstructor.cpp:
     66        (JSC::constructWithStringConstructor):
     67        * runtime/StringObject.h:
     68        (JSC::StringObject::create): Don't create a new JSString if we already
     69        have a JSString.
     70
     71        * runtime/StringPrototype.cpp:
     72        (JSC::stringProtoFuncConcat): Updated for interface changes above.
     73
    1742011-10-18  Gavin Barraclough  <barraclough@apple.com>
    275
  • trunk/Source/JavaScriptCore/heap/MarkStack.cpp

    r97644 r97827  
    103103    ASSERT(Heap::isMarked(cell));
    104104
    105     if (cell->vptr() == jsStringVPtr)
     105    if (cell->vptr() == jsStringVPtr) {
     106        JSString::visitChildren(const_cast<JSCell*>(cell), visitor);
    106107        return;
     108    }
    107109
    108110    if (cell->vptr() == jsFinalObjectVPtr) {
  • trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.h

    r96146 r97827  
    7575    macro(valueOf) \
    7676    macro(writable) \
    77     macro(displayName)
     77    macro(displayName) \
     78    macro(undefined)
    7879
    7980#define JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(macro) \
  • trunk/Source/JavaScriptCore/runtime/JSString.cpp

    r97537 r97827  
    3737const ClassInfo JSString::s_info = { "string", 0, 0, 0, CREATE_METHOD_TABLE(JSString) };
    3838
     39void JSString::RopeBuilder::expand()
     40{
     41    ASSERT(m_jsString->m_fiberCount == JSString::s_maxInternalRopeLength);
     42    JSString* jsString = m_jsString;
     43    m_jsString = jsStringBuilder(&m_globalData);
     44    append(jsString);
     45}
     46
     47JSString::~JSString()
     48{
     49    ASSERT(vptr() == JSGlobalData::jsStringVPtr);
     50}
     51
     52void JSString::visitChildren(JSCell* cell, SlotVisitor& visitor)
     53{
     54    JSString* thisObject = static_cast<JSString*>(cell);
     55    Base::visitChildren(thisObject, visitor);
     56    for (size_t i = 0; i < thisObject->m_fiberCount; ++i)
     57        visitor.append(&thisObject->m_fibers[i]);
     58}
     59
    3960void JSString::resolveRope(ExecState* exec) const
    4061{
     
    4970    }
    5071
    51     RopeImpl::Fiber currentFiber = m_fibers[0];
    52 
    53     if ((m_fiberCount > 2) || (RopeImpl::isRope(currentFiber))
    54         || ((m_fiberCount == 2) && (RopeImpl::isRope(m_fibers[1])))) {
    55         resolveRopeSlowCase(exec, buffer);
    56         return;
     72    for (size_t i = 0; i < m_fiberCount; ++i) {
     73        if (m_fibers[i]->isRope())
     74            return resolveRopeSlowCase(exec, buffer);
    5775    }
    5876
    5977    UChar* position = buffer;
    60     StringImpl* string = static_cast<StringImpl*>(currentFiber);
    61     unsigned length = string->length();
    62     StringImpl::copyChars(position, string->characters(), length);
    63 
    64     if (m_fiberCount > 1) {
    65         position += length;
    66         currentFiber = m_fibers[1];
    67         string = static_cast<StringImpl*>(currentFiber);
    68         length = string->length();
     78    for (size_t i = 0; i < m_fiberCount; ++i) {
     79        StringImpl* string = m_fibers[i]->m_value.impl();
     80        unsigned length = string->length();
    6981        StringImpl::copyChars(position, string->characters(), length);
    7082        position += length;
    7183    }
    72 
    7384    ASSERT((buffer + m_length) == position);
    74     for (unsigned i = 0; i < m_fiberCount; ++i) {
    75         RopeImpl::deref(m_fibers[i]);
    76         m_fibers[i] = 0;
    77     }
     85
    7886    m_fiberCount = 0;
    79 
    8087    ASSERT(!isRope());
    8188}
     
    97104    UChar* position = buffer + m_length;
    98105
    99     // Start with the current RopeImpl.
    100     Vector<RopeImpl::Fiber, 32> workQueue;
    101     RopeImpl::Fiber currentFiber;
     106    Vector<JSString*, 32> workQueue; // These strings are kept alive by the parent rope, so using a Vector is OK.
     107    JSString* currentFiber;
    102108    for (unsigned i = 0; i < (m_fiberCount - 1); ++i)
    103         workQueue.append(m_fibers[i]);
    104     currentFiber = m_fibers[m_fiberCount - 1];
     109        workQueue.append(m_fibers[i].get());
     110    currentFiber = m_fibers[m_fiberCount - 1].get();
    105111    while (true) {
    106         if (RopeImpl::isRope(currentFiber)) {
    107             RopeImpl* rope = static_cast<RopeImpl*>(currentFiber);
     112        if (currentFiber->isRope()) {
    108113            // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber'
    109114            // (we will be working backwards over the rope).
    110             unsigned fiberCountMinusOne = rope->fiberCount() - 1;
     115            unsigned fiberCountMinusOne = currentFiber->fiberCount() - 1;
    111116            for (unsigned i = 0; i < fiberCountMinusOne; ++i)
    112                 workQueue.append(rope->fibers()[i]);
    113             currentFiber = rope->fibers()[fiberCountMinusOne];
     117                workQueue.append(currentFiber->m_fibers[i].get());
     118            currentFiber = currentFiber->m_fibers[fiberCountMinusOne].get();
    114119        } else {
    115             StringImpl* string = static_cast<StringImpl*>(currentFiber);
     120            StringImpl* string = static_cast<StringImpl*>(currentFiber->m_value.impl());
    116121            unsigned length = string->length();
    117122            position -= length;
    118123            StringImpl::copyChars(position, string->characters(), length);
    119124
    120             // Was this the last item in the work queue?
    121125            if (workQueue.isEmpty()) {
    122                 // Create a string from the UChar buffer, clear the rope RefPtr.
     126                m_fiberCount = 0;
    123127                ASSERT(buffer == position);
    124                 for (unsigned i = 0; i < m_fiberCount; ++i) {
    125                     RopeImpl::deref(m_fibers[i]);
    126                     m_fibers[i] = 0;
    127                 }
    128                 m_fiberCount = 0;
    129                
    130128                ASSERT(!isRope());
    131129                return;
    132130            }
    133131
    134             // No! - set the next item up to process.
    135132            currentFiber = workQueue.last();
    136133            workQueue.removeLast();
     
    141138void JSString::outOfMemory(ExecState* exec) const
    142139{
    143     for (unsigned i = 0; i < m_fiberCount; ++i) {
    144         RopeImpl::deref(m_fibers[i]);
    145         m_fibers[i] = 0;
    146     }
    147140    m_fiberCount = 0;
    148141    ASSERT(!isRope());
     
    152145}
    153146
    154 // This function construsts a substring out of a rope without flattening by reusing the existing fibers.
    155 // This can reduce memory usage substantially. Since traversing ropes is slow the function will revert
    156 // back to flattening if the rope turns out to be long.
    157 JSString* JSString::substringFromRope(ExecState* exec, unsigned substringStart, unsigned substringLength)
    158 {
    159     ASSERT(isRope());
    160     ASSERT(substringLength);
    161    
    162     JSGlobalData* globalData = &exec->globalData();
    163 
    164     UString substringFibers[3];
    165    
    166     unsigned fiberCount = 0;
    167     unsigned substringFiberCount = 0;
    168     unsigned substringEnd = substringStart + substringLength;
    169     unsigned fiberEnd = 0;
    170 
    171     RopeIterator end;
    172     for (RopeIterator it(m_fibers.data(), m_fiberCount); it != end; ++it) {
    173         ++fiberCount;
    174         StringImpl* fiberString = *it;
    175         unsigned fiberStart = fiberEnd;
    176         fiberEnd = fiberStart + fiberString->length();
    177         if (fiberEnd <= substringStart)
    178             continue;
    179         unsigned copyStart = std::max(substringStart, fiberStart);
    180         unsigned copyEnd = std::min(substringEnd, fiberEnd);
    181         if (copyStart == fiberStart && copyEnd == fiberEnd)
    182             substringFibers[substringFiberCount++] = UString(fiberString);
    183         else
    184             substringFibers[substringFiberCount++] = UString(StringImpl::create(fiberString, copyStart - fiberStart, copyEnd - copyStart));
    185         if (fiberEnd >= substringEnd)
    186             break;
    187         if (fiberCount > substringFromRopeCutoff || substringFiberCount >= 3) {
    188             // This turned out to be a really inefficient rope. Just flatten it.
    189             resolveRope(exec);
    190             return jsSubstring(&exec->globalData(), m_value, substringStart, substringLength);
    191         }
    192     }
    193     ASSERT(substringFiberCount && substringFiberCount <= 3);
    194 
    195     if (substringLength == 1) {
    196         ASSERT(substringFiberCount == 1);
    197         UChar c = substringFibers[0][0];
    198         if (c <= maxSingleCharacterString)
    199             return globalData->smallStrings.singleCharacterString(globalData, c);
    200     }
    201     if (substringFiberCount == 1)
    202         return JSString::create(*globalData, substringFibers[0]);
    203     if (substringFiberCount == 2)
    204         return JSString::create(*globalData, substringFibers[0], substringFibers[1]);
    205     return JSString::create(*globalData, substringFibers[0], substringFibers[1], substringFibers[2]);
    206 }
    207 
    208147JSValue JSString::replaceCharacter(ExecState* exec, UChar character, const UString& replacement)
    209148{
    210     if (!isRope()) {
    211         size_t matchPosition = m_value.find(character);
    212         if (matchPosition == notFound)
    213             return JSValue(this);
    214         return jsString(exec, m_value.substringSharingImpl(0, matchPosition), replacement, m_value.substringSharingImpl(matchPosition + 1));
    215     }
    216 
    217     RopeIterator end;
    218    
    219     // Count total fibers and find matching string.
    220     size_t fiberCount = 0;
    221     StringImpl* matchString = 0;
    222     size_t matchPosition = notFound;
    223     for (RopeIterator it(m_fibers.data(), m_fiberCount); it != end; ++it) {
    224         ++fiberCount;
    225         if (matchString)
    226             continue;
    227 
    228         StringImpl* string = *it;
    229         matchPosition = string->find(character);
    230         if (matchPosition == notFound)
    231             continue;
    232         matchString = string;
    233     }
    234 
    235     if (!matchString)
    236         return this;
    237 
    238     RopeBuilder builder(replacement.length() ? fiberCount + 2 : fiberCount + 1);
    239     if (UNLIKELY(builder.isOutOfMemory()))
    240         return throwOutOfMemoryError(exec);
    241 
    242     for (RopeIterator it(m_fibers.data(), m_fiberCount); it != end; ++it) {
    243         StringImpl* string = *it;
    244         if (string != matchString) {
    245             builder.append(UString(string));
    246             continue;
    247         }
    248 
    249         builder.append(UString(string).substringSharingImpl(0, matchPosition));
    250         if (replacement.length())
    251             builder.append(replacement);
    252         builder.append(UString(string).substringSharingImpl(matchPosition + 1));
    253         matchString = 0;
    254     }
    255 
    256     JSGlobalData* globalData = &exec->globalData();
    257     return JSValue(JSString::create(*globalData, builder.release()));
     149    size_t matchPosition = value(exec).find(character);
     150    if (matchPosition == notFound)
     151        return JSValue(this);
     152    return jsString(exec, m_value.substringSharingImpl(0, matchPosition), replacement, value(exec).substringSharingImpl(matchPosition + 1));
    258153}
    259154
  • trunk/Source/JavaScriptCore/runtime/JSString.h

    r97537 r97827  
    6060    JSString* jsOwnedString(ExecState*, const UString&);
    6161
     62    JSString* jsStringBuilder(JSGlobalData*);
     63
    6264    class JS_EXPORTCLASS JSString : public JSCell {
    6365    public:
     
    6668        friend class SpecializedThunkJIT;
    6769        friend struct ThunkHelpers;
     70        friend JSString* jsStringBuilder(JSGlobalData*);
    6871
    6972        typedef JSCell Base;
     
    7174        class RopeBuilder {
    7275        public:
    73             RopeBuilder(unsigned fiberCount)
    74                 : m_index(0)
    75                 , m_rope(RopeImpl::tryCreateUninitialized(fiberCount))
     76            RopeBuilder(JSGlobalData& globalData)
     77                : m_globalData(globalData)
     78                , m_jsString(jsStringBuilder(&globalData))
    7679            {
    7780            }
    7881
    79             bool isOutOfMemory() { return !m_rope; }
    80 
    81             void append(RopeImpl::Fiber& fiber)
    82             {
    83                 ASSERT(m_rope);
    84                 m_rope->initializeFiber(m_index, fiber);
    85             }
    86             void append(const UString& string)
    87             {
    88                 ASSERT(m_rope);
    89                 m_rope->initializeFiber(m_index, string.impl());
    90             }
    9182            void append(JSString* jsString)
    9283            {
    93                 if (jsString->isRope()) {
    94                     for (unsigned i = 0; i < jsString->m_fiberCount; ++i)
    95                         append(jsString->m_fibers[i]);
    96                 } else
    97                     append(jsString->string());
     84                if (m_jsString->m_fiberCount == JSString::s_maxInternalRopeLength)
     85                    expand();
     86                m_jsString->m_fibers[m_jsString->m_fiberCount].set(m_globalData, m_jsString, jsString);
     87                m_jsString->m_fiberCount += 1;
     88                m_jsString->m_length += jsString->m_length;
    9889            }
    9990
    100             PassRefPtr<RopeImpl> release()
     91            JSString* release()
    10192            {
    102                 ASSERT(m_index == m_rope->fiberCount());
    103                 return m_rope.release();
     93                JSString* tmp = m_jsString;
     94                m_jsString = 0;
     95                return tmp;
    10496            }
    10597
    106             unsigned length() { return m_rope->length(); }
     98            unsigned length() { return m_jsString->m_length; }
    10799
    108100        private:
    109             unsigned m_index;
    110             RefPtr<RopeImpl> m_rope;
     101            void expand();
     102
     103            JSGlobalData& m_globalData;
     104            JSString* m_jsString;
    111105        };
    112106
    113         class RopeIterator {
    114             public:
    115                 RopeIterator() { }
    116 
    117                 RopeIterator(RopeImpl::Fiber* fibers, size_t fiberCount)
    118                 {
    119                     ASSERT(fiberCount);
    120                     m_workQueue.append(WorkItem(fibers, fiberCount));
    121                     skipRopes();
    122                 }
    123 
    124                 RopeIterator& operator++()
    125                 {
    126                     WorkItem& item = m_workQueue.last();
    127                     ASSERT(!RopeImpl::isRope(item.fibers[item.i]));
    128                     if (++item.i == item.fiberCount)
    129                         m_workQueue.removeLast();
    130                     skipRopes();
    131                     return *this;
    132                 }
    133 
    134                 StringImpl* operator*()
    135                 {
    136                     WorkItem& item = m_workQueue.last();
    137                     RopeImpl::Fiber fiber = item.fibers[item.i];
    138                     ASSERT(!RopeImpl::isRope(fiber));
    139                     return static_cast<StringImpl*>(fiber);
    140                 }
    141 
    142                 bool operator!=(const RopeIterator& other) const
    143                 {
    144                     return m_workQueue != other.m_workQueue;
    145                 }
    146 
    147             private:
    148                 struct WorkItem {
    149                     WorkItem(RopeImpl::Fiber* fibers, size_t fiberCount)
    150                         : fibers(fibers)
    151                         , fiberCount(fiberCount)
    152                         , i(0)
    153                     {
    154                     }
    155 
    156                     bool operator!=(const WorkItem& other) const
    157                     {
    158                         return fibers != other.fibers || fiberCount != other.fiberCount || i != other.i;
    159                     }
    160 
    161                     RopeImpl::Fiber* fibers;
    162                     size_t fiberCount;
    163                     size_t i;
    164                 };
    165 
    166                 void skipRopes()
    167                 {
    168                     if (m_workQueue.isEmpty())
    169                         return;
    170 
    171                     while (1) {
    172                         WorkItem& item = m_workQueue.last();
    173                         RopeImpl::Fiber fiber = item.fibers[item.i];
    174                         if (!RopeImpl::isRope(fiber))
    175                             break;
    176                         RopeImpl* rope = static_cast<RopeImpl*>(fiber);
    177                         if (++item.i == item.fiberCount)
    178                             m_workQueue.removeLast();
    179                         m_workQueue.append(WorkItem(rope->fibers(), rope->fiberCount()));
    180                     }
    181                 }
    182 
    183                 Vector<WorkItem, 16> m_workQueue;
    184         };
    185        
    186107    private:
    187         ALWAYS_INLINE JSString(JSGlobalData& globalData, const UString& value)
     108        JSString(JSGlobalData& globalData, PassRefPtr<StringImpl> value)
    188109            : JSCell(globalData, globalData.stringStructure.get())
    189             , m_length(value.length())
    190110            , m_value(value)
    191111            , m_fiberCount(0)
     
    193113        }
    194114
    195         enum HasOtherOwnerType { HasOtherOwner };
    196         JSString(JSGlobalData& globalData, const UString& value, HasOtherOwnerType)
     115        JSString(JSGlobalData& globalData)
    197116            : JSCell(globalData, globalData.stringStructure.get())
    198             , m_length(value.length())
    199             , m_value(value)
    200117            , m_fiberCount(0)
    201118        {
    202119        }
    203         JSString(JSGlobalData& globalData, PassRefPtr<StringImpl> value, HasOtherOwnerType)
    204             : JSCell(globalData, globalData.stringStructure.get())
    205             , m_length(value->length())
    206             , m_value(value)
    207             , m_fiberCount(0)
    208         {
    209         }
    210         JSString(JSGlobalData& globalData, PassRefPtr<RopeImpl> rope)
    211             : JSCell(globalData, globalData.stringStructure.get())
    212             , m_length(rope->length())
    213             , m_fiberCount(1)
    214         {
    215         }
    216         // This constructor constructs a new string by concatenating s1 & s2.
    217         // This should only be called with fiberCount <= 3.
    218         JSString(JSGlobalData& globalData, unsigned fiberCount, JSString* s1, JSString* s2)
    219             : JSCell(globalData, globalData.stringStructure.get())
    220             , m_length(s1->length() + s2->length())
    221             , m_fiberCount(fiberCount)
    222         {
    223         }
    224         // This constructor constructs a new string by concatenating s1 & s2.
    225         // This should only be called with fiberCount <= 3.
    226         JSString(JSGlobalData& globalData, unsigned fiberCount, JSString* s1, const UString& u2)
    227             : JSCell(globalData, globalData.stringStructure.get())
    228             , m_length(s1->length() + u2.length())
    229             , m_fiberCount(fiberCount)
    230         {
    231         }
    232         // This constructor constructs a new string by concatenating s1 & s2.
    233         // This should only be called with fiberCount <= 3.
    234         JSString(JSGlobalData& globalData, unsigned fiberCount, const UString& u1, JSString* s2)
    235             : JSCell(globalData, globalData.stringStructure.get())
    236             , m_length(u1.length() + s2->length())
    237             , m_fiberCount(fiberCount)
    238         {
    239         }
    240         JSString(ExecState* exec)
    241             : JSCell(exec->globalData(), exec->globalData().stringStructure.get())
    242             , m_length(0)
    243             , m_fiberCount(s_maxInternalRopeLength)
    244         {
    245         }
    246 
    247         // This constructor constructs a new string by concatenating u1 & u2.
    248         JSString(JSGlobalData& globalData, const UString& u1, const UString& u2)
    249             : JSCell(globalData, globalData.stringStructure.get())
    250             , m_length(u1.length() + u2.length())
    251             , m_fiberCount(2)
    252         {
    253         }
    254 
    255         // This constructor constructs a new string by concatenating u1, u2 & u3.
    256         JSString(JSGlobalData& globalData, const UString& u1, const UString& u2, const UString& u3)
    257             : JSCell(globalData, globalData.stringStructure.get())
    258             , m_length(u1.length() + u2.length() + u3.length())
    259             , m_fiberCount(s_maxInternalRopeLength)
    260         {
    261         }
    262 
    263         void finishCreation(JSGlobalData& globalData, const UString& value)
     120
     121        void finishCreation(JSGlobalData& globalData)
    264122        {
    265123            Base::finishCreation(globalData);
     124            m_length = 0;
     125        }
     126
     127        void finishCreation(JSGlobalData& globalData, size_t length)
     128        {
    266129            ASSERT(!m_value.isNull());
    267             Heap::heap(this)->reportExtraMemoryCost(value.impl()->cost());
    268         }
    269 
    270         void finishCreation(JSGlobalData& globalData)
    271         {
    272130            Base::finishCreation(globalData);
     131            m_length = length;
     132        }
     133
     134        void finishCreation(JSGlobalData& globalData, size_t length, size_t cost)
     135        {
    273136            ASSERT(!m_value.isNull());
    274         }
    275 
    276         void finishCreation(JSGlobalData& globalData, PassRefPtr<RopeImpl> rope)
    277         {
    278137            Base::finishCreation(globalData);
    279             m_fibers[0] = rope.leakRef();
    280         }
    281 
    282         void finishCreation(JSGlobalData& globalData, unsigned fiberCount, JSString* s1, JSString* s2)
     138            m_length = length;
     139            Heap::heap(this)->reportExtraMemoryCost(cost);
     140        }
     141
     142        void finishCreation(JSGlobalData& globalData, JSString* s1, JSString* s2)
    283143        {
    284144            Base::finishCreation(globalData);
    285             ASSERT_UNUSED(fiberCount, fiberCount <= s_maxInternalRopeLength);
    286             unsigned index = 0;
    287             appendStringInCreate(index, s1);
    288             appendStringInCreate(index, s2);
    289             ASSERT(fiberCount == index);
    290         }
    291 
    292         void finishCreation(JSGlobalData& globalData, unsigned fiberCount, JSString* s1, const UString& u2)
     145            m_length = s1->length() + s2->length();
     146            m_fiberCount = 2;
     147            m_fibers[0].set(globalData, this, s1);
     148            m_fibers[1].set(globalData, this, s2);
     149        }
     150
     151        void finishCreation(JSGlobalData& globalData, JSString* s1, JSString* s2, JSString* s3)
    293152        {
    294153            Base::finishCreation(globalData);
    295             ASSERT_UNUSED(fiberCount, fiberCount <= s_maxInternalRopeLength);
    296             unsigned index = 0;
    297             appendStringInCreate(index, s1);
    298             appendStringInCreate(index, u2);
    299             ASSERT(fiberCount == index);
    300         }
    301 
    302         void finishCreation(JSGlobalData& globalData, unsigned fiberCount, const UString& u1, JSString* s2)
    303         {
    304             Base::finishCreation(globalData);
    305             ASSERT_UNUSED(fiberCount, fiberCount <= s_maxInternalRopeLength);
    306             unsigned index = 0;
    307             appendStringInCreate(index, u1);
    308             appendStringInCreate(index, s2);
    309             ASSERT(fiberCount == index);
    310         }
    311 
    312         // Fills in the new string by concatenating v1, v2 & v3.
    313         // This should only be called with fiberCount <= 3 ... which since every
    314         // value must require a fiberCount of at least one implies that the length
    315         // for each value must be exactly 1!
    316         void finishCreation(ExecState* exec, JSValue v1, JSValue v2, JSValue v3)
    317         {
    318             Base::finishCreation(exec->globalData());
    319             unsigned index = 0;
    320             appendValueInCreateAndIncrementLength(exec, index, v1);
    321             appendValueInCreateAndIncrementLength(exec, index, v2);
    322             appendValueInCreateAndIncrementLength(exec, index, v3);
    323             ASSERT(index == s_maxInternalRopeLength);
    324         }
    325 
    326         void finishCreation(JSGlobalData& globalData, const UString& u1, const UString& u2)
    327         {
    328             Base::finishCreation(globalData);
    329             unsigned index = 0;
    330             appendStringInCreate(index, u1);
    331             appendStringInCreate(index, u2);
    332             ASSERT(index <= s_maxInternalRopeLength);
    333         }
    334 
    335         void finishCreation(JSGlobalData& globalData, const UString& u1, const UString& u2, const UString& u3)
    336         {
    337             Base::finishCreation(globalData);
    338             unsigned index = 0;
    339             appendStringInCreate(index, u1);
    340             appendStringInCreate(index, u2);
    341             appendStringInCreate(index, u3);
    342             ASSERT(index <= s_maxInternalRopeLength);
    343         }
    344 
    345     public:
    346         static JSString* create(JSGlobalData& globalData, const UString& value)
    347         {
    348             JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, value);
    349             newString->finishCreation(globalData, value);
    350             return newString;
    351         }
    352         static JSString* createHasOtherOwner(JSGlobalData& globalData, const UString& value)
    353         {
    354             JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, value, HasOtherOwner);
    355             newString->finishCreation(globalData, value);
    356             return newString;
    357         }
    358         static JSString* createHasOtherOwner(JSGlobalData& globalData, PassRefPtr<StringImpl> value)
    359         {
    360             JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, value, HasOtherOwner);
     154            m_length = s1->length() + s2->length() + s3->length();
     155            m_fiberCount = 3;
     156            m_fibers[0].set(globalData, this, s1);
     157            m_fibers[1].set(globalData, this, s2);
     158            m_fibers[2].set(globalData, this, s3);
     159        }
     160
     161        static JSString* createNull(JSGlobalData& globalData)
     162        {
     163            JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData);
    361164            newString->finishCreation(globalData);
    362165            return newString;
    363166        }
    364         static JSString* create(JSGlobalData& globalData, PassRefPtr<RopeImpl> rope)
    365         {
    366             RefPtr<RopeImpl> tempRope = rope;
    367             JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, tempRope);
    368             newString->finishCreation(globalData, tempRope);
     167
     168    public:
     169        static JSString* create(JSGlobalData& globalData, PassRefPtr<StringImpl> value)
     170        {
     171            ASSERT(value);
     172            size_t length = value->length();
     173            size_t cost = value->cost();
     174            JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, value);
     175            newString->finishCreation(globalData, length, cost);
    369176            return newString;
    370177        }
    371         static JSString* create(JSGlobalData& globalData, unsigned fiberCount, JSString* s1, JSString* s2)
    372         {
    373             JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, fiberCount, s1, s2);
    374             newString->finishCreation(globalData, fiberCount, s1, s2);
     178        static JSString* create(JSGlobalData& globalData, JSString* s1, JSString* s2)
     179        {
     180            JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData);
     181            newString->finishCreation(globalData, s1, s2);
    375182            return newString;
    376183        }
    377         static JSString* create(JSGlobalData& globalData, unsigned fiberCount, JSString* s1, const UString& u2)
    378         {
    379             JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, fiberCount, s1, u2);
    380             newString->finishCreation(globalData, fiberCount, s1, u2);
     184        static JSString* create(JSGlobalData& globalData, JSString* s1, JSString* s2, JSString* s3)
     185        {
     186            JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData);
     187            newString->finishCreation(globalData, s1, s2, s3);
    381188            return newString;
    382189        }
    383         static JSString* create(JSGlobalData& globalData, unsigned fiberCount, const UString& u1, JSString* s2)
    384         {
    385             JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, fiberCount, u1, s2);
    386             newString->finishCreation(globalData, fiberCount, u1, s2);
     190        static JSString* createHasOtherOwner(JSGlobalData& globalData, PassRefPtr<StringImpl> value)
     191        {
     192            ASSERT(value);
     193            size_t length = value->length();
     194            JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, value);
     195            newString->finishCreation(globalData, length);
    387196            return newString;
    388197        }
    389         static JSString* create(ExecState* exec, JSValue v1, JSValue v2, JSValue v3)
    390         {
    391             JSString* newString = new (allocateCell<JSString>(*exec->heap())) JSString(exec);
    392             newString->finishCreation(exec, v1, v2, v3);
    393             return newString;
    394         }
    395         static JSString* create(JSGlobalData& globalData, const UString& u1, const UString& u2)
    396         {
    397             JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, u1, u2);
    398             newString->finishCreation(globalData, u1, u2);
    399             return newString;
    400         }
    401         static JSString* create(JSGlobalData& globalData, const UString& u1, const UString& u2, const UString& u3)
    402         {
    403             JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, u1, u2, u3);
    404             newString->finishCreation(globalData, u1, u2, u3);
    405             return newString;
    406         }
    407 
    408         ~JSString()
    409         {
    410             ASSERT(vptr() == JSGlobalData::jsStringVPtr);
    411             for (unsigned i = 0; i < m_fiberCount; ++i)
    412                 RopeImpl::deref(m_fibers[i]);
    413         }
     198
     199        virtual ~JSString();
    414200
    415201        const UString& value(ExecState* exec) const
     
    455241        static const ClassInfo s_info;
    456242
     243        static void visitChildren(JSCell*, SlotVisitor&);
     244
    457245    private:
    458246        JSString(VPtrStealingHackType)
     
    465253        void resolveRopeSlowCase(ExecState*, UChar*) const;
    466254        void outOfMemory(ExecState*) const;
    467         JSString* substringFromRope(ExecState*, unsigned offset, unsigned length);
    468 
    469         void appendStringInCreate(unsigned& index, const UString& string)
    470         {
    471             StringImpl* impl = string.impl();
    472             impl->ref();
    473             m_fibers[index++] = impl;
    474             Heap::heap(this)->reportExtraMemoryCost(string.impl()->cost());
    475         }
    476 
    477         void appendStringInCreate(unsigned& index, JSString* jsString)
    478         {
    479             if (jsString->isRope()) {
    480                 for (unsigned i = 0; i < jsString->m_fiberCount; ++i) {
    481                     RopeImpl::Fiber fiber = jsString->m_fibers[i];
    482                     fiber->ref();
    483                     m_fibers[index++] = fiber;
    484                 }
    485             } else
    486                 appendStringInCreate(index, jsString->string());
    487         }
    488 
    489         void appendValueInCreateAndIncrementLength(ExecState* exec, unsigned& index, JSValue v)
    490         {
    491             if (v.isString()) {
    492                 ASSERT(v.asCell()->isString());
    493                 JSString* s = static_cast<JSString*>(v.asCell());
    494                 ASSERT(s->fiberCount() == 1);
    495                 appendStringInCreate(index, s);
    496                 m_length += s->length();
    497             } else {
    498                 UString u(v.toString(exec));
    499                 StringImpl* impl = u.impl();
    500                 impl->ref();
    501                 m_fibers[index++] = impl;
    502                 m_length += u.length();
    503             }
    504         }
    505255
    506256        virtual JSObject* toThisObject(ExecState*) const;
     
    519269        mutable UString m_value;
    520270        mutable unsigned m_fiberCount;
    521         mutable FixedArray<RopeImpl::Fiber, s_maxInternalRopeLength> m_fibers;
     271        mutable FixedArray<WriteBarrier<JSString>, s_maxInternalRopeLength> m_fibers;
    522272
    523273        bool isRope() const { return m_fiberCount; }
     
    526276
    527277        friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2);
    528         friend JSValue jsString(ExecState* exec, const UString& u1, JSString* s2);
    529         friend JSValue jsString(ExecState* exec, JSString* s1, const UString& u2);
    530278        friend JSValue jsString(ExecState* exec, Register* strings, unsigned count);
    531279        friend JSValue jsString(ExecState* exec, JSValue thisValue);
     
    560308        if (c <= maxSingleCharacterString)
    561309            return globalData->smallStrings.singleCharacterString(globalData, c);
    562         return fixupVPtr(globalData, JSString::create(*globalData, UString(&c, 1)));
     310        return fixupVPtr(globalData, JSString::create(*globalData, UString(&c, 1).impl()));
    563311    }
    564312
     
    570318        if (c <= maxSingleCharacterString)
    571319            return globalData->smallStrings.singleCharacterString(globalData, c);
    572         return fixupVPtr(globalData, JSString::create(*globalData, UString(StringImpl::create(s.impl(), offset, 1))));
     320        return fixupVPtr(globalData, JSString::create(*globalData, StringImpl::create(s.impl(), offset, 1)));
    573321    }
    574322
     
    578326        ASSERT(s[0]);
    579327        ASSERT(s[1]);
    580         return fixupVPtr(globalData, JSString::create(*globalData, s));
     328        return fixupVPtr(globalData, JSString::create(*globalData, UString(s).impl()));
    581329    }
    582330
     
    584332    {
    585333        ASSERT(s.length() > 1);
    586         return fixupVPtr(globalData, JSString::create(*globalData, s));
     334        return fixupVPtr(globalData, JSString::create(*globalData, s.impl()));
    587335    }
    588336
     
    606354                return globalData->smallStrings.singleCharacterString(globalData, c);
    607355        }
    608         return fixupVPtr(globalData, JSString::create(*globalData, s));
     356        return fixupVPtr(globalData, JSString::create(*globalData, s.impl()));
    609357    }
    610358
     
    617365        if (!length)
    618366            return globalData->smallStrings.emptyString(globalData);
    619         if (s->isRope())
    620             return s->substringFromRope(exec, offset, length);
    621         return jsSubstring(globalData, s->m_value, offset, length);
     367        return jsSubstring(globalData, s->value(exec), offset, length);
    622368    }
    623369
     
    634380                return globalData->smallStrings.singleCharacterString(globalData, c);
    635381        }
    636         return fixupVPtr(globalData, JSString::createHasOtherOwner(*globalData, UString(StringImpl::create(s.impl(), offset, length))));
     382        return fixupVPtr(globalData, JSString::createHasOtherOwner(*globalData, StringImpl::create(s.impl(), offset, length)));
    637383    }
    638384
     
    647393                return globalData->smallStrings.singleCharacterString(globalData, c);
    648394        }
    649         return fixupVPtr(globalData, JSString::createHasOtherOwner(*globalData, s));
     395        return fixupVPtr(globalData, JSString::createHasOtherOwner(*globalData, s.impl()));
     396    }
     397
     398    inline JSString* jsStringBuilder(JSGlobalData* globalData)
     399    {
     400        return fixupVPtr(globalData, JSString::createNull(*globalData));
    650401    }
    651402
     
    727478    }
    728479
    729     inline UString JSValue::toPrimitiveString(ExecState* exec) const
    730     {
    731         ASSERT(!isString());
    732         if (isInt32())
    733             return exec->globalData().numericStrings.add(asInt32());
    734         if (isDouble())
    735             return exec->globalData().numericStrings.add(asDouble());
    736         if (isTrue())
    737             return "true";
    738         if (isFalse())
    739             return "false";
    740         if (isNull())
    741             return "null";
    742         if (isUndefined())
    743             return "undefined";
    744         ASSERT(isCell());
    745         return asCell()->toPrimitive(exec, NoPreference).toString(exec);
    746     }
    747 
    748480} // namespace JSC
    749481
  • trunk/Source/JavaScriptCore/runtime/JSValue.cpp

    r94996 r97827  
    205205}
    206206
     207JSString* JSValue::toPrimitiveString(ExecState* exec) const
     208{
     209    if (isString())
     210        return static_cast<JSString*>(asCell());
     211    if (isInt32())
     212        return jsString(&exec->globalData(), exec->globalData().numericStrings.add(asInt32()));
     213    if (isDouble())
     214        return jsString(&exec->globalData(), exec->globalData().numericStrings.add(asDouble()));
     215    if (isTrue())
     216        return jsNontrivialString(exec, exec->propertyNames().trueKeyword.ustring());
     217    if (isFalse())
     218        return jsNontrivialString(exec, exec->propertyNames().falseKeyword.ustring());
     219    if (isNull())
     220        return jsNontrivialString(exec, exec->propertyNames().nullKeyword.ustring());
     221    if (isUndefined())
     222        return jsNontrivialString(exec, exec->propertyNames().undefined.ustring());
     223
     224    ASSERT(isCell());
     225    JSValue v = asCell()->toPrimitive(exec, NoPreference);
     226    if (v.isString())
     227        return static_cast<JSString*>(v.asCell());
     228    return jsString(&exec->globalData(), v.toString(exec));
     229}
     230
    207231} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/JSValue.h

    r97675 r97827  
    192192        double toNumber(ExecState*) const;
    193193        UString toString(ExecState*) const;
    194         UString toPrimitiveString(ExecState*) const;
     194        JSString* toPrimitiveString(ExecState*) const;
    195195        JSObject* toObject(ExecState*) const;
    196196        JSObject* toObject(ExecState*, JSGlobalObject*) const;
  • trunk/Source/JavaScriptCore/runtime/Operations.cpp

    r97097 r97827  
    5151        return p2.isString()
    5252            ? jsString(callFrame, asString(p1), asString(p2))
    53             : jsString(callFrame, asString(p1), p2.toString(callFrame));
     53            : jsString(callFrame, asString(p1), jsString(callFrame, p2.toString(callFrame)));
    5454    }
    5555    if (p2.isString())
    56         return jsString(callFrame, p1.toString(callFrame), asString(p2));
     56        return jsString(callFrame, jsString(callFrame, p1.toString(callFrame)), asString(p2));
    5757
    5858    return jsNumber(p1.toNumber(callFrame) + p2.toNumber(callFrame));
  • trunk/Source/JavaScriptCore/runtime/Operations.h

    r96673 r97827  
    3737    ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2)
    3838    {
     39        JSGlobalData& globalData = exec->globalData();
     40
    3941        unsigned length1 = s1->length();
    4042        if (!length1)
     
    4648            return throwOutOfMemoryError(exec);
    4749
    48         unsigned fiberCount = s1->fiberCount() + s2->fiberCount();
     50        return fixupVPtr(&globalData, JSString::create(globalData, s1, s2));
     51    }
     52
     53    ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, const UString& u2, const UString& u3)
     54    {
    4955        JSGlobalData* globalData = &exec->globalData();
    5056
    51         if (fiberCount <= JSString::s_maxInternalRopeLength)
    52             return JSString::create(*globalData, fiberCount, s1, s2);
    53 
    54         JSString::RopeBuilder ropeBuilder(fiberCount);
    55         if (UNLIKELY(ropeBuilder.isOutOfMemory()))
    56             return throwOutOfMemoryError(exec);
    57         ropeBuilder.append(s1);
    58         ropeBuilder.append(s2);
    59         return JSString::create(*globalData, ropeBuilder.release());
    60     }
    61 
    62     ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, JSString* s2)
    63     {
    64         unsigned length1 = u1.length();
    65         if (!length1)
    66             return s2;
    67         unsigned length2 = s2->length();
    68         if (!length2)
    69             return jsString(exec, u1);
    70         if ((length1 + length2) < length1)
    71             return throwOutOfMemoryError(exec);
    72 
    73         unsigned fiberCount = 1 + s2->fiberCount();
    74         JSGlobalData* globalData = &exec->globalData();
    75 
    76         if (fiberCount <= JSString::s_maxInternalRopeLength)
    77             return JSString::create(*globalData, fiberCount, u1, s2);
    78 
    79         JSString::RopeBuilder ropeBuilder(fiberCount);
    80         if (UNLIKELY(ropeBuilder.isOutOfMemory()))
    81             return throwOutOfMemoryError(exec);
    82         ropeBuilder.append(u1);
    83         ropeBuilder.append(s2);
    84         return JSString::create(*globalData, ropeBuilder.release());
    85     }
    86 
    87     ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, const UString& u2)
    88     {
    89         unsigned length1 = s1->length();
    90         if (!length1)
    91             return jsString(exec, u2);
    92         unsigned length2 = u2.length();
    93         if (!length2)
    94             return s1;
    95         if ((length1 + length2) < length1)
    96             return throwOutOfMemoryError(exec);
    97 
    98         unsigned fiberCount = s1->fiberCount() + 1;
    99         JSGlobalData* globalData = &exec->globalData();
    100 
    101         if (fiberCount <= JSString::s_maxInternalRopeLength)
    102             return JSString::create(*globalData, fiberCount, s1, u2);
    103 
    104         JSString::RopeBuilder ropeBuilder(fiberCount);
    105         if (UNLIKELY(ropeBuilder.isOutOfMemory()))
    106             return throwOutOfMemoryError(exec);
    107         ropeBuilder.append(s1);
    108         ropeBuilder.append(u2);
    109         return JSString::create(*globalData, ropeBuilder.release());
    110     }
    111 
    112     ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, const UString& u2)
    113     {
    114         unsigned length1 = u1.length();
    115         if (!length1)
    116             return jsString(exec, u2);
    117         unsigned length2 = u2.length();
    118         if (!length2)
    119             return jsString(exec, u1);
    120         if ((length1 + length2) < length1)
    121             return throwOutOfMemoryError(exec);
    122 
    123         JSGlobalData* globalData = &exec->globalData();
    124         return JSString::create(*globalData, u1, u2);
    125     }
    126 
    127     ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, const UString& u2, const UString& u3)
    128     {
    12957        unsigned length1 = u1.length();
    13058        unsigned length2 = u2.length();
    13159        unsigned length3 = u3.length();
    13260        if (!length1)
    133             return jsString(exec, u2, u3);
     61            return jsString(exec, jsString(globalData, u2), jsString(globalData, u3));
    13462        if (!length2)
    135             return jsString(exec, u1, u3);
     63            return jsString(exec, jsString(globalData, u1), jsString(globalData, u3));
    13664        if (!length3)
    137             return jsString(exec, u1, u2);
     65            return jsString(exec, jsString(globalData, u1), jsString(globalData, u2));
    13866
    13967        if ((length1 + length2) < length1)
     
    14270            return throwOutOfMemoryError(exec);
    14371
     72        return fixupVPtr(globalData, JSString::create(exec->globalData(), jsString(globalData, u1), jsString(globalData, u2), jsString(globalData, u3)));
     73    }
     74
     75    ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count)
     76    {
    14477        JSGlobalData* globalData = &exec->globalData();
    145         return JSString::create(*globalData, u1, u2, u3);
    146     }
    147 
    148     ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count)
    149     {
    150         ASSERT(count >= 3);
    151 
    152         unsigned fiberCount = 0;
     78        JSString::RopeBuilder ropeBuilder(*globalData);
     79
     80        unsigned oldLength = 0;
     81
    15382        for (unsigned i = 0; i < count; ++i) {
    15483            JSValue v = strings[i].jsValue();
    155             if (LIKELY(v.isString()))
    156                 fiberCount += asString(v)->fiberCount();
    157             else
    158                 ++fiberCount;
    159         }
    160 
    161         JSGlobalData* globalData = &exec->globalData();
    162         if (fiberCount == 3)
    163             return JSString::create(exec, strings[0].jsValue(), strings[1].jsValue(), strings[2].jsValue());
    164 
    165         JSString::RopeBuilder ropeBuilder(fiberCount);
    166         if (UNLIKELY(ropeBuilder.isOutOfMemory()))
    167             return throwOutOfMemoryError(exec);
    168 
    169         unsigned length = 0;
    170         bool overflow = false;
    171 
    172         for (unsigned i = 0; i < count; ++i) {
    173             JSValue v = strings[i].jsValue();
    174             if (LIKELY(v.isString()))
     84            if (v.isString())
    17585                ropeBuilder.append(asString(v));
    17686            else
    177                 ropeBuilder.append(v.toString(exec));
    178 
    179             unsigned newLength = ropeBuilder.length();
    180             if (newLength < length)
    181                 overflow = true;
    182             length = newLength;
    183         }
    184 
    185         if (overflow)
    186             return throwOutOfMemoryError(exec);
    187 
    188         return JSString::create(*globalData, ropeBuilder.release());
     87                ropeBuilder.append(jsString(globalData, v.toString(exec)));
     88
     89            if (ropeBuilder.length() < oldLength) // True for overflow
     90                return throwOutOfMemoryError(exec);
     91        }
     92
     93        return ropeBuilder.release();
    18994    }
    19095
    19196    ALWAYS_INLINE JSValue jsString(ExecState* exec, JSValue thisValue)
    19297    {
    193         unsigned fiberCount = 0;
    194         if (LIKELY(thisValue.isString()))
    195             fiberCount += asString(thisValue)->fiberCount();
     98        JSGlobalData* globalData = &exec->globalData();
     99        JSString::RopeBuilder ropeBuilder(*globalData);
     100
     101        if (thisValue.isString())
     102            ropeBuilder.append(asString(thisValue));
    196103        else
    197             ++fiberCount;
     104            ropeBuilder.append(jsString(globalData, thisValue.toString(exec)));
     105
     106        unsigned oldLength = 0;
     107
    198108        for (unsigned i = 0; i < exec->argumentCount(); ++i) {
    199109            JSValue v = exec->argument(i);
    200             if (LIKELY(v.isString()))
    201                 fiberCount += asString(v)->fiberCount();
    202             else
    203                 ++fiberCount;
    204         }
    205 
    206         JSString::RopeBuilder ropeBuilder(fiberCount);
    207         if (UNLIKELY(ropeBuilder.isOutOfMemory()))
    208             return throwOutOfMemoryError(exec);
    209 
    210         if (LIKELY(thisValue.isString()))
    211             ropeBuilder.append(asString(thisValue));
    212         else
    213             ropeBuilder.append(thisValue.toString(exec));
    214 
    215         unsigned length = 0;
    216         bool overflow = false;
    217 
    218         for (unsigned i = 0; i < exec->argumentCount(); ++i) {
    219             JSValue v = exec->argument(i);
    220             if (LIKELY(v.isString()))
     110            if (v.isString())
    221111                ropeBuilder.append(asString(v));
    222112            else
    223                 ropeBuilder.append(v.toString(exec));
    224 
    225             unsigned newLength = ropeBuilder.length();
    226             if (newLength < length)
    227                 overflow = true;
    228             length = newLength;
    229         }
    230 
    231         if (overflow)
    232             return throwOutOfMemoryError(exec);
    233 
    234         JSGlobalData* globalData = &exec->globalData();
    235         return JSString::create(*globalData, ropeBuilder.release());
     113                ropeBuilder.append(jsString(globalData, v.toString(exec)));
     114
     115            if (ropeBuilder.length() < oldLength) // True for overflow
     116                return throwOutOfMemoryError(exec);
     117        }
     118
     119        return ropeBuilder.release();
    236120    }
    237121
  • trunk/Source/JavaScriptCore/runtime/SmallStrings.cpp

    r91194 r97827  
    107107{
    108108    ASSERT(!m_emptyString);
    109     m_emptyString = JSString::createHasOtherOwner(*globalData, "");
     109    m_emptyString = JSString::createHasOtherOwner(*globalData, UString("").impl());
    110110}
    111111
  • trunk/Source/JavaScriptCore/runtime/StringConstructor.cpp

    r97537 r97827  
    9999    if (!exec->argumentCount())
    100100        return JSValue::encode(StringObject::create(exec, globalObject->stringObjectStructure()));
    101     return JSValue::encode(StringObject::create(exec, globalObject->stringObjectStructure(), exec->argument(0).toString(exec)));
     101   
     102    JSString* string = exec->argument(0).isString()
     103        ? asString(exec->argument(0))
     104        : jsString(exec, exec->argument(0).toString(exec));
     105    return JSValue::encode(StringObject::create(exec, globalObject->stringObjectStructure(), string));
    102106}
    103107
  • trunk/Source/JavaScriptCore/runtime/StringObject.h

    r97537 r97827  
    3838            return object;
    3939        }
    40         static StringObject* create(ExecState* exec, Structure* structure, const UString& str)
     40        static StringObject* create(ExecState* exec, Structure* structure, JSString* string)
    4141        {
    42             JSString* string = jsString(exec, str);
    4342            StringObject* object = new (allocateCell<StringObject>(*exec->heap())) StringObject(exec->globalData(), structure);
    4443            object->finishCreation(exec->globalData(), string);
  • trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp

    r97680 r97827  
    638638        return JSValue::encode(v.isString()
    639639            ? jsString(exec, asString(thisValue), asString(v))
    640             : jsString(exec, asString(thisValue), v.toString(exec)));
     640            : jsString(exec, asString(thisValue), jsString(&exec->globalData(), v.toString(exec))));
    641641    }
    642642    if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
Note: See TracChangeset for help on using the changeset viewer.