about summary refs log tree commit diff
path: root/src/libexpr
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2013-07-31T10·44+0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2013-07-31T10·44+0200
commit0a470fc3453f56a0a242d8f467b8079fe0040ff7 (patch)
treefeb889a3540586cb4247fcd8ca017bdd8d1b71dc /src/libexpr
parent8ae6d55db15bb0777e3d707afb994f6fcbcc6a65 (diff)
Make Env smaller
Commit 20866a7031ca823055a221653b77986faa167329 added a ‘withAttrs’
field to Env, which is annoying because it makes every Env structure
bigger and we allocate millions of them.  E.g. NixOS evaluation took
18 MiB more.  So this commit squeezes ‘withAttrs’ into values[0].
Probably should use a union...
Diffstat (limited to 'src/libexpr')
-rw-r--r--src/libexpr/eval.cc40
-rw-r--r--src/libexpr/eval.hh4
2 files changed, 23 insertions, 21 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 904a95d16034..f891496a7568 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -307,25 +307,26 @@ void mkPath(Value & v, const char * s)
 inline Value * EvalState::lookupVar(Env * env, const VarRef & var, bool noEval)
 {
     for (unsigned int l = var.level; l; --l, env = env->up) ;
-    
-    if (var.fromWith) {
-        while (1) {
-            if (!env->values[0]) {
-                if (noEval) return 0;
-                env->values[0] = allocValue();
-                evalAttrs(*env->up, env->withAttrs, *env->values[0]);
-            }
-            Bindings::iterator j = env->values[0]->attrs->find(var.name);
-            if (j != env->values[0]->attrs->end()) {
-                if (countCalls && j->pos) attrSelects[*j->pos]++;
-                return j->value;
-            }
-            if (env->prevWith == 0)
-                throwEvalError("undefined variable `%1%'", var.name);
-            for (unsigned int l = env->prevWith; l; --l, env = env->up) ;
+
+    if (!var.fromWith) return env->values[var.displ];
+
+    while (1) {
+        if (!env->haveWithAttrs) {
+            if (noEval) return 0;
+            Expr * attrs = (Expr *) env->values[0];
+            env->values[0] = allocValue();
+            evalAttrs(*env->up, attrs, *env->values[0]);
+            env->haveWithAttrs = true;
         }
-    } else
-        return env->values[var.displ];
+        Bindings::iterator j = env->values[0]->attrs->find(var.name);
+        if (j != env->values[0]->attrs->end()) {
+            if (countCalls && j->pos) attrSelects[*j->pos]++;
+            return j->value;
+        }
+        if (!env->prevWith)
+            throwEvalError("undefined variable `%1%'", var.name);
+        for (unsigned int l = env->prevWith; l; --l, env = env->up) ;
+    }
 }
 
 
@@ -829,7 +830,8 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v)
     Env & env2(state.allocEnv(1));
     env2.up = &env;
     env2.prevWith = prevWith;
-    env2.withAttrs = attrs;
+    env2.haveWithAttrs = false;
+    env2.values[0] = (Value *) attrs;
 
     body->eval(state, env2, v);
 }
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index c820b28f49ae..6f6b2a9009fe 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -52,8 +52,8 @@ struct PrimOp
 struct Env
 {
     Env * up;
-    unsigned int prevWith; // nr of levels up to next `with' environment
-    Expr * withAttrs;
+    unsigned short prevWith; // nr of levels up to next `with' environment
+    bool haveWithAttrs;
     Value * values[0];
 };