about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2020-07-15T19·30+0100
committertazjin <mail@tazj.in>2020-07-16T00·37+0000
commit5cd7cf93fc6b6b58b05f579866a89bf22c6eacab (patch)
tree379288f99bd607276e4b5bfd4a607b982a0d61ac
parent04ae2933607eaed32c9d99eb3949953a88e63460 (diff)
refactor(3p/nix): Use a static empty Bindings for 0-element attrs r/1305
A significant fraction of all created attribute sets are empty; hence
this is an easy optimisation to make.

Paired-With: Perry Lorier <isomer@tvl.fyi>
Change-Id: I0884194d04c1ee95b2b239a253515f2152bc0856
Reviewed-on: https://cl.tvl.fyi/c/depot/+/1179
Tested-by: BuildkiteCI
Reviewed-by: glittershark <grfn@gws.fyi>
-rw-r--r--third_party/nix/src/libexpr/attr-set.cc13
1 files changed, 11 insertions, 2 deletions
diff --git a/third_party/nix/src/libexpr/attr-set.cc b/third_party/nix/src/libexpr/attr-set.cc
index c1b86387be8e..d44df990ad1e 100644
--- a/third_party/nix/src/libexpr/attr-set.cc
+++ b/third_party/nix/src/libexpr/attr-set.cc
@@ -10,6 +10,8 @@
 
 namespace nix {
 
+static Bindings ZERO_BINDINGS;
+
 // This function inherits its name from previous implementations, in
 // which Bindings was backed by an array of elements which was scanned
 // linearly.
@@ -21,6 +23,8 @@ namespace nix {
 // This behaviour is mimicked by using .insert(), which will *not*
 // override existing values.
 void Bindings::push_back(const Attr& attr) {
+  assert(this != &ZERO_BINDINGS);
+
   auto [_, inserted] = attributes_.insert({attr.name, attr});
 
   if (!inserted) {
@@ -53,19 +57,24 @@ Bindings::iterator Bindings::begin() { return attributes_.begin(); }
 Bindings::iterator Bindings::end() { return attributes_.end(); }
 
 void Bindings::merge(const Bindings& other) {
+  assert(this != &ZERO_BINDINGS);
   for (auto& [key, value] : other.attributes_) {
     this->attributes_.insert_or_assign(key, value);
   }
 }
 
-Bindings* Bindings::NewGC(size_t _capacity) {
+Bindings* Bindings::NewGC(size_t capacity) {
+  if (capacity == 0) {
+    return &ZERO_BINDINGS;
+  }
+
   return new (GC) Bindings;
 }
 
 void EvalState::mkAttrs(Value& v, size_t capacity) {
   clearValue(v);
   v.type = tAttrs;
-  v.attrs = Bindings::NewGC();
+  v.attrs = Bindings::NewGC(capacity);
   nrAttrsets++;
   nrAttrsInAttrsets += capacity;
 }