Commit 9eb49295 authored by verwaest's avatar verwaest Committed by Commit bot

[runtime] Replace hidden_string with a 0-hash-code private symbol

BUG=

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

Cr-Commit-Position: refs/heads/master@{#34070}
parent 1e79bd5c
...@@ -150,6 +150,7 @@ ...@@ -150,6 +150,7 @@
V(formatted_stack_trace_symbol) \ V(formatted_stack_trace_symbol) \
V(frozen_symbol) \ V(frozen_symbol) \
V(hash_code_symbol) \ V(hash_code_symbol) \
V(hidden_properties_symbol) \
V(home_object_symbol) \ V(home_object_symbol) \
V(internal_error_symbol) \ V(internal_error_symbol) \
V(intl_impl_object_symbol) \ V(intl_impl_object_symbol) \
......
...@@ -2667,17 +2667,6 @@ void Heap::CreateInitialObjects() { ...@@ -2667,17 +2667,6 @@ void Heap::CreateInitialObjects() {
roots_[constant_string_table[i].index] = *str; roots_[constant_string_table[i].index] = *str;
} }
// The {hidden_string} is special because it is an empty string, but does not
// match any string (even the {empty_string}) when looked up in properties.
// Allocate the hidden string which is used to identify the hidden properties
// in JSObjects. The hash code has a special value so that it will not match
// the empty string when searching for the property. It cannot be part of the
// loop above because it needs to be allocated manually with the special
// hash code in place. The hash code for the hidden_string is zero to ensure
// that it will always be at the first entry in property descriptors.
set_hidden_string(*factory->NewOneByteInternalizedString(
OneByteVector("", 0), String::kEmptyStringHash));
// Create the code_stubs dictionary. The initial size is set to avoid // Create the code_stubs dictionary. The initial size is set to avoid
// expanding the dictionary during bootstrapping. // expanding the dictionary during bootstrapping.
set_code_stubs(*UnseededNumberDictionary::New(isolate(), 128)); set_code_stubs(*UnseededNumberDictionary::New(isolate(), 128));
...@@ -2706,6 +2695,14 @@ void Heap::CreateInitialObjects() { ...@@ -2706,6 +2695,14 @@ void Heap::CreateInitialObjects() {
#undef SYMBOL_INIT #undef SYMBOL_INIT
} }
// The {hidden_properties_symbol} is special because it is the only name with
// hash code zero. This ensures that it will always be the first entry as
// sorted by hash code in descriptor arrays. It is used to identify the hidden
// properties in JSObjects.
// kIsNotArrayIndexMask is a computed hash with value zero.
Symbol::cast(roots_[khidden_properties_symbolRootIndex])
->set_hash_field(Name::kIsNotArrayIndexMask);
{ {
HandleScope scope(isolate()); HandleScope scope(isolate());
#define SYMBOL_INIT(name, description) \ #define SYMBOL_INIT(name, description) \
......
...@@ -37,7 +37,6 @@ namespace internal { ...@@ -37,7 +37,6 @@ namespace internal {
V(Oddball, true_value, TrueValue) \ V(Oddball, true_value, TrueValue) \
V(Oddball, false_value, FalseValue) \ V(Oddball, false_value, FalseValue) \
V(String, empty_string, empty_string) \ V(String, empty_string, empty_string) \
V(String, hidden_string, hidden_string) \
V(Oddball, uninitialized_value, UninitializedValue) \ V(Oddball, uninitialized_value, UninitializedValue) \
V(Map, cell_map, CellMap) \ V(Map, cell_map, CellMap) \
V(Map, global_property_cell_map, GlobalPropertyCellMap) \ V(Map, global_property_cell_map, GlobalPropertyCellMap) \
......
...@@ -1684,8 +1684,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup, ...@@ -1684,8 +1684,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
// This is currently guaranteed by checks in StoreIC::Store. // This is currently guaranteed by checks in StoreIC::Store.
Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver()); Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
Handle<JSObject> holder = lookup->GetHolder<JSObject>(); Handle<JSObject> holder = lookup->GetHolder<JSObject>();
DCHECK(!receiver->IsAccessCheckNeeded() || DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
isolate()->IsInternallyUsedPropertyName(lookup->name()));
switch (lookup->state()) { switch (lookup->state()) {
case LookupIterator::TRANSITION: { case LookupIterator::TRANSITION: {
......
...@@ -782,14 +782,6 @@ void Isolate::ReportFailedAccessCheck(Handle<JSObject> receiver) { ...@@ -782,14 +782,6 @@ void Isolate::ReportFailedAccessCheck(Handle<JSObject> receiver) {
} }
bool Isolate::IsInternallyUsedPropertyName(Handle<Object> name) {
if (name->IsSymbol()) {
return Handle<Symbol>::cast(name)->is_private();
}
return name.is_identical_to(factory()->hidden_string());
}
bool Isolate::MayAccess(Handle<Context> accessing_context, bool Isolate::MayAccess(Handle<Context> accessing_context,
Handle<JSObject> receiver) { Handle<JSObject> receiver) {
DCHECK(receiver->IsJSGlobalProxy() || receiver->IsAccessCheckNeeded()); DCHECK(receiver->IsJSGlobalProxy() || receiver->IsAccessCheckNeeded());
......
...@@ -683,8 +683,6 @@ class Isolate { ...@@ -683,8 +683,6 @@ class Isolate {
// set. // set.
bool MayAccess(Handle<Context> accessing_context, Handle<JSObject> receiver); bool MayAccess(Handle<Context> accessing_context, Handle<JSObject> receiver);
bool IsInternallyUsedPropertyName(Handle<Object> name);
void SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback); void SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback);
void ReportFailedAccessCheck(Handle<JSObject> receiver); void ReportFailedAccessCheck(Handle<JSObject> receiver);
......
...@@ -606,9 +606,8 @@ LookupIterator::State LookupIterator::LookupInHolder(Map* const map, ...@@ -606,9 +606,8 @@ LookupIterator::State LookupIterator::LookupInHolder(Map* const map,
// Do not leak private property names. // Do not leak private property names.
if (IsElement() || !name_->IsPrivate()) return JSPROXY; if (IsElement() || !name_->IsPrivate()) return JSPROXY;
} }
if (map->is_access_check_needed() && if (map->is_access_check_needed()) {
(IsElement() || !isolate_->IsInternallyUsedPropertyName(name_))) { if (IsElement() || !name_->IsPrivate()) return ACCESS_CHECK;
return ACCESS_CHECK;
} }
// Fall through. // Fall through.
case ACCESS_CHECK: case ACCESS_CHECK:
......
...@@ -209,7 +209,7 @@ class LookupIterator final BASE_EMBEDDED { ...@@ -209,7 +209,7 @@ class LookupIterator final BASE_EMBEDDED {
bool ExtendingNonExtensible(Handle<JSObject> receiver) { bool ExtendingNonExtensible(Handle<JSObject> receiver) {
DCHECK(receiver.is_identical_to(GetStoreTarget())); DCHECK(receiver.is_identical_to(GetStoreTarget()));
return !receiver->map()->is_extensible() && return !receiver->map()->is_extensible() &&
(IsElement() || !isolate_->IsInternallyUsedPropertyName(name_)); (IsElement() || !name_->IsPrivate());
} }
void PrepareForDataProperty(Handle<Object> value); void PrepareForDataProperty(Handle<Object> value);
void PrepareTransitionToDataProperty(Handle<JSObject> receiver, void PrepareTransitionToDataProperty(Handle<JSObject> receiver,
......
...@@ -208,7 +208,7 @@ void HeapObject::VerifyHeapPointer(Object* p) { ...@@ -208,7 +208,7 @@ void HeapObject::VerifyHeapPointer(Object* p) {
void Symbol::SymbolVerify() { void Symbol::SymbolVerify() {
CHECK(IsSymbol()); CHECK(IsSymbol());
CHECK(HasHashCode()); CHECK(HasHashCode());
CHECK_GT(Hash(), 0u); CHECK(GetHeap()->hidden_properties_symbol() == this || Hash() > 0u);
CHECK(name()->IsUndefined() || name()->IsString()); CHECK(name()->IsUndefined() || name()->IsString());
} }
......
...@@ -4395,8 +4395,7 @@ Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) { ...@@ -4395,8 +4395,7 @@ Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
// Fetch before transforming the object since the encoding may become // Fetch before transforming the object since the encoding may become
// incompatible with what's cached in |it|. // incompatible with what's cached in |it|.
bool is_observed = receiver->map()->is_observed() && bool is_observed = receiver->map()->is_observed() &&
(it->IsElement() || (it->IsElement() || !it->name()->IsPrivate());
!it->isolate()->IsInternallyUsedPropertyName(it->name()));
MaybeHandle<Object> maybe_old; MaybeHandle<Object> maybe_old;
if (is_observed) maybe_old = it->GetDataValue(); if (is_observed) maybe_old = it->GetDataValue();
...@@ -4551,8 +4550,7 @@ Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value, ...@@ -4551,8 +4550,7 @@ Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
} }
// Send the change record if there are observers. // Send the change record if there are observers.
if (receiver->map()->is_observed() && if (receiver->map()->is_observed() && !it->name()->IsPrivate()) {
!isolate->IsInternallyUsedPropertyName(it->name())) {
RETURN_ON_EXCEPTION_VALUE(isolate, JSObject::EnqueueChangeRecord( RETURN_ON_EXCEPTION_VALUE(isolate, JSObject::EnqueueChangeRecord(
receiver, "add", it->name(), receiver, "add", it->name(),
it->factory()->the_hole_value()), it->factory()->the_hole_value()),
...@@ -5253,8 +5251,7 @@ void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name, ...@@ -5253,8 +5251,7 @@ void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it); Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
DCHECK(maybe.IsJust()); DCHECK(maybe.IsJust());
DCHECK(!it.IsFound()); DCHECK(!it.IsFound());
DCHECK(object->map()->is_extensible() || DCHECK(object->map()->is_extensible() || name->IsPrivate());
it.isolate()->IsInternallyUsedPropertyName(name));
#endif #endif
CHECK(AddDataProperty(&it, value, attributes, THROW_ON_ERROR, CHECK(AddDataProperty(&it, value, attributes, THROW_ON_ERROR,
CERTAINLY_NOT_STORE_FROM_KEYED) CERTAINLY_NOT_STORE_FROM_KEYED)
...@@ -5280,8 +5277,7 @@ Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes( ...@@ -5280,8 +5277,7 @@ Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
ShouldThrow should_throw, AccessorInfoHandling handling) { ShouldThrow should_throw, AccessorInfoHandling handling) {
Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver());
bool is_observed = object->map()->is_observed() && bool is_observed = object->map()->is_observed() &&
(it->IsElement() || (it->IsElement() || !it->name()->IsPrivate());
!it->isolate()->IsInternallyUsedPropertyName(it->name()));
for (; it->IsFound(); it->Next()) { for (; it->IsFound(); it->Next()) {
switch (it->state()) { switch (it->state()) {
...@@ -6008,10 +6004,12 @@ void JSObject::DeleteHiddenProperty(Handle<JSObject> object, Handle<Name> key) { ...@@ -6008,10 +6004,12 @@ void JSObject::DeleteHiddenProperty(Handle<JSObject> object, Handle<Name> key) {
bool JSObject::HasHiddenProperties(Handle<JSObject> object) { bool JSObject::HasHiddenProperties(Handle<JSObject> object) {
Handle<Name> hidden = object->GetIsolate()->factory()->hidden_string(); Isolate* isolate = object->GetIsolate();
LookupIterator it(object, hidden, LookupIterator::OWN_SKIP_INTERCEPTOR); Handle<Symbol> hidden = isolate->factory()->hidden_properties_symbol();
LookupIterator it(object, hidden);
Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it); Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
// Cannot get an exception since the hidden_string isn't accessible to JS. // Cannot get an exception since the hidden_properties_symbol isn't exposed to
// JS.
DCHECK(maybe.IsJust()); DCHECK(maybe.IsJust());
return maybe.FromJust() != ABSENT; return maybe.FromJust() != ABSENT;
} }
...@@ -6027,7 +6025,8 @@ Object* JSObject::GetHiddenPropertiesHashTable() { ...@@ -6027,7 +6025,8 @@ Object* JSObject::GetHiddenPropertiesHashTable() {
DescriptorArray* descriptors = this->map()->instance_descriptors(); DescriptorArray* descriptors = this->map()->instance_descriptors();
if (descriptors->number_of_descriptors() > 0) { if (descriptors->number_of_descriptors() > 0) {
int sorted_index = descriptors->GetSortedKeyIndex(0); int sorted_index = descriptors->GetSortedKeyIndex(0);
if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() && if (descriptors->GetKey(sorted_index) ==
GetHeap()->hidden_properties_symbol() &&
sorted_index < map()->NumberOfOwnDescriptors()) { sorted_index < map()->NumberOfOwnDescriptors()) {
DCHECK(descriptors->GetType(sorted_index) == DATA); DCHECK(descriptors->GetType(sorted_index) == DATA);
DCHECK(descriptors->GetDetails(sorted_index).representation(). DCHECK(descriptors->GetDetails(sorted_index).representation().
...@@ -6042,9 +6041,8 @@ Object* JSObject::GetHiddenPropertiesHashTable() { ...@@ -6042,9 +6041,8 @@ Object* JSObject::GetHiddenPropertiesHashTable() {
return GetHeap()->undefined_value(); return GetHeap()->undefined_value();
} }
} else { } else {
Isolate* isolate = GetIsolate(); Handle<Symbol> hidden = GetIsolate()->factory()->hidden_properties_symbol();
LookupIterator it(handle(this), isolate->factory()->hidden_string(), LookupIterator it(handle(this), hidden);
LookupIterator::OWN_SKIP_INTERCEPTOR);
// Access check is always skipped for the hidden string anyways. // Access check is always skipped for the hidden string anyways.
return *GetDataProperty(&it); return *GetDataProperty(&it);
} }
...@@ -6073,7 +6071,7 @@ Handle<Object> JSObject::SetHiddenPropertiesHashTable(Handle<JSObject> object, ...@@ -6073,7 +6071,7 @@ Handle<Object> JSObject::SetHiddenPropertiesHashTable(Handle<JSObject> object,
Handle<Object> value) { Handle<Object> value) {
DCHECK(!object->IsJSGlobalProxy()); DCHECK(!object->IsJSGlobalProxy());
Isolate* isolate = object->GetIsolate(); Isolate* isolate = object->GetIsolate();
Handle<Name> name = isolate->factory()->hidden_string(); Handle<Symbol> name = isolate->factory()->hidden_properties_symbol();
SetOwnPropertyIgnoreAttributes(object, name, value, DONT_ENUM).Assert(); SetOwnPropertyIgnoreAttributes(object, name, value, DONT_ENUM).Assert();
return object; return object;
} }
...@@ -6173,9 +6171,8 @@ Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it, ...@@ -6173,9 +6171,8 @@ Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
} }
Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
bool is_observed = bool is_observed = receiver->map()->is_observed() &&
receiver->map()->is_observed() && (it->IsElement() || !it->name()->IsPrivate());
(it->IsElement() || !isolate->IsInternallyUsedPropertyName(it->name()));
Handle<Object> old_value = it->factory()->the_hole_value(); Handle<Object> old_value = it->factory()->the_hole_value();
...@@ -9033,7 +9030,7 @@ MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it, ...@@ -9033,7 +9030,7 @@ MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
Handle<Object> old_value = isolate->factory()->the_hole_value(); Handle<Object> old_value = isolate->factory()->the_hole_value();
bool is_observed = object->map()->is_observed() && bool is_observed = object->map()->is_observed() &&
!isolate->IsInternallyUsedPropertyName(it->GetName()); (it->IsElement() || !it->name()->IsPrivate());
bool preexists = false; bool preexists = false;
if (is_observed) { if (is_observed) {
CHECK(GetPropertyAttributes(it).IsJust()); CHECK(GetPropertyAttributes(it).IsJust());
......
...@@ -2186,12 +2186,11 @@ class JSObject: public JSReceiver { ...@@ -2186,12 +2186,11 @@ class JSObject: public JSReceiver {
// Accessors for hidden properties object. // Accessors for hidden properties object.
// //
// Hidden properties are not own properties of the object itself. // Hidden properties are not own properties of the object itself. Instead
// Instead they are stored in an auxiliary structure kept as an own // they are stored in an auxiliary structure kept as an own property with a
// property with a special name Heap::hidden_string(). But if the // special name Heap::hidden_properties_symbol(). But if the receiver is a
// receiver is a JSGlobalProxy then the auxiliary object is a property // JSGlobalProxy then the auxiliary object is a property of its prototype, and
// of its prototype, and if it's a detached proxy, then you can't have // if it's a detached proxy, then you can't have hidden properties.
// hidden properties.
// Sets a hidden property on this object. Returns this object if successful, // Sets a hidden property on this object. Returns this object if successful,
// undefined if called on a detached proxy. // undefined if called on a detached proxy.
...@@ -8971,9 +8970,6 @@ class String: public Name { ...@@ -8971,9 +8970,6 @@ class String: public Name {
static const uint32_t kMaxUtf16CodeUnitU = kMaxUtf16CodeUnit; static const uint32_t kMaxUtf16CodeUnitU = kMaxUtf16CodeUnit;
static const uc32 kMaxCodePoint = 0x10ffff; static const uc32 kMaxCodePoint = 0x10ffff;
// Value of hash field containing computed hash equal to zero.
static const int kEmptyStringHash = kIsNotArrayIndexMask;
// Maximal string length. // Maximal string length.
static const int kMaxLength = (1 << 28) - 16; static const int kMaxLength = (1 << 28) - 16;
......
...@@ -1598,7 +1598,7 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) { ...@@ -1598,7 +1598,7 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
int field_offset = int field_offset =
field_index.is_inobject() ? field_index.offset() : -1; field_index.is_inobject() ? field_index.offset() : -1;
if (k != heap_->hidden_string()) { if (k != heap_->hidden_properties_symbol()) {
SetDataOrAccessorPropertyReference(details.kind(), js_obj, entry, k, SetDataOrAccessorPropertyReference(details.kind(), js_obj, entry, k,
value, NULL, field_offset); value, NULL, field_offset);
} else { } else {
...@@ -1625,7 +1625,7 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) { ...@@ -1625,7 +1625,7 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
DCHECK(dictionary->ValueAt(i)->IsPropertyCell()); DCHECK(dictionary->ValueAt(i)->IsPropertyCell());
PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(i)); PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(i));
Object* value = cell->value(); Object* value = cell->value();
if (k == heap_->hidden_string()) { if (k == heap_->hidden_properties_symbol()) {
TagObject(value, "(hidden properties)"); TagObject(value, "(hidden properties)");
SetInternalReference(js_obj, entry, "hidden_properties", value); SetInternalReference(js_obj, entry, "hidden_properties", value);
continue; continue;
...@@ -1642,7 +1642,7 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) { ...@@ -1642,7 +1642,7 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
Object* k = dictionary->KeyAt(i); Object* k = dictionary->KeyAt(i);
if (dictionary->IsKey(k)) { if (dictionary->IsKey(k)) {
Object* value = dictionary->ValueAt(i); Object* value = dictionary->ValueAt(i);
if (k == heap_->hidden_string()) { if (k == heap_->hidden_properties_symbol()) {
TagObject(value, "(hidden properties)"); TagObject(value, "(hidden properties)");
SetInternalReference(js_obj, entry, "hidden_properties", value); SetInternalReference(js_obj, entry, "hidden_properties", value);
continue; continue;
......
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