Commit 359b5f93 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Also constant-fold Object.getPrototypeOf if possible.

We already have an optimization to constant-fold access to an object's
prototype via the special __proto__ accessor (specified in appendix B).
We can use the same optimization to also constant-fold accesses to an
object's prototype via the official Object.getPrototypeOf function.

Also add the optimization for Reflect.getPrototypeOf, which is
equivalent for object inputs.

This is commonly used by Babel to implement various new language
features, for example subclassing and certain property lookups.

R=yangguo@chromium.org
BUG=v8:6292

Review-Url: https://codereview.chromium.org/2841463002
Cr-Commit-Position: refs/heads/master@{#44788}
parent e72ee1d3
...@@ -327,39 +327,41 @@ JSCallReducer::HolderLookup JSCallReducer::LookupHolder( ...@@ -327,39 +327,41 @@ JSCallReducer::HolderLookup JSCallReducer::LookupHolder(
return kHolderNotFound; return kHolderNotFound;
} }
// ES6 section B.2.2.1.1 get Object.prototype.__proto__ Reduction JSCallReducer::ReduceObjectGetPrototype(Node* node, Node* object) {
Reduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
// Try to determine the {receiver} map. // Try to determine the {object} map.
ZoneHandleSet<Map> receiver_maps; ZoneHandleSet<Map> object_maps;
NodeProperties::InferReceiverMapsResult result = NodeProperties::InferReceiverMapsResult result =
NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps); NodeProperties::InferReceiverMaps(object, effect, &object_maps);
if (result != NodeProperties::kNoReceiverMaps) { if (result != NodeProperties::kNoReceiverMaps) {
Handle<Map> candidate_map( Handle<Map> candidate_map(
receiver_maps[0]->GetPrototypeChainRootMap(isolate())); object_maps[0]->GetPrototypeChainRootMap(isolate()));
Handle<Object> candidate_prototype(candidate_map->prototype(), isolate()); Handle<Object> candidate_prototype(candidate_map->prototype(), isolate());
// We cannot deal with primitives here.
if (candidate_map->IsPrimitiveMap()) return NoChange();
// Check if we can constant-fold the {candidate_prototype}. // Check if we can constant-fold the {candidate_prototype}.
for (size_t i = 0; i < receiver_maps.size(); ++i) { for (size_t i = 0; i < object_maps.size(); ++i) {
Handle<Map> const receiver_map( Handle<Map> const object_map(
receiver_maps[i]->GetPrototypeChainRootMap(isolate())); object_maps[i]->GetPrototypeChainRootMap(isolate()));
if (receiver_map->IsJSProxyMap() || if (object_map->IsSpecialReceiverMap() ||
receiver_map->has_hidden_prototype() || object_map->has_hidden_prototype() ||
receiver_map->is_access_check_needed() || object_map->prototype() != *candidate_prototype) {
receiver_map->prototype() != *candidate_prototype) { // We exclude special receivers, like JSProxy or API objects that
// might require access checks here; we also don't want to deal
// with hidden prototypes at this point.
return NoChange(); return NoChange();
} }
if (result == NodeProperties::kUnreliableReceiverMaps && if (result == NodeProperties::kUnreliableReceiverMaps &&
!receiver_map->is_stable()) { !object_map->is_stable()) {
return NoChange(); return NoChange();
} }
} }
if (result == NodeProperties::kUnreliableReceiverMaps) { if (result == NodeProperties::kUnreliableReceiverMaps) {
for (size_t i = 0; i < receiver_maps.size(); ++i) { for (size_t i = 0; i < object_maps.size(); ++i) {
dependencies()->AssumeMapStable(receiver_maps[i]); dependencies()->AssumeMapStable(object_maps[i]);
} }
} }
Node* value = jsgraph()->Constant(candidate_prototype); Node* value = jsgraph()->Constant(candidate_prototype);
...@@ -370,6 +372,31 @@ Reduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) { ...@@ -370,6 +372,31 @@ Reduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) {
return NoChange(); return NoChange();
} }
// ES6 section 19.1.2.11 Object.getPrototypeOf ( O )
Reduction JSCallReducer::ReduceObjectGetPrototypeOf(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
Node* object = (node->op()->ValueInputCount() >= 3)
? NodeProperties::GetValueInput(node, 2)
: jsgraph()->UndefinedConstant();
return ReduceObjectGetPrototype(node, object);
}
// ES6 section B.2.2.1.1 get Object.prototype.__proto__
Reduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
Node* receiver = NodeProperties::GetValueInput(node, 1);
return ReduceObjectGetPrototype(node, receiver);
}
// ES6 section 26.1.7 Reflect.getPrototypeOf ( target )
Reduction JSCallReducer::ReduceReflectGetPrototypeOf(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
Node* target = (node->op()->ValueInputCount() >= 3)
? NodeProperties::GetValueInput(node, 2)
: jsgraph()->UndefinedConstant();
return ReduceObjectGetPrototype(node, target);
}
Reduction JSCallReducer::ReduceCallApiFunction( Reduction JSCallReducer::ReduceCallApiFunction(
Node* node, Node* target, Node* node, Node* target,
Handle<FunctionTemplateInfo> function_template_info) { Handle<FunctionTemplateInfo> function_template_info) {
...@@ -570,8 +597,12 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) { ...@@ -570,8 +597,12 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
return ReduceFunctionPrototypeHasInstance(node); return ReduceFunctionPrototypeHasInstance(node);
case Builtins::kNumberConstructor: case Builtins::kNumberConstructor:
return ReduceNumberConstructor(node); return ReduceNumberConstructor(node);
case Builtins::kObjectGetPrototypeOf:
return ReduceObjectGetPrototypeOf(node);
case Builtins::kObjectPrototypeGetProto: case Builtins::kObjectPrototypeGetProto:
return ReduceObjectPrototypeGetProto(node); return ReduceObjectPrototypeGetProto(node);
case Builtins::kReflectGetPrototypeOf:
return ReduceReflectGetPrototypeOf(node);
default: default:
break; break;
} }
......
...@@ -47,7 +47,10 @@ class JSCallReducer final : public AdvancedReducer { ...@@ -47,7 +47,10 @@ class JSCallReducer final : public AdvancedReducer {
Reduction ReduceFunctionPrototypeApply(Node* node); Reduction ReduceFunctionPrototypeApply(Node* node);
Reduction ReduceFunctionPrototypeCall(Node* node); Reduction ReduceFunctionPrototypeCall(Node* node);
Reduction ReduceFunctionPrototypeHasInstance(Node* node); Reduction ReduceFunctionPrototypeHasInstance(Node* node);
Reduction ReduceObjectGetPrototype(Node* node, Node* object);
Reduction ReduceObjectGetPrototypeOf(Node* node);
Reduction ReduceObjectPrototypeGetProto(Node* node); Reduction ReduceObjectPrototypeGetProto(Node* node);
Reduction ReduceReflectGetPrototypeOf(Node* node);
Reduction ReduceSpreadCall(Node* node, int arity); Reduction ReduceSpreadCall(Node* node, int arity);
Reduction ReduceJSConstruct(Node* node); Reduction ReduceJSConstruct(Node* node);
Reduction ReduceJSConstructWithSpread(Node* node); Reduction ReduceJSConstructWithSpread(Node* node);
......
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
var prototype = Object.create(null);
var object = Object.create(prototype);
function foo() { return Object.getPrototypeOf(object); }
assertSame(prototype, foo());
assertSame(prototype, foo());
%OptimizeFunctionOnNextCall(foo);
assertSame(prototype, foo());
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
var prototype = Object.create(null);
var object = Object.create(prototype);
function foo() { return Reflect.getPrototypeOf(object); }
assertSame(prototype, foo());
assertSame(prototype, foo());
%OptimizeFunctionOnNextCall(foo);
assertSame(prototype, foo());
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