about summary refs log tree commit diff
path: root/src/libexpr/eval.cc
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2010-04-15T00·37+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2010-04-15T00·37+0000
commit04c4bd3624b094043ff0f2410c1e376a51f457f7 (patch)
tree0ff3c39628ceeb26af33f2b461d84a13db9aa561 /src/libexpr/eval.cc
parente41b5828db0c154e4a3f0ed6299a987fde5bc03f (diff)
* Store lists as lists of pointers to values rather than as lists of
  values.  This improves sharing and gives another speed up.
  Evaluation of the NixOS system attribute is now almost 7 times
  faster than the old evaluator.

Diffstat (limited to 'src/libexpr/eval.cc')
-rw-r--r--src/libexpr/eval.cc33
1 files changed, 17 insertions, 16 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index d6e39f3654..69e7bd8b3c 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -50,7 +50,7 @@ std::ostream & operator << (std::ostream & str, Value & v)
     case tList:
         str << "[ ";
         for (unsigned int n = 0; n < v.list.length; ++n)
-            str << v.list.elems[n] << " ";
+            str << *v.list.elems[n] << " ";
         str << "]";
         break;
     case tThunk:
@@ -102,7 +102,7 @@ EvalState::EvalState()
     , baseEnvDispl(0)
     , staticBaseEnv(false, 0)
 {
-    nrEnvs = nrValuesInEnvs = nrValuesInLists = nrValues = 0;
+    nrEnvs = nrValuesInEnvs = nrValues = nrListElems = 0;
     nrEvaluated = recursionDepth = maxRecursionDepth = 0;
     deepestStack = (char *) -1;
 
@@ -251,6 +251,7 @@ Value * EvalState::lookupVar(Env * env, const VarRef & var)
 
 Value * EvalState::allocValues(unsigned int count)
 {
+    nrValues += count;
     return new Value[count]; // !!! check destructor
 }
 
@@ -268,8 +269,8 @@ void EvalState::mkList(Value & v, unsigned int length)
 {
     v.type = tList;
     v.list.length = length;
-    v.list.elems = allocValues(length);
-    nrValuesInLists += length;
+    v.list.elems = new Value *[length];
+    nrListElems += length;
 }
 
 
@@ -461,8 +462,11 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
 void ExprList::eval(EvalState & state, Env & env, Value & v)
 {
     state.mkList(v, elems.size());
-    for (unsigned int n = 0; n < v.list.length; ++n)
-        mkThunk(v.list.elems[n], env, elems[n]);
+    Value * vs = state.allocValues(v.list.length);
+    for (unsigned int n = 0; n < v.list.length; ++n) {
+        v.list.elems[n] = &vs[n];
+        mkThunk(vs[n], env, elems[n]);
+    }
 }
 
 
@@ -543,7 +547,6 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
             primOp->primOp.fun(*this, vArgs, v);
         } else {
             Value * v2 = allocValues(2);
-            nrValues += 2;
             v2[0] = fun;
             v2[1] = arg;
             v.type = tPrimOpApp;
@@ -734,8 +737,6 @@ void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
     Value v2; state.eval(env, e2, v2);
     state.forceList(v2);
     state.mkList(v, v1.list.length + v2.list.length);
-    /* !!! This loses sharing with the original lists.  We could use a
-       tCopy node, but that would use more memory. */
     for (unsigned int n = 0; n < v1.list.length; ++n)
         v.list.elems[n] = v1.list.elems[n];
     for (unsigned int n = 0; n < v2.list.length; ++n)
@@ -810,7 +811,7 @@ void EvalState::strictForceValue(Value & v)
     
     else if (v.type == tList) {
         for (unsigned int n = 0; n < v.list.length; ++n)
-            strictForceValue(v.list.elems[n]);
+            strictForceValue(*v.list.elems[n]);
     }
 }
 
@@ -951,11 +952,11 @@ string EvalState::coerceToString(Value & v, PathSet & context,
         if (v.type == tList) {
             string result;
             for (unsigned int n = 0; n < v.list.length; ++n) {
-                result += coerceToString(v.list.elems[n],
+                result += coerceToString(*v.list.elems[n],
                     context, coerceMore, copyToStore);
                 if (n < v.list.length - 1
                     /* !!! not quite correct */
-                    && (v.list.elems[n].type != tList || v.list.elems[n].list.length != 0))
+                    && (v.list.elems[n]->type != tList || v.list.elems[n]->list.length != 0))
                     result += " ";
             }
             return result;
@@ -1009,14 +1010,14 @@ bool EvalState::eqValues(Value & v1, Value & v2)
         case tList:
             if (v2.type != tList || v1.list.length != v2.list.length) return false;
             for (unsigned int n = 0; n < v1.list.length; ++n)
-                if (!eqValues(v1.list.elems[n], v2.list.elems[n])) return false;
+                if (!eqValues(*v1.list.elems[n], *v2.list.elems[n])) return false;
             return true;
 
         case tAttrs: {
             if (v2.type != tAttrs || v1.attrs->size() != v2.attrs->size()) return false;
             Bindings::iterator i, j;
             for (i = v1.attrs->begin(), j = v2.attrs->begin(); i != v1.attrs->end(); ++i, ++j)
-                if (!eqValues(i->second, j->second)) return false;
+                if (i->first != j->first || !eqValues(i->second, j->second)) return false;
             return true;
         }
 
@@ -1046,8 +1047,8 @@ void EvalState::printStats()
         % nrEnvs % (nrEnvs * sizeof(Env)));
     printMsg(v, format("  values allocated in environments: %1% (%2% bytes)")
         % nrValuesInEnvs % (nrValuesInEnvs * sizeof(Value)));
-    printMsg(v, format("  values allocated in lists: %1% (%2% bytes)")
-        % nrValuesInLists % (nrValuesInLists * sizeof(Value)));
+    printMsg(v, format("  list elements: %1% (%2% bytes)")
+        % nrListElems % (nrListElems * sizeof(Value *)));
     printMsg(v, format("  misc. values allocated: %1% (%2% bytes) ")
         % nrValues % (nrValues * sizeof(Value)));
     printMsg(v, format("  symbols in symbol table: %1%") % symbols.size());