Commit 8063cc71 authored by benjamin@webkit.org's avatar benjamin@webkit.org
Browse files

Speed up the conversion from JSValue to String for bulk operations

https://bugs.webkit.org/show_bug.cgi?id=83243

Patch by Benjamin Poulain <bpoulain@apple.com> on 2012-04-05
Reviewed by Geoffrey Garen.

When making operations on primitive types, we loose some time converting
values to JSString in order to extract the string.

This patch speeds up some basic Array operations by avoiding the creation
of intermediary JSString when possible.

For the cases where we need to convert a lot of JSValue in a tight loop,
an inline conversion is used.

* runtime/ArrayPrototype.cpp:
(JSC::arrayProtoFuncToString):
(JSC::arrayProtoFuncToLocaleString):
(JSC::arrayProtoFuncJoin):
(JSC::arrayProtoFuncPush):
(JSC::arrayProtoFuncSort):
* runtime/CommonIdentifiers.h:
* runtime/JSArray.cpp:
(JSC::JSArray::sort):
* runtime/JSString.h:
(JSC::JSValue::toUString):
(JSC):
(JSC::inlineJSValueNotStringtoUString):
(JSC::JSValue::toUStringInline):
* runtime/JSValue.cpp:
(JSC::JSValue::toUStringSlowCase):
(JSC):
* runtime/JSValue.h:
(JSValue):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@113396 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 3853eb01
2012-04-05 Benjamin Poulain <bpoulain@apple.com>
Speed up the conversion from JSValue to String for bulk operations
https://bugs.webkit.org/show_bug.cgi?id=83243
Reviewed by Geoffrey Garen.
When making operations on primitive types, we loose some time converting
values to JSString in order to extract the string.
This patch speeds up some basic Array operations by avoiding the creation
of intermediary JSString when possible.
For the cases where we need to convert a lot of JSValue in a tight loop,
an inline conversion is used.
* runtime/ArrayPrototype.cpp:
(JSC::arrayProtoFuncToString):
(JSC::arrayProtoFuncToLocaleString):
(JSC::arrayProtoFuncJoin):
(JSC::arrayProtoFuncPush):
(JSC::arrayProtoFuncSort):
* runtime/CommonIdentifiers.h:
* runtime/JSArray.cpp:
(JSC::JSArray::sort):
* runtime/JSString.h:
(JSC::JSValue::toUString):
(JSC):
(JSC::inlineJSValueNotStringtoUString):
(JSC::JSValue::toUStringInline):
* runtime/JSValue.cpp:
(JSC::JSValue::toUStringSlowCase):
(JSC):
* runtime/JSValue.h:
(JSValue):
2012-04-05 Benjamin Poulain <bpoulain@apple.com>
 
Use QuickSort when sorting primitive values by string representation
......@@ -281,7 +281,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec)
if (element.isUndefinedOrNull())
continue;
UString str = element.toString(exec)->value(exec);
UString str = element.toUString(exec);
strBuffer[k] = str.impl();
totalSize += str.length();
allStrings8Bit = allStrings8Bit && str.is8Bit();
......@@ -358,9 +358,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec)
CallData callData;
CallType callType = getCallData(conversionFunction, callData);
if (callType != CallTypeNone)
str = call(exec, conversionFunction, callType, callData, element, exec->emptyList()).toString(exec)->value(exec);
str = call(exec, conversionFunction, callType, callData, element, exec->emptyList()).toUString(exec);
else
str = element.toString(exec)->value(exec);
str = element.toUString(exec);
if (exec->hadException())
return JSValue::encode(jsUndefined());
stringJoiner.append(str);
......@@ -383,7 +383,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec)
UString separator;
if (!exec->argument(0).isUndefined())
separator = exec->argument(0).toString(exec)->value(exec);
separator = exec->argument(0).toUString(exec);
if (separator.isNull())
separator = UString(",");
......@@ -399,7 +399,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec)
JSValue element = array->getIndex(k);
if (!element.isUndefinedOrNull())
stringJoiner.append(element.toString(exec)->value(exec));
stringJoiner.append(element.toUStringInline(exec));
else
stringJoiner.append(UString());
}
......@@ -408,7 +408,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec)
for (; k < length; k++) {
JSValue element = thisObj->get(exec, k);
if (!element.isUndefinedOrNull())
stringJoiner.append(element.toString(exec)->value(exec));
stringJoiner.append(element.toUStringInline(exec));
else
stringJoiner.append(UString());
}
......@@ -501,7 +501,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec)
thisObj->methodTable()->putByIndex(thisObj, exec, length + n, exec->argument(n), true);
else {
PutPropertySlot slot;
Identifier propertyName(exec, JSValue(static_cast<int64_t>(length) + static_cast<int64_t>(n)).toString(exec)->value(exec));
Identifier propertyName(exec, JSValue(static_cast<int64_t>(length) + static_cast<int64_t>(n)).toUString(exec));
thisObj->methodTable()->put(thisObj, exec, propertyName, exec->argument(n), slot);
}
if (exec->hadException())
......@@ -642,7 +642,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec)
l.append(minObj);
compareResult = call(exec, function, callType, callData, jsUndefined(), l).toNumber(exec);
} else
compareResult = (jObj.toString(exec)->value(exec) < minObj.toString(exec)->value(exec)) ? -1 : 1;
compareResult = (jObj.toUStringInline(exec) < minObj.toUStringInline(exec)) ? -1 : 1;
if (compareResult < 0) {
themin = j;
......
......@@ -76,6 +76,7 @@
#define JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(macro) \
macro(null) \
macro(undefined) \
macro(true) \
macro(false) \
macro(break) \
......
......@@ -1487,7 +1487,7 @@ void JSArray::sort(ExecState* exec)
// a toString call raises an exception.
for (size_t i = 0; i < lengthNotIncludingUndefined; i++)
values[i].second = values[i].first.toString(exec)->value(exec);
values[i].second = values[i].first.toUStringInline(exec);
if (exec->hadException()) {
Heap::heap(this)->popTempSortVector(&values);
......
......@@ -462,6 +462,39 @@ namespace JSC {
return toStringSlowCase(exec);
}
inline UString JSValue::toUString(ExecState* exec) const
{
if (isString())
return static_cast<JSString*>(asCell())->value(exec);
return toUStringSlowCase(exec);
}
ALWAYS_INLINE UString inlineJSValueNotStringtoUString(const JSValue& value, ExecState* exec)
{
JSGlobalData& globalData = exec->globalData();
if (value.isInt32())
return globalData.numericStrings.add(value.asInt32());
if (value.isDouble())
return globalData.numericStrings.add(value.asDouble());
if (value.isTrue())
return globalData.propertyNames->trueKeyword.ustring();
if (value.isFalse())
return globalData.propertyNames->falseKeyword.ustring();
if (value.isNull())
return globalData.propertyNames->nullKeyword.ustring();
if (value.isUndefined())
return globalData.propertyNames->undefinedKeyword.ustring();
return value.toString(exec)->value(exec);
}
ALWAYS_INLINE UString JSValue::toUStringInline(ExecState* exec) const
{
if (isString())
return static_cast<JSString*>(asCell())->value(exec);
return inlineJSValueNotStringtoUString(*this, exec);
}
} // namespace JSC
#endif // JSString_h
......@@ -283,4 +283,9 @@ JSString* JSValue::toStringSlowCase(ExecState* exec) const
return value.toString(exec);
}
UString JSValue::toUStringSlowCase(ExecState* exec) const
{
return inlineJSValueNotStringtoUString(*this, exec);
}
} // namespace JSC
......@@ -203,6 +203,8 @@ namespace JSC {
// been set in the ExecState already.
double toNumber(ExecState*) const;
JSString* toString(ExecState*) const;
UString toUString(ExecState*) const;
UString toUStringInline(ExecState*) const;
JSObject* toObject(ExecState*) const;
JSObject* toObject(ExecState*, JSGlobalObject*) const;
......@@ -251,6 +253,7 @@ namespace JSC {
inline const JSValue asValue() const { return *this; }
JS_EXPORT_PRIVATE double toNumberSlowCase(ExecState*) const;
JS_EXPORT_PRIVATE JSString* toStringSlowCase(ExecState*) const;
JS_EXPORT_PRIVATE UString toUStringSlowCase(ExecState*) const;
JS_EXPORT_PRIVATE JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const;
JS_EXPORT_PRIVATE JSObject* toThisObjectSlowCase(ExecState*) const;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment