diff --git a/src/CompHash.cc b/src/CompHash.cc index 56b626fa7f..e4ab1c536f 100644 --- a/src/CompHash.cc +++ b/src/CompHash.cc @@ -260,13 +260,16 @@ bool CompositeHash::RecoverOneVal(const HashKey& hk, Type* t, ValPtr* pval, bool { uint32_t id; hk.Read("func", id); - const auto& f = Func::GetFuncPtrByID(id); - if ( ! f ) + ASSERT(func_id_to_func != nullptr); + + if ( id >= func_id_to_func->size() ) reporter->InternalError("failed to look up unique function id %" PRIu32 " in CompositeHash::RecoverOneVal()", id); + const auto& f = func_id_to_func->at(id); + *pval = make_intrusive(f); const auto& pvt = (*pval)->GetType(); @@ -547,7 +550,31 @@ bool CompositeHash::SingleValHash(HashKey& hk, const Val* v, Type* bt, bool type switch ( v->GetType()->Tag() ) { case TYPE_FUNC: - hk.Write("func", v->AsFunc()->GetUniqueFuncID()); + { + auto f = v->AsFunc(); + + if ( ! func_to_func_id ) + const_cast(this)->BuildFuncMappings(); + + auto id_mapping = func_to_func_id->find(f); + uint32_t id; + + if ( id_mapping == func_to_func_id->end() ) + { + // We need the pointer to stick around + // for our lifetime, so we have to get + // a non-const version we can ref. + FuncPtr fptr = {NewRef{}, const_cast(f)}; + + id = func_id_to_func->size(); + func_id_to_func->push_back(std::move(fptr)); + func_to_func_id->insert_or_assign(f, id); + } + else + id = id_mapping->second; + + hk.Write("func", id); + } break; case TYPE_PATTERN: diff --git a/src/CompHash.h b/src/CompHash.h index cbbefe5a02..da51dc6116 100644 --- a/src/CompHash.h +++ b/src/CompHash.h @@ -4,7 +4,7 @@ #include -#include "zeek/IntrusivePtr.h" +#include "zeek/Func.h" #include "zeek/Type.h" namespace zeek @@ -61,6 +61,18 @@ protected: bool EnsureTypeReserve(HashKey& hk, const Val* v, Type* bt, bool type_check) const; + // The following are for allowing hashing of function values. + // These can occur, for example, in sets of predicates that get + // iterated over. We use pointers in order to keep storage + // lower for the common case of these not being needed. + std::unique_ptr> func_to_func_id; + std::unique_ptr> func_id_to_func; + void BuildFuncMappings() + { + func_to_func_id = std::make_unique>(); + func_id_to_func = std::make_unique>(); + } + TypeListPtr type; bool is_singleton = false; // if just one type in index }; diff --git a/src/Func.cc b/src/Func.cc index 992acc9e0e..600c9aaabd 100644 --- a/src/Func.cc +++ b/src/Func.cc @@ -133,20 +133,6 @@ std::string render_call_stack() return rval; } -Func::Func() - { - unique_id = unique_ids.size(); - unique_ids.push_back({NewRef{}, this}); - } - -Func::Func(Kind arg_kind) : kind(arg_kind) - { - unique_id = unique_ids.size(); - unique_ids.push_back({NewRef{}, this}); - } - -Func::~Func() = default; - void Func::AddBody(detail::StmtPtr /* new_body */, const std::vector& /* new_inits */, size_t /* new_frame_size */, int /* priority */) @@ -238,7 +224,6 @@ void Func::CopyStateInto(Func* other) const other->type = type; other->name = name; - other->unique_id = unique_id; } void Func::CheckPluginResult(bool handled, const ValPtr& hook_result, FunctionFlavor flavor) const diff --git a/src/Func.h b/src/Func.h index 9c9b1c0e97..7d89f88609 100644 --- a/src/Func.h +++ b/src/Func.h @@ -61,9 +61,7 @@ public: BUILTIN_FUNC }; - explicit Func(Kind arg_kind); - - ~Func() override; + explicit Func(Kind arg_kind) : kind(arg_kind) { } virtual bool IsPure() const = 0; FunctionFlavor Flavor() const { return GetType()->Flavor(); } @@ -122,14 +120,8 @@ public: virtual detail::TraversalCode Traverse(detail::TraversalCallback* cb) const; - uint32_t GetUniqueFuncID() const { return unique_id; } - static const FuncPtr& GetFuncPtrByID(uint32_t id) - { - return id >= unique_ids.size() ? Func::nil : unique_ids[id]; - } - protected: - Func(); + Func() = default; // Copies this function's state into other. void CopyStateInto(Func* other) const; @@ -140,10 +132,8 @@ protected: std::vector bodies; detail::ScopePtr scope; Kind kind = SCRIPT_FUNC; - uint32_t unique_id = 0; FuncTypePtr type; std::string name; - static inline std::vector unique_ids; }; namespace detail