Commit fc331225 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Unify NodeProperties::InferReceiverMaps.

Unify the three different implementations of InferReceiverMaps, which
were basically copy&paste with slightly different optimizations applied
later into a single NodeProperties::InferReceiverMaps helper, which also
returns a ZoneHandleSet of maps, rather than only a single map.

BUG=v8:5267
R=jarin@chromium.org

Review-Url: https://codereview.chromium.org/2703133003
Cr-Commit-Position: refs/heads/master@{#43318}
parent 46290669
...@@ -110,26 +110,13 @@ JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph, ...@@ -110,26 +110,13 @@ JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph,
namespace { namespace {
MaybeHandle<Map> GetMapWitness(Node* node) { MaybeHandle<Map> GetMapWitness(Node* node) {
ZoneHandleSet<Map> maps;
Node* receiver = NodeProperties::GetValueInput(node, 1); Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
// Check if the {node} is dominated by a CheckMaps with a single map if (NodeProperties::InferReceiverMaps(receiver, effect, &maps)) {
// for the {receiver}, and if so use that map for the lowering below. if (maps.size() == 1) return MaybeHandle<Map>(maps[0]);
for (Node* dominator = effect;;) {
if (dominator->opcode() == IrOpcode::kCheckMaps &&
NodeProperties::IsSame(dominator->InputAt(0), receiver)) {
ZoneHandleSet<Map> const& maps =
CheckMapsParametersOf(dominator->op()).maps();
return (maps.size() == 1) ? MaybeHandle<Map>(maps[0])
: MaybeHandle<Map>();
}
DCHECK_EQ(1, dominator->op()->EffectOutputCount());
if (dominator->op()->EffectInputCount() != 1 ||
!dominator->op()->HasProperty(Operator::kNoWrite)) {
// Didn't find any appropriate CheckMaps node.
return MaybeHandle<Map>();
}
dominator = NodeProperties::GetEffectInput(dominator);
} }
return MaybeHandle<Map>();
} }
// TODO(turbofan): This was copied from Crankshaft, might be too restrictive. // TODO(turbofan): This was copied from Crankshaft, might be too restrictive.
......
...@@ -264,30 +264,6 @@ Reduction JSCallReducer::ReduceFunctionPrototypeHasInstance(Node* node) { ...@@ -264,30 +264,6 @@ Reduction JSCallReducer::ReduceFunctionPrototypeHasInstance(Node* node) {
namespace { namespace {
// TODO(turbofan): Share with similar functionality in JSInliningHeuristic
// and JSNativeContextSpecialization, i.e. move to NodeProperties helper?!
MaybeHandle<Map> InferReceiverMap(Node* node) {
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
// Check if the {node} is dominated by a CheckMaps with a single map
// for the {receiver}, and if so use that map for the lowering below.
for (Node* dominator = effect;;) {
if (dominator->opcode() == IrOpcode::kCheckMaps &&
NodeProperties::IsSame(dominator->InputAt(0), receiver)) {
if (dominator->op()->ValueInputCount() == 2) {
HeapObjectMatcher m(dominator->InputAt(1));
if (m.HasValue()) return Handle<Map>::cast(m.Value());
}
return MaybeHandle<Map>();
}
if (dominator->op()->EffectInputCount() != 1) {
// Didn't find any appropriate CheckMaps node.
return MaybeHandle<Map>();
}
dominator = NodeProperties::GetEffectInput(dominator);
}
}
bool CanInlineApiCall(Isolate* isolate, Node* node, bool CanInlineApiCall(Isolate* isolate, Node* node,
Handle<FunctionTemplateInfo> function_template_info) { Handle<FunctionTemplateInfo> function_template_info) {
DCHECK(node->opcode() == IrOpcode::kJSCall); DCHECK(node->opcode() == IrOpcode::kJSCall);
...@@ -344,19 +320,27 @@ JSCallReducer::HolderLookup JSCallReducer::LookupHolder( ...@@ -344,19 +320,27 @@ JSCallReducer::HolderLookup JSCallReducer::LookupHolder(
// ES6 section B.2.2.1.1 get Object.prototype.__proto__ // ES6 section B.2.2.1.1 get Object.prototype.__proto__
Reduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) { Reduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
// Try to determine the {receiver} map. // Try to determine the {receiver} map.
Handle<Map> receiver_map; ZoneHandleSet<Map> receiver_maps;
if (InferReceiverMap(node).ToHandle(&receiver_map)) { if (NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps)) {
// Check if we can constant-fold the {receiver} map. Handle<Object> receiver_prototype(receiver_maps[0]->prototype(), isolate());
if (!receiver_map->IsJSProxyMap() &&
!receiver_map->has_hidden_prototype() && // Check if we can constant-fold the {receiver_prototype}.
!receiver_map->is_access_check_needed()) { for (size_t i = 0; i < receiver_maps.size(); ++i) {
Handle<Object> receiver_prototype(receiver_map->prototype(), isolate()); Handle<Map> const receiver_map = receiver_maps[i];
Node* value = jsgraph()->Constant(receiver_prototype); if (receiver_map->IsJSProxyMap() ||
ReplaceWithValue(node, value); receiver_map->has_hidden_prototype() ||
return Replace(value); receiver_map->is_access_check_needed() ||
receiver_map->prototype() != *receiver_prototype) {
return NoChange();
}
} }
Node* value = jsgraph()->Constant(receiver_prototype);
ReplaceWithValue(node, value);
return Replace(value);
} }
return NoChange(); return NoChange();
......
...@@ -305,45 +305,20 @@ bool NeedsConvertReceiver(Node* receiver, Node* effect) { ...@@ -305,45 +305,20 @@ bool NeedsConvertReceiver(Node* receiver, Node* effect) {
case IrOpcode::kJSCreateLiteralRegExp: case IrOpcode::kJSCreateLiteralRegExp:
case IrOpcode::kJSConvertReceiver: case IrOpcode::kJSConvertReceiver:
case IrOpcode::kJSGetSuperConstructor: case IrOpcode::kJSGetSuperConstructor:
case IrOpcode::kJSToObject: case IrOpcode::kJSToObject: {
return false;
default:
break;
}
for (Node* dominator = effect;;) {
if (dominator->opcode() == IrOpcode::kCheckMaps &&
NodeProperties::IsSame(dominator->InputAt(0), receiver)) {
// Check if all maps have the given {instance_type}.
ZoneHandleSet<Map> const& maps =
CheckMapsParametersOf(dominator->op()).maps();
for (size_t i = 0; i < maps.size(); ++i) {
if (!maps[i]->IsJSReceiverMap()) return true;
}
return false; return false;
} }
switch (dominator->opcode()) { default: {
case IrOpcode::kStoreField: { ZoneHandleSet<Map> maps;
FieldAccess const& access = FieldAccessOf(dominator->op()); if (NodeProperties::InferReceiverMaps(receiver, effect, &maps)) {
if (access.base_is_tagged == kTaggedBase && // Check if all {maps} are actually JSReceiver maps.
access.offset == HeapObject::kMapOffset) { for (size_t i = 0; i < maps.size(); ++i) {
return true; if (!maps[i]->IsJSReceiverMap()) return true;
} }
break; return false;
}
case IrOpcode::kStoreElement:
case IrOpcode::kStoreTypedElement:
break;
default: {
DCHECK_EQ(1, dominator->op()->EffectOutputCount());
if (dominator->op()->EffectInputCount() != 1 ||
!dominator->op()->HasProperty(Operator::kNoWrite)) {
// Didn't find any appropriate CheckMaps node.
return true;
}
break;
} }
return true;
} }
dominator = NodeProperties::GetEffectInput(dominator);
} }
} }
......
...@@ -2194,15 +2194,14 @@ bool JSNativeContextSpecialization::ExtractReceiverMaps( ...@@ -2194,15 +2194,14 @@ bool JSNativeContextSpecialization::ExtractReceiverMaps(
MapHandleList* receiver_maps) { MapHandleList* receiver_maps) {
DCHECK_EQ(0, receiver_maps->length()); DCHECK_EQ(0, receiver_maps->length());
// See if we can infer a concrete type for the {receiver}. // See if we can infer a concrete type for the {receiver}.
Handle<Map> receiver_map; if (InferReceiverMaps(receiver, effect, receiver_maps)) {
if (InferReceiverMap(receiver, effect).ToHandle(&receiver_map)) { // We can assume that the {receiver} still has the infered {receiver_maps}.
// We can assume that the {receiver} still has the infered {receiver_map}.
receiver_maps->Add(receiver_map);
return true; return true;
} }
// Try to extract some maps from the {nexus}. // Try to extract some maps from the {nexus}.
if (nexus.ExtractMaps(receiver_maps) != 0) { if (nexus.ExtractMaps(receiver_maps) != 0) {
// Try to filter impossible candidates based on infered root map. // Try to filter impossible candidates based on infered root map.
Handle<Map> receiver_map;
if (InferReceiverRootMap(receiver).ToHandle(&receiver_map)) { if (InferReceiverRootMap(receiver).ToHandle(&receiver_map)) {
for (int i = receiver_maps->length(); --i >= 0;) { for (int i = receiver_maps->length(); --i >= 0;) {
if (receiver_maps->at(i)->FindRootMap() != *receiver_map) { if (receiver_maps->at(i)->FindRootMap() != *receiver_map) {
...@@ -2215,65 +2214,16 @@ bool JSNativeContextSpecialization::ExtractReceiverMaps( ...@@ -2215,65 +2214,16 @@ bool JSNativeContextSpecialization::ExtractReceiverMaps(
return false; return false;
} }
MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverMap(Node* receiver, bool JSNativeContextSpecialization::InferReceiverMaps(
Node* effect) { Node* receiver, Node* effect, MapHandleList* receiver_maps) {
HeapObjectMatcher m(receiver); ZoneHandleSet<Map> maps;
if (m.HasValue()) { if (NodeProperties::InferReceiverMaps(receiver, effect, &maps)) {
Handle<Map> receiver_map(m.Value()->map(), isolate()); for (size_t i = 0; i < maps.size(); ++i) {
if (receiver_map->is_stable()) return receiver_map; receiver_maps->Add(maps[i]);
} else if (m.IsJSCreate()) {
HeapObjectMatcher mtarget(m.InputAt(0));
HeapObjectMatcher mnewtarget(m.InputAt(1));
if (mtarget.HasValue() && mnewtarget.HasValue()) {
Handle<JSFunction> original_constructor =
Handle<JSFunction>::cast(mnewtarget.Value());
if (original_constructor->has_initial_map()) {
Handle<Map> initial_map(original_constructor->initial_map(), isolate());
if (initial_map->constructor_or_backpointer() == *mtarget.Value()) {
// Walk up the {effect} chain to see if the {receiver} is the
// dominating effect and there's no other observable write in
// between.
while (true) {
if (receiver == effect) return initial_map;
if (!effect->op()->HasProperty(Operator::kNoWrite) ||
effect->op()->EffectInputCount() != 1) {
break;
}
effect = NodeProperties::GetEffectInput(effect);
}
}
}
}
}
// Go hunting for a matching CheckMaps(receiver) or StoreField[Map](receiver)
// in the {effect} chain.
// TODO(turbofan): Propagate the information along the control/effect chains
// instead at some point to avoid this potentially inefficient hunting.
while (true) {
if (effect->opcode() == IrOpcode::kCheckMaps) {
ZoneHandleSet<Map> maps = CheckMapsParametersOf(effect->op()).maps();
if (maps.size() == 1u) {
Node* object = NodeProperties::GetValueInput(effect, 0);
if (NodeProperties::IsSame(receiver, object)) return maps[0];
}
} else if (effect->opcode() == IrOpcode::kStoreField) {
FieldAccess const access = FieldAccessOf(effect->op());
if (access.offset == HeapObject::kMapOffset) {
Node* object = NodeProperties::GetValueInput(effect, 0);
Node* value = NodeProperties::GetValueInput(effect, 1);
if (object == receiver) {
HeapObjectMatcher m(value);
if (m.HasValue()) return Handle<Map>::cast(m.Value());
}
break;
}
} else if (!effect->op()->HasProperty(Operator::kNoWrite) ||
effect->op()->EffectInputCount() != 1) {
break;
} }
effect = NodeProperties::GetEffectInput(effect); return true;
} }
return MaybeHandle<Map>(); return false;
} }
MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap( MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap(
......
...@@ -147,10 +147,12 @@ class JSNativeContextSpecialization final : public AdvancedReducer { ...@@ -147,10 +147,12 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
FeedbackNexus const& nexus, FeedbackNexus const& nexus,
MapHandleList* receiver_maps); MapHandleList* receiver_maps);
// Try to infer a map for the given {receiver} at the current {effect}. // Try to infer maps for the given {receiver} at the current {effect}.
// If a map is returned then you can be sure that the {receiver} definitely // If maps are returned then you can be sure that the {receiver} definitely
// has the returned map at this point in the program (identified by {effect}). // has one of the returned maps at this point in the program (identified
MaybeHandle<Map> InferReceiverMap(Node* receiver, Node* effect); // by {effect}).
bool InferReceiverMaps(Node* receiver, Node* effect,
MapHandleList* receiver_maps);
// Try to infer a root map for the {receiver} independent of the current // Try to infer a root map for the {receiver} independent of the current
// program location. // program location.
MaybeHandle<Map> InferReceiverRootMap(Node* receiver); MaybeHandle<Map> InferReceiverRootMap(Node* receiver);
......
...@@ -7,7 +7,9 @@ ...@@ -7,7 +7,9 @@
#include "src/compiler/graph.h" #include "src/compiler/graph.h"
#include "src/compiler/js-operator.h" #include "src/compiler/js-operator.h"
#include "src/compiler/linkage.h" #include "src/compiler/linkage.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/operator-properties.h" #include "src/compiler/operator-properties.h"
#include "src/compiler/simplified-operator.h"
#include "src/compiler/verifier.h" #include "src/compiler/verifier.h"
#include "src/handles-inl.h" #include "src/handles-inl.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
...@@ -327,6 +329,90 @@ bool NodeProperties::IsSame(Node* a, Node* b) { ...@@ -327,6 +329,90 @@ bool NodeProperties::IsSame(Node* a, Node* b) {
} }
} }
// static
bool NodeProperties::InferReceiverMaps(Node* receiver, Node* effect,
ZoneHandleSet<Map>* maps_return) {
HeapObjectMatcher m(receiver);
if (m.HasValue()) {
Handle<Map> receiver_map(m.Value()->map());
if (receiver_map->is_stable()) {
*maps_return = ZoneHandleSet<Map>(receiver_map);
return true;
}
}
while (true) {
switch (effect->opcode()) {
case IrOpcode::kCheckMaps: {
Node* const object = GetValueInput(effect, 0);
if (IsSame(receiver, object)) {
*maps_return = CheckMapsParametersOf(effect->op()).maps();
return true;
}
break;
}
case IrOpcode::kJSCreate: {
if (IsSame(receiver, effect)) {
HeapObjectMatcher mtarget(GetValueInput(effect, 0));
HeapObjectMatcher mnewtarget(GetValueInput(effect, 1));
if (mtarget.HasValue() && mnewtarget.HasValue()) {
Handle<JSFunction> original_constructor =
Handle<JSFunction>::cast(mnewtarget.Value());
if (original_constructor->has_initial_map()) {
Handle<Map> initial_map(original_constructor->initial_map());
if (initial_map->constructor_or_backpointer() ==
*mtarget.Value()) {
*maps_return = ZoneHandleSet<Map>(initial_map);
return true;
}
}
}
// We reached the allocation of the {receiver}.
return false;
}
break;
}
case IrOpcode::kStoreField: {
// We only care about StoreField of maps.
Node* const object = GetValueInput(effect, 0);
FieldAccess const& access = FieldAccessOf(effect->op());
if (access.base_is_tagged == kTaggedBase &&
access.offset == HeapObject::kMapOffset) {
if (IsSame(receiver, object)) {
Node* const value = GetValueInput(effect, 1);
HeapObjectMatcher m(value);
if (m.HasValue()) {
*maps_return = ZoneHandleSet<Map>(Handle<Map>::cast(m.Value()));
return true;
}
}
// Without alias analysis we cannot tell whether this
// StoreField[map] affects {receiver} or not.
return false;
}
break;
}
case IrOpcode::kJSStoreMessage:
case IrOpcode::kJSStoreModule:
case IrOpcode::kStoreElement:
case IrOpcode::kStoreTypedElement: {
// These never change the map of objects.
break;
}
default: {
DCHECK_EQ(1, effect->op()->EffectOutputCount());
if (effect->op()->EffectInputCount() != 1 ||
!effect->op()->HasProperty(Operator::kNoWrite)) {
// Didn't find any appropriate CheckMaps node.
return false;
}
break;
}
}
DCHECK_EQ(1, effect->op()->EffectInputCount());
effect = NodeProperties::GetEffectInput(effect);
}
}
// static // static
MaybeHandle<Context> NodeProperties::GetSpecializationContext( MaybeHandle<Context> NodeProperties::GetSpecializationContext(
Node* node, MaybeHandle<Context> context) { Node* node, MaybeHandle<Context> context) {
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "src/compiler/node.h" #include "src/compiler/node.h"
#include "src/compiler/types.h" #include "src/compiler/types.h"
#include "src/globals.h" #include "src/globals.h"
#include "src/zone/zone-handle-set.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -126,6 +127,12 @@ class V8_EXPORT_PRIVATE NodeProperties final { ...@@ -126,6 +127,12 @@ class V8_EXPORT_PRIVATE NodeProperties final {
// Checks if two nodes are the same, looking past {CheckHeapObject}. // Checks if two nodes are the same, looking past {CheckHeapObject}.
static bool IsSame(Node* a, Node* b); static bool IsSame(Node* a, Node* b);
// Walks up the {effect} chain to find a witness that provides map
// information about the {receiver}. Doesn't look through potentially
// side effecting nodes.
static bool InferReceiverMaps(Node* receiver, Node* effect,
ZoneHandleSet<Map>* maps_return);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Context. // Context.
......
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