Commit 589ecbfa authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Utilize maps from field type tracking to eliminate map checks.

Hook up TurboFan with the existing field type tracking machinery to
eliminate redundant map checks on the results of LoadField operators.
The store side is already implemented in TurboFan for quite some time,
this just adds the load part.

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

Review-Url: https://codereview.chromium.org/2604393002
Cr-Commit-Position: refs/heads/master@{#42015}
parent 4f95a1eb
This diff is collapsed.
......@@ -1186,9 +1186,10 @@ Node* JSCreateLowering::AllocateFastLiteral(
Handle<Name> property_name(
boilerplate_map->instance_descriptors()->GetKey(i), isolate());
FieldIndex index = FieldIndex::ForDescriptor(*boilerplate_map, i);
FieldAccess access = {
kTaggedBase, index.offset(), property_name,
Type::Any(), MachineType::AnyTagged(), kFullWriteBarrier};
FieldAccess access = {kTaggedBase, index.offset(),
property_name, MaybeHandle<Map>(),
Type::Any(), MachineType::AnyTagged(),
kFullWriteBarrier};
Node* value;
if (boilerplate->IsUnboxedDoubleField(index)) {
access.machine_type = MachineType::Float64();
......
......@@ -49,7 +49,8 @@ Reduction JSGlobalObjectSpecialization::Reduce(Node* node) {
namespace {
FieldAccess ForPropertyCellValue(MachineRepresentation representation,
Type* type, Handle<Name> name) {
Type* type, MaybeHandle<Map> map,
Handle<Name> name) {
WriteBarrierKind kind = kFullWriteBarrier;
if (representation == MachineRepresentation::kTaggedSigned) {
kind = kNoWriteBarrier;
......@@ -57,8 +58,8 @@ FieldAccess ForPropertyCellValue(MachineRepresentation representation,
kind = kPointerWriteBarrier;
}
MachineType r = MachineType::TypeForRepresentation(representation);
FieldAccess access = {kTaggedBase, PropertyCell::kValueOffset, name, type, r,
kind};
FieldAccess access = {
kTaggedBase, PropertyCell::kValueOffset, name, map, type, r, kind};
return access;
}
} // namespace
......@@ -115,6 +116,7 @@ Reduction JSGlobalObjectSpecialization::ReduceJSLoadGlobal(Node* node) {
}
// Load from constant type cell can benefit from type feedback.
MaybeHandle<Map> map;
Type* property_cell_value_type = Type::NonInternal();
MachineRepresentation representation = MachineRepresentation::kTagged;
if (property_details.cell_type() == PropertyCellType::kConstantType) {
......@@ -126,18 +128,24 @@ Reduction JSGlobalObjectSpecialization::ReduceJSLoadGlobal(Node* node) {
property_cell_value_type = Type::Number();
representation = MachineRepresentation::kTaggedPointer;
} else {
// TODO(turbofan): Track the property_cell_value_map on the FieldAccess
// below and use it in LoadElimination to eliminate map checks.
Handle<Map> property_cell_value_map(
Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
property_cell_value_type = Type::For(property_cell_value_map);
representation = MachineRepresentation::kTaggedPointer;
// We can only use the property cell value map for map check elimination
// if it's stable, i.e. the HeapObject wasn't mutated without the cell
// state being updated.
if (property_cell_value_map->is_stable()) {
dependencies()->AssumeMapStable(property_cell_value_map);
map = property_cell_value_map;
}
}
}
Node* value = effect =
graph()->NewNode(simplified()->LoadField(ForPropertyCellValue(
representation, property_cell_value_type, name)),
jsgraph()->HeapConstant(property_cell), effect, control);
Node* value = effect = graph()->NewNode(
simplified()->LoadField(ForPropertyCellValue(
representation, property_cell_value_type, map, name)),
jsgraph()->HeapConstant(property_cell), effect, control);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
......@@ -218,10 +226,11 @@ Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) {
property_cell_value_type = Type::SignedSmall();
representation = MachineRepresentation::kTaggedSigned;
}
effect = graph()->NewNode(
simplified()->StoreField(ForPropertyCellValue(
representation, property_cell_value_type, name)),
jsgraph()->HeapConstant(property_cell), value, effect, control);
effect = graph()->NewNode(simplified()->StoreField(ForPropertyCellValue(
representation, property_cell_value_type,
MaybeHandle<Map>(), name)),
jsgraph()->HeapConstant(property_cell), value,
effect, control);
break;
}
case PropertyCellType::kMutable: {
......@@ -230,7 +239,8 @@ Reduction JSGlobalObjectSpecialization::ReduceJSStoreGlobal(Node* node) {
dependencies()->AssumePropertyCell(property_cell);
effect = graph()->NewNode(
simplified()->StoreField(ForPropertyCellValue(
MachineRepresentation::kTagged, Type::NonInternal(), name)),
MachineRepresentation::kTagged, Type::NonInternal(),
MaybeHandle<Map>(), name)),
jsgraph()->HeapConstant(property_cell), value, effect, control);
break;
}
......
......@@ -1095,6 +1095,7 @@ JSNativeContextSpecialization::BuildPropertyAccess(
kTaggedBase,
field_index.offset(),
name,
MaybeHandle<Map>(),
field_type,
MachineType::TypeForRepresentation(field_representation),
kFullWriteBarrier};
......@@ -1105,6 +1106,7 @@ JSNativeContextSpecialization::BuildPropertyAccess(
FieldAccess const storage_access = {kTaggedBase,
field_index.offset(),
name,
MaybeHandle<Map>(),
Type::OtherInternal(),
MachineType::TaggedPointer(),
kPointerWriteBarrier};
......@@ -1114,9 +1116,18 @@ JSNativeContextSpecialization::BuildPropertyAccess(
field_access.offset = HeapNumber::kValueOffset;
field_access.name = MaybeHandle<Name>();
}
} else if (field_representation ==
MachineRepresentation::kTaggedPointer) {
// Remember the map of the field value, if its map is stable. This is
// used by the LoadElimination to eliminate map checks on the result.
Handle<Map> field_map;
if (access_info.field_map().ToHandle(&field_map)) {
if (field_map->is_stable()) {
dependencies()->AssumeMapStable(field_map);
field_access.map = field_map;
}
}
}
// TODO(turbofan): Track the field_map (if any) on the {field_access} and
// use it in LoadElimination to eliminate map checks.
value = effect = graph()->NewNode(simplified()->LoadField(field_access),
storage, effect, control);
} else {
......@@ -1153,6 +1164,7 @@ JSNativeContextSpecialization::BuildPropertyAccess(
FieldAccess const storage_access = {kTaggedBase,
field_index.offset(),
name,
MaybeHandle<Map>(),
Type::OtherInternal(),
MachineType::TaggedPointer(),
kPointerWriteBarrier};
......
......@@ -744,6 +744,10 @@ Reduction LoadElimination::ReduceLoadField(Node* node) {
state = state->AddField(object, field_index, node, zone());
}
}
Handle<Map> field_map;
if (access.map.ToHandle(&field_map)) {
state = state->AddMaps(node, ZoneHandleSet<Map>(field_map), zone());
}
return UpdateState(node, state);
}
......
......@@ -92,6 +92,7 @@ bool operator==(FieldAccess const& lhs, FieldAccess const& rhs) {
// really only relevant for eliminating loads and they don't care about the
// write barrier mode.
return lhs.base_is_tagged == rhs.base_is_tagged && lhs.offset == rhs.offset &&
lhs.map.address() == rhs.map.address() &&
lhs.machine_type == rhs.machine_type;
}
......@@ -118,6 +119,10 @@ std::ostream& operator<<(std::ostream& os, FieldAccess const& access) {
name->Print(os);
os << ", ";
}
Handle<Map> map;
if (access.map.ToHandle(&map)) {
os << Brief(*map) << ", ";
}
#endif
access.type->PrintTo(os);
os << ", " << access.machine_type << ", " << access.write_barrier_kind << "]";
......
......@@ -65,6 +65,7 @@ struct FieldAccess {
BaseTaggedness base_is_tagged; // specifies if the base pointer is tagged.
int offset; // offset of the field, without tag.
MaybeHandle<Name> name; // debugging only.
MaybeHandle<Map> map; // map of the field value (if known).
Type* type; // type of the field.
MachineType machine_type; // machine type of the field.
WriteBarrierKind write_barrier_kind; // write barrier hint.
......
......@@ -148,11 +148,9 @@ class EscapeAnalysisTest : public TypedGraphTest {
}
FieldAccess FieldAccessAtIndex(int offset) {
FieldAccess access = {kTaggedBase,
offset,
MaybeHandle<Name>(),
Type::Any(),
MachineType::AnyTagged(),
FieldAccess access = {kTaggedBase, offset,
MaybeHandle<Name>(), MaybeHandle<Map>(),
Type::Any(), MachineType::AnyTagged(),
kFullWriteBarrier};
return access;
}
......
......@@ -125,11 +125,9 @@ TEST_F(LoadEliminationTest, LoadFieldAndLoadField) {
Node* object = Parameter(Type::Any(), 0);
Node* effect = graph()->start();
Node* control = graph()->start();
FieldAccess const access = {kTaggedBase,
kPointerSize,
MaybeHandle<Name>(),
Type::Any(),
MachineType::AnyTagged(),
FieldAccess const access = {kTaggedBase, kPointerSize,
MaybeHandle<Name>(), MaybeHandle<Map>(),
Type::Any(), MachineType::AnyTagged(),
kNoWriteBarrier};
StrictMock<MockAdvancedReducerEditor> editor;
......@@ -154,11 +152,9 @@ TEST_F(LoadEliminationTest, StoreFieldAndLoadField) {
Node* value = Parameter(Type::Any(), 1);
Node* effect = graph()->start();
Node* control = graph()->start();
FieldAccess access = {kTaggedBase,
kPointerSize,
MaybeHandle<Name>(),
Type::Any(),
MachineType::AnyTagged(),
FieldAccess access = {kTaggedBase, kPointerSize,
MaybeHandle<Name>(), MaybeHandle<Map>(),
Type::Any(), MachineType::AnyTagged(),
kNoWriteBarrier};
StrictMock<MockAdvancedReducerEditor> editor;
......@@ -184,11 +180,9 @@ TEST_F(LoadEliminationTest, StoreFieldAndStoreElementAndLoadField) {
Node* index = Parameter(Type::UnsignedSmall(), 2);
Node* effect = graph()->start();
Node* control = graph()->start();
FieldAccess access = {kTaggedBase,
kPointerSize,
MaybeHandle<Name>(),
Type::Any(),
MachineType::AnyTagged(),
FieldAccess access = {kTaggedBase, kPointerSize,
MaybeHandle<Name>(), MaybeHandle<Map>(),
Type::Any(), MachineType::AnyTagged(),
kNoWriteBarrier};
StrictMock<MockAdvancedReducerEditor> editor;
......@@ -288,11 +282,9 @@ TEST_F(LoadEliminationTest, LoadFieldOnFalseBranchOfDiamond) {
Node* check = Parameter(Type::Boolean(), 1);
Node* effect = graph()->start();
Node* control = graph()->start();
FieldAccess const access = {kTaggedBase,
kPointerSize,
MaybeHandle<Name>(),
Type::Any(),
MachineType::AnyTagged(),
FieldAccess const access = {kTaggedBase, kPointerSize,
MaybeHandle<Name>(), MaybeHandle<Map>(),
Type::Any(), MachineType::AnyTagged(),
kNoWriteBarrier};
StrictMock<MockAdvancedReducerEditor> editor;
......@@ -326,11 +318,9 @@ TEST_F(LoadEliminationTest, LoadFieldOnTrueBranchOfDiamond) {
Node* check = Parameter(Type::Boolean(), 1);
Node* effect = graph()->start();
Node* control = graph()->start();
FieldAccess const access = {kTaggedBase,
kPointerSize,
MaybeHandle<Name>(),
Type::Any(),
MachineType::AnyTagged(),
FieldAccess const access = {kTaggedBase, kPointerSize,
MaybeHandle<Name>(), MaybeHandle<Map>(),
Type::Any(), MachineType::AnyTagged(),
kNoWriteBarrier};
StrictMock<MockAdvancedReducerEditor> editor;
......@@ -364,11 +354,9 @@ TEST_F(LoadEliminationTest, LoadFieldWithTypeMismatch) {
Node* value = Parameter(Type::Signed32(), 1);
Node* effect = graph()->start();
Node* control = graph()->start();
FieldAccess const access = {kTaggedBase,
kPointerSize,
MaybeHandle<Name>(),
Type::Unsigned31(),
MachineType::AnyTagged(),
FieldAccess const access = {kTaggedBase, kPointerSize,
MaybeHandle<Name>(), MaybeHandle<Map>(),
Type::Unsigned31(), MachineType::AnyTagged(),
kNoWriteBarrier};
StrictMock<MockAdvancedReducerEditor> editor;
......@@ -422,11 +410,9 @@ TEST_F(LoadEliminationTest, AliasAnalysisForFinishRegion) {
Node* value1 = Parameter(Type::Signed32(), 1);
Node* effect = graph()->start();
Node* control = graph()->start();
FieldAccess const access = {kTaggedBase,
kPointerSize,
MaybeHandle<Name>(),
Type::Signed32(),
MachineType::AnyTagged(),
FieldAccess const access = {kTaggedBase, kPointerSize,
MaybeHandle<Name>(), MaybeHandle<Map>(),
Type::Signed32(), MachineType::AnyTagged(),
kNoWriteBarrier};
StrictMock<MockAdvancedReducerEditor> editor;
......
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