Commit 1f3f8f3e authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[turbofan] Optimize Object constructor subclassing.

Add support to the JSCallReducer to recognize JSConstruct nodes where
the target is the Object constructor, and reduce them to JSCreate
nodes if either

 (a) no value is passed to the Object constructor, or
 (b) the target and new.target are definitely not identical, by checking
     whether both target and new.target are different HeapConstants
     (if they are not, then the JSCreateLowering will not be able to
     do a lot with the JSCreate anyways).

This should cover the relevant cases for subclassing appropriately. It
fixes the 3-4x slowdown on the micro-benchmark mentioned in the linked
bug,

  baseNoExtends: 752 ms.
  baseExtendsObject: 752 ms.
  baseExtendsViaFactory: 751 ms.

and thus removes the performance cliff.

R=jarin@chromium.org

Bug: v8:6801
Change-Id: Id265fd1399302a67b5790a6d0156679920c58bdd
Reviewed-on: https://chromium-review.googlesource.com/657019Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47913}
parent 836d5302
......@@ -1593,6 +1593,27 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
return Changed(node);
}
// Check for the ObjectConstructor.
if (*function == function->native_context()->object_function()) {
// If no value is passed, we can immediately lower to a simple
// JSCreate and don't need to do any massaging of the {node}.
if (arity == 0) {
NodeProperties::ChangeOp(node, javascript()->Create());
return Changed(node);
}
// Otherwise we can only lower to JSCreate if we know that
// the value parameter is ignored, which is only the case if
// the {new_target} and {target} are definitely not identical.
HeapObjectMatcher mnew_target(new_target);
if (mnew_target.HasValue() && *mnew_target.Value() != *function) {
// Drop the value inputs.
for (int i = arity; i > 0; --i) node->RemoveInput(i);
NodeProperties::ChangeOp(node, javascript()->Create());
return Changed(node);
}
}
}
// TODO(bmeurer): Also support optimizing bound functions and proxies here.
......
......@@ -30,3 +30,22 @@
%OptimizeFunctionOnNextCall(foo);
assertEquals('object', typeof foo());
})();
// Object constructor subclassing via Class Factories, see
// https://twitter.com/FremyCompany/status/905977048006402048
// for the hint.
(function ObjectConstructorSubClassing() {
"use strict";
const Factory = Base => class A extends Base {};
const A = Factory(Object);
function foo() {
return new A(1, 2, 3);
}
assertInstanceof(foo(), A);
assertInstanceof(foo(), Object);
assertInstanceof(foo(), A);
assertInstanceof(foo(), Object);
%OptimizeFunctionOnNextCall(foo);
assertInstanceof(foo(), A);
assertInstanceof(foo(), Object);
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment