Bug 842192 - Self-host Array.map. r=jorendorff
authorTill Schneidereit <tschneidereit@gmail.com>
Tue, 19 Feb 2013 21:36:37 +0100
changeset 122645 788c24847525659175fc32933021fd164401b86b
parent 122644 ac6dff6a0811708d1f58af1078c7bae17da5878d
child 122646 b35cf8a9852f441fa950ef3b9f669e3133b7ec44
push id24356
push usergszorc@mozilla.com
push dateSun, 24 Feb 2013 01:00:12 +0000
treeherdermozilla-central@195e706140d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs842192
milestone22.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 842192 - Self-host Array.map. r=jorendorff
js/src/builtin/Array.js
js/src/jsarray.cpp
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -207,16 +207,61 @@ function ArrayForEach(callbackfn/*, this
             callFunction(callbackfn, T, O[k], k, O);
         }
     }
 
     /* Step 8. */
     return void 0;
 }
 
+/* ES5 15.4.4.19. */
+function ArrayMap(callbackfn/*, thisArg*/) {
+    /* Step 1. */
+    var O = ToObject(this);
+
+    /* Step 2-3. */
+    var len = TO_UINT32(O.length);
+
+    /* Step 4. */
+    if (arguments.length === 0)
+        ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.map');
+    if (!IsCallable(callbackfn))
+        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
+
+    /* Step 5. */
+    var T = arguments.length > 1 ? arguments[1] : void 0;
+
+    /* Step 6. */
+    var A = NewDenseArray(len);
+
+    /* Step 7-8. */
+    /* Step a (implicit), and d. */
+    for (var k = 0; k < len; k++) {
+        /* Step b */
+        if (k in O) {
+            /* Step c.i-iii. */
+            var mappedValue = callFunction(callbackfn, T, O[k], k, O);
+            // UnsafeSetElement doesn't invoke setters, so we can use it here.
+            UnsafeSetElement(A, k, mappedValue);
+        }
+    }
+
+    /* Step 9. */
+    return A;
+}
+
+function ArrayStaticMap(list, callbackfn/*, thisArg*/) {
+    if (arguments.length < 2)
+        ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.map');
+    if (!IsCallable(callbackfn))
+        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn));
+    var T = arguments.length > 2 ? arguments[2] : void 0;
+    return callFunction(ArrayMap, list, callbackfn, T);
+}
+
 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(ArrayForEach, list, callbackfn, T);
 }
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -2376,95 +2376,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;
 }
 
-/* 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()));
-    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], args.length() - 1));
-    if (!callable)
-        return false;
-
-    /* Step 5. */
-    RootedValue thisv(cx, args.length() >= 2 ? args[1] : UndefinedValue());
-
-    /* Step 6. */
-    RootedObject arr(cx, NewDenseAllocatedArray(cx, len));
-    if (!arr)
-        return false;
-    TypeObject *newtype = GetTypeCallerInitObject(cx, JSProto_Array);
-    if (!newtype)
-        return false;
-    arr->setType(newtype);
-
-    /* Step 7. */
-    uint32_t k = 0;
-
-    /* Step 8. */
-    RootedValue kValue(cx);
-    JS_ASSERT(!InParallelSection());
-    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;
-            kValue = ag.rval();
-            if (!SetArrayElement(cx, arr, k, kValue))
-                return false;
-        }
-
-        /* Step d. */
-        k++;
-    }
-
-    /* Step 9. */
-    args.rval().setObject(*arr);
-    return true;
-}
-
 /* ES5 15.4.4.20. */
 static JSBool
 array_filter(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
     RootedObject obj(cx, ToObject(cx, args.thisv()));
@@ -2575,32 +2496,33 @@ static JSFunctionSpec array_methods[] = 
 
     /* Pythonic sequence methods. */
     JS_FN("concat",             array_concat,       1,JSFUN_GENERIC_NATIVE),
     JS_FN("slice",              array_slice,        2,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),
+         {"map",                {NULL, NULL},       1,0, "ArrayMap"},
          {"reduce",             {NULL, NULL},       1,0, "ArrayReduce"},
          {"reduceRight",        {NULL, NULL},       1,0, "ArrayReduceRight"},
     JS_FN("filter",             array_filter,       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"},
+         {"map",                {NULL, NULL},       2,0, "ArrayStaticMap"},
          {"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 */