Changeset 51964 in webkit for trunk/JavaScriptCore


Ignore:
Timestamp:
Dec 10, 2009, 2:13:15 PM (15 years ago)
Author:
[email protected]
Message:

https://bugs.webkit.org/show_bug.cgi?id=32367
Add support for short Ropes (up to 3 entries) inline within JSString.
(rather than externally allocating an object to hold the rope).
Switch jsAdd of (JSString* + JSString*) to now make use of Ropes.

Reviewed by Oliver Hunt & Mark Rowe.

~1% progression on Sunspidey.

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::privateExecute):

  • jit/JITOpcodes.cpp:

(JSC::JIT::privateCompileCTIMachineTrampolines):

  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • runtime/JSString.cpp:

(JSC::JSString::resolveRope):
(JSC::JSString::toBoolean):
(JSC::JSString::getStringPropertyDescriptor):

  • runtime/JSString.h:

(JSC::JSString::Rope::Fiber::deref):
(JSC::JSString::Rope::Fiber::ref):
(JSC::JSString::Rope::Fiber::refAndGetLength):
(JSC::JSString::Rope::append):
(JSC::JSString::JSString):
(JSC::JSString::~JSString):
(JSC::JSString::value):
(JSC::JSString::tryGetValue):
(JSC::JSString::length):
(JSC::JSString::canGetIndex):
(JSC::JSString::appendStringInConstruct):
(JSC::JSString::appendValueInConstructAndIncrementLength):
(JSC::JSString::isRope):
(JSC::JSString::string):
(JSC::JSString::ropeLength):
(JSC::JSString::getStringPropertySlot):

  • runtime/Operations.h:

(JSC::jsString):
(JSC::jsAdd):
(JSC::resolveBase):

Location:
trunk/JavaScriptCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r51955 r51964  
     12009-12-10  Gavin Barraclough  <[email protected]>
     2
     3        Reviewed by Oliver Hunt & Mark Rowe.
     4
     5        https://bugs.webkit.org/show_bug.cgi?id=32367
     6        Add support for short Ropes (up to 3 entries) inline within JSString.
     7        (rather than externally allocating an object to hold the rope).
     8        Switch jsAdd of (JSString* + JSString*) to now make use of Ropes.
     9
     10        ~1% progression on Sunspidey.
     11
     12        * interpreter/Interpreter.cpp:
     13        (JSC::Interpreter::privateExecute):
     14        * jit/JITOpcodes.cpp:
     15        (JSC::JIT::privateCompileCTIMachineTrampolines):
     16        * jit/JITStubs.cpp:
     17        (JSC::DEFINE_STUB_FUNCTION):
     18        * runtime/JSString.cpp:
     19        (JSC::JSString::resolveRope):
     20        (JSC::JSString::toBoolean):
     21        (JSC::JSString::getStringPropertyDescriptor):
     22        * runtime/JSString.h:
     23        (JSC::JSString::Rope::Fiber::deref):
     24        (JSC::JSString::Rope::Fiber::ref):
     25        (JSC::JSString::Rope::Fiber::refAndGetLength):
     26        (JSC::JSString::Rope::append):
     27        (JSC::JSString::JSString):
     28        (JSC::JSString::~JSString):
     29        (JSC::JSString::value):
     30        (JSC::JSString::tryGetValue):
     31        (JSC::JSString::length):
     32        (JSC::JSString::canGetIndex):
     33        (JSC::JSString::appendStringInConstruct):
     34        (JSC::JSString::appendValueInConstructAndIncrementLength):
     35        (JSC::JSString::isRope):
     36        (JSC::JSString::string):
     37        (JSC::JSString::ropeLength):
     38        (JSC::JSString::getStringPropertySlot):
     39        * runtime/Operations.h:
     40        (JSC::jsString):
     41        (JSC::jsAdd):
     42        (JSC::resolveBase):
     43
    1442009-12-09  Anders Carlsson  <[email protected]>
    245
  • trunk/JavaScriptCore/interpreter/Interpreter.cpp

    r51801 r51964  
    35313531        int count = vPC[3].u.operand;
    35323532
    3533         callFrame->r(dst) = concatenateStrings(callFrame, &callFrame->registers()[src], count);
     3533        callFrame->r(dst) = jsString(callFrame, &callFrame->registers()[src], count);
    35343534        CHECK_FOR_EXCEPTION();
    35353535        vPC += OPCODE_LENGTH(op_strcat);
  • trunk/JavaScriptCore/jit/JITOpcodes.cpp

    r51765 r51964  
    5353
    5454    // Checks out okay! - get the length from the Ustring.
    55     load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_length)), regT2);
     55    load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_stringLength)), regT2);
    5656
    5757    Jump string_failureCases3 = branch32(Above, regT2, Imm32(INT_MAX));
     
    16371637
    16381638    // Checks out okay! - get the length from the Ustring.
    1639     load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_length)), regT0);
     1639    load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_stringLength)), regT0);
    16401640
    16411641    Jump string_failureCases3 = branch32(Above, regT0, Imm32(JSImmediate::maxImmediateInt));
  • trunk/JavaScriptCore/jit/JITStubs.cpp

    r51801 r51964  
    10441044    bool leftIsString = v1.isString();
    10451045    if (leftIsString && v2.isString()) {
    1046         if (asString(v1)->isRope() || asString(v2)->isRope()) {
    1047             RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(2);
    1048             if (UNLIKELY(!rope)) {
    1049                 throwOutOfMemoryError(callFrame);
    1050                 VM_THROW_EXCEPTION();
    1051             }
    1052             rope->initializeFiber(0, asString(v1));
    1053             rope->initializeFiber(1, asString(v2));
    1054             JSGlobalData* globalData = &callFrame->globalData();
    1055             return JSValue::encode(new (globalData) JSString(globalData, rope.release()));
    1056         }
    1057 
    1058         RefPtr<UString::Rep> value = concatenate(asString(v1)->value(callFrame).rep(), asString(v2)->value(callFrame).rep());
    1059         if (UNLIKELY(!value)) {
    1060             throwOutOfMemoryError(callFrame);
    1061             VM_THROW_EXCEPTION();
    1062         }
    1063 
    1064         return JSValue::encode(jsString(stackFrame.globalData, value.release()));
     1046        JSValue result = jsString(callFrame, asString(v1), asString(v2));
     1047        CHECK_FOR_EXCEPTION_AT_END();
     1048        return JSValue::encode(result);
    10651049    }
    10661050
     
    28522836    STUB_INIT_STACK_FRAME(stackFrame);
    28532837
    2854     JSValue result = concatenateStrings(stackFrame.callFrame, &stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32());
     2838    JSValue result = jsString(stackFrame.callFrame, &stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32());
    28552839    CHECK_FOR_EXCEPTION_AT_END();
    28562840    return JSValue::encode(result);
  • trunk/JavaScriptCore/runtime/JSString.cpp

    r51933 r51964  
    9797    // Allocate the buffer to hold the final string, position initially points to the end.
    9898    UChar* buffer;
    99     if (!tryFastMalloc(m_length * sizeof(UChar)).getValue(buffer)) {
    100         m_rope.clear();
     99    if (!tryFastMalloc(m_stringLength * sizeof(UChar)).getValue(buffer)) {
     100        for (unsigned i = 0; i < m_ropeLength; ++i)
     101            m_fibers[i].deref();
     102        m_ropeLength = 0;
    101103        ASSERT(!isRope());
    102104        ASSERT(m_value == UString());
     
    105107        return;
    106108    }
    107     UChar* position = buffer + m_length;
     109    UChar* position = buffer + m_stringLength;
    108110
    109111    // Start with the current Rope.
    110112    Vector<Rope::Fiber, 32> workQueue;
    111     Rope* rope = m_rope.get();
     113    Rope::Fiber currentFiber;
     114    for (unsigned i = 0; i < (m_ropeLength - 1); ++i)
     115        workQueue.append(m_fibers[i]);
     116    currentFiber = m_fibers[m_ropeLength - 1];
    112117    while (true) {
    113         // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber'
    114         // (we will be working backwards over the rope).
    115         unsigned ropeLengthMinusOne = rope->ropeLength() - 1;
    116         for (unsigned i = 0; i < ropeLengthMinusOne; ++i)
    117             workQueue.append(rope->fibers(i));
    118         Rope::Fiber currentFiber = rope->fibers(ropeLengthMinusOne);
    119 
    120         // Spin backwards over the workQueue (starting with currentFiber),
    121         // writing the strings into the buffer.
    122         while (currentFiber.isString()) {
     118        if (currentFiber.isRope()) {
     119            Rope* rope = currentFiber.rope();
     120            // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber'
     121            // (we will be working backwards over the rope).
     122            unsigned ropeLengthMinusOne = rope->ropeLength() - 1;
     123            for (unsigned i = 0; i < ropeLengthMinusOne; ++i)
     124                workQueue.append(rope->fibers(i));
     125            currentFiber = rope->fibers(ropeLengthMinusOne);
     126        } else {
    123127            UString::Rep* string = currentFiber.string();
    124128            unsigned length = string->len;
     
    130134                // Create a string from the UChar buffer, clear the rope RefPtr.
    131135                ASSERT(buffer == position);
    132                 m_value = UString(buffer, m_length, false);
    133                 m_rope.clear();
     136                m_value = UString::Rep::create(buffer, m_stringLength);
     137                for (unsigned i = 0; i < m_ropeLength; ++i)
     138                    m_fibers[i].deref();
     139                m_ropeLength = 0;
    134140
    135141                ASSERT(!isRope());
     
    141147            workQueue.removeLast();
    142148        }
    143 
    144         // If we get here we fell out of the loop concatenating strings - currentFiber is a rope.
    145         // set the 'rope' variable, and continue around the loop.
    146         ASSERT(currentFiber.isRope());
    147         rope = currentFiber.rope();
    148149    }
    149150}
     
    163164bool JSString::toBoolean(ExecState*) const
    164165{
    165     return m_length;
     166    return m_stringLength;
    166167}
    167168
     
    225226{
    226227    if (propertyName == exec->propertyNames().length) {
    227         descriptor.setDescriptor(jsNumber(exec, m_length), DontEnum | DontDelete | ReadOnly);
     228        descriptor.setDescriptor(jsNumber(exec, m_stringLength), DontEnum | DontDelete | ReadOnly);
    228229        return true;
    229230    }
     
    231232    bool isStrictUInt32;
    232233    unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
    233     if (isStrictUInt32 && i < m_length) {
     234    if (isStrictUInt32 && i < m_stringLength) {
    234235        descriptor.setDescriptor(jsSingleCharacterSubstring(exec, value(exec), i), DontDelete | ReadOnly);
    235236        return true;
  • trunk/JavaScriptCore/runtime/JSString.h

    r51933 r51964  
    7676                Fiber(Rope* rope) : m_value(reinterpret_cast<intptr_t>(rope) | 1) {}
    7777
     78                void deref()
     79                {
     80                    if (isRope())
     81                        rope()->deref();
     82                    else
     83                        string()->deref();
     84                }
     85
     86                Fiber& ref()
     87                {
     88                    if (isString())
     89                        string()->ref();
     90                    else
     91                        rope()->ref();
     92                    return *this;
     93                }
     94
     95                unsigned refAndGetLength()
     96                {
     97                    if (isString()) {
     98                        UString::Rep* rep = string();
     99                        return rep->ref()->len;
     100                    } else {
     101                        Rope* r = rope();
     102                        r->ref();
     103                        return r->stringLength();
     104                    }
     105                }
     106
    78107                bool isRope() { return m_value & 1; }
    79108                Rope* rope() { return reinterpret_cast<Rope*>(m_value & ~1); }
     
    98127            void destructNonRecursive();
    99128
    100             void initializeFiber(unsigned index, const UString& string)
     129            void append(unsigned &index, Fiber& fiber)
     130            {
     131                m_fibers[index++] = fiber;
     132                m_stringLength += fiber.refAndGetLength();
     133            }
     134            void append(unsigned &index, const UString& string)
    101135            {
    102136                UString::Rep* rep = string.rep();
    103                 rep->ref();
    104                 m_fibers[index] = Fiber(rep);
    105                 m_stringLength += rep->len;
     137                m_fibers[index++] = Fiber(rep);
     138                m_stringLength += rep->ref()->len;
    106139            }
    107             void initializeFiber(unsigned index, Rope* rope)
     140            void append(unsigned& index, JSString* jsString)
    108141            {
    109                 rope->ref();
    110                 m_fibers[index] = Fiber(rope);
    111                 m_stringLength += rope->stringLength();
    112             }
    113             void initializeFiber(unsigned index, JSString* jsString)
    114             {
    115                 if (jsString->isRope())
    116                     initializeFiber(index, jsString->rope());
    117                 else
    118                     initializeFiber(index, jsString->string());
     142                if (jsString->isRope()) {
     143                    for (unsigned i = 0; i < jsString->m_ropeLength; ++i)
     144                        append(index, jsString->m_fibers[i]);
     145                } else
     146                    append(index, jsString->string());
    119147            }
    120148
     
    134162        JSString(JSGlobalData* globalData, const UString& value)
    135163            : JSCell(globalData->stringStructure.get())
    136             , m_length(value.size())
     164            , m_stringLength(value.size())
    137165            , m_value(value)
     166            , m_ropeLength(0)
    138167        {
    139168            Heap::heap(this)->reportExtraMemoryCost(value.cost());
     
    143172        JSString(JSGlobalData* globalData, const UString& value, HasOtherOwnerType)
    144173            : JSCell(globalData->stringStructure.get())
    145             , m_length(value.size())
     174            , m_stringLength(value.size())
    146175            , m_value(value)
     176            , m_ropeLength(0)
    147177        {
    148178        }
    149179        JSString(JSGlobalData* globalData, PassRefPtr<UString::Rep> value, HasOtherOwnerType)
    150180            : JSCell(globalData->stringStructure.get())
    151             , m_length(value->size())
     181            , m_stringLength(value->size())
    152182            , m_value(value)
     183            , m_ropeLength(0)
    153184        {
    154185        }
    155186        JSString(JSGlobalData* globalData, PassRefPtr<JSString::Rope> rope)
    156187            : JSCell(globalData->stringStructure.get())
    157             , m_length(rope->stringLength())
    158             , m_rope(rope)
    159         {
     188            , m_stringLength(rope->stringLength())
     189            , m_ropeLength(1)
     190        {
     191            m_fibers[0] = rope.releaseRef();
     192        }
     193        // This constructor constructs a new string by concatenating s1 & s2.
     194        // This should only be called with ropeLength <= 3.
     195        JSString(JSGlobalData* globalData, unsigned ropeLength, JSString* s1, JSString* s2)
     196            : JSCell(globalData->stringStructure.get())
     197            , m_stringLength(s1->length() + s2->length())
     198            , m_ropeLength(ropeLength)
     199        {
     200            ASSERT(ropeLength <= s_maxInternalRopeLength);
     201            unsigned index = 0;
     202            appendStringInConstruct(index, s1);
     203            appendStringInConstruct(index, s2);
     204            ASSERT(ropeLength == index);
     205        }
     206        // This constructor constructs a new string by concatenating v1, v2 & v3.
     207        // This should only be called with ropeLength <= 3 ... which since every
     208        // value must require a ropeLength of at least one implies that the length
     209        // for each value must be exactly 1!
     210        JSString(ExecState* exec, JSValue v1, JSValue v2, JSValue v3)
     211            : JSCell(exec->globalData().stringStructure.get())
     212            , m_stringLength(0)
     213            , m_ropeLength(s_maxInternalRopeLength)
     214        {
     215            unsigned index = 0;
     216            appendValueInConstructAndIncrementLength(exec, index, v1);
     217            appendValueInConstructAndIncrementLength(exec, index, v2);
     218            appendValueInConstructAndIncrementLength(exec, index, v3);
     219            ASSERT(index == s_maxInternalRopeLength);
     220        }
     221
     222        ~JSString()
     223        {
     224            for (unsigned i = 0; i < m_ropeLength; ++i)
     225                m_fibers[i].deref();
    160226        }
    161227
    162228        const UString& value(ExecState* exec) const
    163229        {
    164             if (m_rope)
     230            if (isRope())
    165231                resolveRope(exec);
    166232            return m_value;
     
    168234        const UString tryGetValue() const
    169235        {
    170             if (m_rope)
     236            if (isRope())
    171237                UString();
    172238            return m_value;
    173239        }
    174         unsigned length() { return m_length; }
    175 
    176         bool isRope() const { return m_rope; }
    177         Rope* rope() { ASSERT(isRope()); return m_rope.get(); }
    178         UString& string() { ASSERT(!isRope()); return m_value; }
     240        unsigned length() { return m_stringLength; }
    179241
    180242        bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
     
    182244        bool getStringPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&);
    183245
    184         bool canGetIndex(unsigned i) { return i < m_length; }
     246        bool canGetIndex(unsigned i) { return i < m_stringLength; }
    185247        JSString* getIndex(ExecState*, unsigned);
    186248
     
    191253        JSString(VPtrStealingHackType)
    192254            : JSCell(0)
     255            , m_ropeLength(0)
    193256        {
    194257        }
    195258
    196259        void resolveRope(ExecState*) const;
     260
     261        void appendStringInConstruct(unsigned& index, JSString* jsString)
     262        {
     263            if (jsString->isRope()) {
     264                for (unsigned i = 0; i < jsString->m_ropeLength; ++i)
     265                    m_fibers[index++] = jsString->m_fibers[i].ref();
     266            } else
     267                m_fibers[index++] = Rope::Fiber(jsString->string().rep()->ref());
     268        }
     269
     270        void appendValueInConstructAndIncrementLength(ExecState* exec, unsigned& index, JSValue v)
     271        {
     272            if (v.isString()) {
     273                ASSERT(asCell(v)->isString());
     274                JSString* s = static_cast<JSString*>(asCell(v));
     275                ASSERT(s->ropeLength() == 1);
     276                appendStringInConstruct(index, s);
     277                m_stringLength += s->length();
     278            } else {
     279                UString u(v.toString(exec));
     280                m_fibers[index++] = Rope::Fiber(u.rep()->ref());
     281                m_stringLength += u.size();
     282            }
     283        }
    197284
    198285        virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
     
    212299        virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
    213300
     301        static const unsigned s_maxInternalRopeLength = 3;
     302
    214303        // A string is represented either by a UString or a Rope.
    215         unsigned m_length;
     304        unsigned m_stringLength;
    216305        mutable UString m_value;
    217         mutable RefPtr<Rope> m_rope;
     306        mutable unsigned m_ropeLength;
     307        mutable Rope::Fiber m_fibers[s_maxInternalRopeLength];
     308
     309        bool isRope() const { return m_ropeLength; }
     310        UString& string() { ASSERT(!isRope()); return m_value; }
     311        unsigned ropeLength() { return m_ropeLength ? m_ropeLength : 1; }
     312
     313        friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2);
     314        friend JSValue jsString(ExecState* exec, Register* strings, unsigned count);
    218315    };
    219316
     
    279376        return new (globalData) JSString(globalData, s);
    280377    }
    281        
     378
    282379    inline JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length)
    283380    {
     
    320417    {
    321418        if (propertyName == exec->propertyNames().length) {
    322             slot.setValue(jsNumber(exec, m_length));
     419            slot.setValue(jsNumber(exec, m_stringLength));
    323420            return true;
    324421        }
     
    326423        bool isStrictUInt32;
    327424        unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
    328         if (isStrictUInt32 && i < m_length) {
     425        if (isStrictUInt32 && i < m_stringLength) {
    329426            slot.setValue(jsSingleCharacterSubstring(exec, value(exec), i));
    330427            return true;
     
    336433    ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
    337434    {
    338         if (propertyName < m_length) {
     435        if (propertyName < m_stringLength) {
    339436            slot.setValue(jsSingleCharacterSubstring(exec, value(exec), propertyName));
    340437            return true;
  • trunk/JavaScriptCore/runtime/Operations.h

    r51933 r51964  
    3636    bool jsIsFunctionType(JSValue);
    3737
     38    ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2)
     39    {
     40        unsigned ropeLength = s1->ropeLength() + s2->ropeLength();
     41        JSGlobalData* globalData = &exec->globalData();
     42
     43        if (ropeLength <= JSString::s_maxInternalRopeLength)
     44            return new (globalData) JSString(globalData, ropeLength, s1, s2);
     45
     46        unsigned index = 0;
     47        RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength);
     48        if (UNLIKELY(!rope))
     49            return throwOutOfMemoryError(exec);
     50        rope->append(index, s1);
     51        rope->append(index, s2);
     52        ASSERT(index == ropeLength);
     53        return new (globalData) JSString(globalData, rope.release());
     54    }
     55
     56    ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count)
     57    {
     58        ASSERT(count >= 3);
     59
     60        unsigned ropeLength = 0;
     61        for (unsigned i = 0; i < count; ++i) {
     62            JSValue v = strings[i].jsValue();
     63            if (LIKELY(v.isString()))
     64                ropeLength += asString(v)->ropeLength();
     65            else
     66                ++ropeLength;
     67        }
     68
     69        JSGlobalData* globalData = &exec->globalData();
     70        if (ropeLength == 3)
     71            return new (globalData) JSString(exec, strings[0].jsValue(), strings[1].jsValue(), strings[2].jsValue());
     72
     73        RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength);
     74        if (UNLIKELY(!rope))
     75            return throwOutOfMemoryError(exec);
     76
     77        unsigned index = 0;
     78        for (unsigned i = 0; i < count; ++i) {
     79            JSValue v = strings[i].jsValue();
     80            if (LIKELY(v.isString()))
     81                rope->append(index, asString(v));
     82            else
     83                rope->append(index, v.toString(exec));
     84        }
     85
     86        ASSERT(index == ropeLength);
     87        return new (globalData) JSString(globalData, rope.release());
     88    }
     89
    3890    // ECMA 11.9.3
    3991    inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2)
     
    205257        bool leftIsString = v1.isString();
    206258        if (leftIsString && v2.isString()) {
    207             if (asString(v1)->isRope() || asString(v2)->isRope()) {
    208                 RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(2);
    209                 if (UNLIKELY(!rope))
    210                     return throwOutOfMemoryError(callFrame);
    211                 rope->initializeFiber(0, asString(v1));
    212                 rope->initializeFiber(1, asString(v2));
    213                 JSGlobalData* globalData = &callFrame->globalData();
    214                 return new (globalData) JSString(globalData, rope.release());
    215             }
    216 
    217             RefPtr<UString::Rep> value = concatenate(asString(v1)->value(callFrame).rep(), asString(v2)->value(callFrame).rep());
    218             if (!value)
    219                 return throwOutOfMemoryError(callFrame);
    220             return jsString(callFrame, value.release());
     259            if (!asString(v1)->length())
     260                return asString(v2);
     261            if (!asString(v2)->length())
     262                return asString(v1);
     263            return jsString(callFrame, asString(v1), asString(v2));
    221264        }
    222265
     
    304347        return JSValue();
    305348    }
    306 
    307     ALWAYS_INLINE JSValue concatenateStrings(CallFrame* callFrame, Register* strings, unsigned count)
    308     {
    309         ASSERT(count >= 3);
    310 
    311         RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(count);
    312         if (UNLIKELY(!rope))
    313             return throwOutOfMemoryError(callFrame);
    314 
    315         for (unsigned i = 0; i < count; ++i) {
    316             JSValue v = strings[i].jsValue();
    317             if (LIKELY(v.isString()))
    318                 rope->initializeFiber(i, asString(v));
    319             else
    320                 rope->initializeFiber(i, v.toString(callFrame));
    321         }
    322 
    323         JSGlobalData* globalData = &callFrame->globalData();
    324         return new (globalData) JSString(globalData, rope.release());
    325     }
    326349} // namespace JSC
    327350
Note: See TracChangeset for help on using the changeset viewer.