Ignore:
Timestamp:
Oct 18, 2011, 7:54:29 PM (14 years ago)
Author:
[email protected]
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.

File:
1 edited

Legend:

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