| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 2878154f63df82385e8d7a3824b942cd81ed8664..6265e05211b9bba0b50a536d315afb65ade32db8 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -17510,10 +17510,9 @@ void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
|
| namespace {
|
|
|
| template <class StringClass>
|
| -void MigrateExternalStringResource(Isolate* isolate, Handle<String> from,
|
| - Handle<String> to) {
|
| - Handle<StringClass> cast_from = Handle<StringClass>::cast(from);
|
| - Handle<StringClass> cast_to = Handle<StringClass>::cast(to);
|
| +void MigrateExternalStringResource(Isolate* isolate, String* from, String* to) {
|
| + StringClass* cast_from = StringClass::cast(from);
|
| + StringClass* cast_to = StringClass::cast(to);
|
| const typename StringClass::Resource* to_resource = cast_to->resource();
|
| if (to_resource == nullptr) {
|
| // |to| is a just-created internalized copy of |from|. Migrate the resource.
|
| @@ -17523,7 +17522,43 @@ void MigrateExternalStringResource(Isolate* isolate, Handle<String> from,
|
| cast_from->set_resource(nullptr);
|
| } else if (to_resource != cast_from->resource()) {
|
| // |to| already existed and has its own resource. Finalize |from|.
|
| - isolate->heap()->FinalizeExternalString(*from);
|
| + isolate->heap()->FinalizeExternalString(from);
|
| + }
|
| +}
|
| +
|
| +void MakeStringThin(String* string, String* internalized, Isolate* isolate) {
|
| + if (string->IsExternalString()) {
|
| + if (internalized->IsExternalOneByteString()) {
|
| + MigrateExternalStringResource<ExternalOneByteString>(isolate, string,
|
| + internalized);
|
| + } else if (internalized->IsExternalTwoByteString()) {
|
| + MigrateExternalStringResource<ExternalTwoByteString>(isolate, string,
|
| + internalized);
|
| + } else {
|
| + // If the external string is duped into an existing non-external
|
| + // internalized string, free its resource (it's about to be rewritten
|
| + // into a ThinString below).
|
| + isolate->heap()->FinalizeExternalString(string);
|
| + }
|
| + }
|
| +
|
| + if (!string->IsInternalizedString()) {
|
| + DisallowHeapAllocation no_gc;
|
| + bool one_byte = internalized->IsOneByteRepresentation();
|
| + Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map()
|
| + : isolate->factory()->thin_string_map();
|
| + int old_size = string->Size();
|
| + DCHECK(old_size >= ThinString::kSize);
|
| + string->synchronized_set_map(*map);
|
| + ThinString* thin = ThinString::cast(string);
|
| + thin->set_actual(internalized);
|
| + Address thin_end = thin->address() + ThinString::kSize;
|
| + int size_delta = old_size - ThinString::kSize;
|
| + if (size_delta != 0) {
|
| + Heap* heap = isolate->heap();
|
| + heap->CreateFillerObjectAt(thin_end, size_delta, ClearRecordedSlots::kNo);
|
| + heap->AdjustLiveBytes(thin, -size_delta);
|
| + }
|
| }
|
| }
|
|
|
| @@ -17544,44 +17579,7 @@ Handle<String> StringTable::LookupString(Isolate* isolate,
|
| Handle<String> result = LookupKey(isolate, &key);
|
|
|
| if (FLAG_thin_strings) {
|
| - if (string->IsExternalString()) {
|
| - if (result->IsExternalOneByteString()) {
|
| - MigrateExternalStringResource<ExternalOneByteString>(isolate, string,
|
| - result);
|
| - } else if (result->IsExternalTwoByteString()) {
|
| - MigrateExternalStringResource<ExternalTwoByteString>(isolate, string,
|
| - result);
|
| - } else {
|
| - // If the external string is duped into an existing non-external
|
| - // internalized string, free its resource (it's about to be rewritten
|
| - // into a ThinString below).
|
| - isolate->heap()->FinalizeExternalString(*string);
|
| - }
|
| - }
|
| -
|
| - // The LookupKey() call above tries to internalize the string in-place.
|
| - // In cases where that wasn't possible (e.g. new-space strings), turn them
|
| - // into ThinStrings referring to their internalized versions now.
|
| - if (!string->IsInternalizedString()) {
|
| - DisallowHeapAllocation no_gc;
|
| - bool one_byte = result->IsOneByteRepresentation();
|
| - Handle<Map> map = one_byte
|
| - ? isolate->factory()->thin_one_byte_string_map()
|
| - : isolate->factory()->thin_string_map();
|
| - int old_size = string->Size();
|
| - DCHECK(old_size >= ThinString::kSize);
|
| - string->synchronized_set_map(*map);
|
| - Handle<ThinString> thin = Handle<ThinString>::cast(string);
|
| - thin->set_actual(*result);
|
| - Address thin_end = thin->address() + ThinString::kSize;
|
| - int size_delta = old_size - ThinString::kSize;
|
| - if (size_delta != 0) {
|
| - Heap* heap = isolate->heap();
|
| - heap->CreateFillerObjectAt(thin_end, size_delta,
|
| - ClearRecordedSlots::kNo);
|
| - heap->AdjustLiveBytes(*thin, -size_delta);
|
| - }
|
| - }
|
| + MakeStringThin(*string, *result, isolate);
|
| } else { // !FLAG_thin_strings
|
| if (string->IsConsString()) {
|
| Handle<ConsString> cons = Handle<ConsString>::cast(string);
|
| @@ -17631,10 +17629,172 @@ Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
|
| return Handle<String>::cast(string);
|
| }
|
|
|
| +namespace {
|
| +
|
| +class StringTableNoAllocateKey : public HashTableKey {
|
| + public:
|
| + StringTableNoAllocateKey(String* string, uint32_t seed)
|
| + : string_(string), length_(string->length()) {
|
| + StringShape shape(string);
|
| + one_byte_ = shape.HasOnlyOneByteChars();
|
| + DCHECK(!shape.IsInternalized());
|
| + DCHECK(!shape.IsThin());
|
| + if (shape.IsCons() && length_ <= String::kMaxHashCalcLength) {
|
| + special_flattening_ = true;
|
| + uint32_t hash_field = 0;
|
| + if (one_byte_) {
|
| + one_byte_content_ = new uint8_t[length_];
|
| + String::WriteToFlat(string, one_byte_content_, 0, length_);
|
| + hash_field = StringHasher::HashSequentialString(one_byte_content_,
|
| + length_, seed);
|
| + } else {
|
| + two_byte_content_ = new uint16_t[length_];
|
| + String::WriteToFlat(string, two_byte_content_, 0, length_);
|
| + hash_field = StringHasher::HashSequentialString(two_byte_content_,
|
| + length_, seed);
|
| + }
|
| + string->set_hash_field(hash_field);
|
| + } else {
|
| + special_flattening_ = false;
|
| + }
|
| + hash_ = string->Hash();
|
| + }
|
| +
|
| + ~StringTableNoAllocateKey() {
|
| + if (one_byte_) {
|
| + delete[] one_byte_content_;
|
| + } else {
|
| + delete[] two_byte_content_;
|
| + }
|
| + }
|
| +
|
| + bool IsMatch(Object* otherstring) override {
|
| + String* other = String::cast(otherstring);
|
| + DCHECK(other->IsInternalizedString());
|
| + DCHECK(other->IsFlat());
|
| + if (hash_ != other->Hash()) return false;
|
| + int len = length_;
|
| + if (len != other->length()) return false;
|
| +
|
| + if (!special_flattening_) {
|
| + if (string_->Get(0) != other->Get(0)) return false;
|
| + if (string_->IsFlat()) {
|
| + StringShape shape1(string_);
|
| + StringShape shape2(other);
|
| + if (shape1.encoding_tag() == kOneByteStringTag &&
|
| + shape2.encoding_tag() == kOneByteStringTag) {
|
| + String::FlatContent flat1 = string_->GetFlatContent();
|
| + String::FlatContent flat2 = other->GetFlatContent();
|
| + return CompareRawStringContents(flat1.ToOneByteVector().start(),
|
| + flat2.ToOneByteVector().start(), len);
|
| + }
|
| + if (shape1.encoding_tag() == kTwoByteStringTag &&
|
| + shape2.encoding_tag() == kTwoByteStringTag) {
|
| + String::FlatContent flat1 = string_->GetFlatContent();
|
| + String::FlatContent flat2 = other->GetFlatContent();
|
| + return CompareRawStringContents(flat1.ToUC16Vector().start(),
|
| + flat2.ToUC16Vector().start(), len);
|
| + }
|
| + }
|
| + StringComparator comparator;
|
| + return comparator.Equals(string_, other);
|
| + }
|
| +
|
| + String::FlatContent flat_content = other->GetFlatContent();
|
| + if (one_byte_) {
|
| + if (flat_content.IsOneByte()) {
|
| + return CompareRawStringContents(
|
| + one_byte_content_, flat_content.ToOneByteVector().start(), len);
|
| + } else {
|
| + DCHECK(flat_content.IsTwoByte());
|
| + for (int i = 0; i < len; i++) {
|
| + if (flat_content.Get(i) != one_byte_content_[i]) return false;
|
| + }
|
| + return true;
|
| + }
|
| + } else {
|
| + if (flat_content.IsTwoByte()) {
|
| + return CompareRawStringContents(
|
| + two_byte_content_, flat_content.ToUC16Vector().start(), len);
|
| + } else {
|
| + DCHECK(flat_content.IsOneByte());
|
| + for (int i = 0; i < len; i++) {
|
| + if (flat_content.Get(i) != two_byte_content_[i]) return false;
|
| + }
|
| + return true;
|
| + }
|
| + }
|
| + }
|
| +
|
| + uint32_t Hash() override { return hash_; }
|
| +
|
| + uint32_t HashForObject(Object* key) override {
|
| + return String::cast(key)->Hash();
|
| + }
|
| +
|
| + MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
|
| + UNREACHABLE();
|
| + return Handle<String>();
|
| + }
|
| +
|
| + private:
|
| + String* string_;
|
| + int length_;
|
| + bool one_byte_;
|
| + bool special_flattening_;
|
| + uint32_t hash_ = 0;
|
| + union {
|
| + uint8_t* one_byte_content_ = nullptr;
|
| + uint16_t* two_byte_content_;
|
| + };
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +// static
|
| +Object* StringTable::LookupStringIfExists_NoAllocate(String* string) {
|
| + DisallowHeapAllocation no_gc;
|
| + Heap* heap = string->GetHeap();
|
| + Isolate* isolate = heap->isolate();
|
| + StringTable* table = heap->string_table();
|
| +
|
| + StringTableNoAllocateKey key(string, heap->HashSeed());
|
| +
|
| + // String could be an array index.
|
| + DCHECK(string->HasHashCode());
|
| + uint32_t hash = string->hash_field();
|
| +
|
| + // Valid array indices are >= 0, so they cannot be mixed up with any of
|
| + // the result sentinels, which are negative.
|
| + STATIC_ASSERT(
|
| + !String::ArrayIndexValueBits::is_valid(ResultSentinel::kUnsupported));
|
| + STATIC_ASSERT(
|
| + !String::ArrayIndexValueBits::is_valid(ResultSentinel::kNotFound));
|
| +
|
| + if ((hash & Name::kContainsCachedArrayIndexMask) == 0) {
|
| + return Smi::FromInt(String::ArrayIndexValueBits::decode(hash));
|
| + }
|
| + if ((hash & Name::kIsNotArrayIndexMask) == 0) {
|
| + // It is an indexed, but it's not cached.
|
| + return Smi::FromInt(ResultSentinel::kUnsupported);
|
| + }
|
| +
|
| + int entry = table->FindEntry(isolate, &key, key.Hash());
|
| + if (entry != kNotFound) {
|
| + String* internalized = String::cast(table->KeyAt(entry));
|
| + if (FLAG_thin_strings) {
|
| + MakeStringThin(string, internalized, isolate);
|
| + }
|
| + return internalized;
|
| + }
|
| + // A string that's not an array index, and not in the string table,
|
| + // cannot have been used as a property name before.
|
| + return Smi::FromInt(ResultSentinel::kNotFound);
|
| +}
|
|
|
| String* StringTable::LookupKeyIfExists(Isolate* isolate, HashTableKey* key) {
|
| Handle<StringTable> table = isolate->factory()->string_table();
|
| - int entry = table->FindEntry(key);
|
| + int entry = table->FindEntry(isolate, key);
|
| if (entry != kNotFound) return String::cast(table->KeyAt(entry));
|
| return NULL;
|
| }
|
|
|