[cleanup & objects.h splitting] Move StringHasher
BUG=v8:6325,v8:5402 Change-Id: If0c975fe377c0178c488fc1bedd02f9c8289ebbc Reviewed-on: https://chromium-review.googlesource.com/490086 Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Commit-Queue: Marja Hölttä <marja@chromium.org> Cr-Commit-Position: refs/heads/master@{#44979}
This commit is contained in:
parent
f05c09dd2e
commit
95a7cfe0ea
2
BUILD.gn
2
BUILD.gn
@ -1890,6 +1890,8 @@ v8_source_set("v8_base") {
|
||||
"src/string-builder.h",
|
||||
"src/string-case.cc",
|
||||
"src/string-case.h",
|
||||
"src/string-hasher-inl.h",
|
||||
"src/string-hasher.h",
|
||||
"src/string-search.h",
|
||||
"src/string-stream.cc",
|
||||
"src/string-stream.h",
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "src/char-predicates-inl.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/objects.h"
|
||||
#include "src/string-hasher.h"
|
||||
#include "src/utils.h"
|
||||
|
||||
namespace v8 {
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "src/objects/descriptor-array.h"
|
||||
#include "src/objects/dictionary.h"
|
||||
#include "src/objects/scope-info.h"
|
||||
#include "src/string-hasher.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "src/msan.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/objects/scope-info.h"
|
||||
#include "src/string-hasher.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/parsing/token.h"
|
||||
#include "src/property-descriptor.h"
|
||||
#include "src/string-hasher.h"
|
||||
#include "src/transitions.h"
|
||||
#include "src/unicode-cache.h"
|
||||
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "src/objects/scope-info.h"
|
||||
#include "src/property.h"
|
||||
#include "src/prototype.h"
|
||||
#include "src/string-hasher-inl.h"
|
||||
#include "src/transitions-inl.h"
|
||||
#include "src/v8memory.h"
|
||||
|
||||
@ -7281,152 +7282,6 @@ bool Name::IsPrivate() {
|
||||
return this->IsSymbol() && Symbol::cast(this)->is_private();
|
||||
}
|
||||
|
||||
|
||||
StringHasher::StringHasher(int length, uint32_t seed)
|
||||
: length_(length),
|
||||
raw_running_hash_(seed),
|
||||
array_index_(0),
|
||||
is_array_index_(0 < length_ && length_ <= String::kMaxArrayIndexSize),
|
||||
is_first_char_(true) {
|
||||
DCHECK(FLAG_randomize_hashes || raw_running_hash_ == 0);
|
||||
}
|
||||
|
||||
|
||||
bool StringHasher::has_trivial_hash() {
|
||||
return length_ > String::kMaxHashCalcLength;
|
||||
}
|
||||
|
||||
|
||||
uint32_t StringHasher::AddCharacterCore(uint32_t running_hash, uint16_t c) {
|
||||
running_hash += c;
|
||||
running_hash += (running_hash << 10);
|
||||
running_hash ^= (running_hash >> 6);
|
||||
return running_hash;
|
||||
}
|
||||
|
||||
|
||||
uint32_t StringHasher::GetHashCore(uint32_t running_hash) {
|
||||
running_hash += (running_hash << 3);
|
||||
running_hash ^= (running_hash >> 11);
|
||||
running_hash += (running_hash << 15);
|
||||
if ((running_hash & String::kHashBitMask) == 0) {
|
||||
return kZeroHash;
|
||||
}
|
||||
return running_hash;
|
||||
}
|
||||
|
||||
|
||||
uint32_t StringHasher::ComputeRunningHash(uint32_t running_hash,
|
||||
const uc16* chars, int length) {
|
||||
DCHECK_NOT_NULL(chars);
|
||||
DCHECK(length >= 0);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
running_hash = AddCharacterCore(running_hash, *chars++);
|
||||
}
|
||||
return running_hash;
|
||||
}
|
||||
|
||||
|
||||
uint32_t StringHasher::ComputeRunningHashOneByte(uint32_t running_hash,
|
||||
const char* chars,
|
||||
int length) {
|
||||
DCHECK_NOT_NULL(chars);
|
||||
DCHECK(length >= 0);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
uint16_t c = static_cast<uint16_t>(*chars++);
|
||||
running_hash = AddCharacterCore(running_hash, c);
|
||||
}
|
||||
return running_hash;
|
||||
}
|
||||
|
||||
|
||||
void StringHasher::AddCharacter(uint16_t c) {
|
||||
// Use the Jenkins one-at-a-time hash function to update the hash
|
||||
// for the given character.
|
||||
raw_running_hash_ = AddCharacterCore(raw_running_hash_, c);
|
||||
}
|
||||
|
||||
|
||||
bool StringHasher::UpdateIndex(uint16_t c) {
|
||||
DCHECK(is_array_index_);
|
||||
if (c < '0' || c > '9') {
|
||||
is_array_index_ = false;
|
||||
return false;
|
||||
}
|
||||
int d = c - '0';
|
||||
if (is_first_char_) {
|
||||
is_first_char_ = false;
|
||||
if (c == '0' && length_ > 1) {
|
||||
is_array_index_ = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (array_index_ > 429496729U - ((d + 3) >> 3)) {
|
||||
is_array_index_ = false;
|
||||
return false;
|
||||
}
|
||||
array_index_ = array_index_ * 10 + d;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline void StringHasher::AddCharacters(const Char* chars, int length) {
|
||||
DCHECK(sizeof(Char) == 1 || sizeof(Char) == 2);
|
||||
int i = 0;
|
||||
if (is_array_index_) {
|
||||
for (; i < length; i++) {
|
||||
AddCharacter(chars[i]);
|
||||
if (!UpdateIndex(chars[i])) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
DCHECK(!is_array_index_);
|
||||
AddCharacter(chars[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename schar>
|
||||
uint32_t StringHasher::HashSequentialString(const schar* chars,
|
||||
int length,
|
||||
uint32_t seed) {
|
||||
StringHasher hasher(length, seed);
|
||||
if (!hasher.has_trivial_hash()) hasher.AddCharacters(chars, length);
|
||||
return hasher.GetHashField();
|
||||
}
|
||||
|
||||
|
||||
IteratingStringHasher::IteratingStringHasher(int len, uint32_t seed)
|
||||
: StringHasher(len, seed) {}
|
||||
|
||||
|
||||
uint32_t IteratingStringHasher::Hash(String* string, uint32_t seed) {
|
||||
IteratingStringHasher hasher(string->length(), seed);
|
||||
// Nothing to do.
|
||||
if (hasher.has_trivial_hash()) return hasher.GetHashField();
|
||||
ConsString* cons_string = String::VisitFlat(&hasher, string);
|
||||
if (cons_string == nullptr) return hasher.GetHashField();
|
||||
hasher.VisitConsString(cons_string);
|
||||
return hasher.GetHashField();
|
||||
}
|
||||
|
||||
|
||||
void IteratingStringHasher::VisitOneByteString(const uint8_t* chars,
|
||||
int length) {
|
||||
AddCharacters(chars, length);
|
||||
}
|
||||
|
||||
|
||||
void IteratingStringHasher::VisitTwoByteString(const uint16_t* chars,
|
||||
int length) {
|
||||
AddCharacters(chars, length);
|
||||
}
|
||||
|
||||
|
||||
bool Name::AsArrayIndex(uint32_t* index) {
|
||||
return IsString() && String::cast(this)->AsArrayIndex(index);
|
||||
}
|
||||
|
@ -7776,78 +7776,6 @@ class AliasedArgumentsEntry: public Struct {
|
||||
enum AllowNullsFlag {ALLOW_NULLS, DISALLOW_NULLS};
|
||||
enum RobustnessFlag {ROBUST_STRING_TRAVERSAL, FAST_STRING_TRAVERSAL};
|
||||
|
||||
class V8_EXPORT_PRIVATE StringHasher {
|
||||
public:
|
||||
explicit inline StringHasher(int length, uint32_t seed);
|
||||
|
||||
template <typename schar>
|
||||
static inline uint32_t HashSequentialString(const schar* chars,
|
||||
int length,
|
||||
uint32_t seed);
|
||||
|
||||
// Reads all the data, even for long strings and computes the utf16 length.
|
||||
static uint32_t ComputeUtf8Hash(Vector<const char> chars,
|
||||
uint32_t seed,
|
||||
int* utf16_length_out);
|
||||
|
||||
// Calculated hash value for a string consisting of 1 to
|
||||
// String::kMaxArrayIndexSize digits with no leading zeros (except "0").
|
||||
// value is represented decimal value.
|
||||
static uint32_t MakeArrayIndexHash(uint32_t value, int length);
|
||||
|
||||
// No string is allowed to have a hash of zero. That value is reserved
|
||||
// for internal properties. If the hash calculation yields zero then we
|
||||
// use 27 instead.
|
||||
static const int kZeroHash = 27;
|
||||
|
||||
// Reusable parts of the hashing algorithm.
|
||||
INLINE(static uint32_t AddCharacterCore(uint32_t running_hash, uint16_t c));
|
||||
INLINE(static uint32_t GetHashCore(uint32_t running_hash));
|
||||
INLINE(static uint32_t ComputeRunningHash(uint32_t running_hash,
|
||||
const uc16* chars, int length));
|
||||
INLINE(static uint32_t ComputeRunningHashOneByte(uint32_t running_hash,
|
||||
const char* chars,
|
||||
int length));
|
||||
|
||||
protected:
|
||||
// Returns the value to store in the hash field of a string with
|
||||
// the given length and contents.
|
||||
uint32_t GetHashField();
|
||||
// Returns true if the hash of this string can be computed without
|
||||
// looking at the contents.
|
||||
inline bool has_trivial_hash();
|
||||
// Adds a block of characters to the hash.
|
||||
template<typename Char>
|
||||
inline void AddCharacters(const Char* chars, int len);
|
||||
|
||||
private:
|
||||
// Add a character to the hash.
|
||||
inline void AddCharacter(uint16_t c);
|
||||
// Update index. Returns true if string is still an index.
|
||||
inline bool UpdateIndex(uint16_t c);
|
||||
|
||||
int length_;
|
||||
uint32_t raw_running_hash_;
|
||||
uint32_t array_index_;
|
||||
bool is_array_index_;
|
||||
bool is_first_char_;
|
||||
DISALLOW_COPY_AND_ASSIGN(StringHasher);
|
||||
};
|
||||
|
||||
|
||||
class IteratingStringHasher : public StringHasher {
|
||||
public:
|
||||
static inline uint32_t Hash(String* string, uint32_t seed);
|
||||
inline void VisitOneByteString(const uint8_t* chars, int length);
|
||||
inline void VisitTwoByteString(const uint16_t* chars, int length);
|
||||
|
||||
private:
|
||||
inline IteratingStringHasher(int len, uint32_t seed);
|
||||
void VisitConsString(ConsString* cons_string);
|
||||
DISALLOW_COPY_AND_ASSIGN(IteratingStringHasher);
|
||||
};
|
||||
|
||||
|
||||
// The characteristics of a string are stored in its map. Retrieving these
|
||||
// few bits of information is moderately expensive, involving two memory
|
||||
// loads where the second is dependent on the first. To improve efficiency
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "src/base/platform/time.h"
|
||||
#include "src/objects.h"
|
||||
#include "src/profiler/strings-storage.h"
|
||||
#include "src/string-hasher.h"
|
||||
#include "src/visitors.h"
|
||||
|
||||
namespace v8 {
|
||||
|
147
src/string-hasher-inl.h
Normal file
147
src/string-hasher-inl.h
Normal file
@ -0,0 +1,147 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
#ifndef V8_STRING_HASHER_INL_H_
|
||||
#define V8_STRING_HASHER_INL_H_
|
||||
|
||||
#include "src/objects.h"
|
||||
#include "src/string-hasher.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
StringHasher::StringHasher(int length, uint32_t seed)
|
||||
: length_(length),
|
||||
raw_running_hash_(seed),
|
||||
array_index_(0),
|
||||
is_array_index_(0 < length_ && length_ <= String::kMaxArrayIndexSize),
|
||||
is_first_char_(true) {
|
||||
DCHECK(FLAG_randomize_hashes || raw_running_hash_ == 0);
|
||||
}
|
||||
|
||||
bool StringHasher::has_trivial_hash() {
|
||||
return length_ > String::kMaxHashCalcLength;
|
||||
}
|
||||
|
||||
uint32_t StringHasher::AddCharacterCore(uint32_t running_hash, uint16_t c) {
|
||||
running_hash += c;
|
||||
running_hash += (running_hash << 10);
|
||||
running_hash ^= (running_hash >> 6);
|
||||
return running_hash;
|
||||
}
|
||||
|
||||
uint32_t StringHasher::GetHashCore(uint32_t running_hash) {
|
||||
running_hash += (running_hash << 3);
|
||||
running_hash ^= (running_hash >> 11);
|
||||
running_hash += (running_hash << 15);
|
||||
if ((running_hash & String::kHashBitMask) == 0) {
|
||||
return kZeroHash;
|
||||
}
|
||||
return running_hash;
|
||||
}
|
||||
|
||||
uint32_t StringHasher::ComputeRunningHash(uint32_t running_hash,
|
||||
const uc16* chars, int length) {
|
||||
DCHECK_NOT_NULL(chars);
|
||||
DCHECK(length >= 0);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
running_hash = AddCharacterCore(running_hash, *chars++);
|
||||
}
|
||||
return running_hash;
|
||||
}
|
||||
|
||||
uint32_t StringHasher::ComputeRunningHashOneByte(uint32_t running_hash,
|
||||
const char* chars,
|
||||
int length) {
|
||||
DCHECK_NOT_NULL(chars);
|
||||
DCHECK(length >= 0);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
uint16_t c = static_cast<uint16_t>(*chars++);
|
||||
running_hash = AddCharacterCore(running_hash, c);
|
||||
}
|
||||
return running_hash;
|
||||
}
|
||||
|
||||
void StringHasher::AddCharacter(uint16_t c) {
|
||||
// Use the Jenkins one-at-a-time hash function to update the hash
|
||||
// for the given character.
|
||||
raw_running_hash_ = AddCharacterCore(raw_running_hash_, c);
|
||||
}
|
||||
|
||||
bool StringHasher::UpdateIndex(uint16_t c) {
|
||||
DCHECK(is_array_index_);
|
||||
if (c < '0' || c > '9') {
|
||||
is_array_index_ = false;
|
||||
return false;
|
||||
}
|
||||
int d = c - '0';
|
||||
if (is_first_char_) {
|
||||
is_first_char_ = false;
|
||||
if (c == '0' && length_ > 1) {
|
||||
is_array_index_ = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (array_index_ > 429496729U - ((d + 3) >> 3)) {
|
||||
is_array_index_ = false;
|
||||
return false;
|
||||
}
|
||||
array_index_ = array_index_ * 10 + d;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline void StringHasher::AddCharacters(const Char* chars, int length) {
|
||||
DCHECK(sizeof(Char) == 1 || sizeof(Char) == 2);
|
||||
int i = 0;
|
||||
if (is_array_index_) {
|
||||
for (; i < length; i++) {
|
||||
AddCharacter(chars[i]);
|
||||
if (!UpdateIndex(chars[i])) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
DCHECK(!is_array_index_);
|
||||
AddCharacter(chars[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename schar>
|
||||
uint32_t StringHasher::HashSequentialString(const schar* chars, int length,
|
||||
uint32_t seed) {
|
||||
StringHasher hasher(length, seed);
|
||||
if (!hasher.has_trivial_hash()) hasher.AddCharacters(chars, length);
|
||||
return hasher.GetHashField();
|
||||
}
|
||||
|
||||
IteratingStringHasher::IteratingStringHasher(int len, uint32_t seed)
|
||||
: StringHasher(len, seed) {}
|
||||
|
||||
uint32_t IteratingStringHasher::Hash(String* string, uint32_t seed) {
|
||||
IteratingStringHasher hasher(string->length(), seed);
|
||||
// Nothing to do.
|
||||
if (hasher.has_trivial_hash()) return hasher.GetHashField();
|
||||
ConsString* cons_string = String::VisitFlat(&hasher, string);
|
||||
if (cons_string == nullptr) return hasher.GetHashField();
|
||||
hasher.VisitConsString(cons_string);
|
||||
return hasher.GetHashField();
|
||||
}
|
||||
|
||||
void IteratingStringHasher::VisitOneByteString(const uint8_t* chars,
|
||||
int length) {
|
||||
AddCharacters(chars, length);
|
||||
}
|
||||
|
||||
void IteratingStringHasher::VisitTwoByteString(const uint16_t* chars,
|
||||
int length) {
|
||||
AddCharacters(chars, length);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_STRING_HASHER_INL_H_
|
90
src/string-hasher.h
Normal file
90
src/string-hasher.h
Normal file
@ -0,0 +1,90 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
#ifndef V8_STRING_HASHER_H_
|
||||
#define V8_STRING_HASHER_H_
|
||||
|
||||
#include "src/globals.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class ConsString;
|
||||
class String;
|
||||
|
||||
template <typename T>
|
||||
class Vector;
|
||||
|
||||
class V8_EXPORT_PRIVATE StringHasher {
|
||||
public:
|
||||
explicit inline StringHasher(int length, uint32_t seed);
|
||||
|
||||
template <typename schar>
|
||||
static inline uint32_t HashSequentialString(const schar* chars, int length,
|
||||
uint32_t seed);
|
||||
|
||||
// Reads all the data, even for long strings and computes the utf16 length.
|
||||
static uint32_t ComputeUtf8Hash(Vector<const char> chars, uint32_t seed,
|
||||
int* utf16_length_out);
|
||||
|
||||
// Calculated hash value for a string consisting of 1 to
|
||||
// String::kMaxArrayIndexSize digits with no leading zeros (except "0").
|
||||
// value is represented decimal value.
|
||||
static uint32_t MakeArrayIndexHash(uint32_t value, int length);
|
||||
|
||||
// No string is allowed to have a hash of zero. That value is reserved
|
||||
// for internal properties. If the hash calculation yields zero then we
|
||||
// use 27 instead.
|
||||
static const int kZeroHash = 27;
|
||||
|
||||
// Reusable parts of the hashing algorithm.
|
||||
INLINE(static uint32_t AddCharacterCore(uint32_t running_hash, uint16_t c));
|
||||
INLINE(static uint32_t GetHashCore(uint32_t running_hash));
|
||||
INLINE(static uint32_t ComputeRunningHash(uint32_t running_hash,
|
||||
const uc16* chars, int length));
|
||||
INLINE(static uint32_t ComputeRunningHashOneByte(uint32_t running_hash,
|
||||
const char* chars,
|
||||
int length));
|
||||
|
||||
protected:
|
||||
// Returns the value to store in the hash field of a string with
|
||||
// the given length and contents.
|
||||
uint32_t GetHashField();
|
||||
// Returns true if the hash of this string can be computed without
|
||||
// looking at the contents.
|
||||
inline bool has_trivial_hash();
|
||||
// Adds a block of characters to the hash.
|
||||
template <typename Char>
|
||||
inline void AddCharacters(const Char* chars, int len);
|
||||
|
||||
private:
|
||||
// Add a character to the hash.
|
||||
inline void AddCharacter(uint16_t c);
|
||||
// Update index. Returns true if string is still an index.
|
||||
inline bool UpdateIndex(uint16_t c);
|
||||
|
||||
int length_;
|
||||
uint32_t raw_running_hash_;
|
||||
uint32_t array_index_;
|
||||
bool is_array_index_;
|
||||
bool is_first_char_;
|
||||
DISALLOW_COPY_AND_ASSIGN(StringHasher);
|
||||
};
|
||||
|
||||
class IteratingStringHasher : public StringHasher {
|
||||
public:
|
||||
static inline uint32_t Hash(String* string, uint32_t seed);
|
||||
inline void VisitOneByteString(const uint8_t* chars, int length);
|
||||
inline void VisitTwoByteString(const uint16_t* chars, int length);
|
||||
|
||||
private:
|
||||
inline IteratingStringHasher(int len, uint32_t seed);
|
||||
void VisitConsString(ConsString* cons_string);
|
||||
DISALLOW_COPY_AND_ASSIGN(IteratingStringHasher);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_STRING_HASHER_H_
|
@ -1300,6 +1300,8 @@
|
||||
'string-builder.h',
|
||||
'string-case.cc',
|
||||
'string-case.h',
|
||||
'string-hasher-inl.h',
|
||||
'string-hasher.h',
|
||||
'string-search.h',
|
||||
'string-stream.cc',
|
||||
'string-stream.h',
|
||||
|
Loading…
Reference in New Issue
Block a user