[turbofan] Do constant-folding of JSHasInPrototypeChain early.
We need to constant-fold JSHasInPrototypeChain nodes early during inlining, otherwise we already miss a couple of optimization opportunities if we wait until after typing. This moves the constant-folding part of the JSHasInPrototypeChain lowering back to JSNativeContextSpecialization, where it was before the changes in https://codereview.chromium.org/2934893002 (part of JSOrdinaryHasInstance lowering back then). BUG=v8:5269,v8:5989,v8:6483,chromium:733158 R=jgruber@chromium.org Review-Url: https://codereview.chromium.org/2943293002 Cr-Commit-Position: refs/heads/master@{#45989}
This commit is contained in:
parent
a9b9c7ab8c
commit
53b6f27674
@ -76,6 +76,8 @@ Reduction JSNativeContextSpecialization::Reduce(Node* node) {
|
||||
return ReduceJSGetSuperConstructor(node);
|
||||
case IrOpcode::kJSInstanceOf:
|
||||
return ReduceJSInstanceOf(node);
|
||||
case IrOpcode::kJSHasInPrototypeChain:
|
||||
return ReduceJSHasInPrototypeChain(node);
|
||||
case IrOpcode::kJSOrdinaryHasInstance:
|
||||
return ReduceJSOrdinaryHasInstance(node);
|
||||
case IrOpcode::kJSLoadContext:
|
||||
@ -257,6 +259,80 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
JSNativeContextSpecialization::InferHasInPrototypeChainResult
|
||||
JSNativeContextSpecialization::InferHasInPrototypeChain(
|
||||
Node* receiver, Node* effect, Handle<HeapObject> prototype) {
|
||||
ZoneHandleSet<Map> receiver_maps;
|
||||
NodeProperties::InferReceiverMapsResult result =
|
||||
NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
|
||||
if (result == NodeProperties::kNoReceiverMaps) return kMayBeInPrototypeChain;
|
||||
|
||||
// Check if either all or none of the {receiver_maps} have the given
|
||||
// {prototype} in their prototype chain.
|
||||
bool all = true;
|
||||
bool none = true;
|
||||
for (size_t i = 0; i < receiver_maps.size(); ++i) {
|
||||
Handle<Map> receiver_map = receiver_maps[i];
|
||||
if (receiver_map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
|
||||
return kMayBeInPrototypeChain;
|
||||
}
|
||||
if (result == NodeProperties::kUnreliableReceiverMaps) {
|
||||
// In case of an unreliable {result} we need to ensure that all
|
||||
// {receiver_maps} are stable, because otherwise we cannot trust
|
||||
// the {receiver_maps} information, since arbitrary side-effects
|
||||
// may have happened.
|
||||
if (!receiver_map->is_stable()) {
|
||||
return kMayBeInPrototypeChain;
|
||||
}
|
||||
}
|
||||
for (PrototypeIterator j(receiver_map);; j.Advance()) {
|
||||
if (j.IsAtEnd()) {
|
||||
all = false;
|
||||
break;
|
||||
}
|
||||
Handle<HeapObject> const current =
|
||||
PrototypeIterator::GetCurrent<HeapObject>(j);
|
||||
if (current.is_identical_to(prototype)) {
|
||||
none = false;
|
||||
break;
|
||||
}
|
||||
if (!current->map()->is_stable() ||
|
||||
current->map()->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
|
||||
return kMayBeInPrototypeChain;
|
||||
}
|
||||
}
|
||||
}
|
||||
DCHECK_IMPLIES(all, !none);
|
||||
DCHECK_IMPLIES(none, !all);
|
||||
|
||||
if (all) return kIsInPrototypeChain;
|
||||
if (none) return kIsNotInPrototypeChain;
|
||||
return kMayBeInPrototypeChain;
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceJSHasInPrototypeChain(
|
||||
Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kJSHasInPrototypeChain, node->opcode());
|
||||
Node* value = NodeProperties::GetValueInput(node, 0);
|
||||
Node* prototype = NodeProperties::GetValueInput(node, 1);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
|
||||
// Check if we can constant-fold the prototype chain walk
|
||||
// for the given {value} and the {prototype}.
|
||||
HeapObjectMatcher m(prototype);
|
||||
if (m.HasValue()) {
|
||||
InferHasInPrototypeChainResult result =
|
||||
InferHasInPrototypeChain(value, effect, m.Value());
|
||||
if (result != kMayBeInPrototypeChain) {
|
||||
Node* value = jsgraph()->BooleanConstant(result == kIsInPrototypeChain);
|
||||
ReplaceWithValue(node, value);
|
||||
return Replace(value);
|
||||
}
|
||||
}
|
||||
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance(
|
||||
Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode());
|
||||
@ -302,7 +378,8 @@ Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance(
|
||||
NodeProperties::ReplaceValueInput(node, object, 0);
|
||||
NodeProperties::ReplaceValueInput(node, prototype, 1);
|
||||
NodeProperties::ChangeOp(node, javascript()->HasInPrototypeChain());
|
||||
return Changed(node);
|
||||
Reduction const reduction = ReduceJSHasInPrototypeChain(node);
|
||||
return reduction.Changed() ? reduction : Changed(node);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
|
||||
Reduction ReduceJSAdd(Node* node);
|
||||
Reduction ReduceJSGetSuperConstructor(Node* node);
|
||||
Reduction ReduceJSInstanceOf(Node* node);
|
||||
Reduction ReduceJSHasInPrototypeChain(Node* node);
|
||||
Reduction ReduceJSOrdinaryHasInstance(Node* node);
|
||||
Reduction ReduceJSLoadContext(Node* node);
|
||||
Reduction ReduceJSLoadGlobal(Node* node);
|
||||
@ -179,6 +180,17 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
|
||||
// program location.
|
||||
MaybeHandle<Map> InferReceiverRootMap(Node* receiver);
|
||||
|
||||
// Checks if we know at compile time that the {receiver} either definitely
|
||||
// has the {prototype} in it's prototype chain, or the {receiver} definitely
|
||||
// doesn't have the {prototype} in it's prototype chain.
|
||||
enum InferHasInPrototypeChainResult {
|
||||
kIsInPrototypeChain,
|
||||
kIsNotInPrototypeChain,
|
||||
kMayBeInPrototypeChain
|
||||
};
|
||||
InferHasInPrototypeChainResult InferHasInPrototypeChain(
|
||||
Node* receiver, Node* effect, Handle<HeapObject> prototype);
|
||||
|
||||
// Script context lookup logic.
|
||||
struct ScriptContextTableLookupResult;
|
||||
bool LookupInScriptContextTable(Handle<Name> name,
|
||||
|
@ -1390,63 +1390,11 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
JSTypedLowering::InferHasInPrototypeChainResult
|
||||
JSTypedLowering::InferHasInPrototypeChain(Node* receiver, Node* effect,
|
||||
Handle<HeapObject> prototype) {
|
||||
ZoneHandleSet<Map> receiver_maps;
|
||||
NodeProperties::InferReceiverMapsResult result =
|
||||
NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
|
||||
if (result == NodeProperties::kNoReceiverMaps) return kMayBeInPrototypeChain;
|
||||
|
||||
// Check if either all or none of the {receiver_maps} have the given
|
||||
// {prototype} in their prototype chain.
|
||||
bool all = true;
|
||||
bool none = true;
|
||||
for (size_t i = 0; i < receiver_maps.size(); ++i) {
|
||||
Handle<Map> receiver_map = receiver_maps[i];
|
||||
if (receiver_map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
|
||||
return kMayBeInPrototypeChain;
|
||||
}
|
||||
if (result == NodeProperties::kUnreliableReceiverMaps) {
|
||||
// In case of an unreliable {result} we need to ensure that all
|
||||
// {receiver_maps} are stable, because otherwise we cannot trust
|
||||
// the {receiver_maps} information, since arbitrary side-effects
|
||||
// may have happened.
|
||||
if (!receiver_map->is_stable()) {
|
||||
return kMayBeInPrototypeChain;
|
||||
}
|
||||
}
|
||||
for (PrototypeIterator j(receiver_map);; j.Advance()) {
|
||||
if (j.IsAtEnd()) {
|
||||
all = false;
|
||||
break;
|
||||
}
|
||||
Handle<HeapObject> const current =
|
||||
PrototypeIterator::GetCurrent<HeapObject>(j);
|
||||
if (current.is_identical_to(prototype)) {
|
||||
none = false;
|
||||
break;
|
||||
}
|
||||
if (!current->map()->is_stable() ||
|
||||
current->map()->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
|
||||
return kMayBeInPrototypeChain;
|
||||
}
|
||||
}
|
||||
}
|
||||
DCHECK_IMPLIES(all, !none);
|
||||
DCHECK_IMPLIES(none, !all);
|
||||
|
||||
if (all) return kIsInPrototypeChain;
|
||||
if (none) return kIsNotInPrototypeChain;
|
||||
return kMayBeInPrototypeChain;
|
||||
}
|
||||
|
||||
Reduction JSTypedLowering::ReduceJSHasInPrototypeChain(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kJSHasInPrototypeChain, node->opcode());
|
||||
Node* value = NodeProperties::GetValueInput(node, 0);
|
||||
Type* value_type = NodeProperties::GetType(value);
|
||||
Node* prototype = NodeProperties::GetValueInput(node, 1);
|
||||
Type* prototype_type = NodeProperties::GetType(prototype);
|
||||
Node* context = NodeProperties::GetContextInput(node);
|
||||
Node* frame_state = NodeProperties::GetFrameStateInput(node);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
@ -1460,18 +1408,6 @@ Reduction JSTypedLowering::ReduceJSHasInPrototypeChain(Node* node) {
|
||||
return Replace(value);
|
||||
}
|
||||
|
||||
// Check if we can constant-fold the prototype chain walk
|
||||
// for the given {value} and the {prototype}.
|
||||
if (prototype_type->IsHeapConstant()) {
|
||||
InferHasInPrototypeChainResult result = InferHasInPrototypeChain(
|
||||
value, effect, prototype_type->AsHeapConstant()->Value());
|
||||
if (result != kMayBeInPrototypeChain) {
|
||||
Node* value = jsgraph()->BooleanConstant(result == kIsInPrototypeChain);
|
||||
ReplaceWithValue(node, value, effect, control);
|
||||
return Replace(value);
|
||||
}
|
||||
}
|
||||
|
||||
Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
|
||||
Node* branch0 =
|
||||
graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
|
||||
|
@ -94,17 +94,6 @@ class V8_EXPORT_PRIVATE JSTypedLowering final
|
||||
// Helper for ReduceJSLoadModule and ReduceJSStoreModule.
|
||||
Node* BuildGetModuleCell(Node* node);
|
||||
|
||||
// Checks if we know at compile time that the {receiver} either definitely
|
||||
// has the {prototype} in it's prototype chain, or the {receiver} definitely
|
||||
// doesn't have the {prototype} in it's prototype chain.
|
||||
enum InferHasInPrototypeChainResult {
|
||||
kIsInPrototypeChain,
|
||||
kIsNotInPrototypeChain,
|
||||
kMayBeInPrototypeChain
|
||||
};
|
||||
InferHasInPrototypeChainResult InferHasInPrototypeChain(
|
||||
Node* receiver, Node* effect, Handle<HeapObject> prototype);
|
||||
|
||||
Factory* factory() const;
|
||||
Graph* graph() const;
|
||||
JSGraph* jsgraph() const { return jsgraph_; }
|
||||
|
Loading…
Reference in New Issue
Block a user