diff --git a/src/builtins/builtins-string.cc b/src/builtins/builtins-string.cc index 8fe126bb9d7f..3e4ab98ed8bc 100644 --- a/src/builtins/builtins-string.cc +++ b/src/builtins/builtins-string.cc @@ -461,7 +461,7 @@ V8_WARN_UNUSED_RESULT static Object* ConvertCase( // character is also ASCII. This is currently the case, but it // might break in the future if we implement more context and locale // dependent upper/lower conversions. - if (s->IsOneByteRepresentationUnderneath()) { + if (String::IsOneByteRepresentationUnderneath(*s)) { // Same length as input. Handle result = isolate->factory()->NewRawOneByteString(length).ToHandleChecked(); diff --git a/src/conversions.cc b/src/conversions.cc index e369ce93e0b7..dc2f3ac09d90 100644 --- a/src/conversions.cc +++ b/src/conversions.cc @@ -209,7 +209,7 @@ class StringToIntHelper { bool IsOneByte() const { return raw_one_byte_subject_ != nullptr || - subject_->IsOneByteRepresentationUnderneath(); + String::IsOneByteRepresentationUnderneath(*subject_); } Vector GetOneByteVector() { diff --git a/src/json-stringifier.cc b/src/json-stringifier.cc index f7701f84ce28..d4653cca477c 100644 --- a/src/json-stringifier.cc +++ b/src/json-stringifier.cc @@ -901,14 +901,14 @@ void JsonStringifier::SerializeDeferredKey(bool deferred_comma, void JsonStringifier::SerializeString(Handle object) { object = String::Flatten(isolate_, object); if (builder_.CurrentEncoding() == String::ONE_BYTE_ENCODING) { - if (object->IsOneByteRepresentationUnderneath()) { + if (String::IsOneByteRepresentationUnderneath(*object)) { SerializeString_(object); } else { builder_.ChangeEncoding(); SerializeString(object); } } else { - if (object->IsOneByteRepresentationUnderneath()) { + if (String::IsOneByteRepresentationUnderneath(*object)) { SerializeString_(object); } else { SerializeString_(object); diff --git a/src/objects.cc b/src/objects.cc index 10c61f56b8d0..01d8f1b06068 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -16725,7 +16725,7 @@ MaybeHandle EscapeRegExpSource(Isolate* isolate, Handle source) { DCHECK(source->IsFlat()); if (source->length() == 0) return isolate->factory()->query_colon_string(); - bool one_byte = source->IsOneByteRepresentationUnderneath(); + bool one_byte = String::IsOneByteRepresentationUnderneath(*source); int escapes = one_byte ? CountRequiredEscapes(source) : CountRequiredEscapes(source); if (escapes == 0) return source; diff --git a/src/objects/string-inl.h b/src/objects/string-inl.h index ad9f91a669b3..f8d6907b2ed5 100644 --- a/src/objects/string-inl.h +++ b/src/objects/string-inl.h @@ -162,33 +162,20 @@ bool String::IsTwoByteRepresentation() const { return (type & kStringEncodingMask) == kTwoByteStringTag; } -bool String::IsOneByteRepresentationUnderneath() { - uint32_t type = map()->instance_type(); - STATIC_ASSERT(kIsIndirectStringTag != 0); - STATIC_ASSERT((kIsIndirectStringMask & kStringEncodingMask) == 0); - DCHECK(IsFlat()); - switch (type & (kIsIndirectStringMask | kStringEncodingMask)) { - case kOneByteStringTag: - return true; - case kTwoByteStringTag: - return false; - default: // Cons, sliced, thin, strings need to go deeper. - return GetUnderlying()->IsOneByteRepresentationUnderneath(); - } -} - -bool String::IsTwoByteRepresentationUnderneath() { - uint32_t type = map()->instance_type(); - STATIC_ASSERT(kIsIndirectStringTag != 0); - STATIC_ASSERT((kIsIndirectStringMask & kStringEncodingMask) == 0); - DCHECK(IsFlat()); - switch (type & (kIsIndirectStringMask | kStringEncodingMask)) { - case kOneByteStringTag: - return false; - case kTwoByteStringTag: - return true; - default: // Cons, sliced, thin, strings need to go deeper. - return GetUnderlying()->IsTwoByteRepresentationUnderneath(); +bool String::IsOneByteRepresentationUnderneath(String string) { + while (true) { + uint32_t type = string.map()->instance_type(); + STATIC_ASSERT(kIsIndirectStringTag != 0); + STATIC_ASSERT((kIsIndirectStringMask & kStringEncodingMask) == 0); + DCHECK(string.IsFlat()); + switch (type & (kIsIndirectStringMask | kStringEncodingMask)) { + case kOneByteStringTag: + return true; + case kTwoByteStringTag: + return false; + default: // Cons, sliced, thin, strings need to go deeper. + string = string.GetUnderlying(); + } } } diff --git a/src/objects/string.h b/src/objects/string.h index ffe4892e2137..5abaca46eb4d 100644 --- a/src/objects/string.h +++ b/src/objects/string.h @@ -164,9 +164,9 @@ class String : public Name { // Cons and slices have an encoding flag that may not represent the actual // encoding of the underlying string. This is taken into account here. - // Requires: this->IsFlat() - inline bool IsOneByteRepresentationUnderneath(); - inline bool IsTwoByteRepresentationUnderneath(); + // This function is static because that helps it get inlined. + // Requires: string.IsFlat() + static inline bool IsOneByteRepresentationUnderneath(String string); // NOTE: this should be considered only a hint. False negatives are // possible. diff --git a/src/regexp/jsregexp.cc b/src/regexp/jsregexp.cc index 7e640f2ab938..e2f4450c1f98 100644 --- a/src/regexp/jsregexp.cc +++ b/src/regexp/jsregexp.cc @@ -410,7 +410,7 @@ int RegExpImpl::IrregexpPrepare(Isolate* isolate, Handle regexp, DCHECK(subject->IsFlat()); // Check representation of the underlying storage. - bool is_one_byte = subject->IsOneByteRepresentationUnderneath(); + bool is_one_byte = String::IsOneByteRepresentationUnderneath(*subject); if (!EnsureCompiledIrregexp(isolate, regexp, subject, is_one_byte)) return -1; #ifdef V8_INTERPRETED_REGEXP @@ -436,7 +436,7 @@ int RegExpImpl::IrregexpExecRaw(Isolate* isolate, Handle regexp, DCHECK_LE(index, subject->length()); DCHECK(subject->IsFlat()); - bool is_one_byte = subject->IsOneByteRepresentationUnderneath(); + bool is_one_byte = String::IsOneByteRepresentationUnderneath(*subject); #ifndef V8_INTERPRETED_REGEXP DCHECK(output_size >= (IrregexpNumberOfCaptures(*irregexp) + 1) * 2); @@ -472,7 +472,7 @@ int RegExpImpl::IrregexpExecRaw(Isolate* isolate, Handle regexp, // being internal and external, and even between being Latin1 and UC16, // but the characters are always the same). IrregexpPrepare(isolate, regexp, subject); - is_one_byte = subject->IsOneByteRepresentationUnderneath(); + is_one_byte = String::IsOneByteRepresentationUnderneath(*subject); } while (true); UNREACHABLE(); #else // V8_INTERPRETED_REGEXP diff --git a/src/regexp/regexp-macro-assembler.cc b/src/regexp/regexp-macro-assembler.cc index a79775122918..1ebe5cd2be1b 100644 --- a/src/regexp/regexp-macro-assembler.cc +++ b/src/regexp/regexp-macro-assembler.cc @@ -161,7 +161,7 @@ int NativeRegExpMacroAssembler::CheckStackGuardState( HandleScope handles(isolate); Handle code_handle(re_code, isolate); Handle subject_handle(String::cast(ObjectPtr(*subject)), isolate); - bool is_one_byte = subject_handle->IsOneByteRepresentationUnderneath(); + bool is_one_byte = String::IsOneByteRepresentationUnderneath(*subject_handle); StackLimitCheck check(isolate); bool js_has_overflowed = check.JsHasOverflowed(); @@ -192,7 +192,8 @@ int NativeRegExpMacroAssembler::CheckStackGuardState( // If we continue, we need to update the subject string addresses. if (return_value == 0) { // String encoding might have changed. - if (subject_handle->IsOneByteRepresentationUnderneath() != is_one_byte) { + if (String::IsOneByteRepresentationUnderneath(*subject_handle) != + is_one_byte) { // If we changed between an LATIN1 and an UC16 string, the specialized // code cannot be used, and we need to restart regexp matching from // scratch (including, potentially, compiling a new version of the code). diff --git a/src/uri.cc b/src/uri.cc index 2c20582064d9..47b9333dda1b 100644 --- a/src/uri.cc +++ b/src/uri.cc @@ -493,7 +493,7 @@ static MaybeHandle EscapePrivate(Isolate* isolate, MaybeHandle Uri::Escape(Isolate* isolate, Handle string) { Handle result; string = String::Flatten(isolate, string); - return string->IsOneByteRepresentationUnderneath() + return String::IsOneByteRepresentationUnderneath(*string) ? EscapePrivate(isolate, string) : EscapePrivate(isolate, string); } @@ -501,7 +501,7 @@ MaybeHandle Uri::Escape(Isolate* isolate, Handle string) { MaybeHandle Uri::Unescape(Isolate* isolate, Handle string) { Handle result; string = String::Flatten(isolate, string); - return string->IsOneByteRepresentationUnderneath() + return String::IsOneByteRepresentationUnderneath(*string) ? UnescapePrivate(isolate, string) : UnescapePrivate(isolate, string); } diff --git a/test/cctest/test-strings.cc b/test/cctest/test-strings.cc index 09cbf26ccac2..7c7ccac87f49 100644 --- a/test/cctest/test-strings.cc +++ b/test/cctest/test-strings.cc @@ -1832,9 +1832,8 @@ TEST(Regress876759) { CHECK(grandparent->IsOneByteRepresentation()); CHECK(parent->IsTwoByteRepresentation()); CHECK(sliced->IsTwoByteRepresentation()); - // The *Underneath versions return the correct representation. - CHECK(sliced->IsOneByteRepresentationUnderneath()); - CHECK(!sliced->IsTwoByteRepresentationUnderneath()); + // The *Underneath version returns the correct representation. + CHECK(String::IsOneByteRepresentationUnderneath(*sliced)); } } // namespace test_strings