From 9b44480612dd30a7292ec94a88e4018b8f18e3f0 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 4 Feb 2004 16:03:29 +0000 Subject: [PATCH] * Use a map to lookup primops. * Various performance improvements in the evaluator. * Do not link against unused (and missing!) libraries (-lsglr, etc.). --- src/libexpr/eval.cc | 68 +++++++++++++++++++++++++-------- src/libexpr/eval.hh | 11 ++++++ src/libexpr/nixexpr.cc | 23 ++++++++++- src/libexpr/nixexpr.hh | 9 ++++- src/libexpr/parser.cc | 24 ++++-------- src/libexpr/parser.hh | 6 +-- src/libexpr/primops.cc | 12 ++++++ src/libexpr/primops.hh | 6 ++- src/nix-env/Makefile.am | 2 +- src/nix-env/main.cc | 5 ++- src/nix-instantiate/Makefile.am | 2 +- src/nix-instantiate/main.cc | 34 +---------------- 12 files changed, 127 insertions(+), 75 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index bbb1393f8..802b83aa1 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -3,12 +3,52 @@ #include "primops.hh" +static void addPrimOp(ATermMap & map, const string & name, void * f) +{ + map.set(name, (ATerm) ATmakeBlob(0, f)); +} + + +static void * lookupPrimOp(ATermMap & map, ATerm name) +{ + ATermBlob b = (ATermBlob) map.get(name); + if (!b) return 0; + return ATgetBlobData(b); +} + + EvalState::EvalState() - : normalForms(32768, 75) + : normalForms(32768, 50) { blackHole = ATmake("BlackHole()"); if (!blackHole) throw Error("cannot build black hole"); + nrEvaluated = nrCached = 0; + + addPrimOp0("true", primTrue); + addPrimOp0("false", primFalse); + addPrimOp0("null", primNull); + + addPrimOp1("import", primImport); + addPrimOp1("derivation", primDerivation); + addPrimOp1("baseNameOf", primBaseNameOf); + addPrimOp1("toString", primToString); + addPrimOp1("isNull", primIsNull); + + primOpsAll.add(primOps0); + primOpsAll.add(primOps1); +} + + +void EvalState::addPrimOp0(const string & name, PrimOp0 primOp) +{ + addPrimOp(primOps0, name, (void *) primOp); +} + + +void EvalState::addPrimOp1(const string & name, PrimOp1 primOp) +{ + addPrimOp(primOps1, name, (void *) primOp); } @@ -130,7 +170,7 @@ Expr evalExpr2(EvalState & state, Expr e) { ATMatcher m; Expr e1, e2, e3, e4; - string s1; + ATerm name; /* Normal forms. */ if (atMatch(m, e) >> "Str" || @@ -144,11 +184,12 @@ Expr evalExpr2(EvalState & state, Expr e) return e; /* Any encountered variables must be undeclared or primops. */ - if (atMatch(m, e) >> "Var" >> s1) { - if (s1 == "null") return primNull(state); - if (s1 == "true") return ATmake("Bool(True)"); - if (s1 == "false") return ATmake("Bool(False)"); - return e; + if (atMatch(m, e) >> "Var" >> name) { + PrimOp0 primOp = (PrimOp0) lookupPrimOp(state.primOps0, name); + if (primOp) + return primOp(state); + else + return e; } /* Function application. */ @@ -160,13 +201,9 @@ Expr evalExpr2(EvalState & state, Expr e) e1 = evalExpr(state, e1); /* Is it a primop or a function? */ - if (atMatch(m, e1) >> "Var" >> s1) { - if (s1 == "import") return primImport(state, e2); - if (s1 == "derivation") return primDerivation(state, e2); - if (s1 == "toString") return primToString(state, e2); - if (s1 == "baseNameOf") return primBaseNameOf(state, e2); - if (s1 == "isNull") return primIsNull(state, e2); - else throw badTerm("undefined variable/primop", e1); + if (atMatch(m, e1) >> "Var" >> name) { + PrimOp1 primOp = (PrimOp1) lookupPrimOp(state.primOps1, name); + if (primOp) return primOp(state, e2); else abort(); } else if (atMatch(m, e1) >> "Function" >> formals >> e4) @@ -177,6 +214,7 @@ Expr evalExpr2(EvalState & state, Expr e) } /* Attribute selection. */ + string s1; if (atMatch(m, e) >> "Select" >> e1 >> s1) { Expr a = queryAttr(evalExpr(state, e1), s1); if (!a) throw badTerm(format("missing attribute `%1%'") % s1, e); @@ -261,7 +299,7 @@ Expr evalExpr(EvalState & state, Expr e) Expr evalFile(EvalState & state, const Path & path) { startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); - Expr e = parseExprFromFile(path); + Expr e = parseExprFromFile(state, path); return evalExpr(state, e); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 0bc052676..34ac467f1 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -11,9 +11,17 @@ typedef map DrvPaths; typedef map DrvHashes; +struct EvalState; +typedef Expr (* PrimOp0) (EvalState &); +typedef Expr (* PrimOp1) (EvalState &, Expr arg); + + struct EvalState { ATermMap normalForms; + ATermMap primOps0; /* nullary primops */ + ATermMap primOps1; /* unary primops */ + ATermMap primOpsAll; DrvPaths drvPaths; DrvHashes drvHashes; /* normalised derivation hashes */ Expr blackHole; @@ -22,6 +30,9 @@ struct EvalState unsigned int nrCached; EvalState(); + + void addPrimOp0(const string & name, PrimOp0 primOp); + void addPrimOp1(const string & name, PrimOp1 primOp); }; diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 92027a70e..7739e99a9 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -20,8 +20,7 @@ ATermMap::ATermMap(const ATermMap & map) table = ATtableCreate(ATgetLength(keys), maxLoadPct); if (!table) throw Error("cannot create ATerm table"); - for (ATermIterator i(keys); i; ++i) - set(*i, map.get(*i)); + add(map, keys); } @@ -75,6 +74,26 @@ ATermList ATermMap::keys() const } +void ATermMap::add(const ATermMap & map) +{ + ATermList keys = map.keys(); + add(map, keys); +} + + +void ATermMap::add(const ATermMap & map, ATermList & keys) +{ + for (ATermIterator i(keys); i; ++i) + set(*i, map.get(*i)); +} + + +void ATermMap::reset() +{ + ATtableReset(table); +} + + ATerm string2ATerm(const string & s) { return (ATerm) ATmakeAppl0(ATmakeAFun((char *) s.c_str(), 0, ATtrue)); diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 26c29a2f3..924f8b912 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -23,7 +23,7 @@ private: ATermTable table; public: - ATermMap(unsigned int initialSize = 16, unsigned int maxLoadPct = 75); + ATermMap(unsigned int initialSize = 64, unsigned int maxLoadPct = 75); ATermMap(const ATermMap & map); ~ATermMap(); @@ -37,6 +37,13 @@ public: void remove(const string & key); ATermList keys() const; + + void add(const ATermMap & map); + + void reset(); + +private: + void add(const ATermMap & map, ATermList & keys); }; diff --git a/src/libexpr/parser.cc b/src/libexpr/parser.cc index 0a550fb35..68b367340 100644 --- a/src/libexpr/parser.cc +++ b/src/libexpr/parser.cc @@ -66,7 +66,8 @@ int yyparse(yyscan_t scanner, ParseData * data); } -static Expr parse(const char * text, const string & location, +static Expr parse(EvalState & state, + const char * text, const string & location, const Path & basePath) { yyscan_t scanner; @@ -81,18 +82,8 @@ static Expr parse(const char * text, const string & location, if (res) throw Error(data.error); - ATermMap primOps; - primOps.set("import", (ATerm) ATempty); - primOps.set("derivation", (ATerm) ATempty); - primOps.set("true", (ATerm) ATempty); - primOps.set("false", (ATerm) ATempty); - primOps.set("null", (ATerm) ATempty); - primOps.set("isNull", (ATerm) ATempty); - primOps.set("toString", (ATerm) ATempty); - primOps.set("baseNameOf", (ATerm) ATempty); - try { - checkVarDefs(primOps, data.result); + checkVarDefs(state.primOpsAll, data.result); } catch (Error & e) { throw Error(format("%1%, in %2%") % e.msg() % location); } @@ -101,7 +92,7 @@ static Expr parse(const char * text, const string & location, } -Expr parseExprFromFile(Path path) +Expr parseExprFromFile(EvalState & state, Path path) { assert(path[0] == '/'); @@ -137,11 +128,12 @@ Expr parseExprFromFile(Path path) readFull(fd, (unsigned char *) text, st.st_size); text[st.st_size] = 0; - return parse(text, "`" + path + "'", dirOf(path)); + return parse(state, text, "`" + path + "'", dirOf(path)); } -Expr parseExprFromString(const string & s, const Path & basePath) +Expr parseExprFromString(EvalState & state, + const string & s, const Path & basePath) { - return parse(s.c_str(), "(string)", basePath); + return parse(state, s.c_str(), "(string)", basePath); } diff --git a/src/libexpr/parser.hh b/src/libexpr/parser.hh index 461dae08c..2af5385f6 100644 --- a/src/libexpr/parser.hh +++ b/src/libexpr/parser.hh @@ -1,15 +1,15 @@ #ifndef __PARSER_H #define __PARSER_H -#include "nixexpr.hh" +#include "eval.hh" /* Parse a Nix expression from the specified file. If `path' refers to a directory, the "/default.nix" is appended. */ -Expr parseExprFromFile(Path path); +Expr parseExprFromFile(EvalState & state, Path path); /* Parse a Nix expression from the specified string. */ -Expr parseExprFromString(const string & s, +Expr parseExprFromString(EvalState & state, const string & s, const Path & basePath); diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index d1c398a34..92683fcac 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -245,6 +245,18 @@ Expr primToString(EvalState & state, Expr arg) } +Expr primTrue(EvalState & state) +{ + return ATmake("Bool(True)"); +} + + +Expr primFalse(EvalState & state) +{ + return ATmake("Bool(False)"); +} + + Expr primNull(EvalState & state) { return ATmake("Null"); diff --git a/src/libexpr/primops.hh b/src/libexpr/primops.hh index 76d587afd..6b9722dac 100644 --- a/src/libexpr/primops.hh +++ b/src/libexpr/primops.hh @@ -8,7 +8,7 @@ argument. */ Expr primImport(EvalState & state, Expr arg); -/* Construct (as a unobservable) side effect) a Nix derivation +/* Construct (as a unobservable side effect) a Nix derivation expression that performs the derivation described by the argument set. Returns the original set extended with the following attributes: `outPath' containing the primary output path of the @@ -24,6 +24,10 @@ Expr primBaseNameOf(EvalState & state, Expr arg); /* Convert the argument (which can be a path or a uri) to a string. */ Expr primToString(EvalState & state, Expr arg); +/* Boolean constructors. */ +Expr primTrue(EvalState & state); +Expr primFalse(EvalState & state); + /* Return the null value. */ Expr primNull(EvalState & state); diff --git a/src/nix-env/Makefile.am b/src/nix-env/Makefile.am index 53d8d9b02..bfe7369c6 100644 --- a/src/nix-env/Makefile.am +++ b/src/nix-env/Makefile.am @@ -4,7 +4,7 @@ nix_env_SOURCES = main.cc help.txt nix_env_LDADD = ../libmain/libmain.a ../libexpr/libexpr.a \ ../libstore/libstore.a ../libutil/libutil.a \ ../boost/format/libformat.a -L../../externals/inst/lib -ldb_cxx \ - -lsglr -lATB -lconversion -lasfix2 -lmept -lATerm + -lATerm main.o: help.txt.hh diff --git a/src/nix-env/main.cc b/src/nix-env/main.cc index 0fd4ec63a..3810e9144 100644 --- a/src/nix-env/main.cc +++ b/src/nix-env/main.cc @@ -102,7 +102,7 @@ bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs) void loadDerivations(EvalState & state, Path nePath, DrvInfos & drvs) { - Expr e = parseExprFromFile(absPath(nePath)); + Expr e = parseExprFromFile(state, absPath(nePath)); if (!parseDerivations(state, e, drvs)) throw badTerm("expected set of derivations", e); } @@ -193,7 +193,8 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs, const Path & linkPath) { /* Get the environment builder expression. */ - Expr envBuilder = parseExprFromFile(nixDataDir + "/nix/corepkgs/buildenv"); /* !!! */ + Expr envBuilder = parseExprFromFile(state, + nixDataDir + "/nix/corepkgs/buildenv"); /* !!! */ /* Construct the whole top level derivation. */ ATermList inputs = ATempty; diff --git a/src/nix-instantiate/Makefile.am b/src/nix-instantiate/Makefile.am index d04fdb376..0726d1296 100644 --- a/src/nix-instantiate/Makefile.am +++ b/src/nix-instantiate/Makefile.am @@ -4,7 +4,7 @@ nix_instantiate_SOURCES = main.cc help.txt nix_instantiate_LDADD = ../libmain/libmain.a ../libexpr/libexpr.a \ ../libstore/libstore.a ../libutil/libutil.a \ ../boost/format/libformat.a -L../../externals/inst/lib -ldb_cxx \ - -lsglr -lATB -lconversion -lasfix2 -lmept -lATerm + -lATerm main.o: help.txt.hh diff --git a/src/nix-instantiate/main.cc b/src/nix-instantiate/main.cc index 305c3b551..cc3444837 100644 --- a/src/nix-instantiate/main.cc +++ b/src/nix-instantiate/main.cc @@ -15,31 +15,12 @@ void printHelp() } -#if 0 -static Path searchPath(const Paths & searchDirs, const Path & relPath) -{ - if (string(relPath, 0, 1) == "/") return relPath; - - for (Paths::const_iterator i = searchDirs.begin(); - i != searchDirs.end(); i++) - { - Path path = *i + "/" + relPath; - if (pathExists(path)) return path; - } - - throw Error( - format("path `%1%' not found in any of the search directories") - % relPath); -} -#endif - - static Expr evalStdin(EvalState & state) { startNest(nest, lvlTalkative, format("evaluating standard input")); string s, s2; while (getline(cin, s2)) s += s2 + "\n"; - Expr e = parseExprFromString(s, absPath(".")); + Expr e = parseExprFromString(state, s, absPath(".")); return evalExpr(state, e); } @@ -76,24 +57,11 @@ void run(Strings args) Strings files; bool readStdin = false; -#if 0 - state.searchDirs.push_back("."); - state.searchDirs.push_back(nixDataDir + "/nix"); -#endif - for (Strings::iterator it = args.begin(); it != args.end(); ) { string arg = *it++; -#if 0 - if (arg == "--includedir" || arg == "-I") { - if (it == args.end()) - throw UsageError(format("argument required in `%1%'") % arg); - state.searchDirs.push_back(*it++); - } - else -#endif if (arg == "-") readStdin = true; else if (arg[0] == '-')