11cb0ef41Sopenharmony_ci// Copyright 2017 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#ifndef V8_STRINGS_STRING_HASHER_INL_H_ 61cb0ef41Sopenharmony_ci#define V8_STRINGS_STRING_HASHER_INL_H_ 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci#include "src/strings/string-hasher.h" 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ci// Comment inserted to prevent header reordering. 111cb0ef41Sopenharmony_ci#include <type_traits> 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_ci#include "src/objects/name-inl.h" 141cb0ef41Sopenharmony_ci#include "src/objects/objects.h" 151cb0ef41Sopenharmony_ci#include "src/objects/string.h" 161cb0ef41Sopenharmony_ci#include "src/strings/char-predicates-inl.h" 171cb0ef41Sopenharmony_ci#include "src/utils/utils-inl.h" 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_cinamespace v8 { 201cb0ef41Sopenharmony_cinamespace internal { 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ciuint32_t StringHasher::AddCharacterCore(uint32_t running_hash, uint16_t c) { 231cb0ef41Sopenharmony_ci running_hash += c; 241cb0ef41Sopenharmony_ci running_hash += (running_hash << 10); 251cb0ef41Sopenharmony_ci running_hash ^= (running_hash >> 6); 261cb0ef41Sopenharmony_ci return running_hash; 271cb0ef41Sopenharmony_ci} 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ciuint32_t StringHasher::GetHashCore(uint32_t running_hash) { 301cb0ef41Sopenharmony_ci running_hash += (running_hash << 3); 311cb0ef41Sopenharmony_ci running_hash ^= (running_hash >> 11); 321cb0ef41Sopenharmony_ci running_hash += (running_hash << 15); 331cb0ef41Sopenharmony_ci int32_t hash = static_cast<int32_t>(running_hash & String::HashBits::kMax); 341cb0ef41Sopenharmony_ci // Ensure that the hash is kZeroHash, if the computed value is 0. 351cb0ef41Sopenharmony_ci int32_t mask = (hash - 1) >> 31; 361cb0ef41Sopenharmony_ci running_hash |= (kZeroHash & mask); 371cb0ef41Sopenharmony_ci return running_hash; 381cb0ef41Sopenharmony_ci} 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ciuint32_t StringHasher::GetTrivialHash(int length) { 411cb0ef41Sopenharmony_ci DCHECK_GT(length, String::kMaxHashCalcLength); 421cb0ef41Sopenharmony_ci // The hash of a large string is simply computed from the length. 431cb0ef41Sopenharmony_ci // Ensure that the max length is small enough to be encoded without losing 441cb0ef41Sopenharmony_ci // information. 451cb0ef41Sopenharmony_ci STATIC_ASSERT(String::kMaxLength <= String::HashBits::kMax); 461cb0ef41Sopenharmony_ci uint32_t hash = static_cast<uint32_t>(length); 471cb0ef41Sopenharmony_ci return String::CreateHashFieldValue(hash, String::HashFieldType::kHash); 481cb0ef41Sopenharmony_ci} 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_citemplate <typename char_t> 511cb0ef41Sopenharmony_ciuint32_t StringHasher::HashSequentialString(const char_t* chars_raw, int length, 521cb0ef41Sopenharmony_ci uint64_t seed) { 531cb0ef41Sopenharmony_ci STATIC_ASSERT(std::is_integral<char_t>::value); 541cb0ef41Sopenharmony_ci STATIC_ASSERT(sizeof(char_t) <= 2); 551cb0ef41Sopenharmony_ci using uchar = typename std::make_unsigned<char_t>::type; 561cb0ef41Sopenharmony_ci const uchar* chars = reinterpret_cast<const uchar*>(chars_raw); 571cb0ef41Sopenharmony_ci DCHECK_LE(0, length); 581cb0ef41Sopenharmony_ci DCHECK_IMPLIES(0 < length, chars != nullptr); 591cb0ef41Sopenharmony_ci if (length >= 1) { 601cb0ef41Sopenharmony_ci if (IsDecimalDigit(chars[0]) && (length == 1 || chars[0] != '0')) { 611cb0ef41Sopenharmony_ci if (length <= String::kMaxArrayIndexSize) { 621cb0ef41Sopenharmony_ci // Possible array index; try to compute the array index hash. 631cb0ef41Sopenharmony_ci uint32_t index = chars[0] - '0'; 641cb0ef41Sopenharmony_ci int i = 1; 651cb0ef41Sopenharmony_ci do { 661cb0ef41Sopenharmony_ci if (i == length) { 671cb0ef41Sopenharmony_ci return MakeArrayIndexHash(index, length); 681cb0ef41Sopenharmony_ci } 691cb0ef41Sopenharmony_ci } while (TryAddArrayIndexChar(&index, chars[i++])); 701cb0ef41Sopenharmony_ci } 711cb0ef41Sopenharmony_ci // The following block wouldn't do anything on 32-bit platforms, 721cb0ef41Sopenharmony_ci // because kMaxArrayIndexSize == kMaxIntegerIndexSize there, and 731cb0ef41Sopenharmony_ci // if we wanted to compile it everywhere, then {index_big} would 741cb0ef41Sopenharmony_ci // have to be a {size_t}, which the Mac compiler doesn't like to 751cb0ef41Sopenharmony_ci // implicitly cast to uint64_t for the {TryAddIndexChar} call. 761cb0ef41Sopenharmony_ci#if V8_HOST_ARCH_64_BIT 771cb0ef41Sopenharmony_ci // No "else" here: if the block above was entered and fell through, 781cb0ef41Sopenharmony_ci // we'll have to take this branch. 791cb0ef41Sopenharmony_ci if (length <= String::kMaxIntegerIndexSize) { 801cb0ef41Sopenharmony_ci // Not an array index, but it could still be an integer index. 811cb0ef41Sopenharmony_ci // Perform a regular hash computation, and additionally check 821cb0ef41Sopenharmony_ci // if there are non-digit characters. 831cb0ef41Sopenharmony_ci String::HashFieldType type = String::HashFieldType::kIntegerIndex; 841cb0ef41Sopenharmony_ci uint32_t running_hash = static_cast<uint32_t>(seed); 851cb0ef41Sopenharmony_ci uint64_t index_big = 0; 861cb0ef41Sopenharmony_ci const uchar* end = &chars[length]; 871cb0ef41Sopenharmony_ci while (chars != end) { 881cb0ef41Sopenharmony_ci if (type == String::HashFieldType::kIntegerIndex && 891cb0ef41Sopenharmony_ci !TryAddIntegerIndexChar(&index_big, *chars)) { 901cb0ef41Sopenharmony_ci type = String::HashFieldType::kHash; 911cb0ef41Sopenharmony_ci } 921cb0ef41Sopenharmony_ci running_hash = AddCharacterCore(running_hash, *chars++); 931cb0ef41Sopenharmony_ci } 941cb0ef41Sopenharmony_ci uint32_t hash = 951cb0ef41Sopenharmony_ci String::CreateHashFieldValue(GetHashCore(running_hash), type); 961cb0ef41Sopenharmony_ci if (Name::ContainsCachedArrayIndex(hash)) { 971cb0ef41Sopenharmony_ci // The hash accidentally looks like a cached index. Fix that by 981cb0ef41Sopenharmony_ci // setting a bit that looks like a longer-than-cacheable string 991cb0ef41Sopenharmony_ci // length. 1001cb0ef41Sopenharmony_ci hash |= (String::kMaxCachedArrayIndexLength + 1) 1011cb0ef41Sopenharmony_ci << String::ArrayIndexLengthBits::kShift; 1021cb0ef41Sopenharmony_ci } 1031cb0ef41Sopenharmony_ci DCHECK(!Name::ContainsCachedArrayIndex(hash)); 1041cb0ef41Sopenharmony_ci return hash; 1051cb0ef41Sopenharmony_ci } 1061cb0ef41Sopenharmony_ci#endif 1071cb0ef41Sopenharmony_ci } 1081cb0ef41Sopenharmony_ci // No "else" here: if the first character was a decimal digit, we might 1091cb0ef41Sopenharmony_ci // still have to take this branch. 1101cb0ef41Sopenharmony_ci if (length > String::kMaxHashCalcLength) { 1111cb0ef41Sopenharmony_ci return GetTrivialHash(length); 1121cb0ef41Sopenharmony_ci } 1131cb0ef41Sopenharmony_ci } 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_ci // Non-index hash. 1161cb0ef41Sopenharmony_ci uint32_t running_hash = static_cast<uint32_t>(seed); 1171cb0ef41Sopenharmony_ci const uchar* end = &chars[length]; 1181cb0ef41Sopenharmony_ci while (chars != end) { 1191cb0ef41Sopenharmony_ci running_hash = AddCharacterCore(running_hash, *chars++); 1201cb0ef41Sopenharmony_ci } 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci return String::CreateHashFieldValue(GetHashCore(running_hash), 1231cb0ef41Sopenharmony_ci String::HashFieldType::kHash); 1241cb0ef41Sopenharmony_ci} 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_cistd::size_t SeededStringHasher::operator()(const char* name) const { 1271cb0ef41Sopenharmony_ci return StringHasher::HashSequentialString( 1281cb0ef41Sopenharmony_ci name, static_cast<int>(strlen(name)), hashseed_); 1291cb0ef41Sopenharmony_ci} 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ci} // namespace internal 1321cb0ef41Sopenharmony_ci} // namespace v8 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ci#endif // V8_STRINGS_STRING_HASHER_INL_H_ 135