diff options
Diffstat (limited to 'deps/v8/src/compiler/turboshaft/snapshot-table.h')
-rw-r--r-- | deps/v8/src/compiler/turboshaft/snapshot-table.h | 190 |
1 files changed, 98 insertions, 92 deletions
diff --git a/deps/v8/src/compiler/turboshaft/snapshot-table.h b/deps/v8/src/compiler/turboshaft/snapshot-table.h index 2a4b8c3eb2..8a8447c07e 100644 --- a/deps/v8/src/compiler/turboshaft/snapshot-table.h +++ b/deps/v8/src/compiler/turboshaft/snapshot-table.h @@ -18,14 +18,16 @@ // similar snapshots with a closeby common ancestor. // // Complexity: -// creating a scope linear in the number of `Set` operations between the -// current state and the common ancestor of all -// predecessors and the current state, plus the `Set` -// operations from the common ancestor to all predecessors. -// Scope::Get() O(1) -// Scope::Set() O(1) + operator== for Value -// Scope::Seal() O(1) -// NewKey() O(1) +// creating a snapshot linear in the number of `Set` operations between the +// current state and the common ancestor of all +// predecessors and the current state, plus the `Set` +// operations from the common ancestor to all +// predecessors. +// Get() O(1) +// Set() O(1) + operator== for Value +// Seal() O(1) +// NewKey() O(1) +// GetPredecessorValue() O(1) namespace v8::internal::compiler::turboshaft { struct NoKeyData {}; @@ -55,8 +57,7 @@ class SnapshotTable { explicit Key(TableEntry& entry) : entry_(&entry) {} }; - // A `Snapshot` captures the state of the `SnapshotTable`. Using a `Scope`, - // the state of the table can be reset to a given snapshot. + // A `Snapshot` captures the state of the `SnapshotTable`. // A `Snapshot` is implemented as a pointer to internal data and is therefore // cheap to copy. class Snapshot { @@ -69,77 +70,84 @@ class SnapshotTable { explicit Snapshot(SnapshotData& data) : data_(&data) {} }; - // All modifications to the table need to be performed through a `Scope`. - // There can only be a single active scope for a table at a time. A new scope - // is based on a list of predecessor snapshots. If no predecessor is given, - // the scope is based on the initial state of the table. A single predecessor - // snapshot resets the table to exactly this snapshot. In the case of multiple - // snapshots, a merge function is used to unify values that were set since the - // last common ancestor snapshot. - // The previous scope needs to be closed using Seal() before another one can - // be created. - class Scope { - public: - // These overloads move to a new snapshot based on the common ancestor, - // without merging different values from the predecessors. - Scope(SnapshotTable& table, base::Vector<const Snapshot> predecessors) - : snapshot_table_(table), - snapshot_(&table.MoveToNewSnapshot(predecessors)) {} - explicit Scope(SnapshotTable& table, - std::initializer_list<Snapshot> predecessors = {}) - : Scope(table, base::VectorOf(predecessors)) {} - Scope(SnapshotTable& table, Snapshot parent) : Scope(table, {parent}) {} - // These overloads merge different values from the predecessors using the - // given function. - template <class F> - Scope(SnapshotTable& table, base::Vector<const Snapshot> predecessors, - F merge_fun) - : Scope(table, predecessors) { - table.MergePredecessors(predecessors, merge_fun); - } - template <class F> - Scope(SnapshotTable& table, std::initializer_list<Snapshot> predecessors, - F merge_fun) - : Scope(table, base::VectorOf(predecessors), merge_fun) {} - - Scope(const Scope&) = delete; - Scope& operator=(const Scope&) = delete; - - const Value& Get(Key key) { - DCHECK_EQ(snapshot_, snapshot_table_.current_snapshot_); - return key.entry_->value; - } + // A new Snapshot is based on a list of predecessor Snapshots. If no + // predecessor is given, the new Snapshot is based on the initial state of the + // table. A single predecessor Snapshot resets the table to exactly this + // Snapshot. In the case of multiple Snapshots, a merge function is used to + // unify values that were set since the last common ancestor snapshot. + // The previous Snapshot needs to be closed using Seal() before another one + // can be created. + void StartNewSnapshot(base::Vector<const Snapshot> predecessors) { + DCHECK(current_snapshot_->IsSealed()); + MoveToNewSnapshot(predecessors); +#ifdef DEBUG + snapshot_was_created_with_merge = false; +#endif + } + void StartNewSnapshot(std::initializer_list<Snapshot> predecessors = {}) { + StartNewSnapshot(base::VectorOf(predecessors)); + } + void StartNewSnapshot(Snapshot parent) { StartNewSnapshot({parent}); } + template <class F> + void StartNewSnapshot(base::Vector<const Snapshot> predecessors, + F merge_fun) { + StartNewSnapshot(predecessors); + MergePredecessors(predecessors, merge_fun); +#ifdef DEBUG + snapshot_was_created_with_merge = true; +#endif + } + template <class F> + void StartNewSnapshot(std::initializer_list<Snapshot> predecessors, + F merge_fun) { + StartNewSnapshot(base::VectorOf(predecessors), merge_fun); + } - void Set(Key key, Value new_value) { - DCHECK(!snapshot_->IsSealed()); - snapshot_table_.Set(key, new_value); + Snapshot Seal() { + current_snapshot_->Seal(log_.size()); + // Reseting the entries' `merge_offset` and `last_merged_predecessor` + // fields, so that they are cleared for the next Merge. + for (TableEntry* entry : merging_entries_) { + entry->last_merged_predecessor = kNoMergedPredecessor; + entry->merge_offset = kNoMergeOffset; } - - // Sealing the current scope means that no more modifications are possible. - // Produces a new snapshot which represents the current state. - Snapshot Seal() { - snapshot_->Seal(snapshot_table_.log_.size()); - // Optimization: If nothing changed in the new snapshot, we discard it and - // use its parent instead. - if (snapshot_->log_begin == snapshot_->log_end) { - SnapshotData* parent = snapshot_->parent; - snapshot_table_.current_snapshot_ = parent; - DCHECK_EQ(snapshot_, &snapshot_table_.snapshots_.back()); - snapshot_table_.snapshots_.pop_back(); - return Snapshot{*parent}; - } - return Snapshot{*snapshot_}; + merge_values_.clear(); + merging_entries_.clear(); + + // Optimization: If nothing changed in the new snapshot, we discard it and + // use its parent instead. + if (current_snapshot_->log_begin == current_snapshot_->log_end) { + SnapshotData* parent = current_snapshot_->parent; + DCHECK_EQ(current_snapshot_, &snapshots_.back()); + snapshots_.pop_back(); + current_snapshot_ = parent; + return Snapshot{*parent}; } + return Snapshot{*current_snapshot_}; + } - ~Scope() { - // Seal() should have been used to obtain the new snapshot. - DCHECK(snapshot_->IsSealed()); - } + const Value& Get(Key key) { return key.entry_->value; } + + // Returns the value associated to {key} in its {predecessor_index}th + // predecessor (where "predecessor" refers to the predecessors that were + // passed to StartNewSnapshot when creating the current snapshot). + // This function should only be used if the snapshot was started with a merge + // function. + // If {key} wasn't merged but was Set in the current snapshot, then + // the newly set value will be returned rather than the predecessor value. + const Value& GetPredecessorValue(Key key, int predecessor_index) { + DCHECK(!current_snapshot_->IsSealed()); + DCHECK(snapshot_was_created_with_merge); + if (key.entry_->merge_offset == kNoMergeOffset) return Get(key); + return merge_values_[key.entry_->merge_offset + predecessor_index]; + } - private: - SnapshotTable& snapshot_table_; - SnapshotData* snapshot_; - }; + void Set(Key key, Value new_value) { + DCHECK(!current_snapshot_->IsSealed()); + if (key.entry_->value == new_value) return; + log_.push_back(LogEntry{*key.entry_, key.entry_->value, new_value}); + key.entry_->value = new_value; + } explicit SnapshotTable(Zone* zone) : zone_(zone) { root_snapshot_ = &NewSnapshot(nullptr); @@ -159,6 +167,9 @@ class SnapshotTable { return NewKey(KeyData{}, initial_value); } + // Returns true if {current_snapshot_} is sealed. + bool IsSealed() { return current_snapshot_->IsSealed(); } + private: Zone* zone_; ZoneDeque<TableEntry> table_{zone_}; @@ -175,6 +186,10 @@ class SnapshotTable { ZoneVector<TableEntry*> merging_entries_{zone_}; ZoneVector<Value> merge_values_{zone_}; +#ifdef DEBUG + bool snapshot_was_created_with_merge = false; +#endif + SnapshotData& NewSnapshot(SnapshotData* parent) { return snapshots_.emplace_back(parent, log_.size()); } @@ -203,12 +218,6 @@ class SnapshotTable { current_snapshot_ = snapshot; } - void Set(Key key, Value new_value) { - if (key.entry_->value == new_value) return; - log_.push_back(LogEntry{*key.entry_, key.entry_->value, new_value}); - key.entry_->value = new_value; - } - void RecordMergeValue(TableEntry& entry, const Value& value, uint32_t predecessor_index, uint32_t predecessor_count); SnapshotData& MoveToNewSnapshot(base::Vector<const Snapshot> predecessors); @@ -226,8 +235,9 @@ class SnapshotTable { template <class Value, class KeyData> struct SnapshotTable<Value, KeyData>::TableEntry : KeyData { Value value; - // Used during merging: the offset in `merge_values_` where we store the - // merged values. + // `merge_offset` is the offset in `merge_values_` where we store the + // merged values. It is used during merging (to know what to merge) and when + // calling GetPredecessorValue. uint32_t merge_offset = kNoMergeOffset; // Used during merging: the index of the predecessor for which we last // recorded a value. This allows us to only use the last value for a given @@ -269,7 +279,7 @@ struct SnapshotTable<Value, KeyData>::SnapshotData { return self; } void Seal(size_t log_end) { - DCHECK_WITH_MSG(!IsSealed(), "A scope can only be sealed once."); + DCHECK_WITH_MSG(!IsSealed(), "A Snapshot can only be sealed once."); this->log_end = log_end; } @@ -303,7 +313,7 @@ void SnapshotTable<Value, KeyData>::RecordMergeValue( entry.last_merged_predecessor = predecessor_index; } -// This function prepares the SnapshotTable to start a new snapshot/scope whose +// This function prepares the SnapshotTable to start a new snapshot whose // predecessors are `predecessors`. To do this, it resets and replay snapshots // in between the `current_snapshot_` and the position of the new snapshot. For // instance: @@ -330,7 +340,7 @@ SnapshotTable<Value, KeyData>::MoveToNewSnapshot( base::Vector<const Snapshot> predecessors) { DCHECK_WITH_MSG( current_snapshot_->IsSealed(), - "A new scope was opened before the previous scope was sealed."); + "A new Snapshot was opened before the previous Snapshot was sealed."); SnapshotData* common_ancestor; if (predecessors.empty()) { @@ -363,7 +373,7 @@ SnapshotTable<Value, KeyData>::MoveToNewSnapshot( } // Merges all entries modified in `predecessors` since the last common ancestor -// by adding them to the current scope. +// by adding them to the current snapshot. template <class Value, class KeyData> template <class F> void SnapshotTable<Value, KeyData>::MergePredecessors( @@ -399,11 +409,7 @@ void SnapshotTable<Value, KeyData>::MergePredecessors( Key key{*entry}; Set(key, merge_fun(key, base::VectorOf(&merge_values_[entry->merge_offset], predecessor_count))); - entry->last_merged_predecessor = kNoMergedPredecessor; - entry->merge_offset = kNoMergeOffset; } - merge_values_.clear(); - merging_entries_.clear(); } } // namespace v8::internal::compiler::turboshaft |