mirror of
https://github.com/YosysHQ/yosys.git
synced 2026-10-06 01:53:53 +02:00
kernel: best-effort IdString provenance checking
This commit is contained in:
+82
-6
@@ -21,7 +21,7 @@ bool StaticTwines::ready() { return nodes_.size() == count; }
|
||||
int64_t twine_gc_ns;
|
||||
int twine_gc_count;
|
||||
|
||||
Hasher IdString::hash_into(Hasher h) const { h.hash64(value); return h; }
|
||||
Hasher IdString::hash_into(Hasher h) const { h.hash64(raw()); return h; }
|
||||
|
||||
std::string IdString::handle_token() const {
|
||||
return stringf("%s@%zu", isPublic() ? "$pub" : "$priv", untag().raw());
|
||||
@@ -53,9 +53,16 @@ std::string ID::unescaped_str(IdString ref) {
|
||||
return static_names[idx.raw()];
|
||||
}
|
||||
|
||||
Twine::Twine(Leaf v) : data(std::move(v)) {}
|
||||
Twine::Twine(Suffix v) : data(std::move(v)) {}
|
||||
Twine::Twine(AutoSuffix v) : data(std::move(v)) {}
|
||||
|
||||
bool Twine::is_leaf() const { return std::holds_alternative<Leaf>(data); }
|
||||
bool Twine::is_suffix() const { return std::holds_alternative<Suffix>(data); }
|
||||
|
||||
TwineNode::TwineNode(Twine::Leaf v) : data(std::move(v)) {}
|
||||
TwineNode::TwineNode(Twine::Suffix v) : data(std::move(v)) {}
|
||||
|
||||
bool TwineNode::is_dead() const { return std::holds_alternative<std::monostate>(data); }
|
||||
bool TwineNode::is_leaf() const { return std::holds_alternative<Twine::Leaf>(data); }
|
||||
bool TwineNode::is_suffix() const { return std::holds_alternative<Twine::Suffix>(data); }
|
||||
@@ -76,12 +83,62 @@ std::pair<std::string, bool> twine_unescape(std::string s) {
|
||||
return {std::move(s), is_public};
|
||||
}
|
||||
|
||||
TwinePool::TwinePool() : serial_(next_serial()) {}
|
||||
TwinePool::TwinePool(const TwinePool& other) : HashConsPool(other), serial_(next_serial()) {}
|
||||
TwinePool::TwinePool(TwinePool&& other) : HashConsPool(std::move(other)), serial_(next_serial()) {}
|
||||
|
||||
TwinePool& TwinePool::operator=(const TwinePool& other) {
|
||||
HashConsPool::operator=(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TwinePool& TwinePool::operator=(TwinePool&& other) {
|
||||
HashConsPool::operator=(std::move(other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t TwinePool::serial() const { return serial_; }
|
||||
|
||||
bool TwinePool::owns(IdString ref) const {
|
||||
return ref == IdString::Null || ref.serial() == 0 || ref.serial() == serial_ || ID::is_static(ref);
|
||||
}
|
||||
|
||||
IdString TwinePool::stamp(IdString ref) const {
|
||||
if (ref == IdString::Null || ID::is_static(ref))
|
||||
return ref;
|
||||
return ref.stamped(serial_);
|
||||
}
|
||||
|
||||
void TwinePool::check_owned(IdString ref) const {
|
||||
#ifndef NDEBUG
|
||||
log_assert(owns(ref));
|
||||
#endif
|
||||
}
|
||||
|
||||
const TwineNode& TwinePool::operator[](IdString ref) const {
|
||||
check_owned(ref);
|
||||
return HashConsPool::operator[](ref);
|
||||
}
|
||||
|
||||
const TwineNode& TwinePool::static_node(size_t idx) { return StaticTwines::node(idx); }
|
||||
void TwinePool::check_ready() { log_assert(StaticTwines::ready()); }
|
||||
|
||||
void TwinePool::canonicalize(TwineNode& t) {
|
||||
if (auto *sfx = std::get_if<Twine::Suffix>(&t.data))
|
||||
sfx->prefix = sfx->prefix.untag();
|
||||
sfx->prefix = sfx->prefix.untag().stamped(0);
|
||||
}
|
||||
|
||||
size_t TwinePool::next_serial() {
|
||||
static size_t counter = 0;
|
||||
size_t serial = ++counter;
|
||||
return serial > IdString::MAX_SERIAL ? (serial % IdString::MAX_SERIAL) + 1 : serial;
|
||||
}
|
||||
|
||||
IdString TwinePool::add_inner(TwineNode t) {
|
||||
if (free_list.empty() && STATIC_COUNT + backing.size() > IdString::MAX_INDEX)
|
||||
log_error("Out of twine handles: a design may name at most %zu distinct twines.\n",
|
||||
IdString::MAX_INDEX - STATIC_COUNT);
|
||||
return HashConsPool::add_inner(std::move(t));
|
||||
}
|
||||
|
||||
size_t TwinePool::hash_node(const TwineNode& t) {
|
||||
@@ -164,7 +221,7 @@ std::string TwinePool::unescaped_str(IdString ref) const {
|
||||
|
||||
IdString TwinePool::find(const std::string &name) const {
|
||||
bool is_public = !name.empty() && name[0] == '\\';
|
||||
return find(Twine::Leaf{is_public ? name.substr(1) : name}).tag(is_public);
|
||||
return stamp(find(Twine::Leaf{is_public ? name.substr(1) : name}).tag(is_public));
|
||||
}
|
||||
|
||||
IdString TwinePool::find(Twine t) const {
|
||||
@@ -175,7 +232,7 @@ IdString TwinePool::find(Twine t) const {
|
||||
t = Twine::Suffix{prefix, std::move(ap->tail)};
|
||||
}
|
||||
bool is_public = inherits_publicity(t);
|
||||
return HashConsPool::find(to_node(std::move(t))).tag(is_public);
|
||||
return stamp(HashConsPool::find(to_node(std::move(t))).tag(is_public));
|
||||
}
|
||||
|
||||
IdString TwinePool::add(Twine t) {
|
||||
@@ -184,14 +241,14 @@ IdString TwinePool::add(Twine t) {
|
||||
t = Twine::Suffix{prefix, std::move(ap->tail)};
|
||||
}
|
||||
bool is_public = inherits_publicity(t);
|
||||
return add_inner(to_node(std::move(t))).tag(is_public);
|
||||
return stamp(add_inner(to_node(std::move(t))).tag(is_public));
|
||||
}
|
||||
|
||||
IdString TwinePool::add(std::string s) {
|
||||
if (s.empty())
|
||||
return IdString::Null;
|
||||
auto [content, is_public] = twine_unescape(std::move(s));
|
||||
return add_inner(Twine::Leaf{std::move(content)}).tag(is_public);
|
||||
return stamp(add_inner(Twine::Leaf{std::move(content)}).tag(is_public));
|
||||
}
|
||||
|
||||
IdString TwinePool::copy_from(const TwinePool& src, IdString ref) {
|
||||
@@ -230,6 +287,25 @@ IdString TwinePool::find_from(const TwinePool& src, IdString ref) const {
|
||||
return IdString::Null;
|
||||
}
|
||||
|
||||
std::string TwinePool::ref_token(IdString ref) const {
|
||||
return "#" + std::to_string((uint64_t)stamp(ref).bits());
|
||||
}
|
||||
|
||||
IdString TwinePool::ref_from_token(std::string_view token) const {
|
||||
if (token.size() < 2 || token[0] != '#')
|
||||
return IdString::Null;
|
||||
size_t value = 0;
|
||||
for (char c : token.substr(1)) {
|
||||
if (c < '0' || c > '9')
|
||||
return IdString::Null;
|
||||
value = value * 10 + (c - '0');
|
||||
}
|
||||
IdString ref(value);
|
||||
if (ref == IdString::Null || (!ID::is_static(ref) && ref.serial() != serial_))
|
||||
return IdString::Null;
|
||||
return is_live(ref) ? ref : IdString::Null;
|
||||
}
|
||||
|
||||
void TwinePool::dump(std::ostream& os) const {
|
||||
os << "--- TwinePool Dump (" << backing.size() << " nodes) ---\n";
|
||||
for (size_t idx = 0; idx < backing.size(); ++idx) {
|
||||
|
||||
+52
-10
@@ -49,20 +49,42 @@ private:
|
||||
|
||||
static constexpr size_t TWINE_PUBLIC_BIT = 1ULL << 63;
|
||||
static constexpr size_t TWINE_NULL_VAL = ~size_t{0};
|
||||
static constexpr int TWINE_SERIAL_SHIFT = 32;
|
||||
static constexpr size_t TWINE_INDEX_MASK = (size_t{1} << TWINE_SERIAL_SHIFT) - 1;
|
||||
static constexpr size_t TWINE_SERIAL_MASK = ~(TWINE_INDEX_MASK | TWINE_PUBLIC_BIT);
|
||||
|
||||
public:
|
||||
static constexpr NullIdString Null{};
|
||||
|
||||
constexpr size_t raw() const { return value; }
|
||||
static constexpr size_t MAX_INDEX = TWINE_INDEX_MASK;
|
||||
static constexpr size_t MAX_SERIAL = TWINE_SERIAL_MASK >> TWINE_SERIAL_SHIFT;
|
||||
|
||||
constexpr size_t raw() const {
|
||||
return value == TWINE_NULL_VAL ? value : (value & ~TWINE_SERIAL_MASK);
|
||||
}
|
||||
|
||||
// raw() with the pool serial kept
|
||||
constexpr size_t bits() const { return value; }
|
||||
|
||||
constexpr size_t serial() const {
|
||||
return value == TWINE_NULL_VAL ? 0 : ((value & TWINE_SERIAL_MASK) >> TWINE_SERIAL_SHIFT);
|
||||
}
|
||||
|
||||
constexpr IdString stamped(size_t pool_serial) const {
|
||||
return value == TWINE_NULL_VAL ? *this
|
||||
: IdString((value & ~TWINE_SERIAL_MASK) | (pool_serial << TWINE_SERIAL_SHIFT));
|
||||
}
|
||||
|
||||
constexpr IdString() : value(TWINE_NULL_VAL) {}
|
||||
explicit constexpr IdString(size_t val) : value(val) {}
|
||||
|
||||
constexpr bool operator==(const IdString&) const = default;
|
||||
constexpr bool operator==(const IdString &rhs) const { return raw() == rhs.raw(); }
|
||||
constexpr bool operator!=(const IdString &rhs) const { return raw() != rhs.raw(); }
|
||||
constexpr std::strong_ordering operator<=>(const IdString &rhs) const {
|
||||
if (auto cmp = (value & ~TWINE_PUBLIC_BIT) <=> (rhs.value & ~TWINE_PUBLIC_BIT); cmp != 0)
|
||||
size_t a = raw(), b = rhs.raw();
|
||||
if (auto cmp = (a & ~TWINE_PUBLIC_BIT) <=> (b & ~TWINE_PUBLIC_BIT); cmp != 0)
|
||||
return cmp;
|
||||
return (value & TWINE_PUBLIC_BIT) <=> (rhs.value & TWINE_PUBLIC_BIT);
|
||||
return (a & TWINE_PUBLIC_BIT) <=> (b & TWINE_PUBLIC_BIT);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
@@ -177,9 +199,9 @@ struct Twine {
|
||||
|
||||
std::variant<Leaf, Suffix, AutoSuffix> data;
|
||||
|
||||
Twine(Leaf v) : data(std::move(v)) {}
|
||||
Twine(Suffix v) : data(std::move(v)) {}
|
||||
Twine(AutoSuffix v) : data(std::move(v)) {}
|
||||
Twine(Leaf v);
|
||||
Twine(Suffix v);
|
||||
Twine(AutoSuffix v);
|
||||
|
||||
bool is_leaf() const;
|
||||
bool is_suffix() const;
|
||||
@@ -191,8 +213,8 @@ struct TwineNode {
|
||||
std::variant<std::monostate, Twine::Leaf, Twine::Suffix> data;
|
||||
|
||||
TwineNode() = default;
|
||||
TwineNode(Twine::Leaf v) : data(std::move(v)) {}
|
||||
TwineNode(Twine::Suffix v) : data(std::move(v)) {}
|
||||
TwineNode(Twine::Leaf v);
|
||||
TwineNode(Twine::Suffix v);
|
||||
|
||||
bool is_dead() const;
|
||||
bool is_leaf() const;
|
||||
@@ -220,6 +242,18 @@ std::pair<std::string, bool> twine_unescape(std::string s);
|
||||
struct TwinePool : HashConsPool<TwinePool, TwineNode, IdString> {
|
||||
static constexpr size_t STATIC_COUNT = StaticTwines::count;
|
||||
|
||||
TwinePool();
|
||||
TwinePool(const TwinePool& other);
|
||||
TwinePool(TwinePool&& other);
|
||||
TwinePool& operator=(const TwinePool& other);
|
||||
TwinePool& operator=(TwinePool&& other);
|
||||
|
||||
size_t serial() const;
|
||||
bool owns(IdString ref) const;
|
||||
IdString stamp(IdString ref) const;
|
||||
void check_owned(IdString ref) const;
|
||||
const TwineNode& operator[](IdString ref) const;
|
||||
|
||||
static const TwineNode& static_node(size_t idx);
|
||||
// static IdString untag(IdString ref);
|
||||
|
||||
@@ -259,13 +293,21 @@ struct TwinePool : HashConsPool<TwinePool, TwineNode, IdString> {
|
||||
IdString copy_from(const TwinePool& src, IdString ref);
|
||||
// Non-mutating counterpart of copy_from
|
||||
IdString find_from(const TwinePool& src, IdString ref) const;
|
||||
// Opaque handle for files that never leave one run of yosys.
|
||||
// Only valid until garbage collection reuses the slot.
|
||||
std::string ref_token(IdString ref) const;
|
||||
// Null unless the token names a live twine stamped by this pool
|
||||
IdString ref_from_token(std::string_view token) const;
|
||||
void dump(std::ostream& os = std::cout) const;
|
||||
using HashConsPool::gc;
|
||||
|
||||
private:
|
||||
IdString add_inner(TwineNode t);
|
||||
static size_t next_serial();
|
||||
size_t serial_;
|
||||
|
||||
static bool inherits_publicity(const Twine &t);
|
||||
static TwineNode to_node(Twine t);
|
||||
using HashConsPool::add_inner;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user