Commit 3055139a authored by Frank Emrich's avatar Frank Emrich Committed by Commit Bot

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

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.

Specifically, this CL contains minor changes to CSA code, short of
actually performing ordered dictionary lookups using CSA
implementations of these lookups.

Bug: v8:7569
Change-Id: I0dab0f21000ca3b9b170ace58787ec639d587e64
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2540590
Commit-Queue: Frank Emrich <emrich@google.com>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71304}
parent 43d888f4
......@@ -395,6 +395,11 @@ extern enum PrimitiveType { kString, kBoolean, kSymbol, kNumber }
const kNameDictionaryInitialCapacity:
constexpr int32 generates 'NameDictionary::kInitialCapacity';
const kOrderedNameDictionaryInitialCapacity:
constexpr int32 generates 'OrderedNameDictionary::kInitialCapacity';
const kDictModePrototypes:
constexpr bool generates 'V8_DICT_MODE_PROTOTYPES_BOOL';
type TheHole extends Oddball;
type Null extends Oddball;
......@@ -614,6 +619,8 @@ extern macro SpeciesConstructor(implicit context: Context)(
extern macro ConstructorBuiltinsAssembler::IsDictionaryMap(Map): bool;
extern macro CodeStubAssembler::AllocateNameDictionary(constexpr int32):
NameDictionary;
extern macro CodeStubAssembler::AllocateOrderedNameDictionary(constexpr int32):
OrderedNameDictionary;
extern builtin ToObject(Context, JSAny): JSReceiver;
extern macro ToObject_Inline(Context, JSAny): JSReceiver;
......
......@@ -13,6 +13,7 @@
#include "src/codegen/code-stub-assembler.h"
#include "src/codegen/interface-descriptors.h"
#include "src/codegen/macro-assembler.h"
#include "src/common/globals.h"
#include "src/logging/counters.h"
#include "src/objects/objects-inl.h"
......@@ -281,7 +282,12 @@ TNode<JSObject> ConstructorBuiltinsAssembler::FastNewObject(
}
BIND(&allocate_properties);
{
properties = AllocateNameDictionary(NameDictionary::kInitialCapacity);
if (V8_DICT_MODE_PROTOTYPES_BOOL) {
properties = AllocateOrderedNameDictionary(
OrderedNameDictionary::kInitialCapacity);
} else {
properties = AllocateNameDictionary(NameDictionary::kInitialCapacity);
}
Goto(&instantiate_map);
}
......
......@@ -5,6 +5,7 @@
#include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/codegen/code-stub-assembler.h"
#include "src/common/globals.h"
#include "src/heap/factory-inl.h"
#include "src/ic/accessor-assembler.h"
#include "src/ic/keyed-store-generic.h"
......@@ -1068,7 +1069,12 @@ TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
BIND(&null_proto);
{
map = LoadSlowObjectWithNullPrototypeMap(native_context);
properties = AllocateNameDictionary(NameDictionary::kInitialCapacity);
if (V8_DICT_MODE_PROTOTYPES_BOOL) {
properties = AllocateOrderedNameDictionary(
OrderedNameDictionary::kInitialCapacity);
} else {
properties = AllocateNameDictionary(NameDictionary::kInitialCapacity);
}
Goto(&instantiate_map);
}
......
......@@ -7,6 +7,7 @@
#include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins.h"
#include "src/common/globals.h"
#include "src/logging/counters.h"
#include "src/objects/js-proxy.h"
#include "src/objects/objects-inl.h"
......@@ -51,8 +52,10 @@ TNode<JSProxy> ProxiesCodeStubAssembler::AllocateProxy(
BIND(&create_proxy);
TNode<HeapObject> proxy = Allocate(JSProxy::kSize);
StoreMapNoWriteBarrier(proxy, map.value());
StoreObjectFieldRoot(proxy, JSProxy::kPropertiesOrHashOffset,
RootIndex::kEmptyPropertyDictionary);
RootIndex empty_dict = V8_DICT_MODE_PROTOTYPES_BOOL
? RootIndex::kEmptyOrderedPropertyDictionary
: RootIndex::kEmptyPropertyDictionary;
StoreObjectFieldRoot(proxy, JSProxy::kPropertiesOrHashOffset, empty_dict);
StoreObjectFieldNoWriteBarrier(proxy, JSProxy::kTargetOffset, target);
StoreObjectFieldNoWriteBarrier(proxy, JSProxy::kHandlerOffset, handler);
......
......@@ -11,6 +11,7 @@
#include "src/codegen/code-factory.h"
#include "src/codegen/code-stub-assembler.h"
#include "src/codegen/macro-assembler.h"
#include "src/common/globals.h"
#include "src/execution/protectors.h"
#include "src/heap/factory-inl.h"
#include "src/logging/counters.h"
......@@ -289,8 +290,14 @@ TNode<JSRegExpResult> RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
TNode<IntPtrT> num_properties = WordSar(names_length, 1);
TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<Map> map = LoadSlowObjectWithNullPrototypeMap(native_context);
TNode<NameDictionary> properties =
AllocateNameDictionary(num_properties, kAllowLargeObjectAllocation);
TNode<HeapObject> properties;
if (V8_DICT_MODE_PROTOTYPES_BOOL) {
// AllocateOrderedNameDictionary always uses kAllowLargeObjectAllocation.
properties = AllocateOrderedNameDictionary(num_properties);
} else {
properties =
AllocateNameDictionary(num_properties, kAllowLargeObjectAllocation);
}
TNode<JSObject> group_object = AllocateJSObjectFromMap(map, properties);
StoreObjectField(result, JSRegExpResult::kGroupsOffset, group_object);
......@@ -325,7 +332,7 @@ TNode<JSRegExpResult> RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
// - Receiver is extensible
// - Receiver has no interceptors
Label add_dictionary_property_slow(this, Label::kDeferred);
Add<NameDictionary>(properties, name, capture,
Add<NameDictionary>(CAST(properties), name, capture,
&add_dictionary_property_slow);
var_i = i_plus_2;
......
......@@ -94,12 +94,17 @@ transitioning builtin CreateObjectWithoutProperties(implicit context: Context)(
prototype: JSAny): JSAny {
try {
let map: Map;
let properties: NameDictionary|EmptyFixedArray;
let properties: NameDictionary|OrderedNameDictionary|EmptyFixedArray;
typeswitch (prototype) {
case (Null): {
map = *NativeContextSlot(
ContextSlot::SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP);
properties = AllocateNameDictionary(kNameDictionaryInitialCapacity);
if (kDictModePrototypes) {
properties = AllocateOrderedNameDictionary(
kOrderedNameDictionaryInitialCapacity);
} else {
properties = AllocateNameDictionary(kNameDictionaryInitialCapacity);
}
}
case (prototype: JSReceiver): {
properties = kEmptyFixedArray;
......
......@@ -1590,10 +1590,26 @@ TNode<HeapObject> CodeStubAssembler::LoadSlowProperties(
TNode<JSReceiver> object) {
CSA_SLOW_ASSERT(this, IsDictionaryMap(LoadMap(object)));
TNode<Object> properties = LoadJSReceiverPropertiesOrHash(object);
return Select<HeapObject>(
TaggedIsSmi(properties),
[=] { return EmptyPropertyDictionaryConstant(); },
[=] { return CAST(properties); });
NodeGenerator<HeapObject> make_empty = [=]() -> TNode<HeapObject> {
if (V8_DICT_MODE_PROTOTYPES_BOOL) {
return EmptyOrderedPropertyDictionaryConstant();
} else {
return EmptyPropertyDictionaryConstant();
}
};
NodeGenerator<HeapObject> cast_properties = [=] {
TNode<HeapObject> dict = CAST(properties);
if (V8_DICT_MODE_PROTOTYPES_BOOL) {
CSA_ASSERT(this, Word32Or(IsOrderedNameDictionary(dict),
IsGlobalDictionary(dict)));
} else {
CSA_ASSERT(this,
Word32Or(IsNameDictionary(dict), IsGlobalDictionary(dict)));
}
return dict;
};
return Select<HeapObject>(TaggedIsSmi(properties), make_empty,
cast_properties);
}
TNode<Object> CodeStubAssembler::LoadJSArgumentsObjectLength(
......@@ -1763,7 +1779,8 @@ TNode<IntPtrT> CodeStubAssembler::LoadJSReceiverIdentityHash(
SloppyTNode<Object> receiver, Label* if_no_hash) {
TVARIABLE(IntPtrT, var_hash);
Label done(this), if_smi(this), if_property_array(this),
if_property_dictionary(this), if_fixed_array(this);
if_ordered_property_dictionary(this), if_property_dictionary(this),
if_fixed_array(this);
TNode<Object> properties_or_hash =
LoadObjectField(TNode<HeapObject>::UncheckedCast(receiver),
......@@ -1776,6 +1793,11 @@ TNode<IntPtrT> CodeStubAssembler::LoadJSReceiverIdentityHash(
GotoIf(InstanceTypeEqual(properties_instance_type, PROPERTY_ARRAY_TYPE),
&if_property_array);
if (V8_DICT_MODE_PROTOTYPES_BOOL) {
GotoIf(InstanceTypeEqual(properties_instance_type,
ORDERED_NAME_DICTIONARY_TYPE),
&if_ordered_property_dictionary);
}
Branch(InstanceTypeEqual(properties_instance_type, NAME_DICTIONARY_TYPE),
&if_property_dictionary, &if_fixed_array);
......@@ -1799,6 +1821,14 @@ TNode<IntPtrT> CodeStubAssembler::LoadJSReceiverIdentityHash(
DecodeWord<PropertyArray::HashField>(length_and_hash));
Goto(&done);
}
if (V8_DICT_MODE_PROTOTYPES_BOOL) {
BIND(&if_ordered_property_dictionary);
{
var_hash = SmiUntag(CAST(LoadFixedArrayElement(
CAST(properties), OrderedNameDictionary::HashIndex())));
Goto(&done);
}
}
BIND(&if_property_dictionary);
{
......@@ -3522,8 +3552,9 @@ void CodeStubAssembler::InitializeJSObjectFromMap(
StoreObjectFieldRoot(object, JSObject::kPropertiesOrHashOffset,
RootIndex::kEmptyFixedArray);
} else {
CSA_ASSERT(this, Word32Or(Word32Or(IsPropertyArray(*properties),
IsNameDictionary(*properties)),
CSA_ASSERT(this, Word32Or(Word32Or(Word32Or(IsPropertyArray(*properties),
IsNameDictionary(*properties)),
IsOrderedNameDictionary(*properties)),
IsEmptyFixedArray(*properties)));
StoreObjectFieldNoWriteBarrier(object, JSObject::kPropertiesOrHashOffset,
*properties);
......@@ -6321,6 +6352,10 @@ TNode<BoolT> CodeStubAssembler::IsEphemeronHashTable(TNode<HeapObject> object) {
TNode<BoolT> CodeStubAssembler::IsNameDictionary(TNode<HeapObject> object) {
return HasInstanceType(object, NAME_DICTIONARY_TYPE);
}
TNode<BoolT> CodeStubAssembler::IsOrderedNameDictionary(
TNode<HeapObject> object) {
return HasInstanceType(object, ORDERED_NAME_DICTIONARY_TYPE);
}
TNode<BoolT> CodeStubAssembler::IsGlobalDictionary(TNode<HeapObject> object) {
return HasInstanceType(object, GLOBAL_DICTIONARY_TYPE);
......@@ -8032,6 +8067,27 @@ template void CodeStubAssembler::Add<NameDictionary>(TNode<NameDictionary>,
TNode<Name>, TNode<Object>,
Label*);
template <class Dictionary>
TNode<Smi> CodeStubAssembler::GetNumberOfElements(
TNode<Dictionary> dictionary) {
return CAST(
LoadFixedArrayElement(dictionary, Dictionary::kNumberOfElementsIndex));
}
template <>
TNode<Smi> CodeStubAssembler::GetNumberOfElements(
TNode<OrderedNameDictionary> dictionary) {
return CAST(LoadFixedArrayElement(
dictionary, OrderedNameDictionary::NumberOfElementsIndex()));
}
template TNode<Smi> CodeStubAssembler::GetNumberOfElements(
TNode<NameDictionary> dictionary);
template TNode<Smi> CodeStubAssembler::GetNumberOfElements(
TNode<NumberDictionary> dictionary);
template TNode<Smi> CodeStubAssembler::GetNumberOfElements(
TNode<GlobalDictionary> dictionary);
template <typename Array>
void CodeStubAssembler::LookupLinear(TNode<Name> unique_name,
TNode<Array> array,
......@@ -13259,13 +13315,32 @@ TNode<Map> CodeStubAssembler::CheckEnumCache(TNode<JSReceiver> receiver,
{
// Avoid runtime-call for empty dictionary receivers.
GotoIfNot(IsDictionaryMap(receiver_map), if_runtime);
TNode<HashTableBase> properties =
UncheckedCast<HashTableBase>(LoadSlowProperties(receiver));
CSA_ASSERT(this, Word32Or(IsNameDictionary(properties),
IsGlobalDictionary(properties)));
STATIC_ASSERT(static_cast<int>(NameDictionary::kNumberOfElementsIndex) ==
static_cast<int>(GlobalDictionary::kNumberOfElementsIndex));
TNode<Smi> length = GetNumberOfElements(properties);
TNode<Smi> length;
TNode<HeapObject> properties = LoadSlowProperties(receiver);
if (V8_DICT_MODE_PROTOTYPES_BOOL) {
CSA_ASSERT(this, Word32Or(IsOrderedNameDictionary(properties),
IsGlobalDictionary(properties)));
length = Select<Smi>(
IsOrderedNameDictionary(properties),
[=] {
return GetNumberOfElements(
UncheckedCast<OrderedNameDictionary>(properties));
},
[=] {
return GetNumberOfElements(
UncheckedCast<GlobalDictionary>(properties));
});
} else {
CSA_ASSERT(this, Word32Or(IsNameDictionary(properties),
IsGlobalDictionary(properties)));
STATIC_ASSERT(static_cast<int>(NameDictionary::kNumberOfElementsIndex) ==
static_cast<int>(GlobalDictionary::kNumberOfElementsIndex));
length = GetNumberOfElements(UncheckedCast<HashTableBase>(properties));
}
GotoIfNot(TaggedEqual(length, SmiConstant(0)), if_runtime);
// Check that there are no elements on the {receiver} and its prototype
// chain. Given that we do not create an EnumCache for dict-mode objects,
......
......@@ -132,6 +132,8 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
V(EmptyScopeInfo, empty_scope_info, EmptyScopeInfo) \
V(EmptyPropertyDictionary, empty_property_dictionary, \
EmptyPropertyDictionary) \
V(EmptyOrderedPropertyDictionary, empty_ordered_property_dictionary, \
EmptyOrderedPropertyDictionary) \
V(EmptySlowElementDictionary, empty_slow_element_dictionary, \
EmptySlowElementDictionary) \
V(empty_string, empty_string, EmptyString) \
......@@ -2327,6 +2329,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BoolT> IsConstructor(TNode<HeapObject> object);
TNode<BoolT> IsDeprecatedMap(TNode<Map> map);
TNode<BoolT> IsNameDictionary(TNode<HeapObject> object);
TNode<BoolT> IsOrderedNameDictionary(TNode<HeapObject> object);
TNode<BoolT> IsGlobalDictionary(TNode<HeapObject> object);
TNode<BoolT> IsExtensibleMap(TNode<Map> map);
TNode<BoolT> IsExtensibleNonPrototypeMap(TNode<Map> map);
......@@ -2838,10 +2841,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<IntPtrT> HashTableComputeCapacity(TNode<IntPtrT> at_least_space_for);
template <class Dictionary>
TNode<Smi> GetNumberOfElements(TNode<Dictionary> dictionary) {
return CAST(
LoadFixedArrayElement(dictionary, Dictionary::kNumberOfElementsIndex));
}
TNode<Smi> GetNumberOfElements(TNode<Dictionary> dictionary);
TNode<Smi> GetNumberDictionaryNumberOfElements(
TNode<NumberDictionary> dictionary) {
......
......@@ -1562,8 +1562,11 @@ Handle<JSObject> Factory::CopyJSObjectWithAllocationSite(
clone->set_raw_properties_or_hash(*prop);
}
} else {
Handle<FixedArray> properties(
FixedArray::cast(source->property_dictionary()), isolate());
Handle<FixedArray> properties =
handle(V8_DICT_MODE_PROTOTYPES_BOOL
? FixedArray::cast(source->property_dictionary_ordered())
: FixedArray::cast(source->property_dictionary()),
isolate());
Handle<FixedArray> prop = CopyFixedArray(properties);
clone->set_raw_properties_or_hash(*prop);
}
......
......@@ -73,9 +73,15 @@ macro GetDerivedMap(implicit context: Context)(
macro AllocateFastOrSlowJSObjectFromMap(implicit context: Context)(map: Map):
JSObject {
let properties: EmptyFixedArray|NameDictionary = kEmptyFixedArray;
let properties: EmptyFixedArray|NameDictionary|OrderedNameDictionary =
kEmptyFixedArray;
if (IsDictionaryMap(map)) {
properties = AllocateNameDictionary(kNameDictionaryInitialCapacity);
if (kDictModePrototypes) {
properties =
AllocateOrderedNameDictionary(kOrderedNameDictionaryInitialCapacity);
} else {
properties = AllocateNameDictionary(kNameDictionaryInitialCapacity);
}
}
return AllocateJSObjectFromMap(
map, properties, kEmptyFixedArray, AllocationFlag::kNone,
......@@ -154,7 +160,11 @@ extern class JSStringIterator extends JSObject {
extern macro AllocateJSObjectFromMap(Map): JSObject;
extern macro AllocateJSObjectFromMap(
Map, NameDictionary | EmptyFixedArray | PropertyArray): JSObject;
Map,
NameDictionary | OrderedNameDictionary | EmptyFixedArray |
PropertyArray): JSObject;
extern macro AllocateJSObjectFromMap(
Map, NameDictionary | EmptyFixedArray | PropertyArray, FixedArray,
constexpr AllocationFlag, constexpr SlackTrackingMode): JSObject;
Map,
NameDictionary | OrderedNameDictionary | EmptyFixedArray | PropertyArray,
FixedArray, constexpr AllocationFlag,
constexpr SlackTrackingMode): JSObject;
......@@ -232,11 +232,11 @@ inline int SmallOrderedNameDictionary::Hash() {
inline void OrderedNameDictionary::SetHash(int hash) {
DCHECK(PropertyArray::HashField::is_valid(hash));
this->set(PrefixIndex(), Smi::FromInt(hash));
this->set(HashIndex(), Smi::FromInt(hash));
}
inline int OrderedNameDictionary::Hash() {
Object hash_obj = this->get(PrefixIndex());
Object hash_obj = this->get(HashIndex());
int hash = Smi::ToInt(hash_obj);
DCHECK(PropertyArray::HashField::is_valid(hash));
return hash;
......
......@@ -831,6 +831,8 @@ class V8_EXPORT_PRIVATE OrderedNameDictionary
static const int kPropertyDetailsOffset = 2;
static const int kPrefixSize = 1;
static constexpr int HashIndex() { return PrefixIndex(); }
static const bool kIsOrderedDictionaryType = true;
OBJECT_CONSTRUCTORS(OrderedNameDictionary,
......
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