diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh index 0748fbd3f3e..bd003432fef 100644 --- a/src/libexpr/eval-inline.hh +++ b/src/libexpr/eval-inline.hh @@ -27,23 +27,15 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v, const void EvalState::forceValue(Value & v, const Pos & pos) { if (v.type == tThunk) { - Env * env = v.thunk.env; - Expr * expr = v.thunk.expr; - try { - v.type = tBlackhole; - //checkInterrupt(); - expr->eval(*this, *env, v); - } catch (Error & e) { - v.type = tThunk; - v.thunk.env = env; - v.thunk.expr = expr; - throw; - } + Value vTmp; + v.thunk.expr->eval(*this, *v.thunk.env, vTmp); + v = vTmp; + } + else if (v.type == tApp) { + Value vTmp; + callFunction(*v.app.left, *v.app.right, vTmp, noPos); + v = vTmp; } - else if (v.type == tApp) - callFunction(*v.app.left, *v.app.right, v, noPos); - else if (v.type == tBlackhole) - throwEvalError("infinite recursion encountered, at %1%", pos); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 2805f7f468f..5515c13cdc8 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -492,12 +492,13 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) if (!var.fromWith) return env->values[var.displ]; while (1) { - if (!env->haveWithAttrs) { + Expr * withAttrs = env->withAttrs; + if (withAttrs) { if (noEval) return 0; Value * v = allocValue(); - evalAttrs(*env->up, (Expr *) env->values[0], *v); + evalAttrs(*env->up, withAttrs, *v); env->values[0] = v; - env->haveWithAttrs = true; + env->withAttrs = 0; } Bindings::iterator j = env->values[0]->attrs->find(var.name); if (j != env->values[0]->attrs->end()) { @@ -906,7 +907,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) if (state.countCalls && pos2) state.attrSelects[*pos2]++; } - state.forceValue(*vAttrs, ( pos2 != NULL ? *pos2 : this->pos ) ); + state.forceValue(*vAttrs, pos2 ? *pos2 : this->pos); } catch (Error & e) { if (pos2 && pos2->file != state.sDerivationNix) @@ -928,6 +929,7 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v) for (auto & i : attrPath) { state.forceValue(*vAttrs); + assert(vAttrs->type != tAttrs || vAttrs->attrs != 0); Bindings::iterator j; Symbol name = getName(i, state, env); if (vAttrs->type != tAttrs || @@ -1140,8 +1142,7 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v) Env & env2(state.allocEnv(1)); env2.up = &env; env2.prevWith = prevWith; - env2.haveWithAttrs = false; - env2.values[0] = (Value *) attrs; + env2.withAttrs = attrs; body->eval(state, env2, v); } @@ -1416,12 +1417,8 @@ void EvalState::forceFunction(Value & v, const Pos & pos) string EvalState::forceString(Value & v, const Pos & pos) { forceValue(v, pos); - if (v.type != tString) { - if (pos) - throwTypeError("value is %1% while a string was expected, at %2%", v, pos); - else - throwTypeError("value is %1% while a string was expected", v); - } + if (v.type != tString) + throwTypeError("value is %1% while a string was expected, at %2%", v, pos); return string(v.string.s); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index ff2e3730380..28b496a9dae 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -37,8 +37,8 @@ struct Env { Env * up; unsigned short size; // used by ‘valueSize’ - unsigned short prevWith:15; // nr of levels up to next `with' environment - unsigned short haveWithAttrs:1; + unsigned short prevWith; // nr of levels up to next `with' environment + Expr * withAttrs; Value * values[0]; }; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index e52de6dd4d6..d1be817481d 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -1231,8 +1231,9 @@ static void elemAt(EvalState & state, const Pos & pos, Value & list, int n, Valu state.forceList(list, pos); if (n < 0 || (unsigned int) n >= list.listSize()) throw Error(format("list index %1% is out of bounds, at %2%") % n % pos); - state.forceValue(*list.listElems()[n]); - v = *list.listElems()[n]; + auto & v2 = *list.listElems()[n]; + state.forceValue(v2); + v = v2; } @@ -1426,7 +1427,6 @@ static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value v.listElems()[n] = args[1]->listElems()[n]; } - auto comparator = [&](Value * a, Value * b) { /* Optimization: if the comparator is lessThan, bypass callFunction. */ diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh index 048522016c6..f74087a198d 100644 --- a/src/libexpr/value.hh +++ b/src/libexpr/value.hh @@ -90,7 +90,21 @@ std::ostream & operator << (std::ostream & str, const ExternalValueBase & v); struct Value { + // FIXME: should be std::atomic, with readers using + // memory_order_relaxed and writers using memory_order_release. ValueType type; + + union + { + struct { + Env * env; + Expr * expr; + } thunk; + struct { + Value * left, * right; + } app; + }; + union { NixInt integer; @@ -128,13 +142,6 @@ struct Value Value * * elems; } bigList; Value * smallList[2]; - struct { - Env * env; - Expr * expr; - } thunk; - struct { - Value * left, * right; - } app; struct { Env * env; ExprLambda * fun; @@ -147,6 +154,20 @@ struct Value NixFloat fpoint; }; + Value() + { + } + + Value(const Value & v) = delete; + + Value & operator = (const Value & v) + { + lambda.env = v.lambda.env; + lambda.fun = v.lambda.fun; + type = v.type; // FIXME: memory_order_release + return *this; + } + bool isList() const { return type == tList1 || type == tList2 || type == tListN; @@ -173,7 +194,7 @@ struct Value Value to ensure that the target isn't kept alive unnecessarily. */ static inline void clearValue(Value & v) { - v.app.left = v.app.right = 0; + //v.app.left = v.app.right = 0; }