diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 8cf4d9549..a95726f5f 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -821,8 +821,23 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) Value * EvalState::allocValue() { + /* We use the boehm batch allocator to speed up allocations of Values (of which there are many). + GC_malloc_many returns a linked list of objects of the given size, where the first word + of each object is also the pointer to the next object in the list. This also means that we + have to explicitly clear the first word of every object we take. */ + if (!valueAllocCache) { + valueAllocCache = GC_malloc_many(sizeof(Value)); + if (!valueAllocCache) throw std::bad_alloc(); + } + + /* GC_NEXT is a convenience macro for accessing the first word of an object. + Take the first list item, advance the list to the next item, and clear the next pointer. */ + void * p = valueAllocCache; + GC_PTR_STORE_AND_DIRTY(&valueAllocCache, GC_NEXT(p)); + GC_NEXT(p) = nullptr; + nrValues++; - auto v = (Value *) allocBytes(sizeof(Value)); + auto v = (Value *) p; return v; } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 1aab8e166..cc63294c6 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -133,6 +133,9 @@ private: /* Cache used by prim_match(). */ std::shared_ptr regexCache; + /* Allocation cache for GC'd Value objects. */ + void * valueAllocCache = nullptr; + public: EvalState(