|
| 1 | +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
| 2 | +From: "ishell@chromium.org" <ishell@chromium.org> |
| 3 | +Date: Tue, 3 Nov 2020 12:42:43 +0100 |
| 4 | +Subject: Merged: Squashed multiple commits. |
| 5 | + |
| 6 | +Merged: [map] Try to in-place transition during map update |
| 7 | +Revision: 8e3ae62d294818733a0322d8e8abd53d4e410f19 |
| 8 | + |
| 9 | +Merged: [map] Skip loading the field owner before GeneralizeField |
| 10 | +Revision: a928f5fcc2a67c2c8d621ece48f76deb0d36637b |
| 11 | + |
| 12 | +BUG=chromium:1143772 |
| 13 | +NOTRY=true |
| 14 | +NOPRESUBMIT=true |
| 15 | +NOTREECHECKS=true |
| 16 | +R=verwaest@chromium.org |
| 17 | + |
| 18 | +Change-Id: I78628cb697b21caa2098cc5948e226af5fcd020c |
| 19 | +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2516474 |
| 20 | +Reviewed-by: Toon Verwaest <verwaest@chromium.org> |
| 21 | +Cr-Commit-Position: refs/branch-heads/8.7@{#31} |
| 22 | +Cr-Branched-From: 0d81cd72688512abcbe1601015baee390c484a6a-refs/heads/8.7.220@{#1} |
| 23 | +Cr-Branched-From: 942c2ef85caef00fcf02517d049f05e9a3d4b440-refs/heads/master@{#70196} |
| 24 | + |
| 25 | +diff --git a/src/objects/map-updater.cc b/src/objects/map-updater.cc |
| 26 | +index 8c9b94014f8efaa4463cc883877ed52d24963d4c..5a016614a1782913e2297a4a396fc4402ea41cee 100644 |
| 27 | +--- a/src/objects/map-updater.cc |
| 28 | ++++ b/src/objects/map-updater.cc |
| 29 | +@@ -232,10 +232,7 @@ MapUpdater::State MapUpdater::TryReconfigureToDataFieldInplace() { |
| 30 | + handle(old_descriptors_->GetFieldType(modified_descriptor_), isolate_), |
| 31 | + MaybeHandle<Object>(), new_field_type_, MaybeHandle<Object>()); |
| 32 | + } |
| 33 | +- Handle<Map> field_owner( |
| 34 | +- old_map_->FindFieldOwner(isolate_, modified_descriptor_), isolate_); |
| 35 | +- |
| 36 | +- GeneralizeField(field_owner, modified_descriptor_, new_constness_, |
| 37 | ++ GeneralizeField(old_map_, modified_descriptor_, new_constness_, |
| 38 | + new_representation_, new_field_type_); |
| 39 | + // Check that the descriptor array was updated. |
| 40 | + DCHECK(old_descriptors_->GetDetails(modified_descriptor_) |
| 41 | +@@ -401,7 +398,13 @@ MapUpdater::State MapUpdater::FindTargetMap() { |
| 42 | + } |
| 43 | + Representation tmp_representation = tmp_details.representation(); |
| 44 | + if (!old_details.representation().fits_into(tmp_representation)) { |
| 45 | +- break; |
| 46 | ++ // Try updating the field in-place to a generalized type. |
| 47 | ++ Representation generalized = |
| 48 | ++ tmp_representation.generalize(old_details.representation()); |
| 49 | ++ if (!tmp_representation.CanBeInPlaceChangedTo(generalized)) { |
| 50 | ++ break; |
| 51 | ++ } |
| 52 | ++ tmp_representation = generalized; |
| 53 | + } |
| 54 | + |
| 55 | + if (tmp_details.location() == kField) { |
| 56 | +diff --git a/src/objects/map.cc b/src/objects/map.cc |
| 57 | +index 60100c2030ce6d32213312227f03919e8cd0c88b..565ca697423fc29072716d37a56193b530939803 100644 |
| 58 | +--- a/src/objects/map.cc |
| 59 | ++++ b/src/objects/map.cc |
| 60 | +@@ -590,6 +590,7 @@ void Map::DeprecateTransitionTree(Isolate* isolate) { |
| 61 | + transitions.GetTarget(i).DeprecateTransitionTree(isolate); |
| 62 | + } |
| 63 | + DCHECK(!constructor_or_backpointer().IsFunctionTemplateInfo()); |
| 64 | ++ DCHECK(CanBeDeprecated()); |
| 65 | + set_is_deprecated(true); |
| 66 | + if (FLAG_trace_maps) { |
| 67 | + LOG(isolate, MapEvent("Deprecate", *this, Map())); |
| 68 | +diff --git a/test/cctest/test-field-type-tracking.cc b/test/cctest/test-field-type-tracking.cc |
| 69 | +index 9deb1ff70cf3364d9033dde00ca0a1262034f0ff..55a5b45a6a57eeeddc3934d7978eafe1a8c50fd1 100644 |
| 70 | +--- a/test/cctest/test-field-type-tracking.cc |
| 71 | ++++ b/test/cctest/test-field-type-tracking.cc |
| 72 | +@@ -1019,7 +1019,8 @@ namespace { |
| 73 | + // where "p2A" and "p2B" differ only in the attributes. |
| 74 | + // |
| 75 | + void TestReconfigureDataFieldAttribute_GeneralizeField( |
| 76 | +- const CRFTData& from, const CRFTData& to, const CRFTData& expected) { |
| 77 | ++ const CRFTData& from, const CRFTData& to, const CRFTData& expected, |
| 78 | ++ bool expected_deprecation) { |
| 79 | + Isolate* isolate = CcTest::i_isolate(); |
| 80 | + |
| 81 | + Expectations expectations(isolate); |
| 82 | +@@ -1079,22 +1080,26 @@ void TestReconfigureDataFieldAttribute_GeneralizeField( |
| 83 | + CHECK_NE(*map2, *new_map); |
| 84 | + CHECK(expectations2.Check(*map2)); |
| 85 | + |
| 86 | +- // |map| should be deprecated and |new_map| should match new expectations. |
| 87 | + for (int i = kSplitProp; i < kPropCount; i++) { |
| 88 | + expectations.SetDataField(i, expected.constness, expected.representation, |
| 89 | + expected.type); |
| 90 | + } |
| 91 | +- CHECK(map->is_deprecated()); |
| 92 | +- CHECK(!code->marked_for_deoptimization()); |
| 93 | +- CHECK_NE(*map, *new_map); |
| 94 | ++ if (expected_deprecation) { |
| 95 | ++ CHECK(map->is_deprecated()); |
| 96 | ++ CHECK(!code->marked_for_deoptimization()); |
| 97 | ++ CHECK_NE(*map, *new_map); |
| 98 | + |
| 99 | +- CHECK(!new_map->is_deprecated()); |
| 100 | +- CHECK(expectations.Check(*new_map)); |
| 101 | ++ CHECK(!new_map->is_deprecated()); |
| 102 | ++ CHECK(expectations.Check(*new_map)); |
| 103 | + |
| 104 | +- // Update deprecated |map|, it should become |new_map|. |
| 105 | +- Handle<Map> updated_map = Map::Update(isolate, map); |
| 106 | +- CHECK_EQ(*new_map, *updated_map); |
| 107 | +- CheckMigrationTarget(isolate, *map, *updated_map); |
| 108 | ++ // Update deprecated |map|, it should become |new_map|. |
| 109 | ++ Handle<Map> updated_map = Map::Update(isolate, map); |
| 110 | ++ CHECK_EQ(*new_map, *updated_map); |
| 111 | ++ CheckMigrationTarget(isolate, *map, *updated_map); |
| 112 | ++ } else { |
| 113 | ++ CHECK(!map->is_deprecated()); |
| 114 | ++ CHECK(expectations.Check(*map)); |
| 115 | ++ } |
| 116 | + } |
| 117 | + |
| 118 | + // This test ensures that trivial field generalization (from HeapObject to |
| 119 | +@@ -1200,22 +1205,22 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeSmiFieldToDouble) { |
| 120 | + TestReconfigureDataFieldAttribute_GeneralizeField( |
| 121 | + {PropertyConstness::kConst, Representation::Smi(), any_type}, |
| 122 | + {PropertyConstness::kConst, Representation::Double(), any_type}, |
| 123 | +- {PropertyConstness::kConst, Representation::Double(), any_type}); |
| 124 | ++ {PropertyConstness::kConst, Representation::Double(), any_type}, true); |
| 125 | + |
| 126 | + TestReconfigureDataFieldAttribute_GeneralizeField( |
| 127 | + {PropertyConstness::kConst, Representation::Smi(), any_type}, |
| 128 | + {PropertyConstness::kMutable, Representation::Double(), any_type}, |
| 129 | +- {PropertyConstness::kMutable, Representation::Double(), any_type}); |
| 130 | ++ {PropertyConstness::kMutable, Representation::Double(), any_type}, true); |
| 131 | + |
| 132 | + TestReconfigureDataFieldAttribute_GeneralizeField( |
| 133 | + {PropertyConstness::kMutable, Representation::Smi(), any_type}, |
| 134 | + {PropertyConstness::kConst, Representation::Double(), any_type}, |
| 135 | +- {PropertyConstness::kMutable, Representation::Double(), any_type}); |
| 136 | ++ {PropertyConstness::kMutable, Representation::Double(), any_type}, true); |
| 137 | + |
| 138 | + TestReconfigureDataFieldAttribute_GeneralizeField( |
| 139 | + {PropertyConstness::kMutable, Representation::Smi(), any_type}, |
| 140 | + {PropertyConstness::kMutable, Representation::Double(), any_type}, |
| 141 | +- {PropertyConstness::kMutable, Representation::Double(), any_type}); |
| 142 | ++ {PropertyConstness::kMutable, Representation::Double(), any_type}, true); |
| 143 | + } |
| 144 | + |
| 145 | + TEST(ReconfigureDataFieldAttribute_GeneralizeSmiFieldToTagged) { |
| 146 | +@@ -1230,22 +1235,26 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeSmiFieldToTagged) { |
| 147 | + TestReconfigureDataFieldAttribute_GeneralizeField( |
| 148 | + {PropertyConstness::kConst, Representation::Smi(), any_type}, |
| 149 | + {PropertyConstness::kConst, Representation::HeapObject(), value_type}, |
| 150 | +- {PropertyConstness::kConst, Representation::Tagged(), any_type}); |
| 151 | ++ {PropertyConstness::kConst, Representation::Tagged(), any_type}, |
| 152 | ++ !FLAG_modify_field_representation_inplace); |
| 153 | + |
| 154 | + TestReconfigureDataFieldAttribute_GeneralizeField( |
| 155 | + {PropertyConstness::kConst, Representation::Smi(), any_type}, |
| 156 | + {PropertyConstness::kMutable, Representation::HeapObject(), value_type}, |
| 157 | +- {PropertyConstness::kMutable, Representation::Tagged(), any_type}); |
| 158 | ++ {PropertyConstness::kMutable, Representation::Tagged(), any_type}, |
| 159 | ++ !FLAG_modify_field_representation_inplace); |
| 160 | + |
| 161 | + TestReconfigureDataFieldAttribute_GeneralizeField( |
| 162 | + {PropertyConstness::kMutable, Representation::Smi(), any_type}, |
| 163 | + {PropertyConstness::kConst, Representation::HeapObject(), value_type}, |
| 164 | +- {PropertyConstness::kMutable, Representation::Tagged(), any_type}); |
| 165 | ++ {PropertyConstness::kMutable, Representation::Tagged(), any_type}, |
| 166 | ++ !FLAG_modify_field_representation_inplace); |
| 167 | + |
| 168 | + TestReconfigureDataFieldAttribute_GeneralizeField( |
| 169 | + {PropertyConstness::kMutable, Representation::Smi(), any_type}, |
| 170 | + {PropertyConstness::kMutable, Representation::HeapObject(), value_type}, |
| 171 | +- {PropertyConstness::kMutable, Representation::Tagged(), any_type}); |
| 172 | ++ {PropertyConstness::kMutable, Representation::Tagged(), any_type}, |
| 173 | ++ !FLAG_modify_field_representation_inplace); |
| 174 | + } |
| 175 | + |
| 176 | + TEST(ReconfigureDataFieldAttribute_GeneralizeDoubleFieldToTagged) { |
| 177 | +@@ -1260,22 +1269,26 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeDoubleFieldToTagged) { |
| 178 | + TestReconfigureDataFieldAttribute_GeneralizeField( |
| 179 | + {PropertyConstness::kConst, Representation::Double(), any_type}, |
| 180 | + {PropertyConstness::kConst, Representation::HeapObject(), value_type}, |
| 181 | +- {PropertyConstness::kConst, Representation::Tagged(), any_type}); |
| 182 | ++ {PropertyConstness::kConst, Representation::Tagged(), any_type}, |
| 183 | ++ FLAG_unbox_double_fields || !FLAG_modify_field_representation_inplace); |
| 184 | + |
| 185 | + TestReconfigureDataFieldAttribute_GeneralizeField( |
| 186 | + {PropertyConstness::kConst, Representation::Double(), any_type}, |
| 187 | + {PropertyConstness::kMutable, Representation::HeapObject(), value_type}, |
| 188 | +- {PropertyConstness::kMutable, Representation::Tagged(), any_type}); |
| 189 | ++ {PropertyConstness::kMutable, Representation::Tagged(), any_type}, |
| 190 | ++ FLAG_unbox_double_fields || !FLAG_modify_field_representation_inplace); |
| 191 | + |
| 192 | + TestReconfigureDataFieldAttribute_GeneralizeField( |
| 193 | + {PropertyConstness::kMutable, Representation::Double(), any_type}, |
| 194 | + {PropertyConstness::kConst, Representation::HeapObject(), value_type}, |
| 195 | +- {PropertyConstness::kMutable, Representation::Tagged(), any_type}); |
| 196 | ++ {PropertyConstness::kMutable, Representation::Tagged(), any_type}, |
| 197 | ++ FLAG_unbox_double_fields || !FLAG_modify_field_representation_inplace); |
| 198 | + |
| 199 | + TestReconfigureDataFieldAttribute_GeneralizeField( |
| 200 | + {PropertyConstness::kMutable, Representation::Double(), any_type}, |
| 201 | + {PropertyConstness::kMutable, Representation::HeapObject(), value_type}, |
| 202 | +- {PropertyConstness::kMutable, Representation::Tagged(), any_type}); |
| 203 | ++ {PropertyConstness::kMutable, Representation::Tagged(), any_type}, |
| 204 | ++ FLAG_unbox_double_fields || !FLAG_modify_field_representation_inplace); |
| 205 | + } |
| 206 | + |
| 207 | + TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjFieldToHeapObj) { |
| 208 | +@@ -1361,7 +1374,8 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjectFieldToTagged) { |
| 209 | + TestReconfigureDataFieldAttribute_GeneralizeField( |
| 210 | + {PropertyConstness::kMutable, Representation::HeapObject(), value_type}, |
| 211 | + {PropertyConstness::kMutable, Representation::Smi(), any_type}, |
| 212 | +- {PropertyConstness::kMutable, Representation::Tagged(), any_type}); |
| 213 | ++ {PropertyConstness::kMutable, Representation::Tagged(), any_type}, |
| 214 | ++ !FLAG_modify_field_representation_inplace); |
| 215 | + } |
| 216 | + |
| 217 | + |
| 218 | +diff --git a/test/mjsunit/regress/regress-1143772.js b/test/mjsunit/regress/regress-1143772.js |
| 219 | +new file mode 100644 |
| 220 | +index 0000000000000000000000000000000000000000..40bc494d458afec816fd72e3fbb36b20a7942649 |
| 221 | +--- /dev/null |
| 222 | ++++ b/test/mjsunit/regress/regress-1143772.js |
| 223 | +@@ -0,0 +1,71 @@ |
| 224 | ++// Copyright 2020 the V8 project authors. All rights reserved. |
| 225 | ++// Use of this source code is governed by a BSD-style license that can be |
| 226 | ++// found in the LICENSE file. |
| 227 | ++// |
| 228 | ++// Flags: --allow-natives-syntax |
| 229 | ++ |
| 230 | ++(function() { |
| 231 | ++ // Only run this test if doubles are transitioned in-place to tagged. |
| 232 | ++ let x = {}; |
| 233 | ++ x.a = 0.1; |
| 234 | ++ let y = {}; |
| 235 | ++ y.a = {}; |
| 236 | ++ if (!%HaveSameMap(x, y)) return; |
| 237 | ++ |
| 238 | ++ // m1: {} |
| 239 | ++ let m1 = {}; |
| 240 | ++ |
| 241 | ++ // m2: {a:d} |
| 242 | ++ let m2 = {}; |
| 243 | ++ assertTrue(%HaveSameMap(m2, m1)); |
| 244 | ++ m2.a = 13.37; |
| 245 | ++ |
| 246 | ++ // m3: {a:d, b:s} |
| 247 | ++ let m3 = {}; |
| 248 | ++ m3.a = 13.37; |
| 249 | ++ assertTrue(%HaveSameMap(m3, m2)); |
| 250 | ++ m3.b = 1; |
| 251 | ++ |
| 252 | ++ // m4: {a:d, b:s, c:h} |
| 253 | ++ let m4 = {}; |
| 254 | ++ m4.a = 13.37; |
| 255 | ++ m4.b = 1; |
| 256 | ++ assertTrue(%HaveSameMap(m4, m3)); |
| 257 | ++ m4.c = {}; |
| 258 | ++ |
| 259 | ++ // m4_2 == m4 |
| 260 | ++ let m4_2 = {}; |
| 261 | ++ m4_2.a = 13.37; |
| 262 | ++ m4_2.b = 1; |
| 263 | ++ m4_2.c = {}; |
| 264 | ++ assertTrue(%HaveSameMap(m4_2, m4)); |
| 265 | ++ |
| 266 | ++ // m5: {a:d, b:d} |
| 267 | ++ let m5 = {}; |
| 268 | ++ m5.a = 13.37; |
| 269 | ++ assertTrue(%HaveSameMap(m5, m2)); |
| 270 | ++ m5.b = 13.37; |
| 271 | ++ assertFalse(%HaveSameMap(m5, m3)); |
| 272 | ++ |
| 273 | ++ // At this point, Map3 and Map4 are both deprecated. Map2 transitions to |
| 274 | ++ // Map5. Map5 is the migration target for Map3. |
| 275 | ++ assertFalse(%HaveSameMap(m5, m3)); |
| 276 | ++ |
| 277 | ++ // m6: {a:d, b:d, c:d} |
| 278 | ++ let m6 = {}; |
| 279 | ++ m6.a = 13.37; |
| 280 | ++ assertTrue(%HaveSameMap(m6, m2)); |
| 281 | ++ m6.b = 13.37; |
| 282 | ++ assertTrue(%HaveSameMap(m6, m5)); |
| 283 | ++ m6.c = 13.37 |
| 284 | ++ |
| 285 | ++ // Make m7: {a:d, b:d, c:t} |
| 286 | ++ let m7 = m4_2; |
| 287 | ++ assertTrue(%HaveSameMap(m7, m4)); |
| 288 | ++ // Map4 is deprecated, so this property access triggers a Map migration. |
| 289 | ++ // With in-place map updates and no double unboxing, this should end up |
| 290 | ++ // migrating to Map6, and updating it in-place. |
| 291 | ++ m7.c; |
| 292 | ++ assertFalse(%HaveSameMap(m7, m4)); |
| 293 | ++ assertTrue(%HaveSameMap(m6, m7)); |
| 294 | ++})(); |
0 commit comments