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
+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.
__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
__ZN3KJS12PropertySlot15undefinedGetterEPNS_9ExecStateERKNS_10IdentifierERKS0_
__ZN3KJS12RegisterFile14addGlobalSlotsEm
__ZN3KJS12StringObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
+__ZN3KJS12StringObject14toThisJSStringEPNS_9ExecStateE
__ZN3KJS12StringObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE
__ZN3KJS12StringObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
__ZN3KJS12StringObject18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
__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
__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
__ZN3WTF8fastFreeEPv
__ZNK3KJS11PropertyMap3getERKNS_10IdentifierE
__ZNK3KJS12DateInstance7getTimeERdRi
+__ZNK3KJS12StringObject12toThisStringEPNS_9ExecStateE
+__ZNK3KJS12StringObject8toStringEPNS_9ExecStateE
__ZNK3KJS14JSGlobalObject14isDynamicScopeEv
__ZNK3KJS14JSGlobalObject14toGlobalObjectEPNS_9ExecStateE
__ZNK3KJS16InternalFunction21implementsHasInstanceEv
__ZNK3KJS17DebuggerCallFrame8evaluateERKNS_7UStringERPNS_7JSValueE
__ZNK3KJS4Node8toStringEv
__ZNK3KJS6JSCell12toThisObjectEPNS_9ExecStateE
+__ZNK3KJS6JSCell12toThisStringEPNS_9ExecStateE
__ZNK3KJS6JSCell17getTruncatedInt32ERi
__ZNK3KJS6JSCell18getTruncatedUInt32ERj
__ZNK3KJS6JSCell9classInfoEv
#include "config.h"
#include "JSPropertyNameIterator.h"
-#include "identifier.h"
#include "JSObject.h"
+#include "JSString.h"
#include "PropertyNameArray.h"
+#include "identifier.h"
namespace KJS {
(*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);
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&)
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 == ' ')
k += 2;
}
k++;
- s += UString(c, 1);
+ s.append(*c);
}
return jsString(exec, s);
#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
static JSValue* impossibleValue();
+ static JSObject* prototype(const JSValue*, ExecState*);
+
private:
static const uintptr_t TagMask = 3; // type tags are 2 bits long
return prim->toNumber(exec);
}
-UString JSObject::toString(ExecState *exec) const
+UString JSObject::toString(ExecState* exec) 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
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);
}
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);
}
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&);
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);
}
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);
}
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);
}
class ExecState;
class Identifier;
-class JSObject;
class JSCell;
+class JSObject;
+class JSString;
class PropertySlot;
struct ClassInfo;
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&);
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.
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)
{
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;
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
{
}
+JSValue* NumberObject::getJSNumber()
+{
+ return internalValue();
+}
+
// ------------------------------ NumberPrototype ---------------------------
static JSValue* numberProtoFuncToString(ExecState*, JSObject*, JSValue*, const ArgList&);
strncpy(buf.data(), result, decimalPoint);
buf[decimalPoint] = '\0';
- str += UString(buf.data());
+ str.append(buf.data());
}
freedtoa(result);
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));
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))
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));
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))
private:
virtual const ClassInfo* classInfo() const { return &info; }
+ virtual JSValue* getJSNumber();
};
NumberObject* constructNumber(ExecState*, JSNumberCell*);
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;
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);
// 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)
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
return true;
}
+JSValue* JSNumberCell::getJSNumber()
+{
+ return this;
+}
+
// --------------------------- GetterSetter ---------------------------------
void GetterSetter::mark()
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));
+}
+
}
/**
* @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();
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;
}
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&);
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
// ------------------------------ 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 == '`') {
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())
} 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;
}
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 {
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;
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;
} 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;
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;
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;
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) {
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];
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];
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];
*/
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);
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];
*/
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];
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];
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];
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];
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;
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;
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;
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;
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>");
}
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
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();
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().