[SCM] WebKit Debian packaging branch, webkit-1.2, updated. upstream/1.1.90-6072-g9a69373

barraclough at apple.com barraclough at apple.com
Thu Apr 8 00:31:36 UTC 2010


The following commit has been merged in the webkit-1.2 branch:
commit 69ec720497438ba9379a7dc30cf74dd54e765434
Author: barraclough at apple.com <barraclough at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Thu Dec 10 22:13:15 2009 +0000

    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):
    
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@51964 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog
index 3d4d640..c678494 100644
--- a/JavaScriptCore/ChangeLog
+++ b/JavaScriptCore/ChangeLog
@@ -1,3 +1,46 @@
+2009-12-10  Gavin Barraclough  <barraclough at apple.com>
+
+        Reviewed by Oliver Hunt & Mark Rowe.
+
+        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.
+
+        ~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):
+
 2009-12-09  Anders Carlsson  <andersca at apple.com>
 
         Reviewed by Geoffrey Garen.
diff --git a/JavaScriptCore/interpreter/Interpreter.cpp b/JavaScriptCore/interpreter/Interpreter.cpp
index 4e1a56c..ed8bf5b 100644
--- a/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/JavaScriptCore/interpreter/Interpreter.cpp
@@ -3530,7 +3530,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
         int src = vPC[2].u.operand;
         int count = vPC[3].u.operand;
 
-        callFrame->r(dst) = concatenateStrings(callFrame, &callFrame->registers()[src], count);
+        callFrame->r(dst) = jsString(callFrame, &callFrame->registers()[src], count);
         CHECK_FOR_EXCEPTION();
         vPC += OPCODE_LENGTH(op_strcat);
 
diff --git a/JavaScriptCore/jit/JITOpcodes.cpp b/JavaScriptCore/jit/JITOpcodes.cpp
index d7e7496..77fec28 100644
--- a/JavaScriptCore/jit/JITOpcodes.cpp
+++ b/JavaScriptCore/jit/JITOpcodes.cpp
@@ -52,7 +52,7 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable
     Jump string_failureCases2 = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr));
 
     // Checks out okay! - get the length from the Ustring.
-    load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_length)), regT2);
+    load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_stringLength)), regT2);
 
     Jump string_failureCases3 = branch32(Above, regT2, Imm32(INT_MAX));
     move(regT2, regT0);
@@ -1636,7 +1636,7 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable
     Jump string_failureCases2 = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr));
 
     // Checks out okay! - get the length from the Ustring.
-    load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_length)), regT0);
+    load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_stringLength)), regT0);
 
     Jump string_failureCases3 = branch32(Above, regT0, Imm32(JSImmediate::maxImmediateInt));
 
diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp
index 418782f..fdf3d48 100644
--- a/JavaScriptCore/jit/JITStubs.cpp
+++ b/JavaScriptCore/jit/JITStubs.cpp
@@ -1043,25 +1043,9 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_add)
 
     bool leftIsString = v1.isString();
     if (leftIsString && v2.isString()) {
-        if (asString(v1)->isRope() || asString(v2)->isRope()) {
-            RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(2);
-            if (UNLIKELY(!rope)) {
-                throwOutOfMemoryError(callFrame);
-                VM_THROW_EXCEPTION();
-            }
-            rope->initializeFiber(0, asString(v1));
-            rope->initializeFiber(1, asString(v2));
-            JSGlobalData* globalData = &callFrame->globalData();
-            return JSValue::encode(new (globalData) JSString(globalData, rope.release()));
-        }
-
-        RefPtr<UString::Rep> value = concatenate(asString(v1)->value(callFrame).rep(), asString(v2)->value(callFrame).rep());
-        if (UNLIKELY(!value)) {
-            throwOutOfMemoryError(callFrame);
-            VM_THROW_EXCEPTION();
-        }
-
-        return JSValue::encode(jsString(stackFrame.globalData, value.release()));
+        JSValue result = jsString(callFrame, asString(v1), asString(v2));
+        CHECK_FOR_EXCEPTION_AT_END();
+        return JSValue::encode(result);
     }
 
     if (rightIsNumber & leftIsString) {
@@ -2851,7 +2835,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_strcat)
 {
     STUB_INIT_STACK_FRAME(stackFrame);
 
-    JSValue result = concatenateStrings(stackFrame.callFrame, &stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32());
+    JSValue result = jsString(stackFrame.callFrame, &stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32());
     CHECK_FOR_EXCEPTION_AT_END();
     return JSValue::encode(result);
 }
diff --git a/JavaScriptCore/runtime/JSString.cpp b/JavaScriptCore/runtime/JSString.cpp
index c668928..28ae6f7 100644
--- a/JavaScriptCore/runtime/JSString.cpp
+++ b/JavaScriptCore/runtime/JSString.cpp
@@ -96,30 +96,34 @@ void JSString::resolveRope(ExecState* exec) const
 
     // Allocate the buffer to hold the final string, position initially points to the end.
     UChar* buffer;
-    if (!tryFastMalloc(m_length * sizeof(UChar)).getValue(buffer)) {
-        m_rope.clear();
+    if (!tryFastMalloc(m_stringLength * sizeof(UChar)).getValue(buffer)) {
+        for (unsigned i = 0; i < m_ropeLength; ++i)
+            m_fibers[i].deref();
+        m_ropeLength = 0;
         ASSERT(!isRope());
         ASSERT(m_value == UString());
 
         throwOutOfMemoryError(exec);
         return;
     }
-    UChar* position = buffer + m_length;
+    UChar* position = buffer + m_stringLength;
 
     // Start with the current Rope.
     Vector<Rope::Fiber, 32> workQueue;
-    Rope* rope = m_rope.get();
+    Rope::Fiber currentFiber;
+    for (unsigned i = 0; i < (m_ropeLength - 1); ++i)
+        workQueue.append(m_fibers[i]);
+    currentFiber = m_fibers[m_ropeLength - 1];
     while (true) {
-        // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber'
-        // (we will be working backwards over the rope).
-        unsigned ropeLengthMinusOne = rope->ropeLength() - 1;
-        for (unsigned i = 0; i < ropeLengthMinusOne; ++i)
-            workQueue.append(rope->fibers(i));
-        Rope::Fiber currentFiber = rope->fibers(ropeLengthMinusOne);
-
-        // Spin backwards over the workQueue (starting with currentFiber),
-        // writing the strings into the buffer.
-        while (currentFiber.isString()) {
+        if (currentFiber.isRope()) {
+            Rope* rope = currentFiber.rope();
+            // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber'
+            // (we will be working backwards over the rope).
+            unsigned ropeLengthMinusOne = rope->ropeLength() - 1;
+            for (unsigned i = 0; i < ropeLengthMinusOne; ++i)
+                workQueue.append(rope->fibers(i));
+            currentFiber = rope->fibers(ropeLengthMinusOne);
+        } else {
             UString::Rep* string = currentFiber.string();
             unsigned length = string->len;
             position -= length;
@@ -129,8 +133,10 @@ void JSString::resolveRope(ExecState* exec) const
             if (workQueue.isEmpty()) {
                 // Create a string from the UChar buffer, clear the rope RefPtr.
                 ASSERT(buffer == position);
-                m_value = UString(buffer, m_length, false);
-                m_rope.clear();
+                m_value = UString::Rep::create(buffer, m_stringLength);
+                for (unsigned i = 0; i < m_ropeLength; ++i)
+                    m_fibers[i].deref();
+                m_ropeLength = 0;
 
                 ASSERT(!isRope());
                 return;
@@ -140,11 +146,6 @@ void JSString::resolveRope(ExecState* exec) const
             currentFiber = workQueue.last();
             workQueue.removeLast();
         }
-
-        // If we get here we fell out of the loop concatenating strings - currentFiber is a rope.
-        // set the 'rope' variable, and continue around the loop.
-        ASSERT(currentFiber.isRope());
-        rope = currentFiber.rope();
     }
 }
 
@@ -162,7 +163,7 @@ bool JSString::getPrimitiveNumber(ExecState* exec, double& number, JSValue& resu
 
 bool JSString::toBoolean(ExecState*) const
 {
-    return m_length;
+    return m_stringLength;
 }
 
 double JSString::toNumber(ExecState* exec) const
@@ -224,13 +225,13 @@ bool JSString::getOwnPropertySlot(ExecState* exec, const Identifier& propertyNam
 bool JSString::getStringPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
 {
     if (propertyName == exec->propertyNames().length) {
-        descriptor.setDescriptor(jsNumber(exec, m_length), DontEnum | DontDelete | ReadOnly);
+        descriptor.setDescriptor(jsNumber(exec, m_stringLength), DontEnum | DontDelete | ReadOnly);
         return true;
     }
     
     bool isStrictUInt32;
     unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
-    if (isStrictUInt32 && i < m_length) {
+    if (isStrictUInt32 && i < m_stringLength) {
         descriptor.setDescriptor(jsSingleCharacterSubstring(exec, value(exec), i), DontDelete | ReadOnly);
         return true;
     }
diff --git a/JavaScriptCore/runtime/JSString.h b/JavaScriptCore/runtime/JSString.h
index 633dd98..93b11f1 100644
--- a/JavaScriptCore/runtime/JSString.h
+++ b/JavaScriptCore/runtime/JSString.h
@@ -75,6 +75,35 @@ namespace JSC {
                 Fiber(UString::Rep* string) : m_value(reinterpret_cast<intptr_t>(string)) {}
                 Fiber(Rope* rope) : m_value(reinterpret_cast<intptr_t>(rope) | 1) {}
 
+                void deref()
+                {
+                    if (isRope())
+                        rope()->deref();
+                    else
+                        string()->deref();
+                }
+
+                Fiber& ref()
+                {
+                    if (isString())
+                        string()->ref();
+                    else
+                        rope()->ref();
+                    return *this;
+                }
+
+                unsigned refAndGetLength()
+                {
+                    if (isString()) {
+                        UString::Rep* rep = string();
+                        return rep->ref()->len;
+                    } else {
+                        Rope* r = rope();
+                        r->ref();
+                        return r->stringLength();
+                    }
+                }
+
                 bool isRope() { return m_value & 1; }
                 Rope* rope() { return reinterpret_cast<Rope*>(m_value & ~1); }
                 bool isString() { return !isRope(); }
@@ -97,25 +126,24 @@ namespace JSC {
             ~Rope();
             void destructNonRecursive();
 
-            void initializeFiber(unsigned index, const UString& string)
+            void append(unsigned &index, Fiber& fiber)
             {
-                UString::Rep* rep = string.rep();
-                rep->ref();
-                m_fibers[index] = Fiber(rep);
-                m_stringLength += rep->len;
+                m_fibers[index++] = fiber;
+                m_stringLength += fiber.refAndGetLength();
             }
-            void initializeFiber(unsigned index, Rope* rope)
+            void append(unsigned &index, const UString& string)
             {
-                rope->ref();
-                m_fibers[index] = Fiber(rope);
-                m_stringLength += rope->stringLength();
+                UString::Rep* rep = string.rep();
+                m_fibers[index++] = Fiber(rep);
+                m_stringLength += rep->ref()->len;
             }
-            void initializeFiber(unsigned index, JSString* jsString)
+            void append(unsigned& index, JSString* jsString)
             {
-                if (jsString->isRope())
-                    initializeFiber(index, jsString->rope());
-                else
-                    initializeFiber(index, jsString->string());
+                if (jsString->isRope()) {
+                    for (unsigned i = 0; i < jsString->m_ropeLength; ++i)
+                        append(index, jsString->m_fibers[i]);
+                } else
+                    append(index, jsString->string());
             }
 
             unsigned ropeLength() { return m_ropeLength; }
@@ -133,8 +161,9 @@ namespace JSC {
 
         JSString(JSGlobalData* globalData, const UString& value)
             : JSCell(globalData->stringStructure.get())
-            , m_length(value.size())
+            , m_stringLength(value.size())
             , m_value(value)
+            , m_ropeLength(0)
         {
             Heap::heap(this)->reportExtraMemoryCost(value.cost());
         }
@@ -142,46 +171,79 @@ namespace JSC {
         enum HasOtherOwnerType { HasOtherOwner };
         JSString(JSGlobalData* globalData, const UString& value, HasOtherOwnerType)
             : JSCell(globalData->stringStructure.get())
-            , m_length(value.size())
+            , m_stringLength(value.size())
             , m_value(value)
+            , m_ropeLength(0)
         {
         }
         JSString(JSGlobalData* globalData, PassRefPtr<UString::Rep> value, HasOtherOwnerType)
             : JSCell(globalData->stringStructure.get())
-            , m_length(value->size())
+            , m_stringLength(value->size())
             , m_value(value)
+            , m_ropeLength(0)
         {
         }
         JSString(JSGlobalData* globalData, PassRefPtr<JSString::Rope> rope)
             : JSCell(globalData->stringStructure.get())
-            , m_length(rope->stringLength())
-            , m_rope(rope)
+            , m_stringLength(rope->stringLength())
+            , m_ropeLength(1)
         {
+            m_fibers[0] = rope.releaseRef();
+        }
+        // This constructor constructs a new string by concatenating s1 & s2.
+        // This should only be called with ropeLength <= 3.
+        JSString(JSGlobalData* globalData, unsigned ropeLength, JSString* s1, JSString* s2)
+            : JSCell(globalData->stringStructure.get())
+            , m_stringLength(s1->length() + s2->length())
+            , m_ropeLength(ropeLength)
+        {
+            ASSERT(ropeLength <= s_maxInternalRopeLength);
+            unsigned index = 0;
+            appendStringInConstruct(index, s1);
+            appendStringInConstruct(index, s2);
+            ASSERT(ropeLength == index);
+        }
+        // This constructor constructs a new string by concatenating v1, v2 & v3.
+        // This should only be called with ropeLength <= 3 ... which since every
+        // value must require a ropeLength of at least one implies that the length
+        // for each value must be exactly 1!
+        JSString(ExecState* exec, JSValue v1, JSValue v2, JSValue v3)
+            : JSCell(exec->globalData().stringStructure.get())
+            , m_stringLength(0)
+            , m_ropeLength(s_maxInternalRopeLength)
+        {
+            unsigned index = 0;
+            appendValueInConstructAndIncrementLength(exec, index, v1);
+            appendValueInConstructAndIncrementLength(exec, index, v2);
+            appendValueInConstructAndIncrementLength(exec, index, v3);
+            ASSERT(index == s_maxInternalRopeLength);
+        }
+
+        ~JSString()
+        {
+            for (unsigned i = 0; i < m_ropeLength; ++i)
+                m_fibers[i].deref();
         }
 
         const UString& value(ExecState* exec) const
         {
-            if (m_rope)
+            if (isRope())
                 resolveRope(exec);
             return m_value;
         }
         const UString tryGetValue() const
         {
-            if (m_rope)
+            if (isRope())
                 UString();
             return m_value;
         }
-        unsigned length() { return m_length; }
-
-        bool isRope() const { return m_rope; }
-        Rope* rope() { ASSERT(isRope()); return m_rope.get(); }
-        UString& string() { ASSERT(!isRope()); return m_value; }
+        unsigned length() { return m_stringLength; }
 
         bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
         bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
         bool getStringPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&);
 
-        bool canGetIndex(unsigned i) { return i < m_length; }
+        bool canGetIndex(unsigned i) { return i < m_stringLength; }
         JSString* getIndex(ExecState*, unsigned);
 
         static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion)); }
@@ -190,11 +252,36 @@ namespace JSC {
         enum VPtrStealingHackType { VPtrStealingHack };
         JSString(VPtrStealingHackType) 
             : JSCell(0)
+            , m_ropeLength(0)
         {
         }
 
         void resolveRope(ExecState*) const;
 
+        void appendStringInConstruct(unsigned& index, JSString* jsString)
+        {
+            if (jsString->isRope()) {
+                for (unsigned i = 0; i < jsString->m_ropeLength; ++i)
+                    m_fibers[index++] = jsString->m_fibers[i].ref();
+            } else
+                m_fibers[index++] = Rope::Fiber(jsString->string().rep()->ref());
+        }
+
+        void appendValueInConstructAndIncrementLength(ExecState* exec, unsigned& index, JSValue v)
+        {
+            if (v.isString()) {
+                ASSERT(asCell(v)->isString());
+                JSString* s = static_cast<JSString*>(asCell(v));
+                ASSERT(s->ropeLength() == 1);
+                appendStringInConstruct(index, s);
+                m_stringLength += s->length();
+            } else {
+                UString u(v.toString(exec));
+                m_fibers[index++] = Rope::Fiber(u.rep()->ref());
+                m_stringLength += u.size();
+            }
+        }
+
         virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
         virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
         virtual bool toBoolean(ExecState*) const;
@@ -211,10 +298,20 @@ namespace JSC {
         virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
         virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
 
+        static const unsigned s_maxInternalRopeLength = 3;
+
         // A string is represented either by a UString or a Rope.
-        unsigned m_length;
+        unsigned m_stringLength;
         mutable UString m_value;
-        mutable RefPtr<Rope> m_rope;
+        mutable unsigned m_ropeLength;
+        mutable Rope::Fiber m_fibers[s_maxInternalRopeLength];
+
+        bool isRope() const { return m_ropeLength; }
+        UString& string() { ASSERT(!isRope()); return m_value; }
+        unsigned ropeLength() { return m_ropeLength ? m_ropeLength : 1; }
+
+        friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2);
+        friend JSValue jsString(ExecState* exec, Register* strings, unsigned count);
     };
 
     JSString* asString(JSValue);
@@ -278,7 +375,7 @@ namespace JSC {
         }
         return new (globalData) JSString(globalData, s);
     }
-        
+
     inline JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length)
     {
         ASSERT(offset <= static_cast<unsigned>(s.size()));
@@ -319,13 +416,13 @@ namespace JSC {
     ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
     {
         if (propertyName == exec->propertyNames().length) {
-            slot.setValue(jsNumber(exec, m_length));
+            slot.setValue(jsNumber(exec, m_stringLength));
             return true;
         }
 
         bool isStrictUInt32;
         unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
-        if (isStrictUInt32 && i < m_length) {
+        if (isStrictUInt32 && i < m_stringLength) {
             slot.setValue(jsSingleCharacterSubstring(exec, value(exec), i));
             return true;
         }
@@ -335,7 +432,7 @@ namespace JSC {
         
     ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
     {
-        if (propertyName < m_length) {
+        if (propertyName < m_stringLength) {
             slot.setValue(jsSingleCharacterSubstring(exec, value(exec), propertyName));
             return true;
         }
diff --git a/JavaScriptCore/runtime/Operations.h b/JavaScriptCore/runtime/Operations.h
index 035adc9..1cab06d 100644
--- a/JavaScriptCore/runtime/Operations.h
+++ b/JavaScriptCore/runtime/Operations.h
@@ -35,6 +35,58 @@ namespace JSC {
     bool jsIsObjectType(JSValue);
     bool jsIsFunctionType(JSValue);
 
+    ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2)
+    {
+        unsigned ropeLength = s1->ropeLength() + s2->ropeLength();
+        JSGlobalData* globalData = &exec->globalData();
+
+        if (ropeLength <= JSString::s_maxInternalRopeLength)
+            return new (globalData) JSString(globalData, ropeLength, s1, s2);
+
+        unsigned index = 0;
+        RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength);
+        if (UNLIKELY(!rope))
+            return throwOutOfMemoryError(exec);
+        rope->append(index, s1);
+        rope->append(index, s2);
+        ASSERT(index == ropeLength);
+        return new (globalData) JSString(globalData, rope.release());
+    }
+
+    ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count)
+    {
+        ASSERT(count >= 3);
+
+        unsigned ropeLength = 0;
+        for (unsigned i = 0; i < count; ++i) {
+            JSValue v = strings[i].jsValue();
+            if (LIKELY(v.isString()))
+                ropeLength += asString(v)->ropeLength();
+            else
+                ++ropeLength;
+        }
+
+        JSGlobalData* globalData = &exec->globalData();
+        if (ropeLength == 3)
+            return new (globalData) JSString(exec, strings[0].jsValue(), strings[1].jsValue(), strings[2].jsValue());
+
+        RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength);
+        if (UNLIKELY(!rope))
+            return throwOutOfMemoryError(exec);
+
+        unsigned index = 0;
+        for (unsigned i = 0; i < count; ++i) {
+            JSValue v = strings[i].jsValue();
+            if (LIKELY(v.isString()))
+                rope->append(index, asString(v));
+            else
+                rope->append(index, v.toString(exec));
+        }
+
+        ASSERT(index == ropeLength);
+        return new (globalData) JSString(globalData, rope.release());
+    }
+
     // ECMA 11.9.3
     inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2)
     {
@@ -204,20 +256,11 @@ namespace JSC {
         
         bool leftIsString = v1.isString();
         if (leftIsString && v2.isString()) {
-            if (asString(v1)->isRope() || asString(v2)->isRope()) {
-                RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(2);
-                if (UNLIKELY(!rope))
-                    return throwOutOfMemoryError(callFrame);
-                rope->initializeFiber(0, asString(v1));
-                rope->initializeFiber(1, asString(v2));
-                JSGlobalData* globalData = &callFrame->globalData();
-                return new (globalData) JSString(globalData, rope.release());
-            }
-
-            RefPtr<UString::Rep> value = concatenate(asString(v1)->value(callFrame).rep(), asString(v2)->value(callFrame).rep());
-            if (!value)
-                return throwOutOfMemoryError(callFrame);
-            return jsString(callFrame, value.release());
+            if (!asString(v1)->length())
+                return asString(v2);
+            if (!asString(v2)->length())
+                return asString(v1);
+            return jsString(callFrame, asString(v1), asString(v2));
         }
 
         if (rightIsNumber & leftIsString) {
@@ -303,26 +346,6 @@ namespace JSC {
         ASSERT_NOT_REACHED();
         return JSValue();
     }
-
-    ALWAYS_INLINE JSValue concatenateStrings(CallFrame* callFrame, Register* strings, unsigned count)
-    {
-        ASSERT(count >= 3);
-
-        RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(count);
-        if (UNLIKELY(!rope))
-            return throwOutOfMemoryError(callFrame);
-
-        for (unsigned i = 0; i < count; ++i) {
-            JSValue v = strings[i].jsValue();
-            if (LIKELY(v.isString()))
-                rope->initializeFiber(i, asString(v));
-            else
-                rope->initializeFiber(i, v.toString(callFrame));
-        }
-
-        JSGlobalData* globalData = &callFrame->globalData();
-        return new (globalData) JSString(globalData, rope.release());
-    }
 } // namespace JSC
 
 #endif // Operations_h

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list