Commit 45aa1351 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Track multiple maps for LoadElimination.

Store maps on the CheckMaps operator instead of burning inputs for
the individual maps. Use the same data structure (the ZoneHandleSet)
in the LoadElimination to track multiple maps per object.

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

Review-Url: https://codereview.chromium.org/2431563002
Cr-Commit-Position: refs/heads/master@{#42010}
parent 09cb6efd
...@@ -1783,6 +1783,7 @@ v8_source_set("v8_base") { ...@@ -1783,6 +1783,7 @@ v8_source_set("v8_base") {
"src/zone/zone-allocator.h", "src/zone/zone-allocator.h",
"src/zone/zone-chunk-list.h", "src/zone/zone-chunk-list.h",
"src/zone/zone-containers.h", "src/zone/zone-containers.h",
"src/zone/zone-handle-set.h",
"src/zone/zone-segment.cc", "src/zone/zone-segment.cc",
"src/zone/zone-segment.h", "src/zone/zone-segment.h",
"src/zone/zone.cc", "src/zone/zone.cc",
......
...@@ -1202,18 +1202,20 @@ EffectControlLinearizer::LowerCheckBounds(Node* node, Node* frame_state, ...@@ -1202,18 +1202,20 @@ EffectControlLinearizer::LowerCheckBounds(Node* node, Node* frame_state,
EffectControlLinearizer::ValueEffectControl EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckMaps(Node* node, Node* frame_state, EffectControlLinearizer::LowerCheckMaps(Node* node, Node* frame_state,
Node* effect, Node* control) { Node* effect, Node* control) {
CheckMapsParameters const& p = CheckMapsParametersOf(node->op());
Node* value = node->InputAt(0); Node* value = node->InputAt(0);
// Load the current map of the {value}. // Load the current map of the {value}.
Node* value_map = effect = graph()->NewNode( Node* value_map = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control); simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control);
int const map_count = node->op()->ValueInputCount() - 1; ZoneHandleSet<Map> const& maps = p.maps();
int const map_count = static_cast<int>(maps.size());
Node** controls = temp_zone()->NewArray<Node*>(map_count); Node** controls = temp_zone()->NewArray<Node*>(map_count);
Node** effects = temp_zone()->NewArray<Node*>(map_count + 1); Node** effects = temp_zone()->NewArray<Node*>(map_count + 1);
for (int i = 0; i < map_count; ++i) { for (int i = 0; i < map_count; ++i) {
Node* map = node->InputAt(1 + i); Node* map = jsgraph()->HeapConstant(maps[i]);
Node* check = graph()->NewNode(machine()->WordEqual(), value_map, map); Node* check = graph()->NewNode(machine()->WordEqual(), value_map, map);
if (i == map_count - 1) { if (i == map_count - 1) {
...@@ -3002,8 +3004,8 @@ EffectControlLinearizer::LowerTransitionElementsKind(Node* node, Node* effect, ...@@ -3002,8 +3004,8 @@ EffectControlLinearizer::LowerTransitionElementsKind(Node* node, Node* effect,
Node* control) { Node* control) {
ElementsTransition const transition = ElementsTransitionOf(node->op()); ElementsTransition const transition = ElementsTransitionOf(node->op());
Node* object = node->InputAt(0); Node* object = node->InputAt(0);
Node* source_map = node->InputAt(1); Node* source_map = jsgraph()->HeapConstant(transition.source());
Node* target_map = node->InputAt(2); Node* target_map = jsgraph()->HeapConstant(transition.target());
// Load the current map of {object}. // Load the current map of {object}.
Node* object_map = effect = Node* object_map = effect =
...@@ -3020,7 +3022,7 @@ EffectControlLinearizer::LowerTransitionElementsKind(Node* node, Node* effect, ...@@ -3020,7 +3022,7 @@ EffectControlLinearizer::LowerTransitionElementsKind(Node* node, Node* effect,
Node* if_true = graph()->NewNode(common()->IfTrue(), branch); Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* etrue = effect; Node* etrue = effect;
{ {
switch (transition) { switch (transition.mode()) {
case ElementsTransition::kFastTransition: { case ElementsTransition::kFastTransition: {
// In-place migration of {object}, just store the {target_map}. // In-place migration of {object}, just store the {target_map}.
etrue = etrue =
......
...@@ -128,11 +128,10 @@ MaybeHandle<Map> GetMapWitness(Node* node) { ...@@ -128,11 +128,10 @@ MaybeHandle<Map> GetMapWitness(Node* node) {
for (Node* dominator = effect;;) { for (Node* dominator = effect;;) {
if (dominator->opcode() == IrOpcode::kCheckMaps && if (dominator->opcode() == IrOpcode::kCheckMaps &&
IsSame(dominator->InputAt(0), receiver)) { IsSame(dominator->InputAt(0), receiver)) {
if (dominator->op()->ValueInputCount() == 2) { ZoneHandleSet<Map> const& maps =
HeapObjectMatcher m(dominator->InputAt(1)); CheckMapsParametersOf(dominator->op()).maps();
if (m.HasValue()) return Handle<Map>::cast(m.Value()); return (maps.size() == 1) ? MaybeHandle<Map>(maps[0])
} : MaybeHandle<Map>();
return MaybeHandle<Map>();
} }
if (dominator->op()->EffectInputCount() != 1) { if (dominator->op()->EffectInputCount() != 1) {
// Didn't find any appropriate CheckMaps node. // Didn't find any appropriate CheckMaps node.
...@@ -413,12 +412,17 @@ Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext( ...@@ -413,12 +412,17 @@ Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext(
} else { } else {
// For value/entry iteration, first step is a mapcheck to ensure // For value/entry iteration, first step is a mapcheck to ensure
// inlining is still valid. // inlining is still valid.
Node* array_map = etrue1 =
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
array, etrue1, if_true1);
Node* orig_map = etrue1 = Node* orig_map = etrue1 =
graph()->NewNode(simplified()->LoadField( graph()->NewNode(simplified()->LoadField(
AccessBuilder::ForJSArrayIteratorObjectMap()), AccessBuilder::ForJSArrayIteratorObjectMap()),
iterator, etrue1, if_true1); iterator, etrue1, if_true1);
etrue1 = graph()->NewNode(simplified()->CheckMaps(1), array, orig_map, Node* check_map = graph()->NewNode(simplified()->ReferenceEqual(),
etrue1, if_true1); array_map, orig_map);
etrue1 = graph()->NewNode(simplified()->CheckIf(), check_map, etrue1,
if_true1);
} }
if (kind != IterationKind::kKeys) { if (kind != IterationKind::kKeys) {
...@@ -910,14 +914,11 @@ bool HasInstanceTypeWitness(Node* receiver, Node* effect, ...@@ -910,14 +914,11 @@ bool HasInstanceTypeWitness(Node* receiver, Node* effect,
for (Node* dominator = effect;;) { for (Node* dominator = effect;;) {
if (dominator->opcode() == IrOpcode::kCheckMaps && if (dominator->opcode() == IrOpcode::kCheckMaps &&
IsSame(dominator->InputAt(0), receiver)) { IsSame(dominator->InputAt(0), receiver)) {
ZoneHandleSet<Map> const& maps =
CheckMapsParametersOf(dominator->op()).maps();
// Check if all maps have the given {instance_type}. // Check if all maps have the given {instance_type}.
for (int i = 1; i < dominator->op()->ValueInputCount(); ++i) { for (size_t i = 0; i < maps.size(); ++i) {
Node* const map = NodeProperties::GetValueInput(dominator, i); if (maps[i]->instance_type() != instance_type) return false;
Type* const map_type = NodeProperties::GetType(map);
if (!map_type->IsHeapConstant()) return false;
Handle<Map> const map_value =
Handle<Map>::cast(map_type->AsHeapConstant()->Value());
if (map_value->instance_type() != instance_type) return false;
} }
return true; return true;
} }
......
...@@ -206,9 +206,9 @@ Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) { ...@@ -206,9 +206,9 @@ Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) {
value, effect, control); value, effect, control);
// Check {value} map agains the {property_cell} map. // Check {value} map agains the {property_cell} map.
effect = graph()->NewNode( effect = graph()->NewNode(simplified()->CheckMaps(ZoneHandleSet<Map>(
simplified()->CheckMaps(1), value, property_cell_value_map)),
jsgraph()->HeapConstant(property_cell_value_map), effect, control); value, effect, control);
property_cell_value_type = Type::OtherInternal(); property_cell_value_type = Type::OtherInternal();
representation = MachineRepresentation::kTaggedPointer; representation = MachineRepresentation::kTaggedPointer;
} else { } else {
......
...@@ -307,11 +307,10 @@ bool NeedsConvertReceiver(Node* receiver, Node* effect) { ...@@ -307,11 +307,10 @@ bool NeedsConvertReceiver(Node* receiver, Node* effect) {
if (dominator->opcode() == IrOpcode::kCheckMaps && if (dominator->opcode() == IrOpcode::kCheckMaps &&
IsSame(dominator->InputAt(0), receiver)) { IsSame(dominator->InputAt(0), receiver)) {
// Check if all maps have the given {instance_type}. // Check if all maps have the given {instance_type}.
for (int i = 1; i < dominator->op()->ValueInputCount(); ++i) { ZoneHandleSet<Map> const& maps =
HeapObjectMatcher m(NodeProperties::GetValueInput(dominator, i)); CheckMapsParametersOf(dominator->op()).maps();
if (!m.HasValue()) return true; for (size_t i = 0; i < maps.size(); ++i) {
Handle<Map> const map = Handle<Map>::cast(m.Value()); if (!maps[i]->IsJSReceiverMap()) return true;
if (!map->IsJSReceiverMap()) return true;
} }
return false; return false;
} }
......
...@@ -643,13 +643,13 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( ...@@ -643,13 +643,13 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
Handle<Map> const transition_source = transition.first; Handle<Map> const transition_source = transition.first;
Handle<Map> const transition_target = transition.second; Handle<Map> const transition_target = transition.second;
effect = graph()->NewNode( effect = graph()->NewNode(
simplified()->TransitionElementsKind( simplified()->TransitionElementsKind(ElementsTransition(
IsSimpleMapChangeTransition(transition_source->elements_kind(), IsSimpleMapChangeTransition(transition_source->elements_kind(),
transition_target->elements_kind()) transition_target->elements_kind())
? ElementsTransition::kFastTransition ? ElementsTransition::kFastTransition
: ElementsTransition::kSlowTransition), : ElementsTransition::kSlowTransition,
receiver, jsgraph()->HeapConstant(transition_source), transition_source, transition_target)),
jsgraph()->HeapConstant(transition_target), effect, control); receiver, effect, control);
} }
// TODO(turbofan): The effect/control linearization will not find a // TODO(turbofan): The effect/control linearization will not find a
...@@ -694,14 +694,13 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( ...@@ -694,14 +694,13 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
Handle<Map> const transition_target = transition.second; Handle<Map> const transition_target = transition.second;
this_effect = graph()->NewNode( this_effect = graph()->NewNode(
simplified()->TransitionElementsKind( simplified()->TransitionElementsKind(
IsSimpleMapChangeTransition( ElementsTransition(IsSimpleMapChangeTransition(
transition_source->elements_kind(), transition_source->elements_kind(),
transition_target->elements_kind()) transition_target->elements_kind())
? ElementsTransition::kFastTransition ? ElementsTransition::kFastTransition
: ElementsTransition::kSlowTransition), : ElementsTransition::kSlowTransition,
receiver, jsgraph()->HeapConstant(transition_source), transition_source, transition_target)),
jsgraph()->HeapConstant(transition_target), this_effect, receiver, this_effect, this_control);
this_control);
} }
// Load the {receiver} map. // Load the {receiver} map.
...@@ -1179,9 +1178,9 @@ JSNativeContextSpecialization::BuildPropertyAccess( ...@@ -1179,9 +1178,9 @@ JSNativeContextSpecialization::BuildPropertyAccess(
Handle<Map> field_map; Handle<Map> field_map;
if (access_info.field_map().ToHandle(&field_map)) { if (access_info.field_map().ToHandle(&field_map)) {
// Emit a map check for the value. // Emit a map check for the value.
effect = graph()->NewNode(simplified()->CheckMaps(1), value, effect = graph()->NewNode(
jsgraph()->HeapConstant(field_map), simplified()->CheckMaps(ZoneHandleSet<Map>(field_map)), value,
effect, control); effect, control);
} }
field_access.write_barrier_kind = kPointerWriteBarrier; field_access.write_barrier_kind = kPointerWriteBarrier;
break; break;
...@@ -1418,9 +1417,9 @@ JSNativeContextSpecialization::BuildElementAccess( ...@@ -1418,9 +1417,9 @@ JSNativeContextSpecialization::BuildElementAccess(
if (access_mode == AccessMode::kStore && if (access_mode == AccessMode::kStore &&
IsFastSmiOrObjectElementsKind(elements_kind) && IsFastSmiOrObjectElementsKind(elements_kind) &&
store_mode != STORE_NO_TRANSITION_HANDLE_COW) { store_mode != STORE_NO_TRANSITION_HANDLE_COW) {
effect = effect = graph()->NewNode(simplified()->CheckMaps(ZoneHandleSet<Map>(
graph()->NewNode(simplified()->CheckMaps(1), elements, factory()->fixed_array_map())),
jsgraph()->FixedArrayMapConstant(), effect, control); elements, effect, control);
} }
// Check if the {receiver} is a JSArray. // Check if the {receiver} is a JSArray.
...@@ -1640,12 +1639,12 @@ Node* JSNativeContextSpecialization::BuildCheckHeapObject(Node* receiver, ...@@ -1640,12 +1639,12 @@ Node* JSNativeContextSpecialization::BuildCheckHeapObject(Node* receiver,
Node* JSNativeContextSpecialization::BuildCheckMaps( Node* JSNativeContextSpecialization::BuildCheckMaps(
Node* receiver, Node* effect, Node* control, Node* receiver, Node* effect, Node* control,
std::vector<Handle<Map>> const& maps) { std::vector<Handle<Map>> const& receiver_maps) {
HeapObjectMatcher m(receiver); HeapObjectMatcher m(receiver);
if (m.HasValue()) { if (m.HasValue()) {
Handle<Map> receiver_map(m.Value()->map(), isolate()); Handle<Map> receiver_map(m.Value()->map(), isolate());
if (receiver_map->is_stable()) { if (receiver_map->is_stable()) {
for (Handle<Map> map : maps) { for (Handle<Map> map : receiver_maps) {
if (map.is_identical_to(receiver_map)) { if (map.is_identical_to(receiver_map)) {
dependencies()->AssumeMapStable(receiver_map); dependencies()->AssumeMapStable(receiver_map);
return effect; return effect;
...@@ -1653,17 +1652,12 @@ Node* JSNativeContextSpecialization::BuildCheckMaps( ...@@ -1653,17 +1652,12 @@ Node* JSNativeContextSpecialization::BuildCheckMaps(
} }
} }
} }
int const map_input_count = static_cast<int>(maps.size()); ZoneHandleSet<Map> maps;
int const input_count = 1 + map_input_count + 1 + 1; for (Handle<Map> map : receiver_maps) {
Node** inputs = zone()->NewArray<Node*>(input_count); maps.insert(map, graph()->zone());
inputs[0] = receiver;
for (int i = 0; i < map_input_count; ++i) {
inputs[1 + i] = jsgraph()->HeapConstant(maps[i]);
} }
inputs[input_count - 2] = effect; return graph()->NewNode(simplified()->CheckMaps(maps), receiver, effect,
inputs[input_count - 1] = control; control);
return graph()->NewNode(simplified()->CheckMaps(map_input_count), input_count,
inputs);
} }
void JSNativeContextSpecialization::AssumePrototypesStable( void JSNativeContextSpecialization::AssumePrototypesStable(
......
This diff is collapsed.
...@@ -8,9 +8,14 @@ ...@@ -8,9 +8,14 @@
#include "src/base/compiler-specific.h" #include "src/base/compiler-specific.h"
#include "src/compiler/graph-reducer.h" #include "src/compiler/graph-reducer.h"
#include "src/globals.h" #include "src/globals.h"
#include "src/zone/zone-handle-set.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
// Forward declarations.
class Factory;
namespace compiler { namespace compiler {
// Foward declarations. // Foward declarations.
...@@ -152,6 +157,49 @@ class V8_EXPORT_PRIVATE LoadElimination final ...@@ -152,6 +157,49 @@ class V8_EXPORT_PRIVATE LoadElimination final
static size_t const kMaxTrackedFields = 32; static size_t const kMaxTrackedFields = 32;
// Abstract state to approximate the current map of an object along the
// effect paths through the graph.
class AbstractMaps final : public ZoneObject {
public:
explicit AbstractMaps(Zone* zone) : info_for_node_(zone) {}
AbstractMaps(Node* object, ZoneHandleSet<Map> maps, Zone* zone)
: info_for_node_(zone) {
info_for_node_.insert(std::make_pair(object, maps));
}
AbstractMaps const* Extend(Node* object, ZoneHandleSet<Map> maps,
Zone* zone) const {
AbstractMaps* that = new (zone) AbstractMaps(zone);
that->info_for_node_ = this->info_for_node_;
that->info_for_node_.insert(std::make_pair(object, maps));
return that;
}
bool Lookup(Node* object, ZoneHandleSet<Map>* object_maps) const;
AbstractMaps const* Kill(Node* object, Zone* zone) const;
bool Equals(AbstractMaps const* that) const {
return this == that || this->info_for_node_ == that->info_for_node_;
}
AbstractMaps const* Merge(AbstractMaps const* that, Zone* zone) const {
if (this->Equals(that)) return this;
AbstractMaps* copy = new (zone) AbstractMaps(zone);
for (auto this_it : this->info_for_node_) {
Node* this_object = this_it.first;
ZoneHandleSet<Map> this_maps = this_it.second;
auto that_it = that->info_for_node_.find(this_object);
if (that_it != that->info_for_node_.end() &&
that_it->second == this_maps) {
copy->info_for_node_.insert(this_it);
}
}
return copy;
}
void Print() const;
private:
ZoneMap<Node*, ZoneHandleSet<Map>> info_for_node_;
};
class AbstractState final : public ZoneObject { class AbstractState final : public ZoneObject {
public: public:
AbstractState() { AbstractState() {
...@@ -163,6 +211,11 @@ class V8_EXPORT_PRIVATE LoadElimination final ...@@ -163,6 +211,11 @@ class V8_EXPORT_PRIVATE LoadElimination final
bool Equals(AbstractState const* that) const; bool Equals(AbstractState const* that) const;
void Merge(AbstractState const* that, Zone* zone); void Merge(AbstractState const* that, Zone* zone);
AbstractState const* AddMaps(Node* object, ZoneHandleSet<Map> maps,
Zone* zone) const;
AbstractState const* KillMaps(Node* object, Zone* zone) const;
bool LookupMaps(Node* object, ZoneHandleSet<Map>* object_maps) const;
AbstractState const* AddField(Node* object, size_t index, Node* value, AbstractState const* AddField(Node* object, size_t index, Node* value,
Zone* zone) const; Zone* zone) const;
AbstractState const* KillField(Node* object, size_t index, AbstractState const* KillField(Node* object, size_t index,
...@@ -185,6 +238,7 @@ class V8_EXPORT_PRIVATE LoadElimination final ...@@ -185,6 +238,7 @@ class V8_EXPORT_PRIVATE LoadElimination final
AbstractChecks const* checks_ = nullptr; AbstractChecks const* checks_ = nullptr;
AbstractElements const* elements_ = nullptr; AbstractElements const* elements_ = nullptr;
AbstractField const* fields_[kMaxTrackedFields]; AbstractField const* fields_[kMaxTrackedFields];
AbstractMaps const* maps_ = nullptr;
}; };
class AbstractStateForEffectNodes final : public ZoneObject { class AbstractStateForEffectNodes final : public ZoneObject {
...@@ -223,6 +277,7 @@ class V8_EXPORT_PRIVATE LoadElimination final ...@@ -223,6 +277,7 @@ class V8_EXPORT_PRIVATE LoadElimination final
CommonOperatorBuilder* common() const; CommonOperatorBuilder* common() const;
AbstractState const* empty_state() const { return &empty_state_; } AbstractState const* empty_state() const { return &empty_state_; }
Factory* factory() const;
Graph* graph() const; Graph* graph() const;
JSGraph* jsgraph() const { return jsgraph_; } JSGraph* jsgraph() const { return jsgraph_; }
Zone* zone() const { return node_states_.zone(); } Zone* zone() const { return node_states_.zone(); }
......
...@@ -229,6 +229,32 @@ std::ostream& operator<<(std::ostream& os, CheckForMinusZeroMode mode) { ...@@ -229,6 +229,32 @@ std::ostream& operator<<(std::ostream& os, CheckForMinusZeroMode mode) {
return os; return os;
} }
bool operator==(CheckMapsParameters const& lhs,
CheckMapsParameters const& rhs) {
return lhs.maps() == rhs.maps();
}
bool operator!=(CheckMapsParameters const& lhs,
CheckMapsParameters const& rhs) {
return !(lhs == rhs);
}
size_t hash_value(CheckMapsParameters const& p) { return hash_value(p.maps()); }
std::ostream& operator<<(std::ostream& os, CheckMapsParameters const& p) {
ZoneHandleSet<Map> const& maps = p.maps();
for (size_t i = 0; i < maps.size(); ++i) {
if (i != 0) os << ", ";
os << Brief(*maps[i]);
}
return os;
}
CheckMapsParameters const& CheckMapsParametersOf(Operator const* op) {
DCHECK_EQ(IrOpcode::kCheckMaps, op->opcode());
return OpParameter<CheckMapsParameters>(op);
}
size_t hash_value(CheckTaggedInputMode mode) { size_t hash_value(CheckTaggedInputMode mode) {
return static_cast<size_t>(mode); return static_cast<size_t>(mode);
} }
...@@ -274,22 +300,36 @@ GrowFastElementsFlags GrowFastElementsFlagsOf(const Operator* op) { ...@@ -274,22 +300,36 @@ GrowFastElementsFlags GrowFastElementsFlagsOf(const Operator* op) {
return OpParameter<GrowFastElementsFlags>(op); return OpParameter<GrowFastElementsFlags>(op);
} }
bool operator==(ElementsTransition const& lhs, ElementsTransition const& rhs) {
return lhs.mode() == rhs.mode() &&
lhs.source().address() == rhs.source().address() &&
lhs.target().address() == rhs.target().address();
}
bool operator!=(ElementsTransition const& lhs, ElementsTransition const& rhs) {
return !(lhs == rhs);
}
size_t hash_value(ElementsTransition transition) { size_t hash_value(ElementsTransition transition) {
return static_cast<uint8_t>(transition); return base::hash_combine(static_cast<uint8_t>(transition.mode()),
transition.source().address(),
transition.target().address());
} }
std::ostream& operator<<(std::ostream& os, ElementsTransition transition) { std::ostream& operator<<(std::ostream& os, ElementsTransition transition) {
switch (transition) { switch (transition.mode()) {
case ElementsTransition::kFastTransition: case ElementsTransition::kFastTransition:
return os << "fast-transition"; return os << "fast-transition from " << Brief(*transition.source())
<< " to " << Brief(*transition.target());
case ElementsTransition::kSlowTransition: case ElementsTransition::kSlowTransition:
return os << "slow-transition"; return os << "slow-transition from " << Brief(*transition.source())
<< " to " << Brief(*transition.target());
} }
UNREACHABLE(); UNREACHABLE();
return os; return os;
} }
ElementsTransition ElementsTransitionOf(const Operator* op) { ElementsTransition const& ElementsTransitionOf(const Operator* op) {
DCHECK_EQ(IrOpcode::kTransitionElementsKind, op->opcode()); DCHECK_EQ(IrOpcode::kTransitionElementsKind, op->opcode());
return OpParameter<ElementsTransition>(op); return OpParameter<ElementsTransition>(op);
} }
...@@ -697,16 +737,14 @@ const Operator* SimplifiedOperatorBuilder::CheckedTaggedToFloat64( ...@@ -697,16 +737,14 @@ const Operator* SimplifiedOperatorBuilder::CheckedTaggedToFloat64(
return nullptr; return nullptr;
} }
const Operator* SimplifiedOperatorBuilder::CheckMaps(int map_input_count) { const Operator* SimplifiedOperatorBuilder::CheckMaps(ZoneHandleSet<Map> maps) {
// TODO(bmeurer): Cache the most important versions of this operator. CheckMapsParameters const parameters(maps);
DCHECK_LT(0, map_input_count); return new (zone()) Operator1<CheckMapsParameters>( // --
int const value_input_count = 1 + map_input_count; IrOpcode::kCheckMaps, // opcode
return new (zone()) Operator1<int>( // -- Operator::kNoThrow | Operator::kNoWrite, // flags
IrOpcode::kCheckMaps, // opcode "CheckMaps", // name
Operator::kNoThrow | Operator::kNoWrite, // flags 1, 1, 1, 0, 1, 0, // counts
"CheckMaps", // name parameters); // parameter
value_input_count, 1, 1, 0, 1, 0, // counts
map_input_count); // parameter
} }
const Operator* SimplifiedOperatorBuilder::CheckFloat64Hole( const Operator* SimplifiedOperatorBuilder::CheckFloat64Hole(
...@@ -741,7 +779,7 @@ const Operator* SimplifiedOperatorBuilder::TransitionElementsKind( ...@@ -741,7 +779,7 @@ const Operator* SimplifiedOperatorBuilder::TransitionElementsKind(
IrOpcode::kTransitionElementsKind, // opcode IrOpcode::kTransitionElementsKind, // opcode
Operator::kNoDeopt | Operator::kNoThrow, // flags Operator::kNoDeopt | Operator::kNoThrow, // flags
"TransitionElementsKind", // name "TransitionElementsKind", // name
3, 1, 1, 0, 1, 0, // counts 1, 1, 1, 0, 1, 0, // counts
transition); // parameter transition); // parameter
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "src/handles.h" #include "src/handles.h"
#include "src/machine-type.h" #include "src/machine-type.h"
#include "src/objects.h" #include "src/objects.h"
#include "src/zone/zone-handle-set.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -143,6 +144,27 @@ std::ostream& operator<<(std::ostream&, CheckForMinusZeroMode); ...@@ -143,6 +144,27 @@ std::ostream& operator<<(std::ostream&, CheckForMinusZeroMode);
CheckForMinusZeroMode CheckMinusZeroModeOf(const Operator*) WARN_UNUSED_RESULT; CheckForMinusZeroMode CheckMinusZeroModeOf(const Operator*) WARN_UNUSED_RESULT;
// A descriptor for map checks.
class CheckMapsParameters final {
public:
explicit CheckMapsParameters(ZoneHandleSet<Map> const& maps) : maps_(maps) {}
ZoneHandleSet<Map> const& maps() const { return maps_; }
private:
ZoneHandleSet<Map> const maps_;
};
bool operator==(CheckMapsParameters const&, CheckMapsParameters const&);
bool operator!=(CheckMapsParameters const&, CheckMapsParameters const&);
size_t hash_value(CheckMapsParameters const&);
std::ostream& operator<<(std::ostream&, CheckMapsParameters const&);
CheckMapsParameters const& CheckMapsParametersOf(Operator const*)
WARN_UNUSED_RESULT;
// A descriptor for growing elements backing stores. // A descriptor for growing elements backing stores.
enum class GrowFastElementsFlag : uint8_t { enum class GrowFastElementsFlag : uint8_t {
kNone = 0u, kNone = 0u,
...@@ -160,16 +182,35 @@ GrowFastElementsFlags GrowFastElementsFlagsOf(const Operator*) ...@@ -160,16 +182,35 @@ GrowFastElementsFlags GrowFastElementsFlagsOf(const Operator*)
WARN_UNUSED_RESULT; WARN_UNUSED_RESULT;
// A descriptor for elements kind transitions. // A descriptor for elements kind transitions.
enum class ElementsTransition : uint8_t { class ElementsTransition final {
kFastTransition, // simple transition, just updating the map. public:
kSlowTransition // full transition, round-trip to the runtime. enum Mode : uint8_t {
kFastTransition, // simple transition, just updating the map.
kSlowTransition // full transition, round-trip to the runtime.
};
ElementsTransition(Mode mode, Handle<Map> source, Handle<Map> target)
: mode_(mode), source_(source), target_(target) {}
Mode mode() const { return mode_; }
Handle<Map> source() const { return source_; }
Handle<Map> target() const { return target_; }
private:
Mode const mode_;
Handle<Map> const source_;
Handle<Map> const target_;
}; };
bool operator==(ElementsTransition const&, ElementsTransition const&);
bool operator!=(ElementsTransition const&, ElementsTransition const&);
size_t hash_value(ElementsTransition); size_t hash_value(ElementsTransition);
std::ostream& operator<<(std::ostream&, ElementsTransition); std::ostream& operator<<(std::ostream&, ElementsTransition);
ElementsTransition ElementsTransitionOf(const Operator* op) WARN_UNUSED_RESULT; ElementsTransition const& ElementsTransitionOf(const Operator* op)
WARN_UNUSED_RESULT;
// A hint for speculative number operations. // A hint for speculative number operations.
enum class NumberOperationHint : uint8_t { enum class NumberOperationHint : uint8_t {
...@@ -322,7 +363,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final ...@@ -322,7 +363,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* CheckIf(); const Operator* CheckIf();
const Operator* CheckBounds(); const Operator* CheckBounds();
const Operator* CheckMaps(int map_input_count); const Operator* CheckMaps(ZoneHandleSet<Map>);
const Operator* CheckHeapObject(); const Operator* CheckHeapObject();
const Operator* CheckInternalizedString(); const Operator* CheckInternalizedString();
......
...@@ -956,8 +956,6 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -956,8 +956,6 @@ void Verifier::Visitor::Check(Node* node) {
break; break;
case IrOpcode::kTransitionElementsKind: case IrOpcode::kTransitionElementsKind:
CheckValueInputIs(node, 0, Type::Any()); CheckValueInputIs(node, 0, Type::Any());
CheckValueInputIs(node, 1, Type::Internal());
CheckValueInputIs(node, 2, Type::Internal());
CheckNotTyped(node); CheckNotTyped(node);
break; break;
......
...@@ -1327,6 +1327,7 @@ ...@@ -1327,6 +1327,7 @@
'zone/zone-segment.h', 'zone/zone-segment.h',
'zone/zone-allocator.h', 'zone/zone-allocator.h',
'zone/zone-containers.h', 'zone/zone-containers.h',
'zone/zone-handle-set.h',
], ],
'conditions': [ 'conditions': [
['want_separate_host_toolset==1', { ['want_separate_host_toolset==1', {
......
// Copyright 2016 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.
#ifndef V8_ZONE_ZONE_HANDLE_SET_H_
#define V8_ZONE_ZONE_HANDLE_SET_H_
#include "src/handles.h"
#include "src/zone/zone.h"
namespace v8 {
namespace internal {
template <typename T>
class ZoneHandleSet final {
public:
ZoneHandleSet() : data_(kEmptyTag) {}
explicit ZoneHandleSet(Handle<T> handle)
: data_(bit_cast<intptr_t>(handle.address()) | kSingletonTag) {
DCHECK(IsAligned(bit_cast<intptr_t>(handle.address()), kPointerAlignment));
}
bool is_empty() const { return data_ == kEmptyTag; }
size_t size() const {
if ((data_ & kTagMask) == kEmptyTag) return 0;
if ((data_ & kTagMask) == kSingletonTag) return 1;
return list()->length();
}
Handle<T> at(size_t i) const {
DCHECK_NE(kEmptyTag, data_ & kTagMask);
if ((data_ & kTagMask) == kSingletonTag) {
DCHECK_EQ(0u, i);
return Handle<T>(singleton());
}
return Handle<T>(list()->at(static_cast<int>(i)));
}
Handle<T> operator[](size_t i) const { return at(i); }
void insert(Handle<T> handle, Zone* zone) {
T** const value = bit_cast<T**>(handle.address());
DCHECK(IsAligned(bit_cast<intptr_t>(value), kPointerAlignment));
if ((data_ & kTagMask) == kEmptyTag) {
data_ = bit_cast<intptr_t>(value) | kSingletonTag;
} else if ((data_ & kTagMask) == kSingletonTag) {
if (singleton() == value) return;
List* list = new (zone) List(2, zone);
if (singleton() < value) {
list->Add(singleton(), zone);
list->Add(value, zone);
} else {
list->Add(value, zone);
list->Add(singleton(), zone);
}
DCHECK(IsAligned(bit_cast<intptr_t>(list), kPointerAlignment));
data_ = bit_cast<intptr_t>(list) | kListTag;
} else {
DCHECK_EQ(kListTag, data_ & kTagMask);
List const* const old_list = list();
for (int i = 0; i < old_list->length(); ++i) {
if (old_list->at(i) == value) return;
if (old_list->at(i) > value) break;
}
List* new_list = new (zone) List(old_list->length() + 1, zone);
int i = 0;
for (; i < old_list->length(); ++i) {
if (old_list->at(i) > value) break;
new_list->Add(old_list->at(i), zone);
}
new_list->Add(value, zone);
for (; i < old_list->length(); ++i) {
new_list->Add(old_list->at(i), zone);
}
DCHECK_EQ(old_list->length() + 1, new_list->length());
DCHECK(IsAligned(bit_cast<intptr_t>(new_list), kPointerAlignment));
data_ = bit_cast<intptr_t>(new_list) | kListTag;
}
}
bool contains(ZoneHandleSet<T> const& other) const {
if (data_ == other.data_) return true;
if (data_ == kEmptyTag) return false;
if (other.data_ == kEmptyTag) return true;
if ((data_ & kTagMask) == kSingletonTag) return false;
DCHECK_EQ(kListTag, data_ & kTagMask);
if ((other.data_ & kTagMask) == kSingletonTag) {
return list()->Contains(other.singleton());
}
DCHECK_EQ(kListTag, other.data_ & kTagMask);
// TODO(bmeurer): Optimize this case.
for (int i = 0; i < other.list()->length(); ++i) {
if (!list()->Contains(other.list()->at(i))) return false;
}
return true;
}
void remove(Handle<T> handle, Zone* zone) {
// TODO(bmeurer): Optimize this case.
ZoneHandleSet<T> that;
for (size_t i = 0; i < size(); ++i) {
Handle<T> value = at(i);
if (value.address() != handle.address()) {
that.insert(value, zone);
}
}
std::swap(*this, that);
}
friend bool operator==(ZoneHandleSet<T> const& lhs,
ZoneHandleSet<T> const& rhs) {
if (lhs.data_ == rhs.data_) return true;
if ((lhs.data_ & kTagMask) == kListTag &&
(rhs.data_ & kTagMask) == kListTag) {
List const* const lhs_list = lhs.list();
List const* const rhs_list = rhs.list();
if (lhs_list->length() == rhs_list->length()) {
for (int i = 0; i < lhs_list->length(); ++i) {
if (lhs_list->at(i) != rhs_list->at(i)) return false;
}
return true;
}
}
return false;
}
friend bool operator!=(ZoneHandleSet<T> const& lhs,
ZoneHandleSet<T> const& rhs) {
return !(lhs == rhs);
}
friend size_t hash_value(ZoneHandleSet<T> const& set) {
return static_cast<size_t>(set.data_);
}
private:
typedef ZoneList<T**> List;
List const* list() const {
DCHECK_EQ(kListTag, data_ & kTagMask);
return bit_cast<List const*>(data_ - kListTag);
}
T** singleton() const {
DCHECK_EQ(kSingletonTag, data_ & kTagMask);
return bit_cast<T**>(data_ - kSingletonTag);
}
enum Tag : intptr_t {
kSingletonTag = 0,
kEmptyTag = 1,
kListTag = 2,
kTagMask = 3
};
STATIC_ASSERT(kTagMask < kPointerAlignment);
intptr_t data_;
};
} // namespace internal
} // namespace v8
#endif // V8_ZONE_ZONE_HANDLE_SET_H_
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