diff --git a/src/elements-kind.h b/src/elements-kind.h index d4616a134c2..511bb0b0f4b 100644 --- a/src/elements-kind.h +++ b/src/elements-kind.h @@ -7,6 +7,7 @@ #include "src/base/macros.h" #include "src/checks.h" +#include "src/flags.h" #include "src/utils.h" namespace v8 { @@ -154,13 +155,24 @@ inline bool IsDoubleOrFloatElementsKind(ElementsKind kind) { } inline bool IsPackedFrozenOrSealedElementsKind(ElementsKind kind) { + DCHECK_IMPLIES( + IsInRange(kind, PACKED_SEALED_ELEMENTS, PACKED_FROZEN_ELEMENTS), + FLAG_enable_sealed_frozen_elements_kind); return IsInRange(kind, PACKED_SEALED_ELEMENTS, PACKED_FROZEN_ELEMENTS); } inline bool IsSealedElementsKind(ElementsKind kind) { + DCHECK_IMPLIES(kind == PACKED_SEALED_ELEMENTS, + FLAG_enable_sealed_frozen_elements_kind); return kind == PACKED_SEALED_ELEMENTS; } +inline bool IsFrozenElementsKind(ElementsKind kind) { + DCHECK_IMPLIES(kind == PACKED_FROZEN_ELEMENTS, + FLAG_enable_sealed_frozen_elements_kind); + return kind == PACKED_FROZEN_ELEMENTS; +} + inline bool IsSmiOrObjectElementsKind(ElementsKind kind) { return kind == PACKED_SMI_ELEMENTS || kind == HOLEY_SMI_ELEMENTS || kind == PACKED_ELEMENTS || kind == HOLEY_ELEMENTS; diff --git a/src/elements.cc b/src/elements.cc index 31772c9dbe3..824baeebb6a 100644 --- a/src/elements.cc +++ b/src/elements.cc @@ -2409,7 +2409,8 @@ class FastElementsAccessor : public ElementsAccessorBase { // Search for NaN in PACKED_ELEMENTS, HOLEY_ELEMENTS, // PACKED_SMI_ELEMENTS or HOLEY_SMI_ELEMENTS. Return true if // elementK->IsHeapNumber() && std::isnan(elementK->Number()) - DCHECK(IsSmiOrObjectElementsKind(Subclass::kind())); + DCHECK(IsSmiOrObjectElementsKind(Subclass::kind()) || + IsPackedFrozenOrSealedElementsKind(Subclass::kind())); auto elements = FixedArray::cast(receiver->elements()); for (uint32_t k = start_from; k < length; ++k) { diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 3bdb2c30f18..12b9435622e 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -354,6 +354,9 @@ DEFINE_BOOL(enable_one_shot_optimization, true, "Enable size optimizations for the code that will " "only be executed once") +// Flag for sealed, frozen elements kind instead of dictionary elements kind +DEFINE_BOOL(enable_sealed_frozen_elements_kind, true, + "Enable sealed, frozen elements kind") // Flags for data representation optimizations DEFINE_BOOL(unbox_double_arrays, true, "automatically unbox arrays of doubles") diff --git a/src/ic/ic.cc b/src/ic/ic.cc index b5a8cebd595..1605f69a417 100644 --- a/src/ic/ic.cc +++ b/src/ic/ic.cc @@ -1948,7 +1948,7 @@ Handle KeyedStoreIC::StoreElementHandler( code = CodeFactory::KeyedStoreIC_SloppyArguments(isolate(), store_mode).code(); } else if (receiver_map->has_fast_elements() || - PACKED_SEALED_ELEMENTS == receiver_map->elements_kind() || + receiver_map->has_sealed_elements() || receiver_map->has_fixed_typed_array_elements()) { TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub); code = CodeFactory::StoreFastElementIC(isolate(), store_mode).code(); @@ -1962,7 +1962,7 @@ Handle KeyedStoreIC::StoreElementHandler( // TODO(jgruber): Update counter name. TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub); DCHECK(DICTIONARY_ELEMENTS == receiver_map->elements_kind() || - PACKED_FROZEN_ELEMENTS == receiver_map->elements_kind()); + receiver_map->has_frozen_elements()); code = CodeFactory::KeyedStoreIC_Slow(isolate(), store_mode).code(); } diff --git a/src/lookup.cc b/src/lookup.cc index f93cafa3118..ddd1260ff13 100644 --- a/src/lookup.cc +++ b/src/lookup.cc @@ -1167,9 +1167,8 @@ LookupIterator::State LookupIterator::LookupInRegularHolder( return holder->IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND; } property_details_ = accessor->GetDetails(js_object, number_); - if (map->is_frozen_or_sealed_elements()) { - PropertyAttributes attrs = - map->elements_kind() == PACKED_SEALED_ELEMENTS ? SEALED : FROZEN; + if (map->has_frozen_or_sealed_elements()) { + PropertyAttributes attrs = map->has_sealed_elements() ? SEALED : FROZEN; property_details_ = property_details_.CopyAddAttributes(attrs); } } else if (!map->is_dictionary_map()) { diff --git a/src/objects-debug.cc b/src/objects-debug.cc index b8cfb02153e..309063f8180 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -645,7 +645,7 @@ void JSObject::JSObjectVerify(Isolate* isolate) { // pointer may point to a one pointer filler map. if (ElementsAreSafeToExamine()) { CHECK_EQ((map()->has_fast_smi_or_object_elements() || - map()->is_frozen_or_sealed_elements() || + map()->has_frozen_or_sealed_elements() || (elements() == GetReadOnlyRoots().empty_fixed_array()) || HasFastStringWrapperElements()), (elements()->map() == GetReadOnlyRoots().fixed_array_map() || diff --git a/src/objects/js-objects.cc b/src/objects/js-objects.cc index 758755567f8..5ed726f3387 100644 --- a/src/objects/js-objects.cc +++ b/src/objects/js-objects.cc @@ -3673,8 +3673,8 @@ bool TestElementsIntegrityLevel(JSObject object, PropertyAttributes level) { return false; // TypedArrays with elements can't be frozen. return TestPropertiesIntegrityLevel(object, level); } - if (kind == PACKED_FROZEN_ELEMENTS) return true; - if (kind == PACKED_SEALED_ELEMENTS && level != FROZEN) return true; + if (IsFrozenElementsKind(kind)) return true; + if (IsSealedElementsKind(kind) && level != FROZEN) return true; ElementsAccessor* accessor = ElementsAccessor::ForKind(kind); // Only DICTIONARY_ELEMENTS and SLOW_SLOPPY_ARGUMENTS_ELEMENTS have @@ -3813,7 +3813,7 @@ Maybe JSObject::PreventExtensionsWithTransition( if (attrs == NONE && !object->map()->is_extensible()) return Just(true); ElementsKind old_elements_kind = object->map()->elements_kind(); - if (attrs != FROZEN && old_elements_kind == PACKED_SEALED_ELEMENTS) + if (attrs != FROZEN && IsSealedElementsKind(old_elements_kind)) return Just(true); if (old_elements_kind == PACKED_FROZEN_ELEMENTS) return Just(true); @@ -3874,7 +3874,7 @@ Maybe JSObject::PreventExtensionsWithTransition( DCHECK(transition_map->has_dictionary_elements() || transition_map->has_fixed_typed_array_elements() || transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS || - transition_map->is_frozen_or_sealed_elements()); + transition_map->has_frozen_or_sealed_elements()); DCHECK(!transition_map->is_extensible()); JSObject::MigrateToMap(object, transition_map); } else if (transitions.CanHaveMoreTransitions()) { @@ -3918,7 +3918,7 @@ Maybe JSObject::PreventExtensionsWithTransition( } } - if (object->map()->is_frozen_or_sealed_elements()) { + if (object->map()->has_frozen_or_sealed_elements()) { return Just(true); } diff --git a/src/objects/map-inl.h b/src/objects/map-inl.h index a57e596c45f..792e12d1262 100644 --- a/src/objects/map-inl.h +++ b/src/objects/map-inl.h @@ -500,10 +500,18 @@ bool Map::has_dictionary_elements() const { return IsDictionaryElementsKind(elements_kind()); } -bool Map::is_frozen_or_sealed_elements() const { +bool Map::has_frozen_or_sealed_elements() const { return IsPackedFrozenOrSealedElementsKind(elements_kind()); } +bool Map::has_sealed_elements() const { + return IsSealedElementsKind(elements_kind()); +} + +bool Map::has_frozen_elements() const { + return IsFrozenElementsKind(elements_kind()); +} + void Map::set_is_dictionary_map(bool value) { uint32_t new_bit_field3 = IsDictionaryMapBit::update(bit_field3(), value); new_bit_field3 = IsUnstableBit::update(new_bit_field3, value); diff --git a/src/objects/map.cc b/src/objects/map.cc index ee1cabab05f..80ea74a1765 100644 --- a/src/objects/map.cc +++ b/src/objects/map.cc @@ -2043,21 +2043,23 @@ Handle Map::CopyForPreventExtensions(Isolate* isolate, Handle map, ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind()) ? SLOW_STRING_WRAPPER_ELEMENTS : DICTIONARY_ELEMENTS; - switch (map->elements_kind()) { - case PACKED_ELEMENTS: - if (attrs_to_add == SEALED) { - new_kind = PACKED_SEALED_ELEMENTS; - } else if (attrs_to_add == FROZEN) { - new_kind = PACKED_FROZEN_ELEMENTS; - } - break; - case PACKED_SEALED_ELEMENTS: - if (attrs_to_add == FROZEN) { - new_kind = PACKED_FROZEN_ELEMENTS; - } - break; - default: - break; + if (FLAG_enable_sealed_frozen_elements_kind) { + switch (map->elements_kind()) { + case PACKED_ELEMENTS: + if (attrs_to_add == SEALED) { + new_kind = PACKED_SEALED_ELEMENTS; + } else if (attrs_to_add == FROZEN) { + new_kind = PACKED_FROZEN_ELEMENTS; + } + break; + case PACKED_SEALED_ELEMENTS: + if (attrs_to_add == FROZEN) { + new_kind = PACKED_FROZEN_ELEMENTS; + } + break; + default: + break; + } } new_map->set_elements_kind(new_kind); } diff --git a/src/objects/map.h b/src/objects/map.h index da307b7973c..96c09e1664f 100644 --- a/src/objects/map.h +++ b/src/objects/map.h @@ -421,7 +421,9 @@ class Map : public HeapObject { inline bool has_fast_string_wrapper_elements() const; inline bool has_fixed_typed_array_elements() const; inline bool has_dictionary_elements() const; - inline bool is_frozen_or_sealed_elements() const; + inline bool has_frozen_or_sealed_elements() const; + inline bool has_sealed_elements() const; + inline bool has_frozen_elements() const; // Returns true if the current map doesn't have DICTIONARY_ELEMENTS but if a // map with DICTIONARY_ELEMENTS was found in the prototype chain. diff --git a/test/mjsunit/object-freeze.js b/test/mjsunit/object-freeze.js index 7977659df49..fe392e749c5 100644 --- a/test/mjsunit/object-freeze.js +++ b/test/mjsunit/object-freeze.js @@ -430,6 +430,8 @@ function testPackedFrozenArray1(obj) { assertEquals(obj.indexOf(undefined), 0); assertFalse(obj.includes(Symbol("test"))); assertTrue(obj.includes(undefined)); + assertFalse(obj.includes(NaN)); + assertTrue(obj.includes()); assertEquals(obj.find(x => x==0), undefined); assertEquals(obj.findIndex(x => x=='a'), 4); assertTrue(obj.some(x => typeof x == 'symbol')); diff --git a/test/mjsunit/object-prevent-extensions.js b/test/mjsunit/object-prevent-extensions.js index baae0864d0a..a2da9372a2e 100644 --- a/test/mjsunit/object-prevent-extensions.js +++ b/test/mjsunit/object-prevent-extensions.js @@ -190,6 +190,8 @@ assertEquals(obj.indexOf('a'), 4); assertEquals(obj.indexOf(undefined), 0); assertFalse(obj.includes(Symbol("test"))); assertTrue(obj.includes(undefined)); +assertFalse(obj.includes(NaN)); +assertTrue(obj.includes()); assertEquals(obj.find(x => x==0), undefined); assertEquals(obj.findIndex(x => x=='a'), 4); assertTrue(obj.some(x => typeof x == 'symbol')); diff --git a/test/mjsunit/object-seal.js b/test/mjsunit/object-seal.js index e83d8742310..4de0e1c7e22 100644 --- a/test/mjsunit/object-seal.js +++ b/test/mjsunit/object-seal.js @@ -419,6 +419,8 @@ function testPackedSealedArray1(obj) { assertEquals(obj.indexOf(undefined), 0); assertFalse(obj.includes(Symbol("test"))); assertTrue(obj.includes(undefined)); + assertFalse(obj.includes(NaN)); + assertTrue(obj.includes()); assertEquals(obj.find(x => x==0), undefined); assertEquals(obj.findIndex(x => x=='a'), 4); assertTrue(obj.some(x => typeof x == 'symbol'));