]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/Operations.h
JavaScriptCore-621.1.tar.gz
[apple/javascriptcore.git] / runtime / Operations.h
index c3aa0fa4f65a07302c7577dde378fce739699d94..122890247e1c3042dad8487290fd56a09de0af2e 100644 (file)
@@ -22,6 +22,7 @@
 #ifndef Operations_h
 #define Operations_h
 
+#include "ExceptionHelpers.h"
 #include "Interpreter.h"
 #include "JSImmediate.h"
 #include "JSNumberCell.h"
@@ -29,7 +30,6 @@
 
 namespace JSC {
 
-    NEVER_INLINE JSValue throwOutOfMemoryError(ExecState*);
     NEVER_INLINE JSValue jsAddSlowCase(CallFrame*, JSValue, JSValue);
     JSValue jsTypeStringForValue(CallFrame*, JSValue);
     bool jsIsObjectType(JSValue);
@@ -37,132 +37,203 @@ namespace JSC {
 
     ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2)
     {
-        if (!s1->length())
+        unsigned length1 = s1->length();
+        if (!length1)
             return s2;
-        if (!s2->length())
+        unsigned length2 = s2->length();
+        if (!length2)
             return s1;
+        if ((length1 + length2) < length1)
+            return throwOutOfMemoryError(exec);
 
-        unsigned ropeLength = s1->ropeLength() + s2->ropeLength();
+        unsigned fiberCount = s1->size() + s2->size();
         JSGlobalData* globalData = &exec->globalData();
 
-        if (ropeLength <= JSString::s_maxInternalRopeLength)
-            return new (globalData) JSString(globalData, ropeLength, s1, s2);
+        if (fiberCount <= JSString::s_maxInternalRopeLength)
+            return new (globalData) JSString(globalData, fiberCount, s1, s2);
 
-        unsigned index = 0;
-        RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength);
-        if (UNLIKELY(!rope))
+        JSString::RopeBuilder ropeBuilder(fiberCount);
+        if (UNLIKELY(ropeBuilder.isOutOfMemory()))
             return throwOutOfMemoryError(exec);
-        rope->append(index, s1);
-        rope->append(index, s2);
-        ASSERT(index == ropeLength);
-        return new (globalData) JSString(globalData, rope.release());
+        ropeBuilder.append(s1);
+        ropeBuilder.append(s2);
+        return new (globalData) JSString(globalData, ropeBuilder.release());
     }
 
     ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, JSString* s2)
     {
-        unsigned ropeLength = 1 + s2->ropeLength();
+        unsigned length1 = u1.size();
+        if (!length1)
+            return s2;
+        unsigned length2 = s2->length();
+        if (!length2)
+            return jsString(exec, u1);
+        if ((length1 + length2) < length1)
+            return throwOutOfMemoryError(exec);
+
+        unsigned fiberCount = 1 + s2->size();
         JSGlobalData* globalData = &exec->globalData();
 
-        if (ropeLength <= JSString::s_maxInternalRopeLength)
-            return new (globalData) JSString(globalData, ropeLength, u1, s2);
+        if (fiberCount <= JSString::s_maxInternalRopeLength)
+            return new (globalData) JSString(globalData, fiberCount, u1, s2);
 
-        unsigned index = 0;
-        RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength);
-        if (UNLIKELY(!rope))
+        JSString::RopeBuilder ropeBuilder(fiberCount);
+        if (UNLIKELY(ropeBuilder.isOutOfMemory()))
             return throwOutOfMemoryError(exec);
-        rope->append(index, u1);
-        rope->append(index, s2);
-        ASSERT(index == ropeLength);
-        return new (globalData) JSString(globalData, rope.release());
+        ropeBuilder.append(u1);
+        ropeBuilder.append(s2);
+        return new (globalData) JSString(globalData, ropeBuilder.release());
     }
 
     ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, const UString& u2)
     {
-        unsigned ropeLength = s1->ropeLength() + 1;
+        unsigned length1 = s1->length();
+        if (!length1)
+            return jsString(exec, u2);
+        unsigned length2 = u2.size();
+        if (!length2)
+            return s1;
+        if ((length1 + length2) < length1)
+            return throwOutOfMemoryError(exec);
+
+        unsigned fiberCount = s1->size() + 1;
         JSGlobalData* globalData = &exec->globalData();
 
-        if (ropeLength <= JSString::s_maxInternalRopeLength)
-            return new (globalData) JSString(globalData, ropeLength, s1, u2);
+        if (fiberCount <= JSString::s_maxInternalRopeLength)
+            return new (globalData) JSString(globalData, fiberCount, s1, u2);
 
-        unsigned index = 0;
-        RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength);
-        if (UNLIKELY(!rope))
+        JSString::RopeBuilder ropeBuilder(fiberCount);
+        if (UNLIKELY(ropeBuilder.isOutOfMemory()))
             return throwOutOfMemoryError(exec);
-        rope->append(index, s1);
-        rope->append(index, u2);
-        ASSERT(index == ropeLength);
-        return new (globalData) JSString(globalData, rope.release());
+        ropeBuilder.append(s1);
+        ropeBuilder.append(u2);
+        return new (globalData) JSString(globalData, ropeBuilder.release());
+    }
+
+    ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, const UString& u2)
+    {
+        unsigned length1 = u1.size();
+        if (!length1)
+            return jsString(exec, u2);
+        unsigned length2 = u2.size();
+        if (!length2)
+            return jsString(exec, u1);
+        if ((length1 + length2) < length1)
+            return throwOutOfMemoryError(exec);
+
+        JSGlobalData* globalData = &exec->globalData();
+        return new (globalData) JSString(globalData, u1, u2);
+    }
+
+    ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, const UString& u2, const UString& u3)
+    {
+        unsigned length1 = u1.size();
+        unsigned length2 = u2.size();
+        unsigned length3 = u3.size();
+        if (!length1)
+            return jsString(exec, u2, u3);
+        if (!length2)
+            return jsString(exec, u1, u3);
+        if (!length3)
+            return jsString(exec, u1, u2);
+
+        if ((length1 + length2) < length1)
+            return throwOutOfMemoryError(exec);
+        if ((length1 + length2 + length3) < length3)
+            return throwOutOfMemoryError(exec);
+
+        JSGlobalData* globalData = &exec->globalData();
+        return new (globalData) JSString(globalData, u1, u2, u3);
     }
 
     ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count)
     {
         ASSERT(count >= 3);
 
-        unsigned ropeLength = 0;
+        unsigned fiberCount = 0;
         for (unsigned i = 0; i < count; ++i) {
             JSValue v = strings[i].jsValue();
             if (LIKELY(v.isString()))
-                ropeLength += asString(v)->ropeLength();
+                fiberCount += asString(v)->size();
             else
-                ++ropeLength;
+                ++fiberCount;
         }
 
         JSGlobalData* globalData = &exec->globalData();
-        if (ropeLength == 3)
+        if (fiberCount == 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))
+        JSString::RopeBuilder ropeBuilder(fiberCount);
+        if (UNLIKELY(ropeBuilder.isOutOfMemory()))
             return throwOutOfMemoryError(exec);
 
-        unsigned index = 0;
+        unsigned length = 0;
+        bool overflow = false;
+
         for (unsigned i = 0; i < count; ++i) {
             JSValue v = strings[i].jsValue();
             if (LIKELY(v.isString()))
-                rope->append(index, asString(v));
+                ropeBuilder.append(asString(v));
             else
-                rope->append(index, v.toString(exec));
+                ropeBuilder.append(v.toString(exec));
+
+            unsigned newLength = ropeBuilder.length();
+            if (newLength < length)
+                overflow = true;
+            length = newLength;
         }
 
-        ASSERT(index == ropeLength);
-        return new (globalData) JSString(globalData, rope.release());
+        if (overflow)
+            return throwOutOfMemoryError(exec);
+
+        return new (globalData) JSString(globalData, ropeBuilder.release());
     }
 
     ALWAYS_INLINE JSValue jsString(ExecState* exec, JSValue thisValue, const ArgList& args)
     {
-        unsigned ropeLength = 0;
+        unsigned fiberCount = 0;
         if (LIKELY(thisValue.isString()))
-            ropeLength += asString(thisValue)->ropeLength();
+            fiberCount += asString(thisValue)->size();
         else
-            ++ropeLength;
+            ++fiberCount;
         for (unsigned i = 0; i < args.size(); ++i) {
             JSValue v = args.at(i);
             if (LIKELY(v.isString()))
-                ropeLength += asString(v)->ropeLength();
+                fiberCount += asString(v)->size();
             else
-                ++ropeLength;
+                ++fiberCount;
         }
 
-        RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength);
-        if (UNLIKELY(!rope))
+        JSString::RopeBuilder ropeBuilder(fiberCount);
+        if (UNLIKELY(ropeBuilder.isOutOfMemory()))
             return throwOutOfMemoryError(exec);
 
-        unsigned index = 0;
         if (LIKELY(thisValue.isString()))
-            rope->append(index, asString(thisValue));
+            ropeBuilder.append(asString(thisValue));
         else
-            rope->append(index, thisValue.toString(exec));
+            ropeBuilder.append(thisValue.toString(exec));
+
+        unsigned length = 0;
+        bool overflow = false;
+
         for (unsigned i = 0; i < args.size(); ++i) {
             JSValue v = args.at(i);
             if (LIKELY(v.isString()))
-                rope->append(index, asString(v));
+                ropeBuilder.append(asString(v));
             else
-                rope->append(index, v.toString(exec));
+                ropeBuilder.append(v.toString(exec));
+
+            unsigned newLength = ropeBuilder.length();
+            if (newLength < length)
+                overflow = true;
+            length = newLength;
         }
-        ASSERT(index == ropeLength);
+
+        if (overflow)
+            return throwOutOfMemoryError(exec);
 
         JSGlobalData* globalData = &exec->globalData();
-        return new (globalData) JSString(globalData, rope.release());
+        return new (globalData) JSString(globalData, ropeBuilder.release());
     }
 
     // ECMA 11.9.3