Avoid brittle use of .bind in Promise.all
authorrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 7 Jul 2014 09:47:43 +0000 (09:47 +0000)
committerrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 7 Jul 2014 09:47:43 +0000 (09:47 +0000)
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
test/mjsunit/es6/promises.js

index 4ad7a50..9289cc5 100644 (file)
@@ -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) }
           );
         }
index 6dfe926..faf154e 100644 (file)
 
 // 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 = ""