Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(215)

Side by Side Diff: src/objects.cc

Issue 2549773002: Internalize strings in-place (Closed)
Patch Set: fix performance Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/objects.h" 5 #include "src/objects.h"
6 6
7 #include <cmath> 7 #include <cmath>
8 #include <iomanip> 8 #include <iomanip>
9 #include <memory> 9 #include <memory>
10 #include <sstream> 10 #include <sstream>
(...skipping 2518 matching lines...) Expand 10 before | Expand all | Expand 10 after
2529 resource->data(), 2529 resource->data(),
2530 resource->length() * sizeof(smart_chars[0])) == 0); 2530 resource->length() * sizeof(smart_chars[0])) == 0);
2531 } 2531 }
2532 #endif // DEBUG 2532 #endif // DEBUG
2533 int size = this->Size(); // Byte size of the original string. 2533 int size = this->Size(); // Byte size of the original string.
2534 // Abort if size does not allow in-place conversion. 2534 // Abort if size does not allow in-place conversion.
2535 if (size < ExternalString::kShortSize) return false; 2535 if (size < ExternalString::kShortSize) return false;
2536 Heap* heap = GetHeap(); 2536 Heap* heap = GetHeap();
2537 bool is_one_byte = this->IsOneByteRepresentation(); 2537 bool is_one_byte = this->IsOneByteRepresentation();
2538 bool is_internalized = this->IsInternalizedString(); 2538 bool is_internalized = this->IsInternalizedString();
2539 bool has_pointers = this->IsConsString() || this->IsSlicedString(); 2539 bool has_pointers = StringShape(this).IsIndirect();
2540 2540
2541 // Morph the string to an external string by replacing the map and 2541 // Morph the string to an external string by replacing the map and
2542 // reinitializing the fields. This won't work if the space the existing 2542 // reinitializing the fields. This won't work if the space the existing
2543 // string occupies is too small for a regular external string. 2543 // string occupies is too small for a regular external string.
2544 // Instead, we resort to a short external string instead, omitting 2544 // Instead, we resort to a short external string instead, omitting
2545 // the field caching the address of the backing store. When we encounter 2545 // the field caching the address of the backing store. When we encounter
2546 // short external strings in generated code, we need to bailout to runtime. 2546 // short external strings in generated code, we need to bailout to runtime.
2547 Map* new_map; 2547 Map* new_map;
2548 if (size < ExternalString::kSize) { 2548 if (size < ExternalString::kSize) {
2549 new_map = is_internalized 2549 new_map = is_internalized
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
2601 DCHECK(memcmp(smart_chars.start(), 2601 DCHECK(memcmp(smart_chars.start(),
2602 resource->data(), 2602 resource->data(),
2603 resource->length() * sizeof(smart_chars[0])) == 0); 2603 resource->length() * sizeof(smart_chars[0])) == 0);
2604 } 2604 }
2605 #endif // DEBUG 2605 #endif // DEBUG
2606 int size = this->Size(); // Byte size of the original string. 2606 int size = this->Size(); // Byte size of the original string.
2607 // Abort if size does not allow in-place conversion. 2607 // Abort if size does not allow in-place conversion.
2608 if (size < ExternalString::kShortSize) return false; 2608 if (size < ExternalString::kShortSize) return false;
2609 Heap* heap = GetHeap(); 2609 Heap* heap = GetHeap();
2610 bool is_internalized = this->IsInternalizedString(); 2610 bool is_internalized = this->IsInternalizedString();
2611 bool has_pointers = this->IsConsString() || this->IsSlicedString(); 2611 bool has_pointers = StringShape(this).IsIndirect();
2612 2612
2613 // Morph the string to an external string by replacing the map and 2613 // Morph the string to an external string by replacing the map and
2614 // reinitializing the fields. This won't work if the space the existing 2614 // reinitializing the fields. This won't work if the space the existing
2615 // string occupies is too small for a regular external string. 2615 // string occupies is too small for a regular external string.
2616 // Instead, we resort to a short external string instead, omitting 2616 // Instead, we resort to a short external string instead, omitting
2617 // the field caching the address of the backing store. When we encounter 2617 // the field caching the address of the backing store. When we encounter
2618 // short external strings in generated code, we need to bailout to runtime. 2618 // short external strings in generated code, we need to bailout to runtime.
2619 Map* new_map; 2619 Map* new_map;
2620 if (size < ExternalString::kSize) { 2620 if (size < ExternalString::kSize) {
2621 new_map = is_internalized 2621 new_map = is_internalized
(...skipping 7733 matching lines...) Expand 10 before | Expand all | Expand 10 after
10355 while ( 10355 while (
10356 right > left && 10356 right > left &&
10357 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) { 10357 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) {
10358 right--; 10358 right--;
10359 } 10359 }
10360 } 10360 }
10361 10361
10362 return isolate->factory()->NewSubString(string, left, right); 10362 return isolate->factory()->NewSubString(string, left, right);
10363 } 10363 }
10364 10364
10365 bool String::LooksValid() { 10365 bool String::LooksValid() { return GetIsolate()->heap()->Contains(this); }
10366 if (!GetIsolate()->heap()->Contains(this)) return false;
10367 return true;
10368 }
10369 10366
10370 // static 10367 // static
10371 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) { 10368 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) {
10372 if (name->IsString()) return Handle<String>::cast(name); 10369 if (name->IsString()) return Handle<String>::cast(name);
10373 // ES6 section 9.2.11 SetFunctionName, step 4. 10370 // ES6 section 9.2.11 SetFunctionName, step 4.
10374 Isolate* const isolate = name->GetIsolate(); 10371 Isolate* const isolate = name->GetIsolate();
10375 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate); 10372 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate);
10376 if (description->IsUndefined(isolate)) { 10373 if (description->IsUndefined(isolate)) {
10377 return isolate->factory()->empty_string(); 10374 return isolate->factory()->empty_string();
10378 } 10375 }
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
10492 StringShape shape(this); 10489 StringShape shape(this);
10493 String* string = this; 10490 String* string = this;
10494 int offset = 0; 10491 int offset = 0;
10495 if (shape.representation_tag() == kConsStringTag) { 10492 if (shape.representation_tag() == kConsStringTag) {
10496 ConsString* cons = ConsString::cast(string); 10493 ConsString* cons = ConsString::cast(string);
10497 if (cons->second()->length() != 0) { 10494 if (cons->second()->length() != 0) {
10498 return FlatContent(); 10495 return FlatContent();
10499 } 10496 }
10500 string = cons->first(); 10497 string = cons->first();
10501 shape = StringShape(string); 10498 shape = StringShape(string);
10502 } 10499 } else if (shape.representation_tag() == kSlicedStringTag) {
10503 if (shape.representation_tag() == kSlicedStringTag) {
10504 SlicedString* slice = SlicedString::cast(string); 10500 SlicedString* slice = SlicedString::cast(string);
10505 offset = slice->offset(); 10501 offset = slice->offset();
10506 string = slice->parent(); 10502 string = slice->parent();
10507 shape = StringShape(string); 10503 shape = StringShape(string);
10508 DCHECK(shape.representation_tag() != kConsStringTag && 10504 DCHECK(shape.representation_tag() != kConsStringTag &&
10509 shape.representation_tag() != kSlicedStringTag); 10505 shape.representation_tag() != kSlicedStringTag);
10510 } 10506 }
10507 if (shape.representation_tag() == kThinStringTag) {
10508 ThinString* thin = ThinString::cast(string);
10509 string = thin->actual();
10510 shape = StringShape(string);
10511 DCHECK(!shape.IsCons());
10512 DCHECK(!shape.IsSliced());
10513 }
10511 if (shape.encoding_tag() == kOneByteStringTag) { 10514 if (shape.encoding_tag() == kOneByteStringTag) {
10512 const uint8_t* start; 10515 const uint8_t* start;
10513 if (shape.representation_tag() == kSeqStringTag) { 10516 if (shape.representation_tag() == kSeqStringTag) {
10514 start = SeqOneByteString::cast(string)->GetChars(); 10517 start = SeqOneByteString::cast(string)->GetChars();
10515 } else { 10518 } else {
10516 start = ExternalOneByteString::cast(string)->GetChars(); 10519 start = ExternalOneByteString::cast(string)->GetChars();
10517 } 10520 }
10518 return FlatContent(start + offset, length); 10521 return FlatContent(start + offset, length);
10519 } else { 10522 } else {
10520 DCHECK(shape.encoding_tag() == kTwoByteStringTag); 10523 DCHECK(shape.encoding_tag() == kTwoByteStringTag);
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
10586 case kSeqStringTag: 10589 case kSeqStringTag:
10587 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); 10590 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
10588 case kExternalStringTag: 10591 case kExternalStringTag:
10589 return ExternalTwoByteString::cast(this)-> 10592 return ExternalTwoByteString::cast(this)->
10590 ExternalTwoByteStringGetData(start); 10593 ExternalTwoByteStringGetData(start);
10591 case kSlicedStringTag: { 10594 case kSlicedStringTag: {
10592 SlicedString* slice = SlicedString::cast(this); 10595 SlicedString* slice = SlicedString::cast(this);
10593 return slice->parent()->GetTwoByteData(start + slice->offset()); 10596 return slice->parent()->GetTwoByteData(start + slice->offset());
10594 } 10597 }
10595 case kConsStringTag: 10598 case kConsStringTag:
10599 case kThinStringTag:
10596 UNREACHABLE(); 10600 UNREACHABLE();
10597 return NULL; 10601 return NULL;
10598 } 10602 }
10599 UNREACHABLE(); 10603 UNREACHABLE();
10600 return NULL; 10604 return NULL;
10601 } 10605 }
10602 10606
10603 10607
10604 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) { 10608 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
10605 return reinterpret_cast<uc16*>( 10609 return reinterpret_cast<uc16*>(
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after
10852 } 10856 }
10853 } else { 10857 } else {
10854 return string->Get(index); 10858 return string->Get(index);
10855 } 10859 }
10856 } 10860 }
10857 10861
10858 UNREACHABLE(); 10862 UNREACHABLE();
10859 return 0; 10863 return 0;
10860 } 10864 }
10861 10865
10866 uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); }
10862 10867
10863 uint16_t SlicedString::SlicedStringGet(int index) { 10868 uint16_t SlicedString::SlicedStringGet(int index) {
10864 return parent()->Get(offset() + index); 10869 return parent()->Get(offset() + index);
10865 } 10870 }
10866 10871
10867 10872
10868 template <typename sinkchar> 10873 template <typename sinkchar>
10869 void String::WriteToFlat(String* src, 10874 void String::WriteToFlat(String* src,
10870 sinkchar* sink, 10875 sinkchar* sink,
10871 int f, 10876 int f,
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
10946 } 10951 }
10947 break; 10952 break;
10948 } 10953 }
10949 case kOneByteStringTag | kSlicedStringTag: 10954 case kOneByteStringTag | kSlicedStringTag:
10950 case kTwoByteStringTag | kSlicedStringTag: { 10955 case kTwoByteStringTag | kSlicedStringTag: {
10951 SlicedString* slice = SlicedString::cast(source); 10956 SlicedString* slice = SlicedString::cast(source);
10952 unsigned offset = slice->offset(); 10957 unsigned offset = slice->offset();
10953 WriteToFlat(slice->parent(), sink, from + offset, to + offset); 10958 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
10954 return; 10959 return;
10955 } 10960 }
10961 case kOneByteStringTag | kThinStringTag:
10962 case kTwoByteStringTag | kThinStringTag:
10963 source = ThinString::cast(source)->actual();
10964 break;
10956 } 10965 }
10957 } 10966 }
10958 } 10967 }
10959 10968
10960 10969
10961 10970
10962 template <typename SourceChar> 10971 template <typename SourceChar>
10963 static void CalculateLineEndsImpl(Isolate* isolate, 10972 static void CalculateLineEndsImpl(Isolate* isolate,
10964 List<int>* line_ends, 10973 List<int>* line_ends,
10965 Vector<const SourceChar> src, 10974 Vector<const SourceChar> src,
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after
11167 }; 11176 };
11168 11177
11169 11178
11170 bool String::SlowEquals(String* other) { 11179 bool String::SlowEquals(String* other) {
11171 DisallowHeapAllocation no_gc; 11180 DisallowHeapAllocation no_gc;
11172 // Fast check: negative check with lengths. 11181 // Fast check: negative check with lengths.
11173 int len = length(); 11182 int len = length();
11174 if (len != other->length()) return false; 11183 if (len != other->length()) return false;
11175 if (len == 0) return true; 11184 if (len == 0) return true;
11176 11185
11186 // Fast check: if at least one ThinString is involved, dereference it/them
11187 // and restart.
11188 if (this->IsThinString() || other->IsThinString()) {
11189 if (other->IsThinString()) other = ThinString::cast(other)->actual();
11190 if (this->IsThinString()) {
11191 return ThinString::cast(this)->actual()->Equals(other);
11192 } else {
11193 return this->Equals(other);
11194 }
11195 }
11196
11177 // Fast check: if hash code is computed for both strings 11197 // Fast check: if hash code is computed for both strings
11178 // a fast negative check can be performed. 11198 // a fast negative check can be performed.
11179 if (HasHashCode() && other->HasHashCode()) { 11199 if (HasHashCode() && other->HasHashCode()) {
11180 #ifdef ENABLE_SLOW_DCHECKS 11200 #ifdef ENABLE_SLOW_DCHECKS
11181 if (FLAG_enable_slow_asserts) { 11201 if (FLAG_enable_slow_asserts) {
11182 if (Hash() != other->Hash()) { 11202 if (Hash() != other->Hash()) {
11183 bool found_difference = false; 11203 bool found_difference = false;
11184 for (int i = 0; i < len; i++) { 11204 for (int i = 0; i < len; i++) {
11185 if (Get(i) != other->Get(i)) { 11205 if (Get(i) != other->Get(i)) {
11186 found_difference = true; 11206 found_difference = true;
(...skipping 21 matching lines...) Expand all
11208 return comparator.Equals(this, other); 11228 return comparator.Equals(this, other);
11209 } 11229 }
11210 11230
11211 11231
11212 bool String::SlowEquals(Handle<String> one, Handle<String> two) { 11232 bool String::SlowEquals(Handle<String> one, Handle<String> two) {
11213 // Fast check: negative check with lengths. 11233 // Fast check: negative check with lengths.
11214 int one_length = one->length(); 11234 int one_length = one->length();
11215 if (one_length != two->length()) return false; 11235 if (one_length != two->length()) return false;
11216 if (one_length == 0) return true; 11236 if (one_length == 0) return true;
11217 11237
11238 // Fast check: if at least one ThinString is involved, dereference it/them
11239 // and restart.
11240 if (one->IsThinString() || two->IsThinString()) {
11241 if (one->IsThinString()) one = handle(ThinString::cast(*one)->actual());
11242 if (two->IsThinString()) two = handle(ThinString::cast(*two)->actual());
11243 return String::Equals(one, two);
11244 }
11245
11218 // Fast check: if hash code is computed for both strings 11246 // Fast check: if hash code is computed for both strings
11219 // a fast negative check can be performed. 11247 // a fast negative check can be performed.
11220 if (one->HasHashCode() && two->HasHashCode()) { 11248 if (one->HasHashCode() && two->HasHashCode()) {
11221 #ifdef ENABLE_SLOW_DCHECKS 11249 #ifdef ENABLE_SLOW_DCHECKS
11222 if (FLAG_enable_slow_asserts) { 11250 if (FLAG_enable_slow_asserts) {
11223 if (one->Hash() != two->Hash()) { 11251 if (one->Hash() != two->Hash()) {
11224 bool found_difference = false; 11252 bool found_difference = false;
11225 for (int i = 0; i < one_length; i++) { 11253 for (int i = 0; i < one_length; i++) {
11226 if (one->Get(i) != two->Get(i)) { 11254 if (one->Get(i) != two->Get(i)) {
11227 found_difference = true; 11255 found_difference = true;
(...skipping 5030 matching lines...) Expand 10 before | Expand all | Expand 10 after
16258 Handle<Object> AsHandle(Isolate* isolate) override { 16286 Handle<Object> AsHandle(Isolate* isolate) override {
16259 // Internalize the string if possible. 16287 // Internalize the string if possible.
16260 MaybeHandle<Map> maybe_map = 16288 MaybeHandle<Map> maybe_map =
16261 isolate->factory()->InternalizedStringMapForString(string_); 16289 isolate->factory()->InternalizedStringMapForString(string_);
16262 Handle<Map> map; 16290 Handle<Map> map;
16263 if (maybe_map.ToHandle(&map)) { 16291 if (maybe_map.ToHandle(&map)) {
16264 string_->set_map_no_write_barrier(*map); 16292 string_->set_map_no_write_barrier(*map);
16265 DCHECK(string_->IsInternalizedString()); 16293 DCHECK(string_->IsInternalizedString());
16266 return string_; 16294 return string_;
16267 } 16295 }
16296 // External strings get special treatment, to avoid copying their contents.
16297 if (string_->IsExternalOneByteString()) {
16298 return isolate->factory()
16299 ->InternalizeExternalString<ExternalOneByteString>(string_);
16300 } else if (string_->IsExternalTwoByteString()) {
16301 return isolate->factory()
16302 ->InternalizeExternalString<ExternalTwoByteString>(string_);
16303 }
16268 // Otherwise allocate a new internalized string. 16304 // Otherwise allocate a new internalized string.
16269 return isolate->factory()->NewInternalizedStringImpl( 16305 return isolate->factory()->NewInternalizedStringImpl(
16270 string_, string_->length(), string_->hash_field()); 16306 string_, string_->length(), string_->hash_field());
16271 } 16307 }
16272 16308
16273 static uint32_t StringHash(Object* obj) { 16309 static uint32_t StringHash(Object* obj) {
16274 return String::cast(obj)->Hash(); 16310 return String::cast(obj)->Hash();
16275 } 16311 }
16276 16312
16313 private:
16277 Handle<String> string_; 16314 Handle<String> string_;
16278 }; 16315 };
16279 16316
16280 16317
16281 template<typename Derived, typename Shape, typename Key> 16318 template<typename Derived, typename Shape, typename Key>
16282 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) { 16319 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) {
16283 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v); 16320 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v);
16284 } 16321 }
16285 16322
16286 16323
(...skipping 914 matching lines...) Expand 10 before | Expand all | Expand 10 after
17201 uint32_t hash_; 17238 uint32_t hash_;
17202 }; 17239 };
17203 17240
17204 17241
17205 MaybeHandle<String> StringTable::InternalizeStringIfExists( 17242 MaybeHandle<String> StringTable::InternalizeStringIfExists(
17206 Isolate* isolate, 17243 Isolate* isolate,
17207 Handle<String> string) { 17244 Handle<String> string) {
17208 if (string->IsInternalizedString()) { 17245 if (string->IsInternalizedString()) {
17209 return string; 17246 return string;
17210 } 17247 }
17248 if (string->IsThinString()) {
17249 return handle(Handle<ThinString>::cast(string)->actual(), isolate);
17250 }
17211 return LookupStringIfExists(isolate, string); 17251 return LookupStringIfExists(isolate, string);
17212 } 17252 }
17213 17253
17214 17254
17215 MaybeHandle<String> StringTable::LookupStringIfExists( 17255 MaybeHandle<String> StringTable::LookupStringIfExists(
17216 Isolate* isolate, 17256 Isolate* isolate,
17217 Handle<String> string) { 17257 Handle<String> string) {
17218 Handle<StringTable> string_table = isolate->factory()->string_table(); 17258 Handle<StringTable> string_table = isolate->factory()->string_table();
17219 InternalizedStringKey key(string); 17259 InternalizedStringKey key(string);
17220 int entry = string_table->FindEntry(&key); 17260 int entry = string_table->FindEntry(&key);
(...skipping 26 matching lines...) Expand all
17247 17287
17248 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate, 17288 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
17249 int expected) { 17289 int expected) {
17250 Handle<StringTable> table = isolate->factory()->string_table(); 17290 Handle<StringTable> table = isolate->factory()->string_table();
17251 // We need a key instance for the virtual hash function. 17291 // We need a key instance for the virtual hash function.
17252 InternalizedStringKey dummy_key(isolate->factory()->empty_string()); 17292 InternalizedStringKey dummy_key(isolate->factory()->empty_string());
17253 table = StringTable::EnsureCapacity(table, expected, &dummy_key); 17293 table = StringTable::EnsureCapacity(table, expected, &dummy_key);
17254 isolate->heap()->SetRootStringTable(*table); 17294 isolate->heap()->SetRootStringTable(*table);
17255 } 17295 }
17256 17296
17297 namespace {
17298
17299 template <class StringClass>
17300 void MigrateExternalStringResource(Isolate* isolate, Handle<String> from,
17301 Handle<String> to) {
17302 Handle<StringClass> cast_from = Handle<StringClass>::cast(from);
17303 Handle<StringClass> cast_to = Handle<StringClass>::cast(to);
17304 const typename StringClass::Resource* to_resource = cast_to->resource();
17305 if (to_resource == nullptr) {
17306 // |to| is a just-created internalized copy of |from|. Migrate the resource.
17307 cast_to->set_resource(cast_from->resource());
17308 // Zap |from|'s resource pointer to reflect the fact that |from| has
17309 // relinquished ownership of its resource.
17310 cast_from->set_resource(nullptr);
17311 } else if (to_resource != cast_from->resource()) {
17312 // |to| already existed and has its own resource. Finalize |from|.
17313 isolate->heap()->FinalizeExternalString(*from);
17314 }
17315 }
17316
17317 } // namespace
17257 17318
17258 Handle<String> StringTable::LookupString(Isolate* isolate, 17319 Handle<String> StringTable::LookupString(Isolate* isolate,
17259 Handle<String> string) { 17320 Handle<String> string) {
17321 if (string->IsThinString()) {
17322 DCHECK(Handle<ThinString>::cast(string)->actual()->IsInternalizedString());
17323 return handle(Handle<ThinString>::cast(string)->actual(), isolate);
17324 }
17260 if (string->IsConsString() && string->IsFlat()) { 17325 if (string->IsConsString() && string->IsFlat()) {
17261 string = String::Flatten(string); 17326 string = handle(Handle<ConsString>::cast(string)->first(), isolate);
17262 if (string->IsInternalizedString()) return string; 17327 if (string->IsInternalizedString()) return string;
17263 } 17328 }
17264 17329
17265 InternalizedStringKey key(string); 17330 InternalizedStringKey key(string);
17266 Handle<String> result = LookupKey(isolate, &key); 17331 Handle<String> result = LookupKey(isolate, &key);
17267 17332
17268 if (string->IsConsString()) { 17333 if (string->IsExternalString()) {
17269 Handle<ConsString> cons = Handle<ConsString>::cast(string); 17334 if (result->IsExternalOneByteString()) {
17270 cons->set_first(*result); 17335 MigrateExternalStringResource<ExternalOneByteString>(isolate, string,
17271 cons->set_second(isolate->heap()->empty_string()); 17336 result);
17272 } else if (string->IsSlicedString()) { 17337 } else if (result->IsExternalTwoByteString()) {
17273 STATIC_ASSERT(ConsString::kSize == SlicedString::kSize); 17338 MigrateExternalStringResource<ExternalTwoByteString>(isolate, string,
17339 result);
17340 } else {
17341 // If the external string is duped into an existing non-external
17342 // internalized string, free its resource (it's about to be rewritten
17343 // into a ThinString below).
17344 isolate->heap()->FinalizeExternalString(*string);
17345 }
17346 }
17347
17348 // The LookupKey() call above tries to internalize the string in-place.
17349 // In cases where that wasn't possible (e.g. new-space strings), turn them
17350 // into ThinStrings referring to their internalized versions now.
17351 if (!string->IsInternalizedString()) {
17274 DisallowHeapAllocation no_gc; 17352 DisallowHeapAllocation no_gc;
17275 bool one_byte = result->IsOneByteRepresentation(); 17353 bool one_byte = result->IsOneByteRepresentation();
17276 Handle<Map> map = one_byte ? isolate->factory()->cons_one_byte_string_map() 17354 Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map()
17277 : isolate->factory()->cons_string_map(); 17355 : isolate->factory()->thin_string_map();
17278 string->set_map(*map); 17356 int old_size = string->Size();
17279 Handle<ConsString> cons = Handle<ConsString>::cast(string); 17357 DCHECK(old_size >= ThinString::kSize);
17280 cons->set_first(*result); 17358 string->synchronized_set_map(*map);
17281 cons->set_second(isolate->heap()->empty_string()); 17359 Handle<ThinString> thin = Handle<ThinString>::cast(string);
17360 thin->set_actual(*result);
17361 Address thin_end = thin->address() + ThinString::kSize;
17362 int size_delta = old_size - ThinString::kSize;
17363 if (size_delta != 0) {
17364 Heap* heap = isolate->heap();
17365 heap->CreateFillerObjectAt(thin_end, size_delta, ClearRecordedSlots::kNo);
17366 heap->AdjustLiveBytes(*thin, -size_delta);
17367 }
17282 } 17368 }
17283 return result; 17369 return result;
17284 } 17370 }
17285 17371
17286 17372
17287 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) { 17373 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
17288 Handle<StringTable> table = isolate->factory()->string_table(); 17374 Handle<StringTable> table = isolate->factory()->string_table();
17289 int entry = table->FindEntry(key); 17375 int entry = table->FindEntry(key);
17290 17376
17291 // String already in table. 17377 // String already in table.
(...skipping 2624 matching lines...) Expand 10 before | Expand all | Expand 10 after
19916 // depend on this. 20002 // depend on this.
19917 return DICTIONARY_ELEMENTS; 20003 return DICTIONARY_ELEMENTS;
19918 } 20004 }
19919 DCHECK_LE(kind, LAST_ELEMENTS_KIND); 20005 DCHECK_LE(kind, LAST_ELEMENTS_KIND);
19920 return kind; 20006 return kind;
19921 } 20007 }
19922 } 20008 }
19923 20009
19924 } // namespace internal 20010 } // namespace internal
19925 } // namespace v8 20011 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698