* Work around problems with the ATerm library.

The ATerm library doesn't search the heap for pointers to ATerms
  when garbage collecting.  As a result, C++ containers such as
  `map<ATerm, ATerm>' will cause pointer to be hidden from the garbage
  collector, causing crashes.  Instead, we now use ATermTables.
This commit is contained in:
Eelco Dolstra 2003-11-03 20:30:40 +00:00
parent ff31324278
commit 0690c1c9c0
5 changed files with 182 additions and 55 deletions

View file

@ -5,6 +5,7 @@
EvalState::EvalState() EvalState::EvalState()
: normalForms(32768, 75)
{ {
blackHole = ATmake("BlackHole()"); blackHole = ATmake("BlackHole()");
if (!blackHole) throw Error("cannot build black hole"); if (!blackHole) throw Error("cannot build black hole");
@ -20,32 +21,43 @@ Expr getAttr(EvalState & state, Expr e, const string & name)
/* Substitute an argument set into the body of a function. */ /* Substitute an argument set into the body of a function. */
static Expr substArgs(Expr body, ATermList formals, Expr arg) static Expr substArgs(Expr body, ATermList formals, Expr arg)
{ {
Subs subs; ATermMap subs;
Expr undefined = ATmake("Undefined"); Expr undefined = ATmake("Undefined");
/* Get the formal arguments. */ /* Get the formal arguments. */
while (!ATisEmpty(formals)) { while (!ATisEmpty(formals)) {
ATerm t = ATgetFirst(formals);
char * s; char * s;
if (!ATmatch(ATgetFirst(formals), "<str>", &s)) if (!ATmatch(t, "<str>", &s))
abort(); /* can't happen */ abort(); /* can't happen */
subs[s] = undefined; subs.set(t, undefined);
formals = ATgetNext(formals); formals = ATgetNext(formals);
} }
/* Get the actual arguments, and check that they match with the /* Get the actual arguments, and check that they match with the
formals. */ formals. */
Attrs args; ATermMap args;
queryAllAttrs(arg, args); queryAllAttrs(arg, args);
for (Attrs::iterator i = args.begin(); i != args.end(); i++) { for (ATermList keys = args.keys(); !ATisEmpty(keys);
if (subs.find(i->first) == subs.end()) keys = ATgetNext(keys))
throw badTerm(format("argument `%1%' not declared") % i->first, arg); {
subs[i->first] = i->second; Expr key = ATgetFirst(keys);
Expr cur = subs.get(key);
if (!cur)
throw badTerm(format("argument `%1%' not declared")
% aterm2String(key), arg);
subs.set(key, args.get(key));
} }
/* Check that all arguments are defined. */ /* Check that all arguments are defined. */
for (Subs::iterator i = subs.begin(); i != subs.end(); i++) for (ATermList keys = subs.keys(); !ATisEmpty(keys);
if (i->second == undefined) keys = ATgetNext(keys))
throw badTerm(format("formal argument `%1%' missing") % i->first, arg); {
Expr key = ATgetFirst(keys);
if (subs.get(key) == undefined)
throw badTerm(format("formal argument `%1%' missing")
% aterm2String(key), arg);
}
return substitute(subs, body); return substitute(subs, body);
} }
@ -59,26 +71,26 @@ static Expr substArgs(Expr body, ATermList formals, Expr arg)
ATerm expandRec(ATerm e, ATermList bnds) ATerm expandRec(ATerm e, ATermList bnds)
{ {
/* Create the substitution list. */ /* Create the substitution list. */
Subs subs; ATermMap subs;
ATermList bs = bnds; ATermList bs = bnds;
while (!ATisEmpty(bs)) { while (!ATisEmpty(bs)) {
char * s; char * s;
Expr e2; Expr e2;
if (!ATmatch(ATgetFirst(bs), "Bind(<str>, <term>)", &s, &e2)) if (!ATmatch(ATgetFirst(bs), "Bind(<str>, <term>)", &s, &e2))
abort(); /* can't happen */ abort(); /* can't happen */
subs[s] = ATmake("Select(<term>, <str>)", e, s); subs.set(s, ATmake("Select(<term>, <str>)", e, s));
bs = ATgetNext(bs); bs = ATgetNext(bs);
} }
/* Create the non-recursive set. */ /* Create the non-recursive set. */
Attrs as; ATermMap as;
bs = bnds; bs = bnds;
while (!ATisEmpty(bs)) { while (!ATisEmpty(bs)) {
char * s; char * s;
Expr e2; Expr e2;
if (!ATmatch(ATgetFirst(bs), "Bind(<str>, <term>)", &s, &e2)) if (!ATmatch(ATgetFirst(bs), "Bind(<str>, <term>)", &s, &e2))
abort(); /* can't happen */ abort(); /* can't happen */
as[s] = substitute(subs, e2); as.set(s, substitute(subs, e2));
bs = ATgetNext(bs); bs = ATgetNext(bs);
} }
@ -205,18 +217,18 @@ Expr evalExpr(EvalState & state, Expr e)
/* Consult the memo table to quickly get the normal form of /* Consult the memo table to quickly get the normal form of
previously evaluated expressions. */ previously evaluated expressions. */
NormalForms::iterator i = state.normalForms.find(e); Expr nf = state.normalForms.get(e);
if (i != state.normalForms.end()) { if (nf) {
if (i->second == state.blackHole) if (nf == state.blackHole)
throw badTerm("infinite recursion", e); throw badTerm("infinite recursion", e);
state.nrCached++; state.nrCached++;
return i->second; return nf;
} }
/* Otherwise, evaluate and memoize. */ /* Otherwise, evaluate and memoize. */
state.normalForms[e] = state.blackHole; state.normalForms.set(e, state.blackHole);
Expr nf = evalExpr2(state, e); nf = evalExpr2(state, e);
state.normalForms[e] = nf; state.normalForms.set(e, nf);
return nf; return nf;
} }

View file

@ -7,13 +7,12 @@
#include "expr.hh" #include "expr.hh"
typedef map<Expr, Expr> NormalForms;
typedef map<Path, PathSet> DrvPaths; typedef map<Path, PathSet> DrvPaths;
typedef map<Path, Hash> DrvHashes; typedef map<Path, Hash> DrvHashes;
struct EvalState struct EvalState
{ {
NormalForms normalForms; ATermMap normalForms;
DrvPaths drvPaths; DrvPaths drvPaths;
DrvHashes drvHashes; /* normalised derivation hashes */ DrvHashes drvHashes; /* normalised derivation hashes */
Expr blackHole; Expr blackHole;

View file

@ -2,6 +2,91 @@
#include "expr.hh" #include "expr.hh"
ATermMap::ATermMap(unsigned int initialSize, unsigned int maxLoadPct)
{
table = ATtableCreate(initialSize, maxLoadPct);
if (!table) throw Error("cannot create ATerm table");
}
ATermMap::ATermMap(const ATermMap & map)
: table(0)
{
ATermList keys = map.keys();
/* !!! adjust allocation for load pct */
table = ATtableCreate(ATgetLength(keys), map.maxLoadPct);
if (!table) throw Error("cannot create ATerm table");
for (; !ATisEmpty(keys); keys = ATgetNext(keys)) {
ATerm key = ATgetFirst(keys);
set(key, map.get(key));
}
}
ATermMap::~ATermMap()
{
if (table) ATtableDestroy(table);
}
void ATermMap::set(ATerm key, ATerm value)
{
return ATtablePut(table, key, value);
}
void ATermMap::set(const string & key, ATerm value)
{
set(string2ATerm(key), value);
}
ATerm ATermMap::get(ATerm key) const
{
return ATtableGet(table, key);
}
ATerm ATermMap::get(const string & key) const
{
return get(string2ATerm(key));
}
void ATermMap::remove(ATerm key)
{
ATtableRemove(table, key);
}
void ATermMap::remove(const string & key)
{
remove(string2ATerm(key));
}
ATermList ATermMap::keys() const
{
ATermList keys = ATtableKeys(table);
if (!keys) throw Error("cannot query aterm map keys");
return keys;
}
ATerm string2ATerm(const string & s)
{
return (ATerm) ATmakeAppl0(ATmakeAFun((char *) s.c_str(), 0, ATtrue));
}
string aterm2String(ATerm t)
{
return ATgetName(ATgetAFun(t));
}
ATerm bottomupRewrite(TermFun & f, ATerm e) ATerm bottomupRewrite(TermFun & f, ATerm e)
{ {
if (ATgetType(e) == AT_APPL) { if (ATgetType(e) == AT_APPL) {
@ -31,7 +116,7 @@ ATerm bottomupRewrite(TermFun & f, ATerm e)
} }
void queryAllAttrs(Expr e, Attrs & attrs) void queryAllAttrs(Expr e, ATermMap & attrs)
{ {
ATermList bnds; ATermList bnds;
if (!ATmatch(e, "Attrs([<list>])", &bnds)) if (!ATmatch(e, "Attrs([<list>])", &bnds))
@ -42,7 +127,7 @@ void queryAllAttrs(Expr e, Attrs & attrs)
Expr e; Expr e;
if (!ATmatch(ATgetFirst(bnds), "Bind(<str>, <term>)", &s, &e)) if (!ATmatch(ATgetFirst(bnds), "Bind(<str>, <term>)", &s, &e))
abort(); /* can't happen */ abort(); /* can't happen */
attrs[s] = e; attrs.set(s, e);
bnds = ATgetNext(bnds); bnds = ATgetNext(bnds);
} }
} }
@ -50,33 +135,32 @@ void queryAllAttrs(Expr e, Attrs & attrs)
Expr queryAttr(Expr e, const string & name) Expr queryAttr(Expr e, const string & name)
{ {
Attrs attrs; ATermMap attrs;
queryAllAttrs(e, attrs); queryAllAttrs(e, attrs);
Attrs::iterator i = attrs.find(name); return attrs.get(name);
return i == attrs.end() ? 0 : i->second;
} }
Expr makeAttrs(const Attrs & attrs) Expr makeAttrs(const ATermMap & attrs)
{ {
ATermList bnds = ATempty; ATermList bnds = ATempty, keys = attrs.keys();
for (Attrs::const_iterator i = attrs.begin(); i != attrs.end(); i++) while (!ATisEmpty(keys)) {
Expr key = ATgetFirst(keys);
bnds = ATinsert(bnds, bnds = ATinsert(bnds,
ATmake("Bind(<str>, <term>)", i->first.c_str(), i->second)); ATmake("Bind(<term>, <term>)", key, attrs.get(key)));
keys = ATgetNext(keys);
}
return ATmake("Attrs(<term>)", ATreverse(bnds)); return ATmake("Attrs(<term>)", ATreverse(bnds));
} }
ATerm substitute(Subs & subs, ATerm e) Expr substitute(const ATermMap & subs, Expr e)
{ {
char * s; char * s;
if (ATmatch(e, "Var(<str>)", &s)) { if (ATmatch(e, "Var(<str>)", &s)) {
Subs::iterator i = subs.find(s); Expr sub = subs.get(s);
if (i == subs.end()) return sub ? sub : e;
return e;
else
return i->second;
} }
/* In case of a function, filter out all variables bound by this /* In case of a function, filter out all variables bound by this
@ -84,11 +168,11 @@ ATerm substitute(Subs & subs, ATerm e)
ATermList formals; ATermList formals;
ATerm body; ATerm body;
if (ATmatch(e, "Function([<list>], <term>)", &formals, &body)) { if (ATmatch(e, "Function([<list>], <term>)", &formals, &body)) {
Subs subs2(subs); ATermMap subs2(subs);
ATermList fs = formals; ATermList fs = formals;
while (!ATisEmpty(fs)) { while (!ATisEmpty(fs)) {
if (!ATmatch(ATgetFirst(fs), "<str>", &s)) abort(); if (!ATmatch(ATgetFirst(fs), "<str>", &s)) abort();
subs2.erase(s); subs2.remove(s);
fs = ATgetNext(fs); fs = ATgetNext(fs);
} }
return ATmake("Function(<term>, <term>)", formals, return ATmake("Function(<term>, <term>)", formals,
@ -98,13 +182,13 @@ ATerm substitute(Subs & subs, ATerm e)
/* Idem for a mutually recursive attribute set. */ /* Idem for a mutually recursive attribute set. */
ATermList bindings; ATermList bindings;
if (ATmatch(e, "Rec([<list>])", &bindings)) { if (ATmatch(e, "Rec([<list>])", &bindings)) {
Subs subs2(subs); ATermMap subs2(subs);
ATermList bnds = bindings; ATermList bnds = bindings;
while (!ATisEmpty(bnds)) { while (!ATisEmpty(bnds)) {
Expr e; Expr e;
if (!ATmatch(ATgetFirst(bnds), "Bind(<str>, <term>)", &s, &e)) if (!ATmatch(ATgetFirst(bnds), "Bind(<str>, <term>)", &s, &e))
abort(); /* can't happen */ abort(); /* can't happen */
subs2.erase(s); subs2.remove(s);
bnds = ATgetNext(bnds); bnds = ATgetNext(bnds);
} }
return ATmake("Rec(<term>)", substitute(subs2, (ATerm) bindings)); return ATmake("Rec(<term>)", substitute(subs2, (ATerm) bindings));

View file

@ -14,6 +14,38 @@
typedef ATerm Expr; typedef ATerm Expr;
/* Mappings from ATerms to ATerms. This is just a wrapper around
ATerm tables. */
class ATermMap
{
private:
unsigned int maxLoadPct;
ATermTable table;
public:
ATermMap(unsigned int initialSize = 16, unsigned int maxLoadPct = 75);
ATermMap(const ATermMap & map);
~ATermMap();
void set(ATerm key, ATerm value);
void set(const string & key, ATerm value);
ATerm get(ATerm key) const;
ATerm get(const string & key) const;
void remove(ATerm key);
void remove(const string & key);
ATermList keys() const;
};
/* Convert a string to an ATerm (i.e., a quoted nullary function
applicaton). */
ATerm string2ATerm(const string & s);
string aterm2String(ATerm t);
/* Generic bottomup traversal over ATerms. The traversal first /* Generic bottomup traversal over ATerms. The traversal first
recursively descends into subterms, and then applies the given term recursively descends into subterms, and then applies the given term
function to the resulting term. */ function to the resulting term. */
@ -25,19 +57,17 @@ ATerm bottomupRewrite(TermFun & f, ATerm e);
/* Query all attributes in an attribute set expression. The /* Query all attributes in an attribute set expression. The
expression must be in normal form. */ expression must be in normal form. */
typedef map<string, Expr> Attrs; void queryAllAttrs(Expr e, ATermMap & attrs);
void queryAllAttrs(Expr e, Attrs & attrs);
/* Query a specific attribute from an attribute set expression. The /* Query a specific attribute from an attribute set expression. The
expression must be in normal form. */ expression must be in normal form. */
Expr queryAttr(Expr e, const string & name); Expr queryAttr(Expr e, const string & name);
/* Create an attribute set expression from an Attrs value. */ /* Create an attribute set expression from an Attrs value. */
Expr makeAttrs(const Attrs & attrs); Expr makeAttrs(const ATermMap & attrs);
/* Perform a set of substitutions on an expression. */ /* Perform a set of substitutions on an expression. */
typedef map<string, Expr> Subs; Expr substitute(const ATermMap & subs, Expr e);
ATerm substitute(Subs & subs, ATerm e);
#endif /* !__FIXEXPR_H */ #endif /* !__FIXEXPR_H */

View file

@ -123,7 +123,7 @@ Expr primDerivation(EvalState & state, Expr args)
{ {
Nest nest(lvlVomit, "evaluating derivation"); Nest nest(lvlVomit, "evaluating derivation");
Attrs attrs; ATermMap attrs;
args = evalExpr(state, args); args = evalExpr(state, args);
queryAllAttrs(args, attrs); queryAllAttrs(args, attrs);
@ -136,9 +136,11 @@ Expr primDerivation(EvalState & state, Expr args)
Hash outHash; Hash outHash;
bool outHashGiven = false; bool outHashGiven = false;
for (Attrs::iterator i = attrs.begin(); i != attrs.end(); i++) { for (ATermList keys = attrs.keys(); !ATisEmpty(keys);
string key = i->first; keys = ATgetNext(keys))
Expr value = i->second; {
string key = aterm2String(ATgetFirst(keys));
Expr value = attrs.get(key);
Nest nest(lvlVomit, format("processing attribute `%1%'") % key); Nest nest(lvlVomit, format("processing attribute `%1%'") % key);
/* The `args' attribute is special: it supplies the /* The `args' attribute is special: it supplies the
@ -198,9 +200,9 @@ Expr primDerivation(EvalState & state, Expr args)
msg(lvlChatty, format("instantiated `%1%' -> `%2%'") msg(lvlChatty, format("instantiated `%1%' -> `%2%'")
% drvName % drvPath); % drvName % drvPath);
attrs["outPath"] = ATmake("Path(<str>)", outPath.c_str()); attrs.set("outPath", ATmake("Path(<str>)", outPath.c_str()));
attrs["drvPath"] = ATmake("Path(<str>)", drvPath.c_str()); attrs.set("drvPath", ATmake("Path(<str>)", drvPath.c_str()));
attrs["type"] = ATmake("Str(\"derivation\")"); attrs.set("type", ATmake("Str(\"derivation\")"));
return makeAttrs(attrs); return makeAttrs(attrs);
} }