Revert "[map] Support in-place field representation changes."
This reverts commit 1416d5a565
.
Reason for revert: blocks roll https://chromium-review.googlesource.com/c/chromium/src/+/1564550
Original change's description:
> [map] Support in-place field representation changes.
>
> This adds a new flag --modify-field-representation-inplace (enabled by
> default), which lets the runtime perform field representation changes
> for Smi to Tagged or for HeapObject to Tagged in-place instead of
> creating new maps and marking the previous map tree as deprecated.
>
> That means we create (a lot) fewer Maps and DescriptorArrays in the
> beginning and also need to self-heal fewer objects later (migrating
> off the deprecated maps). In TurboFan we just take the "field owner
> dependency" whenever we use the field representation, which is very
> similar to what we already do for the field types. That means if we
> change the representation of a field that we used in optimized code,
> we will simply deoptimize that code and have TurboFan potentially
> later optimize it again with the new field representation.
>
> On the Speedometer2/ElmJS-TodoMVC test, this reduces the total execution
> time from around 415ms to around 352ms, which corresponds to a **15%**
> improvement. The overall Speedometer2 score improves from around 74.1
> to around 78.3 (on local runs with content_shell), corresponding to a
> **5.6%** improvement here. 🎉
>
> On the CNN desktop browsing story, it seems that we reduce map space
> utilization/fragmentation by about 4-5%. But since we allocate a lot
> less (fewer Maps and DescriptorArrays) we also significantly change
> the GC timing, which heavily influences the results here. So take this
> with a grain of salt. 🤷♂️
>
> Note: For Double fields, this doesn't change anything, meaning they
> still create new maps and deprecate the previous map trees.
>
> Bug: v8:8749, v8:8865, v8:9114
> Change-Id: I694a53f87ae5caeb868fd98a21809b66d4297d35
> Cq-Include-Trybots: luci.chromium.try:linux-blink-rel
> Doc: http://bit.ly/v8-in-place-field-representation-changes
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1561132
> Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
> Reviewed-by: Igor Sheludko <ishell@chromium.org>
> Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
> Reviewed-by: Georg Neis <neis@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#60764}
TBR=jarin@chromium.org,neis@chromium.org,ishell@chromium.org,bmeurer@chromium.org,verwaest@chromium.org
# Not skipping CQ checks because original CL landed > 1 day ago.
Bug: v8:8749, v8:8865, v8:9114
Change-Id: I666975d08d51bbe7ab4faec9428b9a1f88e9b322
Cq-Include-Trybots: luci.chromium.try:linux-blink-rel
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1564208
Reviewed-by: Michael Hablich <hablich@chromium.org>
Commit-Queue: Michael Hablich <hablich@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60807}
This commit is contained in:
parent
e4b5fcebdf
commit
48efe388d8
@ -319,12 +319,9 @@ bool AccessInfoFactory::ComputeDataFieldAccessInfo(
|
||||
Type field_type = Type::NonInternal();
|
||||
MachineRepresentation field_representation = MachineRepresentation::kTagged;
|
||||
MaybeHandle<Map> field_map;
|
||||
MapRef map_ref(broker(), map);
|
||||
if (details_representation.IsSmi()) {
|
||||
field_type = Type::SignedSmall();
|
||||
field_representation = MachineRepresentation::kTaggedSigned;
|
||||
map_ref.SerializeOwnDescriptors(); // TODO(neis): Remove later.
|
||||
dependencies()->DependOnFieldRepresentation(map_ref, number);
|
||||
} else if (details_representation.IsDouble()) {
|
||||
field_type = type_cache_->kFloat64;
|
||||
field_representation = MachineRepresentation::kFloat64;
|
||||
@ -340,10 +337,9 @@ bool AccessInfoFactory::ComputeDataFieldAccessInfo(
|
||||
|
||||
// The field type was cleared by the GC, so we don't know anything
|
||||
// about the contents now.
|
||||
}
|
||||
map_ref.SerializeOwnDescriptors(); // TODO(neis): Remove later.
|
||||
dependencies()->DependOnFieldRepresentation(map_ref, number);
|
||||
if (descriptors_field_type->IsClass()) {
|
||||
} else if (descriptors_field_type->IsClass()) {
|
||||
MapRef map_ref(broker(), map);
|
||||
map_ref.SerializeOwnDescriptors(); // TODO(neis): Remove later.
|
||||
dependencies()->DependOnFieldType(map_ref, number);
|
||||
// Remember the field map, and try to infer a useful type.
|
||||
Handle<Map> map(descriptors_field_type->AsClass(), isolate());
|
||||
@ -703,12 +699,9 @@ bool AccessInfoFactory::LookupTransition(
|
||||
Type field_type = Type::NonInternal();
|
||||
MaybeHandle<Map> field_map;
|
||||
MachineRepresentation field_representation = MachineRepresentation::kTagged;
|
||||
MapRef transition_map_ref(broker(), transition_map);
|
||||
if (details_representation.IsSmi()) {
|
||||
field_type = Type::SignedSmall();
|
||||
field_representation = MachineRepresentation::kTaggedSigned;
|
||||
transition_map_ref.SerializeOwnDescriptors(); // TODO(neis): Remove later.
|
||||
dependencies()->DependOnFieldRepresentation(transition_map_ref, number);
|
||||
} else if (details_representation.IsDouble()) {
|
||||
field_type = type_cache_->kFloat64;
|
||||
field_representation = MachineRepresentation::kFloat64;
|
||||
@ -722,10 +715,10 @@ bool AccessInfoFactory::LookupTransition(
|
||||
if (descriptors_field_type->IsNone()) {
|
||||
// Store is not safe if the field type was cleared.
|
||||
return false;
|
||||
}
|
||||
transition_map_ref.SerializeOwnDescriptors(); // TODO(neis): Remove later.
|
||||
dependencies()->DependOnFieldRepresentation(transition_map_ref, number);
|
||||
if (descriptors_field_type->IsClass()) {
|
||||
} else if (descriptors_field_type->IsClass()) {
|
||||
MapRef transition_map_ref(broker(), transition_map);
|
||||
transition_map_ref
|
||||
.SerializeOwnDescriptors(); // TODO(neis): Remove later.
|
||||
dependencies()->DependOnFieldType(transition_map_ref, number);
|
||||
// Remember the field map, and try to infer a useful type.
|
||||
Handle<Map> map(descriptors_field_type->AsClass(), isolate());
|
||||
|
@ -163,41 +163,6 @@ class PretenureModeDependency final
|
||||
AllocationType allocation_;
|
||||
};
|
||||
|
||||
class FieldRepresentationDependency final
|
||||
: public CompilationDependencies::Dependency {
|
||||
public:
|
||||
// TODO(neis): Once the concurrent compiler frontend is always-on, we no
|
||||
// longer need to explicitly store the representation.
|
||||
FieldRepresentationDependency(const MapRef& owner, int descriptor,
|
||||
Representation representation)
|
||||
: owner_(owner),
|
||||
descriptor_(descriptor),
|
||||
representation_(representation) {
|
||||
DCHECK(owner_.equals(owner_.FindFieldOwner(descriptor_)));
|
||||
DCHECK(representation_.Equals(
|
||||
owner_.GetPropertyDetails(descriptor_).representation()));
|
||||
}
|
||||
|
||||
bool IsValid() const override {
|
||||
DisallowHeapAllocation no_heap_allocation;
|
||||
Handle<Map> owner = owner_.object();
|
||||
return representation_.Equals(owner->instance_descriptors()
|
||||
->GetDetails(descriptor_)
|
||||
.representation());
|
||||
}
|
||||
|
||||
void Install(const MaybeObjectHandle& code) override {
|
||||
SLOW_DCHECK(IsValid());
|
||||
DependentCode::InstallDependency(owner_.isolate(), code, owner_.object(),
|
||||
DependentCode::kFieldOwnerGroup);
|
||||
}
|
||||
|
||||
private:
|
||||
MapRef owner_;
|
||||
int descriptor_;
|
||||
Representation representation_;
|
||||
};
|
||||
|
||||
class FieldTypeDependency final : public CompilationDependencies::Dependency {
|
||||
public:
|
||||
// TODO(neis): Once the concurrent compiler frontend is always-on, we no
|
||||
@ -445,16 +410,6 @@ PropertyConstness CompilationDependencies::DependOnFieldConstness(
|
||||
return PropertyConstness::kConst;
|
||||
}
|
||||
|
||||
void CompilationDependencies::DependOnFieldRepresentation(const MapRef& map,
|
||||
int descriptor) {
|
||||
MapRef owner = map.FindFieldOwner(descriptor);
|
||||
PropertyDetails details = owner.GetPropertyDetails(descriptor);
|
||||
DCHECK(details.representation().Equals(
|
||||
map.GetPropertyDetails(descriptor).representation()));
|
||||
dependencies_.push_front(new (zone_) FieldRepresentationDependency(
|
||||
owner, descriptor, details.representation()));
|
||||
}
|
||||
|
||||
void CompilationDependencies::DependOnFieldType(const MapRef& map,
|
||||
int descriptor) {
|
||||
MapRef owner = map.FindFieldOwner(descriptor);
|
||||
|
@ -51,10 +51,6 @@ class V8_EXPORT_PRIVATE CompilationDependencies : public ZoneObject {
|
||||
// not change.
|
||||
AllocationType DependOnPretenureMode(const AllocationSiteRef& site);
|
||||
|
||||
// Record the assumption that the field representation of a field does not
|
||||
// change. The field is identified by the arguments.
|
||||
void DependOnFieldRepresentation(const MapRef& map, int descriptor);
|
||||
|
||||
// Record the assumption that the field type of a field does not change. The
|
||||
// field is identified by the arguments.
|
||||
void DependOnFieldType(const MapRef& map, int descriptor);
|
||||
|
@ -1040,8 +1040,6 @@ DEFINE_BOOL_READONLY(track_constant_fields, true,
|
||||
"enable constant field tracking")
|
||||
DEFINE_BOOL_READONLY(fast_map_update, false,
|
||||
"enable fast map update by caching the migration target")
|
||||
DEFINE_BOOL(modify_field_representation_inplace, true,
|
||||
"enable in-place field representation updates")
|
||||
DEFINE_INT(max_polymorphic_map_count, 4,
|
||||
"maximum number of maps to track in POLYMORPHIC state")
|
||||
|
||||
|
@ -211,9 +211,6 @@ MapUpdater::State MapUpdater::CopyGeneralizeAllFields(const char* reason) {
|
||||
}
|
||||
|
||||
MapUpdater::State MapUpdater::TryReconfigureToDataFieldInplace() {
|
||||
// Updating deprecated maps in-place doesn't make sense.
|
||||
if (old_map_->is_deprecated()) return state_;
|
||||
|
||||
// If it's just a representation generalization case (i.e. property kind and
|
||||
// attributes stays unchanged) it's fine to transition from None to anything
|
||||
// but double without any modification to the object, because the default
|
||||
@ -226,7 +223,7 @@ MapUpdater::State MapUpdater::TryReconfigureToDataFieldInplace() {
|
||||
PropertyDetails old_details =
|
||||
old_descriptors_->GetDetails(modified_descriptor_);
|
||||
Representation old_representation = old_details.representation();
|
||||
if (!old_representation.CanBeInPlaceChangedTo(new_representation_)) {
|
||||
if (!old_representation.IsNone()) {
|
||||
return state_; // Not done yet.
|
||||
}
|
||||
|
||||
|
@ -748,14 +748,12 @@ void Map::UpdateFieldType(Isolate* isolate, int descriptor, Handle<Name> name,
|
||||
DescriptorArray descriptors = current->instance_descriptors();
|
||||
PropertyDetails details = descriptors->GetDetails(descriptor);
|
||||
|
||||
// It is allowed to change representation here only from None
|
||||
// to something or from Smi or HeapObject to Tagged.
|
||||
// It is allowed to change representation here only from None to something.
|
||||
DCHECK(details.representation().Equals(new_representation) ||
|
||||
details.representation().CanBeInPlaceChangedTo(new_representation));
|
||||
details.representation().IsNone());
|
||||
|
||||
// Skip if already updated the shared descriptor.
|
||||
if (new_constness != details.constness() ||
|
||||
!new_representation.Equals(details.representation()) ||
|
||||
descriptors->GetFieldType(descriptor) != *new_wrapped_type.object()) {
|
||||
DCHECK_IMPLIES(!FLAG_track_constant_fields,
|
||||
new_constness == PropertyConstness::kMutable);
|
||||
|
@ -116,12 +116,6 @@ class Representation {
|
||||
return Equals(other);
|
||||
}
|
||||
|
||||
bool CanBeInPlaceChangedTo(const Representation& other) const {
|
||||
if (IsNone()) return true;
|
||||
if (!FLAG_modify_field_representation_inplace) return false;
|
||||
return (IsSmi() || IsHeapObject()) && other.IsTagged();
|
||||
}
|
||||
|
||||
bool is_more_general_than(const Representation& other) const {
|
||||
if (IsHeapObject()) return other.IsNone();
|
||||
return kind_ > other.kind_;
|
||||
|
@ -646,7 +646,7 @@ void TestGeneralizeField(int detach_property_at_index, int property_index,
|
||||
from.representation, from.type);
|
||||
} else {
|
||||
map = expectations.AddDataField(map, NONE, kDefaultFieldConstness,
|
||||
Representation::Double(), any_type);
|
||||
Representation::Smi(), any_type);
|
||||
if (i == detach_property_at_index) {
|
||||
detach_point_map = map;
|
||||
}
|
||||
@ -801,9 +801,7 @@ TEST(GeneralizeSmiFieldToTagged) {
|
||||
TestGeneralizeField(
|
||||
{PropertyConstness::kMutable, Representation::Smi(), any_type},
|
||||
{PropertyConstness::kMutable, Representation::HeapObject(), value_type},
|
||||
{PropertyConstness::kMutable, Representation::Tagged(), any_type},
|
||||
!FLAG_modify_field_representation_inplace,
|
||||
FLAG_modify_field_representation_inplace);
|
||||
{PropertyConstness::kMutable, Representation::Tagged(), any_type});
|
||||
}
|
||||
|
||||
TEST(GeneralizeDoubleFieldToTagged) {
|
||||
@ -833,9 +831,7 @@ TEST(GeneralizeHeapObjectFieldToTagged) {
|
||||
TestGeneralizeField(
|
||||
{PropertyConstness::kMutable, Representation::HeapObject(), value_type},
|
||||
{PropertyConstness::kMutable, Representation::Smi(), any_type},
|
||||
{PropertyConstness::kMutable, Representation::Tagged(), any_type},
|
||||
!FLAG_modify_field_representation_inplace,
|
||||
FLAG_modify_field_representation_inplace);
|
||||
{PropertyConstness::kMutable, Representation::Tagged(), any_type});
|
||||
}
|
||||
|
||||
TEST(GeneralizeHeapObjectFieldToHeapObject) {
|
||||
@ -2256,9 +2252,10 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) {
|
||||
// IS_PROTO_TRANS_ISSUE_FIXED and IS_NON_EQUIVALENT_TRANSITION_SUPPORTED are
|
||||
// fixed.
|
||||
template <typename TestConfig>
|
||||
static void TestGeneralizeFieldWithSpecialTransition(
|
||||
TestConfig& config, const CRFTData& from, const CRFTData& to,
|
||||
const CRFTData& expected, bool expected_deprecation) {
|
||||
static void TestGeneralizeFieldWithSpecialTransition(TestConfig& config,
|
||||
const CRFTData& from,
|
||||
const CRFTData& to,
|
||||
const CRFTData& expected) {
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Expectations expectations(isolate);
|
||||
@ -2304,46 +2301,39 @@ static void TestGeneralizeFieldWithSpecialTransition(
|
||||
expectations.SetDataField(i, expected.constness, expected.representation,
|
||||
expected.type);
|
||||
|
||||
if (expected_deprecation) {
|
||||
CHECK(map->is_deprecated());
|
||||
CHECK_NE(*map, *new_map);
|
||||
CHECK(i == 0 || maps[i - 1]->is_deprecated());
|
||||
CHECK(expectations.Check(*new_map));
|
||||
CHECK(map->is_deprecated());
|
||||
CHECK_NE(*map, *new_map);
|
||||
CHECK(i == 0 || maps[i - 1]->is_deprecated());
|
||||
CHECK(expectations.Check(*new_map));
|
||||
|
||||
Handle<Map> new_map2 = Map::Update(isolate, map2);
|
||||
CHECK(!new_map2->is_deprecated());
|
||||
CHECK(!new_map2->is_dictionary_map());
|
||||
Handle<Map> new_map2 = Map::Update(isolate, map2);
|
||||
CHECK(!new_map2->is_deprecated());
|
||||
CHECK(!new_map2->is_dictionary_map());
|
||||
|
||||
Handle<Map> tmp_map;
|
||||
if (Map::TryUpdate(isolate, map2).ToHandle(&tmp_map)) {
|
||||
// If Map::TryUpdate() manages to succeed the result must match the
|
||||
// result of Map::Update().
|
||||
CHECK_EQ(*new_map2, *tmp_map);
|
||||
} else {
|
||||
// Equivalent transitions should always find the updated map.
|
||||
CHECK(config.is_non_equivalent_transition());
|
||||
}
|
||||
|
||||
if (config.is_non_equivalent_transition()) {
|
||||
// In case of non-equivalent transition currently we generalize all
|
||||
// representations.
|
||||
for (int i = 0; i < kPropCount; i++) {
|
||||
expectations2.GeneralizeField(i);
|
||||
}
|
||||
CHECK(new_map2->GetBackPointer()->IsUndefined(isolate));
|
||||
CHECK(expectations2.Check(*new_map2));
|
||||
} else {
|
||||
expectations2.SetDataField(i, expected.constness,
|
||||
expected.representation, expected.type);
|
||||
|
||||
CHECK(!new_map2->GetBackPointer()->IsUndefined(isolate));
|
||||
CHECK(expectations2.Check(*new_map2));
|
||||
}
|
||||
Handle<Map> tmp_map;
|
||||
if (Map::TryUpdate(isolate, map2).ToHandle(&tmp_map)) {
|
||||
// If Map::TryUpdate() manages to succeed the result must match the result
|
||||
// of Map::Update().
|
||||
CHECK_EQ(*new_map2, *tmp_map);
|
||||
} else {
|
||||
CHECK(!map->is_deprecated());
|
||||
// TODO(ishell): Update test expectations properly.
|
||||
// CHECK_EQ(*map2, *new_map);
|
||||
// CHECK(expectations2.Check(*new_map));
|
||||
// Equivalent transitions should always find the updated map.
|
||||
CHECK(config.is_non_equivalent_transition());
|
||||
}
|
||||
|
||||
if (config.is_non_equivalent_transition()) {
|
||||
// In case of non-equivalent transition currently we generalize all
|
||||
// representations.
|
||||
for (int i = 0; i < kPropCount; i++) {
|
||||
expectations2.GeneralizeField(i);
|
||||
}
|
||||
CHECK(new_map2->GetBackPointer()->IsUndefined(isolate));
|
||||
CHECK(expectations2.Check(*new_map2));
|
||||
} else {
|
||||
expectations2.SetDataField(i, expected.constness, expected.representation,
|
||||
expected.type);
|
||||
|
||||
CHECK(!new_map2->GetBackPointer()->IsUndefined(isolate));
|
||||
CHECK(expectations2.Check(*new_map2));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2361,6 +2351,7 @@ static void TestGeneralizeFieldWithSpecialTransition(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(ElementsKindTransitionFromMapOwningDescriptor) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
@ -2396,14 +2387,7 @@ TEST(ElementsKindTransitionFromMapOwningDescriptor) {
|
||||
configs[i],
|
||||
{PropertyConstness::kMutable, Representation::Smi(), any_type},
|
||||
{PropertyConstness::kMutable, Representation::HeapObject(), value_type},
|
||||
{PropertyConstness::kMutable, Representation::Tagged(), any_type},
|
||||
!FLAG_modify_field_representation_inplace);
|
||||
TestGeneralizeFieldWithSpecialTransition(
|
||||
configs[i],
|
||||
{PropertyConstness::kMutable, Representation::Double(), any_type},
|
||||
{PropertyConstness::kMutable, Representation::HeapObject(), value_type},
|
||||
{PropertyConstness::kMutable, Representation::Tagged(), any_type},
|
||||
true);
|
||||
{PropertyConstness::kMutable, Representation::Tagged(), any_type});
|
||||
}
|
||||
}
|
||||
|
||||
@ -2455,14 +2439,7 @@ TEST(ElementsKindTransitionFromMapNotOwningDescriptor) {
|
||||
configs[i],
|
||||
{PropertyConstness::kMutable, Representation::Smi(), any_type},
|
||||
{PropertyConstness::kMutable, Representation::HeapObject(), value_type},
|
||||
{PropertyConstness::kMutable, Representation::Tagged(), any_type},
|
||||
!FLAG_modify_field_representation_inplace);
|
||||
TestGeneralizeFieldWithSpecialTransition(
|
||||
configs[i],
|
||||
{PropertyConstness::kMutable, Representation::Double(), any_type},
|
||||
{PropertyConstness::kMutable, Representation::HeapObject(), value_type},
|
||||
{PropertyConstness::kMutable, Representation::Tagged(), any_type},
|
||||
true);
|
||||
{PropertyConstness::kMutable, Representation::Tagged(), any_type});
|
||||
}
|
||||
}
|
||||
|
||||
@ -2498,12 +2475,7 @@ TEST(PrototypeTransitionFromMapOwningDescriptor) {
|
||||
TestGeneralizeFieldWithSpecialTransition(
|
||||
config, {PropertyConstness::kMutable, Representation::Smi(), any_type},
|
||||
{PropertyConstness::kMutable, Representation::HeapObject(), value_type},
|
||||
{PropertyConstness::kMutable, Representation::Tagged(), any_type},
|
||||
!FLAG_modify_field_representation_inplace);
|
||||
TestGeneralizeFieldWithSpecialTransition(
|
||||
config, {PropertyConstness::kMutable, Representation::Double(), any_type},
|
||||
{PropertyConstness::kMutable, Representation::HeapObject(), value_type},
|
||||
{PropertyConstness::kMutable, Representation::Tagged(), any_type}, true);
|
||||
{PropertyConstness::kMutable, Representation::Tagged(), any_type});
|
||||
}
|
||||
|
||||
|
||||
@ -2550,12 +2522,7 @@ TEST(PrototypeTransitionFromMapNotOwningDescriptor) {
|
||||
TestGeneralizeFieldWithSpecialTransition(
|
||||
config, {PropertyConstness::kMutable, Representation::Smi(), any_type},
|
||||
{PropertyConstness::kMutable, Representation::HeapObject(), value_type},
|
||||
{PropertyConstness::kMutable, Representation::Tagged(), any_type},
|
||||
!FLAG_modify_field_representation_inplace);
|
||||
TestGeneralizeFieldWithSpecialTransition(
|
||||
config, {PropertyConstness::kMutable, Representation::Double(), any_type},
|
||||
{PropertyConstness::kMutable, Representation::HeapObject(), value_type},
|
||||
{PropertyConstness::kMutable, Representation::Tagged(), any_type}, true);
|
||||
{PropertyConstness::kMutable, Representation::Tagged(), any_type});
|
||||
}
|
||||
|
||||
|
||||
@ -2844,17 +2811,12 @@ TEST(TransitionDataConstantToDataField) {
|
||||
|
||||
Handle<Object> value2 = isolate->factory()->NewHeapNumber(0);
|
||||
TransitionToDataFieldOperator transition_op2(
|
||||
PropertyConstness::kMutable, Representation::Tagged(), any_type, value2);
|
||||
PropertyConstness::kMutable, Representation::Double(), any_type, value2);
|
||||
|
||||
if (FLAG_track_constant_fields && FLAG_modify_field_representation_inplace) {
|
||||
SameMapChecker checker;
|
||||
TestTransitionTo(transition_op1, transition_op2, checker);
|
||||
} else {
|
||||
FieldGeneralizationChecker checker(kPropCount - 1,
|
||||
PropertyConstness::kMutable,
|
||||
Representation::Tagged(), any_type);
|
||||
TestTransitionTo(transition_op1, transition_op2, checker);
|
||||
}
|
||||
FieldGeneralizationChecker checker(kPropCount - 1,
|
||||
PropertyConstness::kMutable,
|
||||
Representation::Tagged(), any_type);
|
||||
TestTransitionTo(transition_op1, transition_op2, checker);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2948,8 +2948,7 @@ TEST(WeakContainers) {
|
||||
CHECK_NE(0, count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const v8::HeapGraphEdge* prop = dependent_code->GetChild(i);
|
||||
CHECK(prop->GetType() == v8::HeapGraphEdge::kInternal ||
|
||||
prop->GetType() == v8::HeapGraphEdge::kWeak);
|
||||
CHECK_EQ(v8::HeapGraphEdge::kInternal, prop->GetType());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,74 +0,0 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
// Flags: --allow-natives-syntax --modify-field-representation-inplace
|
||||
// Flags: --no-always-opt --opt
|
||||
|
||||
// Test that code embedding accesses to a Smi field gets properly
|
||||
// deoptimized if s->t field representation changes are done in-place.
|
||||
(function() {
|
||||
function O(x) { this.x = x; }
|
||||
|
||||
function foo(o) { return o.x; }
|
||||
%PrepareFunctionForOptimization(foo);
|
||||
foo(new O(1));
|
||||
foo(new O(2));
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(new O(3));
|
||||
assertOptimized(foo);
|
||||
|
||||
new O(null);
|
||||
assertUnoptimized(foo);
|
||||
})();
|
||||
|
||||
// Test that code embedding assignments to a Smi field gets properly
|
||||
// deoptimized if s->t field representation changes are done in-place.
|
||||
(function() {
|
||||
function O(x) { this.x = x; }
|
||||
|
||||
function foo(o) { o.x = 0; }
|
||||
%PrepareFunctionForOptimization(foo);
|
||||
foo(new O(1));
|
||||
foo(new O(2));
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(new O(3));
|
||||
assertOptimized(foo);
|
||||
|
||||
new O(null);
|
||||
assertUnoptimized(foo);
|
||||
})();
|
||||
|
||||
// Test that code embedding accesses to a HeapObject field gets properly
|
||||
// deoptimized if h->t field representation changes are done in-place.
|
||||
(function() {
|
||||
function O(x) { this.x = x; }
|
||||
|
||||
function foo(o) { return o.x; }
|
||||
%PrepareFunctionForOptimization(foo);
|
||||
foo(new O(null));
|
||||
foo(new O("Hello"));
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(new O({}));
|
||||
assertOptimized(foo);
|
||||
|
||||
new O(1);
|
||||
assertUnoptimized(foo);
|
||||
})();
|
||||
|
||||
// Test that code embedding assignments to a Smi field gets properly
|
||||
// deoptimized if s->t field representation changes are done in-place.
|
||||
(function() {
|
||||
function O(x) { this.x = x; }
|
||||
|
||||
function foo(o) { o.x = true; }
|
||||
%PrepareFunctionForOptimization(foo);
|
||||
foo(new O(null));
|
||||
foo(new O("Hello"));
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(new O({}));
|
||||
assertOptimized(foo);
|
||||
|
||||
new O(1);
|
||||
assertUnoptimized(foo);
|
||||
})();
|
@ -1,31 +0,0 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
// Flags: --allow-natives-syntax --modify-field-representation-inplace
|
||||
|
||||
// Test that s->t field representation changes are done in-place.
|
||||
(function() {
|
||||
function O(x) { this.x = x; }
|
||||
|
||||
const a = new O(42);
|
||||
const b = new O(-8);
|
||||
assertTrue(%HaveSameMap(a, b));
|
||||
a.x = null;
|
||||
assertTrue(%HaveSameMap(a, b));
|
||||
b.x = null;
|
||||
assertTrue(%HaveSameMap(a, b));
|
||||
})();
|
||||
|
||||
// Test that h->t field representation changes are done in-place.
|
||||
(function() {
|
||||
function O(x) { this.x = x; }
|
||||
|
||||
const a = new O(null);
|
||||
const b = new O("Hello");
|
||||
assertTrue(%HaveSameMap(a, b));
|
||||
a.x = 1;
|
||||
assertTrue(%HaveSameMap(a, b));
|
||||
b.x = 2;
|
||||
assertTrue(%HaveSameMap(a, b));
|
||||
})();
|
@ -148,11 +148,11 @@
|
||||
var f2 = new Narf(2);
|
||||
var f3 = new Narf(3);
|
||||
function baz(f, y) { f.y = y; }
|
||||
baz(f1, {b: 9});
|
||||
baz(f2, {b: 9});
|
||||
baz(f2, {b: 9});
|
||||
baz(f1, {y: 9});
|
||||
baz(f2, {y: 9});
|
||||
baz(f2, {y: 9});
|
||||
%OptimizeFunctionOnNextCall(baz);
|
||||
baz(f2, {b: 9});
|
||||
baz(f2, {y: 9});
|
||||
baz(f3, {a: -1});
|
||||
assertUnoptimized(baz);
|
||||
})();
|
||||
|
@ -26,7 +26,6 @@
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Flags: --track-fields --track-double-fields --allow-natives-syntax
|
||||
// Flags: --modify-field-representation-inplace
|
||||
|
||||
// Test transitions caused by changes to field representations.
|
||||
|
||||
@ -96,7 +95,7 @@ o6.b = 1.5;
|
||||
assertFalse(%HaveSameMap(o6, o7));
|
||||
// Smi, double, object.
|
||||
o7.c = {};
|
||||
assertTrue(%HaveSameMap(o6, o7));
|
||||
assertFalse(%HaveSameMap(o6, o7));
|
||||
// Smi, double, object.
|
||||
o6.c = {};
|
||||
assertTrue(%HaveSameMap(o6, o7));
|
||||
|
Loading…
Reference in New Issue
Block a user