aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/eval.cc71
-rw-r--r--src/libexpr/eval.hh10
-rw-r--r--src/libexpr/primops.cc2
3 files changed, 60 insertions, 23 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 85394b768..124cf6498 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -316,6 +316,11 @@ Env & EvalState::allocEnv(unsigned int size)
nrEnvs++;
nrValuesInEnvs += size;
Env * env = (Env *) GC_MALLOC(sizeof(Env) + size * sizeof(Value *));
+
+ /* Clear the values because maybeThunk() expects this. */
+ for (unsigned i = 0; i < size; ++i)
+ env->values[i] = 0;
+
return *env;
}
@@ -346,12 +351,48 @@ void EvalState::mkAttrs(Value & v)
}
+unsigned long nrThunks = 0;
+
+static inline void mkThunk(Value & v, Env & env, Expr * expr)
+{
+ v.type = tThunk;
+ v.thunk.env = &env;
+ v.thunk.expr = expr;
+ nrThunks++;
+}
+
+
void EvalState::mkThunk_(Value & v, Expr * expr)
{
mkThunk(v, baseEnv, expr);
}
+unsigned long nrAvoided = 0;
+
+/* Create a thunk for the delayed computation of the given expression
+ in the given environment. But if the expression is a variable,
+ then look it up right away. This significantly reduces the number
+ of thunks allocated. */
+Value * EvalState::maybeThunk(Env & env, Expr * expr)
+{
+ ExprVar * var;
+ /* Ignore variables from `withs' because they can throw an
+ exception. */
+ if ((var = dynamic_cast<ExprVar *>(expr))) {
+ Value * v = lookupVar(&env, var->info);
+ /* The value might not be initialised in the environment yet.
+ In that case, ignore it. */
+ if (v) { nrAvoided++; return v; }
+ }
+
+ Value * v = allocValue();
+ mkThunk(*v, env, expr);
+
+ return v;
+}
+
+
void EvalState::cloneAttrs(Value & src, Value & dst)
{
mkAttrs(dst);
@@ -478,8 +519,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
/* The recursive attributes are evaluated in the new
environment. */
foreach (Attrs::iterator, i, attrs) {
- Value * vAttr = state.allocValue();
- mkThunk(*vAttr, env2, i->second.first);
+ Value * vAttr = state.maybeThunk(env2, i->second.first);
env2.values[displ++] = vAttr;
v.attrs->push_back(nix::Attr(i->first, vAttr, &i->second.second));
}
@@ -515,8 +555,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
else {
foreach (Attrs::iterator, i, attrs) {
nix::Attr & a = (*v.attrs)[i->first];
- a.value = state.allocValue();
- mkThunk(*a.value, env, i->second.first);
+ a.value = state.maybeThunk(env, i->second.first);
a.pos = &i->second.second;
}
@@ -540,10 +579,8 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
/* The recursive attributes are evaluated in the new
environment. */
- foreach (ExprAttrs::Attrs::iterator, i, attrs->attrs) {
- env2.values[displ] = state.allocValue();
- mkThunk(*env2.values[displ++], env2, i->second.first);
- }
+ foreach (ExprAttrs::Attrs::iterator, i, attrs->attrs)
+ env2.values[displ++] = state.maybeThunk(env2, i->second.first);
/* The inherited attributes, on the other hand, are evaluated in
the original environment. */
@@ -558,7 +595,7 @@ 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] = state.allocValue()), env, elems[n]);
+ v.list.elems[n] = state.maybeThunk(env, elems[n]);
}
@@ -570,10 +607,15 @@ void ExprVar::eval(EvalState & state, Env & env, Value & v)
}
+unsigned long nrLookups = 0;
+unsigned long nrLookupSize = 0;
+
void ExprSelect::eval(EvalState & state, Env & env, Value & v)
{
+ nrLookups++;
Value v2;
state.evalAttrs(env, e, v2);
+ nrLookupSize += v2.attrs->size();
Bindings::iterator i = v2.attrs->find(name);
if (i == v2.attrs->end())
throwEvalError("attribute `%1%' missing", name);
@@ -608,9 +650,7 @@ void ExprApp::eval(EvalState & state, Env & env, Value & v)
{
Value vFun;
state.eval(env, e1, vFun);
- Value * vArg = state.allocValue();
- mkThunk(*vArg, env, e2);
- state.callFunction(vFun, *vArg, v);
+ state.callFunction(vFun, *state.maybeThunk(env, e2), v);
}
@@ -685,8 +725,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
if (j == arg.attrs->end()) {
if (!i->def) throwTypeError("function at %1% called without required argument `%2%'",
fun.lambda.fun->pos, i->name);
- env2.values[displ] = allocValue();
- mkThunk(*env2.values[displ++], env2, i->def);
+ env2.values[displ++] = maybeThunk(env2, i->def);
} else {
attrsUsed++;
env2.values[displ++] = j->value;
@@ -1156,6 +1195,10 @@ void EvalState::printStats()
printMsg(v, format(" right-biased unions: %1%") % nrOpUpdates);
printMsg(v, format(" values copied in right-biased unions: %1%") % nrOpUpdateValuesCopied);
printMsg(v, format(" symbols in symbol table: %1%") % symbols.size());
+ printMsg(v, format(" number of thunks: %1%") % nrThunks);
+ printMsg(v, format(" number of thunks avoided: %1%") % nrAvoided);
+ printMsg(v, format(" number of attr lookups: %1%") % nrLookups);
+ printMsg(v, format(" attr lookup size: %1%") % nrLookupSize);
}
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index 2f1b3fa45..e1aa69dd3 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -169,14 +169,6 @@ static inline void mkBool(Value & v, bool b)
}
-static inline void mkThunk(Value & v, Env & env, Expr * expr)
-{
- v.type = tThunk;
- v.thunk.env = &env;
- v.thunk.expr = expr;
-}
-
-
static inline void mkApp(Value & v, Value & left, Value & right)
{
v.type = tApp;
@@ -325,6 +317,8 @@ public:
void mkList(Value & v, unsigned int length);
void mkAttrs(Value & v);
void mkThunk_(Value & v, Expr * expr);
+
+ Value * maybeThunk(Env & env, Expr * expr);
void cloneAttrs(Value & src, Value & dst);
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 20b839508..3e32dd3ff 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -1070,7 +1070,7 @@ void EvalState::createBaseEnv()
/* Add a wrapper around the derivation primop that computes the
`drvPath' and `outPath' attributes lazily. */
string s = "attrs: let res = derivationStrict attrs; in attrs // { drvPath = res.drvPath; outPath = res.outPath; type = \"derivation\"; }";
- mkThunk(v, baseEnv, parseExprFromString(*this, s, "/"));
+ mkThunk_(v, parseExprFromString(*this, s, "/"));
addConstant("derivation", v);
// Paths