+ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2)
+{
+ VM& vm = exec->vm();
+
+ int32_t length1 = s1->length();
+ if (!length1)
+ return s2;
+ int32_t length2 = s2->length();
+ if (!length2)
+ return s1;
+ if (sumOverflows<int32_t>(length1, length2))
+ return throwOutOfMemoryError(exec);
+
+ return JSRopeString::create(vm, s1, s2);
+}
+
+ALWAYS_INLINE JSValue jsString(ExecState* exec, const String& u1, const String& u2, const String& u3)
+{
+ VM* vm = &exec->vm();
+
+ int32_t length1 = u1.length();
+ int32_t length2 = u2.length();
+ int32_t length3 = u3.length();
+
+ if (length1 < 0 || length2 < 0 || length3 < 0)
+ return throwOutOfMemoryError(exec);
+
+ if (!length1)
+ return jsString(exec, jsString(vm, u2), jsString(vm, u3));
+ if (!length2)
+ return jsString(exec, jsString(vm, u1), jsString(vm, u3));
+ if (!length3)
+ return jsString(exec, jsString(vm, u1), jsString(vm, u2));
+
+ if (sumOverflows<int32_t>(length1, length2, length3))
+ return throwOutOfMemoryError(exec);
+
+ return JSRopeString::create(exec->vm(), jsString(vm, u1), jsString(vm, u2), jsString(vm, u3));
+}
+
+ALWAYS_INLINE JSValue jsStringFromRegisterArray(ExecState* exec, Register* strings, unsigned count)
+{
+ VM* vm = &exec->vm();
+ JSRopeString::RopeBuilder ropeBuilder(*vm);
+
+ for (unsigned i = 0; i < count; ++i) {
+ JSValue v = strings[-static_cast<int>(i)].jsValue();
+ if (!ropeBuilder.append(v.toString(exec)))
+ return throwOutOfMemoryError(exec);