From 7aff3023aee2d3b4d6974057aabffa00be26c5d2 Mon Sep 17 00:00:00 2001 From: "rossberg@chromium.org" Date: Mon, 7 Jul 2014 09:47:43 +0000 Subject: [PATCH] Avoid brittle use of .bind in Promise.all R=yangguo@chromium.org BUG=v8:3420 LOG=Y Review URL: https://codereview.chromium.org/366103005 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22231 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/promise.js | 14 +++++++++----- test/mjsunit/es6/promises.js | 42 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/promise.js b/src/promise.js index 4ad7a50..9289cc5 100644 --- a/src/promise.js +++ b/src/promise.js @@ -283,11 +283,15 @@ var lastMicrotaskId = 0; } else { for (var i = 0; i < values.length; ++i) { this.resolve(values[i]).then( - function(i, x) { - resolutions[i] = x; - if (--count === 0) deferred.resolve(resolutions); - }.bind(UNDEFINED, i), // TODO(rossberg): use let loop once - // available + (function() { + // Nested scope to get closure over current i (and avoid .bind). + // TODO(rossberg): Use for-let instead once available. + var i_captured = i; + return function(x) { + resolutions[i_captured] = x; + if (--count === 0) deferred.resolve(resolutions); + }; + })(), function(r) { deferred.reject(r) } ); } diff --git a/test/mjsunit/es6/promises.js b/test/mjsunit/es6/promises.js index 6dfe926..faf154e 100644 --- a/test/mjsunit/es6/promises.js +++ b/test/mjsunit/es6/promises.js @@ -27,6 +27,42 @@ // Flags: --allow-natives-syntax +// Make sure we don't rely on functions patchable by monkeys. +var call = Function.prototype.call.call.bind(Function.prototype.call) +var observe = Object.observe; +var getOwnPropertyNames = Object.getOwnPropertyNames +var defineProperty = Object.defineProperty + +function clear(o) { + if (o === null || (typeof o !== 'object' && typeof o !== 'function')) return + clear(o.__proto__) + var properties = getOwnPropertyNames(o) + for (var i in properties) { + clearProp(o, properties[i]) + } +} + +function clearProp(o, name) { + var poisoned = {caller: 0, callee: 0, arguments: 0} + try { + var x = o[name] + o[name] = undefined + clear(x) + } catch(e) {} // assertTrue(name in poisoned) } +} + +// Find intrinsics and null them out. +var globals = Object.getOwnPropertyNames(this) +var whitelist = {Promise: true, TypeError: true} +for (var i in globals) { + var name = globals[i] + if (name in whitelist || name[0] === name[0].toLowerCase()) delete globals[i] +} +for (var i in globals) { + if (globals[i]) clearProp(this, globals[i]) +} + + var asyncAssertsExpected = 0; function assertAsyncRan() { ++asyncAssertsExpected } @@ -43,7 +79,7 @@ function assertAsync(b, s) { function assertAsyncDone(iteration) { var iteration = iteration || 0 var dummy = {} - Object.observe(dummy, + observe(dummy, function() { if (asyncAssertsExpected === 0) assertAsync(true, "all") @@ -777,13 +813,13 @@ function assertAsyncDone(iteration) { MyPromise.__proto__ = Promise MyPromise.defer = function() { log += "d" - return this.__proto__.defer.call(this) + return call(this.__proto__.defer, this) } MyPromise.prototype.__proto__ = Promise.prototype MyPromise.prototype.chain = function(resolve, reject) { log += "c" - return this.__proto__.__proto__.chain.call(this, resolve, reject) + return call(this.__proto__.__proto__.chain, this, resolve, reject) } log = "" -- 2.7.4