- Revision
- 198256
- Author
- [email protected]
- Date
- 2016-03-15 19:16:40 -0700 (Tue, 15 Mar 2016)
Log Message
[JSC] Help clang generate better code on arrayProtoFuncToString()
https://bugs.webkit.org/show_bug.cgi?id=155512
Patch by Benjamin Poulain <[email protected]> on 2016-03-15
Reviewed by Mark Lam.
3d-raytrace hits Array.toString() hard with small arrays.
Half of the time is going into overhead around the StringJoiner.
This patch makes the function shorter and the layout better.
* runtime/ArrayPrototype.cpp:
(JSC::arrayProtoFuncToString):
Add "UNLIKELY" on rare cases. Clang pushes that code to the tail.
Factor the code of jsMakeNontrivialString() so that the operation
is not duplicated in the function.
* runtime/JSStringBuilder.h:
(JSC::jsMakeNontrivialString):
jsNontrivialString() supports r-value reference.
Move the result string into jsNontrivialString(), this removes
the deref+destructor from the function.
* runtime/JSStringJoiner.cpp:
(JSC::JSStringJoiner::~JSStringJoiner):
The destructor is pretty large. No point in inlining it.
(JSC::joinStrings):
* runtime/JSStringJoiner.h:
(JSC::JSStringJoiner::JSStringJoiner):
(JSC::JSStringJoiner::append):
The calls were duplicated. That's unnecessary.
* runtime/NumericStrings.h:
(JSC::NumericStrings::add):
Return a reference in all cases.
This removes a deref+destructor.
Modified Paths
Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (198255 => 198256)
--- trunk/Source/_javascript_Core/ChangeLog 2016-03-16 01:51:12 UTC (rev 198255)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-03-16 02:16:40 UTC (rev 198256)
@@ -1,3 +1,42 @@
+2016-03-15 Benjamin Poulain <[email protected]>
+
+ [JSC] Help clang generate better code on arrayProtoFuncToString()
+ https://bugs.webkit.org/show_bug.cgi?id=155512
+
+ Reviewed by Mark Lam.
+
+ 3d-raytrace hits Array.toString() hard with small arrays.
+ Half of the time is going into overhead around the StringJoiner.
+ This patch makes the function shorter and the layout better.
+
+ * runtime/ArrayPrototype.cpp:
+ (JSC::arrayProtoFuncToString):
+ Add "UNLIKELY" on rare cases. Clang pushes that code to the tail.
+
+ Factor the code of jsMakeNontrivialString() so that the operation
+ is not duplicated in the function.
+
+ * runtime/JSStringBuilder.h:
+ (JSC::jsMakeNontrivialString):
+ jsNontrivialString() supports r-value reference.
+ Move the result string into jsNontrivialString(), this removes
+ the deref+destructor from the function.
+
+ * runtime/JSStringJoiner.cpp:
+ (JSC::JSStringJoiner::~JSStringJoiner):
+ The destructor is pretty large. No point in inlining it.
+
+ (JSC::joinStrings):
+ * runtime/JSStringJoiner.h:
+ (JSC::JSStringJoiner::JSStringJoiner):
+ (JSC::JSStringJoiner::append):
+ The calls were duplicated. That's unnecessary.
+
+ * runtime/NumericStrings.h:
+ (JSC::NumericStrings::add):
+ Return a reference in all cases.
+ This removes a deref+destructor.
+
2016-03-15 Joseph Pecoraro <[email protected]>
Remove stale ArrayPrototype declarations
Modified: trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp (198255 => 198256)
--- trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp 2016-03-16 01:51:12 UTC (rev 198255)
+++ trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp 2016-03-16 02:16:40 UTC (rev 198256)
@@ -322,18 +322,23 @@
// 1. Let array be the result of calling ToObject on the this value.
JSObject* thisObject = thisValue.toObject(exec);
- if (exec->hadException())
+ VM& vm = exec->vm();
+ if (UNLIKELY(vm.exception()))
return JSValue::encode(jsUndefined());
// 2. Let func be the result of calling the [[Get]] internal method of array with argument "join".
JSValue function = JSValue(thisObject).get(exec, exec->propertyNames().join);
// 3. If IsCallable(func) is false, then let func be the standard built-in method Object.prototype.toString (15.2.4.2).
+ bool customJoinCase = false;
if (!function.isCell())
- return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable(exec->vm())->className(thisObject), "]"));
+ customJoinCase = true;
CallData callData;
CallType callType = getCallData(function, callData);
if (callType == CallType::None)
+ customJoinCase = true;
+
+ if (UNLIKELY(customJoinCase))
return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable(exec->vm())->className(thisObject), "]"));
// 4. Return the result of calling the [[Call]] internal method of func providing array as the this value and an empty arguments list.
@@ -350,18 +355,18 @@
return JSValue::encode(earlyReturnValue);
JSStringJoiner joiner(*exec, ',', length);
- if (exec->hadException())
+ if (UNLIKELY(vm.exception()))
return JSValue::encode(jsUndefined());
for (unsigned i = 0; i < length; ++i) {
JSValue element = thisArray->tryGetIndexQuickly(i);
if (!element) {
element = thisArray->get(exec, i);
- if (exec->hadException())
+ if (UNLIKELY(vm.exception()))
return JSValue::encode(jsUndefined());
}
joiner.append(*exec, element);
- if (exec->hadException())
+ if (UNLIKELY(vm.exception()))
return JSValue::encode(jsUndefined());
}
Modified: trunk/Source/_javascript_Core/runtime/JSStringBuilder.h (198255 => 198256)
--- trunk/Source/_javascript_Core/runtime/JSStringBuilder.h 2016-03-16 01:51:12 UTC (rev 198255)
+++ trunk/Source/_javascript_Core/runtime/JSStringBuilder.h 2016-03-16 02:16:40 UTC (rev 198256)
@@ -130,7 +130,7 @@
String result = WTF::tryMakeString(string, strings...);
if (!result)
return throwOutOfMemoryError(exec);
- return jsNontrivialString(exec, result);
+ return jsNontrivialString(exec, WTFMove(result));
}
}
Modified: trunk/Source/_javascript_Core/runtime/JSStringJoiner.cpp (198255 => 198256)
--- trunk/Source/_javascript_Core/runtime/JSStringJoiner.cpp 2016-03-16 01:51:12 UTC (rev 198255)
+++ trunk/Source/_javascript_Core/runtime/JSStringJoiner.cpp 2016-03-16 02:16:40 UTC (rev 198256)
@@ -30,6 +30,10 @@
namespace JSC {
+JSStringJoiner::~JSStringJoiner()
+{
+}
+
template<typename CharacterType>
static inline void appendStringToData(CharacterType*& data, StringView string)
{
@@ -44,7 +48,7 @@
CharacterType* data;
String result = StringImpl::tryCreateUninitialized(joinedLength, data);
- if (result.isNull())
+ if (UNLIKELY(result.isNull()))
return result;
appendStringToData(data, strings[0].view);
Modified: trunk/Source/_javascript_Core/runtime/JSStringJoiner.h (198255 => 198256)
--- trunk/Source/_javascript_Core/runtime/JSStringJoiner.h 2016-03-16 01:51:12 UTC (rev 198255)
+++ trunk/Source/_javascript_Core/runtime/JSStringJoiner.h 2016-03-16 02:16:40 UTC (rev 198256)
@@ -35,6 +35,7 @@
public:
JSStringJoiner(ExecState&, LChar separator, unsigned stringCount);
JSStringJoiner(ExecState&, StringView separator, unsigned stringCount);
+ ~JSStringJoiner();
void append(ExecState&, JSValue);
void appendEmptyString();
@@ -58,7 +59,7 @@
: m_separator(separator)
, m_isAll8Bit(m_separator.is8Bit())
{
- if (!m_strings.tryReserveCapacity(stringCount))
+ if (UNLIKELY(!m_strings.tryReserveCapacity(stringCount)))
throwOutOfMemoryError(&state);
}
@@ -66,7 +67,7 @@
: m_singleCharacterSeparator(separator)
, m_separator { &m_singleCharacterSeparator, 1 }
{
- if (!m_strings.tryReserveCapacity(stringCount))
+ if (UNLIKELY(!m_strings.tryReserveCapacity(stringCount)))
throwOutOfMemoryError(&state);
}
@@ -106,11 +107,12 @@
// 5) It uses optimized code paths for all the cases known to be 8-bit and for the empty string.
if (value.isCell()) {
- if (value.asCell()->isString()) {
- append(asString(value)->viewWithUnderlyingString(state));
- return;
- }
- append(value.toString(&state)->viewWithUnderlyingString(state));
+ JSString* jsString;
+ if (value.asCell()->isString())
+ jsString = asString(value);
+ else
+ jsString = value.toString(&state);
+ append(jsString->viewWithUnderlyingString(state));
return;
}
Modified: trunk/Source/_javascript_Core/runtime/NumericStrings.h (198255 => 198256)
--- trunk/Source/_javascript_Core/runtime/NumericStrings.h 2016-03-16 01:51:12 UTC (rev 198255)
+++ trunk/Source/_javascript_Core/runtime/NumericStrings.h 2016-03-16 02:16:40 UTC (rev 198256)
@@ -34,7 +34,7 @@
class NumericStrings {
public:
- ALWAYS_INLINE String add(double d)
+ ALWAYS_INLINE const String& add(double d)
{
CacheEntry<double>& entry = lookup(d);
if (d == entry.key && !entry.value.isNull())
@@ -44,7 +44,7 @@
return entry.value;
}
- ALWAYS_INLINE String add(int i)
+ ALWAYS_INLINE const String& add(int i)
{
if (static_cast<unsigned>(i) < cacheSize)
return lookupSmallString(static_cast<unsigned>(i));
@@ -56,7 +56,7 @@
return entry.value;
}
- ALWAYS_INLINE String add(unsigned i)
+ ALWAYS_INLINE const String& add(unsigned i)
{
if (i < cacheSize)
return lookupSmallString(static_cast<unsigned>(i));