[elements] Introduce SloppyArgumentsElements helper

This CL introduces SloppyArgumentsElements to encapsulate all the constants
for SLOW_ and FAST_SLOPPY_ARGUMENTS_KINDS. This will serve as a better
documentation and reduces the use of undocumented constants.

Change-Id: I7a5b4e79f02573161d8a83aaf6f69fc490883aa5
Reviewed-on: https://chromium-review.googlesource.com/467666
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#44433}
This commit is contained in:
Camillo Bruni 2017-04-06 10:51:47 +02:00 committed by Commit Bot
parent b5b87aecf1
commit 4817c544ab
8 changed files with 271 additions and 146 deletions

View File

@ -7167,7 +7167,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
elements_kind != GetInitialFastElementsKind()) {
possible_transitioned_maps.Add(map);
}
if (IsSloppyArgumentsElements(elements_kind)) {
if (IsSloppyArgumentsElementsKind(elements_kind)) {
HInstruction* result =
BuildKeyedGeneric(access_type, expr, slot, object, key, val);
*has_side_effects = result->HasObservableSideEffects();

View File

@ -86,8 +86,7 @@ inline bool IsDictionaryElementsKind(ElementsKind kind) {
return kind == DICTIONARY_ELEMENTS;
}
inline bool IsSloppyArgumentsElements(ElementsKind kind) {
inline bool IsSloppyArgumentsElementsKind(ElementsKind kind) {
return kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS ||
kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
}

View File

@ -1152,8 +1152,8 @@ class ElementsAccessorBase : public ElementsAccessor {
}
uint32_t nof_indices = 0;
bool needs_sorting =
IsDictionaryElementsKind(kind()) || IsSloppyArgumentsElements(kind());
bool needs_sorting = IsDictionaryElementsKind(kind()) ||
IsSloppyArgumentsElementsKind(kind());
combined_keys = Subclass::DirectCollectElementIndicesImpl(
isolate, object, backing_store,
needs_sorting ? GetKeysConversion::kKeepNumbers : convert, filter,
@ -1178,7 +1178,7 @@ class ElementsAccessorBase : public ElementsAccessor {
// For holey elements and arguments we might have to shrink the collected
// keys since the estimates might be off.
if (IsHoleyElementsKind(kind()) || IsSloppyArgumentsElements(kind())) {
if (IsHoleyElementsKind(kind()) || IsSloppyArgumentsElementsKind(kind())) {
// Shrink combined_keys to the final size.
int final_size = nof_indices + nof_property_keys;
DCHECK_LE(final_size, combined_keys->length());
@ -1840,7 +1840,7 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
// Dynamically ask for the elements kind here since we manually redirect
// the operations for argument backing stores.
if (obj->GetElementsKind() == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
FixedArray::cast(obj->elements())->set(1, empty);
SloppyArgumentsElements::cast(obj->elements())->set_arguments(empty);
} else {
obj->set_elements(empty);
}
@ -3098,31 +3098,31 @@ class SloppyArgumentsElementsAccessor
USE(KindTraits::Kind);
}
static void ConvertArgumentsStoreResult(
Isolate* isolate, Handle<SloppyArgumentsElements> elements,
Handle<Object> result) {
UNREACHABLE();
}
static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase* parameters,
uint32_t entry) {
Handle<FixedArray> parameter_map(FixedArray::cast(parameters), isolate);
uint32_t length = parameter_map->length() - 2;
Handle<SloppyArgumentsElements> elements(
SloppyArgumentsElements::cast(parameters), isolate);
uint32_t length = elements->parameter_map_length();
if (entry < length) {
// Read context mapped entry.
DisallowHeapAllocation no_gc;
Object* probe = parameter_map->get(entry + 2);
Context* context = Context::cast(parameter_map->get(0));
Object* probe = elements->get_mapped_entry(entry);
DCHECK(!probe->IsTheHole(isolate));
Context* context = elements->context();
int context_entry = Smi::cast(probe)->value();
DCHECK(!context->get(context_entry)->IsTheHole(isolate));
return handle(context->get(context_entry), isolate);
} else {
// Object is not mapped, defer to the arguments.
// Entry is not context mapped, defer to the arguments.
Handle<Object> result = ArgumentsAccessor::GetImpl(
isolate, FixedArray::cast(parameter_map->get(1)), entry - length);
// Elements of the arguments object in slow mode might be slow aliases.
if (result->IsAliasedArgumentsEntry()) {
DisallowHeapAllocation no_gc;
AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(*result);
Context* context = Context::cast(parameter_map->get(0));
int context_entry = alias->aliased_context_slot();
DCHECK(!context->get(context_entry)->IsTheHole(isolate));
return handle(context->get(context_entry), isolate);
}
return result;
isolate, elements->arguments(), entry - length);
return Subclass::ConvertArgumentsStoreResult(isolate, elements, result);
}
}
@ -3143,20 +3143,24 @@ class SloppyArgumentsElementsAccessor
static inline void SetImpl(FixedArrayBase* store, uint32_t entry,
Object* value) {
FixedArray* parameter_map = FixedArray::cast(store);
uint32_t length = parameter_map->length() - 2;
SloppyArgumentsElements* elements = SloppyArgumentsElements::cast(store);
uint32_t length = elements->parameter_map_length();
if (entry < length) {
Object* probe = parameter_map->get(entry + 2);
Context* context = Context::cast(parameter_map->get(0));
// Store context mapped entry.
DisallowHeapAllocation no_gc;
Object* probe = elements->get_mapped_entry(entry);
DCHECK(!probe->IsTheHole(store->GetIsolate()));
Context* context = elements->context();
int context_entry = Smi::cast(probe)->value();
DCHECK(!context->get(context_entry)->IsTheHole(store->GetIsolate()));
context->set(context_entry, value);
} else {
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
// Entry is not context mapped defer to arguments.
FixedArray* arguments = elements->arguments();
Object* current = ArgumentsAccessor::GetRaw(arguments, entry - length);
if (current->IsAliasedArgumentsEntry()) {
AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(current);
Context* context = Context::cast(parameter_map->get(0));
Context* context = elements->context();
int context_entry = alias->aliased_context_slot();
DCHECK(!context->get(context_entry)->IsTheHole(store->GetIsolate()));
context->set(context_entry, value);
@ -3173,30 +3177,32 @@ class SloppyArgumentsElementsAccessor
UNREACHABLE();
}
static uint32_t GetCapacityImpl(JSObject* holder,
FixedArrayBase* backing_store) {
FixedArray* parameter_map = FixedArray::cast(backing_store);
FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
return parameter_map->length() - 2 +
static uint32_t GetCapacityImpl(JSObject* holder, FixedArrayBase* store) {
SloppyArgumentsElements* elements = SloppyArgumentsElements::cast(store);
FixedArray* arguments = elements->arguments();
return elements->parameter_map_length() +
ArgumentsAccessor::GetCapacityImpl(holder, arguments);
}
static uint32_t GetMaxNumberOfEntries(JSObject* holder,
FixedArrayBase* backing_store) {
FixedArray* parameter_map = FixedArray::cast(backing_store);
FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
return parameter_map->length() - 2 +
SloppyArgumentsElements* elements =
SloppyArgumentsElements::cast(backing_store);
FixedArrayBase* arguments = elements->arguments();
return elements->parameter_map_length() +
ArgumentsAccessor::GetMaxNumberOfEntries(holder, arguments);
}
static uint32_t NumberOfElementsImpl(JSObject* receiver,
FixedArrayBase* backing_store) {
FixedArray* parameter_map = FixedArray::cast(backing_store);
FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
Isolate* isolate = receiver->GetIsolate();
SloppyArgumentsElements* elements =
SloppyArgumentsElements::cast(backing_store);
FixedArrayBase* arguments = elements->arguments();
uint32_t nof_elements = 0;
uint32_t length = parameter_map->length() - 2;
uint32_t length = elements->parameter_map_length();
for (uint32_t entry = 0; entry < length; entry++) {
if (HasParameterMapArg(parameter_map, entry)) nof_elements++;
if (HasParameterMapArg(isolate, elements, entry)) nof_elements++;
}
return nof_elements +
ArgumentsAccessor::NumberOfElementsImpl(receiver, arguments);
@ -3217,71 +3223,75 @@ class SloppyArgumentsElementsAccessor
static bool HasEntryImpl(Isolate* isolate, FixedArrayBase* parameters,
uint32_t entry) {
FixedArray* parameter_map = FixedArray::cast(parameters);
uint32_t length = parameter_map->length() - 2;
SloppyArgumentsElements* elements =
SloppyArgumentsElements::cast(parameters);
uint32_t length = elements->parameter_map_length();
if (entry < length) {
return HasParameterMapArg(parameter_map, entry);
return HasParameterMapArg(isolate, elements, entry);
}
FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
FixedArrayBase* arguments = elements->arguments();
return ArgumentsAccessor::HasEntryImpl(isolate, arguments, entry - length);
}
static bool HasAccessorsImpl(JSObject* holder,
FixedArrayBase* backing_store) {
FixedArray* parameter_map = FixedArray::cast(backing_store);
FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
SloppyArgumentsElements* elements =
SloppyArgumentsElements::cast(backing_store);
FixedArray* arguments = elements->arguments();
return ArgumentsAccessor::HasAccessorsImpl(holder, arguments);
}
static uint32_t GetIndexForEntryImpl(FixedArrayBase* parameters,
uint32_t entry) {
FixedArray* parameter_map = FixedArray::cast(parameters);
uint32_t length = parameter_map->length() - 2;
SloppyArgumentsElements* elements =
SloppyArgumentsElements::cast(parameters);
uint32_t length = elements->parameter_map_length();
if (entry < length) return entry;
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
FixedArray* arguments = elements->arguments();
return ArgumentsAccessor::GetIndexForEntryImpl(arguments, entry - length);
}
static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
FixedArrayBase* parameters,
uint32_t index, PropertyFilter filter) {
FixedArray* parameter_map = FixedArray::cast(parameters);
if (HasParameterMapArg(parameter_map, index)) return index;
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
SloppyArgumentsElements* elements =
SloppyArgumentsElements::cast(parameters);
if (HasParameterMapArg(isolate, elements, index)) return index;
FixedArray* arguments = elements->arguments();
uint32_t entry = ArgumentsAccessor::GetEntryForIndexImpl(
isolate, holder, arguments, index, filter);
if (entry == kMaxUInt32) return kMaxUInt32;
return (parameter_map->length() - 2) + entry;
return elements->parameter_map_length() + entry;
}
static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
FixedArray* parameter_map = FixedArray::cast(holder->elements());
uint32_t length = parameter_map->length() - 2;
SloppyArgumentsElements* elements =
SloppyArgumentsElements::cast(holder->elements());
uint32_t length = elements->parameter_map_length();
if (entry < length) {
return PropertyDetails(kData, NONE, 0, PropertyCellType::kNoCell);
}
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
FixedArray* arguments = elements->arguments();
return ArgumentsAccessor::GetDetailsImpl(arguments, entry - length);
}
static bool HasParameterMapArg(FixedArray* parameter_map, uint32_t index) {
uint32_t length = parameter_map->length() - 2;
static bool HasParameterMapArg(Isolate* isolate,
SloppyArgumentsElements* elements,
uint32_t index) {
uint32_t length = elements->parameter_map_length();
if (index >= length) return false;
return !parameter_map->get(index + 2)->IsTheHole(
parameter_map->GetIsolate());
return !elements->get_mapped_entry(index)->IsTheHole(isolate);
}
static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
FixedArray* parameter_map = FixedArray::cast(obj->elements());
uint32_t length = static_cast<uint32_t>(parameter_map->length()) - 2;
SloppyArgumentsElements* elements =
SloppyArgumentsElements::cast(obj->elements());
uint32_t length = elements->parameter_map_length();
if (entry < length) {
// TODO(kmillikin): We could check if this was the last aliased
// parameter, and revert to normal elements in that case. That
// would enable GC of the context.
parameter_map->set_the_hole(entry + 2);
elements->set_mapped_entry(entry, obj->GetHeap()->the_hole_value());
} else {
Subclass::DeleteFromArguments(obj, entry - length);
}
@ -3308,11 +3318,12 @@ class SloppyArgumentsElementsAccessor
Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
uint32_t insertion_index = 0) {
Handle<FixedArray> parameter_map(FixedArray::cast(*backing_store), isolate);
uint32_t length = parameter_map->length() - 2;
Handle<SloppyArgumentsElements> elements =
Handle<SloppyArgumentsElements>::cast(backing_store);
uint32_t length = elements->parameter_map_length();
for (uint32_t i = 0; i < length; ++i) {
if (parameter_map->get(i + 2)->IsTheHole(isolate)) continue;
if (elements->get_mapped_entry(i)->IsTheHole(isolate)) continue;
if (convert == GetKeysConversion::kConvertToString) {
Handle<String> index_string = isolate->factory()->Uint32ToString(i);
list->set(insertion_index, *index_string);
@ -3322,7 +3333,7 @@ class SloppyArgumentsElementsAccessor
insertion_index++;
}
Handle<FixedArrayBase> store(FixedArrayBase::cast(parameter_map->get(1)));
Handle<FixedArray> store(elements->arguments(), isolate);
return ArgumentsAccessor::DirectCollectElementIndicesImpl(
isolate, object, store, convert, filter, list, nof_indices,
insertion_index);
@ -3334,20 +3345,19 @@ class SloppyArgumentsElementsAccessor
uint32_t start_from, uint32_t length) {
DCHECK(JSObject::PrototypeHasNoElements(isolate, *object));
Handle<Map> original_map = handle(object->map(), isolate);
Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()),
isolate);
Handle<SloppyArgumentsElements> elements(
SloppyArgumentsElements::cast(object->elements()), isolate);
bool search_for_hole = value->IsUndefined(isolate);
for (uint32_t k = start_from; k < length; ++k) {
uint32_t entry = GetEntryForIndexImpl(isolate, *object, *parameter_map, k,
ALL_PROPERTIES);
uint32_t entry =
GetEntryForIndexImpl(isolate, *object, *elements, k, ALL_PROPERTIES);
if (entry == kMaxUInt32) {
if (search_for_hole) return Just(true);
continue;
}
Handle<Object> element_k =
Subclass::GetImpl(isolate, *parameter_map, entry);
Handle<Object> element_k = Subclass::GetImpl(isolate, *elements, entry);
if (element_k->IsAccessorPair()) {
LookupIterator it(isolate, object, k, LookupIterator::OWN);
@ -3376,18 +3386,17 @@ class SloppyArgumentsElementsAccessor
uint32_t start_from, uint32_t length) {
DCHECK(JSObject::PrototypeHasNoElements(isolate, *object));
Handle<Map> original_map = handle(object->map(), isolate);
Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()),
isolate);
Handle<SloppyArgumentsElements> elements(
SloppyArgumentsElements::cast(object->elements()), isolate);
for (uint32_t k = start_from; k < length; ++k) {
uint32_t entry = GetEntryForIndexImpl(isolate, *object, *parameter_map, k,
ALL_PROPERTIES);
uint32_t entry =
GetEntryForIndexImpl(isolate, *object, *elements, k, ALL_PROPERTIES);
if (entry == kMaxUInt32) {
continue;
}
Handle<Object> element_k =
Subclass::GetImpl(isolate, *parameter_map, entry);
Handle<Object> element_k = Subclass::GetImpl(isolate, *elements, entry);
if (element_k->IsAccessorPair()) {
LookupIterator it(isolate, object, k, LookupIterator::OWN);
@ -3424,10 +3433,26 @@ class SlowSloppyArgumentsElementsAccessor
SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
static Handle<Object> ConvertArgumentsStoreResult(
Isolate* isolate, Handle<SloppyArgumentsElements> elements,
Handle<Object> result) {
// Elements of the arguments object in slow mode might be slow aliases.
if (result->IsAliasedArgumentsEntry()) {
DisallowHeapAllocation no_gc;
AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(*result);
Context* context = elements->context();
int context_entry = alias->aliased_context_slot();
DCHECK(!context->get(context_entry)->IsTheHole(isolate));
return handle(context->get(context_entry), isolate);
}
return result;
}
static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements()));
Isolate* isolate = obj->GetIsolate();
Handle<SloppyArgumentsElements> elements(
SloppyArgumentsElements::cast(obj->elements()), isolate);
Handle<SeededNumberDictionary> dict(
SeededNumberDictionary::cast(parameter_map->get(1)));
SeededNumberDictionary::cast(elements->arguments()), isolate);
// TODO(verwaest): Remove reliance on index in Shrink.
uint32_t index = GetIndexForEntryImpl(*dict, entry);
Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
@ -3435,18 +3460,20 @@ class SlowSloppyArgumentsElementsAccessor
DCHECK(result->IsTrue(dict->GetIsolate()));
Handle<FixedArray> new_elements =
SeededNumberDictionary::Shrink(dict, index);
parameter_map->set(1, *new_elements);
elements->set_arguments(*new_elements);
}
static void AddImpl(Handle<JSObject> object, uint32_t index,
Handle<Object> value, PropertyAttributes attributes,
uint32_t new_capacity) {
Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
Handle<FixedArrayBase> old_elements(
FixedArrayBase::cast(parameter_map->get(1)));
Isolate* isolate = object->GetIsolate();
Handle<SloppyArgumentsElements> elements(
SloppyArgumentsElements::cast(object->elements()), isolate);
Handle<FixedArrayBase> old_arguments(
FixedArrayBase::cast(elements->arguments()), isolate);
Handle<SeededNumberDictionary> dictionary =
old_elements->IsSeededNumberDictionary()
? Handle<SeededNumberDictionary>::cast(old_elements)
old_arguments->IsSeededNumberDictionary()
? Handle<SeededNumberDictionary>::cast(old_arguments)
: JSObject::NormalizeElements(object);
PropertyDetails details(kData, attributes, 0, PropertyCellType::kNoCell);
Handle<SeededNumberDictionary> new_dictionary =
@ -3454,7 +3481,7 @@ class SlowSloppyArgumentsElementsAccessor
details, object);
if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
if (*dictionary != *new_dictionary) {
FixedArray::cast(object->elements())->set(1, *new_dictionary);
elements->set_arguments(*new_dictionary);
}
}
@ -3462,19 +3489,20 @@ class SlowSloppyArgumentsElementsAccessor
Handle<FixedArrayBase> store, uint32_t entry,
Handle<Object> value,
PropertyAttributes attributes) {
Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(store);
uint32_t length = parameter_map->length() - 2;
Isolate* isolate = store->GetIsolate();
Handle<SloppyArgumentsElements> elements =
Handle<SloppyArgumentsElements>::cast(store);
uint32_t length = elements->parameter_map_length();
if (entry < length) {
Object* probe = parameter_map->get(entry + 2);
Object* probe = elements->get_mapped_entry(entry);
DCHECK(!probe->IsTheHole(isolate));
Context* context = Context::cast(parameter_map->get(0));
Context* context = elements->context();
int context_entry = Smi::cast(probe)->value();
DCHECK(!context->get(context_entry)->IsTheHole(isolate));
context->set(context_entry, *value);
// Redefining attributes of an aliased element destroys fast aliasing.
parameter_map->set_the_hole(isolate, entry + 2);
elements->set_mapped_entry(entry, isolate->heap()->the_hole_value());
// For elements that are still writable we re-establish slow aliasing.
if ((attributes & READ_ONLY) == 0) {
value = isolate->factory()->NewAliasedArgumentsEntry(context_entry);
@ -3482,17 +3510,16 @@ class SlowSloppyArgumentsElementsAccessor
PropertyDetails details(kData, attributes, 0, PropertyCellType::kNoCell);
Handle<SeededNumberDictionary> arguments(
SeededNumberDictionary::cast(parameter_map->get(1)), isolate);
SeededNumberDictionary::cast(elements->arguments()), isolate);
arguments = SeededNumberDictionary::AddNumberEntry(
arguments, entry, value, details, object);
// If the attributes were NONE, we would have called set rather than
// reconfigure.
DCHECK_NE(NONE, attributes);
object->RequireSlowElements(*arguments);
parameter_map->set(1, *arguments);
elements->set_arguments(*arguments);
} else {
Handle<FixedArrayBase> arguments(
FixedArrayBase::cast(parameter_map->get(1)), isolate);
Handle<FixedArrayBase> arguments(elements->arguments(), isolate);
DictionaryElementsAccessor::ReconfigureImpl(
object, arguments, entry - length, value, attributes);
}
@ -3511,10 +3538,17 @@ class FastSloppyArgumentsElementsAccessor
FastHoleyObjectElementsAccessor,
ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
static Handle<Object> ConvertArgumentsStoreResult(
Isolate* isolate, Handle<SloppyArgumentsElements> paramtere_map,
Handle<Object> result) {
DCHECK(!result->IsAliasedArgumentsEntry());
return result;
}
static Handle<FixedArray> GetArguments(Isolate* isolate,
FixedArrayBase* backing_store) {
FixedArray* parameter_map = FixedArray::cast(backing_store);
return Handle<FixedArray>(FixedArray::cast(parameter_map->get(1)), isolate);
FixedArrayBase* store) {
SloppyArgumentsElements* elements = SloppyArgumentsElements::cast(store);
return Handle<FixedArray>(elements->arguments(), isolate);
}
static Handle<JSObject> SliceImpl(Handle<JSObject> receiver, uint32_t start,
@ -3557,14 +3591,15 @@ class FastSloppyArgumentsElementsAccessor
Handle<Object> value, PropertyAttributes attributes,
uint32_t new_capacity) {
DCHECK_EQ(NONE, attributes);
Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
Handle<FixedArrayBase> old_elements(
FixedArrayBase::cast(parameter_map->get(1)));
if (old_elements->IsSeededNumberDictionary() ||
static_cast<uint32_t>(old_elements->length()) < new_capacity) {
Isolate* isolate = object->GetIsolate();
Handle<SloppyArgumentsElements> elements(
SloppyArgumentsElements::cast(object->elements()), isolate);
Handle<FixedArray> old_arguments(elements->arguments(), isolate);
if (old_arguments->IsSeededNumberDictionary() ||
static_cast<uint32_t>(old_arguments->length()) < new_capacity) {
GrowCapacityAndConvertImpl(object, new_capacity);
}
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
FixedArray* arguments = elements->arguments();
// For fast holey objects, the entry equals the index. The code above made
// sure that there's enough space to store the value. We cannot convert
// index to entry explicitly since the slot still contains the hole, so the
@ -3579,8 +3614,9 @@ class FastSloppyArgumentsElementsAccessor
PropertyAttributes attributes) {
Handle<SeededNumberDictionary> dictionary =
JSObject::NormalizeElements(object);
FixedArray::cast(*store)->set(1, *dictionary);
uint32_t length = static_cast<uint32_t>(store->length()) - 2;
SloppyArgumentsElements* elements = SloppyArgumentsElements::cast(*store);
elements->set_arguments(*dictionary);
uint32_t length = elements->parameter_map_length();
if (entry >= length) {
entry = dictionary->FindEntry(entry - length) + length;
}
@ -3605,19 +3641,22 @@ class FastSloppyArgumentsElementsAccessor
static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
uint32_t capacity) {
Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
Handle<FixedArray> old_elements(FixedArray::cast(parameter_map->get(1)));
Isolate* isolate = object->GetIsolate();
Handle<SloppyArgumentsElements> elements(
SloppyArgumentsElements::cast(object->elements()), isolate);
Handle<FixedArray> old_arguments(FixedArray::cast(elements->arguments()),
isolate);
ElementsKind from_kind = object->GetElementsKind();
// This method should only be called if there's a reason to update the
// elements.
DCHECK(from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS ||
static_cast<uint32_t>(old_elements->length()) < capacity);
Handle<FixedArrayBase> elements =
ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
static_cast<uint32_t>(old_arguments->length()) < capacity);
Handle<FixedArrayBase> arguments =
ConvertElementsWithCapacity(object, old_arguments, from_kind, capacity);
Handle<Map> new_map = JSObject::GetElementsTransitionMap(
object, FAST_SLOPPY_ARGUMENTS_ELEMENTS);
JSObject::MigrateToMap(object, new_map);
parameter_map->set(1, *elements);
elements->set_arguments(FixedArray::cast(*arguments));
JSObject::ValidateElements(object);
}
};

View File

@ -172,7 +172,7 @@ Handle<Object> ElementHandlerCompiler::GetKeyedLoadHandler(
}
ElementsKind elements_kind = receiver_map->elements_kind();
if (IsSloppyArgumentsElements(elements_kind)) {
if (IsSloppyArgumentsElementsKind(elements_kind)) {
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_KeyedLoadSloppyArgumentsStub);
return KeyedLoadSloppyArgumentsStub(isolate).GetCode();
}

View File

@ -200,6 +200,8 @@ bool HeapObject::IsFixedArray() const {
instance_type == TRANSITION_ARRAY_TYPE;
}
bool HeapObject::IsSloppyArgumentsElements() const { return IsFixedArray(); }
bool HeapObject::IsJSGeneratorObject() const {
return map()->instance_type() == JS_GENERATOR_OBJECT_TYPE ||
IsJSAsyncGeneratorObject();
@ -697,6 +699,7 @@ CAST_ACCESSOR(UnseededNumberDictionary)
CAST_ACCESSOR(WeakCell)
CAST_ACCESSOR(WeakFixedArray)
CAST_ACCESSOR(WeakHashTable)
CAST_ACCESSOR(SloppyArgumentsElements)
#define MAKE_STRUCT_CAST(NAME, Name, name) CAST_ACCESSOR(Name)
STRUCT_LIST(MAKE_STRUCT_CAST)
@ -1581,6 +1584,29 @@ FixedArrayBase* JSObject::elements() const {
return static_cast<FixedArrayBase*>(array);
}
Context* SloppyArgumentsElements::context() {
return Context::cast(get(kContextIndex));
}
FixedArray* SloppyArgumentsElements::arguments() {
return FixedArray::cast(get(kArgumentsIndex));
}
void SloppyArgumentsElements::set_arguments(FixedArray* arguments) {
set(kArgumentsIndex, arguments);
}
uint32_t SloppyArgumentsElements::parameter_map_length() {
return length() - kParameterMapStart;
}
Object* SloppyArgumentsElements::get_mapped_entry(uint32_t entry) {
return get(entry + kParameterMapStart);
}
void SloppyArgumentsElements::set_mapped_entry(uint32_t entry, Object* object) {
set(entry + kParameterMapStart, object);
}
void AllocationSite::Initialize() {
set_transition_info(Smi::kZero);
@ -4553,7 +4579,7 @@ bool Map::has_fast_double_elements() {
bool Map::has_fast_elements() { return IsFastElementsKind(elements_kind()); }
bool Map::has_sloppy_arguments_elements() {
return IsSloppyArgumentsElements(elements_kind());
return IsSloppyArgumentsElementsKind(elements_kind());
}
bool Map::has_fast_sloppy_arguments_elements() {
@ -7031,7 +7057,7 @@ ElementsKind JSObject::GetElementsKind() {
} else {
DCHECK(kind > DICTIONARY_ELEMENTS);
}
DCHECK(!IsSloppyArgumentsElements(kind) ||
DCHECK(!IsSloppyArgumentsElementsKind(kind) ||
(elements()->IsFixedArray() && elements()->length() >= 2));
}
#endif
@ -7085,7 +7111,7 @@ bool JSObject::HasSlowArgumentsElements() {
bool JSObject::HasSloppyArgumentsElements() {
return IsSloppyArgumentsElements(GetElementsKind());
return IsSloppyArgumentsElementsKind(GetElementsKind());
}
bool JSObject::HasStringWrapperElements() {

View File

@ -383,12 +383,40 @@ void PrintFixedArrayElements(std::ostream& os, FixedArray* array) {
}
}
void PrintSloppyArgumentElements(std::ostream& os, ElementsKind kind,
SloppyArgumentsElements* elements) {
FixedArray* arguments_store = elements->arguments();
os << "\n 0: context= " << Brief(elements->context())
<< "\n 1: arguments_store= " << Brief(arguments_store)
<< "\n parameter to context slot map:";
for (uint32_t i = 0; i < elements->parameter_map_length(); i++) {
uint32_t raw_index = i + SloppyArgumentsElements::kParameterMapStart;
os << "\n " << raw_index << ": param(" << i
<< ")= " << Brief(elements->get_mapped_entry(i));
}
if (arguments_store->length() == 0) return;
os << "\n }"
<< "\n - arguments_store = " << Brief(arguments_store) << " "
<< ElementsKindToString(arguments_store->map()->elements_kind()) << " {";
if (kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
PrintFixedArrayElements(os, arguments_store);
} else {
DCHECK_EQ(kind, SLOW_SLOPPY_ARGUMENTS_ELEMENTS);
SeededNumberDictionary::cast(arguments_store)->Print(os);
}
os << "\n }";
}
} // namespace
bool JSObject::PrintElements(std::ostream& os) { // NOLINT
void JSObject::PrintElements(std::ostream& os) { // NOLINT
// Don't call GetElementsKind, its validation code can cause the printer to
// fail when debugging.
if (elements()->length() == 0) return false;
os << " - elements= " << Brief(elements()) << " {";
if (elements()->length() == 0) {
os << " }\n";
return;
}
switch (map()->elements_kind()) {
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_SMI_ELEMENTS:
@ -417,20 +445,14 @@ bool JSObject::PrintElements(std::ostream& os) { // NOLINT
SeededNumberDictionary::cast(elements())->Print(os);
break;
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
FixedArray* p = FixedArray::cast(elements());
os << "\n parameter map:";
for (int i = 2; i < p->length(); i++) {
os << " " << (i - 2) << ":" << Brief(p->get(i));
}
os << "\n context: " << Brief(p->get(0))
<< "\n arguments: " << Brief(p->get(1));
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
PrintSloppyArgumentElements(os, map()->elements_kind(),
SloppyArgumentsElements::cast(elements()));
break;
}
case NO_ELEMENTS:
break;
}
return true;
os << "\n }\n";
}
@ -465,9 +487,7 @@ static void JSObjectPrintBody(std::ostream& os, JSObject* obj, // NOLINT
if (obj->PrintProperties(os)) os << "\n ";
os << "}\n";
if (print_elements && obj->elements()->length() > 0) {
os << " - elements = " << Brief(obj->elements()) << " {";
if (obj->PrintElements(os)) os << "\n ";
os << "}\n";
obj->PrintElements(os);
}
int embedder_fields = obj->GetEmbedderFieldCount();
if (embedder_fields > 0) {

View File

@ -7300,15 +7300,15 @@ bool JSObject::ReferencesObject(Object* obj) {
}
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
FixedArray* parameter_map = FixedArray::cast(elements());
SloppyArgumentsElements* elements =
SloppyArgumentsElements::cast(this->elements());
// Check the mapped parameters.
int length = parameter_map->length();
for (int i = 2; i < length; ++i) {
Object* value = parameter_map->get(i);
for (uint32_t i = 0; i < elements->parameter_map_length(); ++i) {
Object* value = elements->get_mapped_entry(i);
if (!value->IsTheHole(heap->isolate()) && value == obj) return true;
}
// Check the arguments.
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
FixedArray* arguments = elements->arguments();
kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
FAST_HOLEY_ELEMENTS;
if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
@ -15590,7 +15590,7 @@ Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
ElementsKind kind = object->GetElementsKind();
FixedArrayBase* elements = object->elements();
ElementsKind dictionary_kind = DICTIONARY_ELEMENTS;
if (IsSloppyArgumentsElements(kind)) {
if (IsSloppyArgumentsElementsKind(kind)) {
elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1));
dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
} else if (IsStringWrapperElementsKind(kind)) {
@ -15884,7 +15884,7 @@ int JSObject::GetFastElementsUsage() {
return IsJSArray() ? Smi::cast(JSArray::cast(this)->length())->value()
: store->length();
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
store = FixedArray::cast(FixedArray::cast(store)->get(1));
store = SloppyArgumentsElements::cast(store)->arguments();
// Fall through.
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_HOLEY_ELEMENTS:

View File

@ -1097,7 +1097,8 @@ template <class C> inline bool Is(Object* obj);
V(ObjectHashTable) \
V(ObjectHashSet) \
V(WeakHashTable) \
V(OrderedHashTable)
V(OrderedHashTable) \
V(SloppyArgumentsElements)
#define ODDBALL_LIST(V) \
V(Undefined, undefined_value) \
@ -2483,7 +2484,7 @@ class JSObject: public JSReceiver {
DECLARE_VERIFIER(JSObject)
#ifdef OBJECT_PRINT
bool PrintProperties(std::ostream& os); // NOLINT
bool PrintElements(std::ostream& os); // NOLINT
void PrintElements(std::ostream& os); // NOLINT
#endif
#if defined(DEBUG) || defined(OBJECT_PRINT)
void PrintTransitions(std::ostream& os); // NOLINT
@ -2877,6 +2878,46 @@ class FixedDoubleArray: public FixedArrayBase {
DISALLOW_IMPLICIT_CONSTRUCTORS(FixedDoubleArray);
};
// Helper class to access FAST_ and SLOW_SLOPPY_ARGUMENTS_ELEMENTS
//
// +---+-----------------------+
// | 0 | Context* context |
// +---------------------------+
// | 1 | FixedArray* arguments +----+ FAST_HOLEY_ELEMENTS
// +---------------------------+ v-----+-----------+
// | 2 | Object* param_1_map | | 0 | the_hole |
// |...| ... | | ... | ... |
// |n+1| Object* param_n_map | | n-1 | the_hole |
// +---------------------------+ | n | element_1 |
// | ... | ... |
// |n+m-1| element_m |
// +-----------------+
//
// Parameter maps give the index into the provided context. If a map entry is
// the_hole it means that the given entry has been deleted from the arguments
// object.
// The arguments backing store kind depends on the ElementsKind of the outer
// JSArgumentsObject:
// - FAST_SLOPPY_ARGUMENTS_ELEMENTS: FAST_HOLEY_ELEMENTS
// - SLOW_SLOPPY_ARGUMENTS_ELEMENTS: DICTIONARY_ELEMENTS
class SloppyArgumentsElements : public FixedArray {
public:
static const int kContextIndex = 0;
static const int kArgumentsIndex = 1;
static const uint32_t kParameterMapStart = 2;
inline Context* context();
inline FixedArray* arguments();
inline void set_arguments(FixedArray* arguments);
inline uint32_t parameter_map_length();
inline Object* get_mapped_entry(uint32_t entry);
inline void set_mapped_entry(uint32_t entry, Object* object);
DECLARE_CAST(SloppyArgumentsElements)
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(SloppyArgumentsElements);
};
class WeakFixedArray : public FixedArray {
public: