summaryrefslogtreecommitdiff
path: root/deps/v8/src/objects/string.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/objects/string.cc')
-rw-r--r--deps/v8/src/objects/string.cc349
1 files changed, 224 insertions, 125 deletions
diff --git a/deps/v8/src/objects/string.cc b/deps/v8/src/objects/string.cc
index 22157a3500..cc513f88cb 100644
--- a/deps/v8/src/objects/string.cc
+++ b/deps/v8/src/objects/string.cc
@@ -4,34 +4,35 @@
#include "src/objects/string.h"
-#include "src/char-predicates.h"
-#include "src/conversions.h"
-#include "src/handles-inl.h"
+#include "src/handles/handles-inl.h"
#include "src/heap/heap-inl.h" // For LooksValid implementation.
+#include "src/heap/read-only-heap.h"
+#include "src/numbers/conversions.h"
#include "src/objects/map.h"
#include "src/objects/oddball.h"
#include "src/objects/string-comparator.h"
#include "src/objects/string-inl.h"
-#include "src/ostreams.h"
-#include "src/string-builder-inl.h"
-#include "src/string-hasher.h"
-#include "src/string-search.h"
-#include "src/string-stream.h"
-#include "src/unicode-inl.h"
+#include "src/strings/char-predicates.h"
+#include "src/strings/string-builder-inl.h"
+#include "src/strings/string-hasher.h"
+#include "src/strings/string-search.h"
+#include "src/strings/string-stream.h"
+#include "src/strings/unicode-inl.h"
+#include "src/utils/ostreams.h"
namespace v8 {
namespace internal {
Handle<String> String::SlowFlatten(Isolate* isolate, Handle<ConsString> cons,
AllocationType allocation) {
- DCHECK_NE(cons->second()->length(), 0);
+ DCHECK_NE(cons->second().length(), 0);
// TurboFan can create cons strings with empty first parts.
- while (cons->first()->length() == 0) {
+ while (cons->first().length() == 0) {
// We do not want to call this function recursively. Therefore we call
// String::Flatten only in those cases where String::SlowFlatten is not
// called again.
- if (cons->second()->IsConsString() && !cons->second()->IsFlat()) {
+ if (cons->second().IsConsString() && !cons->second().IsFlat()) {
cons = handle(ConsString::cast(cons->second()), isolate);
} else {
return String::Flatten(isolate, handle(cons->second(), isolate));
@@ -66,6 +67,66 @@ Handle<String> String::SlowFlatten(Isolate* isolate, Handle<ConsString> cons,
return result;
}
+namespace {
+
+template <class StringClass>
+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.
+ cast_to.SetResource(isolate, cast_from.resource());
+ // Zap |from|'s resource pointer to reflect the fact that |from| has
+ // relinquished ownership of its resource.
+ isolate->heap()->UpdateExternalString(
+ from, ExternalString::cast(from).ExternalPayloadSize(), 0);
+ cast_from.SetResource(isolate, nullptr);
+ } else if (to_resource != cast_from.resource()) {
+ // |to| already existed and has its own resource. Finalize |from|.
+ isolate->heap()->FinalizeExternalString(from);
+ }
+}
+
+} // namespace
+
+void String::MakeThin(Isolate* isolate, String internalized) {
+ DisallowHeapAllocation no_gc;
+ DCHECK_NE(*this, internalized);
+ DCHECK(internalized.IsInternalizedString());
+
+ if (this->IsExternalString()) {
+ if (internalized.IsExternalOneByteString()) {
+ MigrateExternalStringResource<ExternalOneByteString>(isolate, *this,
+ internalized);
+ } else if (internalized.IsExternalTwoByteString()) {
+ MigrateExternalStringResource<ExternalTwoByteString>(isolate, *this,
+ 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(*this);
+ }
+ }
+
+ int old_size = this->Size();
+ isolate->heap()->NotifyObjectLayoutChange(*this, old_size, no_gc);
+ bool one_byte = internalized.IsOneByteRepresentation();
+ Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map()
+ : isolate->factory()->thin_string_map();
+ DCHECK_GE(old_size, ThinString::kSize);
+ this->synchronized_set_map(*map);
+ ThinString thin = ThinString::cast(*this);
+ 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);
+ }
+}
+
bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
DisallowHeapAllocation no_allocation;
// Externalizing twice leaks the external resource, so it's
@@ -77,8 +138,8 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
// Assert that the resource and the string are equivalent.
DCHECK(static_cast<size_t>(this->length()) == resource->length());
ScopedVector<uc16> smart_chars(this->length());
- String::WriteToFlat(*this, smart_chars.start(), 0, this->length());
- DCHECK_EQ(0, memcmp(smart_chars.start(), resource->data(),
+ String::WriteToFlat(*this, smart_chars.begin(), 0, this->length());
+ DCHECK_EQ(0, memcmp(smart_chars.begin(), resource->data(),
resource->length() * sizeof(smart_chars[0])));
}
#endif // DEBUG
@@ -103,7 +164,7 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
// strings in generated code, we need to bailout to runtime.
Map new_map;
ReadOnlyRoots roots(heap);
- if (size < ExternalString::kSize) {
+ if (size < ExternalString::kSizeOfAllExternalStrings) {
if (is_internalized) {
new_map = roots.uncached_external_internalized_string_map();
} else {
@@ -127,9 +188,9 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
this->synchronized_set_map(new_map);
ExternalTwoByteString self = ExternalTwoByteString::cast(*this);
- self->SetResource(isolate, resource);
+ self.SetResource(isolate, resource);
heap->RegisterExternalString(*this);
- if (is_internalized) self->Hash(); // Force regeneration of the hash value.
+ if (is_internalized) self.Hash(); // Force regeneration of the hash value.
return true;
}
@@ -145,12 +206,12 @@ bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
DCHECK(static_cast<size_t>(this->length()) == resource->length());
if (this->IsTwoByteRepresentation()) {
ScopedVector<uint16_t> smart_chars(this->length());
- String::WriteToFlat(*this, smart_chars.start(), 0, this->length());
- DCHECK(String::IsOneByte(smart_chars.start(), this->length()));
+ String::WriteToFlat(*this, smart_chars.begin(), 0, this->length());
+ DCHECK(String::IsOneByte(smart_chars.begin(), this->length()));
}
ScopedVector<char> smart_chars(this->length());
- String::WriteToFlat(*this, smart_chars.start(), 0, this->length());
- DCHECK_EQ(0, memcmp(smart_chars.start(), resource->data(),
+ String::WriteToFlat(*this, smart_chars.begin(), 0, this->length());
+ DCHECK_EQ(0, memcmp(smart_chars.begin(), resource->data(),
resource->length() * sizeof(smart_chars[0])));
}
#endif // DEBUG
@@ -177,7 +238,7 @@ bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
// strings in generated code, we need to bailout to runtime.
Map new_map;
ReadOnlyRoots roots(heap);
- if (size < ExternalString::kSize) {
+ if (size < ExternalString::kSizeOfAllExternalStrings) {
new_map = is_internalized
? roots.uncached_external_one_byte_internalized_string_map()
: roots.uncached_external_one_byte_string_map();
@@ -200,15 +261,15 @@ bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
this->synchronized_set_map(new_map);
ExternalOneByteString self = ExternalOneByteString::cast(*this);
- self->SetResource(isolate, resource);
+ self.SetResource(isolate, resource);
heap->RegisterExternalString(*this);
- if (is_internalized) self->Hash(); // Force regeneration of the hash value.
+ if (is_internalized) self.Hash(); // Force regeneration of the hash value.
return true;
}
bool String::SupportsExternalization() {
if (this->IsThinString()) {
- return i::ThinString::cast(*this)->actual()->SupportsExternalization();
+ return i::ThinString::cast(*this).actual().SupportsExternalization();
}
Isolate* isolate;
@@ -295,7 +356,6 @@ void String::StringShortPrint(StringStream* accumulator, bool show_details) {
}
if (show_details) accumulator->Put('>');
}
- return;
}
void String::PrintUC16(std::ostream& os, int start, int end) { // NOLINT
@@ -337,7 +397,7 @@ bool String::LooksValid() {
// basically the same logic as the way we access the heap in the first place.
MemoryChunk* chunk = MemoryChunk::FromHeapObject(*this);
// RO_SPACE objects should always be valid.
- if (chunk->owner()->identity() == RO_SPACE) return true;
+ if (ReadOnlyHeap::Contains(*this)) return true;
if (chunk->heap() == nullptr) return false;
return chunk->heap()->Contains(*this);
}
@@ -435,22 +495,22 @@ String::FlatContent String::GetFlatContent(
int offset = 0;
if (shape.representation_tag() == kConsStringTag) {
ConsString cons = ConsString::cast(string);
- if (cons->second()->length() != 0) {
+ if (cons.second().length() != 0) {
return FlatContent();
}
- string = cons->first();
+ string = cons.first();
shape = StringShape(string);
} else if (shape.representation_tag() == kSlicedStringTag) {
SlicedString slice = SlicedString::cast(string);
- offset = slice->offset();
- string = slice->parent();
+ offset = slice.offset();
+ string = slice.parent();
shape = StringShape(string);
DCHECK(shape.representation_tag() != kConsStringTag &&
shape.representation_tag() != kSlicedStringTag);
}
if (shape.representation_tag() == kThinStringTag) {
ThinString thin = ThinString::cast(string);
- string = thin->actual();
+ string = thin.actual();
shape = StringShape(string);
DCHECK(!shape.IsCons());
DCHECK(!shape.IsSliced());
@@ -458,18 +518,18 @@ String::FlatContent String::GetFlatContent(
if (shape.encoding_tag() == kOneByteStringTag) {
const uint8_t* start;
if (shape.representation_tag() == kSeqStringTag) {
- start = SeqOneByteString::cast(string)->GetChars(no_gc);
+ start = SeqOneByteString::cast(string).GetChars(no_gc);
} else {
- start = ExternalOneByteString::cast(string)->GetChars();
+ start = ExternalOneByteString::cast(string).GetChars();
}
return FlatContent(start + offset, length);
} else {
DCHECK_EQ(shape.encoding_tag(), kTwoByteStringTag);
const uc16* start;
if (shape.representation_tag() == kSeqStringTag) {
- start = SeqTwoByteString::cast(string)->GetChars(no_gc);
+ start = SeqTwoByteString::cast(string).GetChars(no_gc);
} else {
- start = ExternalTwoByteString::cast(string)->GetChars();
+ start = ExternalTwoByteString::cast(string).GetChars();
}
return FlatContent(start + offset, length);
}
@@ -533,38 +593,40 @@ void String::WriteToFlat(String src, sinkchar* sink, int f, int t) {
int from = f;
int to = t;
while (true) {
- DCHECK(0 <= from && from <= to && to <= source->length());
+ DCHECK_LE(0, from);
+ DCHECK_LE(from, to);
+ DCHECK_LE(to, source.length());
switch (StringShape(source).full_representation_tag()) {
case kOneByteStringTag | kExternalStringTag: {
- CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from,
+ CopyChars(sink, ExternalOneByteString::cast(source).GetChars() + from,
to - from);
return;
}
case kTwoByteStringTag | kExternalStringTag: {
- const uc16* data = ExternalTwoByteString::cast(source)->GetChars();
+ const uc16* data = ExternalTwoByteString::cast(source).GetChars();
CopyChars(sink, data + from, to - from);
return;
}
case kOneByteStringTag | kSeqStringTag: {
- CopyChars(sink, SeqOneByteString::cast(source)->GetChars(no_gc) + from,
+ CopyChars(sink, SeqOneByteString::cast(source).GetChars(no_gc) + from,
to - from);
return;
}
case kTwoByteStringTag | kSeqStringTag: {
- CopyChars(sink, SeqTwoByteString::cast(source)->GetChars(no_gc) + from,
+ CopyChars(sink, SeqTwoByteString::cast(source).GetChars(no_gc) + from,
to - from);
return;
}
case kOneByteStringTag | kConsStringTag:
case kTwoByteStringTag | kConsStringTag: {
ConsString cons_string = ConsString::cast(source);
- String first = cons_string->first();
- int boundary = first->length();
+ String first = cons_string.first();
+ int boundary = first.length();
if (to - boundary >= boundary - from) {
// Right hand side is longer. Recurse over left.
if (from < boundary) {
WriteToFlat(first, sink, from, boundary);
- if (from == 0 && cons_string->second() == first) {
+ if (from == 0 && cons_string.second() == first) {
CopyChars(sink + boundary, sink, boundary);
return;
}
@@ -574,19 +636,19 @@ void String::WriteToFlat(String src, sinkchar* sink, int f, int t) {
from -= boundary;
}
to -= boundary;
- source = cons_string->second();
+ source = cons_string.second();
} else {
// Left hand side is longer. Recurse over right.
if (to > boundary) {
- String second = cons_string->second();
+ String second = cons_string.second();
// When repeatedly appending to a string, we get a cons string that
// is unbalanced to the left, a list, essentially. We inline the
// common case of sequential one-byte right child.
if (to - boundary == 1) {
- sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
- } else if (second->IsSeqOneByteString()) {
+ sink[boundary - from] = static_cast<sinkchar>(second.Get(0));
+ } else if (second.IsSeqOneByteString()) {
CopyChars(sink + boundary - from,
- SeqOneByteString::cast(second)->GetChars(no_gc),
+ SeqOneByteString::cast(second).GetChars(no_gc),
to - boundary);
} else {
WriteToFlat(second, sink + boundary - from, 0, to - boundary);
@@ -600,13 +662,13 @@ void String::WriteToFlat(String src, sinkchar* sink, int f, int t) {
case kOneByteStringTag | kSlicedStringTag:
case kTwoByteStringTag | kSlicedStringTag: {
SlicedString slice = SlicedString::cast(source);
- unsigned offset = slice->offset();
- WriteToFlat(slice->parent(), sink, from + offset, to + offset);
+ unsigned offset = slice.offset();
+ WriteToFlat(slice.parent(), sink, from + offset, to + offset);
return;
}
case kOneByteStringTag | kThinStringTag:
case kTwoByteStringTag | kThinStringTag:
- source = ThinString::cast(source)->actual();
+ source = ThinString::cast(source).actual();
break;
}
}
@@ -667,15 +729,15 @@ bool String::SlowEquals(String other) {
DisallowHeapAllocation no_gc;
// Fast check: negative check with lengths.
int len = length();
- if (len != other->length()) return false;
+ if (len != other.length()) return false;
if (len == 0) return true;
// Fast check: if at least one ThinString is involved, dereference it/them
// and restart.
- if (this->IsThinString() || other->IsThinString()) {
- if (other->IsThinString()) other = ThinString::cast(other)->actual();
+ if (this->IsThinString() || other.IsThinString()) {
+ if (other.IsThinString()) other = ThinString::cast(other).actual();
if (this->IsThinString()) {
- return ThinString::cast(*this)->actual()->Equals(other);
+ return ThinString::cast(*this).actual().Equals(other);
} else {
return this->Equals(other);
}
@@ -683,13 +745,13 @@ bool String::SlowEquals(String other) {
// Fast check: if hash code is computed for both strings
// a fast negative check can be performed.
- if (HasHashCode() && other->HasHashCode()) {
+ 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)) {
+ if (Get(i) != other.Get(i)) {
found_difference = true;
break;
}
@@ -698,16 +760,16 @@ 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
// before we try to flatten the strings.
- if (this->Get(0) != other->Get(0)) return false;
+ if (this->Get(0) != other.Get(0)) return false;
- if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
- const uint8_t* str1 = SeqOneByteString::cast(*this)->GetChars(no_gc);
- const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars(no_gc);
+ if (IsSeqOneByteString() && other.IsSeqOneByteString()) {
+ const uint8_t* str1 = SeqOneByteString::cast(*this).GetChars(no_gc);
+ const uint8_t* str2 = SeqOneByteString::cast(other).GetChars(no_gc);
return CompareRawStringContents(str1, str2, len);
}
@@ -726,9 +788,9 @@ bool String::SlowEquals(Isolate* isolate, Handle<String> one,
// and restart.
if (one->IsThinString() || two->IsThinString()) {
if (one->IsThinString())
- one = handle(ThinString::cast(*one)->actual(), isolate);
+ one = handle(ThinString::cast(*one).actual(), isolate);
if (two->IsThinString())
- two = handle(ThinString::cast(*two)->actual(), isolate);
+ two = handle(ThinString::cast(*two).actual(), isolate);
return String::Equals(isolate, one, two);
}
@@ -764,8 +826,8 @@ bool String::SlowEquals(Isolate* isolate, Handle<String> one,
String::FlatContent flat2 = two->GetFlatContent(no_gc);
if (flat1.IsOneByte() && flat2.IsOneByte()) {
- return CompareRawStringContents(flat1.ToOneByteVector().start(),
- flat2.ToOneByteVector().start(),
+ return CompareRawStringContents(flat1.ToOneByteVector().begin(),
+ flat2.ToOneByteVector().begin(),
one_length);
} else {
for (int i = 0; i < one_length; i++) {
@@ -815,19 +877,19 @@ ComparisonResult String::Compare(Isolate* isolate, Handle<String> x,
Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
if (y_content.IsOneByte()) {
Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
- r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
+ r = CompareChars(x_chars.begin(), y_chars.begin(), prefix_length);
} else {
Vector<const uc16> y_chars = y_content.ToUC16Vector();
- r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
+ r = CompareChars(x_chars.begin(), y_chars.begin(), prefix_length);
}
} else {
Vector<const uc16> x_chars = x_content.ToUC16Vector();
if (y_content.IsOneByte()) {
Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
- r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
+ r = CompareChars(x_chars.begin(), y_chars.begin(), prefix_length);
} else {
Vector<const uc16> y_chars = y_content.ToUC16Vector();
- r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
+ r = CompareChars(x_chars.begin(), y_chars.begin(), prefix_length);
}
}
if (r < 0) {
@@ -1180,26 +1242,6 @@ Object String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
return Smi::FromInt(last_index);
}
-bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
- int slen = length();
- // Can't check exact length equality, but we can check bounds.
- int str_len = str.length();
- if (!allow_prefix_match &&
- (str_len < slen ||
- str_len > slen * static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
- return false;
- }
-
- int i = 0;
- unibrow::Utf8Iterator it = unibrow::Utf8Iterator(str);
- while (i < slen && !it.Done()) {
- if (Get(i++) != *it) return false;
- ++it;
- }
-
- return (allow_prefix_match || i == slen) && it.Done();
-}
-
template <>
bool String::IsEqualTo(Vector<const uint8_t> str) {
return IsOneByteEqualTo(str);
@@ -1210,16 +1252,28 @@ bool String::IsEqualTo(Vector<const uc16> str) {
return IsTwoByteEqualTo(str);
}
+bool String::HasOneBytePrefix(Vector<const char> str) {
+ int slen = str.length();
+ if (slen > length()) return false;
+ DisallowHeapAllocation no_gc;
+ FlatContent content = GetFlatContent(no_gc);
+ if (content.IsOneByte()) {
+ return CompareChars(content.ToOneByteVector().begin(), str.begin(), slen) ==
+ 0;
+ }
+ return CompareChars(content.ToUC16Vector().begin(), str.begin(), slen) == 0;
+}
+
bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
int slen = length();
if (str.length() != slen) return false;
DisallowHeapAllocation no_gc;
FlatContent content = GetFlatContent(no_gc);
if (content.IsOneByte()) {
- return CompareChars(content.ToOneByteVector().start(), str.start(), slen) ==
+ return CompareChars(content.ToOneByteVector().begin(), str.begin(), slen) ==
0;
}
- return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
+ return CompareChars(content.ToUC16Vector().begin(), str.begin(), slen) == 0;
}
bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
@@ -1228,20 +1282,67 @@ bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
DisallowHeapAllocation no_gc;
FlatContent content = GetFlatContent(no_gc);
if (content.IsOneByte()) {
- return CompareChars(content.ToOneByteVector().start(), str.start(), slen) ==
+ return CompareChars(content.ToOneByteVector().begin(), str.begin(), slen) ==
0;
}
- return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
+ return CompareChars(content.ToUC16Vector().begin(), str.begin(), slen) == 0;
+}
+
+namespace {
+
+template <typename Char>
+uint32_t HashString(String string, size_t start, int length, uint64_t seed) {
+ DisallowHeapAllocation no_gc;
+
+ if (length > String::kMaxHashCalcLength) {
+ return StringHasher::GetTrivialHash(length);
+ }
+
+ std::unique_ptr<Char[]> buffer;
+ const Char* chars;
+
+ if (string.IsConsString()) {
+ DCHECK_EQ(0, start);
+ DCHECK(!string.IsFlat());
+ buffer.reset(new Char[length]);
+ String::WriteToFlat(string, buffer.get(), 0, length);
+ chars = buffer.get();
+ } else {
+ chars = string.GetChars<Char>(no_gc) + start;
+ }
+
+ return StringHasher::HashSequentialString<Char>(chars, length, seed);
}
+} // namespace
+
uint32_t String::ComputeAndSetHash() {
DisallowHeapAllocation no_gc;
// Should only be called if hash code has not yet been computed.
DCHECK(!HasHashCode());
// Store the hash code in the object.
- uint32_t field =
- IteratingStringHasher::Hash(*this, HashSeed(GetReadOnlyRoots()));
+ uint64_t seed = HashSeed(GetReadOnlyRoots());
+ size_t start = 0;
+ String string = *this;
+ if (string.IsSlicedString()) {
+ SlicedString sliced = SlicedString::cast(string);
+ start = sliced.offset();
+ string = sliced.parent();
+ }
+ if (string.IsConsString() && string.IsFlat()) {
+ string = ConsString::cast(string).first();
+ }
+ if (string.IsThinString()) {
+ string = ThinString::cast(string).actual();
+ if (length() == string.length()) {
+ set_hash_field(string.hash_field());
+ return hash_field() >> kHashShift;
+ }
+ }
+ uint32_t field = string.IsOneByteRepresentation()
+ ? HashString<uint8_t>(string, start, length(), seed)
+ : HashString<uint16_t>(string, start, length(), seed);
set_hash_field(field);
// Check the hash code is there.
@@ -1325,13 +1426,13 @@ void SeqTwoByteString::clear_padding() {
SizeFor(length()) - data_size);
}
-uint16_t ConsString::ConsStringGet(int index) {
+uint16_t ConsString::Get(int index) {
DCHECK(index >= 0 && index < this->length());
// Check for a flattened cons string
- if (second()->length() == 0) {
+ if (second().length() == 0) {
String left = first();
- return left->Get(index);
+ return left.Get(index);
}
String string = String::cast(*this);
@@ -1339,26 +1440,24 @@ uint16_t ConsString::ConsStringGet(int index) {
while (true) {
if (StringShape(string).IsCons()) {
ConsString cons_string = ConsString::cast(string);
- String left = cons_string->first();
- if (left->length() > index) {
+ String left = cons_string.first();
+ if (left.length() > index) {
string = left;
} else {
- index -= left->length();
- string = cons_string->second();
+ index -= left.length();
+ string = cons_string.second();
}
} else {
- return string->Get(index);
+ return string.Get(index);
}
}
UNREACHABLE();
}
-uint16_t ThinString::ThinStringGet(int index) { return actual()->Get(index); }
+uint16_t ThinString::Get(int index) { return actual().Get(index); }
-uint16_t SlicedString::SlicedStringGet(int index) {
- return parent()->Get(offset() + index);
-}
+uint16_t SlicedString::Get(int index) { return parent().Get(offset() + index); }
int ExternalString::ExternalPayloadSize() const {
int length_multiplier = IsTwoByteRepresentation() ? i::kShortSize : kCharSize;
@@ -1375,7 +1474,7 @@ FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
str_(nullptr),
is_one_byte_(true),
length_(input.length()),
- start_(input.start()) {}
+ start_(input.begin()) {}
void FlatStringReader::PostGarbageCollection() {
if (str_ == nullptr) return;
@@ -1387,9 +1486,9 @@ void FlatStringReader::PostGarbageCollection() {
DCHECK(content.IsFlat());
is_one_byte_ = content.IsOneByte();
if (is_one_byte_) {
- start_ = content.ToOneByteVector().start();
+ start_ = content.ToOneByteVector().begin();
} else {
- start_ = content.ToUC16Vector().start();
+ start_ = content.ToUC16Vector().begin();
}
}
@@ -1430,13 +1529,13 @@ String ConsStringIterator::Search(int* offset_out) {
int offset = 0;
while (true) {
// Loop until the string is found which contains the target offset.
- String string = cons_string->first();
- int length = string->length();
+ String string = cons_string.first();
+ int length = string.length();
int32_t type;
if (consumed < offset + length) {
// Target offset is in the left branch.
// Keep going if we're still in a ConString.
- type = string->map()->instance_type();
+ type = string.map().instance_type();
if ((type & kStringRepresentationMask) == kConsStringTag) {
cons_string = ConsString::cast(string);
PushLeft(cons_string);
@@ -1449,15 +1548,15 @@ String ConsStringIterator::Search(int* offset_out) {
// Update progress through the string.
offset += length;
// Keep going if we're still in a ConString.
- string = cons_string->second();
- type = string->map()->instance_type();
+ string = cons_string.second();
+ type = string.map().instance_type();
if ((type & kStringRepresentationMask) == kConsStringTag) {
cons_string = ConsString::cast(string);
PushRight(cons_string);
continue;
}
// Need this to be updated for the current string.
- length = string->length();
+ length = string.length();
// Account for the possibility of an empty right leaf.
// This happens only if we have asked for an offset outside the string.
if (length == 0) {
@@ -1493,12 +1592,12 @@ String ConsStringIterator::NextLeaf(bool* blew_stack) {
}
// Go right.
ConsString cons_string = frames_[OffsetForDepth(depth_ - 1)];
- String string = cons_string->second();
- int32_t type = string->map()->instance_type();
+ String string = cons_string.second();
+ int32_t type = string.map().instance_type();
if ((type & kStringRepresentationMask) != kConsStringTag) {
// Pop stack so next iteration is in correct place.
Pop();
- int length = string->length();
+ int length = string.length();
// Could be a flattened ConsString.
if (length == 0) continue;
consumed_ += length;
@@ -1509,11 +1608,11 @@ String ConsStringIterator::NextLeaf(bool* blew_stack) {
// Need to traverse all the way left.
while (true) {
// Continue left.
- string = cons_string->first();
- type = string->map()->instance_type();
+ string = cons_string.first();
+ type = string.map().instance_type();
if ((type & kStringRepresentationMask) != kConsStringTag) {
AdjustMaximumDepth();
- int length = string->length();
+ int length = string.length();
if (length == 0) break; // Skip empty left-hand sides of ConsStrings.
consumed_ += length;
return string;