Commit b015dd11 authored by verwaest's avatar verwaest Committed by Commit bot

Move elements normalization to the ElementsAccessor

This speeds up element normalization.

BUG=

Review URL: https://codereview.chromium.org/1802733002

Cr-Commit-Position: refs/heads/master@{#34812}
parent 7f19628a
......@@ -845,6 +845,17 @@ class ElementsAccessorBase : public ElementsAccessor {
from, from_start, *to, from_kind, to_start, packed_size, copy_size);
}
Handle<SeededNumberDictionary> Normalize(Handle<JSObject> object) final {
return ElementsAccessorSubclass::NormalizeImpl(object,
handle(object->elements()));
}
static Handle<SeededNumberDictionary> NormalizeImpl(
Handle<JSObject> object, Handle<FixedArrayBase> elements) {
UNREACHABLE();
return Handle<SeededNumberDictionary>();
}
void CollectElementIndices(Handle<JSObject> object,
Handle<FixedArrayBase> backing_store,
KeyAccumulator* keys, uint32_t range,
......@@ -1293,6 +1304,36 @@ class FastElementsAccessor
typedef typename KindTraits::BackingStore BackingStore;
static Handle<SeededNumberDictionary> NormalizeImpl(
Handle<JSObject> object, Handle<FixedArrayBase> store) {
Isolate* isolate = store->GetIsolate();
ElementsKind kind = FastElementsAccessorSubclass::kind();
// Ensure that notifications fire if the array or object prototypes are
// normalizing.
if (IsFastSmiOrObjectElementsKind(kind)) {
isolate->UpdateArrayProtectorOnNormalizeElements(object);
}
int capacity = object->GetFastElementsUsage();
Handle<SeededNumberDictionary> dictionary =
SeededNumberDictionary::New(isolate, capacity);
PropertyDetails details = PropertyDetails::Empty();
bool used_as_prototype = object->map()->is_prototype_map();
int j = 0;
for (int i = 0; j < capacity; i++) {
if (IsHoleyElementsKind(kind)) {
if (BackingStore::cast(*store)->is_the_hole(i)) continue;
}
Handle<Object> value = FastElementsAccessorSubclass::GetImpl(*store, i);
dictionary = SeededNumberDictionary::AddNumberEntry(
dictionary, i, value, details, used_as_prototype);
j++;
}
return dictionary;
}
static void DeleteAtEnd(Handle<JSObject> obj,
Handle<BackingStore> backing_store, uint32_t entry) {
uint32_t length = static_cast<uint32_t>(backing_store->length());
......@@ -2403,6 +2444,13 @@ class FastSloppyArgumentsElementsAccessor
FastHoleyObjectElementsAccessor,
ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
static Handle<SeededNumberDictionary> NormalizeImpl(
Handle<JSObject> object, Handle<FixedArrayBase> elements) {
FixedArray* parameter_map = FixedArray::cast(*elements);
Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
return FastHoleyObjectElementsAccessor::NormalizeImpl(object, arguments);
}
static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
FixedArray* parameter_map = FixedArray::cast(obj->elements());
Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
......@@ -2625,6 +2673,11 @@ class FastStringWrapperElementsAccessor
: StringWrapperElementsAccessor<
FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>>(name) {}
static Handle<SeededNumberDictionary> NormalizeImpl(
Handle<JSObject> object, Handle<FixedArrayBase> elements) {
return FastHoleyObjectElementsAccessor::NormalizeImpl(object, elements);
}
};
class SlowStringWrapperElementsAccessor
......
......@@ -149,6 +149,8 @@ class ElementsAccessor {
virtual Handle<Object> Shift(Handle<JSArray> receiver) = 0;
virtual Handle<SeededNumberDictionary> Normalize(Handle<JSObject> object) = 0;
protected:
friend class LookupIterator;
......
......@@ -5696,35 +5696,6 @@ void JSObject::ResetElements(Handle<JSObject> object) {
}
static Handle<SeededNumberDictionary> CopyFastElementsToDictionary(
Handle<FixedArrayBase> array, int length,
Handle<SeededNumberDictionary> dictionary, bool used_as_prototype) {
Isolate* isolate = array->GetIsolate();
Factory* factory = isolate->factory();
bool has_double_elements = array->IsFixedDoubleArray();
for (int i = 0; i < length; i++) {
Handle<Object> value;
if (has_double_elements) {
Handle<FixedDoubleArray> double_array =
Handle<FixedDoubleArray>::cast(array);
if (double_array->is_the_hole(i)) {
value = factory->the_hole_value();
} else {
value = factory->NewHeapNumber(double_array->get_scalar(i));
}
} else {
value = handle(Handle<FixedArray>::cast(array)->get(i), isolate);
}
if (!value->IsTheHole()) {
PropertyDetails details = PropertyDetails::Empty();
dictionary = SeededNumberDictionary::AddNumberEntry(
dictionary, i, value, details, used_as_prototype);
}
}
return dictionary;
}
void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) {
if (dictionary->requires_slow_elements()) return;
dictionary->set_requires_slow_elements();
......@@ -5735,40 +5706,23 @@ void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) {
}
Handle<SeededNumberDictionary> JSObject::GetNormalizedElementDictionary(
Handle<JSObject> object, Handle<FixedArrayBase> elements) {
DCHECK(!object->HasDictionaryElements());
DCHECK(!object->HasSlowArgumentsElements());
Isolate* isolate = object->GetIsolate();
// Ensure that notifications fire if the array or object prototypes are
// normalizing.
isolate->UpdateArrayProtectorOnNormalizeElements(object);
int length = object->IsJSArray()
? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
: elements->length();
int used = object->GetFastElementsUsage();
Handle<SeededNumberDictionary> dictionary =
SeededNumberDictionary::New(isolate, used);
return CopyFastElementsToDictionary(elements, length, dictionary,
object->map()->is_prototype_map());
}
Handle<SeededNumberDictionary> JSObject::NormalizeElements(
Handle<JSObject> object) {
DCHECK(!object->HasFixedTypedArrayElements());
Isolate* isolate = object->GetIsolate();
// Find the backing store.
Handle<FixedArrayBase> elements(object->elements(), isolate);
bool is_arguments = object->HasSloppyArgumentsElements();
if (is_arguments) {
FixedArray* parameter_map = FixedArray::cast(*elements);
elements = handle(FixedArrayBase::cast(parameter_map->get(1)), isolate);
}
{
DisallowHeapAllocation no_gc;
FixedArrayBase* elements = object->elements();
if (elements->IsDictionary()) {
return Handle<SeededNumberDictionary>::cast(elements);
if (is_arguments) {
FixedArray* parameter_map = FixedArray::cast(elements);
elements = FixedArrayBase::cast(parameter_map->get(1));
}
if (elements->IsDictionary()) {
return handle(SeededNumberDictionary::cast(elements), isolate);
}
}
DCHECK(object->HasFastSmiOrObjectElements() ||
......@@ -5777,7 +5731,7 @@ Handle<SeededNumberDictionary> JSObject::NormalizeElements(
object->HasFastStringWrapperElements());
Handle<SeededNumberDictionary> dictionary =
GetNormalizedElementDictionary(object, elements);
object->GetElementsAccessor()->Normalize(object);
// Switch to using the dictionary as the backing storage for elements.
ElementsKind target_kind = is_arguments
......@@ -7764,8 +7718,7 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition(
: object->elements()->length();
new_element_dictionary =
length == 0 ? isolate->factory()->empty_slow_element_dictionary()
: GetNormalizedElementDictionary(
object, handle(object->elements()));
: object->GetElementsAccessor()->Normalize(object);
}
Handle<Symbol> transition_marker;
......
......@@ -2541,9 +2541,6 @@ class JSObject: public JSReceiver {
static Handle<Smi> GetOrCreateIdentityHash(Handle<JSObject> object);
static Handle<SeededNumberDictionary> GetNormalizedElementDictionary(
Handle<JSObject> object, Handle<FixedArrayBase> elements);
// Helper for fast versions of preventExtensions, seal, and freeze.
// attrs is one of NONE, SEALED, or FROZEN (depending on the operation).
template <PropertyAttributes attrs>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment