From 705868a8a96a10f70e629433cfffc2d5cd2703eb Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 4 Oct 2010 17:55:38 +0000 Subject: * Make sure that config.h is included before the system headers, because it defines _FILE_OFFSET_BITS. Without this, on OpenSolaris the system headers define it to be 32, and then the 32-bit stat() ends up being called with a 64-bit "struct stat", or vice versa. This also ensures that we get 64-bit file sizes everywhere. * Remove the redundant call to stat() in parseExprFromFile(). The file cannot be a symlink because that's the exit condition of the loop before. --- src/nix-instantiate/nix-instantiate.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nix-instantiate') diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc index 4d629ea1b333..2925f9c5efb7 100644 --- a/src/nix-instantiate/nix-instantiate.cc +++ b/src/nix-instantiate/nix-instantiate.cc @@ -1,6 +1,3 @@ -#include -#include - #include "globals.hh" #include "shared.hh" #include "eval.hh" @@ -13,6 +10,9 @@ #include "common-opts.hh" #include "help.txt.hh" +#include +#include + using namespace nix; -- cgit 1.4.1 From e879a0371ba7ef99da2d82547823c3f96b445fdb Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 20 Oct 2010 11:38:30 +0000 Subject: * Use the Boehm garbage collector to reclaim unused memory in the Nix expression evaluator. --- src/libexpr/Makefile.am | 3 ++- src/libexpr/eval.cc | 23 ++++++++++++++--------- src/libexpr/eval.hh | 5 ++++- src/nix-env/Makefile.am | 6 ++++-- src/nix-instantiate/Makefile.am | 7 +++++-- 5 files changed, 29 insertions(+), 15 deletions(-) (limited to 'src/nix-instantiate') diff --git a/src/libexpr/Makefile.am b/src/libexpr/Makefile.am index e7228e183581..24aa2968b195 100644 --- a/src/libexpr/Makefile.am +++ b/src/libexpr/Makefile.am @@ -20,7 +20,8 @@ EXTRA_DIST = lexer.l parser.y AM_CXXFLAGS = \ -I$(srcdir)/.. \ - -I$(srcdir)/../libutil -I$(srcdir)/../libstore + -I$(srcdir)/../libutil -I$(srcdir)/../libstore \ + -I/home/eelco/Dev/nix/boehmgc/include # Parser generation. diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index e55f28822b6a..ba331749fe9c 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -8,6 +8,9 @@ #include +#include +#include + #define LocalNoInline(f) static f __attribute__((noinline)); f #define LocalNoInlineNoReturn(f) static f __attribute__((noinline, noreturn)); f @@ -147,7 +150,7 @@ void EvalState::addPrimOp(const string & name, v.type = tPrimOp; v.primOp.arity = arity; v.primOp.fun = primOp; - v.primOp.name = strdup(name2.c_str()); + v.primOp.name = GC_strdup(name2.c_str()); staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl; baseEnv.values[baseEnvDispl++] = v; (*baseEnv.values[0].attrs)[symbols.create(name2)].value = v; @@ -218,7 +221,7 @@ LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2, void mkString(Value & v, const char * s) { v.type = tString; - v.string.s = strdup(s); + v.string.s = GC_strdup(s); v.string.context = 0; } @@ -228,9 +231,10 @@ void mkString(Value & v, const string & s, const PathSet & context) mkString(v, s.c_str()); if (!context.empty()) { unsigned int n = 0; - v.string.context = new const char *[context.size() + 1]; + v.string.context = (const char * *) + GC_malloc((context.size() + 1) * sizeof(char *)); foreach (PathSet::const_iterator, i, context) - v.string.context[n++] = strdup(i->c_str()); + v.string.context[n++] = GC_strdup(i->c_str()); v.string.context[n] = 0; } } @@ -239,7 +243,7 @@ void mkString(Value & v, const string & s, const PathSet & context) void mkPath(Value & v, const char * s) { v.type = tPath; - v.path = strdup(s); + v.path = GC_strdup(s); } @@ -264,7 +268,7 @@ Value * EvalState::lookupVar(Env * env, const VarRef & var) Value * EvalState::allocValues(unsigned int count) { nrValues += count; - return new Value[count]; // !!! check destructor + return (Value *) GC_MALLOC(count * sizeof(Value)); } @@ -272,7 +276,7 @@ Env & EvalState::allocEnv(unsigned int size) { nrEnvs++; nrValuesInEnvs += size; - Env * env = (Env *) malloc(sizeof(Env) + size * sizeof(Value)); + Env * env = (Env *) GC_MALLOC(sizeof(Env) + size * sizeof(Value)); return *env; } @@ -281,7 +285,7 @@ void EvalState::mkList(Value & v, unsigned int length) { v.type = tList; v.list.length = length; - v.list.elems = new Value *[length]; + v.list.elems = (Value * *) GC_MALLOC(length * sizeof(Value *)); nrListElems += length; } @@ -289,7 +293,7 @@ void EvalState::mkList(Value & v, unsigned int length) void EvalState::mkAttrs(Value & v) { v.type = tAttrs; - v.attrs = new Bindings; + v.attrs = new (UseGC) Bindings; } @@ -1089,6 +1093,7 @@ void EvalState::printStats() bool showStats = getEnv("NIX_SHOW_STATS", "0") != "0"; Verbosity v = showStats ? lvlInfo : lvlDebug; printMsg(v, "evaluation statistics:"); + printMsg(v, format(" size of a value: %1%") % sizeof(Value)); printMsg(v, format(" expressions evaluated: %1%") % nrEvaluated); printMsg(v, format(" stack space used: %1% bytes") % (&x - deepestStack)); printMsg(v, format(" max eval() nesting depth: %1%") % maxRecursionDepth); diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 501ac93d016e..d74a0350624d 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -7,6 +7,8 @@ #include +#include + namespace nix { @@ -16,7 +18,7 @@ struct Env; struct Value; struct Attr; -typedef std::map Bindings; +typedef std::map, gc_allocator > > Bindings; typedef enum { @@ -313,6 +315,7 @@ private: char * deepestStack; /* for measuring stack usage */ friend class RecursionCounter; + friend class ExprOpUpdate; }; diff --git a/src/nix-env/Makefile.am b/src/nix-env/Makefile.am index 7dfa7425a062..169c85fcb679 100644 --- a/src/nix-env/Makefile.am +++ b/src/nix-env/Makefile.am @@ -4,7 +4,8 @@ nix_env_SOURCES = nix-env.cc profiles.cc profiles.hh user-env.cc user-env.hh hel nix_env_LDADD = ../libmain/libmain.la ../libexpr/libexpr.la \ ../libstore/libstore.la ../libutil/libutil.la \ - ../boost/format/libformat.la @ADDITIONAL_NETWORK_LIBS@ + ../boost/format/libformat.la @ADDITIONAL_NETWORK_LIBS@ \ + -L/home/eelco/Dev/nix/boehmgc/lib -lgc nix-env.o: help.txt.hh @@ -14,4 +15,5 @@ nix-env.o: help.txt.hh AM_CXXFLAGS = \ -I$(srcdir)/.. \ -I$(srcdir)/../libutil -I$(srcdir)/../libstore \ - -I$(srcdir)/../libexpr -I$(srcdir)/../libmain -I../libexpr + -I$(srcdir)/../libexpr -I$(srcdir)/../libmain -I../libexpr \ + -I/home/eelco/Dev/nix/boehmgc/include diff --git a/src/nix-instantiate/Makefile.am b/src/nix-instantiate/Makefile.am index a65907a8d40a..c6455b116d43 100644 --- a/src/nix-instantiate/Makefile.am +++ b/src/nix-instantiate/Makefile.am @@ -3,7 +3,8 @@ bin_PROGRAMS = nix-instantiate nix_instantiate_SOURCES = nix-instantiate.cc help.txt nix_instantiate_LDADD = ../libmain/libmain.la ../libexpr/libexpr.la \ ../libstore/libstore.la ../libutil/libutil.la \ - ../boost/format/libformat.la @ADDITIONAL_NETWORK_LIBS@ + ../boost/format/libformat.la @ADDITIONAL_NETWORK_LIBS@ \ + -L/home/eelco/Dev/nix/boehmgc/lib -lgc nix-instantiate.o: help.txt.hh @@ -12,4 +13,6 @@ nix-instantiate.o: help.txt.hh AM_CXXFLAGS = \ -I$(srcdir)/.. -I$(srcdir)/../libutil -I$(srcdir)/../libstore \ - -I$(srcdir)/../libexpr -I$(srcdir)/../libmain -I../libexpr + -I$(srcdir)/../libexpr -I$(srcdir)/../libmain -I../libexpr \ + -I/home/eelco/Dev/nix/boehmgc/include + -- cgit 1.4.1 From 64c3325b0bef8c0234bf797033e129323b36ad1e Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 22 Oct 2010 13:39:15 +0000 Subject: * Make building against the Boehm GC a configure option. --- configure.ac | 13 +++++++++++++ src/libexpr/Makefile.am | 3 +-- src/libexpr/eval.cc | 23 ++++++++++++++++++----- src/libexpr/eval.hh | 6 ++++++ src/nix-env/Makefile.am | 5 ++--- src/nix-instantiate/Makefile.am | 6 ++---- 6 files changed, 42 insertions(+), 14 deletions(-) (limited to 'src/nix-instantiate') diff --git a/configure.ac b/configure.ac index 1caa9be5c4a6..02eebf6924b7 100644 --- a/configure.ac +++ b/configure.ac @@ -250,6 +250,19 @@ AC_SUBST(bzip2_bin) AC_SUBST(bzip2_bin_test) +# Whether to use the Boehm garbage collector. +AC_ARG_WITH(boehm-gc, AC_HELP_STRING([--with-boehm-gc=PATH], + [prefix of the Boehm GC package to enable garbage collection in the Nix expression evaluator]), + boehmgc=$withval, boehmgc=) +if test -n "$boehmgc"; then + boehmgc_lib="-L$boehmgc/lib -lgc" + CXXFLAGS="-I$boehmgc/include $CXXFLAGS" + AC_DEFINE(HAVE_BOEHMGC, 1, [Whether to use the Boehm garbage collector.]) +fi +AC_SUBST(boehmgc_lib) +AC_SUBST(boehmgc_include) + + AC_ARG_ENABLE(init-state, AC_HELP_STRING([--disable-init-state], [do not initialise DB etc. in `make install']), init_state=$enableval, init_state=yes) diff --git a/src/libexpr/Makefile.am b/src/libexpr/Makefile.am index 24aa2968b195..e7228e183581 100644 --- a/src/libexpr/Makefile.am +++ b/src/libexpr/Makefile.am @@ -20,8 +20,7 @@ EXTRA_DIST = lexer.l parser.y AM_CXXFLAGS = \ -I$(srcdir)/.. \ - -I$(srcdir)/../libutil -I$(srcdir)/../libstore \ - -I/home/eelco/Dev/nix/boehmgc/include + -I$(srcdir)/../libutil -I$(srcdir)/../libstore # Parser generation. diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 46978f6d0b81..c8a031ac6d0a 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -8,9 +8,18 @@ #include +#if HAVE_BOEHMGC + #include #include +#else + +#define GC_STRDUP strdup +#define GC_MALLOC malloc + +#endif + #define LocalNoInline(f) static f __attribute__((noinline)); f #define LocalNoInlineNoReturn(f) static f __attribute__((noinline, noreturn)); f @@ -151,7 +160,7 @@ void EvalState::addPrimOp(const string & name, v.type = tPrimOp; v.primOp.arity = arity; v.primOp.fun = primOp; - v.primOp.name = GC_strdup(name2.c_str()); + v.primOp.name = GC_STRDUP(name2.c_str()); staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl; baseEnv.values[baseEnvDispl++] = v; (*baseEnv.values[0].attrs)[symbols.create(name2)].value = v; @@ -222,7 +231,7 @@ LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2, void mkString(Value & v, const char * s) { v.type = tString; - v.string.s = GC_strdup(s); + v.string.s = GC_STRDUP(s); v.string.context = 0; } @@ -233,9 +242,9 @@ void mkString(Value & v, const string & s, const PathSet & context) if (!context.empty()) { unsigned int n = 0; v.string.context = (const char * *) - GC_malloc((context.size() + 1) * sizeof(char *)); + GC_MALLOC((context.size() + 1) * sizeof(char *)); foreach (PathSet::const_iterator, i, context) - v.string.context[n++] = GC_strdup(i->c_str()); + v.string.context[n++] = GC_STRDUP(i->c_str()); v.string.context[n] = 0; } } @@ -244,7 +253,7 @@ void mkString(Value & v, const string & s, const PathSet & context) void mkPath(Value & v, const char * s) { v.type = tPath; - v.path = GC_strdup(s); + v.path = GC_STRDUP(s); } @@ -294,7 +303,11 @@ void EvalState::mkList(Value & v, unsigned int length) void EvalState::mkAttrs(Value & v) { v.type = tAttrs; +#if HAVE_BOEHMGC v.attrs = new (UseGC) Bindings; +#else + v.attrs = new Bindings; +#endif nrAttrsets++; } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 9144d99a4b38..738ca9439f6d 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -7,7 +7,9 @@ #include +#if HAVE_BOEHMGC #include +#endif namespace nix { @@ -18,7 +20,11 @@ struct Env; struct Value; struct Attr; +#if HAVE_BOEHMGC typedef std::map, gc_allocator > > Bindings; +#else +typedef std::map Bindings; +#endif typedef enum { diff --git a/src/nix-env/Makefile.am b/src/nix-env/Makefile.am index 169c85fcb679..a876b3eb386d 100644 --- a/src/nix-env/Makefile.am +++ b/src/nix-env/Makefile.am @@ -5,7 +5,7 @@ nix_env_SOURCES = nix-env.cc profiles.cc profiles.hh user-env.cc user-env.hh hel nix_env_LDADD = ../libmain/libmain.la ../libexpr/libexpr.la \ ../libstore/libstore.la ../libutil/libutil.la \ ../boost/format/libformat.la @ADDITIONAL_NETWORK_LIBS@ \ - -L/home/eelco/Dev/nix/boehmgc/lib -lgc + @boehmgc_lib@ nix-env.o: help.txt.hh @@ -15,5 +15,4 @@ nix-env.o: help.txt.hh AM_CXXFLAGS = \ -I$(srcdir)/.. \ -I$(srcdir)/../libutil -I$(srcdir)/../libstore \ - -I$(srcdir)/../libexpr -I$(srcdir)/../libmain -I../libexpr \ - -I/home/eelco/Dev/nix/boehmgc/include + -I$(srcdir)/../libexpr -I$(srcdir)/../libmain -I../libexpr diff --git a/src/nix-instantiate/Makefile.am b/src/nix-instantiate/Makefile.am index c6455b116d43..bc9792818c3c 100644 --- a/src/nix-instantiate/Makefile.am +++ b/src/nix-instantiate/Makefile.am @@ -4,7 +4,7 @@ nix_instantiate_SOURCES = nix-instantiate.cc help.txt nix_instantiate_LDADD = ../libmain/libmain.la ../libexpr/libexpr.la \ ../libstore/libstore.la ../libutil/libutil.la \ ../boost/format/libformat.la @ADDITIONAL_NETWORK_LIBS@ \ - -L/home/eelco/Dev/nix/boehmgc/lib -lgc + @boehmgc_lib@ nix-instantiate.o: help.txt.hh @@ -13,6 +13,4 @@ nix-instantiate.o: help.txt.hh AM_CXXFLAGS = \ -I$(srcdir)/.. -I$(srcdir)/../libutil -I$(srcdir)/../libstore \ - -I$(srcdir)/../libexpr -I$(srcdir)/../libmain -I../libexpr \ - -I/home/eelco/Dev/nix/boehmgc/include - + -I$(srcdir)/../libexpr -I$(srcdir)/../libmain -I../libexpr -- cgit 1.4.1 From 41c45a9b319a5578e2731505ca3de2b9c50b4988 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 22 Oct 2010 14:47:42 +0000 Subject: * Store Value nodes outside of attribute sets. I.e., Attr now stores a pointer to a Value, rather than the Value directly. This improves the effectiveness of garbage collection a lot: if the Value is stored inside the set directly, then any live pointer to the Value causes all other attributes in the set to be live as well. --- src/libexpr/Makefile.am | 2 +- src/libexpr/attr-path.cc | 5 +- src/libexpr/attr-path.hh | 2 +- src/libexpr/common-opts.cc | 7 +-- src/libexpr/eval.cc | 97 ++++++++++++++++++++-------------- src/libexpr/eval.hh | 7 ++- src/libexpr/get-drvs.cc | 40 +++++++------- src/libexpr/get-drvs.hh | 2 +- src/libexpr/nixexpr.cc | 4 +- src/libexpr/nixexpr.hh | 1 + src/libexpr/primops.cc | 70 ++++++++++++------------ src/libexpr/value-to-xml.cc | 14 ++--- src/nix-env/nix-env.cc | 4 +- src/nix-env/user-env.cc | 23 ++++---- src/nix-instantiate/nix-instantiate.cc | 2 +- 15 files changed, 150 insertions(+), 130 deletions(-) (limited to 'src/nix-instantiate') diff --git a/src/libexpr/Makefile.am b/src/libexpr/Makefile.am index e7228e183581..6c38ecdd565f 100644 --- a/src/libexpr/Makefile.am +++ b/src/libexpr/Makefile.am @@ -11,7 +11,7 @@ pkginclude_HEADERS = \ names.hh symbol-table.hh libexpr_la_LIBADD = ../libutil/libutil.la ../libstore/libstore.la \ - ../boost/format/libformat.la + ../boost/format/libformat.la @boehmgc_lib@ BUILT_SOURCES = \ parser-tab.hh lexer-tab.hh parser-tab.cc lexer-tab.cc diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc index 0660ba1c1efc..365b03c0bf60 100644 --- a/src/libexpr/attr-path.cc +++ b/src/libexpr/attr-path.cc @@ -5,8 +5,9 @@ namespace nix { +// !!! Shouldn't we return a pointer to a Value? void findAlongAttrPath(EvalState & state, const string & attrPath, - const Bindings & autoArgs, Expr * e, Value & v) + Bindings & autoArgs, Expr * e, Value & v) { Strings tokens = tokenizeString(attrPath, "."); @@ -48,7 +49,7 @@ void findAlongAttrPath(EvalState & state, const string & attrPath, Bindings::iterator a = v.attrs->find(state.symbols.create(attr)); if (a == v.attrs->end()) throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath); - v = a->second.value; + v = *a->second.value; } else if (apType == apIndex) { diff --git a/src/libexpr/attr-path.hh b/src/libexpr/attr-path.hh index b4f5c29d2ed8..b106da5ef817 100644 --- a/src/libexpr/attr-path.hh +++ b/src/libexpr/attr-path.hh @@ -11,7 +11,7 @@ namespace nix { void findAlongAttrPath(EvalState & state, const string & attrPath, - const Bindings & autoArgs, Expr * e, Value & v); + Bindings & autoArgs, Expr * e, Value & v); } diff --git a/src/libexpr/common-opts.cc b/src/libexpr/common-opts.cc index 9131951e315d..6b393c07df50 100644 --- a/src/libexpr/common-opts.cc +++ b/src/libexpr/common-opts.cc @@ -20,12 +20,13 @@ bool parseOptionArg(const string & arg, Strings::iterator & i, if (i == argsEnd) throw error; string value = *i++; - Value & v(autoArgs[state.symbols.create(name)].value); + Value * v = state.allocValue(); + autoArgs[state.symbols.create(name)].value = v; if (arg == "--arg") - state.mkThunk_(v, parseExprFromString(state, value, absPath("."))); + state.mkThunk_(*v, parseExprFromString(state, value, absPath("."))); else - mkString(v, value); + mkString(*v, value); return true; } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index c8a031ac6d0a..ea48947258ec 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -58,7 +58,7 @@ std::ostream & operator << (std::ostream & str, const Value & v) typedef std::map Sorted; Sorted sorted; foreach (Bindings::iterator, i, *v.attrs) - sorted[i->first] = &i->second.value; + sorted[i->first] = i->second.value; foreach (Sorted::iterator, i, sorted) str << i->first << " = " << *i->second << "; "; str << "}"; @@ -145,24 +145,26 @@ EvalState::~EvalState() void EvalState::addConstant(const string & name, Value & v) { + Value * v2 = allocValue(); + *v2 = v; staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl; baseEnv.values[baseEnvDispl++] = v; string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; - (*baseEnv.values[0].attrs)[symbols.create(name2)].value = v; + (*baseEnv.values[0].attrs)[symbols.create(name2)].value = v2; } void EvalState::addPrimOp(const string & name, unsigned int arity, PrimOp primOp) { - Value v; + Value * v = allocValue(); string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name; - v.type = tPrimOp; - v.primOp.arity = arity; - v.primOp.fun = primOp; - v.primOp.name = GC_STRDUP(name2.c_str()); + v->type = tPrimOp; + v->primOp.arity = arity; + v->primOp.fun = primOp; + v->primOp.name = GC_STRDUP(name2.c_str()); staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl; - baseEnv.values[baseEnvDispl++] = v; + baseEnv.values[baseEnvDispl++] = *v; (*baseEnv.values[0].attrs)[symbols.create(name2)].value = v; } @@ -265,7 +267,7 @@ Value * EvalState::lookupVar(Env * env, const VarRef & var) while (1) { Bindings::iterator j = env->values[0].attrs->find(var.name); if (j != env->values[0].attrs->end()) - return &j->second.value; + return j->second.value; if (env->prevWith == 0) throwEvalError("undefined variable `%1%'", var.name); for (unsigned int l = env->prevWith; l; --l, env = env->up) ; @@ -275,6 +277,13 @@ Value * EvalState::lookupVar(Env * env, const VarRef & var) } +Value * EvalState::allocValue() +{ + nrValues++; + return (Value *) GC_MALLOC(sizeof(Value)); +} + + Value * EvalState::allocValues(unsigned int count) { nrValues += count; @@ -291,6 +300,14 @@ Env & EvalState::allocEnv(unsigned int size) } +Value * EvalState::allocAttr(Value & vAttrs, const Symbol & name) +{ + Attr & a = (*vAttrs.attrs)[name]; + a.value = allocValue(); + return a.value; +} + + void EvalState::mkList(Value & v, unsigned int length) { v.type = tList; @@ -321,11 +338,8 @@ void EvalState::mkThunk_(Value & v, Expr * expr) void EvalState::cloneAttrs(Value & src, Value & dst) { mkAttrs(dst); - foreach (Bindings::iterator, i, *src.attrs) { - Attr & a = (*dst.attrs)[i->first]; - mkCopy(a.value, i->second.value); - a.pos = i->second.pos; - } + foreach (Bindings::iterator, i, *src.attrs) + (*dst.attrs)[i->first] = i->second; } @@ -449,8 +463,9 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) environment. */ foreach (Attrs::iterator, i, attrs) { nix::Attr & a = (*v.attrs)[i->first]; - mkThunk(a.value, env2, i->second.first); - mkCopy(env2.values[displ++], a.value); + a.value = state.allocValue(); + mkThunk(*a.value, env2, i->second.first); + mkCopy(env2.values[displ++], *a.value); a.pos = &i->second.second; } @@ -459,7 +474,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) foreach (list::iterator, i, inherited) { nix::Attr & a = (*v.attrs)[i->first.name]; Value * v2 = state.lookupVar(&env, i->first); - mkCopy(a.value, *v2); + a.value = v2; mkCopy(env2.values[displ++], *v2); a.pos = &i->second; } @@ -474,10 +489,12 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) Hence we need __overrides.) */ Bindings::iterator overrides = v.attrs->find(state.sOverrides); if (overrides != v.attrs->end()) { - state.forceAttrs(overrides->second.value); - foreach (Bindings::iterator, i, *overrides->second.value.attrs) { + state.forceAttrs(*overrides->second.value); + foreach (Bindings::iterator, i, *overrides->second.value->attrs) { nix::Attr & a = (*v.attrs)[i->first]; - mkCopy(a.value, i->second.value); + if (a.value) + mkCopy(env2.values[displs[i->first]], *i->second.value); + a = i->second; } } } @@ -485,13 +502,14 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) else { foreach (Attrs::iterator, i, attrs) { nix::Attr & a = (*v.attrs)[i->first]; - mkThunk(a.value, env, i->second.first); + a.value = state.allocValue(); + mkThunk(*a.value, env, i->second.first); a.pos = &i->second.second; } foreach (list::iterator, i, inherited) { nix::Attr & a = (*v.attrs)[i->first.name]; - mkCopy(a.value, *state.lookupVar(&env, i->first)); + a.value = state.lookupVar(&env, i->first); a.pos = &i->second; } } @@ -548,13 +566,13 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) if (i == v2.attrs->end()) throwEvalError("attribute `%1%' missing", name); try { - state.forceValue(i->second.value); + state.forceValue(*i->second.value); } catch (Error & e) { addErrorPrefix(e, "while evaluating the attribute `%1%' at %2%:\n", name, *i->second.pos); throw; } - v = i->second.value; + v = *i->second.value; } @@ -578,9 +596,9 @@ void ExprApp::eval(EvalState & state, Env & env, Value & v) { Value vFun; state.eval(env, e1, vFun); - Value vArg; - mkThunk(vArg, env, e2); // !!! should this be on the heap? - state.callFunction(vFun, vArg, v); + Value * vArg = state.allocValue(); + mkThunk(*vArg, env, e2); + state.callFunction(vFun, *vArg, v); } @@ -656,7 +674,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v) mkThunk(env2.values[displ++], env2, i->def); } else { attrsUsed++; - mkCopy(env2.values[displ++], j->second.value); + mkCopy(env2.values[displ++], *j->second.value); } } @@ -677,7 +695,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v) } -void EvalState::autoCallFunction(const Bindings & args, Value & fun, Value & res) +void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) { forceValue(fun); @@ -690,7 +708,7 @@ void EvalState::autoCallFunction(const Bindings & args, Value & fun, Value & res mkAttrs(actualArgs); foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) { - Bindings::const_iterator j = args.find(i->name); + Bindings::iterator j = args.find(i->name); if (j != args.end()) (*actualArgs.attrs)[i->name] = j->second; else if (!i->def) @@ -780,11 +798,8 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v) state.cloneAttrs(v1, v); - foreach (Bindings::iterator, i, *v2.attrs) { - Attr & a = (*v.attrs)[i->first]; - mkCopy(a.value, i->second.value); - a.pos = i->second.pos; - } + foreach (Bindings::iterator, i, *v2.attrs) + (*v.attrs)[i->first] = i->second; state.nrOpUpdateValuesCopied += v.attrs->size(); } @@ -866,7 +881,7 @@ void EvalState::strictForceValue(Value & v) if (v.type == tAttrs) { foreach (Bindings::iterator, i, *v.attrs) - strictForceValue(i->second.value); + strictForceValue(*i->second.value); } else if (v.type == tList) { @@ -957,7 +972,7 @@ bool EvalState::isDerivation(Value & v) { if (v.type != tAttrs) return false; Bindings::iterator i = v.attrs->find(sType); - return i != v.attrs->end() && forceStringNoCtx(i->second.value) == "derivation"; + return i != v.attrs->end() && forceStringNoCtx(*i->second.value) == "derivation"; } @@ -1001,7 +1016,7 @@ string EvalState::coerceToString(Value & v, PathSet & context, Bindings::iterator i = v.attrs->find(sOutPath); if (i == v.attrs->end()) throwTypeError("cannot coerce an attribute set (except a derivation) to a string"); - return coerceToString(i->second.value, context, coerceMore, copyToStore); + return coerceToString(*i->second.value, context, coerceMore, copyToStore); } if (coerceMore) { @@ -1087,9 +1102,9 @@ bool EvalState::eqValues(Value & v1, Value & v2) case tAttrs: { if (v1.attrs->size() != v2.attrs->size()) return false; - Bindings::iterator i, j; - for (i = v1.attrs->begin(), j = v2.attrs->begin(); i != v1.attrs->end(); ++i, ++j) - if (i->first != j->first || !eqValues(i->second.value, j->second.value)) + Bindings::iterator i = v1.attrs->begin(), j = v2.attrs->begin(); + for ( ; i != v1.attrs->end(); ++i, ++j) + if (i->first != j->first || !eqValues(*i->second.value, *j->second.value)) return false; return true; } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 738ca9439f6d..ee7db91a08b2 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -122,7 +122,7 @@ struct Env struct Attr { - Value value; + Value * value; Pos * pos; Attr() : pos(&noPos) { }; }; @@ -294,12 +294,15 @@ public: /* Automatically call a function for which each argument has a default value or has a binding in the `args' map. */ - void autoCallFunction(const Bindings & args, Value & fun, Value & res); + void autoCallFunction(Bindings & args, Value & fun, Value & res); /* Allocation primitives. */ + Value * allocValue(); Value * allocValues(unsigned int count); Env & allocEnv(unsigned int size); + Value * allocAttr(Value & vAttrs, const Symbol & name); + void mkList(Value & v, unsigned int length); void mkAttrs(Value & v); void mkThunk_(Value & v, Expr * expr); diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 82a92416bed6..63106b87b5af 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -10,7 +10,7 @@ string DrvInfo::queryDrvPath(EvalState & state) const if (drvPath == "" && attrs) { Bindings::iterator i = attrs->find(state.sDrvPath); PathSet context; - (string &) drvPath = i != attrs->end() ? state.coerceToPath(i->second.value, context) : ""; + (string &) drvPath = i != attrs->end() ? state.coerceToPath(*i->second.value, context) : ""; } return drvPath; } @@ -21,7 +21,7 @@ string DrvInfo::queryOutPath(EvalState & state) const if (outPath == "" && attrs) { Bindings::iterator i = attrs->find(state.sOutPath); PathSet context; - (string &) outPath = i != attrs->end() ? state.coerceToPath(i->second.value, context) : ""; + (string &) outPath = i != attrs->end() ? state.coerceToPath(*i->second.value, context) : ""; } return outPath; } @@ -36,21 +36,21 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const Bindings::iterator a = attrs->find(state.sMeta); if (a == attrs->end()) return meta; /* fine, empty meta information */ - state.forceAttrs(a->second.value); + state.forceAttrs(*a->second.value); - foreach (Bindings::iterator, i, *a->second.value.attrs) { + foreach (Bindings::iterator, i, *a->second.value->attrs) { MetaValue value; - state.forceValue(i->second.value); - if (i->second.value.type == tString) { + state.forceValue(*i->second.value); + if (i->second.value->type == tString) { value.type = MetaValue::tpString; - value.stringValue = i->second.value.string.s; - } else if (i->second.value.type == tInt) { + value.stringValue = i->second.value->string.s; + } else if (i->second.value->type == tInt) { value.type = MetaValue::tpInt; - value.intValue = i->second.value.integer; - } else if (i->second.value.type == tList) { + value.intValue = i->second.value->integer; + } else if (i->second.value->type == tList) { value.type = MetaValue::tpStrings; - for (unsigned int j = 0; j < i->second.value.list.length; ++j) - value.stringValues.push_back(state.forceStringNoCtx(*i->second.value.list.elems[j])); + for (unsigned int j = 0; j < i->second.value->list.length; ++j) + value.stringValues.push_back(state.forceStringNoCtx(*i->second.value->list.elems[j])); } else continue; ((MetaInfo &) meta)[i->first] = value; } @@ -99,13 +99,13 @@ static bool getDerivation(EvalState & state, Value & v, Bindings::iterator i = v.attrs->find(state.sName); /* !!! We really would like to have a decent back trace here. */ if (i == v.attrs->end()) throw TypeError("derivation name missing"); - drv.name = state.forceStringNoCtx(i->second.value); + drv.name = state.forceStringNoCtx(*i->second.value); - i = v.attrs->find(state.sSystem); - if (i == v.attrs->end()) + Bindings::iterator i2 = v.attrs->find(state.sSystem); + if (i2 == v.attrs->end()) drv.system = "unknown"; else - drv.system = state.forceStringNoCtx(i->second.value); + drv.system = state.forceStringNoCtx(*i2->second.value); drv.attrs = v.attrs; @@ -138,7 +138,7 @@ static string addToPath(const string & s1, const string & s2) static void getDerivations(EvalState & state, Value & vIn, - const string & pathPrefix, const Bindings & autoArgs, + const string & pathPrefix, Bindings & autoArgs, DrvInfos & drvs, Done & done) { Value v; @@ -168,7 +168,7 @@ static void getDerivations(EvalState & state, Value & vIn, foreach (SortedSymbols::iterator, i, attrs) { startNest(nest, lvlDebug, format("evaluating attribute `%1%'") % i->first); string pathPrefix2 = addToPath(pathPrefix, i->first); - Value & v2((*v.attrs)[i->second].value); + Value & v2(*(*v.attrs)[i->second].value); if (combineChannels) getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done); else if (getDerivation(state, v2, pathPrefix2, drvs, done)) { @@ -178,7 +178,7 @@ static void getDerivations(EvalState & state, Value & vIn, attribute. */ if (v2.type == tAttrs) { Bindings::iterator j = v2.attrs->find(state.symbols.create("recurseForDerivations")); - if (j != v2.attrs->end() && state.forceBool(j->second.value)) + if (j != v2.attrs->end() && state.forceBool(*j->second.value)) getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done); } } @@ -200,7 +200,7 @@ static void getDerivations(EvalState & state, Value & vIn, void getDerivations(EvalState & state, Value & v, const string & pathPrefix, - const Bindings & autoArgs, DrvInfos & drvs) + Bindings & autoArgs, DrvInfos & drvs) { Done done; getDerivations(state, v, pathPrefix, autoArgs, drvs, done); diff --git a/src/libexpr/get-drvs.hh b/src/libexpr/get-drvs.hh index 7b96decf4a08..7c014b7e41f2 100644 --- a/src/libexpr/get-drvs.hh +++ b/src/libexpr/get-drvs.hh @@ -70,7 +70,7 @@ typedef list DrvInfos; bool getDerivation(EvalState & state, Value & v, DrvInfo & drv); void getDerivations(EvalState & state, Value & v, const string & pathPrefix, - const Bindings & autoArgs, DrvInfos & drvs); + Bindings & autoArgs, DrvInfos & drvs); } diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 898fdb609417..9f2ea78831f2 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -213,10 +213,10 @@ void ExprAttrs::bindVars(const StaticEnv & env) unsigned int displ = 0; foreach (ExprAttrs::Attrs::iterator, i, attrs) - newEnv.vars[i->first] = displ++; + displs[i->first] = newEnv.vars[i->first] = displ++; foreach (list::iterator, i, inherited) { - newEnv.vars[i->first.name] = displ++; + displs[i->first.name] = newEnv.vars[i->first.name] = displ++; i->first.bind(env); } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 1d03220f644a..5c0071dca2ce 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -137,6 +137,7 @@ struct ExprAttrs : Expr Attrs attrs; list inherited; std::map attrNames; // used during parsing + std::map displs; ExprAttrs() : recursive(false) { }; COMMON_METHODS }; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 973670e68384..c7709ca9eb36 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -119,24 +119,24 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v) args[0]->attrs->find(state.symbols.create("startSet")); if (startSet == args[0]->attrs->end()) throw EvalError("attribute `startSet' required"); - state.forceList(startSet->second.value); + state.forceList(*startSet->second.value); list workSet; - for (unsigned int n = 0; n < startSet->second.value.list.length; ++n) - workSet.push_back(startSet->second.value.list.elems[n]); + for (unsigned int n = 0; n < startSet->second.value->list.length; ++n) + workSet.push_back(startSet->second.value->list.elems[n]); /* Get the operator. */ Bindings::iterator op = args[0]->attrs->find(state.symbols.create("operator")); if (op == args[0]->attrs->end()) throw EvalError("attribute `operator' required"); - state.forceValue(op->second.value); + state.forceValue(*op->second.value); /* Construct the closure by applying the operator to element of `workSet', adding the result to `workSet', continuing until no new elements are found. */ list res; - set doneKeys; + set doneKeys; // !!! use Value *? while (!workSet.empty()) { Value * e = *(workSet.begin()); workSet.pop_front(); @@ -147,15 +147,15 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v) e->attrs->find(state.symbols.create("key")); if (key == e->attrs->end()) throw EvalError("attribute `key' required"); - state.forceValue(key->second.value); + state.forceValue(*key->second.value); - if (doneKeys.find(key->second.value) != doneKeys.end()) continue; - doneKeys.insert(key->second.value); + if (doneKeys.find(*key->second.value) != doneKeys.end()) continue; + doneKeys.insert(*key->second.value); res.push_back(*e); /* Call the `operator' function with `e' as argument. */ Value call; - mkApp(call, op->second.value, *e); + mkApp(call, *op->second.value, *e); state.forceList(call); /* Add the values returned by the operator to the work set. */ @@ -213,11 +213,13 @@ static void prim_tryEval(EvalState & state, Value * * args, Value & v) state.mkAttrs(v); try { state.forceValue(*args[0]); - (*v.attrs)[state.symbols.create("value")].value = *args[0]; - mkBool((*v.attrs)[state.symbols.create("success")].value, true); + printMsg(lvlError, format("%1%") % *args[0]); + (*v.attrs)[state.symbols.create("value")].value = args[0]; + mkBool(*state.allocAttr(v, state.symbols.create("success")), true); + printMsg(lvlError, format("%1%") % v); } catch (AssertionError & e) { - mkBool((*v.attrs)[state.symbols.create("value")].value, false); - mkBool((*v.attrs)[state.symbols.create("success")].value, false); + mkBool(*state.allocAttr(v, state.symbols.create("value")), false); + mkBool(*state.allocAttr(v, state.symbols.create("success")), false); } } @@ -326,7 +328,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) string drvName; Pos & posDrvName(*attr->second.pos); try { - drvName = state.forceStringNoCtx(attr->second.value); + drvName = state.forceStringNoCtx(*attr->second.value); } catch (Error & e) { e.addPrefix(format("while evaluating the derivation attribute `name' at %1%:\n") % posDrvName); throw; @@ -349,9 +351,9 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) /* The `args' attribute is special: it supplies the command-line arguments to the builder. */ if (key == "args") { - state.forceList(i->second.value); - for (unsigned int n = 0; n < i->second.value.list.length; ++n) { - string s = state.coerceToString(*i->second.value.list.elems[n], context, true); + state.forceList(*i->second.value); + for (unsigned int n = 0; n < i->second.value->list.length; ++n) { + string s = state.coerceToString(*i->second.value->list.elems[n], context, true); drv.args.push_back(s); } } @@ -359,7 +361,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) /* All other attributes are passed to the builder through the environment. */ else { - string s = state.coerceToString(i->second.value, context, true); + string s = state.coerceToString(*i->second.value, context, true); drv.env[key] = s; if (key == "builder") drv.builder = s; else if (i->first == state.sSystem) drv.platform = s; @@ -488,8 +490,8 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) /* !!! assumes a single output */ state.mkAttrs(v); - mkString((*v.attrs)[state.sOutPath].value, outPath, singleton(drvPath)); - mkString((*v.attrs)[state.sDrvPath].value, drvPath, singleton("=" + drvPath)); + mkString(*state.allocAttr(v, state.sOutPath), outPath, singleton(drvPath)); + mkString(*state.allocAttr(v, state.sDrvPath), drvPath, singleton("=" + drvPath)); } @@ -713,8 +715,8 @@ static void prim_getAttr(EvalState & state, Value * * args, Value & v) if (i == args[1]->attrs->end()) throw EvalError(format("attribute `%1%' missing") % attr); // !!! add to stack trace? - state.forceValue(i->second.value); - v = i->second.value; + state.forceValue(*i->second.value); + v = *i->second.value; } @@ -766,15 +768,13 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v) Bindings::iterator j = v2.attrs->find(state.sName); if (j == v2.attrs->end()) throw TypeError("`name' attribute missing in a call to `listToAttrs'"); - string name = state.forceStringNoCtx(j->second.value); + string name = state.forceStringNoCtx(*j->second.value); - j = v2.attrs->find(state.symbols.create("value")); - if (j == v2.attrs->end()) + Bindings::iterator j2 = v2.attrs->find(state.symbols.create("value")); + if (j2 == v2.attrs->end()) throw TypeError("`value' attribute missing in a call to `listToAttrs'"); - Attr & a = (*v.attrs)[state.symbols.create(name)]; - mkCopy(a.value, j->second.value); - a.pos = j->second.pos; + (*v.attrs)[state.symbols.create(name)] = j2->second; } } @@ -791,11 +791,8 @@ static void prim_intersectAttrs(EvalState & state, Value * * args, Value & v) foreach (Bindings::iterator, i, *args[0]->attrs) { Bindings::iterator j = args[1]->attrs->find(i->first); - if (j != args[1]->attrs->end()) { - Attr & a = (*v.attrs)[j->first]; - mkCopy(a.value, j->second.value); - a.pos = j->second.pos; - } + if (j != args[1]->attrs->end()) + (*v.attrs)[j->first] = j->second; } } @@ -824,7 +821,8 @@ static void prim_functionArgs(EvalState & state, Value * * args, Value & v) if (!args[0]->lambda.fun->matchAttrs) return; foreach (Formals::Formals_::iterator, i, args[0]->lambda.fun->formals->formals) - mkBool((*v.attrs)[i->name].value, i->def); + // !!! should optimise booleans (allocate only once) + mkBool(*state.allocAttr(v, i->name), i->def); } @@ -1007,8 +1005,8 @@ static void prim_parseDrvName(EvalState & state, Value * * args, Value & v) string name = state.forceStringNoCtx(*args[0]); DrvName parsed(name); state.mkAttrs(v); - mkString((*v.attrs)[state.sName].value, parsed.name); - mkString((*v.attrs)[state.symbols.create("version")].value, parsed.version); + mkString(*state.allocAttr(v, state.sName), parsed.name); + mkString(*state.allocAttr(v, state.symbols.create("version")), parsed.version); } diff --git a/src/libexpr/value-to-xml.cc b/src/libexpr/value-to-xml.cc index 8955a8a33931..1bb200fb858b 100644 --- a/src/libexpr/value-to-xml.cc +++ b/src/libexpr/value-to-xml.cc @@ -45,7 +45,7 @@ static void showAttrs(EvalState & state, bool strict, bool location, XMLOpenElement _(doc, "attr", xmlAttrs); printValueAsXML(state, strict, location, - a.value, doc, context, drvsSeen); + *a.value, doc, context, drvsSeen); } } @@ -90,16 +90,16 @@ static void printValueAsXML(EvalState & state, bool strict, bool location, Path drvPath; a = v.attrs->find(state.sDrvPath); if (a != v.attrs->end()) { - if (strict) state.forceValue(a->second.value); - if (a->second.value.type == tString) - xmlAttrs["drvPath"] = drvPath = a->second.value.string.s; + if (strict) state.forceValue(*a->second.value); + if (a->second.value->type == tString) + xmlAttrs["drvPath"] = drvPath = a->second.value->string.s; } a = v.attrs->find(state.sOutPath); if (a != v.attrs->end()) { - if (strict) state.forceValue(a->second.value); - if (a->second.value.type == tString) - xmlAttrs["outPath"] = a->second.value.string.s; + if (strict) state.forceValue(*a->second.value); + if (a->second.value->type == tString) + xmlAttrs["outPath"] = a->second.value->string.s; } XMLOpenElement _(doc, "derivation", xmlAttrs); diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index df32b9f603ab..4895c68e94a8 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -161,7 +161,7 @@ static Expr * loadSourceExpr(EvalState & state, const Path & path) static void loadDerivations(EvalState & state, Path nixExprPath, - string systemFilter, const Bindings & autoArgs, + string systemFilter, Bindings & autoArgs, const string & pathPrefix, DrvInfos & elems) { Value v; @@ -321,7 +321,7 @@ static bool isPath(const string & s) static void queryInstSources(EvalState & state, - const InstallSourceInfo & instSource, const Strings & args, + InstallSourceInfo & instSource, const Strings & args, DrvInfos & elems, bool newestOnly) { InstallSourceType type = instSource.type; diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc index 0a619f698f98..07c94fe4d49a 100644 --- a/src/nix-env/user-env.cc +++ b/src/nix-env/user-env.cc @@ -25,7 +25,8 @@ DrvInfos queryInstalled(EvalState & state, const Path & userEnv) if (pathExists(manifestFile)) { Value v; state.eval(parseExprFromFile(state, manifestFile), v); - getDerivations(state, v, "", Bindings(), elems); + Bindings bindings; + getDerivations(state, v, "", bindings, elems); } else if (pathExists(oldManifestFile)) readLegacyManifest(oldManifestFile, elems); @@ -62,19 +63,19 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, manifest.list.elems[n++] = &v; state.mkAttrs(v); - mkString((*v.attrs)[state.sType].value, "derivation"); - mkString((*v.attrs)[state.sName].value, i->name); - mkString((*v.attrs)[state.sSystem].value, i->system); - mkString((*v.attrs)[state.sOutPath].value, i->queryOutPath(state)); + mkString(*state.allocAttr(v, state.sType), "derivation"); + mkString(*state.allocAttr(v, state.sName), i->name); + mkString(*state.allocAttr(v, state.sSystem), i->system); + mkString(*state.allocAttr(v, state.sOutPath), i->queryOutPath(state)); if (drvPath != "") - mkString((*v.attrs)[state.sDrvPath].value, i->queryDrvPath(state)); + mkString(*state.allocAttr(v, state.sDrvPath), i->queryDrvPath(state)); - state.mkAttrs((*v.attrs)[state.sMeta].value); + state.mkAttrs(*state.allocAttr(v, state.sMeta)); MetaInfo meta = i->queryMetaInfo(state); foreach (MetaInfo::const_iterator, j, meta) { - Value & v2((*(*v.attrs)[state.sMeta].value.attrs)[state.symbols.create(j->first)].value); + Value & v2(*state.allocAttr(*(*v.attrs)[state.sMeta].value, state.symbols.create(j->first))); switch (j->second.type) { case MetaValue::tpInt: mkInt(v2, j->second.intValue); break; case MetaValue::tpString: mkString(v2, j->second.stringValue); break; @@ -114,10 +115,10 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, builder with the manifest as argument. */ Value args, topLevel; state.mkAttrs(args); - mkString((*args.attrs)[state.sSystem].value, thisSystem); - mkString((*args.attrs)[state.symbols.create("manifest")].value, + mkString(*state.allocAttr(args, state.sSystem), thisSystem); + mkString(*state.allocAttr(args, state.symbols.create("manifest")), manifestFile, singleton(manifestFile)); - (*args.attrs)[state.symbols.create("derivations")].value = manifest; + (*args.attrs)[state.symbols.create("derivations")].value = &manifest; mkApp(topLevel, envBuilder, args); /* Evaluate it. */ diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc index 2925f9c5efb7..b330f0cf11f8 100644 --- a/src/nix-instantiate/nix-instantiate.cc +++ b/src/nix-instantiate/nix-instantiate.cc @@ -38,7 +38,7 @@ static bool indirectRoot = false; void processExpr(EvalState & state, const Strings & attrPaths, - bool parseOnly, bool strict, const Bindings & autoArgs, + bool parseOnly, bool strict, Bindings & autoArgs, bool evalOnly, bool xmlOutput, bool location, Expr * e) { if (parseOnly) -- cgit 1.4.1 From e11e6fb1c6709ca3f0e596a7b1fb988df2fbd9b1 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 28 Oct 2010 12:29:40 +0000 Subject: * Handle out of memory condition. --- src/libexpr/eval.cc | 10 +++++----- src/libmain/Makefile.am | 2 +- src/libmain/shared.cc | 20 ++++++++++++++++++++ src/nix-env/Makefile.am | 3 +-- src/nix-instantiate/Makefile.am | 3 +-- 5 files changed, 28 insertions(+), 10 deletions(-) (limited to 'src/nix-instantiate') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 919ebd4ba9b6..c36a679d350d 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -259,9 +259,8 @@ void mkString(Value & v, const string & s, const PathSet & context) mkString(v, s.c_str()); if (!context.empty()) { unsigned int n = 0; - v.string.context = (const char * *) - GC_MALLOC((context.size() + 1) * sizeof(char *)); - foreach (PathSet::const_iterator, i, context) + v.string.context = NEW const char *[context.size() + 1]; + foreach (PathSet::const_iterator, i, context) v.string.context[n++] = GC_STRDUP(i->c_str()); v.string.context[n] = 0; } @@ -305,7 +304,7 @@ Value * EvalState::lookupVar(Env * env, const VarRef & var) Value * EvalState::allocValue() { nrValues++; - return (Value *) GC_MALLOC(sizeof(Value)); + return NEW Value; } @@ -314,6 +313,7 @@ Env & EvalState::allocEnv(unsigned int size) nrEnvs++; nrValuesInEnvs += size; Env * env = (Env *) GC_MALLOC(sizeof(Env) + size * sizeof(Value *)); + if (!env) throw std::bad_alloc(); /* Clear the values because maybeThunk() expects this. */ for (unsigned i = 0; i < size; ++i) @@ -335,7 +335,7 @@ void EvalState::mkList(Value & v, unsigned int length) { v.type = tList; v.list.length = length; - v.list.elems = (Value * *) GC_MALLOC(length * sizeof(Value *)); + v.list.elems = NEW Value *[length]; nrListElems += length; } diff --git a/src/libmain/Makefile.am b/src/libmain/Makefile.am index a9ee6604255e..1a2146e0448f 100644 --- a/src/libmain/Makefile.am +++ b/src/libmain/Makefile.am @@ -2,7 +2,7 @@ pkglib_LTLIBRARIES = libmain.la libmain_la_SOURCES = shared.cc -libmain_la_LIBADD = ../libstore/libstore.la +libmain_la_LIBADD = ../libstore/libstore.la @boehmgc_lib@ pkginclude_HEADERS = shared.hh diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index eddc4e64b3d7..440949bd2a0a 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -13,6 +13,10 @@ #include #include +#if HAVE_BOEHMGC +#include +#endif + namespace nix { @@ -314,6 +318,14 @@ static void setuidInit() } +/* Called when the Boehm GC runs out of memory. */ +static void * oomHandler(size_t requested) +{ + /* Convert this to a proper C++ exception. */ + throw std::bad_alloc(); +} + + } @@ -335,6 +347,14 @@ int main(int argc, char * * argv) std::ios::sync_with_stdio(false); +#if HAVE_BOEHMGC + /* Initialise the Boehm garbage collector. This isn't necessary + on most platforms, but for portability we do it anyway. */ + GC_INIT(); + + GC_oom_fn = oomHandler; +#endif + try { try { initAndRun(argc, argv); diff --git a/src/nix-env/Makefile.am b/src/nix-env/Makefile.am index a876b3eb386d..7dfa7425a062 100644 --- a/src/nix-env/Makefile.am +++ b/src/nix-env/Makefile.am @@ -4,8 +4,7 @@ nix_env_SOURCES = nix-env.cc profiles.cc profiles.hh user-env.cc user-env.hh hel nix_env_LDADD = ../libmain/libmain.la ../libexpr/libexpr.la \ ../libstore/libstore.la ../libutil/libutil.la \ - ../boost/format/libformat.la @ADDITIONAL_NETWORK_LIBS@ \ - @boehmgc_lib@ + ../boost/format/libformat.la @ADDITIONAL_NETWORK_LIBS@ nix-env.o: help.txt.hh diff --git a/src/nix-instantiate/Makefile.am b/src/nix-instantiate/Makefile.am index bc9792818c3c..a65907a8d40a 100644 --- a/src/nix-instantiate/Makefile.am +++ b/src/nix-instantiate/Makefile.am @@ -3,8 +3,7 @@ bin_PROGRAMS = nix-instantiate nix_instantiate_SOURCES = nix-instantiate.cc help.txt nix_instantiate_LDADD = ../libmain/libmain.la ../libexpr/libexpr.la \ ../libstore/libstore.la ../libutil/libutil.la \ - ../boost/format/libformat.la @ADDITIONAL_NETWORK_LIBS@ \ - @boehmgc_lib@ + ../boost/format/libformat.la @ADDITIONAL_NETWORK_LIBS@ nix-instantiate.o: help.txt.hh -- cgit 1.4.1