summaryrefslogtreecommitdiff
path: root/src/analysis
diff options
context:
space:
mode:
Diffstat (limited to 'src/analysis')
-rw-r--r--src/analysis/lattices/shared.h126
1 files changed, 126 insertions, 0 deletions
diff --git a/src/analysis/lattices/shared.h b/src/analysis/lattices/shared.h
new file mode 100644
index 000000000..489ed0003
--- /dev/null
+++ b/src/analysis/lattices/shared.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2023 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef wasm_analysis_lattices_shared_h
+#define wasm_analysis_lattices_shared_h
+
+#include <cstdint>
+#include <utility>
+
+#include "../lattice.h"
+#include "bool.h"
+
+namespace wasm::analysis {
+
+// A lattice whose elements are a single ascending chain in lattice `L`.
+// Internally, there is only ever a single monotonically increasing element of L
+// materialized. Dereferencing any element of the Shared lattice will produce
+// the current value of that single element of L, which is generally safe
+// because the current value always overapproximates (i.e. is higher in the
+// lattice than) the value at the time of the Shared element's construction.
+//
+// Each element of this lattice maintains a sequence number that corresponds to
+// a value the shared underlying element has had at some point in time. Higher
+// sequence numbers correspond to greater values of the underlying element.
+// Elements of this lattice are compared and joined using these sequence
+// numbers, so blocks will correctly be re-analyzed if the value has increased
+// since the last time they were analyzed.
+template<Lattice L> struct Shared {
+ // If we ever have extremely long-running analyses, this may need to be
+ // changed to uint64_t.
+ using Seq = uint32_t;
+
+ class Element {
+ const typename L::Element* val;
+ Seq seq = 0;
+
+ Element(const typename L::Element* val) : val(val) {}
+
+ public:
+ Element() = default;
+ Element(const Element&) = default;
+ Element(Element&&) = default;
+ Element& operator=(const Element&) = default;
+ Element& operator=(Element&&) = default;
+
+ // Only provide const references to the value to force all updates to go
+ // through our API.
+ const typename L::Element& operator*() const noexcept { return *val; }
+ const typename L::Element* operator->() const noexcept { return val; }
+
+ bool operator==(const Element& other) const noexcept {
+ assert(val == other.val);
+ return seq == other.seq;
+ }
+
+ bool operator!=(const Element& other) const noexcept {
+ return !(*this == other);
+ }
+
+ friend Shared;
+ };
+
+ L lattice;
+
+ // The current value that all elements point to and the current maximum
+ // sequence number. The sequence numbers monotonically increase along with
+ // `val` and serve to provide ordering between elements of this lattice. These
+ // are mutable because they are logically not part of the lattice itself, but
+ // rather of its elements. They are only stored inside the lattice because it
+ // is simpler and more efficient than using shared pointers.
+ mutable typename L::Element val;
+ mutable Seq seq = 0;
+
+ Shared(L&& l) : lattice(std::move(l)), val(lattice.getBottom()) {}
+
+ // TODO: Delete the move constructor and the move assignment operator. This
+ // requires fixing the lattice fuzzer first, since it depends on lattices
+ // being moveable.
+
+ Element getBottom() const noexcept { return Element{&val}; }
+
+ LatticeComparison compare(const Element& a, const Element& b) const noexcept {
+ assert(a.val == b.val);
+ return a.seq < b.seq ? LESS : a.seq == b.seq ? EQUAL : GREATER;
+ }
+
+ bool join(Element& joinee, const Element& joiner) const noexcept {
+ assert(joinee.val == joiner.val);
+ if (joinee.seq < joiner.seq) {
+ joinee.seq = joiner.seq;
+ return true;
+ }
+ return false;
+ }
+
+ bool join(Element& joinee, const typename L::Element& joiner) const noexcept {
+ if (lattice.join(val, joiner)) {
+ // We have moved to the next value in our ascending chain. Assign it a new
+ // sequence number and update joinee with that sequence number.
+ joinee.seq = ++seq;
+ return true;
+ }
+ return false;
+ }
+};
+
+#if __cplusplus >= 202002L
+static_assert(Lattice<Shared<Bool>>);
+#endif // __cplusplus >= 202002L
+
+} // namespace wasm::analysis
+
+#endif // wasm_analysis_lattices_shared_h