Commit 03f2f686 authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

Reland "[string] Fix non-SeqStrings in IsEqualTo"

This is a reland of e70cbb83

Moved the ConsString comparison logic out-of-line, both to make gcc
happy, and to reduce the size of the fast-path in IsEqualToImpl.

Original change's description:
> [string] Fix non-SeqStrings in IsEqualTo
>
> Bug: chromium:1193903
> Change-Id: I80704dd3cba5754779432356b20bd3ea99630291
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2794426
> Commit-Queue: Leszek Swirski <leszeks@chromium.org>
> Commit-Queue: Igor Sheludko <ishell@chromium.org>
> Reviewed-by: Igor Sheludko <ishell@chromium.org>
> Auto-Submit: Leszek Swirski <leszeks@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#73746}

Bug: chromium:1193903
Change-Id: Iae6f078853438427e86d3ac68bcfed0712a85bf7
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2797288
Auto-Submit: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73763}
parent 14a970f3
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "src/common/external-pointer-inl.h" #include "src/common/external-pointer-inl.h"
#include "src/common/external-pointer.h" #include "src/common/external-pointer.h"
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/execution/isolate-utils.h"
#include "src/handles/handles-inl.h" #include "src/handles/handles-inl.h"
#include "src/heap/factory.h" #include "src/heap/factory.h"
#include "src/numbers/conversions-inl.h" #include "src/numbers/conversions-inl.h"
...@@ -403,7 +404,8 @@ class SeqSubStringKey final : public StringTableKey { ...@@ -403,7 +404,8 @@ class SeqSubStringKey final : public StringTableKey {
DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*string_)); DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*string_));
DisallowGarbageCollection no_gc; DisallowGarbageCollection no_gc;
return string.IsEqualTo<String::EqualityType::kNoLengthCheck>( return string.IsEqualTo<String::EqualityType::kNoLengthCheck>(
Vector<const Char>(string_->GetChars(no_gc) + from_, length())); Vector<const Char>(string_->GetChars(no_gc) + from_, length()),
isolate);
} }
Handle<String> AsHandle(Isolate* isolate) { Handle<String> AsHandle(Isolate* isolate) {
...@@ -454,19 +456,26 @@ bool String::Equals(Isolate* isolate, Handle<String> one, Handle<String> two) { ...@@ -454,19 +456,26 @@ bool String::Equals(Isolate* isolate, Handle<String> one, Handle<String> two) {
template <String::EqualityType kEqType, typename Char> template <String::EqualityType kEqType, typename Char>
bool String::IsEqualTo(Vector<const Char> str, Isolate* isolate) const { bool String::IsEqualTo(Vector<const Char> str, Isolate* isolate) const {
DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this)); DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
return IsEqualToImpl<kEqType>(str, return IsEqualToImpl<kEqType>(str, isolate,
SharedStringAccessGuardIfNeeded::NotNeeded());
}
template <String::EqualityType kEqType, typename Char>
bool String::IsEqualTo(Vector<const Char> str) const {
DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
return IsEqualToImpl<kEqType>(str, GetIsolateForPtrCompr(*this),
SharedStringAccessGuardIfNeeded::NotNeeded()); SharedStringAccessGuardIfNeeded::NotNeeded());
} }
template <String::EqualityType kEqType, typename Char> template <String::EqualityType kEqType, typename Char>
bool String::IsEqualTo(Vector<const Char> str, LocalIsolate* isolate) const { bool String::IsEqualTo(Vector<const Char> str, LocalIsolate* isolate) const {
SharedStringAccessGuardIfNeeded access_guard(isolate); SharedStringAccessGuardIfNeeded access_guard(isolate);
return IsEqualToImpl<kEqType>(str, access_guard); return IsEqualToImpl<kEqType>(str, isolate, access_guard);
} }
template <String::EqualityType kEqType, typename Char> template <String::EqualityType kEqType, typename Char>
bool String::IsEqualToImpl( bool String::IsEqualToImpl(
Vector<const Char> str, Vector<const Char> str, IsolateRoot isolate,
const SharedStringAccessGuardIfNeeded& access_guard) const { const SharedStringAccessGuardIfNeeded& access_guard) const {
size_t len = str.size(); size_t len = str.size();
switch (kEqType) { switch (kEqType) {
...@@ -483,60 +492,85 @@ bool String::IsEqualToImpl( ...@@ -483,60 +492,85 @@ bool String::IsEqualToImpl(
DisallowGarbageCollection no_gc; DisallowGarbageCollection no_gc;
class IsEqualToDispatcher : public AllStatic { int slice_offset = 0;
public: String string = *this;
static inline bool HandleSeqOneByteString( const Char* data = str.data();
SeqOneByteString str, const Char* data, size_t len, while (true) {
const DisallowGarbageCollection& no_gc, int32_t type = string.map(isolate).instance_type();
const SharedStringAccessGuardIfNeeded& access_guard) { switch (type & (kStringRepresentationMask | kStringEncodingMask)) {
return CompareCharsEqual(str.GetChars(no_gc, access_guard), data, len); case kSeqStringTag | kOneByteStringTag:
} return CompareCharsEqual(
static inline bool HandleSeqTwoByteString( SeqOneByteString::cast(string).GetChars(no_gc, access_guard) +
SeqTwoByteString str, const Char* data, size_t len, slice_offset,
const DisallowGarbageCollection& no_gc, data, len);
const SharedStringAccessGuardIfNeeded& access_guard) { case kSeqStringTag | kTwoByteStringTag:
return CompareCharsEqual(str.GetChars(no_gc, access_guard), data, len); return CompareCharsEqual(
} SeqTwoByteString::cast(string).GetChars(no_gc, access_guard) +
static inline bool HandleExternalOneByteString( slice_offset,
ExternalOneByteString str, const Char* data, size_t len, data, len);
const DisallowGarbageCollection& no_gc, case kExternalStringTag | kOneByteStringTag:
const SharedStringAccessGuardIfNeeded& access_guard) { return CompareCharsEqual(
return CompareCharsEqual(str.GetChars(), data, len); ExternalOneByteString::cast(string).GetChars() + slice_offset, data,
len);
case kExternalStringTag | kTwoByteStringTag:
return CompareCharsEqual(
ExternalTwoByteString::cast(string).GetChars() + slice_offset, data,
len);
case kSlicedStringTag | kOneByteStringTag:
case kSlicedStringTag | kTwoByteStringTag: {
SlicedString slicedString = SlicedString::cast(string);
slice_offset += slicedString.offset();
string = slicedString.parent(isolate);
continue;
} }
static inline bool HandleExternalTwoByteString(
ExternalTwoByteString str, const Char* data, size_t len, case kConsStringTag | kOneByteStringTag:
const DisallowGarbageCollection& no_gc, case kConsStringTag | kTwoByteStringTag: {
const SharedStringAccessGuardIfNeeded& access_guard) { // The ConsString path is more complex and rare, so call out to an
return CompareCharsEqual(str.GetChars(), data, len); // out-of-line handler.
return IsConsStringEqualToImpl<Char>(
ConsString::cast(string), slice_offset, str, isolate, access_guard);
} }
static inline bool HandleConsString(
ConsString str, const Char* data, size_t len, case kThinStringTag | kOneByteStringTag:
const DisallowGarbageCollection& no_gc, case kThinStringTag | kTwoByteStringTag:
const SharedStringAccessGuardIfNeeded& access_guard) { string = ThinString::cast(string).actual(isolate);
continue;
default:
UNREACHABLE(); UNREACHABLE();
} }
static inline bool HandleSlicedString(
SlicedString str, const Char* data, size_t len,
const DisallowGarbageCollection& no_gc,
const SharedStringAccessGuardIfNeeded& access_guard) {
UNREACHABLE();
} }
static inline bool HandleThinString( }
ThinString str, const Char* data, size_t len,
const DisallowGarbageCollection& no_gc, // static
const SharedStringAccessGuardIfNeeded& access_guard) { template <typename Char>
UNREACHABLE(); bool String::IsConsStringEqualToImpl(
ConsString string, int slice_offset, Vector<const Char> str,
IsolateRoot isolate, const SharedStringAccessGuardIfNeeded& access_guard) {
// Already checked the len in IsEqualToImpl. Check GE rather than EQ in case
// this is a prefix check.
DCHECK_GE(string.length(), str.size());
ConsStringIterator iter(ConsString::cast(string), slice_offset);
Vector<const Char> remaining_str = str;
for (String segment = iter.Next(&slice_offset); !segment.is_null();
segment = iter.Next(&slice_offset)) {
// Compare the individual segment against the appropriate subvector of the
// remaining string.
size_t len = std::min<size_t>(segment.length(), remaining_str.size());
Vector<const Char> sub_str = remaining_str.SubVector(0, len);
if (!segment.IsEqualToImpl<EqualityType::kNoLengthCheck>(sub_str, isolate,
access_guard)) {
return false;
} }
static inline bool HandleInvalidString( remaining_str += len;
String str, const Char* data, size_t len, if (remaining_str.empty()) break;
const DisallowGarbageCollection& no_gc,
const SharedStringAccessGuardIfNeeded& access_guard) {
UNREACHABLE();
} }
}; DCHECK_EQ(remaining_str.data(), str.end());
DCHECK_EQ(remaining_str.size(), 0);
return StringShape(*this).DispatchToSpecificType<IsEqualToDispatcher, bool>( return true;
*this, str.data(), len, no_gc, access_guard);
} }
bool String::IsOneByteEqualTo(Vector<const char> str) { return IsEqualTo(str); } bool String::IsOneByteEqualTo(Vector<const char> str) { return IsEqualTo(str); }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "src/common/assert-scope.h" #include "src/common/assert-scope.h"
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/execution/isolate-utils.h"
#include "src/execution/thread-id.h" #include "src/execution/thread-id.h"
#include "src/handles/handles-inl.h" #include "src/handles/handles-inl.h"
#include "src/heap/heap-inl.h" #include "src/heap/heap-inl.h"
...@@ -1286,7 +1287,10 @@ Object String::LastIndexOf(Isolate* isolate, Handle<Object> receiver, ...@@ -1286,7 +1287,10 @@ Object String::LastIndexOf(Isolate* isolate, Handle<Object> receiver,
} }
bool String::HasOneBytePrefix(Vector<const char> str) { bool String::HasOneBytePrefix(Vector<const char> str) {
return IsEqualTo<EqualityType::kPrefix>(str); DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
return IsEqualToImpl<EqualityType::kPrefix>(
str, GetIsolateForPtrCompr(*this),
SharedStringAccessGuardIfNeeded::NotNeeded());
} }
namespace { namespace {
......
...@@ -326,8 +326,15 @@ class String : public TorqueGeneratedString<String, Name> { ...@@ -326,8 +326,15 @@ class String : public TorqueGeneratedString<String, Name> {
// The Isolate is passed as "evidence" that this call is on the main thread, // The Isolate is passed as "evidence" that this call is on the main thread,
// and to distiguish from the LocalIsolate overload. // and to distiguish from the LocalIsolate overload.
template <EqualityType kEqType = EqualityType::kWholeString, typename Char> template <EqualityType kEqType = EqualityType::kWholeString, typename Char>
inline bool IsEqualTo(Vector<const Char> str, inline bool IsEqualTo(Vector<const Char> str, Isolate* isolate) const;
Isolate* isolate = nullptr) const;
// Check if this string matches the given vector of characters, either as a
// whole string or just a prefix.
//
// This is main-thread only, like the Isolate* overload, but additionally
// computes the IsolateRoot for IsEqualToImpl.
template <EqualityType kEqType = EqualityType::kWholeString, typename Char>
inline bool IsEqualTo(Vector<const Char> str) const;
// Check if this string matches the given vector of characters, either as a // Check if this string matches the given vector of characters, either as a
// whole string or just a prefix. // whole string or just a prefix.
...@@ -539,9 +546,15 @@ class String : public TorqueGeneratedString<String, Name> { ...@@ -539,9 +546,15 @@ class String : public TorqueGeneratedString<String, Name> {
// Implementation of the IsEqualTo() public methods. Do not use directly. // Implementation of the IsEqualTo() public methods. Do not use directly.
template <EqualityType kEqType, typename Char> template <EqualityType kEqType, typename Char>
V8_INLINE bool IsEqualToImpl( V8_INLINE bool IsEqualToImpl(
Vector<const Char> str, Vector<const Char> str, IsolateRoot isolate,
const SharedStringAccessGuardIfNeeded& access_guard) const; const SharedStringAccessGuardIfNeeded& access_guard) const;
// Out-of-line IsEqualToImpl for ConsString.
template <typename Char>
V8_NOINLINE static bool IsConsStringEqualToImpl(
ConsString string, int slice_offset, Vector<const Char> str,
IsolateRoot isolate, const SharedStringAccessGuardIfNeeded& access_guard);
V8_EXPORT_PRIVATE static Handle<String> SlowFlatten( V8_EXPORT_PRIVATE static Handle<String> SlowFlatten(
Isolate* isolate, Handle<ConsString> cons, AllocationType allocation); Isolate* isolate, Handle<ConsString> cons, AllocationType allocation);
......
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax
var no_sync_uninternalized = "no " + "sync";
%InternalizeString(no_sync_uninternalized);
// Make sure %GetOptimizationStatus works with a non-internalized string
// parameter.
%GetOptimizationStatus(function() {}, no_sync_uninternalized)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment