* Simulate conventional laziness a bit better still by "allocating"

all local variables when entering a new scope.  I.e., don't do
  implicit let-floating.
This commit is contained in:
Eelco Dolstra 2007-10-11 22:42:09 +00:00
parent 981afe821c
commit 74ce938e18
4 changed files with 49 additions and 5 deletions

View file

@ -478,7 +478,7 @@ LocalNoInline(Expr evalCall(EvalState & state, Expr fun, Expr arg))
else if (matchFunction(fun, formals, body, pos)) {
arg = evalExpr(state, arg);
try {
return evalExpr(state, substArgs(state, body, formals, arg));
return evalExpr(state, substArgs(state, allocCells(body), formals, arg));
} catch (Error & e) {
addErrorPrefix(e, "while evaluating the function at %1%:\n",
showPos(pos));
@ -491,7 +491,7 @@ LocalNoInline(Expr evalCall(EvalState & state, Expr fun, Expr arg))
arg = speculativeEval(state, arg);
ATermMap subs(1);
subs.set(name, allocCell(arg));
return evalExpr(state, substitute(Substitution(0, &subs), body));
return evalExpr(state, substitute(Substitution(0, &subs), allocCells(body)));
} catch (Error & e) {
addErrorPrefix(e, "while evaluating the function at %1%:\n",
showPos(pos));

View file

@ -201,6 +201,48 @@ Expr substitute(const Substitution & subs, Expr e)
}
Expr allocCells(Expr e)
{
checkInterrupt();
ATerm e2;
if (matchClosed(e, e2)) return e;
int i;
if (matchCell(e, i, e2))
return allocCell(allocCells(e2));
if (ATgetType(e) == AT_APPL) {
AFun fun = ATgetAFun(e);
int arity = ATgetArity(fun);
ATerm args[arity];
bool changed = false;
for (int i = 0; i < arity; ++i) {
ATerm arg = ATgetArgument(e, i);
args[i] = allocCells(arg);
if (args[i] != arg) changed = true;
}
return changed ? (ATerm) ATmakeApplArray(fun, args) : e;
}
if (ATgetType(e) == AT_LIST) {
unsigned int len = ATgetLength((ATermList) e);
ATerm es[len];
ATermIterator i((ATermList) e);
for (unsigned int j = 0; i; ++i, ++j)
es[j] = allocCells(*i);
ATermList out = ATempty;
for (unsigned int j = len; j; --j)
out = ATinsert(out, es[j - 1]);
return (ATerm) out;
}
return e;
}
/* We use memoisation to prevent exponential complexity on heavily
shared ATerms (remember, an ATerm is a graph, not a tree!). Note
that using an STL set is fine here wrt to ATerm garbage collection

View file

@ -119,6 +119,8 @@ string showValue(Expr e);
Expr allocCell(Expr e); // make an updateable cell (for simulating conventional laziness)
Expr allocCells(Expr e); // re-allocate all cells in e
}

View file

@ -564,12 +564,12 @@ static Expr prim_derivationLazy(EvalState & state, const ATermVector & args)
attrs.set(toATerm("type"),
makeAttrRHS(makeStr("derivation"), makeNoPos()));
Expr drvStrict = makeCall(makeVar(toATerm("derivation!")), eAttrs);
Expr drvStrict = allocCell(makeCall(makeVar(toATerm("derivation!")), eAttrs));
attrs.set(toATerm("outPath"),
makeAttrRHS(allocCell(makeSelect(drvStrict, toATerm("outPath"))), makeNoPos()));
makeAttrRHS(makeSelect(drvStrict, toATerm("outPath")), makeNoPos()));
attrs.set(toATerm("drvPath"),
makeAttrRHS(allocCell(makeSelect(drvStrict, toATerm("drvPath"))), makeNoPos()));
makeAttrRHS(makeSelect(drvStrict, toATerm("drvPath")), makeNoPos()));
return makeAttrs(attrs);
}