Ignore:
Timestamp:
Jun 23, 2015, 7:33:18 PM (10 years ago)
Author:
Darin Adler
Message:

Make Array.join work directly on substrings without reifying them
https://bugs.webkit.org/show_bug.cgi?id=146191

Reviewed by Andreas Kling.

Source/JavaScriptCore:

Besides the Array.join change, this has other optimizations based on
profiling the Peacekeeper array benchmark.

I measured a 14% speed improvement in the Peacekeeper array benchmark.

Still a lot of low hanging fruit in that test because so many of functions
on the array prototype are not optimizing for simple cases. For example,
the reverse function does individual get and put calls even when the array
is entirely made up of integers in contiguous storage.

  • runtime/ArrayPrototype.cpp:

(JSC::getProperty): Use tryGetIndexQuickly first before getPropertySlot.
(JSC::argumentClampedIndexFromStartOrEnd): Marked inline.
(JSC::shift): Use the getProperty helper in this file instead of using
getPropertySlot. Use putByIndexInline instead of calling putByIndex directly.
In both cases this can yield a faster code path.
(JSC::unshift): Ditto.
(JSC::arrayProtoFuncToString): Updated to use the new JSStringJoiner
interface. Changed local variable name to thisArray since it's not a
JSObject*. Changed loop index to i instead of k.
(JSC::arrayProtoFuncToLocaleString): Updated to use the new JSStringJoiner
interface. Renamed thisObj to thisObject. Added a missing exception check
after the toLocaleString function is called, but before toString is called
the result of that function.
(JSC::arrayProtoFuncJoin): Updated to use the new JSStringJointer interface.
Added a missing exception check after calling toString on the separator
but before calling get to get the first element in the array-like object
being joined. Changed loop index to i instead of k. Added missing exception
check after calling toString on each string from the array before calling
get for the next element.
(JSC::arrayProtoFuncConcat): Use JSArray::length instead of using the
getLength function.
(JSC::arrayProtoFuncReverse): Ditto. Also use putByIndexInline.
(JSC::arrayProtoFuncShift): Ditto.
(JSC::arrayProtoFuncSplice): Use getIndex instead of get, which includes some
additional optimizations.
(JSC::getOrHole): Deleted. Unused function.
(JSC::arrayProtoFuncUnShift): Use putByIndexInline.

  • runtime/ExceptionHelpers.cpp:

(JSC::errorDescriptionForValue): Removed the duplicate copy of the the logic
from JSValue::toString.

  • runtime/JSCJSValue.cpp:

(JSC::JSValue::toStringSlowCase): Improved the performance when converting a
small integer to a single character string.
(JSC::JSValue::toWTFStringSlowCase): Moved the contents of the
inlineJSValueNotStringtoString function here.

  • runtime/JSCJSValue.h: Removed no longer used toWTFStringInline and fixed

a comment with a typo.

  • runtime/JSObject.h:

(JSC::JSObject::putByIndexInline): Marked ALWAYS_INLINE because this was not
getting inlined at some call sites.
(JSC::JSObject::indexingData): Deleted. Unused function.
(JSC::JSObject::currentIndexingData): Deleted. Unused function.
(JSC::JSObject::getHolyIndexQuickly): Deleted. Unused function.
(JSC::JSObject::relevantLength): Deleted. Unused function.
(JSC::JSObject::currentRelevantLength): Deleted. Unused function.

  • runtime/JSString.h: Added the StringViewWithUnderlyingString struct and

the viewWithUnderlyingString function. Removed the inlineJSValueNotStringtoString
and toWTFStringInline functions.

  • runtime/JSStringJoiner.cpp:

(JSC::appendStringToData): Changed this to be a template instead of writing
it out, since StringView::getCharactersWithUpconvert does almsot exactly what
this function was trying to do.
(JSC::joinStrings): Rewrote this to use StringView.
(JSC::JSStringJoiner::joinedLength): Added. Factored out from the join function.
(JSC::JSStringJoiner::join): Rewrote to make it a bit simpler. Added an assertion
that we entirely filled capacity, since we are now reserving capacity and using
uncheckedAppend. Use String instead of RefPtr<StringImpl> because there was no
particular value to using the impl directly.

  • runtime/JSStringJoiner.h: Changed the interface to the class to use StringView.

Also changed this class so it now has the responsibility to convert each JSValue
into a string. This let us share more code between toString and join, and also
lets us use the new viewWithUnderlyingString function, which could be confusing at
all the call sites, but is easier to understand here.

Source/WTF:

  • wtf/Vector.h: Added an overload of uncheckedAppend like the one we added

a while back, a non-template function that forwards through to the function
template. This lets us call uncheckedAppend on an argument list and have it
properly convert it to the Vector's element type.

  • wtf/text/StringView.h:

(WTF::StringView::getCharactersWithUpconvert): Changed to not use memcpy;
saw some indication the hand-written loop was faster when profiling. Also
use m_length directly when we know we are dealing with an 8-bit string,
since the masking that the index function does is not needed in that case.
(WTF::StringView::UpconvertedCharacters::UpconvertedCharacters): Ditto.
(WTF::StringView::toString): Ditto.
(WTF::StringView::toFloat): Ditto.
(WTF::StringView::toInt): Ditto.
(WTF::StringView::toStringWithoutCopying): Ditto.
(WTF::StringView::find): Ditto.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/JSCJSValue.cpp

    r182406 r185899  
    354354    VM& vm = exec->vm();
    355355    ASSERT(!isString());
    356     if (isInt32())
    357         return jsString(&vm, vm.numericStrings.add(asInt32()));
     356    if (isInt32()) {
     357        auto integer = asInt32();
     358        if (static_cast<unsigned>(integer) <= 9)
     359            return vm.smallStrings.singleCharacterString(integer + '0');
     360        return jsNontrivialString(&vm, vm.numericStrings.add(integer));
     361    }
    358362    if (isDouble())
    359363        return jsString(&vm, vm.numericStrings.add(asDouble()));
     
    381385String JSValue::toWTFStringSlowCase(ExecState* exec) const
    382386{
    383     return inlineJSValueNotStringtoString(*this, exec);
     387    VM& vm = exec->vm();
     388    if (isInt32())
     389        return vm.numericStrings.add(asInt32());
     390    if (isDouble())
     391        return vm.numericStrings.add(asDouble());
     392    if (isTrue())
     393        return vm.propertyNames->trueKeyword.string();
     394    if (isFalse())
     395        return vm.propertyNames->falseKeyword.string();
     396    if (isNull())
     397        return vm.propertyNames->nullKeyword.string();
     398    if (isUndefined())
     399        return vm.propertyNames->undefinedKeyword.string();
     400    return toString(exec)->value(exec);
    384401}
    385402
Note: See TracChangeset for help on using the changeset viewer.