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