summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/turboshaft/snapshot-table.h
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/turboshaft/snapshot-table.h')
-rw-r--r--deps/v8/src/compiler/turboshaft/snapshot-table.h190
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