Commit 52cfffde authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[utils] Add CompareCharsEqual

Add a CompareCharsEqual to complement CompareChars, where we only care
about equality and not ordering. For such cases, we can memcmp for two-
byte as well as one-byte strings (we can't for CompareChars because the
ordering would be incorrect on little-endian systems).

Replace uses of CompareChars that only compare the result against zero,
with CompareCharsEqual. Additionally, use some template magic to
simplify the "make unsigned" operation in these methods.

Change-Id: I0d65bee81b98d3938d15daa4af331c90558ea84f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2557980
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71385}
parent 546939fe
......@@ -126,23 +126,23 @@ bool AstRawString::Equal(const AstRawString* lhs, const AstRawString* rhs) {
size_t length = rhs->length();
if (lhs->is_one_byte()) {
if (rhs->is_one_byte()) {
return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(l),
reinterpret_cast<const uint8_t*>(r),
length) == 0;
return CompareCharsEqualUnsigned(reinterpret_cast<const uint8_t*>(l),
reinterpret_cast<const uint8_t*>(r),
length);
} else {
return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(l),
reinterpret_cast<const uint16_t*>(r),
length) == 0;
return CompareCharsEqualUnsigned(reinterpret_cast<const uint8_t*>(l),
reinterpret_cast<const uint16_t*>(r),
length);
}
} else {
if (rhs->is_one_byte()) {
return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(l),
reinterpret_cast<const uint8_t*>(r),
length) == 0;
return CompareCharsEqualUnsigned(reinterpret_cast<const uint16_t*>(l),
reinterpret_cast<const uint8_t*>(r),
length);
} else {
return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(l),
reinterpret_cast<const uint16_t*>(r),
length) == 0;
return CompareCharsEqualUnsigned(reinterpret_cast<const uint16_t*>(l),
reinterpret_cast<const uint16_t*>(r),
length);
}
}
}
......
......@@ -231,7 +231,7 @@ class JsonParser final {
STATIC_ASSERT(N > 2);
size_t remaining = static_cast<size_t>(end_ - cursor_);
if (V8_LIKELY(remaining >= N - 1 &&
CompareChars(s + 1, cursor_ + 1, N - 2) == 0)) {
CompareCharsEqual(s + 1, cursor_ + 1, N - 2))) {
cursor_ += N - 1;
return;
}
......
......@@ -13,44 +13,6 @@
namespace v8 {
namespace internal {
// Compares the contents of two strings by reading and comparing
// int-sized blocks of characters.
template <typename Char>
static inline bool CompareRawStringContents(const Char* const a,
const Char* const b, int length) {
return CompareChars(a, b, length) == 0;
}
template <typename Chars1, typename Chars2>
class RawStringComparator : public AllStatic {
public:
static inline bool compare(const Chars1* a, const Chars2* b, int len) {
DCHECK(sizeof(Chars1) != sizeof(Chars2));
for (int i = 0; i < len; i++) {
if (a[i] != b[i]) {
return false;
}
}
return true;
}
};
template <>
class RawStringComparator<uint16_t, uint16_t> {
public:
static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
return CompareRawStringContents(a, b, len);
}
};
template <>
class RawStringComparator<uint8_t, uint8_t> {
public:
static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
return CompareRawStringContents(a, b, len);
}
};
class StringComparator {
class State {
public:
......@@ -92,7 +54,7 @@ class StringComparator {
static inline bool Equals(State* state_1, State* state_2, int to_check) {
const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
return CompareCharsEqual(a, b, to_check);
}
bool Equals(String string_1, String string_2);
......
......@@ -450,25 +450,25 @@ bool String::IsEqualTo(Vector<const Char> str,
SeqOneByteString str, const Char* data, size_t len,
const DisallowGarbageCollection& no_gc,
const SharedStringAccessGuardIfNeeded& access_guard) {
return CompareChars(str.GetChars(no_gc, access_guard), data, len) == 0;
return CompareCharsEqual(str.GetChars(no_gc, access_guard), data, len);
}
static inline bool HandleSeqTwoByteString(
SeqTwoByteString str, const Char* data, size_t len,
const DisallowGarbageCollection& no_gc,
const SharedStringAccessGuardIfNeeded& access_guard) {
return CompareChars(str.GetChars(no_gc, access_guard), data, len) == 0;
return CompareCharsEqual(str.GetChars(no_gc, access_guard), data, len);
}
static inline bool HandleExternalOneByteString(
ExternalOneByteString str, const Char* data, size_t len,
const DisallowGarbageCollection& no_gc,
const SharedStringAccessGuardIfNeeded& access_guard) {
return CompareChars(str.GetChars(), data, len) == 0;
return CompareCharsEqual(str.GetChars(), data, len);
}
static inline bool HandleExternalTwoByteString(
ExternalTwoByteString str, const Char* data, size_t len,
const DisallowGarbageCollection& no_gc,
const SharedStringAccessGuardIfNeeded& access_guard) {
return CompareChars(str.GetChars(), data, len) == 0;
return CompareCharsEqual(str.GetChars(), data, len);
}
static inline bool HandleConsString(
ConsString str, const Char* data, size_t len,
......
......@@ -835,7 +835,7 @@ bool String::SlowEquals(String other) {
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);
return CompareCharsEqual(str1, str2, len);
}
StringComparator comparator;
......@@ -891,9 +891,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().begin(),
flat2.ToOneByteVector().begin(),
one_length);
return CompareCharsEqual(flat1.ToOneByteVector().begin(),
flat2.ToOneByteVector().begin(), one_length);
} else {
for (int i = 0; i < one_length; i++) {
if (flat1.Get(i) != flat2.Get(i)) return false;
......
......@@ -799,7 +799,7 @@ IrregexpInterpreter::Result RawMatch(
int len = registers[LoadPacked24Unsigned(insn) + 1] - from;
if (from >= 0 && len > 0) {
if (current + len > subject.length() ||
CompareChars(&subject[from], &subject[current], len) != 0) {
!CompareCharsEqual(&subject[from], &subject[current], len)) {
SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
DISPATCH();
}
......@@ -813,7 +813,7 @@ IrregexpInterpreter::Result RawMatch(
int len = registers[LoadPacked24Unsigned(insn) + 1] - from;
if (from >= 0 && len > 0) {
if (current - len < 0 ||
CompareChars(&subject[from], &subject[current - len], len) != 0) {
!CompareCharsEqual(&subject[from], &subject[current - len], len)) {
SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
DISPATCH();
}
......
......@@ -66,9 +66,7 @@ struct IntrinsicFunctionIdentifier {
const IntrinsicFunctionIdentifier* rhs =
static_cast<IntrinsicFunctionIdentifier*>(key2);
if (lhs->length_ != rhs->length_) return false;
return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(lhs->data_),
reinterpret_cast<const uint8_t*>(rhs->data_),
rhs->length_) == 0;
return CompareCharsEqual(lhs->data_, rhs->data_, rhs->length_);
}
uint32_t Hash() {
......
......@@ -335,48 +335,56 @@ class SetOncePointer {
T* pointer_ = nullptr;
};
// Compare 8bit/16bit chars to 8bit/16bit chars.
template <typename lchar, typename rchar>
inline bool CompareCharsEqualUnsigned(const lchar* lhs, const rchar* rhs,
size_t chars) {
STATIC_ASSERT(std::is_unsigned<lchar>::value);
STATIC_ASSERT(std::is_unsigned<rchar>::value);
if (sizeof(*lhs) == sizeof(*rhs)) {
// memcmp compares byte-by-byte, but for equality it doesn't matter whether
// two-byte char comparison is little- or big-endian.
return memcmp(lhs, rhs, chars * sizeof(*lhs)) == 0;
}
for (const lchar* limit = lhs + chars; lhs < limit; ++lhs, ++rhs) {
if (*lhs != *rhs) return false;
}
return true;
}
template <typename lchar, typename rchar>
inline bool CompareCharsEqual(const lchar* lhs, const rchar* rhs,
size_t chars) {
using ulchar = typename std::make_unsigned<lchar>::type;
using urchar = typename std::make_unsigned<rchar>::type;
return CompareCharsEqualUnsigned(reinterpret_cast<const ulchar*>(lhs),
reinterpret_cast<const urchar*>(rhs), chars);
}
// Compare 8bit/16bit chars to 8bit/16bit chars.
template <typename lchar, typename rchar>
inline int CompareCharsUnsigned(const lchar* lhs, const rchar* rhs,
size_t chars) {
const lchar* limit = lhs + chars;
STATIC_ASSERT(std::is_unsigned<lchar>::value);
STATIC_ASSERT(std::is_unsigned<rchar>::value);
if (sizeof(*lhs) == sizeof(char) && sizeof(*rhs) == sizeof(char)) {
// memcmp compares byte-by-byte, yielding wrong results for two-byte
// strings on little-endian systems.
return memcmp(lhs, rhs, chars);
}
while (lhs < limit) {
for (const lchar* limit = lhs + chars; lhs < limit; ++lhs, ++rhs) {
int r = static_cast<int>(*lhs) - static_cast<int>(*rhs);
if (r != 0) return r;
++lhs;
++rhs;
}
return 0;
}
template <typename lchar, typename rchar>
inline int CompareChars(const lchar* lhs, const rchar* rhs, size_t chars) {
DCHECK_LE(sizeof(lchar), 2);
DCHECK_LE(sizeof(rchar), 2);
if (sizeof(lchar) == 1) {
if (sizeof(rchar) == 1) {
return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(lhs),
reinterpret_cast<const uint8_t*>(rhs), chars);
} else {
return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(lhs),
reinterpret_cast<const uint16_t*>(rhs),
chars);
}
} else {
if (sizeof(rchar) == 1) {
return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(lhs),
reinterpret_cast<const uint8_t*>(rhs), chars);
} else {
return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(lhs),
reinterpret_cast<const uint16_t*>(rhs),
chars);
}
}
using ulchar = typename std::make_unsigned<lchar>::type;
using urchar = typename std::make_unsigned<rchar>::type;
return CompareCharsUnsigned(reinterpret_cast<const ulchar*>(lhs),
reinterpret_cast<const urchar*>(rhs), chars);
}
// Calculate 10^exponent.
......
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