Bug 1398780 - Part 1: Add a fast path when Array.prototype.slice is called with an arguments object. r=till
authorAndré Bargull <andre.bargull@gmail.com>
Tue, 17 Oct 2017 22:57:40 +0100
changeset 387012 f87472bf4efa9b34ec871a0858483b65ae19ac29
parent 387011 8503e0f7970e6eeb0c419bcb2e3aa0e9b645dd5c
child 387013 9a67d1a285ce8352bc2e722fac7e09a688c6ddb5
push id32705
push userryanvm@gmail.com
push dateThu, 19 Oct 2017 01:01:49 +0000
treeherdermozilla-central@a21099ce055f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs1398780
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1398780 - Part 1: Add a fast path when Array.prototype.slice is called with an arguments object. r=till
js/src/jsarray.cpp
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3155,16 +3155,38 @@ SliceSparse(JSContext* cx, HandleObject 
 
         if (!hole && !DefineDataElement(cx, result, index - uint32_t(begin), value))
             return false;
     }
 
     return true;
 }
 
+static JSObject*
+SliceArguments(JSContext* cx, Handle<ArgumentsObject*> argsobj, uint32_t begin, uint32_t count)
+{
+    MOZ_ASSERT(!argsobj->hasOverriddenLength() && !argsobj->isAnyElementDeleted());
+    MOZ_ASSERT(begin + count <= argsobj->initialLength());
+
+    ArrayObject* result = NewDenseFullyAllocatedArray(cx, count);
+    if (!result)
+        return nullptr;
+    result->setDenseInitializedLength(count);
+
+    MOZ_ASSERT(result->group()->unknownProperties(),
+               "The default array group has unknown properties, so we can directly initialize the"
+               "dense elements without needing to update the indexed type set.");
+
+    for (uint32_t index = 0; index < count; index++) {
+        const Value& v = argsobj->element(begin + index);
+        result->initDenseElement(index, v);
+    }
+    return result;
+}
+
 template <typename T, typename ArrayLength>
 static inline ArrayLength
 NormalizeSliceTerm(T value, ArrayLength length)
 {
     if (value < 0) {
         value += length;
         if (value < 0)
             return 0;
@@ -3193,16 +3215,29 @@ ArraySliceOrdinary(JSContext* cx, Handle
                                                 count);
         if (!narr)
             return false;
 
         rval.setObject(*narr);
         return true;
     }
 
+    if (obj->is<ArgumentsObject>()) {
+        Handle<ArgumentsObject*> argsobj = obj.as<ArgumentsObject>();
+        if (!argsobj->hasOverriddenLength() && !argsobj->isAnyElementDeleted()) {
+            MOZ_ASSERT(begin <= UINT32_MAX, "begin is limited by |argsobj|'s length");
+            JSObject* narr = SliceArguments(cx, argsobj, uint32_t(begin), count);
+            if (!narr)
+                return false;
+
+            rval.setObject(*narr);
+            return true;
+        }
+    }
+
     RootedArrayObject narr(cx, NewPartlyAllocatedArrayTryReuseGroup(cx, obj, count));
     if (!narr)
         return false;
 
     if (end <= UINT32_MAX) {
         if (js::GetElementsOp op = obj->getOpsGetElements()) {
             ElementAdder adder(cx, narr, count, ElementAdder::CheckHasElemPreserveHoles);
             if (!op(cx, obj, uint32_t(begin), uint32_t(end), &adder))