Skip to content
Permalink
Browse files
[JSC] Accelerate DirectArguments slice
https://bugs.webkit.org/show_bug.cgi?id=247040
rdar://101570036

Reviewed by Alexey Shvayka.

This patch adds fast Array#slice operation onto DirectArguments since this can be seen in some applications including
Speedometer2.1/Ember-Debug-TodoMVC and JetStream2/coffeescript-wtb. This improves performance by 3.5x.

                                       ToT                     Patched

    direct-arguments-slice       15.8485+-0.1058     ^      4.5368+-0.2171        ^ definitely 3.4933x faster

* JSTests/microbenchmarks/direct-arguments-slice.js: Added.
(test):
* Source/JavaScriptCore/runtime/DirectArguments.cpp:
(JSC::DirectArguments::fastSlice):
* Source/JavaScriptCore/runtime/DirectArguments.h:
* Source/JavaScriptCore/runtime/JSArray.cpp:
(JSC::JSArray::fastSlice):

Canonical link: https://commits.webkit.org/256027@main
  • Loading branch information
Constellation committed Oct 26, 2022
1 parent 5c76515 commit df06fbb5f652bdb89e2f2bda187c44b83f4e3d7d
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 1 deletion.
@@ -0,0 +1,10 @@
var slice = Array.prototype.slice;
function test(a, b, c, d, e, f, g, h, i, j, k, l)
{
return slice.call(arguments);
}
noInline(test);

for (var i = 0; i < 1e5; ++i) {
test(1, "hello", null, undefined, 42, Array, Symbol.iterator, false, 42.195, 0, -200, -44.2);
}
@@ -190,5 +190,32 @@ bool DirectArguments::isIteratorProtocolFastAndNonObservable()
return true;
}

JSArray* DirectArguments::fastSlice(JSGlobalObject* globalObject, DirectArguments* arguments, uint64_t startIndex, uint64_t count)
{
if (count >= MIN_SPARSE_ARRAY_INDEX)
return nullptr;

if (UNLIKELY(arguments->m_mappedArguments))
return nullptr;

if (startIndex + count > arguments->m_length)
return nullptr;

Structure* resultStructure = globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous);
if (UNLIKELY(hasAnyArrayStorage(resultStructure->indexingType())))
return nullptr;

ObjectInitializationScope scope(globalObject->vm());
JSArray* resultArray = JSArray::tryCreateUninitializedRestricted(scope, resultStructure, static_cast<uint32_t>(count));
if (UNLIKELY(!resultArray))
return nullptr;

auto& resultButterfly = *resultArray->butterfly();
gcSafeMemcpy(resultButterfly.contiguous().data(), arguments->storage() + startIndex, sizeof(JSValue) * static_cast<uint32_t>(count));

ASSERT(resultButterfly.publicLength() == count);
return resultArray;
}

} // namespace JSC

@@ -146,6 +146,8 @@ class DirectArguments final : public GenericArguments<DirectArguments> {

void copyToArguments(JSGlobalObject*, JSValue* firstElementDest, unsigned offset, unsigned length);

static JSArray* fastSlice(JSGlobalObject*, DirectArguments*, uint64_t startIndex, uint64_t count);

JS_EXPORT_PRIVATE bool isIteratorProtocolFastAndNonObservable();

DECLARE_INFO;
@@ -731,8 +731,16 @@ JSArray* JSArray::fastSlice(JSGlobalObject* globalObject, JSObject* source, uint
VM& vm = globalObject->vm();

Structure* sourceStructure = source->structure();
if (sourceStructure->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero())
if (sourceStructure->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) {
// We do not need to have ClonedArgumentsType here since it does not have interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero.
switch (source->type()) {
case DirectArgumentsType:
return DirectArguments::fastSlice(globalObject, jsCast<DirectArguments*>(source), startIndex, count);
default:
return nullptr;
}
return nullptr;
}

auto arrayType = source->indexingType() | IsArray;
switch (arrayType) {

0 comments on commit df06fbb

Please sign in to comment.