Backed out changeset fd9745f7a697 (
bug 1073816) for test_bug930091.js xpcshell failures.
CLOSED TREE
--- 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");