2008-06-26 Darin Adler <darin@apple.com>
authordarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Jun 2008 02:53:42 +0000 (02:53 +0000)
committerdarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Jun 2008 02:53:42 +0000 (02:53 +0000)
        Reviewed by Geoff.

        - https://bugs.webkit.org/show_bug.cgi?id=19721
          speed up JavaScriptCore by not wrapping strings in objects just
          to call functions on them

        - optimize UString append and the replace function a bit

        SunSpider says 1.8% faster.

        * JavaScriptCore.exp: Updated.

        * VM/JSPropertyNameIterator.cpp: Added include of JSString.h, now needed
        because jsString returns a JSString*.

        * VM/Machine.cpp:
        (KJS::Machine::privateExecute): Removed the toObject call from native
        function calls. Also removed code to put the this value into a register.

        * kjs/BooleanObject.cpp:
        (KJS::booleanProtoFuncToString): Rewrite to handle false and true
        separately.

        * kjs/FunctionPrototype.cpp:
        (KJS::constructFunction): Use single-character append rather than building
        a string for each character.
        * kjs/JSFunction.cpp:
        (KJS::globalFuncUnescape): Ditto.

        * kjs/JSImmediate.cpp:
        (KJS::JSImmediate::prototype): Added. Gets the appropriate prototype for
        use with an immediate value. To be used instead of toObject when doing a
        get on an immediate value.
        * kjs/JSImmediate.h: Added prototype.

        * kjs/JSObject.cpp:
        (KJS::JSObject::toString): Tweaked formatting.

        * kjs/JSObject.h:
        (KJS::JSValue::get): Use prototype instead of toObject to avoid creating
        an object wrapper just to search for properties. This also saves an
        unnecessary hash table lookup since the object wrappers themselves don't
        have any properties.

        * kjs/JSString.h: Added toThisString and toThisJSString.

        * kjs/JSValue.cpp:
        (KJS::JSCell::toThisString): Added.
        (KJS::JSCell::toThisJSString): Added.
        (KJS::JSCell::getJSNumber): Added.
        (KJS::jsString): Changed return type to JSString*.
        (KJS::jsOwnedString): Ditto.

        * kjs/JSValue.h:
        (KJS::JSValue::toThisString): Added.
        (KJS::JSValue::toThisJSString): Added.
        (KJS::JSValue::getJSNumber): Added.

        * kjs/NumberObject.cpp:
        (KJS::NumberObject::getJSNumber): Added.
        (KJS::integer_part_noexp): Append C string directly rather than first
        turning it into a UString.
        (KJS::numberProtoFuncToString): Use getJSNumber to check if the value
        is a number rather than isObject(&NumberObject::info). This works for
        immediate numbers, number cells, and NumberObject instances.
        (KJS::numberProtoFuncToLocaleString): Ditto.
        (KJS::numberProtoFuncValueOf): Ditto.
        (KJS::numberProtoFuncToFixed): Ditto.
        (KJS::numberProtoFuncToExponential): Ditto.
        (KJS::numberProtoFuncToPrecision): Ditto.
        * kjs/NumberObject.h: Added getJSNumber.

        * kjs/PropertySlot.cpp: Tweaked comment.

        * kjs/internal.cpp:
        (KJS::JSString::toThisString): Added.
        (KJS::JSString::toThisJSString): Added.
        (KJS::JSString::getOwnPropertySlot): Changed code that searches the
        prototype chain to start with the string prototype and not create a
        string object.
        (KJS::JSNumberCell::toThisString): Added.
        (KJS::JSNumberCell::getJSNumber): Added.

        * kjs/lookup.cpp:
        (KJS::staticFunctionGetter): Moved here, because there's no point in
        having a function that's only used for a function pointer be inline.
        (KJS::setUpStaticFunctionSlot): New function for getStaticFunctionSlot.

        * kjs/lookup.h:
        (KJS::staticValueGetter): Don't mark this inline. It doesn't make sense
        to have a function that's only used for a function pointer be inline.
        (KJS::getStaticFunctionSlot): Changed to get properties from the parent
        first before doing any handling of functions. This is the fastest way
        to return the function once the initial setup is done.

        * kjs/string_object.cpp:
        (KJS::StringObject::getPropertyNames): Call value() instead of getString(),
        avoiding an unnecessary virtual function call (the call to the type()
        function in the implementation of the isString() function).
        (KJS::StringObject::toString): Added.
        (KJS::StringObject::toThisString): Added.
        (KJS::StringObject::toThisJSString): Added.
        (KJS::substituteBackreferences): Rewrote to use a appending algorithm
        instead of a the old one that tried to replace in place.
        (KJS::stringProtoFuncReplace): Merged this function and the replace function.
        Replaced the hand-rolled dynamic arrays for source ranges and replacements
        with Vector.
        (KJS::stringProtoFuncToString): Handle JSString as well as StringObject.
        Removed the separate valueOf implementation, since it can just share this.
        (KJS::stringProtoFuncCharAt): Use toThisString, which handles JSString as
        well as StringObject, and is slightly more efficient than the old code too.
        (KJS::stringProtoFuncCharCodeAt): Ditto.
        (KJS::stringProtoFuncConcat): Ditto.
        (KJS::stringProtoFuncIndexOf): Ditto.
        (KJS::stringProtoFuncLastIndexOf): Ditto.
        (KJS::stringProtoFuncMatch): Ditto.
        (KJS::stringProtoFuncSearch): Ditto.
        (KJS::stringProtoFuncSlice): Ditto.
        (KJS::stringProtoFuncSplit): Ditto.
        (KJS::stringProtoFuncSubstr): Ditto.
        (KJS::stringProtoFuncSubstring): Ditto.
        (KJS::stringProtoFuncToLowerCase): Use toThisJSString.
        (KJS::stringProtoFuncToUpperCase): Ditto.
        (KJS::stringProtoFuncToLocaleLowerCase): Ditto.
        (KJS::stringProtoFuncToLocaleUpperCase): Ditto.
        (KJS::stringProtoFuncLocaleCompare): Ditto.
        (KJS::stringProtoFuncBig): Use toThisString.
        (KJS::stringProtoFuncSmall): Ditto.
        (KJS::stringProtoFuncBlink): Ditto.
        (KJS::stringProtoFuncBold): Ditto.
        (KJS::stringProtoFuncFixed): Ditto.
        (KJS::stringProtoFuncItalics): Ditto.
        (KJS::stringProtoFuncStrike): Ditto.
        (KJS::stringProtoFuncSub): Ditto.
        (KJS::stringProtoFuncSup): Ditto.
        (KJS::stringProtoFuncFontcolor): Ditto.
        (KJS::stringProtoFuncFontsize): Ditto.
        (KJS::stringProtoFuncAnchor): Ditto.
        (KJS::stringProtoFuncLink): Ditto.

        * kjs/string_object.h: Added toString, toThisString, and toThisJSString.

        * kjs/ustring.cpp:
        (KJS::UString::append): Added a version that takes a character pointer and
        size, so we don't have to create a UString just to append to another UString.
        * kjs/ustring.h:

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

24 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.exp
JavaScriptCore/VM/JSPropertyNameIterator.cpp
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/kjs/BooleanObject.cpp
JavaScriptCore/kjs/FunctionPrototype.cpp
JavaScriptCore/kjs/JSFunction.cpp
JavaScriptCore/kjs/JSImmediate.cpp
JavaScriptCore/kjs/JSImmediate.h
JavaScriptCore/kjs/JSObject.cpp
JavaScriptCore/kjs/JSObject.h
JavaScriptCore/kjs/JSString.h
JavaScriptCore/kjs/JSValue.cpp
JavaScriptCore/kjs/JSValue.h
JavaScriptCore/kjs/NumberObject.cpp
JavaScriptCore/kjs/NumberObject.h
JavaScriptCore/kjs/PropertySlot.cpp
JavaScriptCore/kjs/internal.cpp
JavaScriptCore/kjs/lookup.cpp
JavaScriptCore/kjs/lookup.h
JavaScriptCore/kjs/string_object.cpp
JavaScriptCore/kjs/string_object.h
JavaScriptCore/kjs/ustring.cpp
JavaScriptCore/kjs/ustring.h

index 5ff4db1d1c58ab5d876b9747f2556115b113d3dc..1a213cdeb8a11295cc4a4bb3dae4f98bfb71bc19 100644 (file)
@@ -1,3 +1,152 @@
+2008-06-26  Darin Adler  <darin@apple.com>
+
+        Reviewed by Geoff.
+
+        - https://bugs.webkit.org/show_bug.cgi?id=19721
+          speed up JavaScriptCore by not wrapping strings in objects just
+          to call functions on them
+
+        - optimize UString append and the replace function a bit
+
+        SunSpider says 1.8% faster.
+
+        * JavaScriptCore.exp: Updated.
+
+        * VM/JSPropertyNameIterator.cpp: Added include of JSString.h, now needed
+        because jsString returns a JSString*.
+
+        * VM/Machine.cpp:
+        (KJS::Machine::privateExecute): Removed the toObject call from native
+        function calls. Also removed code to put the this value into a register.
+
+        * kjs/BooleanObject.cpp:
+        (KJS::booleanProtoFuncToString): Rewrite to handle false and true
+        separately.
+
+        * kjs/FunctionPrototype.cpp:
+        (KJS::constructFunction): Use single-character append rather than building
+        a string for each character.
+        * kjs/JSFunction.cpp:
+        (KJS::globalFuncUnescape): Ditto.
+
+        * kjs/JSImmediate.cpp:
+        (KJS::JSImmediate::prototype): Added. Gets the appropriate prototype for
+        use with an immediate value. To be used instead of toObject when doing a
+        get on an immediate value.
+        * kjs/JSImmediate.h: Added prototype.
+
+        * kjs/JSObject.cpp:
+        (KJS::JSObject::toString): Tweaked formatting.
+
+        * kjs/JSObject.h:
+        (KJS::JSValue::get): Use prototype instead of toObject to avoid creating
+        an object wrapper just to search for properties. This also saves an
+        unnecessary hash table lookup since the object wrappers themselves don't
+        have any properties.
+
+        * kjs/JSString.h: Added toThisString and toThisJSString.
+
+        * kjs/JSValue.cpp:
+        (KJS::JSCell::toThisString): Added.
+        (KJS::JSCell::toThisJSString): Added.
+        (KJS::JSCell::getJSNumber): Added.
+        (KJS::jsString): Changed return type to JSString*.
+        (KJS::jsOwnedString): Ditto.
+
+        * kjs/JSValue.h:
+        (KJS::JSValue::toThisString): Added.
+        (KJS::JSValue::toThisJSString): Added.
+        (KJS::JSValue::getJSNumber): Added.
+
+        * kjs/NumberObject.cpp:
+        (KJS::NumberObject::getJSNumber): Added.
+        (KJS::integer_part_noexp): Append C string directly rather than first
+        turning it into a UString.
+        (KJS::numberProtoFuncToString): Use getJSNumber to check if the value
+        is a number rather than isObject(&NumberObject::info). This works for
+        immediate numbers, number cells, and NumberObject instances.
+        (KJS::numberProtoFuncToLocaleString): Ditto.
+        (KJS::numberProtoFuncValueOf): Ditto.
+        (KJS::numberProtoFuncToFixed): Ditto.
+        (KJS::numberProtoFuncToExponential): Ditto.
+        (KJS::numberProtoFuncToPrecision): Ditto.
+        * kjs/NumberObject.h: Added getJSNumber.
+
+        * kjs/PropertySlot.cpp: Tweaked comment.
+
+        * kjs/internal.cpp:
+        (KJS::JSString::toThisString): Added.
+        (KJS::JSString::toThisJSString): Added.
+        (KJS::JSString::getOwnPropertySlot): Changed code that searches the
+        prototype chain to start with the string prototype and not create a
+        string object.
+        (KJS::JSNumberCell::toThisString): Added.
+        (KJS::JSNumberCell::getJSNumber): Added.
+
+        * kjs/lookup.cpp:
+        (KJS::staticFunctionGetter): Moved here, because there's no point in
+        having a function that's only used for a function pointer be inline.
+        (KJS::setUpStaticFunctionSlot): New function for getStaticFunctionSlot.
+
+        * kjs/lookup.h:
+        (KJS::staticValueGetter): Don't mark this inline. It doesn't make sense
+        to have a function that's only used for a function pointer be inline.
+        (KJS::getStaticFunctionSlot): Changed to get properties from the parent
+        first before doing any handling of functions. This is the fastest way
+        to return the function once the initial setup is done.
+
+        * kjs/string_object.cpp:
+        (KJS::StringObject::getPropertyNames): Call value() instead of getString(),
+        avoiding an unnecessary virtual function call (the call to the type()
+        function in the implementation of the isString() function).
+        (KJS::StringObject::toString): Added.
+        (KJS::StringObject::toThisString): Added.
+        (KJS::StringObject::toThisJSString): Added.
+        (KJS::substituteBackreferences): Rewrote to use a appending algorithm
+        instead of a the old one that tried to replace in place.
+        (KJS::stringProtoFuncReplace): Merged this function and the replace function.
+        Replaced the hand-rolled dynamic arrays for source ranges and replacements
+        with Vector.
+        (KJS::stringProtoFuncToString): Handle JSString as well as StringObject.
+        Removed the separate valueOf implementation, since it can just share this.
+        (KJS::stringProtoFuncCharAt): Use toThisString, which handles JSString as
+        well as StringObject, and is slightly more efficient than the old code too.
+        (KJS::stringProtoFuncCharCodeAt): Ditto.
+        (KJS::stringProtoFuncConcat): Ditto.
+        (KJS::stringProtoFuncIndexOf): Ditto.
+        (KJS::stringProtoFuncLastIndexOf): Ditto.
+        (KJS::stringProtoFuncMatch): Ditto.
+        (KJS::stringProtoFuncSearch): Ditto.
+        (KJS::stringProtoFuncSlice): Ditto.
+        (KJS::stringProtoFuncSplit): Ditto.
+        (KJS::stringProtoFuncSubstr): Ditto.
+        (KJS::stringProtoFuncSubstring): Ditto.
+        (KJS::stringProtoFuncToLowerCase): Use toThisJSString.
+        (KJS::stringProtoFuncToUpperCase): Ditto.
+        (KJS::stringProtoFuncToLocaleLowerCase): Ditto.
+        (KJS::stringProtoFuncToLocaleUpperCase): Ditto.
+        (KJS::stringProtoFuncLocaleCompare): Ditto.
+        (KJS::stringProtoFuncBig): Use toThisString.
+        (KJS::stringProtoFuncSmall): Ditto.
+        (KJS::stringProtoFuncBlink): Ditto.
+        (KJS::stringProtoFuncBold): Ditto.
+        (KJS::stringProtoFuncFixed): Ditto.
+        (KJS::stringProtoFuncItalics): Ditto.
+        (KJS::stringProtoFuncStrike): Ditto.
+        (KJS::stringProtoFuncSub): Ditto.
+        (KJS::stringProtoFuncSup): Ditto.
+        (KJS::stringProtoFuncFontcolor): Ditto.
+        (KJS::stringProtoFuncFontsize): Ditto.
+        (KJS::stringProtoFuncAnchor): Ditto.
+        (KJS::stringProtoFuncLink): Ditto.
+
+        * kjs/string_object.h: Added toString, toThisString, and toThisJSString.
+
+        * kjs/ustring.cpp:
+        (KJS::UString::append): Added a version that takes a character pointer and
+        size, so we don't have to create a UString just to append to another UString.
+        * kjs/ustring.h:
+
 2008-06-26  Alexey Proskuryakov  <ap@webkit.org>
 
         Reviewed by Maciej.
index e6851f5b0e46e9cfbf3154c7330358c987bbb8c1..2c2ece81dcf5403e582e3da3e44580e57982913a 100644 (file)
@@ -90,6 +90,7 @@ __ZN3KJS11Interpreter8evaluateEPNS_9ExecStateERNS_10ScopeChainERKNS_7UStringEiN3
 __ZN3KJS11Interpreter8evaluateEPNS_9ExecStateERNS_10ScopeChainERKNS_7UStringEiS7_PNS_7JSValueE
 __ZN3KJS11JSImmediate8toObjectEPKNS_7JSValueEPNS_9ExecStateE
 __ZN3KJS11JSImmediate8toStringEPKNS_7JSValueE
+__ZN3KJS11JSImmediate9prototypeEPKNS_7JSValueEPNS_9ExecStateE
 __ZN3KJS11ProfileNode4sortEPFbRKN3WTF6RefPtrIS0_EES5_E
 __ZN3KJS11ProgramNode6createEPNS_12JSGlobalDataEPNS_14SourceElementsEPN3WTF6VectorISt4pairINS_10IdentifierEjELm16EEEPNS6_INS5_6RefPtrINS_12FuncDeclNodeEEELm16EEEbb
 __ZN3KJS11PropertyMap11getLocationERKNS_10IdentifierE
@@ -102,6 +103,7 @@ __ZN3KJS12JSGlobalData14threadInstanceEv
 __ZN3KJS12PropertySlot15undefinedGetterEPNS_9ExecStateERKNS_10IdentifierERKS0_
 __ZN3KJS12RegisterFile14addGlobalSlotsEm
 __ZN3KJS12StringObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
+__ZN3KJS12StringObject14toThisJSStringEPNS_9ExecStateE
 __ZN3KJS12StringObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE
 __ZN3KJS12StringObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
 __ZN3KJS12StringObject18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
@@ -138,7 +140,9 @@ __ZN3KJS17RegisterFileStack20allocateRegisterFileEmPS0_
 __ZN3KJS17constructFunctionEPNS_9ExecStateERKNS_7ArgListERKNS_10IdentifierERKNS_7UStringEi
 __ZN3KJS19constructEmptyArrayEPNS_9ExecStateE
 __ZN3KJS19initializeThreadingEv
+__ZN3KJS20staticFunctionGetterEPNS_9ExecStateERKNS_10IdentifierERKNS_12PropertySlotE
 __ZN3KJS23objectProtoFuncToStringEPNS_9ExecStateEPNS_8JSObjectEPNS_7JSValueERKNS_7ArgListE
+__ZN3KJS23setUpStaticFunctionSlotEPNS_9ExecStateEPKNS_9HashEntryEPNS_8JSObjectERKNS_10IdentifierERNS_12PropertySlotE
 __ZN3KJS4Heap14allocateNumberEm
 __ZN3KJS4Heap15recordExtraCostEm
 __ZN3KJS4Heap17globalObjectCountEv
@@ -154,8 +158,10 @@ __ZN3KJS4Heap9unprotectEPNS_7JSValueE
 __ZN3KJS4callEPNS_9ExecStateEPNS_7JSValueENS_8CallTypeERKNS_8CallDataES3_RKNS_7ArgListE
 __ZN3KJS5equalEPKNS_7UString3RepES3_
 __ZN3KJS6JSCell11getCallDataERNS_8CallDataE
+__ZN3KJS6JSCell11getJSNumberEv
 __ZN3KJS6JSCell14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
 __ZN3KJS6JSCell14deletePropertyEPNS_9ExecStateEj
+__ZN3KJS6JSCell14toThisJSStringEPNS_9ExecStateE
 __ZN3KJS6JSCell16getConstructDataERNS_13ConstructDataE
 __ZN3KJS6JSCell18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
 __ZN3KJS6JSCell18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
@@ -247,6 +253,8 @@ __ZN3WTF8CollatorD1Ev
 __ZN3WTF8fastFreeEPv
 __ZNK3KJS11PropertyMap3getERKNS_10IdentifierE
 __ZNK3KJS12DateInstance7getTimeERdRi
+__ZNK3KJS12StringObject12toThisStringEPNS_9ExecStateE
+__ZNK3KJS12StringObject8toStringEPNS_9ExecStateE
 __ZNK3KJS14JSGlobalObject14isDynamicScopeEv
 __ZNK3KJS14JSGlobalObject14toGlobalObjectEPNS_9ExecStateE
 __ZNK3KJS16InternalFunction21implementsHasInstanceEv
@@ -258,6 +266,7 @@ __ZNK3KJS17DebuggerCallFrame4typeEv
 __ZNK3KJS17DebuggerCallFrame8evaluateERKNS_7UStringERPNS_7JSValueE
 __ZNK3KJS4Node8toStringEv
 __ZNK3KJS6JSCell12toThisObjectEPNS_9ExecStateE
+__ZNK3KJS6JSCell12toThisStringEPNS_9ExecStateE
 __ZNK3KJS6JSCell17getTruncatedInt32ERi
 __ZNK3KJS6JSCell18getTruncatedUInt32ERj
 __ZNK3KJS6JSCell9classInfoEv
index ab46ee331d7e907e34c8b04633dab35795450181..be5b18040e443b57c1b22dbf1909edfd1a011c13 100644 (file)
 #include "config.h"
 #include "JSPropertyNameIterator.h"
 
-#include "identifier.h"
 #include "JSObject.h"
+#include "JSString.h"
 #include "PropertyNameArray.h"
+#include "identifier.h"
 
 namespace KJS {
 
index 6c9640bc5e1c9aa4a280b60400fe54ae145fbd82..956cf975fc4264ae86a7d2303627abc27845f079 100644 (file)
@@ -2114,8 +2114,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
                 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
             int registerOffset = r - (*registerBase);
 
-            r[firstArg].u.jsValue = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : (r[thisVal].u.jsValue)->toObject(exec);
-            JSValue* thisValue = r[firstArg].u.jsValue;
+            JSValue* thisValue = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].u.jsValue;
 
             ArgList args(reinterpret_cast<JSValue***>(registerBase), registerOffset + firstArg + 1, argCount - 1);
 
index d70cb36f0141b6ccf16dee3d0a91d9a53587d4cd..5833de7c95a2e38331cec662b5bae072a5c51824 100644 (file)
@@ -61,13 +61,20 @@ BooleanPrototype::BooleanPrototype(ExecState* exec, ObjectPrototype* objectProto
 
 JSValue* booleanProtoFuncToString(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
 {
-    if (JSImmediate::isBoolean(thisValue))
-        return jsString(exec, JSImmediate::toString(thisValue));
+    if (thisValue == jsBoolean(false))
+        return jsString(exec, "false");
+
+    if (thisValue == jsBoolean(true))
+        return jsString(exec, "true");
 
     if (!thisValue->isObject(&BooleanObject::info))
         return throwError(exec, TypeError);
 
-    return jsString(exec, JSImmediate::toString(static_cast<BooleanObject*>(thisValue)->internalValue()));
+    if (static_cast<BooleanObject*>(thisValue)->internalValue() == jsBoolean(false))
+        return jsString(exec, "false");
+
+    ASSERT(static_cast<BooleanObject*>(thisValue)->internalValue() == jsBoolean(true));
+    return jsString(exec, "true");
 }
 
 JSValue* booleanProtoFuncValueOf(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
index 6cc42ff49c843bd60c6216c2f42577f684266b38..eca341c592e91783ff24a4028822e43d3e398e51 100644 (file)
@@ -214,7 +214,7 @@ JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifi
             param = UString(c, 1);
             c++, i++;
             while (i < len && (Lexer::isIdentPart(c[0]))) {
-                param += UString(c, 1);
+                param.append(*c);
                 c++, i++;
             }
             while (i < len && *c == ' ')
index 62399e23aefc3288464108fa0c19ca9449ba4379..a600ceb377c24e2c119429c1319ca7c13a203e9f 100644 (file)
@@ -692,7 +692,7 @@ JSValue* globalFuncUnescape(ExecState* exec, JSObject*, JSValue*, const ArgList&
             k += 2;
         }
         k++;
-        s += UString(c, 1);
+        s.append(*c);
     }
 
     return jsString(exec, s);
index 4270fe58a253f81166b9ac2de60444098d86f6d7..0a57febc84d96121c497165eb1fcb5ad5399ef9c 100644 (file)
 #include "config.h"
 #include "JSImmediate.h"
 
-#include "JSGlobalObject.h"
 #include "BooleanObject.h"
 #include "JSNotAnObject.h"
 #include "NumberObject.h"
-#include "JSObject.h"
 
 namespace KJS {
 
-JSObject* JSImmediate::toObject(const JSValue *v, ExecState *exec)
+JSObject* JSImmediate::toObject(const JSValue* v, ExecState* exec)
 {
     ASSERT(isImmediate(v));
+    if (isNumber(v))
+        return constructNumberFromImmediateNumber(exec, const_cast<JSValue*>(v));
+    if (isBoolean(v))
+        return constructBooleanFromImmediateBoolean(exec, const_cast<JSValue*>(v));
     if (v == jsNull())
         return new (exec) JSNotAnObject(throwError(exec, TypeError, "Null value"));
-    if (v == jsUndefined())
-        return new (exec) JSNotAnObject(throwError(exec, TypeError, "Undefined value"));
+    ASSERT(v == jsUndefined());
+    return new (exec) JSNotAnObject(throwError(exec, TypeError, "Undefined value"));
+}
+
+JSObject* JSImmediate::prototype(const JSValue* v, ExecState* exec)
+{
+    ASSERT(isImmediate(v));
+    if (isNumber(v))
+        return exec->lexicalGlobalObject()->numberPrototype();
     if (isBoolean(v))
-        return constructBooleanFromImmediateBoolean(exec, const_cast<JSValue*>(v));
-    ASSERT(isNumber(v));
-    return constructNumberFromImmediateNumber(exec, const_cast<JSValue*>(v));
+        return exec->lexicalGlobalObject()->booleanPrototype();
+    if (v == jsNull())
+        return new (exec) JSNotAnObject(throwError(exec, TypeError, "Null value"));
+    ASSERT(v == jsUndefined());
+    return new (exec) JSNotAnObject(throwError(exec, TypeError, "Undefined value"));
 }
 
 UString JSImmediate::toString(const JSValue* v)
 {
     ASSERT(isImmediate(v));
-    if (v == jsNull())
-        return "null";
-    if (v == jsUndefined())
-        return "undefined";
-    if (v == jsBoolean(true))
-        return "true";
+    if (isNumber(v))
+        return UString::from(getTruncatedInt32(v));
     if (v == jsBoolean(false))
         return "false";
-    ASSERT(isNumber(v));
-    return UString::from(getTruncatedInt32(v));
+    if (v == jsBoolean(true))
+        return "true";
+    if (v == jsNull())
+        return "null";
+    ASSERT(v == jsUndefined());
+    return "undefined";
 }
 
 } // namespace KJS
index 266f6b7f9f8183274c011a84e18edfdf2d54877c..89a07aa7ded0d0099c8f00fc14025b3847947f2b 100644 (file)
@@ -183,6 +183,8 @@ public:
 
     static JSValue* impossibleValue();
     
+    static JSObject* prototype(const JSValue*, ExecState*);
+
 private:
     static const uintptr_t TagMask = 3; // type tags are 2 bits long
 
index 023e5df6ca65eb9415acd617f3c4f898352b3da2..90a9b6073c053dc4ed530c770a2843aa8a66b00c 100644 (file)
@@ -434,12 +434,12 @@ double JSObject::toNumber(ExecState *exec) const
   return prim->toNumber(exec);
 }
 
-UString JSObject::toString(ExecState *exec) const
+UString JSObject::toString(ExecStateexec) const
 {
-  JSValue *prim = toPrimitive(exec,StringType);
-  if (exec->hadException()) // should be picked up soon in nodes.cpp
-    return "";
-  return prim->toString(exec);
+    JSValue* primitive = toPrimitive(exec, StringType);
+    if (exec->hadException())
+        return "";
+    return primitive->toString(exec);
 }
 
 JSObject *JSObject::toObject(ExecState*) const
index ca376c7ad6506c2c8964c62169704dc00fd37b69..819d92c3bcf558c1862f36bc8c007354e591c39a 100644 (file)
@@ -581,9 +581,9 @@ inline JSValue* JSObject::toPrimitive(ExecState* exec, JSType preferredType) con
 inline JSValue* JSValue::get(ExecState* exec, const Identifier& propertyName) const
 {
     if (UNLIKELY(JSImmediate::isImmediate(this))) {
-        JSObject* object = JSImmediate::toObject(this, exec);
-        PropertySlot slot(object);
-        if (!object->getPropertySlot(exec, propertyName, slot))
+        JSObject* prototype = JSImmediate::prototype(this, exec);
+        PropertySlot slot(const_cast<JSValue*>(this));
+        if (!prototype->getPropertySlot(exec, propertyName, slot))
             return jsUndefined();
         return slot.getValue(exec, propertyName);
     }
@@ -603,9 +603,9 @@ inline JSValue* JSValue::get(ExecState* exec, const Identifier& propertyName) co
 inline JSValue* JSValue::get(ExecState* exec, unsigned propertyName) const
 {
     if (UNLIKELY(JSImmediate::isImmediate(this))) {
-        JSObject* object = JSImmediate::toObject(this, exec);
-        PropertySlot slot(object);
-        if (!object->getPropertySlot(exec, propertyName, slot))
+        JSObject* prototype = JSImmediate::prototype(this, exec);
+        PropertySlot slot(const_cast<JSValue*>(this));
+        if (!prototype->getPropertySlot(exec, propertyName, slot))
             return jsUndefined();
         return slot.getValue(exec, propertyName);
     }
index f6de21e126742dd62c773f1a4fe464915b95b2ca..169c634795e237660dbd1b294ccbff652644a5bb 100644 (file)
@@ -49,7 +49,10 @@ namespace KJS {
     virtual double toNumber(ExecState*) const;
     virtual JSObject* toObject(ExecState*) const;
     virtual UString toString(ExecState*) const;
+
     virtual JSObject* toThisObject(ExecState*) const;
+    virtual UString toThisString(ExecState*) const;
+    virtual JSString* toThisJSString(ExecState*);
 
     // Actually getPropertySlot, not getOwnPropertySlot (see JSCell).
     virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
index d3abe36ae95b396f71e059b97f0f54f00eaa088d..85baa6b249df4ca17184a61e00873f5e5e99adf4 100644 (file)
@@ -270,22 +270,37 @@ JSObject* JSCell::toThisObject(ExecState* exec) const
     return toObject(exec);
 }
 
+UString JSCell::toThisString(ExecState* exec) const
+{
+    return toThisObject(exec)->toString(exec);
+}
+
+JSString* JSCell::toThisJSString(ExecState* exec)
+{
+    return jsString(exec, toThisString(exec));
+}
+
 const ClassInfo* JSCell::classInfo() const
 {
     return 0;
 }
 
-JSCell* jsString(ExecState* exec, const char* s)
+JSValue* JSCell::getJSNumber()
+{
+    return 0;
+}
+
+JSString* jsString(ExecState* exec, const char* s)
 {
     return new (exec) JSString(s ? s : "");
 }
 
-JSCell* jsString(ExecState* exec, const UString& s)
+JSString* jsString(ExecState* exec, const UString& s)
 {
     return s.isNull() ? new (exec) JSString("") : new (exec) JSString(s);
 }
 
-JSCell* jsOwnedString(ExecState* exec, const UString& s)
+JSString* jsOwnedString(ExecState* exec, const UString& s)
 {
     return s.isNull() ? new (exec) JSString("", JSString::HasOtherOwner) : new (exec) JSString(s, JSString::HasOtherOwner);
 }
@@ -295,7 +310,7 @@ JSValue* call(ExecState* exec, JSValue* functionObject, CallType callType, const
     if (callType == CallTypeNative)
         return callData.native.function(exec, static_cast<JSObject*>(functionObject), thisValue, args);
     ASSERT(callType == CallTypeJS);
-    // FIXME: This can be done more efficiently using the callData.
+    // FIXME: Can this be done more efficiently using the callData?
     return static_cast<JSFunction*>(functionObject)->call(exec, thisValue, args);
 }
 
@@ -304,7 +319,7 @@ JSObject* construct(ExecState* exec, JSValue* object, ConstructType constructTyp
     if (constructType == ConstructTypeNative)
         return constructData.native.function(exec, static_cast<JSObject*>(object), args);
     ASSERT(constructType == ConstructTypeJS);
-    // FIXME: This can be done more efficiently using the constructData.
+    // FIXME: Can this be done more efficiently using the constructData?
     return static_cast<JSFunction*>(object)->construct(exec, args);
 }
 
index ff43ada16eb30fc1aded15eb68ca0725698255c6..d1a88e4d34a5e309d18dd7d00a441bbb15f69d20 100644 (file)
@@ -35,8 +35,9 @@ namespace KJS {
 
 class ExecState;
 class Identifier;
-class JSObject;
 class JSCell;
+class JSObject;
+class JSString;
 class PropertySlot;
 
 struct ClassInfo;
@@ -130,7 +131,12 @@ public:
     void put(ExecState*, unsigned propertyName, JSValue*);
     bool deleteProperty(ExecState*, const Identifier& propertyName);
     bool deleteProperty(ExecState*, unsigned propertyName);
+
     JSObject* toThisObject(ExecState*) const;
+    UString toThisString(ExecState*) const;
+    JSString* toThisJSString(ExecState*);
+
+    JSValue* getJSNumber(); // 0 if this is not a JSNumber or number object
 
 private:
     bool getPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
@@ -198,7 +204,11 @@ public:
     virtual void put(ExecState*, unsigned propertyName, JSValue*);
     virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
     virtual bool deleteProperty(ExecState*, unsigned propertyName);
+
     virtual JSObject* toThisObject(ExecState*) const;
+    virtual UString toThisString(ExecState*) const;
+    virtual JSString* toThisJSString(ExecState*);
+    virtual JSValue* getJSNumber();
 
 private:
     // Base implementation, but for non-object classes implements getPropertySlot.
@@ -219,7 +229,10 @@ public:
     virtual double toNumber(ExecState*) const;
     virtual UString toString(ExecState*) const;
     virtual JSObject* toObject(ExecState*) const;
+
+    virtual UString toThisString(ExecState*) const;
     virtual JSObject* toThisObject(ExecState*) const;
+    virtual JSValue* getJSNumber();
 
     void* operator new(size_t size, ExecState* exec)
     {
@@ -243,13 +256,13 @@ private:
     double val;
 };
 
-JSCell* jsString(ExecState*, const UString&); // returns empty string if passed null string
-JSCell* jsString(ExecState*, const char* = ""); // returns empty string if passed 0
+JSString* jsString(ExecState*, const UString&); // returns empty string if passed null string
+JSString* jsString(ExecState*, const char* = ""); // returns empty string if passed 0
 
 // should be used for strings that are owned by an object that will
 // likely outlive the JSValue this makes, such as the parse tree or a
 // DOM object that contains a UString
-JSCell* jsOwnedString(ExecState*, const UString&); 
+JSString* jsOwnedString(ExecState*, const UString&); 
 
 extern const double NaN;
 extern const double Inf;
@@ -595,6 +608,21 @@ inline JSObject* JSValue::toThisObject(ExecState* exec) const
     return asCell()->toThisObject(exec);
 }
 
+inline UString JSValue::toThisString(ExecState* exec) const
+{
+    return JSImmediate::isImmediate(this) ? JSImmediate::toString(this) : asCell()->toThisString(exec);
+}
+
+inline JSString* JSValue::toThisJSString(ExecState* exec)
+{
+    return JSImmediate::isImmediate(this) ? jsString(exec, JSImmediate::toString(this)) : asCell()->toThisJSString(exec);
+}
+
+inline JSValue* JSValue::getJSNumber()
+{
+    return JSImmediate::isNumber(this) ? this : (JSImmediate::isImmediate(this) ? 0 : asCell()->getJSNumber());
+}
+
 } // namespace KJS
 
 #endif // JSValue_h
index 06980c2813bbe1eba039290d1a8ce6803ad154cf..28ad2e3cf1ae950c06b69c15d738cc9353e0ef06 100644 (file)
@@ -41,6 +41,11 @@ NumberObject::NumberObject(JSObject* proto)
 {
 }
 
+JSValue* NumberObject::getJSNumber()
+{
+    return internalValue();
+}
+
 // ------------------------------ NumberPrototype ---------------------------
 
 static JSValue* numberProtoFuncToString(ExecState*, JSObject*, JSValue*, const ArgList&);
@@ -94,7 +99,7 @@ static UString integer_part_noexp(double d)
             strncpy(buf.data(), result, decimalPoint);
 
         buf[decimalPoint] = '\0';
-        str += UString(buf.data());
+        str.append(buf.data());
     }
 
     freedtoa(result);
@@ -144,11 +149,10 @@ static double intPow10(int e)
 
 JSValue* numberProtoFuncToString(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    if (!thisValue->isObject(&NumberObject::info))
+    JSValue* v = thisValue->getJSNumber();
+    if (!v)
         return throwError(exec, TypeError);
 
-    JSValue* v = static_cast<NumberObject*>(thisValue)->internalValue();
-
     double radixAsDouble = args[0]->toInteger(exec); // nan -> 0
     if (radixAsDouble == 10 || args[0]->isUndefined())
         return jsString(exec, v->toString(exec));
@@ -209,28 +213,30 @@ JSValue* numberProtoFuncToString(ExecState* exec, JSObject*, JSValue* thisValue,
 
 JSValue* numberProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
 {
-    if (!thisValue->isObject(&NumberObject::info))
+    // FIXME: Not implemented yet.
+
+    JSValue* v = thisValue->getJSNumber();
+    if (!v)
         return throwError(exec, TypeError);
 
-    // TODO
-    return jsString(exec, static_cast<NumberObject*>(thisValue)->internalValue()->toString(exec));
+    return jsString(exec, v->toString(exec));
 }
 
 JSValue* numberProtoFuncValueOf(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
 {
-    if (!thisValue->isObject(&NumberObject::info))
+    JSValue* v = thisValue->getJSNumber();
+    if (!v)
         return throwError(exec, TypeError);
 
-    return static_cast<NumberObject*>(thisValue)->internalValue();
+    return v;
 }
 
 JSValue* numberProtoFuncToFixed(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    if (!thisValue->isObject(&NumberObject::info))
+    JSValue* v = thisValue->getJSNumber();
+    if (!v)
         return throwError(exec, TypeError);
 
-    JSValue* v = static_cast<NumberObject*>(thisValue)->internalValue();
-
     JSValue* fractionDigits = args[0];
     double df = fractionDigits->toInteger(exec);
     if (!(df >= 0 && df <= 20))
@@ -312,10 +318,11 @@ static void exponentialPartToString(char* buf, int& i, int decimalPoint)
 
 JSValue* numberProtoFuncToExponential(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    if (!thisValue->isObject(&NumberObject::info))
+    JSValue* v = thisValue->getJSNumber();
+    if (!v)
         return throwError(exec, TypeError);
 
-    double x = static_cast<NumberObject*>(thisValue)->internalValue()->uncheckedGetNumber();
+    double x = v->uncheckedGetNumber();
 
     if (isnan(x) || isinf(x))
         return jsString(exec, UString::from(x));
@@ -381,11 +388,10 @@ JSValue* numberProtoFuncToExponential(ExecState* exec, JSObject*, JSValue* thisV
 
 JSValue* numberProtoFuncToPrecision(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    if (!thisValue->isObject(&NumberObject::info))
+    JSValue* v = thisValue->getJSNumber();
+    if (!v)
         return throwError(exec, TypeError);
 
-    JSValue* v = static_cast<NumberObject*>(thisValue)->internalValue();
-
     double doublePrecision = args[0]->toIntegerPreserveNaN(exec);
     double x = v->uncheckedGetNumber();
     if (args[0]->isUndefined() || isnan(x) || isinf(x))
index a84f40c31f9f9bf6d7bb3aad3778b6421f6ce799..1953c6000d9ba6681748f6aee4c419528fa490d4 100644 (file)
@@ -36,6 +36,7 @@ namespace KJS {
 
     private:
         virtual const ClassInfo* classInfo() const { return &info; }
+        virtual JSValue* getJSNumber();
     };
 
     NumberObject* constructNumber(ExecState*, JSNumberCell*);
index b2573673d62c73ce372ff939016cfc2a5a0bc80b..d24ac64c06318176e1577056e1a1655daf24ad40 100644 (file)
@@ -44,7 +44,7 @@ JSValue* PropertySlot::functionGetter(ExecState* exec, const Identifier&, const
     ASSERT(callType == CallTypeJS);
     RegisterFileStack* stack = &exec->dynamicGlobalObject()->registerFileStack();
     stack->pushFunctionRegisterFile();
-    // FIXME: This can be done more efficiently using the callData.
+    // FIXME: Can this be done more efficiently using the callData?
     JSValue* result = static_cast<JSFunction*>(slot.m_data.getterFunc)->call(exec, slot.slotBase(), exec->emptyList());
     stack->popFunctionRegisterFile();
     return result;
index 3d4f371482c0dd9269103ecc20cfcd0e10dfff91..4bda1bad709be65feca4d2016d01e94a518cc113 100644 (file)
@@ -78,6 +78,16 @@ UString JSString::toString(ExecState*) const
     return m_value;
 }
 
+UString JSString::toThisString(ExecState*) const
+{
+    return m_value;
+}
+
+JSString* JSString::toThisJSString(ExecState*)
+{
+    return this;
+}
+
 inline StringObject* StringObject::create(ExecState* exec, JSString* string)
 {
     return new (exec) StringObject(exec->lexicalGlobalObject()->stringPrototype(), string);
@@ -114,20 +124,16 @@ bool JSString::getOwnPropertySlot(ExecState* exec, const Identifier& propertyNam
     // This function should only be called by JSValue::get.
     if (getStringPropertySlot(exec, propertyName, slot))
         return true;
-    JSObject* object = StringObject::create(exec, this);
-    slot.setBase(object);
-    if (object->JSObject::getOwnPropertySlot(exec, propertyName, slot))
-        return true;
-    while (true) {
-        JSValue* proto = object->prototype();
-        if (!proto->isObject()) {
-            slot.setUndefined();
-            return true;
-        }
-        object = static_cast<JSObject*>(proto);
+    slot.setBase(this);
+    JSObject* object;
+    for (JSValue* prototype = exec->lexicalGlobalObject()->stringPrototype(); prototype != jsNull(); prototype = object->prototype()) {
+        ASSERT(prototype->isObject());
+        object = static_cast<JSObject*>(prototype);
         if (object->getOwnPropertySlot(exec, propertyName, slot))
             return true;
     }
+    slot.setUndefined();
+    return true;
 }
 
 bool JSString::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
@@ -168,11 +174,18 @@ double JSNumberCell::toNumber(ExecState *) const
   return val;
 }
 
-UString JSNumberCell::toString(ExecState *) const
+UString JSNumberCell::toString(ExecState*) const
+{
+    if (val == 0.0) // +0.0 or -0.0
+        return "0";
+    return UString::from(val);
+}
+
+UString JSNumberCell::toThisString(ExecState*) const
 {
-  if (val == 0.0) // +0.0 or -0.0
-    return "0";
-  return UString::from(val);
+    if (val == 0.0) // +0.0 or -0.0
+        return "0";
+    return UString::from(val);
 }
 
 JSObject* JSNumberCell::toObject(ExecState* exec) const
@@ -207,6 +220,11 @@ bool JSNumberCell::getTruncatedUInt32(uint32_t& uint32) const
     return true;
 }
 
+JSValue* JSNumberCell::getJSNumber()
+{
+    return this;
+}
+
 // --------------------------- GetterSetter ---------------------------------
 
 void GetterSetter::mark()
index 345e91600107949fbead6337885d2d5452a9d8b6..5f8aade4cd33c914a52bc37aee538f56d5c4603a 100644 (file)
@@ -40,4 +40,27 @@ void HashTable::createTable(JSGlobalData* globalData) const
     table = entries;
 }
 
+JSValue* staticFunctionGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot)
+{
+    // Look for cached value in dynamic map of properties (in JSObject)
+    ASSERT(slot.slotBase()->isObject());
+    JSObject* thisObj = static_cast<JSObject*>(slot.slotBase());
+    JSValue* cachedVal = thisObj->getDirect(propertyName);
+    if (cachedVal)
+        return cachedVal;
+
+    const HashEntry* entry = slot.staticEntry();
+    JSValue* val = new (exec) PrototypeFunction(exec, entry->length, propertyName, entry->functionValue);
+    thisObj->putDirect(propertyName, val, entry->attributes);
+    return val;
+}
+
+void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
+{
+    ASSERT(entry->attributes & Function);
+    PrototypeFunction* function = new (exec) PrototypeFunction(exec, entry->length, propertyName, entry->functionValue);
+    thisObj->putDirect(propertyName, function, entry->attributes);
+    slot.setValueSlot(thisObj->getDirectLocation(propertyName));
+}
+
 }
index 98dd916ef1c05918a80dc22dd145adb12b1e9d54..8557e206f258e8e48fd6ed73323c5f78150a55c0 100644 (file)
@@ -97,29 +97,18 @@ private:
 
   /**
    * @internal
-   * Helper for getStaticFunctionSlot and getStaticPropertySlot
+   * Helper for getStaticPropertySlot
    */
-  inline JSValue* staticFunctionGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot)
-  {
-      // Look for cached value in dynamic map of properties (in JSObject)
-      ASSERT(slot.slotBase()->isObject());
-      JSObject* thisObj = static_cast<JSObject*>(slot.slotBase());
-      JSValue* cachedVal = thisObj->getDirect(propertyName);
-      if (cachedVal)
-        return cachedVal;
+  JSValue* staticFunctionGetter(ExecState*, const Identifier& propertyName, const PropertySlot&);
 
-      const HashEntry* entry = slot.staticEntry();
-      JSValue* val = new (exec) PrototypeFunction(exec, entry->length, propertyName, entry->functionValue);
-      thisObj->putDirect(propertyName, val, entry->attributes);
-      return val;
-  }
+  void setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& propertyName, PropertySlot&);
 
   /**
    * @internal
    * Helper for getStaticValueSlot and getStaticPropertySlot
    */
   template <class ThisImp>
-  inline JSValue* staticValueGetter(ExecState* exec, const Identifier&, const PropertySlot& slot)
+  JSValue* staticValueGetter(ExecState* exec, const Identifier&, const PropertySlot& slot)
   {
       ThisImp* thisObj = static_cast<ThisImp*>(slot.slotBase());
       const HashEntry* entry = slot.staticEntry();
@@ -170,14 +159,14 @@ private:
   template <class ParentImp>
   inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
   {
-    const HashEntry* entry = table->entry(exec, propertyName);
+    if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertySlot(exec, propertyName, slot))
+      return true;
 
-    if (!entry) // not found, forward to parent
-      return static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
-
-    ASSERT(entry->attributes & Function);
+    const HashEntry* entry = table->entry(exec, propertyName);
+    if (!entry)
+        return false;
 
-    slot.setStaticEntry(thisObj, entry, staticFunctionGetter);
+    setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
     return true;
   }
 
index b679c2520d193f92b714aa54c4c91411bcb482bd..a913a7779dbea4498cc642cfa52b0568db028647 100644 (file)
@@ -36,7 +36,6 @@ using namespace WTF;
 namespace KJS {
 
 static JSValue* stringProtoFuncToString(ExecState*, JSObject*, JSValue*, const ArgList&);
-static JSValue* stringProtoFuncValueOf(ExecState*, JSObject*, JSValue*, const ArgList&);
 static JSValue* stringProtoFuncCharAt(ExecState*, JSObject*, JSValue*, const ArgList&);
 static JSValue* stringProtoFuncCharCodeAt(ExecState*, JSObject*, JSValue*, const ArgList&);
 static JSValue* stringProtoFuncConcat(ExecState*, JSObject*, JSValue*, const ArgList&);
@@ -127,18 +126,33 @@ bool StringObject::deleteProperty(ExecState *exec, const Identifier &propertyNam
 
 void StringObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
 {
-  int size = internalValue()->getString().size();
+  int size = internalValue()->value().size();
   for (int i = 0; i < size; i++)
     propertyNames.add(Identifier(exec, UString::from(i)));
   return JSObject::getPropertyNames(exec, propertyNames);
 }
 
+UString StringObject::toString(ExecState*) const
+{
+    return internalValue()->value();
+}
+
+UString StringObject::toThisString(ExecState*) const
+{
+    return internalValue()->value();
+}
+
+JSString* StringObject::toThisJSString(ExecState*)
+{
+    return internalValue();
+}
+
 // ------------------------------ StringPrototype ---------------------------
 const ClassInfo StringPrototype::info = { "String", &StringObject::info, 0, ExecState::stringTable };
 /* Source for string_object.lut.h
 @begin stringTable 26
   toString              stringProtoFuncToString          DontEnum|Function       0
-  valueOf               stringProtoFuncValueOf           DontEnum|Function       0
+  valueOf               stringProtoFuncToString          DontEnum|Function       0
   charAt                stringProtoFuncCharAt            DontEnum|Function       1
   charCodeAt            stringProtoFuncCharCodeAt        DontEnum|Function       1
   concat                stringProtoFuncConcat            DontEnum|Function       1
@@ -187,82 +201,29 @@ bool StringPrototype::getOwnPropertySlot(ExecState *exec, const Identifier& prop
 
 // ------------------------------ Functions --------------------------
 
-static inline void expandSourceRanges(UString::Range * & array, int& count, int& capacity)
-{
-  int newCapacity;
-  if (capacity == 0) {
-    newCapacity = 16;
-  } else {
-    newCapacity = capacity * 2;
-  }
-
-  UString::Range *newArray = new UString::Range[newCapacity];
-  for (int i = 0; i < count; i++) {
-    newArray[i] = array[i];
-  }
-
-  delete [] array;
-
-  capacity = newCapacity;
-  array = newArray;
-}
-
-static void pushSourceRange(UString::Range * & array, int& count, int& capacity, UString::Range range)
+static inline UString substituteBackreferences(const UString& replacement, const UString& source, const int* ovector, RegExp* reg)
 {
-  if (count + 1 > capacity)
-    expandSourceRanges(array, count, capacity);
-
-  array[count] = range;
-  count++;
-}
-
-static inline void expandReplacements(UString * & array, int& count, int& capacity)
-{
-  int newCapacity;
-  if (capacity == 0) {
-    newCapacity = 16;
-  } else {
-    newCapacity = capacity * 2;
-  }
-
-  UString *newArray = new UString[newCapacity];
-  for (int i = 0; i < count; i++) {
-    newArray[i] = array[i];
-  }
-  
-  delete [] array;
-
-  capacity = newCapacity;
-  array = newArray;
-}
-
-static void pushReplacement(UString * & array, int& count, int& capacity, UString replacement)
-{
-  if (count + 1 > capacity)
-    expandReplacements(array, count, capacity);
-
-  array[count] = replacement;
-  count++;
-}
-
-static inline UString substituteBackreferences(const UString &replacement, const UString &source, int *ovector, RegExp *reg)
-{
-  UString substitutedReplacement = replacement;
-
+  UString substitutedReplacement;
+  int offset = 0;
   int i = -1;
-  while ((i = substitutedReplacement.find(UString("$"), i + 1)) != -1) {
-    if (i+1 == substitutedReplacement.size())
+  while ((i = replacement.find('$', i + 1)) != -1) {
+    if (i + 1 == replacement.size())
         break;
 
-    unsigned short ref = substitutedReplacement[i+1];
-    int backrefStart = 0;
-    int backrefLength = 0;
-    int advance = 0;
-
-    if (ref == '$') {  // "$$" -> "$"
-        substitutedReplacement = substitutedReplacement.substr(0, i + 1) + substitutedReplacement.substr(i + 2);
+    unsigned short ref = replacement[i + 1];
+    if (ref == '$') {
+        // "$$" -> "$"
+        ++i;
+        substitutedReplacement.append(replacement.data() + offset, i - offset);
+        offset = i + 1;
+        substitutedReplacement.append('$');
         continue;
-    } else if (ref == '&') {
+    }
+
+    int backrefStart;
+    int backrefLength;
+    int advance = 0;
+    if (ref == '&') {
         backrefStart = ovector[0];
         backrefLength = ovector[1] - backrefStart;
     } else if (ref == '`') {
@@ -276,8 +237,8 @@ static inline UString substituteBackreferences(const UString &replacement, const
         unsigned backrefIndex = ref - '0';
         if (backrefIndex > reg->numSubpatterns())
             continue;
-        if (substitutedReplacement.size() > i + 2) {
-            ref = substitutedReplacement[i+2];
+        if (replacement.size() > i + 2) {
+            ref = replacement[i + 2];
             if (ref >= '0' && ref <= '9') {
                 backrefIndex = 10 * backrefIndex + ref - '0';
                 if (backrefIndex > reg->numSubpatterns())
@@ -291,10 +252,19 @@ static inline UString substituteBackreferences(const UString &replacement, const
     } else
         continue;
 
-    substitutedReplacement = substitutedReplacement.substr(0, i) + source.substr(backrefStart, backrefLength) + substitutedReplacement.substr(i + 2 + advance);
-    i += backrefLength - 1; // - 1 offsets 'i + 1'
+    if (i - offset)
+        substitutedReplacement.append(replacement.data() + offset, i - offset);
+    i += 1 + advance;
+    offset = i + 1;
+    substitutedReplacement.append(source.data() + backrefStart, backrefLength);
   }
 
+  if (!offset)
+    return replacement;
+
+  if (replacement.size() - offset)
+    substitutedReplacement.append(replacement.data() + offset, replacement.size() - offset);
+
   return substitutedReplacement;
 }
 
@@ -303,31 +273,31 @@ static inline int localeCompare(const UString& a, const UString& b)
     return Collator::userDefault()->collate(reinterpret_cast<const ::UChar*>(a.data()), a.size(), reinterpret_cast<const ::UChar*>(b.data()), b.size());
 }
 
-static JSValue *replace(ExecState *exec, JSString* sourceVal, JSValue *pattern, JSValue *replacement)
+JSValue* stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-  UString source = sourceVal->value();
-  CallData callData;
-  UString replacementString;
+  JSString* sourceVal = thisValue->toThisJSString(exec);
+  const UString& source = sourceVal->value();
+
+  JSValue* pattern = args[0];
 
+  JSValue* replacement = args[1];
+  UString replacementString;
+  CallData callData;
   CallType callType = replacement->getCallData(callData);
   if (callType == CallTypeNone)
     replacementString = replacement->toString(exec);
 
-  if (pattern->isObject() && static_cast<JSObject *>(pattern)->inherits(&RegExpObject::info)) {
-    RegExp *reg = static_cast<RegExpObject *>(pattern)->regExp();
+  if (pattern->isObject(&RegExpObject::info)) {
+    RegExp* reg = static_cast<RegExpObject*>(pattern)->regExp();
     bool global = reg->global();
 
-    RegExpConstructor* regExpObj = static_cast<RegExpConstructor*>(exec->lexicalGlobalObject()->regExpConstructor());
+    RegExpConstructor* regExpObj = exec->lexicalGlobalObject()->regExpConstructor();
 
     int lastIndex = 0;
     int startPosition = 0;
 
-    UString::Range *sourceRanges = 0;
-    int sourceRangeCount = 0;
-    int sourceRangeCapacity = 0;
-    UString *replacements = 0;
-    int replacementCount = 0;
-    int replacementCapacity = 0;
+    Vector<UString::Range, 16> sourceRanges;
+    Vector<UString, 16> replacements;
 
     // This is either a loop (if global is set) or a one-way (if not).
     do {
@@ -338,9 +308,8 @@ static JSValue *replace(ExecState *exec, JSString* sourceVal, JSValue *pattern,
       if (matchIndex < 0)
         break;
 
-      pushSourceRange(sourceRanges, sourceRangeCount, sourceRangeCapacity, UString::Range(lastIndex, matchIndex - lastIndex));
+      sourceRanges.append(UString::Range(lastIndex, matchIndex - lastIndex));
 
-      UString substitutedReplacement;
       if (callType != CallTypeNone) {
           int completeMatchStart = ovector[0];
           ArgList args;
@@ -358,11 +327,9 @@ static JSValue *replace(ExecState *exec, JSString* sourceVal, JSValue *pattern,
           args.append(jsNumber(exec, completeMatchStart));
           args.append(sourceVal);
 
-          substitutedReplacement = call(exec, replacement, callType, callData, exec->globalThisValue(), args)->toString(exec);
+          replacements.append(call(exec, replacement, callType, callData, exec->globalThisValue(), args)->toString(exec));
       } else
-          substitutedReplacement = substituteBackreferences(replacementString, source, ovector, reg);
-
-      pushReplacement(replacements, replacementCount, replacementCapacity, substitutedReplacement);
+          replacements.append(substituteBackreferences(replacementString, source, ovector, reg));
 
       lastIndex = matchIndex + matchLen;
       startPosition = lastIndex;
@@ -376,15 +343,9 @@ static JSValue *replace(ExecState *exec, JSString* sourceVal, JSValue *pattern,
     } while (global);
 
     if (lastIndex < source.size())
-      pushSourceRange(sourceRanges, sourceRangeCount, sourceRangeCapacity, UString::Range(lastIndex, source.size() - lastIndex));
-
-    UString result;
+      sourceRanges.append(UString::Range(lastIndex, source.size() - lastIndex));
 
-    if (sourceRanges)
-        result = source.spliceSubstringsWithSeparators(sourceRanges, sourceRangeCount, replacements, replacementCount);
-
-    delete [] sourceRanges;
-    delete [] replacements;
+    UString result = source.spliceSubstringsWithSeparators(sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size());
 
     if (result == source)
       return sourceVal;
@@ -415,24 +376,20 @@ static JSValue *replace(ExecState *exec, JSString* sourceVal, JSValue *pattern,
 
 JSValue* stringProtoFuncToString(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
 {
-    if (!thisValue->isObject(&StringObject::info))
-        return throwError(exec, TypeError);
+    // Also used for valueOf.
 
-    return static_cast<StringObject*>(thisValue)->internalValue();
-}
+    if (thisValue->isString())
+        return thisValue;
 
-JSValue* stringProtoFuncValueOf(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
-{
-    if (!thisValue->isObject(&StringObject::info))
-        return throwError(exec, TypeError);
+    if (thisValue->isObject(&StringObject::info))
+        return static_cast<StringObject*>(thisValue)->internalValue();
 
-    return static_cast<StringObject*>(thisValue)->internalValue();
+    return throwError(exec, TypeError);
 }
 
 JSValue* stringProtoFuncCharAt(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     int len = s.size();
 
     UString u;
@@ -447,8 +404,7 @@ JSValue* stringProtoFuncCharAt(ExecState* exec, JSObject*, JSValue* thisValue, c
 
 JSValue* stringProtoFuncCharCodeAt(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     int len = s.size();
 
     JSValue* result = 0;
@@ -464,8 +420,7 @@ JSValue* stringProtoFuncCharCodeAt(ExecState* exec, JSObject*, JSValue* thisValu
 
 JSValue* stringProtoFuncConcat(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
 
     ArgList::const_iterator end = args.end();
     for (ArgList::const_iterator it = args.begin(); it != end; ++it) {
@@ -476,8 +431,7 @@ JSValue* stringProtoFuncConcat(ExecState* exec, JSObject*, JSValue* thisValue, c
 
 JSValue* stringProtoFuncIndexOf(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     int len = s.size();
 
     JSValue* a0 = args[0];
@@ -493,8 +447,7 @@ JSValue* stringProtoFuncIndexOf(ExecState* exec, JSObject*, JSValue* thisValue,
 
 JSValue* stringProtoFuncLastIndexOf(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     int len = s.size();
 
     JSValue* a0 = args[0];
@@ -511,8 +464,7 @@ JSValue* stringProtoFuncLastIndexOf(ExecState* exec, JSObject*, JSValue* thisVal
 
 JSValue* stringProtoFuncMatch(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
 
     JSValue* a0 = args[0];
 
@@ -529,7 +481,7 @@ JSValue* stringProtoFuncMatch(ExecState* exec, JSObject*, JSValue* thisValue, co
        */
       reg = RegExp::create(a0->toString(exec));
     }
-    RegExpConstructor* regExpObj = static_cast<RegExpConstructor*>(exec->lexicalGlobalObject()->regExpConstructor());
+    RegExpConstructor* regExpObj = exec->lexicalGlobalObject()->regExpConstructor();
     int pos;
     int matchLength;
     regExpObj->performMatch(reg.get(), u, 0, pos, matchLength);
@@ -566,8 +518,7 @@ JSValue* stringProtoFuncMatch(ExecState* exec, JSObject*, JSValue* thisValue, co
 
 JSValue* stringProtoFuncSearch(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
 
     JSValue* a0 = args[0];
 
@@ -583,32 +534,16 @@ JSValue* stringProtoFuncSearch(ExecState* exec, JSObject*, JSValue* thisValue, c
        */
       reg = RegExp::create(a0->toString(exec));
     }
-    RegExpConstructor* regExpObj = static_cast<RegExpConstructor*>(exec->lexicalGlobalObject()->regExpConstructor());
+    RegExpConstructor* regExpObj = exec->lexicalGlobalObject()->regExpConstructor();
     int pos;
     int matchLength;
     regExpObj->performMatch(reg.get(), u, 0, pos, matchLength);
     return jsNumber(exec, pos);
 }
 
-JSValue* stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
-{
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
-
-    JSString* sVal = thisValue->isObject(&StringObject::info) ?
-      static_cast<StringObject*>(thisValue)->internalValue() :
-      static_cast<JSString*>(jsString(exec, s));
-
-    JSValue* a0 = args[0];
-    JSValue* a1 = args[1];
-
-    return replace(exec, sVal, a0, a1);
-}
-
 JSValue* stringProtoFuncSlice(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     int len = s.size();
 
     JSValue* a0 = args[0];
@@ -632,8 +567,7 @@ JSValue* stringProtoFuncSlice(ExecState* exec, JSObject*, JSValue* thisValue, co
 
 JSValue* stringProtoFuncSplit(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
 
     JSValue* a0 = args[0];
     JSValue* a1 = args[1];
@@ -701,8 +635,7 @@ JSValue* stringProtoFuncSplit(ExecState* exec, JSObject*, JSValue* thisValue, co
 
 JSValue* stringProtoFuncSubstr(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     int len = s.size();
 
     JSValue* a0 = args[0];
@@ -726,8 +659,7 @@ JSValue* stringProtoFuncSubstr(ExecState* exec, JSObject*, JSValue* thisValue, c
 
 JSValue* stringProtoFuncSubstring(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     int len = s.size();
 
     JSValue* a0 = args[0];
@@ -759,12 +691,9 @@ JSValue* stringProtoFuncSubstring(ExecState* exec, JSObject*, JSValue* thisValue
 
 JSValue* stringProtoFuncToLowerCase(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    JSString* sVal = thisValue->toThisJSString(exec);
+    const UString& s = sVal->value();
     
-    JSString* sVal = thisValue->isObject(&StringObject::info)
-        ? static_cast<StringObject*>(thisValue)->internalValue()
-        : static_cast<JSString*>(jsString(exec, s));
     int ssize = s.size();
     if (!ssize)
         return sVal;
@@ -784,12 +713,9 @@ JSValue* stringProtoFuncToLowerCase(ExecState* exec, JSObject*, JSValue* thisVal
 
 JSValue* stringProtoFuncToUpperCase(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
-
-    JSString* sVal = thisValue->isObject(&StringObject::info)
-        ? static_cast<StringObject*>(thisValue)->internalValue()
-        : static_cast<JSString*>(jsString(exec, s));
+    JSString* sVal = thisValue->toThisJSString(exec);
+    const UString& s = sVal->value();
+    
     int ssize = s.size();
     if (!ssize)
         return sVal;
@@ -809,13 +735,11 @@ JSValue* stringProtoFuncToUpperCase(ExecState* exec, JSObject*, JSValue* thisVal
 
 JSValue* stringProtoFuncToLocaleLowerCase(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
-    
     // FIXME: See http://www.unicode.org/Public/UNIDATA/SpecialCasing.txt for locale-sensitive mappings that aren't implemented.
-    JSString* sVal = thisValue->isObject(&StringObject::info)
-        ? static_cast<StringObject*>(thisValue)->internalValue()
-        : static_cast<JSString*>(jsString(exec, s));
+
+    JSString* sVal = thisValue->toThisJSString(exec);
+    const UString& s = sVal->value();
+    
     int ssize = s.size();
     if (!ssize)
         return sVal;
@@ -835,12 +759,9 @@ JSValue* stringProtoFuncToLocaleLowerCase(ExecState* exec, JSObject*, JSValue* t
 
 JSValue* stringProtoFuncToLocaleUpperCase(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
-
-    JSString* sVal = thisValue->isObject(&StringObject::info)
-        ? static_cast<StringObject*>(thisValue)->internalValue()
-        : static_cast<JSString*>(jsString(exec, s));
+    JSString* sVal = thisValue->toThisJSString(exec);
+    const UString& s = sVal->value();
+    
     int ssize = s.size();
     if (!ssize)
         return sVal;
@@ -863,103 +784,89 @@ JSValue* stringProtoFuncLocaleCompare(ExecState* exec, JSObject*, JSValue* thisV
     if (args.size() < 1)
       return jsNumber(exec, 0);
 
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     JSValue* a0 = args[0];
     return jsNumber(exec, localeCompare(s, a0->toString(exec)));
 }
 
 JSValue* stringProtoFuncBig(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     return jsString(exec, "<big>" + s + "</big>");
 }
 
 JSValue* stringProtoFuncSmall(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     return jsString(exec, "<small>" + s + "</small>");
 }
 
 JSValue* stringProtoFuncBlink(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     return jsString(exec, "<blink>" + s + "</blink>");
 }
 
 JSValue* stringProtoFuncBold(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     return jsString(exec, "<b>" + s + "</b>");
 }
 
 JSValue* stringProtoFuncFixed(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     return jsString(exec, "<tt>" + s + "</tt>");
 }
 
 JSValue* stringProtoFuncItalics(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     return jsString(exec, "<i>" + s + "</i>");
 }
 
 JSValue* stringProtoFuncStrike(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     return jsString(exec, "<strike>" + s + "</strike>");
 }
 
 JSValue* stringProtoFuncSub(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     return jsString(exec, "<sub>" + s + "</sub>");
 }
 
 JSValue* stringProtoFuncSup(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     return jsString(exec, "<sup>" + s + "</sup>");
 }
 
 JSValue* stringProtoFuncFontcolor(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     JSValue* a0 = args[0];
     return jsString(exec, "<font color=\"" + a0->toString(exec) + "\">" + s + "</font>");
 }
 
 JSValue* stringProtoFuncFontsize(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     JSValue* a0 = args[0];
     return jsString(exec, "<font size=\"" + a0->toString(exec) + "\">" + s + "</font>");
 }
 
 JSValue* stringProtoFuncAnchor(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     JSValue* a0 = args[0];
     return jsString(exec, "<a name=\"" + a0->toString(exec) + "\">" + s + "</a>");
 }
 
 JSValue* stringProtoFuncLink(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
 {
-    // This optimizes the common case that thisObj is a StringObject
-    UString s = thisValue->isObject(&StringObject::info) ? static_cast<StringObject*>(thisValue)->internalValue()->value() : thisValue->toThisObject(exec)->toString(exec);
+    UString s = thisValue->toThisString(exec);
     JSValue* a0 = args[0];
     return jsString(exec, "<a href=\"" + a0->toString(exec) + "\">" + s + "</a>");
 }
index 10c408311334ec9391d9df4ecde07fce6da63336..8dad490029182e311858f92ca4c5cfb3f3462455 100644 (file)
@@ -50,6 +50,11 @@ namespace KJS {
 
   protected:
     StringObject(JSObject* prototype, JSString*);
+
+  private:
+    virtual UString toString(ExecState*) const;
+    virtual UString toThisString(ExecState*) const;
+    virtual JSString* toThisJSString(ExecState*);
   };
 
   // WebCore uses this to make style.filter undetectable
index 8be88fc104eb5d164ef278134d4f59ab32def61c..699ef79d8a90e3126e98cc7f7976e80bf974c858 100644 (file)
@@ -774,6 +774,50 @@ UString& UString::append(const UString &t)
   return *this;
 }
 
+UString& UString::append(const UChar* tData, int tSize)
+{
+  int thisSize = size();
+  int thisOffset = m_rep->offset;
+  int length = thisSize + tSize;
+
+  // possible cases:
+  if (tSize == 0) {
+    // t is empty
+  } else if (thisSize == 0) {
+    // this is empty
+    m_rep = Rep::createCopying(tData, tSize);
+  } else if (m_rep->baseIsSelf() && m_rep->rc == 1) {
+    // this is direct and has refcount of 1 (so we can just alter it directly)
+    expandCapacity(thisOffset + length);
+    if (data()) {
+        memcpy(const_cast<UChar*>(data() + thisSize), tData, tSize * sizeof(UChar));
+        m_rep->len = length;
+        m_rep->_hash = 0;
+    }
+  } else if (thisOffset + thisSize == usedCapacity() && thisSize >= minShareSize) {
+    // this reaches the end of the buffer - extend it if it's long enough to append to
+    expandCapacity(thisOffset + length);
+    if (data()) {
+        memcpy(const_cast<UChar*>(data() + thisSize), tData, tSize * sizeof(UChar));
+        m_rep = Rep::create(m_rep, 0, length);
+    }
+  } else {
+    // this is shared with someone using more capacity, gotta make a whole new string
+    size_t newCapacity = expandedSize(length, 0);
+    UChar* d = allocChars(newCapacity);
+    if (!d)
+        m_rep = &Rep::null;
+    else {
+        memcpy(d, data(), thisSize * sizeof(UChar));
+        memcpy(const_cast<UChar*>(d + thisSize), tData, tSize * sizeof(UChar));
+        m_rep = Rep::create(d, length);
+        m_rep->capacity = newCapacity;
+    }
+  }
+
+  return *this;
+}
+
 UString& UString::append(const char *t)
 {
   int thisSize = size();
index e9207b845cee32c50fe3c0dd5ed949b9c1375eee..77cd687cf9685b66252d506dd4ab897ee83cf09a 100644 (file)
@@ -222,6 +222,7 @@ namespace KJS {
     UString& append(const char*);
     UString& append(UChar);
     UString& append(char c) { return append(static_cast<UChar>(static_cast<unsigned char>(c))); }
+    UString& append(const UChar*, int size);
 
     /**
      * @return The string converted to the 8-bit string type CString().