[es6] Function bind should preserve [[Prototype]]
authorarv <arv@chromium.org>
Thu, 9 Jul 2015 15:48:50 +0000 (08:48 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 9 Jul 2015 15:49:07 +0000 (15:49 +0000)
The function returned from Function.prototype.bind should have the same
[[Prototype]] as the receiver.

BUG=v8:3889
LOG=N
R=adamk@chromium.org, verwaest@chromium.org
CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:linux_chromium_rel_ng;tryserver.blink:linux_blink_rel

Review URL: https://codereview.chromium.org/1217603005

Cr-Commit-Position: refs/heads/master@{#29556}

src/runtime/runtime-function.cc
test/mjsunit/function-bind.js

index 749e16b..3903c04 100644 (file)
@@ -443,9 +443,18 @@ RUNTIME_FUNCTION(Runtime_FunctionBindArguments) {
   // Update length. Have to remove the prototype first so that map migration
   // is happy about the number of fields.
   RUNTIME_ASSERT(bound_function->RemovePrototype());
+
+  // The new function should have the same [[Prototype]] as the bindee.
   Handle<Map> bound_function_map(
       isolate->native_context()->bound_function_map());
+  PrototypeIterator iter(isolate, bindee);
+  Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
+  if (bound_function_map->prototype() != *proto) {
+    bound_function_map = Map::TransitionToPrototype(bound_function_map, proto,
+                                                    REGULAR_PROTOTYPE);
+  }
   JSObject::MigrateToMap(bound_function, bound_function_map);
+
   Handle<String> length_string = isolate->factory()->length_string();
   // These attributes must be kept in sync with how the bootstrapper
   // configures the bound_function_map retrieved above.
index 23dacf1..ca1ed7e 100644 (file)
@@ -25,6 +25,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+// Flags: --allow-natives-syntax
+
 // Tests the Function.prototype.bind (ES 15.3.4.5) method.
 
 // Simple tests.
@@ -298,3 +300,20 @@ assertThrows(function() { f.arguments = 42; }, TypeError);
 // the caller is strict and the callee isn't. A bound function is built-in,
 // but not considered strict.
 (function foo() { return foo.caller; }).bind()();
+
+
+(function TestProtoIsPreserved() {
+  function fun() {}
+
+  function proto() {}
+  Object.setPrototypeOf(fun, proto);
+  var bound = fun.bind({});
+  assertEquals(proto, Object.getPrototypeOf(bound));
+
+  var bound2 = fun.bind({});
+  assertTrue(%HaveSameMap(new bound, new bound2));
+
+  Object.setPrototypeOf(fun, null);
+  bound = Function.prototype.bind.call(fun, {});
+  assertEquals(null, Object.getPrototypeOf(bound));
+})();