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_COMPILER_PERSISTENT_MAP_H_
61cb0ef41Sopenharmony_ci#define V8_COMPILER_PERSISTENT_MAP_H_
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci#include <array>
91cb0ef41Sopenharmony_ci#include <tuple>
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ci#include "src/base/functional.h"
121cb0ef41Sopenharmony_ci#include "src/zone/zone-containers.h"
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_cinamespace v8 {
151cb0ef41Sopenharmony_cinamespace internal {
161cb0ef41Sopenharmony_cinamespace compiler {
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ci// PersistentMap is a persistent map datastructure based on hash trees (a binary
191cb0ef41Sopenharmony_ci// tree using the bits of a hash value as addresses). The map is a conceptually
201cb0ef41Sopenharmony_ci// infinite: All keys are initially mapped to a default value, values are
211cb0ef41Sopenharmony_ci// deleted by overwriting them with the default value. The iterators produce
221cb0ef41Sopenharmony_ci// exactly the keys that are not the default value. The hash values should have
231cb0ef41Sopenharmony_ci// high variance in their high bits, so dense integers are a bad choice.
241cb0ef41Sopenharmony_ci// Complexity:
251cb0ef41Sopenharmony_ci// - Copy and assignment: O(1)
261cb0ef41Sopenharmony_ci// - access: O(log n)
271cb0ef41Sopenharmony_ci// - update: O(log n) time and space
281cb0ef41Sopenharmony_ci// - iteration: amortized O(1) per step
291cb0ef41Sopenharmony_ci// - Zip: O(n)
301cb0ef41Sopenharmony_ci// - equality check: O(n)
311cb0ef41Sopenharmony_ci// TODO(turbofan): Cache map transitions to avoid re-allocation of the same map.
321cb0ef41Sopenharmony_ci// TODO(turbofan): Implement an O(1) equality check based on hash consing or
331cb0ef41Sopenharmony_ci//              something similar.
341cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher = base::hash<Key>>
351cb0ef41Sopenharmony_ciclass PersistentMap {
361cb0ef41Sopenharmony_ci public:
371cb0ef41Sopenharmony_ci  using key_type = Key;
381cb0ef41Sopenharmony_ci  using mapped_type = Value;
391cb0ef41Sopenharmony_ci  using value_type = std::pair<Key, Value>;
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci private:
421cb0ef41Sopenharmony_ci  static constexpr size_t kHashBits = 32;
431cb0ef41Sopenharmony_ci  enum Bit : int { kLeft = 0, kRight = 1 };
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci  // Access hash bits starting from the high bits and compare them according to
461cb0ef41Sopenharmony_ci  // their unsigned value. This way, the order in the hash tree is compatible
471cb0ef41Sopenharmony_ci  // with numeric hash comparisons.
481cb0ef41Sopenharmony_ci  class HashValue;
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci  struct KeyValue : std::pair<Key, Value> {
511cb0ef41Sopenharmony_ci    const Key& key() const { return this->first; }
521cb0ef41Sopenharmony_ci    const Value& value() const { return this->second; }
531cb0ef41Sopenharmony_ci    using std::pair<Key, Value>::pair;
541cb0ef41Sopenharmony_ci  };
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci  struct FocusedTree;
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci public:
591cb0ef41Sopenharmony_ci  // Depth of the last added element. This is a cheap estimate for the size of
601cb0ef41Sopenharmony_ci  // the hash tree.
611cb0ef41Sopenharmony_ci  size_t last_depth() const {
621cb0ef41Sopenharmony_ci    if (tree_) {
631cb0ef41Sopenharmony_ci      return tree_->length;
641cb0ef41Sopenharmony_ci    } else {
651cb0ef41Sopenharmony_ci      return 0;
661cb0ef41Sopenharmony_ci    }
671cb0ef41Sopenharmony_ci  }
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci  const Value& Get(const Key& key) const {
701cb0ef41Sopenharmony_ci    HashValue key_hash = HashValue(Hasher()(key));
711cb0ef41Sopenharmony_ci    const FocusedTree* tree = FindHash(key_hash);
721cb0ef41Sopenharmony_ci    return GetFocusedValue(tree, key);
731cb0ef41Sopenharmony_ci  }
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci  // Add or overwrite an existing key-value pair.
761cb0ef41Sopenharmony_ci  void Set(Key key, Value value);
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci  bool operator==(const PersistentMap& other) const {
791cb0ef41Sopenharmony_ci    if (tree_ == other.tree_) return true;
801cb0ef41Sopenharmony_ci    if (def_value_ != other.def_value_) return false;
811cb0ef41Sopenharmony_ci    for (std::tuple<Key, Value, Value> triple : Zip(other)) {
821cb0ef41Sopenharmony_ci      if (std::get<1>(triple) != std::get<2>(triple)) return false;
831cb0ef41Sopenharmony_ci    }
841cb0ef41Sopenharmony_ci    return true;
851cb0ef41Sopenharmony_ci  }
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci  bool operator!=(const PersistentMap& other) const {
881cb0ef41Sopenharmony_ci    return !(*this == other);
891cb0ef41Sopenharmony_ci  }
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ci  // The iterator produces key-value pairs in the lexicographical order of
921cb0ef41Sopenharmony_ci  // hash value and key. It produces exactly the key-value pairs where the value
931cb0ef41Sopenharmony_ci  // is not the default value.
941cb0ef41Sopenharmony_ci  class iterator;
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci  iterator begin() const {
971cb0ef41Sopenharmony_ci    if (!tree_) return end();
981cb0ef41Sopenharmony_ci    return iterator::begin(tree_, def_value_);
991cb0ef41Sopenharmony_ci  }
1001cb0ef41Sopenharmony_ci  iterator end() const { return iterator::end(def_value_); }
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci  // Iterator to traverse two maps in lockstep, producing matching value pairs
1031cb0ef41Sopenharmony_ci  // for each key where at least one value is different from the respective
1041cb0ef41Sopenharmony_ci  // default.
1051cb0ef41Sopenharmony_ci  class double_iterator;
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_ci  // An iterable to iterate over the two maps in lockstep.
1081cb0ef41Sopenharmony_ci  struct ZipIterable {
1091cb0ef41Sopenharmony_ci    PersistentMap a;
1101cb0ef41Sopenharmony_ci    PersistentMap b;
1111cb0ef41Sopenharmony_ci    double_iterator begin() { return double_iterator(a.begin(), b.begin()); }
1121cb0ef41Sopenharmony_ci    double_iterator end() { return double_iterator(a.end(), b.end()); }
1131cb0ef41Sopenharmony_ci  };
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci  ZipIterable Zip(const PersistentMap& other) const { return {*this, other}; }
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci  explicit PersistentMap(Zone* zone, Value def_value = Value())
1181cb0ef41Sopenharmony_ci      : PersistentMap(nullptr, zone, def_value) {}
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci private:
1211cb0ef41Sopenharmony_ci  // Find the {FocusedTree} that contains a key-value pair with key hash {hash}.
1221cb0ef41Sopenharmony_ci  const FocusedTree* FindHash(HashValue hash) const;
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_ci  // Find the {FocusedTree} that contains a key-value pair with key hash {hash}.
1251cb0ef41Sopenharmony_ci  // Output the path to this {FocusedTree} and its length. If no such
1261cb0ef41Sopenharmony_ci  // {FocusedTree} exists, return {nullptr} and output the path to the last node
1271cb0ef41Sopenharmony_ci  // with a matching hash prefix. Note that {length} is the length of the found
1281cb0ef41Sopenharmony_ci  // path and may be less than the length of the found {FocusedTree}.
1291cb0ef41Sopenharmony_ci  const FocusedTree* FindHash(HashValue hash,
1301cb0ef41Sopenharmony_ci                              std::array<const FocusedTree*, kHashBits>* path,
1311cb0ef41Sopenharmony_ci                              int* length) const;
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci  // Load value from the leaf node on the focused path of {tree}.
1341cb0ef41Sopenharmony_ci  const Value& GetFocusedValue(const FocusedTree* tree, const Key& key) const;
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_ci  // Return the {FocusedTree} representing the left (bit==kLeft) or right
1371cb0ef41Sopenharmony_ci  // (bit==kRight) child of the node on the path of {tree} at tree level
1381cb0ef41Sopenharmony_ci  // {level}.
1391cb0ef41Sopenharmony_ci  static const FocusedTree* GetChild(const FocusedTree* tree, int level,
1401cb0ef41Sopenharmony_ci                                     Bit bit);
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci  // Find the leftmost path in the tree, starting at the node at tree level
1431cb0ef41Sopenharmony_ci  // {level} on the path of {start}. Output the level of the leaf to {level} and
1441cb0ef41Sopenharmony_ci  // the path to {path}.
1451cb0ef41Sopenharmony_ci  static const FocusedTree* FindLeftmost(
1461cb0ef41Sopenharmony_ci      const FocusedTree* start, int* level,
1471cb0ef41Sopenharmony_ci      std::array<const FocusedTree*, kHashBits>* path);
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci  PersistentMap(const FocusedTree* tree, Zone* zone, Value def_value)
1501cb0ef41Sopenharmony_ci      : tree_(tree), def_value_(def_value), zone_(zone) {}
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_ci  const FocusedTree* tree_;
1531cb0ef41Sopenharmony_ci  Value def_value_;
1541cb0ef41Sopenharmony_ci  Zone* zone_;
1551cb0ef41Sopenharmony_ci};
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci// This structure represents a hash tree with one focused path to a specific
1581cb0ef41Sopenharmony_ci// leaf. For the focused leaf, it stores key, value and key hash. The path is
1591cb0ef41Sopenharmony_ci// defined by the hash bits of the focused leaf. In a traditional tree
1601cb0ef41Sopenharmony_ci// datastructure, the nodes of a path form a linked list with the values being
1611cb0ef41Sopenharmony_ci// the pointers outside of this path. Instead of storing all of these nodes,
1621cb0ef41Sopenharmony_ci// we store an array of the pointers pointing outside of the path. This is
1631cb0ef41Sopenharmony_ci// similar to the stack used when doing DFS traversal of a tree. The hash of
1641cb0ef41Sopenharmony_ci// the leaf is used to know if the pointers point to the left or the
1651cb0ef41Sopenharmony_ci// right of the path. As there is no explicit representation of a tree node,
1661cb0ef41Sopenharmony_ci// this structure also represents all the nodes on its path. The intended node
1671cb0ef41Sopenharmony_ci// depends on the tree depth, which is always clear from the referencing
1681cb0ef41Sopenharmony_ci// context. So the pointer to a {FocusedTree} stored in the
1691cb0ef41Sopenharmony_ci// {PersistentMap.tree_} always references the root, while a pointer from a
1701cb0ef41Sopenharmony_ci// focused node of another {FocusedTree} always references to one tree level
1711cb0ef41Sopenharmony_ci// lower than before.
1721cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher>
1731cb0ef41Sopenharmony_cistruct PersistentMap<Key, Value, Hasher>::FocusedTree {
1741cb0ef41Sopenharmony_ci  KeyValue key_value;
1751cb0ef41Sopenharmony_ci  // The depth of the focused path, that is, the number of pointers stored in
1761cb0ef41Sopenharmony_ci  // this structure.
1771cb0ef41Sopenharmony_ci  int8_t length;
1781cb0ef41Sopenharmony_ci  HashValue key_hash;
1791cb0ef41Sopenharmony_ci  // Out-of-line storage for hash collisions.
1801cb0ef41Sopenharmony_ci  const ZoneMap<Key, Value>* more;
1811cb0ef41Sopenharmony_ci  using more_iterator = typename ZoneMap<Key, Value>::const_iterator;
1821cb0ef41Sopenharmony_ci  // {path_array} has to be the last member: To store an array inline, we
1831cb0ef41Sopenharmony_ci  // over-allocate memory for this structure and access memory beyond
1841cb0ef41Sopenharmony_ci  // {path_array}. This corresponds to a flexible array member as defined in
1851cb0ef41Sopenharmony_ci  // C99.
1861cb0ef41Sopenharmony_ci  const FocusedTree* path_array[1];
1871cb0ef41Sopenharmony_ci  const FocusedTree*& path(int i) {
1881cb0ef41Sopenharmony_ci    DCHECK(i < length);
1891cb0ef41Sopenharmony_ci    return reinterpret_cast<const FocusedTree**>(
1901cb0ef41Sopenharmony_ci        reinterpret_cast<byte*>(this) + offsetof(FocusedTree, path_array))[i];
1911cb0ef41Sopenharmony_ci  }
1921cb0ef41Sopenharmony_ci  const FocusedTree* path(int i) const {
1931cb0ef41Sopenharmony_ci    DCHECK(i < length);
1941cb0ef41Sopenharmony_ci    return reinterpret_cast<const FocusedTree* const*>(
1951cb0ef41Sopenharmony_ci        reinterpret_cast<const byte*>(this) +
1961cb0ef41Sopenharmony_ci        offsetof(FocusedTree, path_array))[i];
1971cb0ef41Sopenharmony_ci  }
1981cb0ef41Sopenharmony_ci};
1991cb0ef41Sopenharmony_ci
2001cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher>
2011cb0ef41Sopenharmony_ciclass PersistentMap<Key, Value, Hasher>::HashValue {
2021cb0ef41Sopenharmony_ci public:
2031cb0ef41Sopenharmony_ci  explicit HashValue(size_t hash) : bits_(static_cast<uint32_t>(hash)) {}
2041cb0ef41Sopenharmony_ci
2051cb0ef41Sopenharmony_ci  Bit operator[](int pos) const {
2061cb0ef41Sopenharmony_ci    DCHECK_LT(pos, kHashBits);
2071cb0ef41Sopenharmony_ci    return bits_ & (static_cast<decltype(bits_)>(1) << (kHashBits - pos - 1))
2081cb0ef41Sopenharmony_ci               ? kRight
2091cb0ef41Sopenharmony_ci               : kLeft;
2101cb0ef41Sopenharmony_ci  }
2111cb0ef41Sopenharmony_ci
2121cb0ef41Sopenharmony_ci  bool operator<(HashValue other) const { return bits_ < other.bits_; }
2131cb0ef41Sopenharmony_ci  bool operator==(HashValue other) const { return bits_ == other.bits_; }
2141cb0ef41Sopenharmony_ci  bool operator!=(HashValue other) const { return bits_ != other.bits_; }
2151cb0ef41Sopenharmony_ci  HashValue operator^(HashValue other) const {
2161cb0ef41Sopenharmony_ci    return HashValue(bits_ ^ other.bits_);
2171cb0ef41Sopenharmony_ci  }
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_ci private:
2201cb0ef41Sopenharmony_ci  static_assert(sizeof(uint32_t) * 8 == kHashBits, "wrong type for bits_");
2211cb0ef41Sopenharmony_ci  uint32_t bits_;
2221cb0ef41Sopenharmony_ci};
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher>
2251cb0ef41Sopenharmony_ciclass PersistentMap<Key, Value, Hasher>::iterator {
2261cb0ef41Sopenharmony_ci public:
2271cb0ef41Sopenharmony_ci  const value_type operator*() const {
2281cb0ef41Sopenharmony_ci    if (current_->more) {
2291cb0ef41Sopenharmony_ci      return *more_iter_;
2301cb0ef41Sopenharmony_ci    } else {
2311cb0ef41Sopenharmony_ci      return current_->key_value;
2321cb0ef41Sopenharmony_ci    }
2331cb0ef41Sopenharmony_ci  }
2341cb0ef41Sopenharmony_ci
2351cb0ef41Sopenharmony_ci  iterator& operator++() {
2361cb0ef41Sopenharmony_ci    do {
2371cb0ef41Sopenharmony_ci      if (!current_) {
2381cb0ef41Sopenharmony_ci        // Iterator is past the end.
2391cb0ef41Sopenharmony_ci        return *this;
2401cb0ef41Sopenharmony_ci      }
2411cb0ef41Sopenharmony_ci      if (current_->more) {
2421cb0ef41Sopenharmony_ci        DCHECK(more_iter_ != current_->more->end());
2431cb0ef41Sopenharmony_ci        ++more_iter_;
2441cb0ef41Sopenharmony_ci        if (more_iter_ != current_->more->end()) return *this;
2451cb0ef41Sopenharmony_ci      }
2461cb0ef41Sopenharmony_ci      if (level_ == 0) {
2471cb0ef41Sopenharmony_ci        *this = end(def_value_);
2481cb0ef41Sopenharmony_ci        return *this;
2491cb0ef41Sopenharmony_ci      }
2501cb0ef41Sopenharmony_ci      --level_;
2511cb0ef41Sopenharmony_ci      while (current_->key_hash[level_] == kRight || path_[level_] == nullptr) {
2521cb0ef41Sopenharmony_ci        if (level_ == 0) {
2531cb0ef41Sopenharmony_ci          *this = end(def_value_);
2541cb0ef41Sopenharmony_ci          return *this;
2551cb0ef41Sopenharmony_ci        }
2561cb0ef41Sopenharmony_ci        --level_;
2571cb0ef41Sopenharmony_ci      }
2581cb0ef41Sopenharmony_ci      const FocusedTree* first_right_alternative = path_[level_];
2591cb0ef41Sopenharmony_ci      level_++;
2601cb0ef41Sopenharmony_ci      current_ = FindLeftmost(first_right_alternative, &level_, &path_);
2611cb0ef41Sopenharmony_ci      if (current_->more) {
2621cb0ef41Sopenharmony_ci        more_iter_ = current_->more->begin();
2631cb0ef41Sopenharmony_ci      }
2641cb0ef41Sopenharmony_ci    } while (!((**this).second != def_value()));
2651cb0ef41Sopenharmony_ci    return *this;
2661cb0ef41Sopenharmony_ci  }
2671cb0ef41Sopenharmony_ci
2681cb0ef41Sopenharmony_ci  bool operator==(const iterator& other) const {
2691cb0ef41Sopenharmony_ci    if (is_end()) return other.is_end();
2701cb0ef41Sopenharmony_ci    if (other.is_end()) return false;
2711cb0ef41Sopenharmony_ci    if (current_->key_hash != other.current_->key_hash) {
2721cb0ef41Sopenharmony_ci      return false;
2731cb0ef41Sopenharmony_ci    } else {
2741cb0ef41Sopenharmony_ci      return (**this).first == (*other).first;
2751cb0ef41Sopenharmony_ci    }
2761cb0ef41Sopenharmony_ci  }
2771cb0ef41Sopenharmony_ci  bool operator!=(const iterator& other) const { return !(*this == other); }
2781cb0ef41Sopenharmony_ci
2791cb0ef41Sopenharmony_ci  bool operator<(const iterator& other) const {
2801cb0ef41Sopenharmony_ci    if (is_end()) return false;
2811cb0ef41Sopenharmony_ci    if (other.is_end()) return true;
2821cb0ef41Sopenharmony_ci    if (current_->key_hash == other.current_->key_hash) {
2831cb0ef41Sopenharmony_ci      return (**this).first < (*other).first;
2841cb0ef41Sopenharmony_ci    } else {
2851cb0ef41Sopenharmony_ci      return current_->key_hash < other.current_->key_hash;
2861cb0ef41Sopenharmony_ci    }
2871cb0ef41Sopenharmony_ci  }
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_ci  bool is_end() const { return current_ == nullptr; }
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci  const Value& def_value() { return def_value_; }
2921cb0ef41Sopenharmony_ci
2931cb0ef41Sopenharmony_ci  static iterator begin(const FocusedTree* tree, Value def_value) {
2941cb0ef41Sopenharmony_ci    iterator i(def_value);
2951cb0ef41Sopenharmony_ci    i.current_ = FindLeftmost(tree, &i.level_, &i.path_);
2961cb0ef41Sopenharmony_ci    if (i.current_->more) {
2971cb0ef41Sopenharmony_ci      i.more_iter_ = i.current_->more->begin();
2981cb0ef41Sopenharmony_ci    }
2991cb0ef41Sopenharmony_ci    // Skip entries with default value. PersistentMap iterators must never point
3001cb0ef41Sopenharmony_ci    // to a default value.
3011cb0ef41Sopenharmony_ci    while (!i.is_end() && !((*i).second != def_value)) ++i;
3021cb0ef41Sopenharmony_ci    return i;
3031cb0ef41Sopenharmony_ci  }
3041cb0ef41Sopenharmony_ci
3051cb0ef41Sopenharmony_ci  static iterator end(Value def_value) { return iterator(def_value); }
3061cb0ef41Sopenharmony_ci
3071cb0ef41Sopenharmony_ci private:
3081cb0ef41Sopenharmony_ci  int level_;
3091cb0ef41Sopenharmony_ci  typename FocusedTree::more_iterator more_iter_;
3101cb0ef41Sopenharmony_ci  const FocusedTree* current_;
3111cb0ef41Sopenharmony_ci  std::array<const FocusedTree*, kHashBits> path_;
3121cb0ef41Sopenharmony_ci  Value def_value_;
3131cb0ef41Sopenharmony_ci
3141cb0ef41Sopenharmony_ci  explicit iterator(Value def_value)
3151cb0ef41Sopenharmony_ci      : level_(0), current_(nullptr), def_value_(def_value) {}
3161cb0ef41Sopenharmony_ci};
3171cb0ef41Sopenharmony_ci
3181cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher>
3191cb0ef41Sopenharmony_ciclass PersistentMap<Key, Value, Hasher>::double_iterator {
3201cb0ef41Sopenharmony_ci public:
3211cb0ef41Sopenharmony_ci  std::tuple<Key, Value, Value> operator*() {
3221cb0ef41Sopenharmony_ci    if (first_current_) {
3231cb0ef41Sopenharmony_ci      auto pair = *first_;
3241cb0ef41Sopenharmony_ci      return std::make_tuple(
3251cb0ef41Sopenharmony_ci          pair.first, pair.second,
3261cb0ef41Sopenharmony_ci          second_current_ ? (*second_).second : second_.def_value());
3271cb0ef41Sopenharmony_ci    } else {
3281cb0ef41Sopenharmony_ci      DCHECK(second_current_);
3291cb0ef41Sopenharmony_ci      auto pair = *second_;
3301cb0ef41Sopenharmony_ci      return std::make_tuple(pair.first, first_.def_value(), pair.second);
3311cb0ef41Sopenharmony_ci    }
3321cb0ef41Sopenharmony_ci  }
3331cb0ef41Sopenharmony_ci
3341cb0ef41Sopenharmony_ci  double_iterator& operator++() {
3351cb0ef41Sopenharmony_ci#ifdef DEBUG
3361cb0ef41Sopenharmony_ci    iterator old_first = first_;
3371cb0ef41Sopenharmony_ci    iterator old_second = second_;
3381cb0ef41Sopenharmony_ci#endif
3391cb0ef41Sopenharmony_ci    if (first_current_) {
3401cb0ef41Sopenharmony_ci      ++first_;
3411cb0ef41Sopenharmony_ci      DCHECK(old_first < first_);
3421cb0ef41Sopenharmony_ci    }
3431cb0ef41Sopenharmony_ci    if (second_current_) {
3441cb0ef41Sopenharmony_ci      ++second_;
3451cb0ef41Sopenharmony_ci      DCHECK(old_second < second_);
3461cb0ef41Sopenharmony_ci    }
3471cb0ef41Sopenharmony_ci    return *this = double_iterator(first_, second_);
3481cb0ef41Sopenharmony_ci  }
3491cb0ef41Sopenharmony_ci
3501cb0ef41Sopenharmony_ci  double_iterator(iterator first, iterator second)
3511cb0ef41Sopenharmony_ci      : first_(first), second_(second) {
3521cb0ef41Sopenharmony_ci    if (first_ == second_) {
3531cb0ef41Sopenharmony_ci      first_current_ = second_current_ = true;
3541cb0ef41Sopenharmony_ci    } else if (first_ < second_) {
3551cb0ef41Sopenharmony_ci      first_current_ = true;
3561cb0ef41Sopenharmony_ci      second_current_ = false;
3571cb0ef41Sopenharmony_ci    } else {
3581cb0ef41Sopenharmony_ci      DCHECK(second_ < first_);
3591cb0ef41Sopenharmony_ci      first_current_ = false;
3601cb0ef41Sopenharmony_ci      second_current_ = true;
3611cb0ef41Sopenharmony_ci    }
3621cb0ef41Sopenharmony_ci  }
3631cb0ef41Sopenharmony_ci
3641cb0ef41Sopenharmony_ci  bool operator!=(const double_iterator& other) {
3651cb0ef41Sopenharmony_ci    return first_ != other.first_ || second_ != other.second_;
3661cb0ef41Sopenharmony_ci  }
3671cb0ef41Sopenharmony_ci
3681cb0ef41Sopenharmony_ci  bool is_end() const { return first_.is_end() && second_.is_end(); }
3691cb0ef41Sopenharmony_ci
3701cb0ef41Sopenharmony_ci private:
3711cb0ef41Sopenharmony_ci  iterator first_;
3721cb0ef41Sopenharmony_ci  iterator second_;
3731cb0ef41Sopenharmony_ci  bool first_current_;
3741cb0ef41Sopenharmony_ci  bool second_current_;
3751cb0ef41Sopenharmony_ci};
3761cb0ef41Sopenharmony_ci
3771cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher>
3781cb0ef41Sopenharmony_civoid PersistentMap<Key, Value, Hasher>::Set(Key key, Value value) {
3791cb0ef41Sopenharmony_ci  HashValue key_hash = HashValue(Hasher()(key));
3801cb0ef41Sopenharmony_ci  std::array<const FocusedTree*, kHashBits> path;
3811cb0ef41Sopenharmony_ci  int length = 0;
3821cb0ef41Sopenharmony_ci  const FocusedTree* old = FindHash(key_hash, &path, &length);
3831cb0ef41Sopenharmony_ci  ZoneMap<Key, Value>* more = nullptr;
3841cb0ef41Sopenharmony_ci  if (!(GetFocusedValue(old, key) != value)) return;
3851cb0ef41Sopenharmony_ci  if (old && !(old->more == nullptr && old->key_value.key() == key)) {
3861cb0ef41Sopenharmony_ci    more = zone_->New<ZoneMap<Key, Value>>(zone_);
3871cb0ef41Sopenharmony_ci    if (old->more) {
3881cb0ef41Sopenharmony_ci      *more = *old->more;
3891cb0ef41Sopenharmony_ci    } else {
3901cb0ef41Sopenharmony_ci      more->erase(old->key_value.key());
3911cb0ef41Sopenharmony_ci      more->emplace(old->key_value.key(), old->key_value.value());
3921cb0ef41Sopenharmony_ci    }
3931cb0ef41Sopenharmony_ci    more->erase(key);
3941cb0ef41Sopenharmony_ci    more->emplace(key, value);
3951cb0ef41Sopenharmony_ci  }
3961cb0ef41Sopenharmony_ci  size_t size = sizeof(FocusedTree) +
3971cb0ef41Sopenharmony_ci                std::max(0, length - 1) * sizeof(const FocusedTree*);
3981cb0ef41Sopenharmony_ci  FocusedTree* tree = new (zone_->Allocate<FocusedTree>(size))
3991cb0ef41Sopenharmony_ci      FocusedTree{KeyValue(std::move(key), std::move(value)),
4001cb0ef41Sopenharmony_ci                  static_cast<int8_t>(length),
4011cb0ef41Sopenharmony_ci                  key_hash,
4021cb0ef41Sopenharmony_ci                  more,
4031cb0ef41Sopenharmony_ci                  {}};
4041cb0ef41Sopenharmony_ci  for (int i = 0; i < length; ++i) {
4051cb0ef41Sopenharmony_ci    tree->path(i) = path[i];
4061cb0ef41Sopenharmony_ci  }
4071cb0ef41Sopenharmony_ci  *this = PersistentMap(tree, zone_, def_value_);
4081cb0ef41Sopenharmony_ci}
4091cb0ef41Sopenharmony_ci
4101cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher>
4111cb0ef41Sopenharmony_ciconst typename PersistentMap<Key, Value, Hasher>::FocusedTree*
4121cb0ef41Sopenharmony_ciPersistentMap<Key, Value, Hasher>::FindHash(HashValue hash) const {
4131cb0ef41Sopenharmony_ci  const FocusedTree* tree = tree_;
4141cb0ef41Sopenharmony_ci  int level = 0;
4151cb0ef41Sopenharmony_ci  while (tree && hash != tree->key_hash) {
4161cb0ef41Sopenharmony_ci    while ((hash ^ tree->key_hash)[level] == 0) {
4171cb0ef41Sopenharmony_ci      ++level;
4181cb0ef41Sopenharmony_ci    }
4191cb0ef41Sopenharmony_ci    tree = level < tree->length ? tree->path(level) : nullptr;
4201cb0ef41Sopenharmony_ci    ++level;
4211cb0ef41Sopenharmony_ci  }
4221cb0ef41Sopenharmony_ci  return tree;
4231cb0ef41Sopenharmony_ci}
4241cb0ef41Sopenharmony_ci
4251cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher>
4261cb0ef41Sopenharmony_ciconst typename PersistentMap<Key, Value, Hasher>::FocusedTree*
4271cb0ef41Sopenharmony_ciPersistentMap<Key, Value, Hasher>::FindHash(
4281cb0ef41Sopenharmony_ci    HashValue hash, std::array<const FocusedTree*, kHashBits>* path,
4291cb0ef41Sopenharmony_ci    int* length) const {
4301cb0ef41Sopenharmony_ci  const FocusedTree* tree = tree_;
4311cb0ef41Sopenharmony_ci  int level = 0;
4321cb0ef41Sopenharmony_ci  while (tree && hash != tree->key_hash) {
4331cb0ef41Sopenharmony_ci    int map_length = tree->length;
4341cb0ef41Sopenharmony_ci    while ((hash ^ tree->key_hash)[level] == 0) {
4351cb0ef41Sopenharmony_ci      (*path)[level] = level < map_length ? tree->path(level) : nullptr;
4361cb0ef41Sopenharmony_ci      ++level;
4371cb0ef41Sopenharmony_ci    }
4381cb0ef41Sopenharmony_ci    (*path)[level] = tree;
4391cb0ef41Sopenharmony_ci    tree = level < tree->length ? tree->path(level) : nullptr;
4401cb0ef41Sopenharmony_ci    ++level;
4411cb0ef41Sopenharmony_ci  }
4421cb0ef41Sopenharmony_ci  if (tree) {
4431cb0ef41Sopenharmony_ci    while (level < tree->length) {
4441cb0ef41Sopenharmony_ci      (*path)[level] = tree->path(level);
4451cb0ef41Sopenharmony_ci      ++level;
4461cb0ef41Sopenharmony_ci    }
4471cb0ef41Sopenharmony_ci  }
4481cb0ef41Sopenharmony_ci  *length = level;
4491cb0ef41Sopenharmony_ci  return tree;
4501cb0ef41Sopenharmony_ci}
4511cb0ef41Sopenharmony_ci
4521cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher>
4531cb0ef41Sopenharmony_ciconst Value& PersistentMap<Key, Value, Hasher>::GetFocusedValue(
4541cb0ef41Sopenharmony_ci    const FocusedTree* tree, const Key& key) const {
4551cb0ef41Sopenharmony_ci  if (!tree) {
4561cb0ef41Sopenharmony_ci    return def_value_;
4571cb0ef41Sopenharmony_ci  }
4581cb0ef41Sopenharmony_ci  if (tree->more) {
4591cb0ef41Sopenharmony_ci    auto it = tree->more->find(key);
4601cb0ef41Sopenharmony_ci    if (it == tree->more->end())
4611cb0ef41Sopenharmony_ci      return def_value_;
4621cb0ef41Sopenharmony_ci    else
4631cb0ef41Sopenharmony_ci      return it->second;
4641cb0ef41Sopenharmony_ci  } else {
4651cb0ef41Sopenharmony_ci    if (key == tree->key_value.key()) {
4661cb0ef41Sopenharmony_ci      return tree->key_value.value();
4671cb0ef41Sopenharmony_ci    } else {
4681cb0ef41Sopenharmony_ci      return def_value_;
4691cb0ef41Sopenharmony_ci    }
4701cb0ef41Sopenharmony_ci  }
4711cb0ef41Sopenharmony_ci}
4721cb0ef41Sopenharmony_ci
4731cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher>
4741cb0ef41Sopenharmony_ciconst typename PersistentMap<Key, Value, Hasher>::FocusedTree*
4751cb0ef41Sopenharmony_ciPersistentMap<Key, Value, Hasher>::GetChild(const FocusedTree* tree, int level,
4761cb0ef41Sopenharmony_ci                                            Bit bit) {
4771cb0ef41Sopenharmony_ci  if (tree->key_hash[level] == bit) {
4781cb0ef41Sopenharmony_ci    return tree;
4791cb0ef41Sopenharmony_ci  } else if (level < tree->length) {
4801cb0ef41Sopenharmony_ci    return tree->path(level);
4811cb0ef41Sopenharmony_ci  } else {
4821cb0ef41Sopenharmony_ci    return nullptr;
4831cb0ef41Sopenharmony_ci  }
4841cb0ef41Sopenharmony_ci}
4851cb0ef41Sopenharmony_ci
4861cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher>
4871cb0ef41Sopenharmony_ciconst typename PersistentMap<Key, Value, Hasher>::FocusedTree*
4881cb0ef41Sopenharmony_ciPersistentMap<Key, Value, Hasher>::FindLeftmost(
4891cb0ef41Sopenharmony_ci    const FocusedTree* start, int* level,
4901cb0ef41Sopenharmony_ci    std::array<const FocusedTree*, kHashBits>* path) {
4911cb0ef41Sopenharmony_ci  const FocusedTree* current = start;
4921cb0ef41Sopenharmony_ci  while (*level < current->length) {
4931cb0ef41Sopenharmony_ci    if (const FocusedTree* left_child = GetChild(current, *level, kLeft)) {
4941cb0ef41Sopenharmony_ci      (*path)[*level] = GetChild(current, *level, kRight);
4951cb0ef41Sopenharmony_ci      current = left_child;
4961cb0ef41Sopenharmony_ci      ++*level;
4971cb0ef41Sopenharmony_ci    } else if (const FocusedTree* right_child =
4981cb0ef41Sopenharmony_ci                   GetChild(current, *level, kRight)) {
4991cb0ef41Sopenharmony_ci      (*path)[*level] = GetChild(current, *level, kLeft);
5001cb0ef41Sopenharmony_ci      current = right_child;
5011cb0ef41Sopenharmony_ci      ++*level;
5021cb0ef41Sopenharmony_ci    } else {
5031cb0ef41Sopenharmony_ci      UNREACHABLE();
5041cb0ef41Sopenharmony_ci    }
5051cb0ef41Sopenharmony_ci  }
5061cb0ef41Sopenharmony_ci  return current;
5071cb0ef41Sopenharmony_ci}
5081cb0ef41Sopenharmony_ci
5091cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher>
5101cb0ef41Sopenharmony_cistd::ostream& operator<<(std::ostream& os,
5111cb0ef41Sopenharmony_ci                         const PersistentMap<Key, Value, Hasher>& map) {
5121cb0ef41Sopenharmony_ci  os << "{";
5131cb0ef41Sopenharmony_ci  bool first = true;
5141cb0ef41Sopenharmony_ci  for (auto pair : map) {
5151cb0ef41Sopenharmony_ci    if (!first) os << ", ";
5161cb0ef41Sopenharmony_ci    first = false;
5171cb0ef41Sopenharmony_ci    os << pair.first << ": " << pair.second;
5181cb0ef41Sopenharmony_ci  }
5191cb0ef41Sopenharmony_ci  return os << "}";
5201cb0ef41Sopenharmony_ci}
5211cb0ef41Sopenharmony_ci
5221cb0ef41Sopenharmony_ci}  // namespace compiler
5231cb0ef41Sopenharmony_ci}  // namespace internal
5241cb0ef41Sopenharmony_ci}  // namespace v8
5251cb0ef41Sopenharmony_ci
5261cb0ef41Sopenharmony_ci#endif  // V8_COMPILER_PERSISTENT_MAP_H_
527