Array.slice should have a fast path like Array.splice
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 12 May 2015 21:04:10 +0000 (21:04 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 12 May 2015 21:04:10 +0000 (21:04 +0000)
https://bugs.webkit.org/show_bug.cgi?id=144901

Reviewed by Geoffrey Garen.

Add a fast memcpy path to Array.prototype.slice as done for Array.prototype.splice.
In Kraken, this appears to be 30% win on stanford-crypto-ccm and 10% win on stanford-crypto-pbkdf2.

* runtime/ArrayPrototype.cpp:
(JSC::arrayProtoFuncSlice):
* runtime/JSArray.cpp:
(JSC::JSArray::fastSlice): Added.
* runtime/JSArray.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@184217 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/ArrayPrototype.cpp
Source/JavaScriptCore/runtime/JSArray.cpp
Source/JavaScriptCore/runtime/JSArray.h

index 850a017..471a8fd 100644 (file)
@@ -1,3 +1,19 @@
+2015-05-12  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Array.slice should have a fast path like Array.splice
+        https://bugs.webkit.org/show_bug.cgi?id=144901
+
+        Reviewed by Geoffrey Garen.
+
+        Add a fast memcpy path to Array.prototype.slice as done for Array.prototype.splice.
+        In Kraken, this appears to be 30% win on stanford-crypto-ccm and 10% win on stanford-crypto-pbkdf2.
+
+        * runtime/ArrayPrototype.cpp:
+        (JSC::arrayProtoFuncSlice):
+        * runtime/JSArray.cpp:
+        (JSC::JSArray::fastSlice): Added.
+        * runtime/JSArray.h:
+
 2015-05-11  Filip Pizlo  <fpizlo@apple.com>
 
         OSR availability analysis would be more scalable (and correct) if it did more liveness pruning
index 07be2a9..bc9ec7e 100644 (file)
@@ -601,6 +601,12 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec)
     unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
     unsigned end = argumentClampedIndexFromStartOrEnd(exec, 1, length, length);
 
+    if (isJSArray(thisObj)) {
+        EncodedJSValue result;
+        if (asArray(thisObj)->fastSlice(*exec, begin, end - begin, result))
+            return result;
+    }
+
     JSArray* result = constructEmptyArray(exec, nullptr, end - begin);
 
     unsigned n = 0;
index f0df029..00fde89 100644 (file)
@@ -666,6 +666,40 @@ void JSArray::push(ExecState* exec, JSValue value)
     }
 }
 
+bool JSArray::fastSlice(ExecState& exec, unsigned startIndex, unsigned count, EncodedJSValue& result)
+{
+    auto arrayType = indexingType();
+    switch (arrayType) {
+    case ArrayWithDouble:
+    case ArrayWithInt32:
+    case ArrayWithContiguous: {
+        VM& vm = exec.vm();
+        if (count >= MIN_SPARSE_ARRAY_INDEX || structure(vm)->holesMustForwardToPrototype(vm))
+            return false;
+
+        Structure* resultStructure = exec.lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(arrayType);
+        JSArray* resultArray = JSArray::tryCreateUninitialized(vm, resultStructure, count);
+        if (!resultArray) {
+            result = JSValue::encode(throwOutOfMemoryError(&exec));
+            return true;
+        }
+
+        auto& resultButterfly = *resultArray->butterfly();
+        if (arrayType == ArrayWithDouble)
+            memcpy(resultButterfly.contiguousDouble().data(), m_butterfly->contiguousDouble().data() + startIndex, sizeof(JSValue) * count);
+        else
+            memcpy(resultButterfly.contiguous().data(), m_butterfly->contiguous().data() + startIndex, sizeof(JSValue) * count);
+        resultButterfly.setPublicLength(count);
+
+        result = JSValue::encode(resultArray);
+        return true;
+    }
+    default:
+        break;
+    }
+    return false;
+}
+
 bool JSArray::shiftCountWithArrayStorage(VM& vm, unsigned startIndex, unsigned count, ArrayStorage* storage)
 {
     unsigned oldLength = storage->length();
index ea3431a..d9e13ed 100644 (file)
@@ -73,6 +73,8 @@ public:
     JS_EXPORT_PRIVATE void push(ExecState*, JSValue);
     JS_EXPORT_PRIVATE JSValue pop(ExecState*);
 
+    bool fastSlice(ExecState&, unsigned startIndex, unsigned count, EncodedJSValue&);
+
     enum ShiftCountMode {
         // This form of shift hints that we're doing queueing. With this assumption in hand,
         // we convert to ArrayStorage, which has queue optimizations.