Increase length for packed sealed object will transition to dictionary mode

Increase length of packed sealed array will create holes in packed array so transition to dictionary elements for now.
Later we can consider transitioning to holey sealed array.

Bug: chromium:952382
Change-Id: Ibe26ce56918859a114fccc1933f9c966c47c4112
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1566968
Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60884}
This commit is contained in:
Z Duong Nguyen-Huu 2019-04-16 12:24:44 -07:00 committed by Commit Bot
parent 5af26d8a2e
commit 3f88ea39b2
6 changed files with 83 additions and 16 deletions

View File

@ -2799,13 +2799,43 @@ class FastPackedSealedObjectElementsAccessor
static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
uint32_t length,
Handle<FixedArrayBase> backing_store) {
#ifdef DEBUG
// Can only go here if length equals old_length.
uint32_t old_length = 0;
CHECK(array->length()->ToArrayIndex(&old_length));
DCHECK_EQ(length, old_length);
#endif
return;
if (length <= old_length) {
// Cannot delete entries so do nothing.
return;
}
// Transition to DICTIONARY_ELEMENTS.
// Convert to dictionary mode
Handle<NumberDictionary> new_element_dictionary =
old_length == 0 ? isolate->factory()->empty_slow_element_dictionary()
: array->GetElementsAccessor()->Normalize(array);
// Migrate map.
Handle<Map> new_map = Map::Copy(isolate, handle(array->map(), isolate),
"SlowCopyForSetLengthImpl");
new_map->set_is_extensible(false);
new_map->set_elements_kind(DICTIONARY_ELEMENTS);
JSObject::MigrateToMap(array, new_map);
if (!new_element_dictionary.is_null()) {
array->set_elements(*new_element_dictionary);
}
if (array->elements() !=
ReadOnlyRoots(isolate).empty_slow_element_dictionary()) {
Handle<NumberDictionary> dictionary(array->element_dictionary(), isolate);
// Make sure we never go back to the fast case
array->RequireSlowElements(*dictionary);
JSObject::ApplyAttributesToDictionary(isolate, ReadOnlyRoots(isolate),
dictionary,
PropertyAttributes::SEALED);
}
// Set length
Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length);
array->set_length(*length_obj);
}
};

View File

@ -3771,12 +3771,10 @@ bool JSObject::IsExtensible(Handle<JSObject> object) {
return object->map()->is_extensible();
}
namespace {
template <typename Dictionary>
void ApplyAttributesToDictionary(Isolate* isolate, ReadOnlyRoots roots,
Handle<Dictionary> dictionary,
const PropertyAttributes attributes) {
void JSObject::ApplyAttributesToDictionary(
Isolate* isolate, ReadOnlyRoots roots, Handle<Dictionary> dictionary,
const PropertyAttributes attributes) {
int capacity = dictionary->Capacity();
for (int i = 0; i < capacity; i++) {
Object k;
@ -3794,8 +3792,6 @@ void ApplyAttributesToDictionary(Isolate* isolate, ReadOnlyRoots roots,
}
}
} // namespace
template <PropertyAttributes attrs>
Maybe<bool> JSObject::PreventExtensionsWithTransition(
Handle<JSObject> object, ShouldThrow should_throw) {
@ -3911,11 +3907,13 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition(
if (object->IsJSGlobalObject()) {
Handle<GlobalDictionary> dictionary(
JSGlobalObject::cast(*object)->global_dictionary(), isolate);
ApplyAttributesToDictionary(isolate, roots, dictionary, attrs);
JSObject::ApplyAttributesToDictionary(isolate, roots, dictionary,
attrs);
} else {
Handle<NameDictionary> dictionary(object->property_dictionary(),
isolate);
ApplyAttributesToDictionary(isolate, roots, dictionary, attrs);
JSObject::ApplyAttributesToDictionary(isolate, roots, dictionary,
attrs);
}
}
}
@ -3948,8 +3946,8 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition(
// Make sure we never go back to the fast case
object->RequireSlowElements(*dictionary);
if (attrs != NONE) {
ApplyAttributesToDictionary(isolate, ReadOnlyRoots(isolate), dictionary,
attrs);
JSObject::ApplyAttributesToDictionary(isolate, ReadOnlyRoots(isolate),
dictionary, attrs);
}
}

View File

@ -797,6 +797,11 @@ class JSObject : public JSReceiver {
static bool AllCanRead(LookupIterator* it);
static bool AllCanWrite(LookupIterator* it);
template <typename Dictionary>
static void ApplyAttributesToDictionary(Isolate* isolate, ReadOnlyRoots roots,
Handle<Dictionary> dictionary,
const PropertyAttributes attributes);
private:
friend class JSReceiver;
friend class Object;

View File

@ -561,3 +561,14 @@ assertEquals(arr, ['a', 0.5]);
Object.freeze(arr);
arr = arr.concat([1.5, 'b']);
assertEquals(arr, ['a', 0.5, 1.5, 'b']);
// Regression test with change length
var arr = ['a', 'b'];
Object.freeze(arr);
assertEquals(arr.length, 2);
arr.length = 3;
assertEquals(arr.length, 2);
arr[2] = 'c';
assertEquals(arr[2], undefined);
arr.length = 1;
assertEquals(arr.length, 2);

View File

@ -266,3 +266,15 @@ assertEquals(arr, ['a', 0.5]);
Object.preventExtensions(arr);
arr = arr.concat([1.5, 'b']);
assertEquals(arr, ['a', 0.5, 1.5, 'b']);
// Regression test with change length
var arr = ['a', 'b'];
Object.preventExtensions(arr);
assertEquals(arr.length, 2);
arr.length = 3;
assertEquals(arr.length, 3);
arr[2] = 'c';
assertEquals(arr[2], undefined);
arr.length = 1;
assertEquals(arr.length, 1);
assertEquals(arr[1], undefined);

View File

@ -537,3 +537,14 @@ assertEquals(arr, ['a', 0.5]);
Object.seal(arr);
arr = arr.concat([1.5, 'b']);
assertEquals(arr, ['a', 0.5, 1.5, 'b']);
// Regression test with change length
var arr = ['a', 'b'];
Object.seal(arr);
assertEquals(arr.length, 2);
arr.length = 3;
assertEquals(arr.length, 3);
arr[2] = 'c';
assertEquals(arr[2], undefined);
arr.length = 1;
assertEquals(arr.length, 2);