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

Side by Side Diff: src/objects.cc

Issue 2549773002: Internalize strings in-place (Closed)
Patch Set: rebased 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
« no previous file with comments | « src/objects.h ('k') | src/objects-body-descriptors-inl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 7741 matching lines...) Expand 10 before | Expand all | Expand 10 after
10363 while ( 10363 while (
10364 right > left && 10364 right > left &&
10365 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) { 10365 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(right - 1))) {
10366 right--; 10366 right--;
10367 } 10367 }
10368 } 10368 }
10369 10369
10370 return isolate->factory()->NewSubString(string, left, right); 10370 return isolate->factory()->NewSubString(string, left, right);
10371 } 10371 }
10372 10372
10373 bool String::LooksValid() { 10373 bool String::LooksValid() { return GetIsolate()->heap()->Contains(this); }
10374 if (!GetIsolate()->heap()->Contains(this)) return false;
10375 return true;
10376 }
10377 10374
10378 // static 10375 // static
10379 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) { 10376 MaybeHandle<String> Name::ToFunctionName(Handle<Name> name) {
10380 if (name->IsString()) return Handle<String>::cast(name); 10377 if (name->IsString()) return Handle<String>::cast(name);
10381 // ES6 section 9.2.11 SetFunctionName, step 4. 10378 // ES6 section 9.2.11 SetFunctionName, step 4.
10382 Isolate* const isolate = name->GetIsolate(); 10379 Isolate* const isolate = name->GetIsolate();
10383 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate); 10380 Handle<Object> description(Handle<Symbol>::cast(name)->name(), isolate);
10384 if (description->IsUndefined(isolate)) { 10381 if (description->IsUndefined(isolate)) {
10385 return isolate->factory()->empty_string(); 10382 return isolate->factory()->empty_string();
10386 } 10383 }
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
10500 StringShape shape(this); 10497 StringShape shape(this);
10501 String* string = this; 10498 String* string = this;
10502 int offset = 0; 10499 int offset = 0;
10503 if (shape.representation_tag() == kConsStringTag) { 10500 if (shape.representation_tag() == kConsStringTag) {
10504 ConsString* cons = ConsString::cast(string); 10501 ConsString* cons = ConsString::cast(string);
10505 if (cons->second()->length() != 0) { 10502 if (cons->second()->length() != 0) {
10506 return FlatContent(); 10503 return FlatContent();
10507 } 10504 }
10508 string = cons->first(); 10505 string = cons->first();
10509 shape = StringShape(string); 10506 shape = StringShape(string);
10510 } 10507 } else if (shape.representation_tag() == kSlicedStringTag) {
10511 if (shape.representation_tag() == kSlicedStringTag) {
10512 SlicedString* slice = SlicedString::cast(string); 10508 SlicedString* slice = SlicedString::cast(string);
10513 offset = slice->offset(); 10509 offset = slice->offset();
10514 string = slice->parent(); 10510 string = slice->parent();
10515 shape = StringShape(string); 10511 shape = StringShape(string);
10516 DCHECK(shape.representation_tag() != kConsStringTag && 10512 DCHECK(shape.representation_tag() != kConsStringTag &&
10517 shape.representation_tag() != kSlicedStringTag); 10513 shape.representation_tag() != kSlicedStringTag);
10518 } 10514 }
10515 if (shape.representation_tag() == kThinStringTag) {
10516 ThinString* thin = ThinString::cast(string);
10517 string = thin->actual();
10518 shape = StringShape(string);
10519 DCHECK(!shape.IsCons());
10520 DCHECK(!shape.IsSliced());
10521 }
10519 if (shape.encoding_tag() == kOneByteStringTag) { 10522 if (shape.encoding_tag() == kOneByteStringTag) {
10520 const uint8_t* start; 10523 const uint8_t* start;
10521 if (shape.representation_tag() == kSeqStringTag) { 10524 if (shape.representation_tag() == kSeqStringTag) {
10522 start = SeqOneByteString::cast(string)->GetChars(); 10525 start = SeqOneByteString::cast(string)->GetChars();
10523 } else { 10526 } else {
10524 start = ExternalOneByteString::cast(string)->GetChars(); 10527 start = ExternalOneByteString::cast(string)->GetChars();
10525 } 10528 }
10526 return FlatContent(start + offset, length); 10529 return FlatContent(start + offset, length);
10527 } else { 10530 } else {
10528 DCHECK(shape.encoding_tag() == kTwoByteStringTag); 10531 DCHECK(shape.encoding_tag() == kTwoByteStringTag);
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
10594 case kSeqStringTag: 10597 case kSeqStringTag:
10595 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start); 10598 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
10596 case kExternalStringTag: 10599 case kExternalStringTag:
10597 return ExternalTwoByteString::cast(this)-> 10600 return ExternalTwoByteString::cast(this)->
10598 ExternalTwoByteStringGetData(start); 10601 ExternalTwoByteStringGetData(start);
10599 case kSlicedStringTag: { 10602 case kSlicedStringTag: {
10600 SlicedString* slice = SlicedString::cast(this); 10603 SlicedString* slice = SlicedString::cast(this);
10601 return slice->parent()->GetTwoByteData(start + slice->offset()); 10604 return slice->parent()->GetTwoByteData(start + slice->offset());
10602 } 10605 }
10603 case kConsStringTag: 10606 case kConsStringTag:
10607 case kThinStringTag:
10604 UNREACHABLE(); 10608 UNREACHABLE();
10605 return NULL; 10609 return NULL;
10606 } 10610 }
10607 UNREACHABLE(); 10611 UNREACHABLE();
10608 return NULL; 10612 return NULL;
10609 } 10613 }
10610 10614
10611 10615
10612 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) { 10616 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
10613 return reinterpret_cast<uc16*>( 10617 return reinterpret_cast<uc16*>(
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after
10860 } 10864 }
10861 } else { 10865 } else {
10862 return string->Get(index); 10866 return string->Get(index);
10863 } 10867 }
10864 } 10868 }
10865 10869
10866 UNREACHABLE(); 10870 UNREACHABLE();
10867 return 0; 10871 return 0;
10868 } 10872 }
10869 10873
10874 uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); }
10870 10875
10871 uint16_t SlicedString::SlicedStringGet(int index) { 10876 uint16_t SlicedString::SlicedStringGet(int index) {
10872 return parent()->Get(offset() + index); 10877 return parent()->Get(offset() + index);
10873 } 10878 }
10874 10879
10875 10880
10876 template <typename sinkchar> 10881 template <typename sinkchar>
10877 void String::WriteToFlat(String* src, 10882 void String::WriteToFlat(String* src,
10878 sinkchar* sink, 10883 sinkchar* sink,
10879 int f, 10884 int f,
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
10954 } 10959 }
10955 break; 10960 break;
10956 } 10961 }
10957 case kOneByteStringTag | kSlicedStringTag: 10962 case kOneByteStringTag | kSlicedStringTag:
10958 case kTwoByteStringTag | kSlicedStringTag: { 10963 case kTwoByteStringTag | kSlicedStringTag: {
10959 SlicedString* slice = SlicedString::cast(source); 10964 SlicedString* slice = SlicedString::cast(source);
10960 unsigned offset = slice->offset(); 10965 unsigned offset = slice->offset();
10961 WriteToFlat(slice->parent(), sink, from + offset, to + offset); 10966 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
10962 return; 10967 return;
10963 } 10968 }
10969 case kOneByteStringTag | kThinStringTag:
10970 case kTwoByteStringTag | kThinStringTag:
10971 source = ThinString::cast(source)->actual();
10972 break;
10964 } 10973 }
10965 } 10974 }
10966 } 10975 }
10967 10976
10968 10977
10969 10978
10970 template <typename SourceChar> 10979 template <typename SourceChar>
10971 static void CalculateLineEndsImpl(Isolate* isolate, 10980 static void CalculateLineEndsImpl(Isolate* isolate,
10972 List<int>* line_ends, 10981 List<int>* line_ends,
10973 Vector<const SourceChar> src, 10982 Vector<const SourceChar> src,
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after
11175 }; 11184 };
11176 11185
11177 11186
11178 bool String::SlowEquals(String* other) { 11187 bool String::SlowEquals(String* other) {
11179 DisallowHeapAllocation no_gc; 11188 DisallowHeapAllocation no_gc;
11180 // Fast check: negative check with lengths. 11189 // Fast check: negative check with lengths.
11181 int len = length(); 11190 int len = length();
11182 if (len != other->length()) return false; 11191 if (len != other->length()) return false;
11183 if (len == 0) return true; 11192 if (len == 0) return true;
11184 11193
11194 // Fast check: if at least one ThinString is involved, dereference it/them
11195 // and restart.
11196 if (this->IsThinString() || other->IsThinString()) {
11197 if (other->IsThinString()) other = ThinString::cast(other)->actual();
11198 if (this->IsThinString()) {
11199 return ThinString::cast(this)->actual()->Equals(other);
11200 } else {
11201 return this->Equals(other);
11202 }
11203 }
11204
11185 // Fast check: if hash code is computed for both strings 11205 // Fast check: if hash code is computed for both strings
11186 // a fast negative check can be performed. 11206 // a fast negative check can be performed.
11187 if (HasHashCode() && other->HasHashCode()) { 11207 if (HasHashCode() && other->HasHashCode()) {
11188 #ifdef ENABLE_SLOW_DCHECKS 11208 #ifdef ENABLE_SLOW_DCHECKS
11189 if (FLAG_enable_slow_asserts) { 11209 if (FLAG_enable_slow_asserts) {
11190 if (Hash() != other->Hash()) { 11210 if (Hash() != other->Hash()) {
11191 bool found_difference = false; 11211 bool found_difference = false;
11192 for (int i = 0; i < len; i++) { 11212 for (int i = 0; i < len; i++) {
11193 if (Get(i) != other->Get(i)) { 11213 if (Get(i) != other->Get(i)) {
11194 found_difference = true; 11214 found_difference = true;
(...skipping 21 matching lines...) Expand all
11216 return comparator.Equals(this, other); 11236 return comparator.Equals(this, other);
11217 } 11237 }
11218 11238
11219 11239
11220 bool String::SlowEquals(Handle<String> one, Handle<String> two) { 11240 bool String::SlowEquals(Handle<String> one, Handle<String> two) {
11221 // Fast check: negative check with lengths. 11241 // Fast check: negative check with lengths.
11222 int one_length = one->length(); 11242 int one_length = one->length();
11223 if (one_length != two->length()) return false; 11243 if (one_length != two->length()) return false;
11224 if (one_length == 0) return true; 11244 if (one_length == 0) return true;
11225 11245
11246 // Fast check: if at least one ThinString is involved, dereference it/them
11247 // and restart.
11248 if (one->IsThinString() || two->IsThinString()) {
11249 if (one->IsThinString()) one = handle(ThinString::cast(*one)->actual());
11250 if (two->IsThinString()) two = handle(ThinString::cast(*two)->actual());
11251 return String::Equals(one, two);
11252 }
11253
11226 // Fast check: if hash code is computed for both strings 11254 // Fast check: if hash code is computed for both strings
11227 // a fast negative check can be performed. 11255 // a fast negative check can be performed.
11228 if (one->HasHashCode() && two->HasHashCode()) { 11256 if (one->HasHashCode() && two->HasHashCode()) {
11229 #ifdef ENABLE_SLOW_DCHECKS 11257 #ifdef ENABLE_SLOW_DCHECKS
11230 if (FLAG_enable_slow_asserts) { 11258 if (FLAG_enable_slow_asserts) {
11231 if (one->Hash() != two->Hash()) { 11259 if (one->Hash() != two->Hash()) {
11232 bool found_difference = false; 11260 bool found_difference = false;
11233 for (int i = 0; i < one_length; i++) { 11261 for (int i = 0; i < one_length; i++) {
11234 if (one->Get(i) != two->Get(i)) { 11262 if (one->Get(i) != two->Get(i)) {
11235 found_difference = true; 11263 found_difference = true;
(...skipping 5030 matching lines...) Expand 10 before | Expand all | Expand 10 after
16266 Handle<Object> AsHandle(Isolate* isolate) override { 16294 Handle<Object> AsHandle(Isolate* isolate) override {
16267 // Internalize the string if possible. 16295 // Internalize the string if possible.
16268 MaybeHandle<Map> maybe_map = 16296 MaybeHandle<Map> maybe_map =
16269 isolate->factory()->InternalizedStringMapForString(string_); 16297 isolate->factory()->InternalizedStringMapForString(string_);
16270 Handle<Map> map; 16298 Handle<Map> map;
16271 if (maybe_map.ToHandle(&map)) { 16299 if (maybe_map.ToHandle(&map)) {
16272 string_->set_map_no_write_barrier(*map); 16300 string_->set_map_no_write_barrier(*map);
16273 DCHECK(string_->IsInternalizedString()); 16301 DCHECK(string_->IsInternalizedString());
16274 return string_; 16302 return string_;
16275 } 16303 }
16304 // External strings get special treatment, to avoid copying their contents.
16305 if (string_->IsExternalOneByteString()) {
16306 return isolate->factory()
16307 ->InternalizeExternalString<ExternalOneByteString>(string_);
16308 } else if (string_->IsExternalTwoByteString()) {
16309 return isolate->factory()
16310 ->InternalizeExternalString<ExternalTwoByteString>(string_);
16311 }
16276 // Otherwise allocate a new internalized string. 16312 // Otherwise allocate a new internalized string.
16277 return isolate->factory()->NewInternalizedStringImpl( 16313 return isolate->factory()->NewInternalizedStringImpl(
16278 string_, string_->length(), string_->hash_field()); 16314 string_, string_->length(), string_->hash_field());
16279 } 16315 }
16280 16316
16281 static uint32_t StringHash(Object* obj) { 16317 static uint32_t StringHash(Object* obj) {
16282 return String::cast(obj)->Hash(); 16318 return String::cast(obj)->Hash();
16283 } 16319 }
16284 16320
16321 private:
16285 Handle<String> string_; 16322 Handle<String> string_;
16286 }; 16323 };
16287 16324
16288 16325
16289 template<typename Derived, typename Shape, typename Key> 16326 template<typename Derived, typename Shape, typename Key>
16290 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) { 16327 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) {
16291 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v); 16328 BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v);
16292 } 16329 }
16293 16330
16294 16331
(...skipping 914 matching lines...) Expand 10 before | Expand all | Expand 10 after
17209 uint32_t hash_; 17246 uint32_t hash_;
17210 }; 17247 };
17211 17248
17212 17249
17213 MaybeHandle<String> StringTable::InternalizeStringIfExists( 17250 MaybeHandle<String> StringTable::InternalizeStringIfExists(
17214 Isolate* isolate, 17251 Isolate* isolate,
17215 Handle<String> string) { 17252 Handle<String> string) {
17216 if (string->IsInternalizedString()) { 17253 if (string->IsInternalizedString()) {
17217 return string; 17254 return string;
17218 } 17255 }
17256 if (string->IsThinString()) {
17257 return handle(Handle<ThinString>::cast(string)->actual(), isolate);
17258 }
17219 return LookupStringIfExists(isolate, string); 17259 return LookupStringIfExists(isolate, string);
17220 } 17260 }
17221 17261
17222 17262
17223 MaybeHandle<String> StringTable::LookupStringIfExists( 17263 MaybeHandle<String> StringTable::LookupStringIfExists(
17224 Isolate* isolate, 17264 Isolate* isolate,
17225 Handle<String> string) { 17265 Handle<String> string) {
17226 Handle<StringTable> string_table = isolate->factory()->string_table(); 17266 Handle<StringTable> string_table = isolate->factory()->string_table();
17227 InternalizedStringKey key(string); 17267 InternalizedStringKey key(string);
17228 int entry = string_table->FindEntry(&key); 17268 int entry = string_table->FindEntry(&key);
(...skipping 26 matching lines...) Expand all
17255 17295
17256 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate, 17296 void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
17257 int expected) { 17297 int expected) {
17258 Handle<StringTable> table = isolate->factory()->string_table(); 17298 Handle<StringTable> table = isolate->factory()->string_table();
17259 // We need a key instance for the virtual hash function. 17299 // We need a key instance for the virtual hash function.
17260 InternalizedStringKey dummy_key(isolate->factory()->empty_string()); 17300 InternalizedStringKey dummy_key(isolate->factory()->empty_string());
17261 table = StringTable::EnsureCapacity(table, expected, &dummy_key); 17301 table = StringTable::EnsureCapacity(table, expected, &dummy_key);
17262 isolate->heap()->SetRootStringTable(*table); 17302 isolate->heap()->SetRootStringTable(*table);
17263 } 17303 }
17264 17304
17305 namespace {
17306
17307 template <class StringClass>
17308 void MigrateExternalStringResource(Isolate* isolate, Handle<String> from,
17309 Handle<String> to) {
17310 Handle<StringClass> cast_from = Handle<StringClass>::cast(from);
17311 Handle<StringClass> cast_to = Handle<StringClass>::cast(to);
17312 const typename StringClass::Resource* to_resource = cast_to->resource();
17313 if (to_resource == nullptr) {
17314 // |to| is a just-created internalized copy of |from|. Migrate the resource.
17315 cast_to->set_resource(cast_from->resource());
17316 // Zap |from|'s resource pointer to reflect the fact that |from| has
17317 // relinquished ownership of its resource.
17318 cast_from->set_resource(nullptr);
17319 } else if (to_resource != cast_from->resource()) {
17320 // |to| already existed and has its own resource. Finalize |from|.
17321 isolate->heap()->FinalizeExternalString(*from);
17322 }
17323 }
17324
17325 } // namespace
17265 17326
17266 Handle<String> StringTable::LookupString(Isolate* isolate, 17327 Handle<String> StringTable::LookupString(Isolate* isolate,
17267 Handle<String> string) { 17328 Handle<String> string) {
17329 if (string->IsThinString()) {
17330 DCHECK(Handle<ThinString>::cast(string)->actual()->IsInternalizedString());
17331 return handle(Handle<ThinString>::cast(string)->actual(), isolate);
17332 }
17268 if (string->IsConsString() && string->IsFlat()) { 17333 if (string->IsConsString() && string->IsFlat()) {
17269 string = String::Flatten(string); 17334 string = handle(Handle<ConsString>::cast(string)->first(), isolate);
17270 if (string->IsInternalizedString()) return string; 17335 if (string->IsInternalizedString()) return string;
17271 } 17336 }
17272 17337
17273 InternalizedStringKey key(string); 17338 InternalizedStringKey key(string);
17274 Handle<String> result = LookupKey(isolate, &key); 17339 Handle<String> result = LookupKey(isolate, &key);
17275 17340
17276 if (string->IsConsString()) { 17341 if (string->IsExternalString()) {
17277 Handle<ConsString> cons = Handle<ConsString>::cast(string); 17342 if (result->IsExternalOneByteString()) {
17278 cons->set_first(*result); 17343 MigrateExternalStringResource<ExternalOneByteString>(isolate, string,
17279 cons->set_second(isolate->heap()->empty_string()); 17344 result);
17280 } else if (string->IsSlicedString()) { 17345 } else if (result->IsExternalTwoByteString()) {
17281 STATIC_ASSERT(ConsString::kSize == SlicedString::kSize); 17346 MigrateExternalStringResource<ExternalTwoByteString>(isolate, string,
17347 result);
17348 } else {
17349 // If the external string is duped into an existing non-external
17350 // internalized string, free its resource (it's about to be rewritten
17351 // into a ThinString below).
17352 isolate->heap()->FinalizeExternalString(*string);
17353 }
17354 }
17355
17356 // The LookupKey() call above tries to internalize the string in-place.
17357 // In cases where that wasn't possible (e.g. new-space strings), turn them
17358 // into ThinStrings referring to their internalized versions now.
17359 if (!string->IsInternalizedString()) {
17282 DisallowHeapAllocation no_gc; 17360 DisallowHeapAllocation no_gc;
17283 bool one_byte = result->IsOneByteRepresentation(); 17361 bool one_byte = result->IsOneByteRepresentation();
17284 Handle<Map> map = one_byte ? isolate->factory()->cons_one_byte_string_map() 17362 Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map()
17285 : isolate->factory()->cons_string_map(); 17363 : isolate->factory()->thin_string_map();
17286 string->set_map(*map); 17364 int old_size = string->Size();
17287 Handle<ConsString> cons = Handle<ConsString>::cast(string); 17365 DCHECK(old_size >= ThinString::kSize);
17288 cons->set_first(*result); 17366 string->synchronized_set_map(*map);
17289 cons->set_second(isolate->heap()->empty_string()); 17367 Handle<ThinString> thin = Handle<ThinString>::cast(string);
17368 thin->set_actual(*result);
17369 Address thin_end = thin->address() + ThinString::kSize;
17370 int size_delta = old_size - ThinString::kSize;
17371 if (size_delta != 0) {
17372 Heap* heap = isolate->heap();
17373 heap->CreateFillerObjectAt(thin_end, size_delta, ClearRecordedSlots::kNo);
17374 heap->AdjustLiveBytes(*thin, -size_delta);
17375 }
17290 } 17376 }
17291 return result; 17377 return result;
17292 } 17378 }
17293 17379
17294 17380
17295 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) { 17381 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
17296 Handle<StringTable> table = isolate->factory()->string_table(); 17382 Handle<StringTable> table = isolate->factory()->string_table();
17297 int entry = table->FindEntry(key); 17383 int entry = table->FindEntry(key);
17298 17384
17299 // String already in table. 17385 // String already in table.
(...skipping 2624 matching lines...) Expand 10 before | Expand all | Expand 10 after
19924 // depend on this. 20010 // depend on this.
19925 return DICTIONARY_ELEMENTS; 20011 return DICTIONARY_ELEMENTS;
19926 } 20012 }
19927 DCHECK_LE(kind, LAST_ELEMENTS_KIND); 20013 DCHECK_LE(kind, LAST_ELEMENTS_KIND);
19928 return kind; 20014 return kind;
19929 } 20015 }
19930 } 20016 }
19931 20017
19932 } // namespace internal 20018 } // namespace internal
19933 } // namespace v8 20019 } // namespace v8
OLDNEW
« no previous file with comments | « src/objects.h ('k') | src/objects-body-descriptors-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698