Commit 59c4d4eb authored by darin@apple.com's avatar darin@apple.com

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:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@34821 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent ffec04e7
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.
......
......@@ -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
......
......@@ -29,9 +29,10 @@
#include "config.h"
#include "JSPropertyNameIterator.h"
#include "identifier.h"
#include "JSObject.h"
#include "JSString.h"
#include "PropertyNameArray.h"
#include "identifier.h"
namespace KJS {
......
......@@ -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);
......
......@@ -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&)
......
......@@ -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 == ' ')
......
......@@ -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);
......
......@@ -21,40 +21,51 @@
#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
......@@ -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
......
......@@ -434,12 +434,12 @@ double JSObject::toNumber(ExecState *exec) const
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
......
......@@ -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);
}
......
......@@ -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&);
......
......@@ -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);
}
......
......@@ -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
......@@ -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))
......
......@@ -36,6 +36,7 @@ namespace KJS {
private:
virtual const ClassInfo* classInfo() const { return &info; }
virtual JSValue* getJSNumber();
};
NumberObject* constructNumber(ExecState*, JSNumberCell*);
......
......@@ -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?