JavaScriptCore:
Reviewed by Darin.
Convert JavaScript internal function objects to use one class per
function. This avoids a switch statement inside what used to be
the shared function classes and will allow Shark to better analyze
the code.
To make this switch, the value property of the HashEntry was changed
to a union of an intptr_t (which is used to continue handle valueGetters)
and function pointer which points to a static constructor for the
individual new function objects.
SunSpider claims this is a 0.5% speedup.
* kjs/array_object.cpp:
(KJS::ArrayPrototype::getOwnPropertySlot):
(KJS::getProperty):
(KJS::ArrayProtoFuncToString::callAsFunction):
(KJS::ArrayProtoFuncToLocaleString::callAsFunction):
(KJS::ArrayProtoFuncJoin::callAsFunction):
(KJS::ArrayProtoFuncConcat::callAsFunction):
(KJS::ArrayProtoFuncPop::callAsFunction):
(KJS::ArrayProtoFuncPush::callAsFunction):
(KJS::ArrayProtoFuncReverse::callAsFunction):
(KJS::ArrayProtoFuncShift::callAsFunction):
(KJS::ArrayProtoFuncSlice::callAsFunction):
(KJS::ArrayProtoFuncSort::callAsFunction):
(KJS::ArrayProtoFuncSplice::callAsFunction):
(KJS::ArrayProtoFuncUnShift::callAsFunction):
(KJS::ArrayProtoFuncFilter::callAsFunction):
(KJS::ArrayProtoFuncMap::callAsFunction):
(KJS::ArrayProtoFuncEvery::callAsFunction):
(KJS::ArrayProtoFuncForEach::callAsFunction):
(KJS::ArrayProtoFuncSome::callAsFunction):
(KJS::ArrayProtoFuncIndexOf::callAsFunction):
(KJS::ArrayProtoFuncLastIndexOf::callAsFunction):
* kjs/array_object.h:
(KJS::ArrayPrototype::classInfo):
* kjs/create_hash_table:
* kjs/date_object.cpp:
(KJS::DatePrototype::getOwnPropertySlot):
(KJS::DateProtoFuncToString::callAsFunction):
(KJS::DateProtoFuncToUTCString::callAsFunction):
(KJS::DateProtoFuncToDateString::callAsFunction):
(KJS::DateProtoFuncToTimeString::callAsFunction):
(KJS::DateProtoFuncToLocaleString::callAsFunction):
(KJS::DateProtoFuncToLocaleDateString::callAsFunction):
(KJS::DateProtoFuncToLocaleTimeString::callAsFunction):
(KJS::DateProtoFuncValueOf::callAsFunction):
(KJS::DateProtoFuncGetTime::callAsFunction):
(KJS::DateProtoFuncGetFullYear::callAsFunction):
(KJS::DateProtoFuncGetUTCFullYear::callAsFunction):
(KJS::DateProtoFuncToGMTString::callAsFunction):
(KJS::DateProtoFuncGetMonth::callAsFunction):
(KJS::DateProtoFuncGetUTCMonth::callAsFunction):
(KJS::DateProtoFuncGetDate::callAsFunction):
(KJS::DateProtoFuncGetUTCDate::callAsFunction):
(KJS::DateProtoFuncGetDay::callAsFunction):
(KJS::DateProtoFuncGetUTCDay::callAsFunction):
(KJS::DateProtoFuncGetHours::callAsFunction):
(KJS::DateProtoFuncGetUTCHours::callAsFunction):
(KJS::DateProtoFuncGetMinutes::callAsFunction):
(KJS::DateProtoFuncGetUTCMinutes::callAsFunction):
(KJS::DateProtoFuncGetSeconds::callAsFunction):
(KJS::DateProtoFuncGetUTCSeconds::callAsFunction):
(KJS::DateProtoFuncGetMilliSeconds::callAsFunction):
(KJS::DateProtoFuncGetUTCMilliseconds::callAsFunction):
(KJS::DateProtoFuncGetTimezoneOffset::callAsFunction):
(KJS::DateProtoFuncSetTime::callAsFunction):
(KJS::DateProtoFuncSetMilliSeconds::callAsFunction):
(KJS::DateProtoFuncSetUTCMilliseconds::callAsFunction):
(KJS::DateProtoFuncSetSeconds::callAsFunction):
(KJS::DateProtoFuncSetUTCSeconds::callAsFunction):
(KJS::DateProtoFuncSetMinutes::callAsFunction):
(KJS::DateProtoFuncSetUTCMinutes::callAsFunction):
(KJS::DateProtoFuncSetHours::callAsFunction):
(KJS::DateProtoFuncSetUTCHours::callAsFunction):
(KJS::DateProtoFuncSetDate::callAsFunction):
(KJS::DateProtoFuncSetUTCDate::callAsFunction):
(KJS::DateProtoFuncSetMonth::callAsFunction):
(KJS::DateProtoFuncSetUTCMonth::callAsFunction):
(KJS::DateProtoFuncSetFullYear::callAsFunction):
(KJS::DateProtoFuncSetUTCFullYear::callAsFunction):
(KJS::DateProtoFuncSetYear::callAsFunction):
(KJS::DateProtoFuncGetYear::callAsFunction):
* kjs/date_object.h:
* kjs/lookup.cpp:
(KJS::Lookup::find):
* kjs/lookup.h:
(KJS::HashEntry::):
(KJS::staticFunctionGetter):
(KJS::staticValueGetter):
(KJS::getStaticPropertySlot):
(KJS::getStaticFunctionSlot):
(KJS::lookupPut):
* kjs/math_object.cpp:
(KJS::MathObjectImp::getOwnPropertySlot):
(KJS::MathProtoFuncAbs::callAsFunction):
(KJS::MathProtoFuncACos::callAsFunction):
(KJS::MathProtoFuncASin::callAsFunction):
(KJS::MathProtoFuncATan::callAsFunction):
(KJS::MathProtoFuncATan2::callAsFunction):
(KJS::MathProtoFuncCeil::callAsFunction):
(KJS::MathProtoFuncCos::callAsFunction):
(KJS::MathProtoFuncExp::callAsFunction):
(KJS::MathProtoFuncFloor::callAsFunction):
(KJS::MathProtoFuncLog::callAsFunction):
(KJS::MathProtoFuncMax::callAsFunction):
(KJS::MathProtoFuncMin::callAsFunction):
(KJS::MathProtoFuncPow::callAsFunction):
(KJS::MathProtoFuncRandom::callAsFunction):
(KJS::MathProtoFuncRound::callAsFunction):
(KJS::MathProtoFuncSin::callAsFunction):
(KJS::MathProtoFuncSqrt::callAsFunction):
(KJS::MathProtoFuncTan::callAsFunction):
* kjs/math_object.h:
(KJS::MathObjectImp::classInfo):
(KJS::MathObjectImp::):
* kjs/string_object.cpp:
(KJS::StringPrototype::getOwnPropertySlot):
(KJS::StringProtoFuncToString::callAsFunction):
(KJS::StringProtoFuncValueOf::callAsFunction):
(KJS::StringProtoFuncCharAt::callAsFunction):
(KJS::StringProtoFuncCharCodeAt::callAsFunction):
(KJS::StringProtoFuncConcat::callAsFunction):
(KJS::StringProtoFuncIndexOf::callAsFunction):
(KJS::StringProtoFuncLastIndexOf::callAsFunction):
(KJS::StringProtoFuncMatch::callAsFunction):
(KJS::StringProtoFuncSearch::callAsFunction):
(KJS::StringProtoFuncReplace::callAsFunction):
(KJS::StringProtoFuncSlice::callAsFunction):
(KJS::StringProtoFuncSplit::callAsFunction):
(KJS::StringProtoFuncSubstr::callAsFunction):
(KJS::StringProtoFuncSubstring::callAsFunction):
(KJS::StringProtoFuncToLowerCase::callAsFunction):
(KJS::StringProtoFuncToUpperCase::callAsFunction):
(KJS::StringProtoFuncToLocaleLowerCase::callAsFunction):
(KJS::StringProtoFuncToLocaleUpperCase::callAsFunction):
(KJS::StringProtoFuncLocaleCompare::callAsFunction):
(KJS::StringProtoFuncBig::callAsFunction):
(KJS::StringProtoFuncSmall::callAsFunction):
(KJS::StringProtoFuncBlink::callAsFunction):
(KJS::StringProtoFuncBold::callAsFunction):
(KJS::StringProtoFuncFixed::callAsFunction):
(KJS::StringProtoFuncItalics::callAsFunction):
(KJS::StringProtoFuncStrike::callAsFunction):
(KJS::StringProtoFuncSub::callAsFunction):
(KJS::StringProtoFuncSup::callAsFunction):
(KJS::StringProtoFuncFontcolor::callAsFunction):
(KJS::StringProtoFuncFontsize::callAsFunction):
(KJS::StringProtoFuncAnchor::callAsFunction):
(KJS::StringProtoFuncLink::callAsFunction):
* kjs/string_object.h:
WebCore:
Reviewed by Darin.
Convert JavaScript internal function objects to use one class per
function. This avoids a switch statement inside what used to be
the shared function classes and will allow Shark to better analyze
the code.
To make this switch, the value property of the HashEntry was changed
to a union of an intptr_t (which is used to continue handle valueGetters)
and function pointer which points to a static constructor for the
individual new function objects.
SunSpider claims this is a 0.5% speedup.
- On the WebCore side, I updated CodeGeneratorJS.pm to generate the
new classes and hand updated the remain non-generated (groan) classes.
* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::JSDOMWindow::customGetOwnPropertySlot):
* bindings/js/JSEventTargetNode.cpp:
(WebCore::JSEventTargetNodePrototypeFunctionAddEventListener::callAsFunction):
(WebCore::JSEventTargetNodePrototypeFunctionRemoveEventListener::callAsFunction):
(WebCore::JSEventTargetNodePrototypeFunctionDispatchEvent::callAsFunction):
* bindings/js/JSEventTargetNode.h:
* bindings/js/JSHTMLInputElementBase.cpp:
(WebCore::JSHTMLInputElementBaseFunctionSetSelectionRange::callAsFunction):
(WebCore::JSHTMLInputElementBase::getOwnPropertySlot):
* bindings/js/JSHTMLInputElementBase.h:
(WebCore::JSHTMLInputElementBase::):
* bindings/js/JSXMLHttpRequest.cpp:
(KJS::JSXMLHttpRequestPrototypeFunctionAbort::callAsFunction):
(KJS::JSXMLHttpRequestPrototypeFunctionGetAllResponseHeaders::callAsFunction):
(KJS::JSXMLHttpRequestPrototypeFunctionGetResponseHeader::callAsFunction):
(KJS::JSXMLHttpRequestPrototypeFunctionOpen::callAsFunction):
(KJS::JSXMLHttpRequestPrototypeFunctionSend::callAsFunction):
(KJS::JSXMLHttpRequestPrototypeFunctionSetRequestHeader::callAsFunction):
(KJS::JSXMLHttpRequestPrototypeFunctionOverrideMIMEType::callAsFunction):
(KJS::JSXMLHttpRequestPrototypeFunctionAddEventListener::callAsFunction):
(KJS::JSXMLHttpRequestPrototypeFunctionRemoveEventListener::callAsFunction):
(KJS::JSXMLHttpRequestPrototypeFunctionDispatchEvent::callAsFunction):
* bindings/js/JSXMLHttpRequest.h:
(KJS::JSXMLHttpRequest::impl):
* bindings/js/JSXSLTProcessor.cpp:
(KJS::JSXSLTProcessorPrototypeFunctionImportStylesheet::callAsFunction):
(KJS::JSXSLTProcessorPrototypeFunctionTransformToFragment::callAsFunction):
(KJS::JSXSLTProcessorPrototypeFunctionTransformToDocument::callAsFunction):
(KJS::JSXSLTProcessorPrototypeFunctionSetParameter::callAsFunction):
(KJS::JSXSLTProcessorPrototypeFunctionGetParameter::callAsFunction):
(KJS::JSXSLTProcessorPrototypeFunctionRemoveParameter::callAsFunction):
(KJS::JSXSLTProcessorPrototypeFunctionClearParameters::callAsFunction):
(KJS::JSXSLTProcessorPrototypeFunctionReset::callAsFunction):
* bindings/js/JSXSLTProcessor.h:
* bindings/js/kjs_events.cpp:
(WebCore::JSClipboardPrototypeFunctionClearData::callAsFunction):
(WebCore::JSClipboardPrototypeFunctionGetData::callAsFunction):
(WebCore::JSClipboardPrototypeFunctionSetData::callAsFunction):
(WebCore::JSClipboardPrototypeFunctionSetDragImage::callAsFunction):
* bindings/js/kjs_events.h:
* bindings/js/kjs_navigator.cpp:
(KJS::Plugins::):
(KJS::Navigator::getOwnPropertySlot):
(KJS::Plugins::getOwnPropertySlot):
(KJS::PluginsFunctionRefresh::callAsFunction):
(KJS::NavigatorProtoFuncJavaEnabled::callAsFunction):
* bindings/js/kjs_navigator.h:
(KJS::Navigator::):
* bindings/js/kjs_window.cpp:
(KJS::Window::getOwnPropertySlot):
(KJS::Window::put):
(KJS::WindowProtoFuncAToB::callAsFunction):
(KJS::WindowProtoFuncBToA::callAsFunction):
(KJS::WindowProtoFuncOpen::callAsFunction):
(KJS::WindowProtoFuncScrollBy::callAsFunction):
(KJS::WindowProtoFuncScrollTo::callAsFunction):
(KJS::WindowProtoFuncMoveBy::callAsFunction):
(KJS::WindowProtoFuncMoveTo::callAsFunction):
(KJS::WindowProtoFuncResizeBy::callAsFunction):
(KJS::WindowProtoFuncResizeTo::callAsFunction):
(KJS::WindowProtoFuncSetTimeout::callAsFunction):
(KJS::WindowProtoFuncClearTimeout::callAsFunction):
(KJS::WindowProtoFuncSetInterval::callAsFunction):
(KJS::WindowProtoFuncAddEventListener::callAsFunction):
(KJS::WindowProtoFuncRemoveEventListener::callAsFunction):
(KJS::WindowProtoFuncShowModalDialog::callAsFunction):
(KJS::WindowProtoFuncNotImplemented::callAsFunction):
(KJS::Location::getOwnPropertySlot):
(KJS::Location::put):
(KJS::LocationProtoFuncReplace::callAsFunction):
(KJS::LocationProtoFuncReload::callAsFunction):
(KJS::LocationProtoFuncAssign::callAsFunction):
(KJS::LocationProtoFuncToString::callAsFunction):
* bindings/js/kjs_window.h:
(KJS::Window::):
* bindings/scripts/CodeGeneratorJS.pm:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@27608 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JavaScriptCore/kjs/string_object.cpp b/JavaScriptCore/kjs/string_object.cpp
index e59694e..3e8dc7b 100644
--- a/JavaScriptCore/kjs/string_object.cpp
+++ b/JavaScriptCore/kjs/string_object.cpp
@@ -129,42 +129,42 @@
const ClassInfo StringPrototype::info = { "String", &StringInstance::info, &stringTable };
/* Source for string_object.lut.h
@begin stringTable 26
- toString StringProtoFunc::ToString DontEnum|Function 0
- valueOf StringProtoFunc::ValueOf DontEnum|Function 0
- charAt StringProtoFunc::CharAt DontEnum|Function 1
- charCodeAt StringProtoFunc::CharCodeAt DontEnum|Function 1
- concat StringProtoFunc::Concat DontEnum|Function 1
- indexOf StringProtoFunc::IndexOf DontEnum|Function 1
- lastIndexOf StringProtoFunc::LastIndexOf DontEnum|Function 1
- match StringProtoFunc::Match DontEnum|Function 1
- replace StringProtoFunc::Replace DontEnum|Function 2
- search StringProtoFunc::Search DontEnum|Function 1
- slice StringProtoFunc::Slice DontEnum|Function 2
- split StringProtoFunc::Split DontEnum|Function 2
- substr StringProtoFunc::Substr DontEnum|Function 2
- substring StringProtoFunc::Substring DontEnum|Function 2
- toLowerCase StringProtoFunc::ToLowerCase DontEnum|Function 0
- toUpperCase StringProtoFunc::ToUpperCase DontEnum|Function 0
- toLocaleLowerCase StringProtoFunc::ToLocaleLowerCase DontEnum|Function 0
- toLocaleUpperCase StringProtoFunc::ToLocaleUpperCase DontEnum|Function 0
- localeCompare StringProtoFunc::LocaleCompare DontEnum|Function 1
+ toString &StringProtoFuncToString::create DontEnum|Function 0
+ valueOf &StringProtoFuncValueOf::create DontEnum|Function 0
+ charAt &StringProtoFuncCharAt::create DontEnum|Function 1
+ charCodeAt &StringProtoFuncCharCodeAt::create DontEnum|Function 1
+ concat &StringProtoFuncConcat::create DontEnum|Function 1
+ indexOf &StringProtoFuncIndexOf::create DontEnum|Function 1
+ lastIndexOf &StringProtoFuncLastIndexOf::create DontEnum|Function 1
+ match &StringProtoFuncMatch::create DontEnum|Function 1
+ replace &StringProtoFuncReplace::create DontEnum|Function 2
+ search &StringProtoFuncSearch::create DontEnum|Function 1
+ slice &StringProtoFuncSlice::create DontEnum|Function 2
+ split &StringProtoFuncSplit::create DontEnum|Function 2
+ substr &StringProtoFuncSubstr::create DontEnum|Function 2
+ substring &StringProtoFuncSubstring::create DontEnum|Function 2
+ toLowerCase &StringProtoFuncToLowerCase::create DontEnum|Function 0
+ toUpperCase &StringProtoFuncToUpperCase::create DontEnum|Function 0
+ toLocaleLowerCase &StringProtoFuncToLocaleLowerCase::create DontEnum|Function 0
+ toLocaleUpperCase &StringProtoFuncToLocaleUpperCase::create DontEnum|Function 0
+ localeCompare &StringProtoFuncLocaleCompare::create DontEnum|Function 1
#
# Under here: html extension, should only exist if KJS_PURE_ECMA is not defined
# I guess we need to generate two hashtables in the .lut.h file, and use #ifdef
# to select the right one... TODO. #####
- big StringProtoFunc::Big DontEnum|Function 0
- small StringProtoFunc::Small DontEnum|Function 0
- blink StringProtoFunc::Blink DontEnum|Function 0
- bold StringProtoFunc::Bold DontEnum|Function 0
- fixed StringProtoFunc::Fixed DontEnum|Function 0
- italics StringProtoFunc::Italics DontEnum|Function 0
- strike StringProtoFunc::Strike DontEnum|Function 0
- sub StringProtoFunc::Sub DontEnum|Function 0
- sup StringProtoFunc::Sup DontEnum|Function 0
- fontcolor StringProtoFunc::Fontcolor DontEnum|Function 1
- fontsize StringProtoFunc::Fontsize DontEnum|Function 1
- anchor StringProtoFunc::Anchor DontEnum|Function 1
- link StringProtoFunc::Link DontEnum|Function 1
+ big &StringProtoFuncBig::create DontEnum|Function 0
+ small &StringProtoFuncSmall::create DontEnum|Function 0
+ blink &StringProtoFuncBlink::create DontEnum|Function 0
+ bold &StringProtoFuncBold::create DontEnum|Function 0
+ fixed &StringProtoFuncFixed::create DontEnum|Function 0
+ italics &StringProtoFuncItalics::create DontEnum|Function 0
+ strike &StringProtoFuncStrike::create DontEnum|Function 0
+ sub &StringProtoFuncSub::create DontEnum|Function 0
+ sup &StringProtoFuncSup::create DontEnum|Function 0
+ fontcolor &StringProtoFuncFontcolor::create DontEnum|Function 1
+ fontsize &StringProtoFuncFontsize::create DontEnum|Function 1
+ anchor &StringProtoFuncAnchor::create DontEnum|Function 1
+ link &StringProtoFuncLink::create DontEnum|Function 1
@end
*/
// ECMA 15.5.4
@@ -177,17 +177,10 @@
bool StringPrototype::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot &slot)
{
- return getStaticFunctionSlot<StringProtoFunc, StringInstance>(exec, &stringTable, this, propertyName, slot);
+ return getStaticFunctionSlot<StringInstance>(exec, &stringTable, this, propertyName, slot);
}
-// ------------------------------ StringProtoFunc ---------------------------
-
-StringProtoFunc::StringProtoFunc(ExecState* exec, int i, int len, const Identifier& name)
- : InternalFunctionImp(static_cast<FunctionPrototype*>(exec->lexicalInterpreter()->builtinFunctionPrototype()), name)
- , id(i)
-{
- putDirect(exec->propertyNames().length, len, DontDelete | ReadOnly | DontEnum);
-}
+// ------------------------------ Functions --------------------------
static inline void expandSourceRanges(UString::Range * & array, int& count, int& capacity)
{
@@ -434,83 +427,113 @@
return jsString(source.substr(0, matchPos) + replacementString + source.substr(matchPos + matchLen));
}
-// ECMA 15.5.4.2 - 15.5.4.20
-JSValue* StringProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+JSValue* StringProtoFuncToString::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
{
- JSValue* result = NULL;
-
- // toString and valueOf are no generic function.
- if (id == ToString || id == ValueOf) {
if (!thisObj->inherits(&StringInstance::info))
- return throwError(exec, TypeError);
+ return throwError(exec, TypeError);
return static_cast<StringInstance*>(thisObj)->internalValue();
- }
+}
- UString u, u2, u3;
- int pos, p0, i;
- double dpos;
- double d = 0.0;
+JSValue* StringProtoFuncValueOf::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&StringInstance::info))
+ return throwError(exec, TypeError);
- // This optimizes the common case that thisObj is a StringInstance
- UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return static_cast<StringInstance*>(thisObj)->internalValue();
+}
- int len = s.size();
- JSValue *a0 = args[0];
- JSValue *a1 = args[1];
+JSValue* StringProtoFuncCharAt::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ int len = s.size();
- switch (id) {
- case ToString:
- case ValueOf:
- // handled above
- break;
- case CharAt:
- dpos = a0->toInteger(exec);
+ UString u;
+ JSValue* a0 = args[0];
+ double dpos = a0->toInteger(exec);
if (dpos >= 0 && dpos < len)
u = s.substr(static_cast<int>(dpos), 1);
else
u = "";
- result = jsString(u);
- break;
- case CharCodeAt:
- dpos = a0->toInteger(exec);
+ return jsString(u);
+}
+
+JSValue* StringProtoFuncCharCodeAt::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ int len = s.size();
+
+ JSValue* result = 0;
+
+ JSValue* a0 = args[0];
+ double dpos = a0->toInteger(exec);
if (dpos >= 0 && dpos < len)
result = jsNumber(s[static_cast<int>(dpos)].unicode());
else
result = jsNaN();
- break;
- case Concat: {
+ return result;
+}
+
+JSValue* StringProtoFuncConcat::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+
List::const_iterator end = args.end();
for (List::const_iterator it = args.begin(); it != end; ++it) {
s += (*it)->toString(exec);
}
- result = jsString(s);
- break;
- }
- case IndexOf:
- u2 = a0->toString(exec);
- dpos = a1->toInteger(exec);
+ return jsString(s);
+}
+
+JSValue* StringProtoFuncIndexOf::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ int len = s.size();
+
+ JSValue* a0 = args[0];
+ JSValue* a1 = args[1];
+ UString u2 = a0->toString(exec);
+ double dpos = a1->toInteger(exec);
if (dpos < 0)
- dpos = 0;
+ dpos = 0;
else if (dpos > len)
- dpos = len;
- result = jsNumber(s.find(u2, static_cast<int>(dpos)));
- break;
- case LastIndexOf:
- u2 = a0->toString(exec);
- d = a1->toNumber(exec);
- dpos = a1->toIntegerPreserveNaN(exec);
+ dpos = len;
+ return jsNumber(s.find(u2, static_cast<int>(dpos)));
+}
+
+JSValue* StringProtoFuncLastIndexOf::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ int len = s.size();
+
+ JSValue* a0 = args[0];
+ JSValue* a1 = args[1];
+
+ UString u2 = a0->toString(exec);
+ double dpos = a1->toIntegerPreserveNaN(exec);
if (dpos < 0)
- dpos = 0;
+ dpos = 0;
else if (!(dpos <= len)) // true for NaN
- dpos = len;
- result = jsNumber(s.rfind(u2, static_cast<int>(dpos)));
- break;
- case Match:
- case Search: {
- u = s;
- RegExp *reg, *tmpReg = 0;
- RegExpImp *imp = 0;
+ dpos = len;
+ return jsNumber(s.rfind(u2, static_cast<int>(dpos)));
+}
+
+JSValue* StringProtoFuncMatch::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+
+ JSValue* a0 = args[0];
+
+ UString u = s;
+ RegExp* reg;
+ RegExp* tmpReg = 0;
+ RegExpImp* imp = 0;
if (a0->isObject() && static_cast<JSObject *>(a0)->inherits(&RegExpImp::info)) {
reg = static_cast<RegExpImp *>(a0)->regExp();
} else {
@@ -525,80 +548,128 @@
int pos;
int matchLength;
regExpObj->performMatch(reg, u, 0, pos, matchLength);
- if (id == Search) {
- result = jsNumber(pos);
+ JSValue* result;
+ if (!(reg->global())) {
+ // case without 'g' flag is handled like RegExp.prototype.exec
+ if (pos < 0)
+ result = jsNull();
+ else
+ result = regExpObj->arrayOfMatches(exec);
} else {
- // Match
- if (!(reg->global())) {
- // case without 'g' flag is handled like RegExp.prototype.exec
- if (pos < 0)
- result = jsNull();
- else
- result = regExpObj->arrayOfMatches(exec);
+ // return array of matches
+ List list;
+ int lastIndex = 0;
+ while (pos >= 0) {
+ list.append(jsString(u.substr(pos, matchLength)));
+ lastIndex = pos;
+ pos += matchLength == 0 ? 1 : matchLength;
+ regExpObj->performMatch(reg, u, pos, pos, matchLength);
+ }
+ if (imp)
+ imp->put(exec, exec->propertyNames().lastIndex, jsNumber(lastIndex), DontDelete|DontEnum);
+ if (list.isEmpty()) {
+ // if there are no matches at all, it's important to return
+ // Null instead of an empty array, because this matches
+ // other browsers and because Null is a false value.
+ result = jsNull();
} else {
- // return array of matches
- List list;
- int lastIndex = 0;
- while (pos >= 0) {
- list.append(jsString(u.substr(pos, matchLength)));
- lastIndex = pos;
- pos += matchLength == 0 ? 1 : matchLength;
- regExpObj->performMatch(reg, u, pos, pos, matchLength);
- }
- if (imp)
- imp->put(exec, exec->propertyNames().lastIndex, jsNumber(lastIndex), DontDelete|DontEnum);
- if (list.isEmpty()) {
- // if there are no matches at all, it's important to return
- // Null instead of an empty array, because this matches
- // other browsers and because Null is a false value.
- result = jsNull();
- } else {
- result = exec->lexicalInterpreter()->builtinArray()->construct(exec, list);
- }
+ result = exec->lexicalInterpreter()->builtinArray()->construct(exec, list);
}
}
delete tmpReg;
- break;
- }
- case Replace: {
+ return result;
+}
+
+JSValue* StringProtoFuncSearch::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+
+ JSValue* a0 = args[0];
+
+ UString u = s;
+ RegExp* reg;
+ RegExp* tmpReg = 0;
+ if (a0->isObject() && static_cast<JSObject *>(a0)->inherits(&RegExpImp::info)) {
+ reg = static_cast<RegExpImp *>(a0)->regExp();
+ } else {
+ /*
+ * ECMA 15.5.4.12 String.prototype.search (regexp)
+ * If regexp is not an object whose [[Class]] property is "RegExp", it is
+ * replaced with the result of the expression new RegExp(regexp).
+ */
+ reg = tmpReg = new RegExp(a0->toString(exec));
+ }
+ RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->lexicalInterpreter()->builtinRegExp());
+ int pos;
+ int matchLength;
+ regExpObj->performMatch(reg, u, 0, pos, matchLength);
+ delete tmpReg;
+ return jsNumber(pos);
+}
+
+JSValue* StringProtoFuncReplace::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+
StringImp* sVal = thisObj->inherits(&StringInstance::info) ?
static_cast<StringInstance*>(thisObj)->internalValue() :
static_cast<StringImp*>(jsString(s));
- result = replace(exec, sVal, a0, a1);
- break;
- }
- case Slice:
- {
- // The arg processing is very much like ArrayProtoFunc::Slice
- double start = a0->toInteger(exec);
- double end = a1->isUndefined() ? len : a1->toInteger(exec);
- double from = start < 0 ? len + start : start;
- double to = end < 0 ? len + end : end;
- if (to > from && to > 0 && from < len) {
+ JSValue* a0 = args[0];
+ JSValue* a1 = args[1];
+
+ return replace(exec, sVal, a0, a1);
+}
+
+JSValue* StringProtoFuncSlice::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ int len = s.size();
+
+ JSValue* a0 = args[0];
+ JSValue* a1 = args[1];
+
+ // The arg processing is very much like ArrayProtoFunc::Slice
+ double start = a0->toInteger(exec);
+ double end = a1->isUndefined() ? len : a1->toInteger(exec);
+ double from = start < 0 ? len + start : start;
+ double to = end < 0 ? len + end : end;
+ if (to > from && to > 0 && from < len) {
if (from < 0)
- from = 0;
+ from = 0;
if (to > len)
- to = len;
- result = jsString(s.substr(static_cast<int>(from), static_cast<int>(to - from)));
- } else {
- result = jsString("");
- }
- break;
+ to = len;
+ return jsString(s.substr(static_cast<int>(from), static_cast<int>(to - from)));
}
- case Split: {
+
+ return jsString("");
+}
+
+JSValue* StringProtoFuncSplit::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+
+ JSValue* a0 = args[0];
+ JSValue* a1 = args[1];
+
JSObject *constructor = exec->lexicalInterpreter()->builtinArray();
JSObject *res = static_cast<JSObject *>(constructor->construct(exec,List::empty()));
- result = res;
- u = s;
- i = p0 = 0;
+ JSValue* result = res;
+ UString u = s;
+ int pos;
+ int i = 0;
+ int p0 = 0;
uint32_t limit = a1->isUndefined() ? 0xFFFFFFFFU : a1->toUInt32(exec);
if (a0->isObject() && static_cast<JSObject *>(a0)->inherits(&RegExpImp::info)) {
RegExp *reg = static_cast<RegExpImp *>(a0)->regExp();
if (u.isEmpty() && reg->match(u, 0) >= 0) {
// empty string matched by regexp -> empty array
res->put(exec, exec->propertyNames().length, jsNumber(0));
- break;
+ return result;
}
pos = 0;
while (static_cast<uint32_t>(i) != limit && pos < u.size()) {
@@ -622,12 +693,12 @@
}
}
} else {
- u2 = a0->toString(exec);
+ UString u2 = a0->toString(exec);
if (u2.isEmpty()) {
if (u.isEmpty()) {
// empty separator matches empty string -> empty array
put(exec, exec->propertyNames().length, jsNumber(0));
- break;
+ return result;
} else {
while (static_cast<uint32_t>(i) != limit && i < u.size()-1)
res->put(exec, i++, jsString(u.substr(p0++, 1)));
@@ -644,9 +715,20 @@
if (static_cast<uint32_t>(i) != limit)
res->put(exec, i++, jsString(u.substr(p0)));
res->put(exec, exec->propertyNames().length, jsNumber(i));
- }
- break;
- case Substr: {
+ return result;
+}
+
+JSValue* StringProtoFuncSubstr::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ int len = s.size();
+
+ JSValue* a0 = args[0];
+ JSValue* a1 = args[1];
+
+ double d = 0.0;
+
double start = a0->toInteger(exec);
double length = a1->isUndefined() ? len : a1->toInteger(exec);
if (start >= len)
@@ -660,10 +742,18 @@
}
if (length > len - d)
length = len - d;
- result = jsString(s.substr(static_cast<int>(start), static_cast<int>(length)));
- break;
- }
- case Substring: {
+ return jsString(s.substr(static_cast<int>(start), static_cast<int>(length)));
+}
+
+JSValue* StringProtoFuncSubstring::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ int len = s.size();
+
+ JSValue* a0 = args[0];
+ JSValue* a1 = args[1];
+
double start = a0->toNumber(exec);
double end = a1->toNumber(exec);
if (isnan(start))
@@ -685,11 +775,14 @@
end = start;
start = temp;
}
- result = jsString(s.substr((int)start, (int)end-(int)start));
- }
- break;
- case ToLowerCase:
- case ToLocaleLowerCase: { // FIXME: See http://www.unicode.org/Public/UNIDATA/SpecialCasing.txt for locale-sensitive mappings that aren't implemented.
+ return jsString(s.substr((int)start, (int)end-(int)start));
+}
+
+JSValue* StringProtoFuncToLowerCase::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+
StringImp* sVal = thisObj->inherits(&StringInstance::info)
? static_cast<StringInstance*>(thisObj)->internalValue()
: static_cast<StringImp*>(jsString(s));
@@ -708,9 +801,13 @@
if (length == ssize && memcmp(buffer.data(), s.data(), length * sizeof(UChar)) == 0)
return sVal;
return jsString(UString(reinterpret_cast<UChar*>(buffer.releaseBuffer()), length, false));
- }
- case ToUpperCase:
- case ToLocaleUpperCase: { // FIXME: See http://www.unicode.org/Public/UNIDATA/SpecialCasing.txt for locale-sensitive mappings that aren't implemented.
+}
+
+JSValue* StringProtoFuncToUpperCase::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+
StringImp* sVal = thisObj->inherits(&StringInstance::info)
? static_cast<StringInstance*>(thisObj)->internalValue()
: static_cast<StringImp*>(jsString(s));
@@ -729,57 +826,169 @@
if (length == ssize && memcmp(buffer.data(), s.data(), length * sizeof(UChar)) == 0)
return sVal;
return jsString(UString(reinterpret_cast<UChar*>(buffer.releaseBuffer()), length, false));
- }
- case LocaleCompare:
+}
+
+JSValue* StringProtoFuncToLocaleLowerCase::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+
+ // FIXME: See http://www.unicode.org/Public/UNIDATA/SpecialCasing.txt for locale-sensitive mappings that aren't implemented.
+ StringImp* sVal = thisObj->inherits(&StringInstance::info)
+ ? static_cast<StringInstance*>(thisObj)->internalValue()
+ : static_cast<StringImp*>(jsString(s));
+ int ssize = s.size();
+ if (!ssize)
+ return sVal;
+ Vector< ::UChar> buffer(ssize);
+ bool error;
+ int length = Unicode::toLower(buffer.data(), ssize, reinterpret_cast<const ::UChar*>(s.data()), ssize, &error);
+ if (error) {
+ buffer.resize(length);
+ length = Unicode::toLower(buffer.data(), length, reinterpret_cast<const ::UChar*>(s.data()), ssize, &error);
+ if (error)
+ return sVal;
+ }
+ if (length == ssize && memcmp(buffer.data(), s.data(), length * sizeof(UChar)) == 0)
+ return sVal;
+ return jsString(UString(reinterpret_cast<UChar*>(buffer.releaseBuffer()), length, false));
+}
+
+JSValue* StringProtoFuncToLocaleUpperCase::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+
+ StringImp* sVal = thisObj->inherits(&StringInstance::info)
+ ? static_cast<StringInstance*>(thisObj)->internalValue()
+ : static_cast<StringImp*>(jsString(s));
+ int ssize = s.size();
+ if (!ssize)
+ return sVal;
+ Vector< ::UChar> buffer(ssize);
+ bool error;
+ int length = Unicode::toUpper(buffer.data(), ssize, reinterpret_cast<const ::UChar*>(s.data()), ssize, &error);
+ if (error) {
+ buffer.resize(length);
+ length = Unicode::toUpper(buffer.data(), length, reinterpret_cast<const ::UChar*>(s.data()), ssize, &error);
+ if (error)
+ return sVal;
+ }
+ if (length == ssize && memcmp(buffer.data(), s.data(), length * sizeof(UChar)) == 0)
+ return sVal;
+ return jsString(UString(reinterpret_cast<UChar*>(buffer.releaseBuffer()), length, false));
+}
+
+JSValue* StringProtoFuncLocaleCompare::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
if (args.size() < 1)
return jsNumber(0);
- return jsNumber(localeCompare(s, a0->toString(exec)));
-#ifndef KJS_PURE_ECMA
- case Big:
- result = jsString("<big>" + s + "</big>");
- break;
- case Small:
- result = jsString("<small>" + s + "</small>");
- break;
- case Blink:
- result = jsString("<blink>" + s + "</blink>");
- break;
- case Bold:
- result = jsString("<b>" + s + "</b>");
- break;
- case Fixed:
- result = jsString("<tt>" + s + "</tt>");
- break;
- case Italics:
- result = jsString("<i>" + s + "</i>");
- break;
- case Strike:
- result = jsString("<strike>" + s + "</strike>");
- break;
- case Sub:
- result = jsString("<sub>" + s + "</sub>");
- break;
- case Sup:
- result = jsString("<sup>" + s + "</sup>");
- break;
- case Fontcolor:
- result = jsString("<font color=\"" + a0->toString(exec) + "\">" + s + "</font>");
- break;
- case Fontsize:
- result = jsString("<font size=\"" + a0->toString(exec) + "\">" + s + "</font>");
- break;
- case Anchor:
- result = jsString("<a name=\"" + a0->toString(exec) + "\">" + s + "</a>");
- break;
- case Link:
- result = jsString("<a href=\"" + a0->toString(exec) + "\">" + s + "</a>");
- break;
-#endif
- }
- return result;
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ JSValue* a0 = args[0];
+ return jsNumber(localeCompare(s, a0->toString(exec)));
}
+#ifndef KJS_PURE_ECMA
+
+JSValue* StringProtoFuncBig::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return jsString("<big>" + s + "</big>");
+}
+
+JSValue* StringProtoFuncSmall::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return jsString("<small>" + s + "</small>");
+}
+
+JSValue* StringProtoFuncBlink::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return jsString("<blink>" + s + "</blink>");
+}
+
+JSValue* StringProtoFuncBold::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return jsString("<b>" + s + "</b>");
+}
+
+JSValue* StringProtoFuncFixed::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return jsString("<tt>" + s + "</tt>");
+}
+
+JSValue* StringProtoFuncItalics::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return jsString("<i>" + s + "</i>");
+}
+
+JSValue* StringProtoFuncStrike::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return jsString("<strike>" + s + "</strike>");
+}
+
+JSValue* StringProtoFuncSub::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return jsString("<sub>" + s + "</sub>");
+}
+
+JSValue* StringProtoFuncSup::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return jsString("<sup>" + s + "</sup>");
+}
+
+JSValue* StringProtoFuncFontcolor::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ JSValue* a0 = args[0];
+ return jsString("<font color=\"" + a0->toString(exec) + "\">" + s + "</font>");
+}
+
+JSValue* StringProtoFuncFontsize::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ JSValue* a0 = args[0];
+ return jsString("<font size=\"" + a0->toString(exec) + "\">" + s + "</font>");
+}
+
+JSValue* StringProtoFuncAnchor::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ JSValue* a0 = args[0];
+ return jsString("<a name=\"" + a0->toString(exec) + "\">" + s + "</a>");
+}
+
+JSValue* StringProtoFuncLink::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ JSValue* a0 = args[0];
+ return jsString("<a href=\"" + a0->toString(exec) + "\">" + s + "</a>");
+}
+
+#endif // KJS_PURE_ECMA
+
// ------------------------------ StringObjectImp ------------------------------
StringObjectImp::StringObjectImp(ExecState* exec,
@@ -849,4 +1058,4 @@
return jsString(s);
}
-}
+} // namespace KJS