Commit a669705f authored by Frank Emrich's avatar Frank Emrich Committed by Commit Bot

[dict-proto] Add support for ordered property dicts, pt.3

This CL adds partial support for objects whose slow mode dictionaries
are OrderedNameDictionaries. This is the case for all slow mode objects
if V8_DICT_MODE_PROTOTYPES is enabled.

In particular, this part contains the remaining fixes to runtime code,
except for the class templating logic, which follows in a later CL.

Bug: v8:7569
Change-Id: Ib4d08d7d352125709ca916dfc75018dabf71b0cd
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2540549Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Reviewed-by: 's avatarPeter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Commit-Queue: Frank Emrich <emrich@google.com>
Cr-Commit-Position: refs/heads/master@{#71275}
parent dc45361e
...@@ -6596,27 +6596,27 @@ Local<v8::Object> v8::Object::New(Isolate* isolate) { ...@@ -6596,27 +6596,27 @@ Local<v8::Object> v8::Object::New(Isolate* isolate) {
return Utils::ToLocal(obj); return Utils::ToLocal(obj);
} }
Local<v8::Object> v8::Object::New(Isolate* isolate, namespace {
Local<Value> prototype_or_null,
Local<Name>* names, Local<Value>* values,
size_t length) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::Handle<i::Object> proto = Utils::OpenHandle(*prototype_or_null);
if (!Utils::ApiCheck(proto->IsNull() || proto->IsJSReceiver(),
"v8::Object::New", "prototype must be null or object")) {
return Local<v8::Object>();
}
LOG_API(i_isolate, Object, New);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
// We assume that this API is mostly used to create objects with named // TODO(v8:7569): This is a workaround for the Handle vs MaybeHandle difference
// properties, and so we default to creating a properties backing store // in the return types of the different Add functions:
// large enough to hold all of them, while we start with no elements // OrderedNameDictionary::Add returns MaybeHandle, NameDictionary::Add returns
// (see http://bit.ly/v8-fast-object-create-cpp for the motivation). // Handle.
i::Handle<i::NameDictionary> properties = template <typename T>
i::NameDictionary::New(i_isolate, static_cast<int>(length)); i::Handle<T> ToHandle(i::Handle<T> h) {
i::Handle<i::FixedArrayBase> elements = return h;
i_isolate->factory()->empty_fixed_array(); }
template <typename T>
i::Handle<T> ToHandle(i::MaybeHandle<T> h) {
return h.ToHandleChecked();
}
template <typename Dictionary>
void AddPropertiesAndElementsToObject(i::Isolate* i_isolate,
i::Handle<Dictionary>& properties,
i::Handle<i::FixedArrayBase>& elements,
Local<Name>* names, Local<Value>* values,
size_t length) {
for (size_t i = 0; i < length; ++i) { for (size_t i = 0; i < length; ++i) {
i::Handle<i::Name> name = Utils::OpenHandle(*names[i]); i::Handle<i::Name> name = Utils::OpenHandle(*names[i]);
i::Handle<i::Object> value = Utils::OpenHandle(*values[i]); i::Handle<i::Object> value = Utils::OpenHandle(*values[i]);
...@@ -6641,18 +6641,58 @@ Local<v8::Object> v8::Object::New(Isolate* isolate, ...@@ -6641,18 +6641,58 @@ Local<v8::Object> v8::Object::New(Isolate* isolate,
i::InternalIndex const entry = properties->FindEntry(i_isolate, name); i::InternalIndex const entry = properties->FindEntry(i_isolate, name);
if (entry.is_not_found()) { if (entry.is_not_found()) {
// Add the {name}/{value} pair as a new entry. // Add the {name}/{value} pair as a new entry.
properties = i::NameDictionary::Add(i_isolate, properties, name, value, properties = ToHandle(Dictionary::Add(
i::PropertyDetails::Empty()); i_isolate, properties, name, value, i::PropertyDetails::Empty()));
} else { } else {
// Overwrite the {entry} with the {value}. // Overwrite the {entry} with the {value}.
properties->ValueAtPut(entry, *value); properties->ValueAtPut(entry, *value);
} }
} }
} }
i::Handle<i::JSObject> obj = }
i_isolate->factory()->NewSlowJSObjectWithPropertiesAndElements(
i::Handle<i::HeapObject>::cast(proto), properties, elements); } // namespace
return Utils::ToLocal(obj);
Local<v8::Object> v8::Object::New(Isolate* isolate,
Local<Value> prototype_or_null,
Local<Name>* names, Local<Value>* values,
size_t length) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::Handle<i::Object> proto = Utils::OpenHandle(*prototype_or_null);
if (!Utils::ApiCheck(proto->IsNull() || proto->IsJSReceiver(),
"v8::Object::New", "prototype must be null or object")) {
return Local<v8::Object>();
}
LOG_API(i_isolate, Object, New);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
i::Handle<i::FixedArrayBase> elements =
i_isolate->factory()->empty_fixed_array();
// We assume that this API is mostly used to create objects with named
// properties, and so we default to creating a properties backing store
// large enough to hold all of them, while we start with no elements
// (see http://bit.ly/v8-fast-object-create-cpp for the motivation).
if (V8_DICT_MODE_PROTOTYPES_BOOL) {
i::Handle<i::OrderedNameDictionary> properties =
i::OrderedNameDictionary::Allocate(i_isolate, static_cast<int>(length))
.ToHandleChecked();
AddPropertiesAndElementsToObject(i_isolate, properties, elements, names,
values, length);
i::Handle<i::JSObject> obj =
i_isolate->factory()->NewSlowJSObjectWithPropertiesAndElements(
i::Handle<i::HeapObject>::cast(proto), properties, elements);
return Utils::ToLocal(obj);
} else {
i::Handle<i::NameDictionary> properties =
i::NameDictionary::New(i_isolate, static_cast<int>(length));
AddPropertiesAndElementsToObject(i_isolate, properties, elements, names,
values, length);
i::Handle<i::JSObject> obj =
i_isolate->factory()->NewSlowJSObjectWithPropertiesAndElements(
i::Handle<i::HeapObject>::cast(proto), properties, elements);
return Utils::ToLocal(obj);
}
} }
Local<v8::Value> v8::NumberObject::New(Isolate* isolate, double value) { Local<v8::Value> v8::NumberObject::New(Isolate* isolate, double value) {
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "src/codegen/assembler-inl.h" #include "src/codegen/assembler-inl.h"
#include "src/common/globals.h"
#include "src/date/date.h" #include "src/date/date.h"
#include "src/diagnostics/disasm.h" #include "src/diagnostics/disasm.h"
#include "src/diagnostics/disassembler.h" #include "src/diagnostics/disassembler.h"
...@@ -1641,6 +1642,11 @@ void JSObject::IncrementSpillStatistics(Isolate* isolate, ...@@ -1641,6 +1642,11 @@ void JSObject::IncrementSpillStatistics(Isolate* isolate,
info->number_of_slow_used_properties_ += dict.NumberOfElements(); info->number_of_slow_used_properties_ += dict.NumberOfElements();
info->number_of_slow_unused_properties_ += info->number_of_slow_unused_properties_ +=
dict.Capacity() - dict.NumberOfElements(); dict.Capacity() - dict.NumberOfElements();
} else if (V8_DICT_MODE_PROTOTYPES_BOOL) {
OrderedNameDictionary dict = property_dictionary_ordered();
info->number_of_slow_used_properties_ += dict.NumberOfElements();
info->number_of_slow_unused_properties_ +=
dict.Capacity() - dict.NumberOfElements();
} else { } else {
NameDictionary dict = property_dictionary(); NameDictionary dict = property_dictionary();
info->number_of_slow_used_properties_ += dict.NumberOfElements(); info->number_of_slow_used_properties_ += dict.NumberOfElements();
......
...@@ -2147,8 +2147,13 @@ Handle<JSObject> Factory::NewSlowJSObjectFromMap( ...@@ -2147,8 +2147,13 @@ Handle<JSObject> Factory::NewSlowJSObjectFromMap(
Handle<Map> map, int capacity, AllocationType allocation, Handle<Map> map, int capacity, AllocationType allocation,
Handle<AllocationSite> allocation_site) { Handle<AllocationSite> allocation_site) {
DCHECK(map->is_dictionary_map()); DCHECK(map->is_dictionary_map());
Handle<NameDictionary> object_properties = Handle<HeapObject> object_properties;
NameDictionary::New(isolate(), capacity); if (V8_DICT_MODE_PROTOTYPES_BOOL) {
object_properties =
OrderedNameDictionary::Allocate(isolate(), capacity).ToHandleChecked();
} else {
object_properties = NameDictionary::New(isolate(), capacity);
}
Handle<JSObject> js_object = Handle<JSObject> js_object =
NewJSObjectFromMap(map, allocation, allocation_site); NewJSObjectFromMap(map, allocation, allocation_site);
js_object->set_raw_properties_or_hash(*object_properties); js_object->set_raw_properties_or_hash(*object_properties);
...@@ -2156,8 +2161,12 @@ Handle<JSObject> Factory::NewSlowJSObjectFromMap( ...@@ -2156,8 +2161,12 @@ Handle<JSObject> Factory::NewSlowJSObjectFromMap(
} }
Handle<JSObject> Factory::NewSlowJSObjectWithPropertiesAndElements( Handle<JSObject> Factory::NewSlowJSObjectWithPropertiesAndElements(
Handle<HeapObject> prototype, Handle<NameDictionary> properties, Handle<HeapObject> prototype, Handle<HeapObject> properties,
Handle<FixedArrayBase> elements) { Handle<FixedArrayBase> elements) {
DCHECK_IMPLIES(V8_DICT_MODE_PROTOTYPES_BOOL,
properties->IsOrderedNameDictionary());
DCHECK_IMPLIES(!V8_DICT_MODE_PROTOTYPES_BOOL, properties->IsNameDictionary());
Handle<Map> object_map = isolate()->slow_object_with_object_prototype_map(); Handle<Map> object_map = isolate()->slow_object_with_object_prototype_map();
if (object_map->prototype() != *prototype) { if (object_map->prototype() != *prototype) {
object_map = Map::TransitionToPrototype(isolate(), object_map, prototype); object_map = Map::TransitionToPrototype(isolate(), object_map, prototype);
......
...@@ -512,7 +512,7 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> { ...@@ -512,7 +512,7 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
// fast elements, or a NumberDictionary, in which case the resulting // fast elements, or a NumberDictionary, in which case the resulting
// object will have dictionary elements. // object will have dictionary elements.
Handle<JSObject> NewSlowJSObjectWithPropertiesAndElements( Handle<JSObject> NewSlowJSObjectWithPropertiesAndElements(
Handle<HeapObject> prototype, Handle<NameDictionary> properties, Handle<HeapObject> prototype, Handle<HeapObject> properties,
Handle<FixedArrayBase> elements); Handle<FixedArrayBase> elements);
// JS arrays are pretenured when allocated by the parser. // JS arrays are pretenured when allocated by the parser.
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "src/extensions/ignition-statistics-extension.h" #include "src/extensions/ignition-statistics-extension.h"
#include "src/extensions/statistics-extension.h" #include "src/extensions/statistics-extension.h"
#include "src/extensions/trigger-failure-extension.h" #include "src/extensions/trigger-failure-extension.h"
#include "src/objects/objects.h"
#ifdef ENABLE_VTUNE_TRACEMARK #ifdef ENABLE_VTUNE_TRACEMARK
#include "src/extensions/vtunedomain-support-extension.h" #include "src/extensions/vtunedomain-support-extension.h"
#endif // ENABLE_VTUNE_TRACEMARK #endif // ENABLE_VTUNE_TRACEMARK
...@@ -5170,6 +5171,29 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from, ...@@ -5170,6 +5171,29 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
if (details.kind() != kData) continue; if (details.kind() != kData) continue;
JSObject::AddProperty(isolate(), to, key, value, details.attributes()); JSObject::AddProperty(isolate(), to, key, value, details.attributes());
} }
} else if (V8_DICT_MODE_PROTOTYPES_BOOL) {
// Copy all keys and values in enumeration order.
Handle<OrderedNameDictionary> properties = Handle<OrderedNameDictionary>(
from->property_dictionary_ordered(), isolate());
ReadOnlyRoots roots(isolate());
for (InternalIndex entry : properties->IterateEntries()) {
Object raw_key;
if (!properties->ToKey(roots, entry, &raw_key)) continue;
DCHECK(raw_key.IsName());
Handle<Name> key(Name::cast(raw_key), isolate());
// If the property is already there we skip it.
if (PropertyAlreadyExists(isolate(), to, key)) continue;
// Set the property.
Handle<Object> value =
Handle<Object>(properties->ValueAt(entry), isolate());
DCHECK(!value->IsCell());
DCHECK(!value->IsTheHole(isolate()));
PropertyDetails details = properties->DetailsAt(entry);
DCHECK_EQ(kData, details.kind());
JSObject::AddProperty(isolate(), to, key, value, details.attributes());
}
} else { } else {
// Copy all keys and values in enumeration order. // Copy all keys and values in enumeration order.
Handle<NameDictionary> properties = Handle<NameDictionary> properties =
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "src/objects/js-regexp.h" #include "src/objects/js-regexp.h"
#include "src/common/globals.h"
#include "src/objects/js-array-inl.h" #include "src/objects/js-array-inl.h"
#include "src/objects/js-regexp-inl.h" #include "src/objects/js-regexp-inl.h"
#include "src/regexp/regexp.h" #include "src/regexp/regexp.h"
...@@ -135,7 +136,12 @@ Handle<JSRegExpResultIndices> JSRegExpResultIndices::BuildIndices( ...@@ -135,7 +136,12 @@ Handle<JSRegExpResultIndices> JSRegExpResultIndices::BuildIndices(
// their corresponding capture indices. // their corresponding capture indices.
Handle<FixedArray> names(Handle<FixedArray>::cast(maybe_names)); Handle<FixedArray> names(Handle<FixedArray>::cast(maybe_names));
int num_names = names->length() >> 1; int num_names = names->length() >> 1;
Handle<NameDictionary> group_names = NameDictionary::New(isolate, num_names); Handle<HeapObject> group_names;
if (V8_DICT_MODE_PROTOTYPES_BOOL) {
group_names = isolate->factory()->NewOrderedNameDictionary(num_names);
} else {
group_names = isolate->factory()->NewNameDictionary(num_names);
}
for (int i = 0; i < num_names; i++) { for (int i = 0; i < num_names; i++) {
int base_offset = i * 2; int base_offset = i * 2;
int name_offset = base_offset; int name_offset = base_offset;
...@@ -147,8 +153,17 @@ Handle<JSRegExpResultIndices> JSRegExpResultIndices::BuildIndices( ...@@ -147,8 +153,17 @@ Handle<JSRegExpResultIndices> JSRegExpResultIndices::BuildIndices(
if (!capture_indices->IsUndefined(isolate)) { if (!capture_indices->IsUndefined(isolate)) {
capture_indices = Handle<JSArray>::cast(capture_indices); capture_indices = Handle<JSArray>::cast(capture_indices);
} }
group_names = NameDictionary::Add( if (V8_DICT_MODE_PROTOTYPES_BOOL) {
isolate, group_names, name, capture_indices, PropertyDetails::Empty()); group_names =
OrderedNameDictionary::Add(
isolate, Handle<OrderedNameDictionary>::cast(group_names), name,
capture_indices, PropertyDetails::Empty())
.ToHandleChecked();
} else {
group_names = NameDictionary::Add(
isolate, Handle<NameDictionary>::cast(group_names), name,
capture_indices, PropertyDetails::Empty());
}
} }
// Convert group_names to a JSObject and store at the groups property of the // Convert group_names to a JSObject and store at the groups property of the
......
...@@ -830,7 +830,7 @@ void CommonCopyEnumKeysTo(Isolate* isolate, Handle<Dictionary> dictionary, ...@@ -830,7 +830,7 @@ void CommonCopyEnumKeysTo(Isolate* isolate, Handle<Dictionary> dictionary,
continue; continue;
} else { } else {
if (Dictionary::kIsOrderedDictionaryType) { if (Dictionary::kIsOrderedDictionaryType) {
storage->set(properties, dictionary->ValueAt(i)); storage->set(properties, dictionary->NameAt(i));
} else { } else {
// If the dictionary does not store elements in enumeration order, // If the dictionary does not store elements in enumeration order,
// we need to sort it afterwards in CopyEnumKeysTo. To enable this we // we need to sort it afterwards in CopyEnumKeysTo. To enable this we
......
...@@ -1365,6 +1365,17 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject js_obj, ...@@ -1365,6 +1365,17 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject js_obj,
PropertyDetails details = cell.property_details(); PropertyDetails details = cell.property_details();
SetDataOrAccessorPropertyReference(details.kind(), entry, name, value); SetDataOrAccessorPropertyReference(details.kind(), entry, name, value);
} }
} else if (V8_DICT_MODE_PROTOTYPES_BOOL) {
OrderedNameDictionary dictionary = js_obj.property_dictionary_ordered();
ReadOnlyRoots roots(isolate);
for (InternalIndex i : dictionary.IterateEntries()) {
Object k = dictionary.KeyAt(i);
if (!dictionary.IsKey(roots, k)) continue;
Object value = dictionary.ValueAt(i);
PropertyDetails details = dictionary.DetailsAt(i);
SetDataOrAccessorPropertyReference(details.kind(), entry, Name::cast(k),
value);
}
} else { } else {
NameDictionary dictionary = js_obj.property_dictionary(); NameDictionary dictionary = js_obj.property_dictionary();
ReadOnlyRoots roots(isolate); ReadOnlyRoots roots(isolate);
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "src/ast/ast.h" #include "src/ast/ast.h"
#include "src/common/globals.h"
#include "src/execution/arguments-inl.h" #include "src/execution/arguments-inl.h"
#include "src/execution/isolate-inl.h" #include "src/execution/isolate-inl.h"
#include "src/logging/counters.h" #include "src/logging/counters.h"
...@@ -133,15 +134,30 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk( ...@@ -133,15 +134,30 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
} }
} }
} else { } else {
Handle<NameDictionary> dict(copy->property_dictionary(isolate), isolate); if (V8_DICT_MODE_PROTOTYPES_BOOL) {
for (InternalIndex i : dict->IterateEntries()) { Handle<OrderedNameDictionary> dict(
Object raw = dict->ValueAt(isolate, i); copy->property_dictionary_ordered(isolate), isolate);
if (!raw.IsJSObject(isolate)) continue; for (InternalIndex i : dict->IterateEntries()) {
DCHECK(dict->KeyAt(isolate, i).IsName()); Object raw = dict->ValueAt(i);
Handle<JSObject> value(JSObject::cast(raw), isolate); if (!raw.IsJSObject(isolate)) continue;
ASSIGN_RETURN_ON_EXCEPTION( DCHECK(dict->KeyAt(i).IsName());
isolate, value, VisitElementOrProperty(copy, value), JSObject); Handle<JSObject> value(JSObject::cast(raw), isolate);
if (copying) dict->ValueAtPut(i, *value); ASSIGN_RETURN_ON_EXCEPTION(
isolate, value, VisitElementOrProperty(copy, value), JSObject);
if (copying) dict->ValueAtPut(i, *value);
}
} else {
Handle<NameDictionary> dict(copy->property_dictionary(isolate),
isolate);
for (InternalIndex i : dict->IterateEntries()) {
Object raw = dict->ValueAt(isolate, i);
if (!raw.IsJSObject(isolate)) continue;
DCHECK(dict->KeyAt(isolate, i).IsName());
Handle<JSObject> value(JSObject::cast(raw), isolate);
ASSIGN_RETURN_ON_EXCEPTION(
isolate, value, VisitElementOrProperty(copy, value), JSObject);
if (copying) dict->ValueAtPut(i, *value);
}
} }
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "src/ast/prettyprinter.h" #include "src/ast/prettyprinter.h"
#include "src/common/globals.h"
#include "src/common/message-template.h" #include "src/common/message-template.h"
#include "src/debug/debug.h" #include "src/debug/debug.h"
#include "src/execution/arguments-inl.h" #include "src/execution/arguments-inl.h"
...@@ -365,11 +366,21 @@ RUNTIME_FUNCTION(Runtime_AddDictionaryProperty) { ...@@ -365,11 +366,21 @@ RUNTIME_FUNCTION(Runtime_AddDictionaryProperty) {
DCHECK(name->IsUniqueName()); DCHECK(name->IsUniqueName());
Handle<NameDictionary> dictionary(receiver->property_dictionary(), isolate);
PropertyDetails property_details(kData, NONE, PropertyCellType::kNoCell); PropertyDetails property_details(kData, NONE, PropertyCellType::kNoCell);
dictionary = if (V8_DICT_MODE_PROTOTYPES_BOOL) {
NameDictionary::Add(isolate, dictionary, name, value, property_details); Handle<OrderedNameDictionary> dictionary(
receiver->SetProperties(*dictionary); receiver->property_dictionary_ordered(), isolate);
dictionary = OrderedNameDictionary::Add(isolate, dictionary, name, value,
property_details)
.ToHandleChecked();
receiver->SetProperties(*dictionary);
} else {
Handle<NameDictionary> dictionary(receiver->property_dictionary(), isolate);
dictionary =
NameDictionary::Add(isolate, dictionary, name, value, property_details);
receiver->SetProperties(*dictionary);
}
return *value; return *value;
} }
...@@ -636,11 +647,21 @@ RUNTIME_FUNCTION(Runtime_GetProperty) { ...@@ -636,11 +647,21 @@ RUNTIME_FUNCTION(Runtime_GetProperty) {
} }
} else if (!holder->HasFastProperties()) { } else if (!holder->HasFastProperties()) {
// Attempt dictionary lookup. // Attempt dictionary lookup.
NameDictionary dictionary = holder->property_dictionary(); if (V8_DICT_MODE_PROTOTYPES_BOOL) {
InternalIndex entry = dictionary.FindEntry(isolate, key); OrderedNameDictionary dictionary =
if ((entry.is_found()) && holder->property_dictionary_ordered();
(dictionary.DetailsAt(entry).kind() == kData)) { InternalIndex entry = dictionary.FindEntry(isolate, *key);
return dictionary.ValueAt(entry); if (entry.is_found() &&
(dictionary.DetailsAt(entry).kind() == kData)) {
return dictionary.ValueAt(entry);
}
} else {
NameDictionary dictionary = holder->property_dictionary();
InternalIndex entry = dictionary.FindEntry(isolate, key);
if ((entry.is_found()) &&
(dictionary.DetailsAt(entry).kind() == kData)) {
return dictionary.ValueAt(entry);
}
} }
} }
} else if (key_obj->IsSmi()) { } else if (key_obj->IsSmi()) {
...@@ -760,10 +781,19 @@ RUNTIME_FUNCTION(Runtime_ShrinkPropertyDictionary) { ...@@ -760,10 +781,19 @@ RUNTIME_FUNCTION(Runtime_ShrinkPropertyDictionary) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(1, args.length()); DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
Handle<NameDictionary> dictionary(receiver->property_dictionary(), isolate); if (V8_DICT_MODE_PROTOTYPES_BOOL) {
Handle<NameDictionary> new_properties = Handle<OrderedNameDictionary> dictionary(
NameDictionary::Shrink(isolate, dictionary); receiver->property_dictionary_ordered(), isolate);
receiver->SetProperties(*new_properties); Handle<OrderedNameDictionary> new_properties =
OrderedNameDictionary::Shrink(isolate, dictionary);
receiver->SetProperties(*new_properties);
} else {
Handle<NameDictionary> dictionary(receiver->property_dictionary(), isolate);
Handle<NameDictionary> new_properties =
NameDictionary::Shrink(isolate, dictionary);
receiver->SetProperties(*new_properties);
}
return Smi::zero(); return Smi::zero();
} }
......
...@@ -28,6 +28,30 @@ int AddToSetAndGetHash(Isolate* isolate, Handle<JSObject> obj, ...@@ -28,6 +28,30 @@ int AddToSetAndGetHash(Isolate* isolate, Handle<JSObject> obj,
return Smi::ToInt(obj->GetHash()); return Smi::ToInt(obj->GetHash());
} }
int GetPropertyDictionaryHash(Handle<JSObject> obj) {
if (V8_DICT_MODE_PROTOTYPES_BOOL) {
return obj->property_dictionary_ordered().Hash();
} else {
return obj->property_dictionary().Hash();
}
}
int GetPropertyDictionaryLength(Handle<JSObject> obj) {
if (V8_DICT_MODE_PROTOTYPES_BOOL) {
return obj->property_dictionary_ordered().length();
} else {
return obj->property_dictionary().length();
}
}
void CheckIsDictionaryModeObject(Handle<JSObject> obj) {
if (V8_DICT_MODE_PROTOTYPES_BOOL) {
CHECK(obj->raw_properties_or_hash().IsOrderedNameDictionary());
} else {
CHECK(obj->raw_properties_or_hash().IsNameDictionary());
}
}
void CheckFastObject(Handle<JSObject> obj, int hash) { void CheckFastObject(Handle<JSObject> obj, int hash) {
CHECK(obj->HasFastProperties()); CHECK(obj->HasFastProperties());
CHECK(obj->raw_properties_or_hash().IsPropertyArray()); CHECK(obj->raw_properties_or_hash().IsPropertyArray());
...@@ -37,9 +61,9 @@ void CheckFastObject(Handle<JSObject> obj, int hash) { ...@@ -37,9 +61,9 @@ void CheckFastObject(Handle<JSObject> obj, int hash) {
void CheckDictionaryObject(Handle<JSObject> obj, int hash) { void CheckDictionaryObject(Handle<JSObject> obj, int hash) {
CHECK(!obj->HasFastProperties()); CHECK(!obj->HasFastProperties());
CHECK(obj->raw_properties_or_hash().IsNameDictionary()); CheckIsDictionaryModeObject(obj);
CHECK_EQ(Smi::FromInt(hash), obj->GetHash()); CHECK_EQ(Smi::FromInt(hash), obj->GetHash());
CHECK_EQ(hash, obj->property_dictionary().Hash()); CHECK_EQ(hash, GetPropertyDictionaryHash(obj));
} }
TEST(AddHashCodeToFastObjectWithoutProperties) { TEST(AddHashCodeToFastObjectWithoutProperties) {
...@@ -98,7 +122,8 @@ TEST(AddHashCodeToSlowObject) { ...@@ -98,7 +122,8 @@ TEST(AddHashCodeToSlowObject) {
CHECK(obj->HasFastProperties()); CHECK(obj->HasFastProperties());
JSObject::NormalizeProperties(isolate, obj, CLEAR_INOBJECT_PROPERTIES, 0, JSObject::NormalizeProperties(isolate, obj, CLEAR_INOBJECT_PROPERTIES, 0,
"cctest/test-hashcode"); "cctest/test-hashcode");
CHECK(obj->raw_properties_or_hash().IsNameDictionary());
CheckIsDictionaryModeObject(obj);
int hash = AddToSetAndGetHash(isolate, obj, false); int hash = AddToSetAndGetHash(isolate, obj, false);
CheckDictionaryObject(obj, hash); CheckDictionaryObject(obj, hash);
...@@ -181,14 +206,14 @@ TEST(TransitionSlowToSlow) { ...@@ -181,14 +206,14 @@ TEST(TransitionSlowToSlow) {
Handle<JSObject> obj = GetGlobal<JSObject>("x"); Handle<JSObject> obj = GetGlobal<JSObject>("x");
JSObject::NormalizeProperties(isolate, obj, CLEAR_INOBJECT_PROPERTIES, 0, JSObject::NormalizeProperties(isolate, obj, CLEAR_INOBJECT_PROPERTIES, 0,
"cctest/test-hashcode"); "cctest/test-hashcode");
CHECK(obj->raw_properties_or_hash().IsNameDictionary()); CheckIsDictionaryModeObject(obj);
int hash = AddToSetAndGetHash(isolate, obj, false); int hash = AddToSetAndGetHash(isolate, obj, false);
CHECK_EQ(hash, obj->property_dictionary().Hash()); CHECK_EQ(hash, GetPropertyDictionaryHash(obj));
int length = obj->property_dictionary().length(); int length = GetPropertyDictionaryLength(obj);
CompileRun("for(var i = 0; i < 10; i++) { x['f'+i] = i };"); CompileRun("for(var i = 0; i < 10; i++) { x['f'+i] = i };");
CHECK(obj->property_dictionary().length() > length); CHECK(GetPropertyDictionaryLength(obj) > length);
CheckDictionaryObject(obj, hash); CheckDictionaryObject(obj, hash);
} }
...@@ -201,10 +226,10 @@ TEST(TransitionSlowToFastWithoutProperties) { ...@@ -201,10 +226,10 @@ TEST(TransitionSlowToFastWithoutProperties) {
isolate->factory()->NewJSObject(isolate->object_function()); isolate->factory()->NewJSObject(isolate->object_function());
JSObject::NormalizeProperties(isolate, obj, CLEAR_INOBJECT_PROPERTIES, 0, JSObject::NormalizeProperties(isolate, obj, CLEAR_INOBJECT_PROPERTIES, 0,
"cctest/test-hashcode"); "cctest/test-hashcode");
CHECK(obj->raw_properties_or_hash().IsNameDictionary()); CheckIsDictionaryModeObject(obj);
int hash = AddToSetAndGetHash(isolate, obj, false); int hash = AddToSetAndGetHash(isolate, obj, false);
CHECK_EQ(hash, obj->property_dictionary().Hash()); CHECK_EQ(hash, GetPropertyDictionaryHash(obj));
JSObject::MigrateSlowToFast(obj, 0, "cctest/test-hashcode"); JSObject::MigrateSlowToFast(obj, 0, "cctest/test-hashcode");
CHECK_EQ(Smi::FromInt(hash), obj->GetHash()); CHECK_EQ(Smi::FromInt(hash), obj->GetHash());
...@@ -221,10 +246,10 @@ TEST(TransitionSlowToFastWithPropertyArray) { ...@@ -221,10 +246,10 @@ TEST(TransitionSlowToFastWithPropertyArray) {
CompileRun(source); CompileRun(source);
Handle<JSObject> obj = GetGlobal<JSObject>("x"); Handle<JSObject> obj = GetGlobal<JSObject>("x");
CHECK(obj->raw_properties_or_hash().IsNameDictionary()); CheckIsDictionaryModeObject(obj);
int hash = AddToSetAndGetHash(isolate, obj, false); int hash = AddToSetAndGetHash(isolate, obj, false);
CHECK_EQ(hash, obj->property_dictionary().Hash()); CHECK_EQ(hash, GetPropertyDictionaryHash(obj));
JSObject::MigrateSlowToFast(obj, 0, "cctest/test-hashcode"); JSObject::MigrateSlowToFast(obj, 0, "cctest/test-hashcode");
CheckFastObject(obj, hash); CheckFastObject(obj, hash);
......
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