[turbofan] Split DependentCode::kFieldOwner group

This patch will allow turboprop to selectively turn off const based
optimizations.

Change-Id: Icd0ec29968287a428cbf38857191900dbf3fda36
Bug: v8:9684, v8:10431
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2149429
Commit-Queue: Sathya Gunasekaran  <gsathya@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67355}
This commit is contained in:
Sathya Gunasekaran 2020-04-23 22:03:02 +01:00 committed by Commit Bot
parent 7712da4d49
commit 6acbbfbe31
7 changed files with 142 additions and 56 deletions

View File

@ -176,7 +176,7 @@ class FieldRepresentationDependency final : public CompilationDependency {
void Install(const MaybeObjectHandle& code) const override {
SLOW_DCHECK(IsValid());
DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
DependentCode::kFieldOwnerGroup);
DependentCode::kFieldRepresentationGroup);
}
private:
@ -206,7 +206,7 @@ class FieldTypeDependency final : public CompilationDependency {
void Install(const MaybeObjectHandle& code) const override {
SLOW_DCHECK(IsValid());
DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
DependentCode::kFieldOwnerGroup);
DependentCode::kFieldTypeGroup);
}
private:
@ -234,7 +234,7 @@ class FieldConstnessDependency final : public CompilationDependency {
void Install(const MaybeObjectHandle& code) const override {
SLOW_DCHECK(IsValid());
DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
DependentCode::kFieldOwnerGroup);
DependentCode::kFieldConstGroup);
}
private:

View File

@ -1026,8 +1026,12 @@ const char* DependentCode::DependencyGroupName(DependencyGroup group) {
return "prototype-check";
case kPropertyCellChangedGroup:
return "property-cell-changed";
case kFieldOwnerGroup:
return "field-owner";
case kFieldConstGroup:
return "field-const";
case kFieldTypeGroup:
return "field-type";
case kFieldRepresentationGroup:
return "field-representation";
case kInitialMapChangedGroup:
return "initial-map-changed";
case kAllocationSiteTenuringChangedGroup:

View File

@ -651,7 +651,9 @@ class DependentCode : public WeakFixedArray {
kPropertyCellChangedGroup,
// Group of code that omit run-time checks for field(s) introduced by
// this map, i.e. for the field type.
kFieldOwnerGroup,
kFieldTypeGroup,
kFieldConstGroup,
kFieldRepresentationGroup,
// Group of code that omit run-time type checks for initial maps of
// constructors.
kInitialMapChangedGroup,
@ -719,8 +721,8 @@ class DependentCode : public WeakFixedArray {
inline int flags();
inline void set_flags(int flags);
using GroupField = base::BitField<int, 0, 3>;
using CountField = base::BitField<int, 3, 27>;
using GroupField = base::BitField<int, 0, 5>;
using CountField = base::BitField<int, 5, 27>;
STATIC_ASSERT(kGroupCount <= GroupField::kMax + 1);
OBJECT_CONSTRUCTORS(DependentCode, WeakFixedArray);

View File

@ -63,6 +63,15 @@ bool FieldType::NowIs(FieldType other) const {
return *this == other;
}
bool FieldType::Equals(FieldType other) const {
if (IsAny() && other.IsAny()) return true;
if (IsNone() && other.IsNone()) return true;
if (IsClass() && other.IsClass()) {
return *this == other;
}
return false;
}
bool FieldType::NowIs(Handle<FieldType> other) const { return NowIs(*other); }
void FieldType::PrintTo(std::ostream& os) const {

View File

@ -41,6 +41,7 @@ class FieldType : public Object {
bool NowIs(FieldType other) const;
bool NowIs(Handle<FieldType> other) const;
V8_EXPORT_PRIVATE bool Equals(FieldType other) const;
V8_EXPORT_PRIVATE void PrintTo(std::ostream& os) const;
private:

View File

@ -797,8 +797,21 @@ void Map::GeneralizeField(Isolate* isolate, Handle<Map> map,
MaybeObjectHandle wrapped_type(WrapFieldType(isolate, new_field_type));
field_owner->UpdateFieldType(isolate, modify_index, name, new_constness,
new_representation, wrapped_type);
field_owner->dependent_code().DeoptimizeDependentCodeGroup(
DependentCode::kFieldOwnerGroup);
if (new_constness != old_constness) {
field_owner->dependent_code().DeoptimizeDependentCodeGroup(
DependentCode::kFieldConstGroup);
}
if (!new_field_type->Equals(*old_field_type)) {
field_owner->dependent_code().DeoptimizeDependentCodeGroup(
DependentCode::kFieldTypeGroup);
}
if (!new_representation.Equals(old_representation)) {
field_owner->dependent_code().DeoptimizeDependentCodeGroup(
DependentCode::kFieldRepresentationGroup);
}
if (FLAG_trace_generalization) {
map->PrintGeneralization(

View File

@ -31,12 +31,10 @@ namespace test_field_type_tracking {
// and observed transitions caused generalization of all fields).
const bool IS_PROTO_TRANS_ISSUE_FIXED = false;
// TODO(ishell): fix this once TransitionToAccessorProperty is able to always
// keep map in fast mode.
const bool IS_ACCESSOR_FIELD_SUPPORTED = false;
// Number of properties used in the tests.
const int kPropCount = 7;
@ -606,6 +604,33 @@ Handle<Code> CreateDummyOptimizedCode(Isolate* isolate) {
.Build();
}
static void CheckCodeObjectForDeopt(const CRFTData& from,
const CRFTData& expected,
Handle<Code> code_field_type,
Handle<Code> code_field_repr,
Handle<Code> code_field_const,
bool expected_deopt) {
if (!from.type->Equals(*expected.type)) {
CHECK_EQ(expected_deopt, code_field_type->marked_for_deoptimization());
} else {
CHECK(!code_field_type->marked_for_deoptimization());
}
if (!from.representation.Equals(expected.representation)) {
CHECK_EQ(expected_deopt, code_field_repr->marked_for_deoptimization());
} else {
CHECK(!code_field_repr->marked_for_deoptimization());
}
if (!code_field_const.is_null()) {
if (from.constness != expected.constness) {
CHECK_EQ(expected_deopt, code_field_const->marked_for_deoptimization());
} else {
CHECK(!code_field_const->marked_for_deoptimization());
}
}
}
// This test ensures that field generalization at |property_index| is done
// correctly independently of the fact that the |map| is detached from
// transition tree or not.
@ -668,13 +693,23 @@ void TestGeneralizeField(int detach_property_at_index, int property_index,
// Create dummy optimized code object to test correct dependencies
// on the field owner.
Handle<Code> code = CreateDummyOptimizedCode(isolate);
Handle<Code> code_field_type = CreateDummyOptimizedCode(isolate);
Handle<Code> code_field_repr = CreateDummyOptimizedCode(isolate);
Handle<Code> code_field_const = CreateDummyOptimizedCode(isolate);
Handle<Map> field_owner(
map->FindFieldOwner(isolate, InternalIndex(property_index)), isolate);
DependentCode::InstallDependency(isolate, MaybeObjectHandle::Weak(code),
field_owner,
DependentCode::kFieldOwnerGroup);
CHECK(!code->marked_for_deoptimization());
DependentCode::InstallDependency(isolate,
MaybeObjectHandle::Weak(code_field_type),
field_owner, DependentCode::kFieldTypeGroup);
DependentCode::InstallDependency(
isolate, MaybeObjectHandle::Weak(code_field_repr), field_owner,
DependentCode::kFieldRepresentationGroup);
DependentCode::InstallDependency(
isolate, MaybeObjectHandle::Weak(code_field_const), field_owner,
DependentCode::kFieldConstGroup);
CHECK(!code_field_type->marked_for_deoptimization());
CHECK(!code_field_repr->marked_for_deoptimization());
CHECK(!code_field_const->marked_for_deoptimization());
// Create new maps by generalizing representation of propX field.
Handle<Map> new_map =
@ -687,29 +722,28 @@ void TestGeneralizeField(int detach_property_at_index, int property_index,
CHECK(!new_map->is_deprecated());
CHECK(expectations.Check(*new_map));
bool should_deopt = false;
if (is_detached_map) {
CHECK(!map->is_stable());
CHECK(map->is_deprecated());
CHECK_NE(*map, *new_map);
CHECK_EQ(expected_field_owner_dependency && !field_owner->is_deprecated(),
code->marked_for_deoptimization());
should_deopt =
expected_field_owner_dependency && !field_owner->is_deprecated();
} else if (expected_deprecation) {
CHECK(!map->is_stable());
CHECK(map->is_deprecated());
CHECK(field_owner->is_deprecated());
CHECK_NE(*map, *new_map);
CHECK(!code->marked_for_deoptimization());
should_deopt = false;
} else {
CHECK(!field_owner->is_deprecated());
CHECK(map->is_stable()); // Map did not change, must be left stable.
CHECK_EQ(*map, *new_map);
CHECK_EQ(expected_field_owner_dependency,
code->marked_for_deoptimization());
should_deopt = expected_field_owner_dependency;
}
CheckCodeObjectForDeopt(from, expected, code_field_type, code_field_repr,
code_field_const, should_deopt);
{
// Check that all previous maps are not stable.
Map tmp = *new_map;
@ -1002,7 +1036,6 @@ TEST(GeneralizeFieldWithAccessorProperties) {
}
}
////////////////////////////////////////////////////////////////////////////////
// A set of tests for attribute reconfiguration case.
//
@ -1035,7 +1068,6 @@ void TestReconfigureDataFieldAttribute_GeneralizeField(
CHECK(map->is_stable());
CHECK(expectations.Check(*map));
// Create another branch in transition tree (property at index |kSplitProp|
// has different attributes), initialize expectations.
const int kSplitProp = kPropCount / 2;
@ -1059,13 +1091,23 @@ void TestReconfigureDataFieldAttribute_GeneralizeField(
// Create dummy optimized code object to test correct dependencies
// on the field owner.
Handle<Code> code = CreateDummyOptimizedCode(isolate);
Handle<Code> code_field_type = CreateDummyOptimizedCode(isolate);
Handle<Code> code_field_repr = CreateDummyOptimizedCode(isolate);
Handle<Code> code_field_const = CreateDummyOptimizedCode(isolate);
Handle<Map> field_owner(
map->FindFieldOwner(isolate, InternalIndex(kSplitProp)), isolate);
DependentCode::InstallDependency(isolate, MaybeObjectHandle::Weak(code),
field_owner,
DependentCode::kFieldOwnerGroup);
CHECK(!code->marked_for_deoptimization());
DependentCode::InstallDependency(isolate,
MaybeObjectHandle::Weak(code_field_type),
field_owner, DependentCode::kFieldTypeGroup);
DependentCode::InstallDependency(
isolate, MaybeObjectHandle::Weak(code_field_repr), field_owner,
DependentCode::kFieldRepresentationGroup);
DependentCode::InstallDependency(
isolate, MaybeObjectHandle::Weak(code_field_const), field_owner,
DependentCode::kFieldConstGroup);
CHECK(!code_field_type->marked_for_deoptimization());
CHECK(!code_field_repr->marked_for_deoptimization());
CHECK(!code_field_const->marked_for_deoptimization());
// Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which
// should generalize representations in |map1|.
@ -1085,7 +1127,9 @@ void TestReconfigureDataFieldAttribute_GeneralizeField(
expected.type);
}
CHECK(map->is_deprecated());
CHECK(!code->marked_for_deoptimization());
CHECK(!code_field_type->marked_for_deoptimization());
CHECK(!code_field_repr->marked_for_deoptimization());
CHECK(!code_field_const->marked_for_deoptimization());
CHECK_NE(*map, *new_map);
CHECK(!new_map->is_deprecated());
@ -1125,7 +1169,6 @@ void TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
CHECK(map->is_stable());
CHECK(expectations.Check(*map));
// Create another branch in transition tree (property at index |kSplitProp|
// has different attributes), initialize expectations.
const int kSplitProp = kPropCount / 2;
@ -1149,13 +1192,23 @@ void TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
// Create dummy optimized code object to test correct dependencies
// on the field owner.
Handle<Code> code = CreateDummyOptimizedCode(isolate);
Handle<Code> code_field_type = CreateDummyOptimizedCode(isolate);
Handle<Code> code_field_repr = CreateDummyOptimizedCode(isolate);
Handle<Code> code_field_const = CreateDummyOptimizedCode(isolate);
Handle<Map> field_owner(
map->FindFieldOwner(isolate, InternalIndex(kSplitProp)), isolate);
DependentCode::InstallDependency(isolate, MaybeObjectHandle::Weak(code),
field_owner,
DependentCode::kFieldOwnerGroup);
CHECK(!code->marked_for_deoptimization());
DependentCode::InstallDependency(isolate,
MaybeObjectHandle::Weak(code_field_type),
field_owner, DependentCode::kFieldTypeGroup);
DependentCode::InstallDependency(
isolate, MaybeObjectHandle::Weak(code_field_repr), field_owner,
DependentCode::kFieldRepresentationGroup);
DependentCode::InstallDependency(
isolate, MaybeObjectHandle::Weak(code_field_const), field_owner,
DependentCode::kFieldConstGroup);
CHECK(!code_field_type->marked_for_deoptimization());
CHECK(!code_field_repr->marked_for_deoptimization());
CHECK(!code_field_const->marked_for_deoptimization());
// Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which
// should generalize representations in |map1|.
@ -1179,7 +1232,8 @@ void TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
}
CHECK(!map->is_deprecated());
CHECK_EQ(*map, *new_map);
CHECK_EQ(expected_field_owner_dependency, code->marked_for_deoptimization());
CheckCodeObjectForDeopt(from, expected, code_field_type, code_field_repr,
code_field_const, expected_field_owner_dependency);
CHECK(!new_map->is_deprecated());
CHECK(expectations.Check(*new_map));
@ -1364,7 +1418,6 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjectFieldToTagged) {
{PropertyConstness::kMutable, Representation::Tagged(), any_type});
}
// Checks that given |map| is deprecated and that it updates to given |new_map|
// which in turn should match expectations.
struct CheckDeprecated {
@ -1383,7 +1436,6 @@ struct CheckDeprecated {
}
};
// Checks that given |map| is NOT deprecated, equals to given |new_map| and
// matches expectations.
struct CheckSameMap {
@ -1403,7 +1455,6 @@ struct CheckSameMap {
}
};
// Checks that given |map| is NOT deprecated and matches expectations.
// |new_map| is unrelated to |map|.
struct CheckUnrelated {
@ -1471,7 +1522,6 @@ static void TestReconfigureProperty_CustomPropertyAfterTargetMap(
CHECK(map->is_stable());
CHECK(expectations.Check(*map));
// Create branch to |map1|.
Handle<Map> map1 = map;
Expectations expectations1 = expectations;
@ -1488,7 +1538,6 @@ static void TestReconfigureProperty_CustomPropertyAfterTargetMap(
CHECK(map1->is_stable());
CHECK(expectations1.Check(*map1));
// Create another branch in transition tree (property at index |kSplitProp|
// has different attributes), initialize expectations.
Handle<Map> map2 = map;
@ -1508,7 +1557,6 @@ static void TestReconfigureProperty_CustomPropertyAfterTargetMap(
CHECK(map2->is_stable());
CHECK(expectations2.Check(*map2));
// Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which
// should generalize representations in |map1|.
Handle<Map> new_map =
@ -1555,7 +1603,6 @@ TEST(ReconfigureDataFieldAttribute_SameDataConstantAfterTargetMap) {
TestReconfigureProperty_CustomPropertyAfterTargetMap(&config, &checker);
}
TEST(ReconfigureDataFieldAttribute_DataConstantToDataFieldAfterTargetMap) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
@ -1600,7 +1647,6 @@ TEST(ReconfigureDataFieldAttribute_DataConstantToDataFieldAfterTargetMap) {
TestReconfigureProperty_CustomPropertyAfterTargetMap(&config, &checker);
}
TEST(ReconfigureDataFieldAttribute_DataConstantToAccConstantAfterTargetMap) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
@ -1795,13 +1841,23 @@ static void TestReconfigureElementsKind_GeneralizeFieldTrivial(
// Create dummy optimized code object to test correct dependencies
// on the field owner.
Handle<Code> code = CreateDummyOptimizedCode(isolate);
Handle<Code> code_field_type = CreateDummyOptimizedCode(isolate);
Handle<Code> code_field_repr = CreateDummyOptimizedCode(isolate);
Handle<Code> code_field_const = CreateDummyOptimizedCode(isolate);
Handle<Map> field_owner(
map->FindFieldOwner(isolate, InternalIndex(kDiffProp)), isolate);
DependentCode::InstallDependency(isolate, MaybeObjectHandle::Weak(code),
field_owner,
DependentCode::kFieldOwnerGroup);
CHECK(!code->marked_for_deoptimization());
DependentCode::InstallDependency(isolate,
MaybeObjectHandle::Weak(code_field_type),
field_owner, DependentCode::kFieldTypeGroup);
DependentCode::InstallDependency(
isolate, MaybeObjectHandle::Weak(code_field_repr), field_owner,
DependentCode::kFieldRepresentationGroup);
DependentCode::InstallDependency(
isolate, MaybeObjectHandle::Weak(code_field_const), field_owner,
DependentCode::kFieldConstGroup);
CHECK(!code_field_type->marked_for_deoptimization());
CHECK(!code_field_repr->marked_for_deoptimization());
CHECK(!code_field_const->marked_for_deoptimization());
// Reconfigure elements kinds of |map2|, which should generalize
// representations in |map|.
@ -1823,7 +1879,9 @@ static void TestReconfigureElementsKind_GeneralizeFieldTrivial(
CHECK(!map->is_deprecated());
CHECK_EQ(*map, *new_map);
CHECK_EQ(IsGeneralizableTo(to.constness, from.constness),
!code->marked_for_deoptimization());
!code_field_const->marked_for_deoptimization());
CheckCodeObjectForDeopt(from, expected, code_field_type, code_field_repr,
Handle<Code>(), false);
CHECK(!new_map->is_deprecated());
CHECK(expectations.Check(*new_map));
@ -2288,7 +2346,6 @@ TEST(ElementsKindTransitionFromMapOwningDescriptor) {
}
}
TEST(ElementsKindTransitionFromMapNotOwningDescriptor) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());