Backed out changeset fd9745f7a697 (bug 1073816) for test_bug930091.js xpcshell failures.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 09 Feb 2015 14:56:10 -0500
changeset 241830 9b6aa9b4039b4f4b3bec47bf8ef90d6f4688ca87
parent 241829 5cfc8f7bd7fabe35d5bb5e997119167dbec72d37
child 241831 b7a61f34185e4128b5155cc3eedfcc7cf6a90f65
push id624
push userdburns@mozilla.com
push dateTue, 10 Feb 2015 13:30:25 +0000
bugs1073816, 930091
milestone38.0a1
backs outfd9745f7a6970fb07d400899d86bec8f417646e4
Backed out changeset fd9745f7a697 (bug 1073816) for test_bug930091.js xpcshell failures. CLOSED TREE
js/src/jsfun.cpp
js/src/jsfun.h
js/src/tests/ecma_6/Function/bound-length-and-name.js
js/src/tests/js1_8_5/extensions/scripted-proxies.js
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -499,20 +499,20 @@ js::fun_resolve(JSContext *cx, HandleObj
         //     assertEq(f.length, 0);  // gets Function.prototype.length!
         //     assertEq(f.name, "");  // gets Function.prototype.name!
         // We use the RESOLVED_LENGTH and RESOLVED_NAME flags as a hack to prevent this
         // bug.
         if (isLength) {
             if (fun->hasResolvedLength())
                 return true;
 
-            uint16_t length;
-            if (!fun->getLength(cx, &length))
+            if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
                 return false;
-
+            uint16_t length = fun->hasScript() ? fun->nonLazyScript()->funLength() :
+                fun->nargs() - fun->hasRest();
             v.setInt32(length);
         } else {
             if (fun->hasResolvedName())
                 return true;
 
             v.setString(fun->atom() == nullptr ? cx->runtime()->emptyString : fun->atom());
         }
 
@@ -1621,130 +1621,83 @@ fun_isGenerator(JSContext *cx, unsigned 
         args.rval().setBoolean(false);
         return true;
     }
 
     args.rval().setBoolean(fun->isGenerator());
     return true;
 }
 
-// ES6 draft rev32 19.2.3.2
+/* ES5 15.3.4.5. */
 bool
 js::fun_bind(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    // Step 1.
+    /* Step 1. */
     RootedValue thisv(cx, args.thisv());
 
-    // Step 2.
+    /* Step 2. */
     if (!IsCallable(thisv)) {
         ReportIncompatibleMethod(cx, args, &JSFunction::class_);
         return false;
     }
 
-    // Step 3.
+    /* Step 3. */
     Value *boundArgs = nullptr;
     unsigned argslen = 0;
     if (args.length() > 1) {
         boundArgs = args.array() + 1;
         argslen = args.length() - 1;
     }
 
-    // Steps 4-14.
+    /* Steps 7-9. */
     RootedValue thisArg(cx, args.length() >= 1 ? args[0] : UndefinedValue());
     RootedObject target(cx, &thisv.toObject());
     JSObject *boundFunction = js_fun_bind(cx, target, thisArg, boundArgs, argslen);
     if (!boundFunction)
         return false;
 
-    // Step 15.
+    /* Step 22. */
     args.rval().setObject(*boundFunction);
     return true;
 }
 
 JSObject*
 js_fun_bind(JSContext *cx, HandleObject target, HandleValue thisArg,
             Value *boundArgs, unsigned argslen)
 {
-    double length = 0.0;
-    // Try to avoid invoking the resolve hook.
-    if (target->is<JSFunction>() && !target->as<JSFunction>().hasResolvedLength()) {
-        uint16_t len;
-        if (!target->as<JSFunction>().getLength(cx, &len))
-            return nullptr;
-        length = Max(0.0, double(len) - argslen);
-    } else {
-        // Steps 5-6.
-        RootedId id(cx, NameToId(cx->names().length));
-        bool hasLength;
-        if (!HasOwnProperty(cx, target, id, &hasLength))
-            return nullptr;
-
-        // Step 7-8.
-        if (hasLength) {
-            // a-b.
-            RootedValue targetLen(cx);
-            if (!GetProperty(cx, target, target, id, &targetLen))
-                return nullptr;
-            // d.
-            if (targetLen.isNumber())
-                length = Max(0.0, JS::ToInteger(targetLen.toNumber()) - argslen);
-        }
+    /* Steps 15-16. */
+    unsigned length = 0;
+    if (target->is<JSFunction>()) {
+        unsigned nargs = target->as<JSFunction>().nargs();
+        if (nargs > argslen)
+            length = nargs - argslen;
     }
 
-    RootedString name(cx, cx->names().empty);
-    if (target->is<JSFunction>() && !target->as<JSFunction>().hasResolvedName()) {
-        if (target->as<JSFunction>().atom())
-            name = target->as<JSFunction>().atom();
-    } else {
-        // Steps 11-12.
-        RootedValue targetName(cx);
-        if (!GetProperty(cx, target, target, cx->names().name, &targetName))
-            return nullptr;
+    /* Step 4-6, 10-11. */
+    RootedAtom name(cx, target->is<JSFunction>() ? target->as<JSFunction>().atom() : nullptr);
 
-        // Step 13.
-        if (targetName.isString())
-            name = targetName.toString();
-    }
-
-    // Step 14. Relevant bits from SetFunctionName.
-    StringBuffer sb(cx);
-    if (!sb.append("bound ") || !sb.append(name))
-        return nullptr;
-
-    RootedAtom nameAtom(cx, sb.finishAtom());
-    if (!nameAtom)
+    JSFunction::Flags flags = target->isConstructor() ? JSFunction::NATIVE_CTOR
+                                                      : JSFunction::NATIVE_FUN;
+    RootedObject funobj(cx, NewFunction(cx, js::NullPtr(), CallOrConstructBoundFunction, length,
+                                        flags, target, name));
+    if (!funobj)
         return nullptr;
 
-    //  Step 4.
-    JSFunction::Flags flags = target->isConstructor() ? JSFunction::NATIVE_CTOR
-                                                      : JSFunction::NATIVE_FUN;
-    RootedFunction fun(cx, NewFunction(cx, js::NullPtr(), CallOrConstructBoundFunction, length,
-                                       flags, target, nameAtom));
-    if (!fun)
+    /* NB: Bound functions abuse |parent| to store their target. */
+    if (!JSObject::setParent(cx, funobj, target))
         return nullptr;
 
-    // NB: Bound functions abuse |parent| to store their target.
-    MOZ_ASSERT(fun->getParent() == target);
-
-    if (!fun->initBoundFunction(cx, thisArg, boundArgs, argslen))
+    if (!funobj->as<JSFunction>().initBoundFunction(cx, thisArg, boundArgs, argslen))
         return nullptr;
 
-    // Steps 9-10. Set length again, because NewFunction sometimes truncates.
-    if (length != fun->nargs()) {
-        RootedValue lengthVal(cx, NumberValue(length));
-        if (!DefineProperty(cx, fun, cx->names().length, lengthVal, nullptr, nullptr,
-                            JSPROP_READONLY))
-        {
-            return nullptr;
-        }
-    }
-
-    return fun;
+    /* Steps 17, 19-21 are handled by fun_resolve. */
+    /* Step 18 is the default for new functions. */
+    return funobj;
 }
 
 /*
  * Report "malformed formal parameter" iff no illegal char or similar scanner
  * error was already reported.
  */
 static bool
 OnBadFormal(JSContext *cx)
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -319,26 +319,16 @@ class JSFunction : public js::NativeObje
     }
 
     JSScript *nonLazyScript() const {
         MOZ_ASSERT(hasScript());
         MOZ_ASSERT(u.i.s.script_);
         return u.i.s.script_;
     }
 
-    bool getLength(JSContext *cx, uint16_t *length) {
-        JS::RootedFunction self(cx, this);
-        if (self->isInterpretedLazy() && !self->getOrCreateScript(cx))
-            return false;
-
-        *length = self->hasScript() ? self->nonLazyScript()->funLength()
-                                    : (self->nargs() - self->hasRest());
-        return true;
-    }
-
     // Returns non-callsited-clone version of this.  Use when return
     // value can flow to arbitrary JS (see Bug 944975).
     JSFunction* originalFunction() {
         if (this->hasScript() && this->nonLazyScript()->isCallsiteClone()) {
             return this->nonLazyScript()->donorFunction();
         } else {
             return this;
         }
deleted file mode 100644
--- a/js/src/tests/ecma_6/Function/bound-length-and-name.js
+++ /dev/null
@@ -1,40 +0,0 @@
-var proxy = new Proxy(function() {}, {
-    getOwnPropertyDescriptor(target, name) {
-        assertEq(name, "length");
-        return {value: 3, configurable: true};
-    },
-
-    get(target, name) {
-        if (name == "length")
-            return 3;
-        if (name == "name")
-            return "hello world";
-        assertEq(false, true);
-    }
-})
-
-var bound = Function.prototype.bind.call(proxy);
-assertEq(bound.name, "bound hello world");
-assertEq(bound.length, 3);
-
-var fun = function() {};
-Object.defineProperty(fun, "name", {value: 1337});
-Object.defineProperty(fun, "length", {value: "15"});
-bound = fun.bind();
-assertEq(bound.name, "bound ");
-assertEq(bound.length, 0);
-
-Object.defineProperty(fun, "length", {value: Number.MAX_SAFE_INTEGER});
-bound = fun.bind();
-assertEq(bound.length, Number.MAX_SAFE_INTEGER);
-
-Object.defineProperty(fun, "length", {value: -100});
-bound = fun.bind();
-assertEq(bound.length, 0);
-
-fun = function f(a, ...b) { };
-assertEq(fun.length, 1);
-bound = fun.bind();
-assertEq(bound.length, 1);
-
-reportCompare(0, 0, 'ok');
--- a/js/src/tests/js1_8_5/extensions/scripted-proxies.js
+++ b/js/src/tests/js1_8_5/extensions/scripted-proxies.js
@@ -26,49 +26,37 @@ function test() {
     testObj(new Array());
     testObj(new RegExp());
     testObj(Date);
     testObj(Array);
     testObj(RegExp);
 
     /* Test function proxies. */
     var proxy = Proxy.createFunction({
-        get: function(obj, name) {
-            return Function.prototype[name];
-        },
-        getOwnPropertyDescriptor: function(obj, name) {
-            return Object.getOwnPropertyDescriptor(Function.prototype, name);
-        },
-        fix: function() {
-            return ({});
-        }
+        get: function(obj,name) { return Function.prototype[name]; },
+	fix: function() {
+	    return ({});
+	}
     }, function() { return "call"; });
 
     assertEq(proxy(), "call");
     assertEq(Function.prototype.bind.call(proxy)(), "call");
     assertEq(typeof proxy, "function");
     if ("isTrapping" in Proxy) {
 	assertEq(Proxy.isTrapping(proxy), true);
 	assertEq(Proxy.fix(proxy), true);
 	assertEq(Proxy.isTrapping(proxy), false);
 	assertEq(typeof proxy, "function");
 	assertEq(proxy(), "call");
     }
 
     /* Test function proxies as constructors. */
     var proxy = Proxy.createFunction({
-        get: function(obj, name) {
-            return Function.prototype[name];
-        },
-        getOwnPropertyDescriptor: function(obj, name) {
-            return Object.getOwnPropertyDescriptor(Function.prototype, name);
-        },
-        fix: function() {
-            return ({});
-        }
+        get: function(obj, name) { return Function.prototype[name]; },
+	fix: function() { return ({}); }
     },
     function() { var x = {}; x.origin = "call"; return x; },
     function() { var x = {}; x.origin = "new"; return x; })
 
     assertEq(proxy().origin, "call");
     assertEq(Function.prototype.bind.call(proxy)().origin, "call");
     assertEq((new proxy()).origin, "new");
     assertEq(new (Function.prototype.bind.call(proxy))().origin, "new");