[runtime] Rename Name::Hash() to Name::EnsureHash()

... and use Name::hash() where the hash is expected to be computed.
In particular, when we are dealing with internalized strings or symbols.

Bug: v8:11074
Change-Id: Ida22f134fee0ddf2c9b962d1bcca6aa0b632af5f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2529451
Reviewed-by: Dominik Inführ <dinfuehr@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71200}
This commit is contained in:
Igor Sheludko 2020-11-13 18:00:46 +01:00 committed by Commit Bot
parent c85ab364d6
commit 93d49c39d8
27 changed files with 78 additions and 68 deletions

View File

@ -5135,7 +5135,7 @@ MaybeLocal<String> v8::Function::FunctionProtoToString(Local<Context> context) {
int Name::GetIdentityHash() {
auto self = Utils::OpenHandle(this);
return static_cast<int>(self->Hash());
return static_cast<int>(self->EnsureHash());
}
int String::Length() const {

View File

@ -77,7 +77,11 @@ class AstRawString final : public ZoneObject {
// For storing AstRawStrings in a hash map.
uint32_t raw_hash_field() const { return raw_hash_field_; }
uint32_t Hash() const { return raw_hash_field_ >> Name::kHashShift; }
uint32_t Hash() const {
// Hash field must be computed.
DCHECK_EQ(raw_hash_field_ & Name::kHashNotComputedMask, 0);
return raw_hash_field_ >> Name::kHashShift;
}
// This function can be called after internalizing.
V8_INLINE Handle<String> string() const {

View File

@ -278,7 +278,7 @@ void HeapObject::VerifyHeapPointer(Isolate* isolate, Object p) {
void Symbol::SymbolVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::SymbolVerify(*this, isolate);
CHECK(HasHashCode());
CHECK_GT(Hash(), 0);
CHECK_GT(hash(), 0);
CHECK(description().IsUndefined(isolate) || description().IsString());
CHECK_IMPLIES(IsPrivateName(), IsPrivate());
CHECK_IMPLIES(IsPrivateBrand(), IsPrivateName());
@ -938,7 +938,13 @@ void Oddball::OddballVerify(Isolate* isolate) {
}
}
USE_TORQUE_VERIFIER(PropertyCell)
void PropertyCell::PropertyCellVerify(Isolate* isolate) {
// TODO(torque): replace with USE_TORQUE_VERIFIER(PropertyCell) once
// it supports UniqueName type.
TorqueGeneratedClassVerifiers::PropertyCellVerify(*this, isolate);
CHECK(name().IsUniqueName());
}
void CodeDataContainer::CodeDataContainerVerify(Isolate* isolate) {
CHECK(IsCodeDataContainer());

View File

@ -1026,8 +1026,8 @@ void Heap::CreateInitialObjects() {
AllocationType::kReadOnly));
// Evaluate the hash values which will then be cached in the strings.
isolate()->factory()->zero_string()->Hash();
isolate()->factory()->one_string()->Hash();
isolate()->factory()->zero_string()->EnsureHash();
isolate()->factory()->one_string()->EnsureHash();
// Initialize builtins constants table.
set_builtins_constants_table(roots.empty_fixed_array());

View File

@ -71,7 +71,6 @@ bool CommonStubCacheChecks(StubCache* stub_cache, Name name, Map map,
DCHECK(!Heap::InYoungGeneration(name));
DCHECK(!Heap::InYoungGeneration(handler));
DCHECK(name.IsUniqueName());
DCHECK(name.HasHashCode());
if (handler->ptr() != kNullAddress) DCHECK(IC::IsHandler(handler));
return true;
}

View File

@ -192,7 +192,7 @@ void Log::MessageBuilder::AppendSymbolName(Symbol symbol) {
AppendSymbolNameDetails(String::cast(symbol.description()), false);
os << "\" ";
}
os << "hash " << std::hex << symbol.Hash() << std::dec << ")";
os << "hash " << std::hex << symbol.hash() << std::dec << ")";
}
void Log::MessageBuilder::AppendSymbolNameDetails(String str,

View File

@ -124,7 +124,7 @@ class CodeEventLogger::NameBuffer {
AppendBytes("\" ");
}
AppendBytes("hash ");
AppendHex(symbol.Hash());
AppendHex(symbol.hash());
AppendByte(')');
}
}
@ -232,7 +232,7 @@ void CodeEventLogger::CodeCreateEvent(LogEventsAndTags tag,
name_buffer_->AppendString(String::cast(*script_name));
} else {
name_buffer_->AppendBytes("symbol(hash ");
name_buffer_->AppendHex(Name::cast(*script_name).Hash());
name_buffer_->AppendHex(Name::cast(*script_name).hash());
name_buffer_->AppendByte(')');
}
name_buffer_->AppendByte(':');

View File

@ -27,14 +27,14 @@ NEVER_READ_ONLY_SPACE_IMPL(CompilationCacheTable)
CAST_ACCESSOR(CompilationCacheTable)
uint32_t CompilationCacheShape::RegExpHash(String string, Smi flags) {
return string.Hash() + flags.value();
return string.EnsureHash() + flags.value();
}
uint32_t CompilationCacheShape::StringSharedHash(String source,
SharedFunctionInfo shared,
LanguageMode language_mode,
int position) {
uint32_t hash = source.Hash();
uint32_t hash = source.EnsureHash();
if (shared.HasSourceCode()) {
// Instead of using the SharedFunctionInfo pointer in the hash
// code computation, we use a combination of the hash of the
@ -42,7 +42,7 @@ uint32_t CompilationCacheShape::StringSharedHash(String source,
// We do this to ensure that the cache entries can survive garbage
// collection.
Script script(Script::cast(shared.script()));
hash ^= String::cast(script.source()).Hash();
hash ^= String::cast(script.source()).EnsureHash();
STATIC_ASSERT(LanguageModeSize == 2);
if (is_strict(language_mode)) hash ^= 0x8000;
hash += position;

View File

@ -223,7 +223,7 @@ void DescriptorArray::Append(Descriptor* desc) {
set_number_of_descriptors(descriptor_number + 1);
Set(InternalIndex(descriptor_number), desc);
uint32_t hash = desc->GetKey()->Hash();
uint32_t hash = desc->GetKey()->hash();
int insertion;

View File

@ -279,11 +279,13 @@ bool NameDictionaryShape::IsMatch(Handle<Name> key, Object other) {
}
uint32_t NameDictionaryShape::Hash(ReadOnlyRoots roots, Handle<Name> key) {
return key->Hash();
DCHECK(key->IsUniqueName());
return key->hash();
}
uint32_t NameDictionaryShape::HashForObject(ReadOnlyRoots roots, Object other) {
return Name::cast(other).Hash();
DCHECK(other.IsUniqueName());
return Name::cast(other).hash();
}
bool GlobalDictionaryShape::IsMatch(Handle<Name> key, Object other) {
@ -294,7 +296,7 @@ bool GlobalDictionaryShape::IsMatch(Handle<Name> key, Object other) {
uint32_t GlobalDictionaryShape::HashForObject(ReadOnlyRoots roots,
Object other) {
return PropertyCell::cast(other).name().Hash();
return PropertyCell::cast(other).name().hash();
}
Handle<Object> NameDictionaryShape::AsHandle(Isolate* isolate,

View File

@ -2389,7 +2389,7 @@ void JSObject::SetNormalizedProperty(Handle<JSObject> object, Handle<Name> name,
DCHECK(name->IsUniqueName());
Isolate* isolate = object->GetIsolate();
uint32_t hash = name->Hash();
uint32_t hash = name->hash();
if (object->IsJSGlobalObject()) {
Handle<JSGlobalObject> global_obj = Handle<JSGlobalObject>::cast(object);

View File

@ -1251,7 +1251,7 @@ Maybe<bool> KeyAccumulator::CollectOwnJSProxyKeys(Handle<JSReceiver> receiver,
int unchecked_result_keys_size = 0;
for (int i = 0; i < trap_result->length(); ++i) {
Handle<Name> key(Name::cast(trap_result->get(i)), isolate_);
auto entry = unchecked_result_keys.LookupOrInsert(key, key->Hash());
auto entry = unchecked_result_keys.LookupOrInsert(key, key->EnsureHash());
if (entry->value != kPresent) {
entry->value = kPresent;
unchecked_result_keys_size++;
@ -1313,7 +1313,7 @@ Maybe<bool> KeyAccumulator::CollectOwnJSProxyKeys(Handle<JSReceiver> receiver,
Handle<Name> key(Name::cast(raw_key), isolate_);
// 19a. If key is not an element of uncheckedResultKeys, throw a
// TypeError exception.
auto found = unchecked_result_keys.Lookup(key, key->Hash());
auto found = unchecked_result_keys.Lookup(key, key->hash());
if (found == nullptr || found->value == kGone) {
isolate_->Throw(*isolate_->factory()->NewTypeError(
MessageTemplate::kProxyOwnKeysMissing, key));
@ -1334,7 +1334,7 @@ Maybe<bool> KeyAccumulator::CollectOwnJSProxyKeys(Handle<JSReceiver> receiver,
Handle<Name> key(Name::cast(raw_key), isolate_);
// 21a. If key is not an element of uncheckedResultKeys, throw a
// TypeError exception.
auto found = unchecked_result_keys.Lookup(key, key->Hash());
auto found = unchecked_result_keys.Lookup(key, key->hash());
if (found == nullptr || found->value == kGone) {
isolate_->Throw(*isolate_->factory()->NewTypeError(
MessageTemplate::kProxyOwnKeysMissing, key));

View File

@ -5,10 +5,10 @@
#ifndef V8_OBJECTS_NAME_INL_H_
#define V8_OBJECTS_NAME_INL_H_
#include "src/objects/name.h"
#include "src/base/logging.h"
#include "src/heap/heap-write-barrier-inl.h"
#include "src/objects/map-inl.h"
#include "src/objects/name.h"
#include "src/objects/primitive-heap-object-inl.h"
// Has to be the last include (doesn't have include guards):
@ -60,6 +60,7 @@ DEF_GETTER(Name, IsUniqueName, bool) {
bool result = (type & (kIsNotStringMask | kIsNotInternalizedMask)) !=
(kStringTag | kNotInternalizedTag);
SLOW_DCHECK(result == HeapObject::IsUniqueName());
DCHECK_IMPLIES(result, HasHashCode());
return result;
}
@ -82,13 +83,13 @@ bool Name::Equals(Isolate* isolate, Handle<Name> one, Handle<Name> two) {
Handle<String>::cast(two));
}
bool Name::IsHashFieldComputed(uint32_t field) {
return (field & kHashNotComputedMask) == 0;
bool Name::IsHashFieldComputed(uint32_t raw_hash_field) {
return (raw_hash_field & kHashNotComputedMask) == 0;
}
bool Name::HasHashCode() { return IsHashFieldComputed(raw_hash_field()); }
bool Name::HasHashCode() const { return IsHashFieldComputed(raw_hash_field()); }
uint32_t Name::Hash() {
uint32_t Name::EnsureHash() {
// Fast case: has hash code already been computed?
uint32_t field = raw_hash_field();
if (IsHashFieldComputed(field)) return field >> kHashShift;

View File

@ -23,12 +23,11 @@ namespace internal {
class Name : public TorqueGeneratedName<Name, PrimitiveHeapObject> {
public:
// Tells whether the hash code has been computed.
inline bool HasHashCode();
inline bool HasHashCode() const;
// Returns a hash value used for the property table. Ensures that the hash
// value is computed.
// TODO(ishell): rename to EnsureHash().
inline uint32_t Hash();
inline uint32_t EnsureHash();
// Returns a hash value used for the property table (same as Hash()), assumes
// the hash is already computed.
@ -139,8 +138,7 @@ class Name : public TorqueGeneratedName<Name, PrimitiveHeapObject> {
static const int kEmptyHashField =
kIsNotIntegerIndexMask | kHashNotComputedMask;
protected:
static inline bool IsHashFieldComputed(uint32_t field);
static inline bool IsHashFieldComputed(uint32_t raw_hash_field);
TQ_OBJECT_CONSTRUCTORS(Name)
};

View File

@ -1044,11 +1044,11 @@ Object Object::GetSimpleHash(Object object) {
return Smi::FromInt(hash & Smi::kMaxValue);
}
if (object.IsName()) {
uint32_t hash = Name::cast(object).Hash();
uint32_t hash = Name::cast(object).EnsureHash();
return Smi::FromInt(hash);
}
if (object.IsOddball()) {
uint32_t hash = Oddball::cast(object).to_string().Hash();
uint32_t hash = Oddball::cast(object).to_string().EnsureHash();
return Smi::FromInt(hash);
}
if (object.IsBigInt()) {

View File

@ -2432,7 +2432,7 @@ void HeapObject::RehashBasedOnMap(Isolate* isolate) {
case INTERNALIZED_STRING_TYPE:
// Rare case, rehash read-only space strings before they are sealed.
DCHECK(ReadOnlyHeap::Contains(*this));
String::cast(*this).Hash();
String::cast(*this).EnsureHash();
break;
default:
UNREACHABLE();

View File

@ -421,7 +421,7 @@ InternalIndex OrderedNameDictionary::FindEntry(LocalIsolate* isolate,
return InternalIndex::NotFound();
}
int raw_entry = HashToEntryRaw(raw_key.Hash());
int raw_entry = HashToEntryRaw(raw_key.hash());
while (raw_entry != kNotFound) {
InternalIndex entry(raw_entry);
Object candidate_key = KeyAt(entry);
@ -474,6 +474,7 @@ template <typename LocalIsolate>
MaybeHandle<OrderedNameDictionary> OrderedNameDictionary::Add(
LocalIsolate* isolate, Handle<OrderedNameDictionary> table,
Handle<Name> key, Handle<Object> value, PropertyDetails details) {
DCHECK(key->IsUniqueName());
DCHECK(table->FindEntry(isolate, *key).is_not_found());
MaybeHandle<OrderedNameDictionary> table_candidate =
@ -482,7 +483,7 @@ MaybeHandle<OrderedNameDictionary> OrderedNameDictionary::Add(
return table_candidate;
}
// Read the existing bucket values.
int hash = key->Hash();
int hash = key->hash();
int bucket = table->HashToBucket(hash);
int previous_entry = table->HashToEntryRaw(hash);
int nof = table->NumberOfElements();
@ -834,7 +835,7 @@ SmallOrderedHashTable<SmallOrderedNameDictionary>::FindEntry(Isolate* isolate,
DCHECK(key.IsUniqueName());
Name raw_key = Name::cast(key);
int raw_entry = HashToFirstEntry(raw_key.Hash());
int raw_entry = HashToFirstEntry(raw_key.hash());
// Walk the chain in the bucket to find the key.
while (raw_entry != kNotFound) {
@ -850,6 +851,7 @@ SmallOrderedHashTable<SmallOrderedNameDictionary>::FindEntry(Isolate* isolate,
MaybeHandle<SmallOrderedNameDictionary> SmallOrderedNameDictionary::Add(
Isolate* isolate, Handle<SmallOrderedNameDictionary> table,
Handle<Name> key, Handle<Object> value, PropertyDetails details) {
DCHECK(key->IsUniqueName());
DCHECK(table->FindEntry(isolate, *key).is_not_found());
if (table->UsedCapacity() >= table->Capacity()) {
@ -863,7 +865,7 @@ MaybeHandle<SmallOrderedNameDictionary> SmallOrderedNameDictionary::Add(
int nof = table->NumberOfElements();
// Read the existing bucket values.
int hash = key->Hash();
int hash = key->hash();
int bucket = table->HashToBucket(hash);
int previous_entry = table->HashToFirstEntry(hash);

View File

@ -19,7 +19,7 @@ namespace internal {
struct StringHandleHash {
V8_INLINE size_t operator()(Handle<String> string) const {
return string->Hash();
return string->EnsureHash();
}
};

View File

@ -26,11 +26,11 @@ bool StringSetShape::IsMatch(String key, Object value) {
}
uint32_t StringSetShape::Hash(ReadOnlyRoots roots, String key) {
return key.Hash();
return key.EnsureHash();
}
uint32_t StringSetShape::HashForObject(ReadOnlyRoots roots, Object object) {
return String::cast(object).Hash();
return String::cast(object).EnsureHash();
}
} // namespace internal

View File

@ -237,7 +237,7 @@ std::unique_ptr<StringTable::Data> StringTable::Data::Resize(
Object element = data->Get(isolate, i);
if (element == empty_element() || element == deleted_element()) continue;
String string = String::cast(element);
uint32_t hash = string.Hash();
uint32_t hash = string.hash();
InternalIndex insertion_index = new_data->FindInsertionEntry(isolate, hash);
new_data->Set(insertion_index, string);
}
@ -354,7 +354,7 @@ class InternalizedStringKey final : public StringTableKey {
DCHECK(!string->IsInternalizedString());
DCHECK(string->IsFlat());
// Make sure hash_field is computed.
string->Hash();
string->EnsureHash();
set_raw_hash_field(string->raw_hash_field());
}

View File

@ -206,7 +206,8 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
self.AllocateExternalPointerEntries(isolate);
self.SetResource(isolate, resource);
isolate->heap()->RegisterExternalString(*this);
if (is_internalized) self.Hash(); // Force regeneration of the hash value.
// Force regeneration of the hash value.
if (is_internalized) self.EnsureHash();
return true;
}
@ -282,7 +283,8 @@ bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
self.AllocateExternalPointerEntries(isolate);
self.SetResource(isolate, resource);
isolate->heap()->RegisterExternalString(*this);
if (is_internalized) self.Hash(); // Force regeneration of the hash value.
// Force regeneration of the hash value.
if (is_internalized) self.EnsureHash();
return true;
}
@ -515,9 +517,8 @@ Handle<Object> String::ToNumber(Isolate* isolate, Handle<String> subject) {
// Update the hash field to speed up sequential convertions.
uint32_t raw_hash_field = StringHasher::MakeArrayIndexHash(d, len);
#ifdef DEBUG
subject->Hash(); // Force hash calculation.
DCHECK_EQ(static_cast<int>(subject->raw_hash_field()),
static_cast<int>(raw_hash_field));
subject->EnsureHash(); // Force hash calculation.
DCHECK_EQ(subject->raw_hash_field(), raw_hash_field);
#endif
subject->set_raw_hash_field(raw_hash_field);
}
@ -813,7 +814,7 @@ bool String::SlowEquals(String other) {
if (HasHashCode() && other.HasHashCode()) {
#ifdef ENABLE_SLOW_DCHECKS
if (FLAG_enable_slow_asserts) {
if (Hash() != other.Hash()) {
if (hash() != other.hash()) {
bool found_difference = false;
for (int i = 0; i < len; i++) {
if (Get(i) != other.Get(i)) {
@ -825,7 +826,7 @@ bool String::SlowEquals(String other) {
}
}
#endif
if (Hash() != other.Hash()) return false;
if (hash() != other.hash()) return false;
}
// We know the strings are both non-empty. Compare the first chars
@ -864,7 +865,7 @@ bool String::SlowEquals(Isolate* isolate, Handle<String> one,
if (one->HasHashCode() && two->HasHashCode()) {
#ifdef ENABLE_SLOW_DCHECKS
if (FLAG_enable_slow_asserts) {
if (one->Hash() != two->Hash()) {
if (one->hash() != two->hash()) {
bool found_difference = false;
for (int i = 0; i < one_length; i++) {
if (one->Get(i) != two->Get(i)) {
@ -876,7 +877,7 @@ bool String::SlowEquals(Isolate* isolate, Handle<String> one,
}
}
#endif
if (one->Hash() != two->Hash()) return false;
if (one->hash() != two->hash()) return false;
}
// We know the strings are both non-empty. Compare the first chars
@ -1417,7 +1418,7 @@ bool String::SlowAsArrayIndex(uint32_t* index) {
DisallowHeapAllocation no_gc;
int length = this->length();
if (length <= kMaxCachedArrayIndexLength) {
Hash(); // Force computation of hash code.
EnsureHash(); // Force computation of hash code.
uint32_t field = raw_hash_field();
if ((field & kIsNotIntegerIndexMask) != 0) return false;
*index = ArrayIndexValueBits::decode(field);
@ -1432,7 +1433,7 @@ bool String::SlowAsIntegerIndex(size_t* index) {
DisallowHeapAllocation no_gc;
int length = this->length();
if (length <= kMaxCachedArrayIndexLength) {
Hash(); // Force computation of hash code.
EnsureHash(); // Force computation of hash code.
uint32_t field = raw_hash_field();
if ((field & kIsNotIntegerIndexMask) != 0) return false;
*index = ArrayIndexValueBits::decode(field);

View File

@ -188,9 +188,6 @@ int TransitionArray::SearchSpecial(Symbol symbol, int* out_insertion_index) {
int TransitionArray::SearchName(Name name, int* out_insertion_index) {
DCHECK(name.IsUniqueName());
// The name is taken from DescriptorArray, so it must already has a computed
// hash.
DCHECK(name.HasHashCode());
return internal::Search<ALL_ENTRIES>(this, name, number_of_entries(),
out_insertion_index);
}

View File

@ -1123,7 +1123,7 @@ Object RegExpResultsCache::Lookup(Heap* heap, String key_string,
cache = heap->regexp_multiple_cache();
}
uint32_t hash = key_string.Hash();
uint32_t hash = key_string.hash();
uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) &
~(kArrayEntriesPerCacheEntry - 1));
if (cache.get(index + kStringOffset) != key_string ||
@ -1158,7 +1158,7 @@ void RegExpResultsCache::Enter(Isolate* isolate, Handle<String> key_string,
cache = factory->regexp_multiple_cache();
}
uint32_t hash = key_string->Hash();
uint32_t hash = key_string->hash();
uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) &
~(kArrayEntriesPerCacheEntry - 1));
if (cache->get(index + kStringOffset) == Smi::zero()) {

View File

@ -321,7 +321,7 @@ Handle<String> StringTableInsertionKey::AsHandle(Isolate* isolate) {
uint32_t StringTableInsertionKey::ComputeRawHashField(String string) {
// Make sure raw_hash_field() is computed.
string.Hash();
string.EnsureHash();
return string.raw_hash_field();
}

View File

@ -1011,15 +1011,14 @@ TEST(StringAllocation) {
Handle<String> one_byte_sym =
factory->InternalizeString(OneByteVector(one_byte, length));
CHECK_EQ(length, one_byte_sym->length());
CHECK(one_byte_sym->HasHashCode());
Handle<String> non_one_byte_str =
factory->NewStringFromUtf8(Vector<const char>(non_one_byte, 3 * length))
.ToHandleChecked();
non_one_byte_str->Hash();
CHECK_EQ(length, non_one_byte_str->length());
Handle<String> one_byte_str =
factory->NewStringFromUtf8(Vector<const char>(one_byte, length))
.ToHandleChecked();
one_byte_str->Hash();
CHECK_EQ(length, one_byte_str->length());
DeleteArray(non_one_byte);
DeleteArray(one_byte);

View File

@ -1829,11 +1829,11 @@ void TestString(i::Isolate* isolate, const IndexData& data) {
size_t index;
CHECK(s->AsIntegerIndex(&index));
CHECK_EQ(data.integer_index, index);
s->Hash();
s->EnsureHash();
CHECK_EQ(0, s->raw_hash_field() & String::kIsNotIntegerIndexMask);
CHECK(s->HasHashCode());
}
if (!s->HasHashCode()) s->Hash();
if (!s->HasHashCode()) s->EnsureHash();
CHECK(s->HasHashCode());
if (!data.is_integer_index) {
CHECK_NE(0, s->raw_hash_field() & String::kIsNotIntegerIndexMask);
@ -1850,11 +1850,11 @@ TEST(HashArrayIndexStrings) {
CHECK_EQ(StringHasher::MakeArrayIndexHash(0 /* value */, 1 /* length */) >>
Name::kHashShift,
isolate->factory()->zero_string()->Hash());
isolate->factory()->zero_string()->hash());
CHECK_EQ(StringHasher::MakeArrayIndexHash(1 /* value */, 1 /* length */) >>
Name::kHashShift,
isolate->factory()->one_string()->Hash());
isolate->factory()->one_string()->hash());
IndexData tests[] = {
{"", false, 0, false, 0},

View File

@ -54,7 +54,8 @@ TEST(Create) {
CHECK(symbols[i]->IsName());
CHECK(symbols[i]->IsSymbol());
CHECK(symbols[i]->HasHashCode());
CHECK_GT(symbols[i]->Hash(), 0u);
CHECK(symbols[i]->IsUniqueName());
CHECK_GT(symbols[i]->hash(), 0u);
os << Brief(*symbols[i]) << "\n";
#if OBJECT_PRINT
symbols[i]->Print(os);