Bug 784294 - Convert some array extras to self-hosted js implementations. r=Waldo
authorTill Schneidereit <tschneidereit@gmail.com>
Tue, 28 Aug 2012 14:35:15 +0200
changeset 113955 5593cd83590e87069b4650421c7b3e309529f703
parent 113954 7ae5ff606cf2d57a6b758e88500749beaa425532
child 113958 5a755dd85a35f65062375ec2e05f140e82e2e41d
push id18469
push usertschneidereit@gmail.com
push dateThu, 22 Nov 2012 00:25:59 +0000
treeherdermozilla-inbound@5593cd83590e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs784294
milestone20.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 784294 - Convert some array extras to self-hosted js implementations. r=Waldo The following methods are converted: - lastIndexOf - indexOf - forEach - some - every - reduce - reduceRight
js/src/builtin/array.js
js/src/jsarray.cpp
--- a/js/src/builtin/array.js
+++ b/js/src/builtin/array.js
@@ -1,1 +1,348 @@
-//this space intentionally left blank
\ No newline at end of file
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+ /* ES5 15.4.4.14. */
+function ArrayIndexOf(searchElement/*, fromIndex*/) {
+    /* Step 1. */
+    var O = %ToObject(this);
+
+    /* Steps 2-3. */
+    var len = TO_UINT32(O.length);
+
+    /* Step 4. */
+    if (len === 0)
+        return -1;
+
+    /* Step 5. */
+    var n = arguments.length > 1 ? %ToInteger(arguments[1]) : 0;
+
+    /* Step 6. */
+    if (n >= len)
+        return -1;
+
+    var k;
+    /* Step 7. */
+    if (n >= 0)
+        k = n;
+    /* Step 8. */
+    else {
+        /* Step a. */
+        k = len + n;
+        /* Step b. */
+        if (k < 0)
+            k = 0;
+    }
+
+    /* Step 9. */
+    for (; k < len; k++) {
+        if (k in O && O[k] === searchElement)
+            return k;
+    }
+
+    /* Step 10. */
+    return -1;
+}
+
+function ArrayStaticIndexOf(list, searchElement/*, fromIndex*/) {
+    if (arguments.length < 1)
+        %ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.indexOf');
+    var fromIndex = arguments.length > 2 ? arguments[2] : 0;
+    return %_CallFunction(list, searchElement, fromIndex, ArrayIndexOf);
+}
+
+/* ES5 15.4.4.15. */
+function ArrayLastIndexOf(searchElement/*, fromIndex*/) {
+    /* Step 1. */
+    var O = %ToObject(this);
+
+    /* Steps 2-3. */
+    var len = TO_UINT32(O.length);
+
+    /* Step 4. */
+    if (len === 0)
+        return -1;
+
+    /* Step 5. */
+    var n = arguments.length > 1 ? %ToInteger(arguments[1]) : len - 1;
+
+    /* Steps 6-7. */
+    var k;
+    if (n > len - 1)
+        k = len - 1;
+    else if (n < 0)
+        k = len + n;
+    else
+        k = n;
+
+    /* Step 8. */
+    for (; k >= 0; k--) {
+        if (k in O && O[k] === searchElement)
+            return k;
+    }
+
+    /* Step 9. */
+    return -1;
+}
+
+function ArrayStaticLastIndexOf(list, searchElement/*, fromIndex*/) {
+    if (arguments.length < 1)
+        %ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.lastIndexOf');
+    var fromIndex;
+    if (arguments.length > 2) {
+        fromIndex = arguments[2];
+    } else {
+        var O = %ToObject(list);
+        var len = TO_UINT32(O.length);
+        fromIndex = len - 1;
+    }
+    return %_CallFunction(list, searchElement, fromIndex, ArrayLastIndexOf);
+}
+
+/* ES5 15.4.4.16. */
+function ArrayEvery(callbackfn/*, thisArg*/) {
+    /* Step 1. */
+    var O = %ToObject(this);
+
+    /* Steps 2-3. */
+    var len = TO_UINT32(O.length);
+
+    /* Step 4. */
+    if (arguments.length === 0)
+        %ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.every');
+    if (!IsCallable(callbackfn))
+        %ThrowError(JSMSG_NOT_FUNCTION, %_DecompileArg(0, callbackfn));
+
+    /* Step 5. */
+    var T = arguments.length > 1 ? arguments[1] : void 0;
+
+    /* Steps 6-7. */
+    /* Steps a (implicit), and d. */
+    for (var k = 0; k < len; k++) {
+        /* Step b */
+        if (k in O) {
+            /* Step c. */
+            if (!%_CallFunction(T, O[k], k, O, callbackfn))
+                return false;
+        }
+    }
+
+    /* Step 8. */
+    return true;
+}
+
+function ArrayStaticEvery(list, callbackfn/*, thisArg*/) {
+    if (arguments.length < 2)
+        %ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.every');
+    if (!IsCallable(callbackfn))
+        %ThrowError(JSMSG_NOT_FUNCTION, %_DecompileArg(1, callbackfn));
+    var T = arguments.length > 2 ? arguments[2] : void 0;
+    return %_CallFunction(list, callbackfn, T, ArrayEvery);
+}
+
+/* ES5 15.4.4.17. */
+function ArraySome(callbackfn/*, thisArg*/) {
+    /* Step 1. */
+    var O = %ToObject(this);
+
+    /* Steps 2-3. */
+    var len = TO_UINT32(O.length);
+
+    /* Step 4. */
+    if (arguments.length === 0)
+        %ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.some');
+    if (!IsCallable(callbackfn))
+        %ThrowError(JSMSG_NOT_FUNCTION, %_DecompileArg(0, callbackfn));
+
+    /* Step 5. */
+    var T = arguments.length > 1 ? arguments[1] : void 0;
+
+    /* Steps 6-7. */
+    /* Steps a (implicit), and d. */
+    for (var k = 0; k < len; k++) {
+        /* Step b */
+        if (k in O) {
+            /* Step c. */
+            if (%_CallFunction(T, O[k], k, O, callbackfn))
+                return true;
+        }
+    }
+
+    /* Step 8. */
+    return false;
+}
+
+function ArrayStaticSome(list, callbackfn/*, thisArg*/) {
+    if (arguments.length < 2)
+        %ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.some');
+    if (!IsCallable(callbackfn))
+        %ThrowError(JSMSG_NOT_FUNCTION, %_DecompileArg(1, callbackfn));
+    var T = arguments.length > 2 ? arguments[2] : void 0;
+    return %_CallFunction(list, callbackfn, T, ArraySome);
+}
+
+/* ES5 15.4.4.18. */
+function ArrayForEach(callbackfn/*, thisArg*/) {
+    /* Step 1. */
+    var O = %ToObject(this);
+
+    /* Steps 2-3. */
+    var len = TO_UINT32(O.length);
+
+    /* Step 4. */
+    if (arguments.length === 0)
+        %ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.forEach');
+    if (!IsCallable(callbackfn))
+        %ThrowError(JSMSG_NOT_FUNCTION, %_DecompileArg(0, callbackfn));
+
+    /* Step 5. */
+    var T = arguments.length > 1 ? arguments[1] : void 0;
+
+    /* Steps 6-7. */
+    /* Steps a (implicit), and d. */
+    for (var k = 0; k < len; k++) {
+        /* Step b */
+        if (k in O) {
+            /* Step c. */
+            %_CallFunction(T, O[k], k, O, callbackfn);
+        }
+    }
+
+    /* Step 8. */
+    return void 0;
+}
+
+function ArrayStaticForEach(list, callbackfn/*, thisArg*/) {
+    if (arguments.length < 2)
+        %ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.forEach');
+    if (!IsCallable(callbackfn))
+        %ThrowError(JSMSG_NOT_FUNCTION, %_DecompileArg(1, callbackfn));
+    var T = arguments.length > 2 ? arguments[2] : void 0;
+    %_CallFunction(list, callbackfn, T, ArrayForEach);
+}
+
+/* ES5 15.4.4.21. */
+function ArrayReduce(callbackfn/*, initialValue*/) {
+    /* Step 1. */
+    var O = %ToObject(this);
+
+    /* Steps 2-3. */
+    var len = TO_UINT32(O.length);
+
+    /* Step 4. */
+    if (arguments.length === 0)
+        %ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.reduce');
+    if (!IsCallable(callbackfn))
+        %ThrowError(JSMSG_NOT_FUNCTION, %_DecompileArg(0, callbackfn));
+
+    /* Step 6. */
+    var k = 0;
+
+    /* Steps 5, 7-8. */
+    var accumulator;
+    if (arguments.length > 1) {
+        accumulator = arguments[1];
+    } else {
+        /* Step 5. */
+        if (len === 0)
+            %ThrowError(JSMSG_EMPTY_ARRAY_REDUCE);
+        var kPresent = false;
+        for (; k < len; k++) {
+            if (k in O) {
+                accumulator = O[k];
+                kPresent = true;
+                k++;
+                break;
+            }
+        }
+        if (!kPresent)
+            %ThrowError(JSMSG_EMPTY_ARRAY_REDUCE);
+    }
+
+    /* Step 9. */
+    /* Steps a (implicit), and d. */
+    for (; k < len; k++) {
+        /* Step b */
+        if (k in O) {
+            /* Step c. */
+            accumulator = callbackfn(accumulator, O[k], k, O);
+        }
+    }
+
+    /* Step 10. */
+    return accumulator;
+}
+
+function ArrayStaticReduce(list, callbackfn) {
+    if (arguments.length < 2)
+        %ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.reduce');
+    if (!IsCallable(callbackfn))
+        %ThrowError(JSMSG_NOT_FUNCTION, %_DecompileArg(1, callbackfn));
+    if (arguments.length > 2)
+        return %_CallFunction(list, callbackfn, arguments[2], ArrayReduce);
+    else
+        return %_CallFunction(list, callbackfn, ArrayReduce);
+}
+
+/* ES5 15.4.4.22. */
+function ArrayReduceRight(callbackfn/*, initialValue*/) {
+    /* Step 1. */
+    var O = %ToObject(this);
+
+    /* Steps 2-3. */
+    var len = TO_UINT32(O.length);
+
+    /* Step 4. */
+    if (arguments.length === 0)
+        %ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.reduce');
+    if (!IsCallable(callbackfn))
+        %ThrowError(JSMSG_NOT_FUNCTION, %_DecompileArg(0, callbackfn));
+
+    /* Step 6. */
+    var k = len - 1;
+
+    /* Steps 5, 7-8. */
+    var accumulator;
+    if (arguments.length > 1) {
+        accumulator = arguments[1];
+    } else {
+        /* Step 5. */
+        if (len === 0)
+            %ThrowError(JSMSG_EMPTY_ARRAY_REDUCE);
+        var kPresent = false;
+        for (; k >= 0; k--) {
+            if (k in O) {
+                accumulator = O[k];
+                kPresent = true;
+                k--;
+                break;
+            }
+        }
+        if (!kPresent)
+            %ThrowError(JSMSG_EMPTY_ARRAY_REDUCE);
+    }
+
+    /* Step 9. */
+    /* Steps a (implicit), and d. */
+    for (; k >= 0; k--) {
+        /* Step b */
+        if (k in O) {
+            /* Step c. */
+            accumulator = callbackfn(accumulator, O[k], k, O);
+        }
+    }
+
+    /* Step 10. */
+    return accumulator;
+}
+
+function ArrayStaticReduceRight(list, callbackfn) {
+    if (arguments.length < 2)
+        %ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.reduceRight');
+    if (!IsCallable(callbackfn))
+        %ThrowError(JSMSG_NOT_FUNCTION, %_DecompileArg(1, callbackfn));
+    if (arguments.length > 2)
+        return %_CallFunction(list, callbackfn, arguments[2], ArrayReduceRight);
+    else
+        return %_CallFunction(list, callbackfn, ArrayReduceRight);
+}
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -2933,238 +2933,16 @@ array_slice(JSContext *cx, unsigned argc
         if (!hole && !SetArrayElement(cx, nobj, slot - begin, value))
             return JS_FALSE;
     }
 
     args.rval().setObject(*nobj);
     return JS_TRUE;
 }
 
-enum IndexOfKind {
-    IndexOf,
-    LastIndexOf
-};
-
-static JSBool
-array_indexOfHelper(JSContext *cx, IndexOfKind mode, CallArgs &args)
-{
-    uint32_t length, i, stop;
-    int direction;
-    JSBool hole;
-
-    RootedValue tosearch(cx), elt(cx);
-
-    RootedObject obj(cx, ToObject(cx, args.thisv()));
-    if (!obj)
-        return false;
-    if (!GetLengthProperty(cx, obj, &length))
-        return JS_FALSE;
-    if (length == 0)
-        goto not_found;
-
-    if (args.length() <= 1) {
-        i = (mode == LastIndexOf) ? length - 1 : 0;
-        tosearch = (args.length() != 0) ? args[0] : UndefinedValue();
-    } else {
-        double start;
-
-        tosearch = args[0];
-        if (!ToInteger(cx, args[1], &start))
-            return false;
-        if (start < 0) {
-            start += length;
-            if (start < 0) {
-                if (mode == LastIndexOf)
-                    goto not_found;
-                i = 0;
-            } else {
-                i = (uint32_t)start;
-            }
-        } else if (start >= length) {
-            if (mode == IndexOf)
-                goto not_found;
-            i = length - 1;
-        } else {
-            i = (uint32_t)start;
-        }
-    }
-
-    if (mode == LastIndexOf) {
-        stop = 0;
-        direction = -1;
-    } else {
-        stop = length - 1;
-        direction = 1;
-    }
-
-    for (;;) {
-        if (!JS_CHECK_OPERATION_LIMIT(cx) ||
-            !GetElement(cx, obj, (uint32_t)i, &hole, &elt)) {
-            return JS_FALSE;
-        }
-        if (!hole) {
-            bool equal;
-            if (!StrictlyEqual(cx, elt, tosearch, &equal))
-                return false;
-            if (equal) {
-                args.rval().setNumber(i);
-                return true;
-            }
-        }
-        if (i == stop)
-            goto not_found;
-        i += direction;
-    }
-
-  not_found:
-    args.rval().setInt32(-1);
-    return JS_TRUE;
-}
-
-static JSBool
-array_indexOf(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return array_indexOfHelper(cx, IndexOf, args);
-}
-
-static JSBool
-array_lastIndexOf(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return array_indexOfHelper(cx, LastIndexOf, args);
-}
-
-/* ECMA 15.4.4.16-15.4.4.18. */
-class ArrayForEachBehavior
-{
-  public:
-    static bool shouldExit(MutableHandleValue callbackRval, MutableHandleValue rval) { return false; }
-    static Value lateExitValue() { return UndefinedValue(); }
-};
-
-class ArrayEveryBehavior
-{
-  public:
-    static bool shouldExit(MutableHandleValue callbackRval, MutableHandleValue rval)
-    {
-        if (!ToBoolean(callbackRval)) {
-            rval.setBoolean(false);
-            return true;
-        }
-        return false;
-    }
-    static Value lateExitValue() { return BooleanValue(true); }
-};
-
-class ArraySomeBehavior
-{
-  public:
-    static bool shouldExit(MutableHandleValue callbackRval, MutableHandleValue rval)
-    {
-        if (ToBoolean(callbackRval)) {
-            rval.setBoolean(true);
-            return true;
-        }
-        return false;
-    }
-    static Value lateExitValue() { return BooleanValue(false); }
-};
-
-template <class Behavior>
-static inline bool
-array_readonlyCommon(JSContext *cx, CallArgs &args)
-{
-    /* Step 1. */
-    RootedObject obj(cx, ToObject(cx, args.thisv()));
-    if (!obj)
-        return false;
-
-    /* Step 2-3. */
-    uint32_t len;
-    if (!GetLengthProperty(cx, obj, &len))
-        return false;
-
-    /* Step 4. */
-    if (args.length() == 0) {
-        js_ReportMissingArg(cx, args.calleev(), 0);
-        return false;
-    }
-    RootedObject callable(cx, ValueToCallable(cx, &args[0]));
-    if (!callable)
-        return false;
-
-    /* Step 5. */
-    RootedValue thisv(cx, args.length() >= 2 ? args[1] : UndefinedValue());
-
-    /* Step 6. */
-    uint32_t k = 0;
-
-    /* Step 7. */
-    RootedValue kValue(cx);
-    FastInvokeGuard fig(cx, ObjectValue(*callable));
-    InvokeArgsGuard &ag = fig.args();
-    while (k < len) {
-        if (!JS_CHECK_OPERATION_LIMIT(cx))
-            return false;
-
-        /* Step a, b, and c.i. */
-        JSBool kNotPresent;
-        if (!GetElement(cx, obj, k, &kNotPresent, &kValue))
-            return false;
-
-        /* Step c.ii-iii. */
-        if (!kNotPresent) {
-            if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 3, &ag))
-                return false;
-            ag.setCallee(ObjectValue(*callable));
-            ag.setThis(thisv);
-            ag[0] = kValue;
-            ag[1] = NumberValue(k);
-            ag[2] = ObjectValue(*obj);
-            if (!fig.invoke(cx))
-                return false;
-
-            if (Behavior::shouldExit(ag.rval(), args.rval()))
-                return true;
-        }
-
-        /* Step d. */
-        k++;
-    }
-
-    /* Step 8. */
-    args.rval().set(Behavior::lateExitValue());
-    return true;
- }
-
-/* ES5 15.4.4.16. */
-static JSBool
-array_every(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return array_readonlyCommon<ArrayEveryBehavior>(cx, args);
-}
-
-/* ES5 15.4.4.17. */
-static JSBool
-array_some(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return array_readonlyCommon<ArraySomeBehavior>(cx, args);
-}
-
-/* ES5 15.4.4.18. */
-static JSBool
-array_forEach(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return array_readonlyCommon<ArrayForEachBehavior>(cx, args);
-}
-
 /* ES5 15.4.4.19. */
 static JSBool
 array_map(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
     RootedObject obj(cx, ToObject(cx, args.thisv()));
@@ -3317,147 +3095,16 @@ array_filter(JSContext *cx, unsigned arg
         k++;
     }
 
     /* Step 10. */
     args.rval().setObject(*arr);
     return true;
 }
 
-/* ES5 15.4.4.21-15.4.4.22. */
-class ArrayReduceBehavior
-{
-  public:
-    static void initialize(uint32_t len, uint32_t *start, uint32_t *end, int32_t *step)
-    {
-        *start = 0;
-        *step = 1;
-        *end = len;
-    }
-};
-
-class ArrayReduceRightBehavior
-{
-  public:
-    static void initialize(uint32_t len, uint32_t *start, uint32_t *end, int32_t *step)
-    {
-        *start = len - 1;
-        *step = -1;
-        /*
-         * We rely on (well defined) unsigned integer underflow to check our
-         * end condition after visiting the full range (including 0).
-         */
-        *end = UINT32_MAX;
-    }
-};
-
-template<class Behavior>
-static inline bool
-array_reduceCommon(JSContext *cx, CallArgs &args)
-{
-    /* Step 1. */
-    RootedObject obj(cx, ToObject(cx, args.thisv()));
-    if (!obj)
-        return false;
-
-    /* Step 2-3. */
-    uint32_t len;
-    if (!GetLengthProperty(cx, obj, &len))
-        return false;
-
-    /* Step 4. */
-    if (args.length() == 0) {
-        js_ReportMissingArg(cx, args.calleev(), 0);
-        return false;
-    }
-    RootedObject callable(cx, ValueToCallable(cx, &args[0]));
-    if (!callable)
-        return false;
-
-    /* Step 5. */
-    if (len == 0 && args.length() < 2) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_EMPTY_ARRAY_REDUCE);
-        return false;
-    }
-
-    /* Step 6. */
-    uint32_t k, end;
-    int32_t step;
-    Behavior::initialize(len, &k, &end, &step);
-
-    /* Step 7-8. */
-    RootedValue accumulator(cx);
-    if (args.length() >= 2) {
-        accumulator = args[1];
-    } else {
-        JSBool kNotPresent = true;
-        while (kNotPresent && k != end) {
-            if (!GetElement(cx, obj, k, &kNotPresent, &accumulator))
-                return false;
-            k += step;
-        }
-        if (kNotPresent) {
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_EMPTY_ARRAY_REDUCE);
-            return false;
-        }
-    }
-
-    /* Step 9. */
-    RootedValue kValue(cx);
-    FastInvokeGuard fig(cx, ObjectValue(*callable));
-    InvokeArgsGuard &ag = fig.args();
-    while (k != end) {
-        if (!JS_CHECK_OPERATION_LIMIT(cx))
-            return false;
-
-        /* Step a, b, and c.i. */
-        JSBool kNotPresent;
-        if (!GetElement(cx, obj, k, &kNotPresent, &kValue))
-            return false;
-
-        /* Step c.ii. */
-        if (!kNotPresent) {
-            if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 4, &ag))
-                return false;
-            ag.setCallee(ObjectValue(*callable));
-            ag.setThis(UndefinedValue());
-            ag[0] = accumulator;
-            ag[1] = kValue;
-            ag[2] = NumberValue(k);
-            ag[3] = ObjectValue(*obj);
-            if (!fig.invoke(cx))
-                return false;
-            accumulator = ag.rval();
-        }
-
-        /* Step d. */
-        k += step;
-    }
-
-    /* Step 10. */
-    args.rval().set(accumulator);
-    return true;
-}
-
-/* ES5 15.4.4.21. */
-static JSBool
-array_reduce(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return array_reduceCommon<ArrayReduceBehavior>(cx, args);
-}
-
-/* ES5 15.4.4.22. */
-static JSBool
-array_reduceRight(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return array_reduceCommon<ArrayReduceRightBehavior>(cx, args);
-}
-
 static JSBool
 array_isArray(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     bool isArray = args.length() > 0 && IsObjectWithClass(args[0], ESClass_Array, cx);
     args.rval().setBoolean(isArray);
     return true;
 }
@@ -3480,32 +3127,39 @@ static JSFunctionSpec array_methods[] = 
     JS_FN("shift",              array_shift,        0,JSFUN_GENERIC_NATIVE),
     JS_FN("unshift",            array_unshift,      1,JSFUN_GENERIC_NATIVE),
     JS_FN("splice",             array_splice,       2,JSFUN_GENERIC_NATIVE),
 
     /* Pythonic sequence methods. */
     JS_FN("concat",             array_concat,       1,JSFUN_GENERIC_NATIVE),
     JS_FN("slice",              array_slice,        2,JSFUN_GENERIC_NATIVE),
 
-    JS_FN("indexOf",            array_indexOf,      1,JSFUN_GENERIC_NATIVE),
-    JS_FN("lastIndexOf",        array_lastIndexOf,  1,JSFUN_GENERIC_NATIVE),
-    JS_FN("forEach",            array_forEach,      1,JSFUN_GENERIC_NATIVE),
+         {"lastIndexOf",        {NULL, NULL},       1,0, "ArrayLastIndexOf"},
+         {"indexOf",            {NULL, NULL},       1,0, "ArrayIndexOf"},
+         {"forEach",            {NULL, NULL},       1,0, "ArrayForEach"},
     JS_FN("map",                array_map,          1,JSFUN_GENERIC_NATIVE),
-    JS_FN("reduce",             array_reduce,       1,JSFUN_GENERIC_NATIVE),
-    JS_FN("reduceRight",        array_reduceRight,  1,JSFUN_GENERIC_NATIVE),
+         {"reduce",             {NULL, NULL},       1,0, "ArrayReduce"},
+         {"reduceRight",        {NULL, NULL},       1,0, "ArrayReduceRight"},
     JS_FN("filter",             array_filter,       1,JSFUN_GENERIC_NATIVE),
-    JS_FN("some",               array_some,         1,JSFUN_GENERIC_NATIVE),
-    JS_FN("every",              array_every,        1,JSFUN_GENERIC_NATIVE),
+         {"some",               {NULL, NULL},       1,0, "ArraySome"},
+         {"every",              {NULL, NULL},       1,0, "ArrayEvery"},
 
     JS_FN("iterator",           JS_ArrayIterator,   0,0),
     JS_FS_END
 };
 
 static JSFunctionSpec array_static_methods[] = {
     JS_FN("isArray",            array_isArray,      1,0),
+         {"lastIndexOf",        {NULL, NULL},       2,0, "ArrayStaticLastIndexOf"},
+         {"indexOf",            {NULL, NULL},       2,0, "ArrayStaticIndexOf"},
+         {"forEach",            {NULL, NULL},       2,0, "ArrayStaticForEach"},
+         {"every",              {NULL, NULL},       2,0, "ArrayStaticEvery"},
+         {"some",               {NULL, NULL},       2,0, "ArrayStaticSome"},
+         {"reduce",             {NULL, NULL},       2,0, "ArrayStaticReduce"},
+         {"reduceRight",        {NULL, NULL},       2,0, "ArrayStaticReduceRight"},
     JS_FS_END
 };
 
 /* ES5 15.4.2 */
 JSBool
 js_Array(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);