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,
namespace {
MaybeHandle<Map> GetMapWitness(Node* node) {
ZoneHandleSet<Map> maps;
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)) {
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);
if (NodeProperties::InferReceiverMaps(receiver, effect, &maps)) {
if (maps.size() == 1) return MaybeHandle<Map>(maps[0]);
}
return MaybeHandle<Map>();
}
// TODO(turbofan): This was copied from Crankshaft, might be too restrictive.
......
......@@ -264,30 +264,6 @@ Reduction JSCallReducer::ReduceFunctionPrototypeHasInstance(Node* node) {
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,
Handle<FunctionTemplateInfo> function_template_info) {
DCHECK(node->opcode() == IrOpcode::kJSCall);
......@@ -344,19 +320,27 @@ JSCallReducer::HolderLookup JSCallReducer::LookupHolder(
// 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);
Node* effect = NodeProperties::GetEffectInput(node);
// Try to determine the {receiver} map.
Handle<Map> receiver_map;
if (InferReceiverMap(node).ToHandle(&receiver_map)) {
// Check if we can constant-fold the {receiver} map.
if (!receiver_map->IsJSProxyMap() &&
!receiver_map->has_hidden_prototype() &&
!receiver_map->is_access_check_needed()) {
Handle<Object> receiver_prototype(receiver_map->prototype(), isolate());
Node* value = jsgraph()->Constant(receiver_prototype);
ReplaceWithValue(node, value);
return Replace(value);
ZoneHandleSet<Map> receiver_maps;
if (NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps)) {
Handle<Object> receiver_prototype(receiver_maps[0]->prototype(), isolate());
// Check if we can constant-fold the {receiver_prototype}.
for (size_t i = 0; i < receiver_maps.size(); ++i) {
Handle<Map> const receiver_map = receiver_maps[i];
if (receiver_map->IsJSProxyMap() ||
receiver_map->has_hidden_prototype() ||
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();
......
......@@ -305,45 +305,20 @@ bool NeedsConvertReceiver(Node* receiver, Node* effect) {
case IrOpcode::kJSCreateLiteralRegExp:
case IrOpcode::kJSConvertReceiver:
case IrOpcode::kJSGetSuperConstructor:
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;
}
case IrOpcode::kJSToObject: {
return false;
}
switch (dominator->opcode()) {
case IrOpcode::kStoreField: {
FieldAccess const& access = FieldAccessOf(dominator->op());
if (access.base_is_tagged == kTaggedBase &&
access.offset == HeapObject::kMapOffset) {
return true;
default: {
ZoneHandleSet<Map> maps;
if (NodeProperties::InferReceiverMaps(receiver, effect, &maps)) {
// Check if all {maps} are actually JSReceiver maps.
for (size_t i = 0; i < maps.size(); ++i) {
if (!maps[i]->IsJSReceiverMap()) return true;
}
break;
}
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 false;
}
return true;
}
dominator = NodeProperties::GetEffectInput(dominator);
}
}
......
......@@ -2194,15 +2194,14 @@ bool JSNativeContextSpecialization::ExtractReceiverMaps(
MapHandleList* receiver_maps) {
DCHECK_EQ(0, receiver_maps->length());
// See if we can infer a concrete type for the {receiver}.
Handle<Map> receiver_map;
if (InferReceiverMap(receiver, effect).ToHandle(&receiver_map)) {
// We can assume that the {receiver} still has the infered {receiver_map}.
receiver_maps->Add(receiver_map);
if (InferReceiverMaps(receiver, effect, receiver_maps)) {
// We can assume that the {receiver} still has the infered {receiver_maps}.
return true;
}
// Try to extract some maps from the {nexus}.
if (nexus.ExtractMaps(receiver_maps) != 0) {
// Try to filter impossible candidates based on infered root map.
Handle<Map> receiver_map;
if (InferReceiverRootMap(receiver).ToHandle(&receiver_map)) {
for (int i = receiver_maps->length(); --i >= 0;) {
if (receiver_maps->at(i)->FindRootMap() != *receiver_map) {
......@@ -2215,65 +2214,16 @@ bool JSNativeContextSpecialization::ExtractReceiverMaps(
return false;
}
MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverMap(Node* receiver,
Node* effect) {
HeapObjectMatcher m(receiver);
if (m.HasValue()) {
Handle<Map> receiver_map(m.Value()->map(), isolate());
if (receiver_map->is_stable()) return receiver_map;
} 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;
bool JSNativeContextSpecialization::InferReceiverMaps(
Node* receiver, Node* effect, MapHandleList* receiver_maps) {
ZoneHandleSet<Map> maps;
if (NodeProperties::InferReceiverMaps(receiver, effect, &maps)) {
for (size_t i = 0; i < maps.size(); ++i) {
receiver_maps->Add(maps[i]);
}
effect = NodeProperties::GetEffectInput(effect);
return true;
}
return MaybeHandle<Map>();
return false;
}
MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap(
......
......@@ -147,10 +147,12 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
FeedbackNexus const& nexus,
MapHandleList* receiver_maps);
// Try to infer a map for the given {receiver} at the current {effect}.
// If a map is returned then you can be sure that the {receiver} definitely
// has the returned map at this point in the program (identified by {effect}).
MaybeHandle<Map> InferReceiverMap(Node* receiver, Node* effect);
// Try to infer maps for the given {receiver} at the current {effect}.
// If maps are returned then you can be sure that the {receiver} definitely
// has one of the returned maps at this point in the program (identified
// by {effect}).
bool InferReceiverMaps(Node* receiver, Node* effect,
MapHandleList* receiver_maps);
// Try to infer a root map for the {receiver} independent of the current
// program location.
MaybeHandle<Map> InferReceiverRootMap(Node* receiver);
......
......@@ -7,7 +7,9 @@
#include "src/compiler/graph.h"
#include "src/compiler/js-operator.h"
#include "src/compiler/linkage.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/operator-properties.h"
#include "src/compiler/simplified-operator.h"
#include "src/compiler/verifier.h"
#include "src/handles-inl.h"
#include "src/objects-inl.h"
......@@ -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
MaybeHandle<Context> NodeProperties::GetSpecializationContext(
Node* node, MaybeHandle<Context> context) {
......
......@@ -8,6 +8,7 @@
#include "src/compiler/node.h"
#include "src/compiler/types.h"
#include "src/globals.h"
#include "src/zone/zone-handle-set.h"
namespace v8 {
namespace internal {
......@@ -126,6 +127,12 @@ class V8_EXPORT_PRIVATE NodeProperties final {
// Checks if two nodes are the same, looking past {CheckHeapObject}.
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.
......
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