https://bugs.webkit.org/show_bug.cgi?id=32496
authorbarraclough@apple.com <barraclough@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 14 Dec 2009 00:27:07 +0000 (00:27 +0000)
committerbarraclough@apple.com <barraclough@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 14 Dec 2009 00:27:07 +0000 (00:27 +0000)
Switch remaining cases of string construction to use StringBuilder.
Builds strings using a vector rather than using string append / addition.

Reviewed by Sam Weinig.

* JavaScriptCore.exp:
* JavaScriptCore.xcodeproj/project.pbxproj:
* runtime/Executable.cpp:
(JSC::FunctionExecutable::paramString):
* runtime/FunctionConstructor.cpp:
(JSC::constructFunction):
* runtime/JSGlobalObjectFunctions.cpp:
(JSC::encode):
(JSC::decode):
(JSC::globalFuncEscape):
(JSC::globalFuncUnescape):
* runtime/JSONObject.cpp:
(JSC::Stringifier::stringify):
(JSC::Stringifier::indent):
* runtime/JSString.h:
* runtime/LiteralParser.cpp:
(JSC::LiteralParser::Lexer::lexString):
* runtime/NumberPrototype.cpp:
(JSC::integerPartNoExp):
(JSC::numberProtoFuncToFixed):
(JSC::numberProtoFuncToPrecision):
* runtime/Operations.h:
(JSC::jsString):
* runtime/StringPrototype.cpp:
(JSC::substituteBackreferencesSlow):
(JSC::substituteBackreferences):
(JSC::stringProtoFuncConcat):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@52075 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
JavaScriptCore/runtime/Executable.cpp
JavaScriptCore/runtime/FunctionConstructor.cpp
JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
JavaScriptCore/runtime/JSONObject.cpp
JavaScriptCore/runtime/JSString.h
JavaScriptCore/runtime/LiteralParser.cpp
JavaScriptCore/runtime/NumberPrototype.cpp
JavaScriptCore/runtime/Operations.h
JavaScriptCore/runtime/StringBuilder.h [new file with mode: 0644]
JavaScriptCore/runtime/StringPrototype.cpp
JavaScriptCore/runtime/UString.h

index 705489707515f124f64f77d3cc6c135bad9a51de..ef8b1c1bb07c476cb683831ba8539438aa7edbb7 100644 (file)
@@ -1,3 +1,39 @@
+2009-12-13  Gavin Barraclough  <barraclough@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        https://bugs.webkit.org/show_bug.cgi?id=32496
+        Switch remaining cases of string construction to use StringBuilder.
+        Builds strings using a vector rather than using string append / addition.
+
+        * JavaScriptCore.exp:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * runtime/Executable.cpp:
+        (JSC::FunctionExecutable::paramString):
+        * runtime/FunctionConstructor.cpp:
+        (JSC::constructFunction):
+        * runtime/JSGlobalObjectFunctions.cpp:
+        (JSC::encode):
+        (JSC::decode):
+        (JSC::globalFuncEscape):
+        (JSC::globalFuncUnescape):
+        * runtime/JSONObject.cpp:
+        (JSC::Stringifier::stringify):
+        (JSC::Stringifier::indent):
+        * runtime/JSString.h:
+        * runtime/LiteralParser.cpp:
+        (JSC::LiteralParser::Lexer::lexString):
+        * runtime/NumberPrototype.cpp:
+        (JSC::integerPartNoExp):
+        (JSC::numberProtoFuncToFixed):
+        (JSC::numberProtoFuncToPrecision):
+        * runtime/Operations.h:
+        (JSC::jsString):
+        * runtime/StringPrototype.cpp:
+        (JSC::substituteBackreferencesSlow):
+        (JSC::substituteBackreferences):
+        (JSC::stringProtoFuncConcat):
+
 2009-12-08  Jeremy Moskovich  <jeremy@chromium.org>
 
         Reviewed by Eric Seidel.
index e766243ee1fdad8900e743e89bfe02a4e552d106..1626e50944d4f45d7dd96c75e5a859f65a8b3f9f 100644 (file)
                863B23E00FC6118900703AA4 /* MacroAssemblerCodeRef.h in Headers */ = {isa = PBXBuildFile; fileRef = 863B23DF0FC60E6200703AA4 /* MacroAssemblerCodeRef.h */; settings = {ATTRIBUTES = (Private, ); }; };
                869083150E6518D7000D36ED /* WREC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 869083130E6518D7000D36ED /* WREC.cpp */; };
                869083160E6518D7000D36ED /* WREC.h in Headers */ = {isa = PBXBuildFile; fileRef = 869083140E6518D7000D36ED /* WREC.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               8698B86910D44D9400D8D01B /* StringBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 8698B86810D44D9400D8D01B /* StringBuilder.h */; };
                869EBCB70E8C6D4A008722CC /* ResultType.h in Headers */ = {isa = PBXBuildFile; fileRef = 869EBCB60E8C6D4A008722CC /* ResultType.h */; settings = {ATTRIBUTES = (Private, ); }; };
                86A90ED00EE7D51F00AB350D /* JITArithmetic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86A90ECF0EE7D51F00AB350D /* JITArithmetic.cpp */; };
                86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86ADD1430FDDEA980006EEC2 /* ARMv7Assembler.h */; };
                863B23DF0FC60E6200703AA4 /* MacroAssemblerCodeRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssemblerCodeRef.h; sourceTree = "<group>"; };
                869083130E6518D7000D36ED /* WREC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WREC.cpp; sourceTree = "<group>"; };
                869083140E6518D7000D36ED /* WREC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WREC.h; sourceTree = "<group>"; };
+               8698B86810D44D9400D8D01B /* StringBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringBuilder.h; sourceTree = "<group>"; };
                869EBCB60E8C6D4A008722CC /* ResultType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResultType.h; sourceTree = "<group>"; };
                86A90ECF0EE7D51F00AB350D /* JITArithmetic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITArithmetic.cpp; sourceTree = "<group>"; };
                86ADD1430FDDEA980006EEC2 /* ARMv7Assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARMv7Assembler.h; sourceTree = "<group>"; };
                                14F252560D08DD8D004ECFFF /* JSVariableObject.h */,
                                65C7A1710A8EAACB00FA37EA /* JSWrapperObject.cpp */,
                                65C7A1720A8EAACB00FA37EA /* JSWrapperObject.h */,
+                               A7C2216810C745E000F97913 /* JSZombie.h */,
+                               A7C2216B10C7469C00F97913 /* JSZombie.cpp */,
                                A7E2EA6A0FB460CF00601F06 /* LiteralParser.cpp */,
                                A7E2EA690FB460CF00601F06 /* LiteralParser.h */,
                                F692A8680255597D01FF60F7 /* Lookup.cpp */,
                                7E2C6C980D31C6B6002D44E2 /* ScopeChainMark.h */,
                                93303FE80E6A72B500786E6A /* SmallStrings.cpp */,
                                93303FEA0E6A72C000786E6A /* SmallStrings.h */,
+                               8698B86810D44D9400D8D01B /* StringBuilder.h */,
                                BC18C3C00E16EE3300B34460 /* StringConstructor.cpp */,
                                BC18C3C10E16EE3300B34460 /* StringConstructor.h */,
                                BC18C3C20E16EE3300B34460 /* StringObject.cpp */,
                                F692A8850255597D01FF60F7 /* UString.cpp */,
                                F692A8860255597D01FF60F7 /* UString.h */,
                                1420BE7A10AA6DDB00F455D2 /* WeakRandom.h */,
-                               A7C2216810C745E000F97913 /* JSZombie.h */,
-                               A7C2216B10C7469C00F97913 /* JSZombie.cpp */,
                        );
                        path = runtime;
                        sourceTree = "<group>";
                                148CD1D8108CF902008163C6 /* JSContextRefPrivate.h in Headers */,
                                14A1563210966365006FA260 /* DateInstanceCache.h in Headers */,
                                1420BE7B10AA6DDB00F455D2 /* WeakRandom.h in Headers */,
+                               8698B86910D44D9400D8D01B /* StringBuilder.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 7586746565a749779ce75a1c8a1f0d069c7644c3..bc18cc9a80a00f2f3125d26bb871936623a208a6 100644 (file)
@@ -30,6 +30,7 @@
 #include "CodeBlock.h"
 #include "JIT.h"
 #include "Parser.h"
+#include "StringBuilder.h"
 #include "Vector.h"
 
 namespace JSC {
@@ -265,14 +266,13 @@ PassRefPtr<FunctionExecutable> FunctionExecutable::fromGlobalCode(const Identifi
 UString FunctionExecutable::paramString() const
 {
     FunctionParameters& parameters = *m_parameters;
-    UString s("");
+    StringBuilder builder;
     for (size_t pos = 0; pos < parameters.size(); ++pos) {
-        if (!s.isEmpty())
-            s += ", ";
-        s += parameters[pos].ustring();
+        if (!builder.isEmpty())
+            builder.append(", ");
+        builder.append(parameters[pos].ustring());
     }
-
-    return s;
+    return builder.release();
 }
 
 };
index 9d8840079fab05e7c43c4a647bc836a17923b9ba..9d55dd109b00ffd40d9aa9ff0999faf6654b7c98 100644 (file)
 #include "config.h"
 #include "FunctionConstructor.h"
 
+#include "Debugger.h"
 #include "FunctionPrototype.h"
 #include "JSFunction.h"
 #include "JSGlobalObject.h"
 #include "JSString.h"
-#include "Parser.h"
-#include "Debugger.h"
 #include "Lexer.h"
 #include "Nodes.h"
+#include "Parser.h"
+#include "StringBuilder.h"
 
 namespace JSC {
 
@@ -76,12 +77,19 @@ JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifi
     if (args.isEmpty())
         program = "(function() { \n})";
     else if (args.size() == 1)
-        program = "(function() { " + args.at(0).toString(exec) + "\n})";
+        program = makeString("(function() { ", args.at(0).toString(exec), "\n})");
     else {
-        program = "(function(" + args.at(0).toString(exec);
-        for (size_t i = 1; i < args.size() - 1; i++)
-            program += "," + args.at(i).toString(exec);
-        program += ") { " + args.at(args.size() - 1).toString(exec) + "\n})";
+        StringBuilder builder;
+        builder.append("(function(");
+        builder.append(args.at(0).toString(exec));
+        for (size_t i = 1; i < args.size() - 1; i++) {
+            builder.append(",");
+            builder.append(args.at(i).toString(exec));
+        }
+        builder.append(") { ");
+        builder.append(args.at(args.size() - 1).toString(exec));
+        builder.append("\n})");
+        program = builder.release();
     }
 
     int errLine;
index dc327188a11656c3f75af8e50e95eafc0756cca1..b0a68d5534e680e1a4e760b0838d2149a60480f9 100644 (file)
 
 #include "CallFrame.h"
 #include "GlobalEvalFunction.h"
+#include "Interpreter.h"
 #include "JSGlobalObject.h"
-#include "LiteralParser.h"
 #include "JSString.h"
-#include "Interpreter.h"
-#include "Parser.h"
-#include "dtoa.h"
 #include "Lexer.h"
+#include "LiteralParser.h"
 #include "Nodes.h"
+#include "Parser.h"
+#include "StringBuilder.h"
+#include "dtoa.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -55,24 +56,24 @@ static JSValue encode(ExecState* exec, const ArgList& args, const char* doNotEsc
     if (!cstr.c_str())
         return throwError(exec, URIError, "String contained an illegal UTF-16 sequence.");
 
-    UString result = "";
+    StringBuilder builder;
     const char* p = cstr.c_str();
     for (size_t k = 0; k < cstr.size(); k++, p++) {
         char c = *p;
         if (c && strchr(doNotEscape, c))
-            result.append(c);
+            builder.append(c);
         else {
             char tmp[4];
-            sprintf(tmp, "%%%02X", static_cast<unsigned char>(c));
-            result += tmp;
+            snprintf(tmp, 4, "%%%02X", static_cast<unsigned char>(c));
+            builder.append((const char*)tmp);
         }
     }
-    return jsString(exec, result);
+    return jsString(exec, builder.release());
 }
 
 static JSValue decode(ExecState* exec, const ArgList& args, const char* doNotUnescape, bool strict)
 {
-    UString result = "";
+    StringBuilder builder;
     UString str = args.at(0).toString(exec);
     int k = 0;
     int len = str.size();
@@ -106,7 +107,7 @@ static JSValue decode(ExecState* exec, const ArgList& args, const char* doNotUne
                             charLen = 0;
                         else if (character >= 0x10000) {
                             // Convert to surrogate pair.
-                            result.append(static_cast<UChar>(0xD800 | ((character - 0x10000) >> 10)));
+                            builder.append(static_cast<UChar>(0xD800 | ((character - 0x10000) >> 10)));
                             u = static_cast<UChar>(0xDC00 | ((character - 0x10000) & 0x3FF));
                         } else
                             u = static_cast<UChar>(character);
@@ -131,9 +132,9 @@ static JSValue decode(ExecState* exec, const ArgList& args, const char* doNotUne
             }
         }
         k++;
-        result.append(c);
+        builder.append(c);
     }
-    return jsString(exec, result);
+    return jsString(exec, builder.release());
 }
 
 bool isStrWhiteSpace(UChar c)
@@ -376,7 +377,7 @@ JSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec, JSObject*, JSValue, cons
         "0123456789"
         "*+-./@_";
 
-    UString result = "";
+    StringBuilder builder;
     UString s;
     UString str = args.at(0).toString(exec);
     const UChar* c = str.data();
@@ -393,15 +394,15 @@ JSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec, JSObject*, JSValue, cons
             sprintf(tmp, "%%%02X", u);
             s = UString(tmp);
         }
-        result += s;
+        builder.append(s);
     }
 
-    return jsString(exec, result);
+    return jsString(exec, builder.release());
 }
 
 JSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec, JSObject*, JSValue, const ArgList& args)
 {
-    UString result = "";
+    StringBuilder builder;
     UString str = args.at(0).toString(exec);
     int k = 0;
     int len = str.size();
@@ -420,10 +421,10 @@ JSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec, JSObject*, JSValue, co
             k += 2;
         }
         k++;
-        result.append(*c);
+        builder.append(*c);
     }
 
-    return jsString(exec, result);
+    return jsString(exec, builder.release());
 }
 
 #ifndef NDEBUG
index cc7f6d9b08a13309906d5216366acedf53b06c3e..f28e70ed3421aa17f829af1814c5dc80011f50c8 100644 (file)
@@ -32,6 +32,7 @@
 #include "JSArray.h"
 #include "LiteralParser.h"
 #include "PropertyNameArray.h"
+#include "StringBuilder.h"
 #include <wtf/MathExtras.h>
 
 namespace JSC {
@@ -70,24 +71,6 @@ public:
     void markAggregate(MarkStack&);
 
 private:
-    class StringBuilder : public Vector<UChar> {
-    public:
-        using Vector<UChar>::append;
-
-        inline void append(const char* str)
-        {
-            size_t len = strlen(str);
-            reserveCapacity(size() + len);
-            for (size_t i = 0; i < len; i++)
-                Vector<UChar>::append(str[i]);
-        }
-
-        inline void append(const UString& str)
-        {
-            append(str.data(), str.size());
-        }
-    };
-
     class Holder {
     public:
         Holder(JSObject*);
@@ -285,9 +268,7 @@ JSValue Stringifier::stringify(JSValue value)
     if (m_exec->hadException())
         return jsNull();
 
-    result.shrinkToFit();
-    size_t length = result.size();
-    return jsString(m_exec, UString(result.releaseBuffer(), length, false));
+    return jsString(m_exec, result.release());
 }
 
 void Stringifier::appendQuotedString(StringBuilder& builder, const UString& value)
@@ -477,7 +458,7 @@ inline void Stringifier::indent()
     // Use a single shared string, m_repeatedGap, so we don't keep allocating new ones as we indent and unindent.
     int newSize = m_indent.size() + m_gap.size();
     if (newSize > m_repeatedGap.size())
-        m_repeatedGap.append(m_gap);
+        m_repeatedGap = makeString(m_repeatedGap, m_gap);
     ASSERT(newSize <= m_repeatedGap.size());
     m_indent = m_repeatedGap.substr(0, newSize);
 }
index 33e60ab96f59d3535059bdee35e54e893ab59b4e..c423814871cc3e75a33b01f038aace14a38cc135 100644 (file)
@@ -345,6 +345,7 @@ namespace JSC {
         friend JSValue jsString(ExecState* exec, const UString& u1, JSString* s2);
         friend JSValue jsString(ExecState* exec, JSString* s1, const UString& u2);
         friend JSValue jsString(ExecState* exec, Register* strings, unsigned count);
+        friend JSValue jsString(ExecState* exec, JSValue thisValue, const ArgList& args);
     };
 
     JSString* asString(JSValue);
index d242282f39036eab736f469ff6210b900230c156..aa1e5ed9f63e63a76731b9cc068905470d54179e 100644 (file)
@@ -29,6 +29,7 @@
 #include "JSArray.h"
 #include "JSString.h"
 #include "Lexer.h"
+#include "StringBuilder.h"
 #include <wtf/ASCIICType.h>
 #include <wtf/dtoa.h>
 
@@ -134,48 +135,48 @@ template <LiteralParser::ParserMode mode> inline LiteralParser::TokenType Litera
 {
     ++m_ptr;
     const UChar* runStart;
-    token.stringToken = UString();
+    StringBuilder builder;
     do {
         runStart = m_ptr;
         while (m_ptr < m_end && isSafeStringCharacter<mode>(*m_ptr))
             ++m_ptr;
         if (runStart < m_ptr)
-            token.stringToken.append(runStart, m_ptr - runStart);
+            builder.append(runStart, m_ptr - runStart);
         if ((mode == StrictJSON) && m_ptr < m_end && *m_ptr == '\\') {
             ++m_ptr;
             if (m_ptr >= m_end)
                 return TokError;
             switch (*m_ptr) {
                 case '"':
-                    token.stringToken.append('"');
+                    builder.append('"');
                     m_ptr++;
                     break;
                 case '\\':
-                    token.stringToken.append('\\');
+                    builder.append('\\');
                     m_ptr++;
                     break;
                 case '/':
-                    token.stringToken.append('/');
+                    builder.append('/');
                     m_ptr++;
                     break;
                 case 'b':
-                    token.stringToken.append('\b');
+                    builder.append('\b');
                     m_ptr++;
                     break;
                 case 'f':
-                    token.stringToken.append('\f');
+                    builder.append('\f');
                     m_ptr++;
                     break;
                 case 'n':
-                    token.stringToken.append('\n');
+                    builder.append('\n');
                     m_ptr++;
                     break;
                 case 'r':
-                    token.stringToken.append('\r');
+                    builder.append('\r');
                     m_ptr++;
                     break;
                 case 't':
-                    token.stringToken.append('\t');
+                    builder.append('\t');
                     m_ptr++;
                     break;
 
@@ -186,7 +187,7 @@ template <LiteralParser::ParserMode mode> inline LiteralParser::TokenType Litera
                         if (!isASCIIHexDigit(m_ptr[i]))
                             return TokError;
                     }
-                    token.stringToken.append(JSC::Lexer::convertUnicode(m_ptr[1], m_ptr[2], m_ptr[3], m_ptr[4]));
+                    builder.append(JSC::Lexer::convertUnicode(m_ptr[1], m_ptr[2], m_ptr[3], m_ptr[4]));
                     m_ptr += 5;
                     break;
 
@@ -199,6 +200,7 @@ template <LiteralParser::ParserMode mode> inline LiteralParser::TokenType Litera
     if (m_ptr >= m_end || *m_ptr != '"')
         return TokError;
 
+    token.stringToken = builder.release();
     token.type = TokString;
     token.end = ++m_ptr;
     return TokString;
index df31404b9c916d55e50ade2651891f0aa533e739..67210fabf717f7b9ea65b320e2f55fef977c6059 100644 (file)
 #include "Error.h"
 #include "JSFunction.h"
 #include "JSString.h"
+#include "Operations.h"
 #include "PrototypeFunction.h"
+#include "StringBuilder.h"
 #include "dtoa.h"
-#include "Operations.h"
 #include <wtf/Assertions.h>
 #include <wtf/MathExtras.h>
 #include <wtf/Vector.h>
@@ -73,11 +74,12 @@ static UString integerPartNoExp(double d)
     bool resultIsInfOrNan = (decimalPoint == 9999);
     size_t length = strlen(result);
 
-    UString str = sign ? "-" : "";
+    StringBuilder builder;
+    builder.append(sign ? "-" : "");
     if (resultIsInfOrNan)
-        str += result;
+        builder.append((const char*)result);
     else if (decimalPoint <= 0)
-        str += "0";
+        builder.append("0");
     else {
         Vector<char, 1024> buf(decimalPoint + 1);
 
@@ -89,10 +91,10 @@ static UString integerPartNoExp(double d)
             strncpy(buf.data(), result, decimalPoint);
         buf[decimalPoint] = '\0';
 
-        str.append(buf.data());
+        builder.append((const char*)(buf.data()));
     }
 
-    return str;
+    return builder.release();
 }
 
 static UString charSequence(char c, int count)
@@ -236,13 +238,16 @@ JSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec, JSObject*, JSValue
 
     UString s;
     if (x < 0) {
-        s.append('-');
+        s = "-";
         x = -x;
-    } else if (x == -0.0)
-        x = 0;
+    } else {
+        s = "";
+        if (x == -0.0)
+            x = 0;
+    }
 
     if (x >= pow(10.0, 21.0))
-        return jsString(exec, s + UString::from(x));
+        return jsString(exec, makeString(s, UString::from(x)));
 
     const double tenToTheF = pow(10.0, f);
     double n = floor(x * tenToTheF);
@@ -253,17 +258,19 @@ JSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec, JSObject*, JSValue
 
     int k = m.size();
     if (k <= f) {
-        UString z;
+        StringBuilder z;
         for (int i = 0; i < f + 1 - k; i++)
             z.append('0');
-        m = z + m;
+        z.append(m);
+        m = z.release();
         k = f + 1;
         ASSERT(k == m.size());
     }
     int kMinusf = k - f;
+
     if (kMinusf < m.size())
-        return jsString(exec, s + m.substr(0, kMinusf) + "." + m.substr(kMinusf));
-    return jsString(exec, s + m.substr(0, kMinusf));
+        return jsString(exec, makeString(s, m.substr(0, kMinusf), ".", m.substr(kMinusf)));
+    return jsString(exec, makeString(s, m.substr(0, kMinusf)));
 }
 
 static void fractionalPartToString(char* buf, int& i, const char* result, int resultLength, int fractionalDigits)
@@ -391,7 +398,8 @@ JSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec, JSObject*, JSV
     if (x < 0) {
         s = "-";
         x = -x;
-    }
+    } else
+        s = "";
 
     if (!(doublePrecision >= 1 && doublePrecision <= 21)) // true for NaN
         return throwError(exec, RangeError, "toPrecision() argument must be between 1 and 21");
@@ -422,10 +430,10 @@ JSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec, JSObject*, JSV
         m = integerPartNoExp(n);
         if (e < -6 || e >= precision) {
             if (m.size() > 1)
-                m = m.substr(0, 1) + "." + m.substr(1);
+                m = makeString(m.substr(0, 1), ".", m.substr(1));
             if (e >= 0)
-                return jsNontrivialString(exec, s + m + "e+" + UString::from(e));
-            return jsNontrivialString(exec, s + m + "e-" + UString::from(-e));
+                return jsNontrivialString(exec, makeString(s, m, "e+", UString::from(e)));
+            return jsNontrivialString(exec, makeString(s, m, "e-", UString::from(-e)));
         }
     } else {
         m = charSequence('0', precision);
@@ -433,13 +441,13 @@ JSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec, JSObject*, JSV
     }
 
     if (e == precision - 1)
-        return jsString(exec, s + m);
+        return jsString(exec, makeString(s, m));
     if (e >= 0) {
         if (e + 1 < m.size())
-            return jsString(exec, s + m.substr(0, e + 1) + "." + m.substr(e + 1));
-        return jsString(exec, s + m);
+            return jsString(exec, makeString(s, m.substr(0, e + 1), ".", m.substr(e + 1)));
+        return jsString(exec, makeString(s, m));
     }
-    return jsNontrivialString(exec, s + "0." + charSequence('0', -(e + 1)) + m);
+    return jsNontrivialString(exec, makeString(s, "0.", charSequence('0', -(e + 1)), m));
 }
 
 } // namespace JSC
index 2d1127b45de5f1dbe3b61e04bd7730fe09301f96..a56893c891d04ba2995e298d858b933b58ceee48 100644 (file)
@@ -128,6 +128,43 @@ namespace JSC {
         return new (globalData) JSString(globalData, rope.release());
     }
 
+    ALWAYS_INLINE JSValue jsString(ExecState* exec, JSValue thisValue, const ArgList& args)
+    {
+        unsigned ropeLength = 0;
+        if (LIKELY(thisValue.isString()))
+            ropeLength += asString(thisValue)->ropeLength();
+        else
+            ++ropeLength;
+        for (unsigned i = 0; i < args.size(); ++i) {
+            JSValue v = args.at(i);
+            if (LIKELY(v.isString()))
+                ropeLength += asString(v)->ropeLength();
+            else
+                ++ropeLength;
+        }
+
+        RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength);
+        if (UNLIKELY(!rope))
+            return throwOutOfMemoryError(exec);
+
+        unsigned index = 0;
+        if (LIKELY(thisValue.isString()))
+            rope->append(index, asString(thisValue));
+        else
+            rope->append(index, thisValue.toString(exec));
+        for (unsigned i = 0; i < args.size(); ++i) {
+            JSValue v = args.at(i);
+            if (LIKELY(v.isString()))
+                rope->append(index, asString(v));
+            else
+                rope->append(index, v.toString(exec));
+        }
+        ASSERT(index == ropeLength);
+
+        JSGlobalData* globalData = &exec->globalData();
+        return new (globalData) JSString(globalData, rope.release());
+    }
+
     // ECMA 11.9.3
     inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2)
     {
diff --git a/JavaScriptCore/runtime/StringBuilder.h b/JavaScriptCore/runtime/StringBuilder.h
new file mode 100644 (file)
index 0000000..6de2c3f
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef StringBuilder_h
+#define StringBuilder_h
+
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+class StringBuilder {
+public:
+    void append(const UChar u)
+    {
+        buffer.append(u);
+    }
+
+    void append(const char* str)
+    {
+        buffer.append(str, strlen(str));
+    }
+
+    void append(const char* str, size_t len)
+    {
+        buffer.reserveCapacity(buffer.size() + len);
+        for (size_t i = 0; i < len; i++)
+            buffer.append(static_cast<unsigned char>(str[i]));
+    }
+
+    void append(const UChar* str, size_t len)
+    {
+        buffer.append(str, len);
+    }
+
+    void append(const UString& str)
+    {
+        buffer.append(str.data(), str.size());
+    }
+
+    bool isEmpty() { return buffer.isEmpty(); }
+    void reserveCapacity(size_t newCapacity) { buffer.reserveCapacity(newCapacity); }
+    void resize(size_t size) { buffer.resize(size); }
+    size_t size() const { return buffer.size(); }
+
+    UChar operator[](size_t i) { return buffer.at(i); }
+    const UChar operator[](size_t i) const { return buffer.at(i); }
+
+    UString release()
+    {
+        buffer.shrinkToFit();
+        size_t length = buffer.size();
+        return UString(buffer.releaseBuffer(), length, false);
+    }
+
+private:
+    Vector<UChar, 64> buffer;
+};
+
+}
+
+#endif
index be5a6718ad5cb0958872cc059c2eebfc6e6d57c8..5f470fd070d3cfade4ed108f1ce3646a479f5b6a 100644 (file)
@@ -29,6 +29,7 @@
 #include "JSArray.h"
 #include "JSFunction.h"
 #include "ObjectPrototype.h"
+#include "Operations.h"
 #include "PropertyNameArray.h"
 #include "RegExpConstructor.h"
 #include "RegExpObject.h"
@@ -148,12 +149,11 @@ bool StringPrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier
 
 // ------------------------------ Functions --------------------------
 
-static inline UString substituteBackreferences(const UString& replacement, const UString& source, const int* ovector, RegExp* reg)
+static NEVER_INLINE UString substituteBackreferencesSlow(const UString& replacement, const UString& source, const int* ovector, RegExp* reg, int i)
 {
-    UString substitutedReplacement;
+    Vector<UChar> substitutedReplacement;
     int offset = 0;
-    int i = -1;
-    while ((i = replacement.find('$', i + 1)) != -1) {
+    do {
         if (i + 1 == replacement.size())
             break;
 
@@ -205,15 +205,22 @@ static inline UString substituteBackreferences(const UString& replacement, const
         i += 1 + advance;
         offset = i + 1;
         substitutedReplacement.append(source.data() + backrefStart, backrefLength);
-    }
-
-    if (!offset)
-        return replacement;
+    } while ((i = replacement.find('$', i + 1)) != -1);
 
     if (replacement.size() - offset)
         substitutedReplacement.append(replacement.data() + offset, replacement.size() - offset);
 
-    return substitutedReplacement;
+    substitutedReplacement.shrinkToFit();
+    unsigned size = substitutedReplacement.size();
+    return UString(substitutedReplacement.releaseBuffer(), size, false);
+}
+
+static inline UString substituteBackreferences(const UString& replacement, const UString& source, const int* ovector, RegExp* reg)
+{
+    int i = replacement.find('$', 0);
+    if (UNLIKELY(i != -1))
+        return substituteBackreferencesSlow(replacement, source, ovector, reg, i);
+    return replacement;
 }
 
 static inline int localeCompare(const UString& a, const UString& b)
@@ -423,12 +430,14 @@ JSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState* exec, JSObject*, JSVa
 
 JSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
 {
-    UString s = thisValue.toThisString(exec);
+    if (thisValue.isString() && (args.size() == 1)) {
+        JSValue v = args.at(0);
+        return v.isString()
+            ? jsString(exec, asString(thisValue), asString(v))
+            : jsString(exec, asString(thisValue), v.toString(exec));
+    }
 
-    ArgList::const_iterator end = args.end();
-    for (ArgList::const_iterator it = args.begin(); it != end; ++it)
-        s += (*it).toString(exec);
-    return jsString(exec, s);
+    return jsString(exec, thisValue, args);
 }
 
 JSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
index 9c2433bd2afa0f8cbaceec457a5c1f6380612ed9..ec9c2117b54be09c16fcc7b466691a364b2caca4 100644 (file)
@@ -543,8 +543,7 @@ namespace JSC {
     };
 
     template<>
-    class StringTypeAdapter<char*>
-    {
+    class StringTypeAdapter<char*> {
     public:
         StringTypeAdapter<char*>(char* buffer)
             : m_buffer((unsigned char*)buffer)
@@ -566,8 +565,7 @@ namespace JSC {
     };
 
     template<>
-    class StringTypeAdapter<const char*>
-    {
+    class StringTypeAdapter<const char*> {
     public:
         StringTypeAdapter<const char*>(const char* buffer)
             : m_buffer((unsigned char*)buffer)
@@ -589,8 +587,7 @@ namespace JSC {
     };
 
     template<>
-    class StringTypeAdapter<UString>
-    {
+    class StringTypeAdapter<UString> {
     public:
         StringTypeAdapter<UString>(UString& string)
             : m_data(string.data())