Store Attrs inside Bindings
This prevents a double allocation per attribute set.
This commit is contained in:
		
							parent
							
								
									0342eb1705
								
							
						
					
					
						commit
						5b58991a71
					
				
					 9 changed files with 101 additions and 60 deletions
				
			
		|  | @ -25,17 +25,19 @@ bool parseAutoArgs(Strings::iterator & i, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| void evalAutoArgs(EvalState & state, std::map<string, string> & in, Bindings & out) | Bindings * evalAutoArgs(EvalState & state, std::map<string, string> & in) | ||||||
| { | { | ||||||
|     for (auto & i: in) { |     Bindings * res = state.allocBindings(in.size()); | ||||||
|  |     for (auto & i : in) { | ||||||
|         Value * v = state.allocValue(); |         Value * v = state.allocValue(); | ||||||
|         if (i.second[0] == 'E') |         if (i.second[0] == 'E') | ||||||
|             state.mkThunk_(*v, state.parseExprFromString(string(i.second, 1), absPath("."))); |             state.mkThunk_(*v, state.parseExprFromString(string(i.second, 1), absPath("."))); | ||||||
|         else |         else | ||||||
|             mkString(*v, string(i.second, 1)); |             mkString(*v, string(i.second, 1)); | ||||||
|         out.push_back(Attr(state.symbols.create(i.first), v)); |         res->push_back(Attr(state.symbols.create(i.first), v)); | ||||||
|     } |     } | ||||||
|     out.sort(); |     res->sort(); | ||||||
|  |     return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ namespace nix { | ||||||
| bool parseAutoArgs(Strings::iterator & i, | bool parseAutoArgs(Strings::iterator & i, | ||||||
|     const Strings::iterator & argsEnd, std::map<string, string> & res); |     const Strings::iterator & argsEnd, std::map<string, string> & res); | ||||||
| 
 | 
 | ||||||
| void evalAutoArgs(EvalState & state, std::map<string, string> & in, Bindings & out); | Bindings * evalAutoArgs(EvalState & state, std::map<string, string> & in); | ||||||
| 
 | 
 | ||||||
| bool parseSearchPathArg(Strings::iterator & i, | bool parseSearchPathArg(Strings::iterator & i, | ||||||
|     const Strings::iterator & argsEnd, Strings & searchPath); |     const Strings::iterator & argsEnd, Strings & searchPath); | ||||||
|  |  | ||||||
|  | @ -35,7 +35,7 @@ namespace nix { | ||||||
| Bindings::iterator Bindings::find(const Symbol & name) | Bindings::iterator Bindings::find(const Symbol & name) | ||||||
| { | { | ||||||
|     Attr key(name, 0); |     Attr key(name, 0); | ||||||
|     iterator i = lower_bound(begin(), end(), key); |     iterator i = std::lower_bound(begin(), end(), key); | ||||||
|     if (i != end() && i->name == name) return i; |     if (i != end() && i->name == name) return i; | ||||||
|     return end(); |     return end(); | ||||||
| } | } | ||||||
|  | @ -175,7 +175,7 @@ EvalState::EvalState(const Strings & _searchPath) | ||||||
|     , baseEnvDispl(0) |     , baseEnvDispl(0) | ||||||
| { | { | ||||||
|     nrEnvs = nrValuesInEnvs = nrValues = nrListElems = 0; |     nrEnvs = nrValuesInEnvs = nrValues = nrListElems = 0; | ||||||
|     nrAttrsets = nrOpUpdates = nrOpUpdateValuesCopied = 0; |     nrAttrsets = nrAttrsInAttrsets = nrOpUpdates = nrOpUpdateValuesCopied = 0; | ||||||
|     nrListConcats = nrPrimOpCalls = nrFunctionCalls = 0; |     nrListConcats = nrPrimOpCalls = nrFunctionCalls = 0; | ||||||
|     countCalls = getEnv("NIX_COUNT_CALLS", "0") != "0"; |     countCalls = getEnv("NIX_COUNT_CALLS", "0") != "0"; | ||||||
| 
 | 
 | ||||||
|  | @ -433,6 +433,12 @@ Value * EvalState::allocAttr(Value & vAttrs, const Symbol & name) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | Bindings * EvalState::allocBindings(Bindings::size_t capacity) | ||||||
|  | { | ||||||
|  |     return new (GC_MALLOC(sizeof(Bindings) + sizeof(Attr) * capacity)) Bindings(capacity); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| void EvalState::mkList(Value & v, unsigned int length) | void EvalState::mkList(Value & v, unsigned int length) | ||||||
| { | { | ||||||
|     v.type = tList; |     v.type = tList; | ||||||
|  | @ -446,9 +452,9 @@ void EvalState::mkAttrs(Value & v, unsigned int expected) | ||||||
| { | { | ||||||
|     clearValue(v); |     clearValue(v); | ||||||
|     v.type = tAttrs; |     v.type = tAttrs; | ||||||
|     v.attrs = NEW Bindings; |     v.attrs = allocBindings(expected); | ||||||
|     v.attrs->reserve(expected); |  | ||||||
|     nrAttrsets++; |     nrAttrsets++; | ||||||
|  |     nrAttrsInAttrsets += expected; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -619,7 +625,7 @@ void ExprPath::eval(EvalState & state, Env & env, Value & v) | ||||||
| 
 | 
 | ||||||
| void ExprAttrs::eval(EvalState & state, Env & env, Value & v) | void ExprAttrs::eval(EvalState & state, Env & env, Value & v) | ||||||
| { | { | ||||||
|     state.mkAttrs(v, attrs.size()); |     state.mkAttrs(v, attrs.size() + dynamicAttrs.size()); | ||||||
|     Env *dynamicEnv = &env; |     Env *dynamicEnv = &env; | ||||||
| 
 | 
 | ||||||
|     if (recursive) { |     if (recursive) { | ||||||
|  | @ -658,15 +664,19 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) | ||||||
|         if (hasOverrides) { |         if (hasOverrides) { | ||||||
|             Value * vOverrides = (*v.attrs)[overrides->second.displ].value; |             Value * vOverrides = (*v.attrs)[overrides->second.displ].value; | ||||||
|             state.forceAttrs(*vOverrides); |             state.forceAttrs(*vOverrides); | ||||||
|             foreach (Bindings::iterator, i, *vOverrides->attrs) { |             Bindings * newBnds = state.allocBindings(v.attrs->size() + vOverrides->attrs->size()); | ||||||
|                 AttrDefs::iterator j = attrs.find(i->name); |             for (auto & i : *v.attrs) | ||||||
|  |                 newBnds->push_back(i); | ||||||
|  |             for (auto & i : *vOverrides->attrs) { | ||||||
|  |                 AttrDefs::iterator j = attrs.find(i.name); | ||||||
|                 if (j != attrs.end()) { |                 if (j != attrs.end()) { | ||||||
|                     (*v.attrs)[j->second.displ] = *i; |                     (*newBnds)[j->second.displ] = i; | ||||||
|                     env2.values[j->second.displ] = i->value; |                     env2.values[j->second.displ] = i.value; | ||||||
|                 } else |                 } else | ||||||
|                     v.attrs->push_back(*i); |                     newBnds->push_back(i); | ||||||
|             } |             } | ||||||
|             v.attrs->sort(); |             newBnds->sort(); | ||||||
|  |             v.attrs = newBnds; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -692,8 +702,8 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) | ||||||
| 
 | 
 | ||||||
|         i->valueExpr->setName(nameSym); |         i->valueExpr->setName(nameSym); | ||||||
|         /* Keep sorted order so find can catch duplicates */ |         /* Keep sorted order so find can catch duplicates */ | ||||||
|         v.attrs->insert(lower_bound(v.attrs->begin(), v.attrs->end(), Attr(nameSym, 0)), |         v.attrs->push_back(Attr(nameSym, i->valueExpr->maybeThunk(state, *dynamicEnv), &i->pos)); | ||||||
|                 Attr(nameSym, i->valueExpr->maybeThunk(state, *dynamicEnv), &i->pos)); |         v.attrs->sort(); // FIXME: inefficient
 | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1424,7 +1434,8 @@ void EvalState::printStats() | ||||||
|     printMsg(v, format("  list concatenations: %1%") % nrListConcats); |     printMsg(v, format("  list concatenations: %1%") % nrListConcats); | ||||||
|     printMsg(v, format("  values allocated: %1% (%2% bytes)") |     printMsg(v, format("  values allocated: %1% (%2% bytes)") | ||||||
|         % nrValues % (nrValues * sizeof(Value))); |         % nrValues % (nrValues * sizeof(Value))); | ||||||
|     printMsg(v, format("  sets allocated: %1%") % nrAttrsets); |     printMsg(v, format("  sets allocated: %1% (%2% bytes)") | ||||||
|  |         % nrAttrsets % (nrAttrsets * sizeof(Bindings) + nrAttrsInAttrsets * sizeof(Attr))); | ||||||
|     printMsg(v, format("  right-biased unions: %1%") % nrOpUpdates); |     printMsg(v, format("  right-biased unions: %1%") % nrOpUpdates); | ||||||
|     printMsg(v, format("  values copied in right-biased unions: %1%") % nrOpUpdateValuesCopied); |     printMsg(v, format("  values copied in right-biased unions: %1%") % nrOpUpdateValuesCopied); | ||||||
|     printMsg(v, format("  symbols in symbol table: %1%") % symbols.size()); |     printMsg(v, format("  symbols in symbol table: %1%") % symbols.size()); | ||||||
|  |  | ||||||
|  | @ -16,23 +16,59 @@ namespace nix { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class EvalState; | class EvalState; | ||||||
| struct Attr; |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* Sets are represented as a vector of attributes, sorted by symbol
 | struct Attr | ||||||
|    (i.e. pointer to the attribute name in the symbol table). */ | { | ||||||
| #if HAVE_BOEHMGC |     Symbol name; | ||||||
| typedef std::vector<Attr, gc_allocator<Attr> > BindingsBase; |     Value * value; | ||||||
| #else |     Pos * pos; | ||||||
| typedef std::vector<Attr> BindingsBase; |     Attr(Symbol name, Value * value, Pos * pos = &noPos) | ||||||
| #endif |         : name(name), value(value), pos(pos) { }; | ||||||
|  |     Attr() : pos(&noPos) { }; | ||||||
|  |     bool operator < (const Attr & a) const | ||||||
|  |     { | ||||||
|  |         return name < a.name; | ||||||
|  |     } | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Bindings : public BindingsBase | class Bindings | ||||||
| { | { | ||||||
| public: | public: | ||||||
|  |     typedef uint32_t size_t; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     size_t size_, capacity; | ||||||
|  |     Attr attrs[0]; | ||||||
|  | 
 | ||||||
|  |     Bindings(uint32_t capacity) : size_(0), capacity(capacity) { } | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  |     size_t size() { return size_; } | ||||||
|  | 
 | ||||||
|  |     bool empty() { return !size_; } | ||||||
|  | 
 | ||||||
|  |     typedef Attr * iterator; | ||||||
|  | 
 | ||||||
|  |     void push_back(const Attr & attr) | ||||||
|  |     { | ||||||
|  |         assert(size_ < capacity); | ||||||
|  |         attrs[size_++] = attr; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     iterator find(const Symbol & name); |     iterator find(const Symbol & name); | ||||||
|  |     iterator begin() { return &attrs[0]; } | ||||||
|  |     iterator end() { return &attrs[size_]; } | ||||||
|  | 
 | ||||||
|  |     Attr & operator[](size_t pos) | ||||||
|  |     { | ||||||
|  |         return attrs[pos]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     void sort(); |     void sort(); | ||||||
|  | 
 | ||||||
|  |     friend class EvalState; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -58,21 +94,6 @@ struct Env | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| struct Attr |  | ||||||
| { |  | ||||||
|     Symbol name; |  | ||||||
|     Value * value; |  | ||||||
|     Pos * pos; |  | ||||||
|     Attr(Symbol name, Value * value, Pos * pos = &noPos) |  | ||||||
|         : name(name), value(value), pos(pos) { }; |  | ||||||
|     Attr() : pos(&noPos) { }; |  | ||||||
|     bool operator < (const Attr & a) const |  | ||||||
|     { |  | ||||||
|         return name < a.name; |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| void mkString(Value & v, const string & s, const PathSet & context = PathSet()); | void mkString(Value & v, const string & s, const PathSet & context = PathSet()); | ||||||
| 
 | 
 | ||||||
| void copyContext(const Value & v, PathSet & context); | void copyContext(const Value & v, PathSet & context); | ||||||
|  | @ -245,6 +266,8 @@ public: | ||||||
| 
 | 
 | ||||||
|     Value * allocAttr(Value & vAttrs, const Symbol & name); |     Value * allocAttr(Value & vAttrs, const Symbol & name); | ||||||
| 
 | 
 | ||||||
|  |     Bindings * allocBindings(Bindings::size_t capacity); | ||||||
|  | 
 | ||||||
|     void mkList(Value & v, unsigned int length); |     void mkList(Value & v, unsigned int length); | ||||||
|     void mkAttrs(Value & v, unsigned int expected); |     void mkAttrs(Value & v, unsigned int expected); | ||||||
|     void mkThunk_(Value & v, Expr * expr); |     void mkThunk_(Value & v, Expr * expr); | ||||||
|  | @ -264,6 +287,7 @@ private: | ||||||
|     unsigned long nrValues; |     unsigned long nrValues; | ||||||
|     unsigned long nrListElems; |     unsigned long nrListElems; | ||||||
|     unsigned long nrAttrsets; |     unsigned long nrAttrsets; | ||||||
|  |     unsigned long nrAttrsInAttrsets; | ||||||
|     unsigned long nrOpUpdates; |     unsigned long nrOpUpdates; | ||||||
|     unsigned long nrOpUpdateValuesCopied; |     unsigned long nrOpUpdateValuesCopied; | ||||||
|     unsigned long nrListConcats; |     unsigned long nrListConcats; | ||||||
|  |  | ||||||
|  | @ -161,12 +161,12 @@ void DrvInfo::setMeta(const string & name, Value * v) | ||||||
| { | { | ||||||
|     getMeta(); |     getMeta(); | ||||||
|     Bindings * old = meta; |     Bindings * old = meta; | ||||||
|     meta = new Bindings(); |     meta = state->allocBindings(1 + (old ? old->size() : 0)); | ||||||
|     Symbol sym = state->symbols.create(name); |     Symbol sym = state->symbols.create(name); | ||||||
|     if (old) |     if (old) | ||||||
|         foreach (Bindings::iterator, i, *old) |         for (auto i : *old) | ||||||
|             if (i->name != sym) |             if (i.name != sym) | ||||||
|                 meta->push_back(*i); |                 meta->push_back(i); | ||||||
|     if (v) meta->push_back(Attr(sym, v)); |     if (v) meta->push_back(Attr(sym, v)); | ||||||
|     meta->sort(); |     meta->sort(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -14,8 +14,10 @@ static void skipWhitespace(const char * & s) | ||||||
| 
 | 
 | ||||||
| #if HAVE_BOEHMGC | #if HAVE_BOEHMGC | ||||||
| typedef std::vector<Value *, gc_allocator<Value *> > ValueVector; | typedef std::vector<Value *, gc_allocator<Value *> > ValueVector; | ||||||
|  | typedef std::map<Symbol, Value *, std::less<Symbol>, gc_allocator<Value *> > ValueMap; | ||||||
| #else | #else | ||||||
| typedef std::vector<Value *> ValueVector; | typedef std::vector<Value *> ValueVector; | ||||||
|  | typedef std::map<Symbol, Value *> ValueMap; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -76,22 +78,25 @@ static void parseJSON(EvalState & state, const char * & s, Value & v) | ||||||
| 
 | 
 | ||||||
|     else if (*s == '{') { |     else if (*s == '{') { | ||||||
|         s++; |         s++; | ||||||
|         state.mkAttrs(v, 1); |         ValueMap attrs; | ||||||
|         while (1) { |         while (1) { | ||||||
|             skipWhitespace(s); |             skipWhitespace(s); | ||||||
|             if (v.attrs->empty() && *s == '}') break; |             if (attrs.empty() && *s == '}') break; | ||||||
|             string name = parseJSONString(s); |             string name = parseJSONString(s); | ||||||
|             skipWhitespace(s); |             skipWhitespace(s); | ||||||
|             if (*s != ':') throw JSONParseError("expected ‘:’ in JSON object"); |             if (*s != ':') throw JSONParseError("expected ‘:’ in JSON object"); | ||||||
|             s++; |             s++; | ||||||
|             Value * v2 = state.allocValue(); |             Value * v2 = state.allocValue(); | ||||||
|             parseJSON(state, s, *v2); |             parseJSON(state, s, *v2); | ||||||
|             v.attrs->push_back(Attr(state.symbols.create(name), v2)); |             attrs[state.symbols.create(name)] = v2; | ||||||
|             skipWhitespace(s); |             skipWhitespace(s); | ||||||
|             if (*s == '}') break; |             if (*s == '}') break; | ||||||
|             if (*s != ',') throw JSONParseError("expected ‘,’ or ‘}’ after JSON member"); |             if (*s != ',') throw JSONParseError("expected ‘,’ or ‘}’ after JSON member"); | ||||||
|             s++; |             s++; | ||||||
|         } |         } | ||||||
|  |         state.mkAttrs(v, attrs.size()); | ||||||
|  |         for (auto & i : attrs) | ||||||
|  |             v.attrs->push_back(Attr(i.first, i.second)); | ||||||
|         v.attrs->sort(); |         v.attrs->sort(); | ||||||
|         s++; |         s++; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -44,7 +44,7 @@ struct InstallSourceInfo | ||||||
|     Path nixExprPath; /* for srcNixExprDrvs, srcNixExprs */ |     Path nixExprPath; /* for srcNixExprDrvs, srcNixExprs */ | ||||||
|     Path profile; /* for srcProfile */ |     Path profile; /* for srcProfile */ | ||||||
|     string systemFilter; /* for srcNixExprDrvs */ |     string systemFilter; /* for srcNixExprDrvs */ | ||||||
|     Bindings autoArgs; |     Bindings * autoArgs; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -350,7 +350,7 @@ static void queryInstSources(EvalState & state, | ||||||
|                Nix expression. */ |                Nix expression. */ | ||||||
|             DrvInfos allElems; |             DrvInfos allElems; | ||||||
|             loadDerivations(state, instSource.nixExprPath, |             loadDerivations(state, instSource.nixExprPath, | ||||||
|                 instSource.systemFilter, instSource.autoArgs, "", allElems); |                 instSource.systemFilter, *instSource.autoArgs, "", allElems); | ||||||
| 
 | 
 | ||||||
|             elems = filterBySelector(state, allElems, args, newestOnly); |             elems = filterBySelector(state, allElems, args, newestOnly); | ||||||
| 
 | 
 | ||||||
|  | @ -373,7 +373,7 @@ static void queryInstSources(EvalState & state, | ||||||
|                 Value vFun, vTmp; |                 Value vFun, vTmp; | ||||||
|                 state.eval(eFun, vFun); |                 state.eval(eFun, vFun); | ||||||
|                 mkApp(vTmp, vFun, vArg); |                 mkApp(vTmp, vFun, vArg); | ||||||
|                 getDerivations(state, vTmp, "", instSource.autoArgs, elems, true); |                 getDerivations(state, vTmp, "", *instSource.autoArgs, elems, true); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             break; |             break; | ||||||
|  | @ -423,8 +423,8 @@ static void queryInstSources(EvalState & state, | ||||||
|             Value vRoot; |             Value vRoot; | ||||||
|             loadSourceExpr(state, instSource.nixExprPath, vRoot); |             loadSourceExpr(state, instSource.nixExprPath, vRoot); | ||||||
|             foreach (Strings::const_iterator, i, args) { |             foreach (Strings::const_iterator, i, args) { | ||||||
|                 Value & v(*findAlongAttrPath(state, *i, instSource.autoArgs, vRoot)); |                 Value & v(*findAlongAttrPath(state, *i, *instSource.autoArgs, vRoot)); | ||||||
|                 getDerivations(state, v, "", instSource.autoArgs, elems, true); |                 getDerivations(state, v, "", *instSource.autoArgs, elems, true); | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  | @ -926,7 +926,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) | ||||||
| 
 | 
 | ||||||
|     if (source == sAvailable || compareVersions) |     if (source == sAvailable || compareVersions) | ||||||
|         loadDerivations(*globals.state, globals.instSource.nixExprPath, |         loadDerivations(*globals.state, globals.instSource.nixExprPath, | ||||||
|             globals.instSource.systemFilter, globals.instSource.autoArgs, |             globals.instSource.systemFilter, *globals.instSource.autoArgs, | ||||||
|             attrPath, availElems); |             attrPath, availElems); | ||||||
| 
 | 
 | ||||||
|     DrvInfos elems_ = filterBySelector(*globals.state, |     DrvInfos elems_ = filterBySelector(*globals.state, | ||||||
|  | @ -1423,7 +1423,7 @@ int main(int argc, char * * argv) | ||||||
|         if (file != "") |         if (file != "") | ||||||
|             globals.instSource.nixExprPath = lookupFileArg(*globals.state, file); |             globals.instSource.nixExprPath = lookupFileArg(*globals.state, file); | ||||||
| 
 | 
 | ||||||
|         evalAutoArgs(*globals.state, autoArgs_, globals.instSource.autoArgs); |         globals.instSource.autoArgs = evalAutoArgs(*globals.state, autoArgs_); | ||||||
| 
 | 
 | ||||||
|         if (globals.profile == "") |         if (globals.profile == "") | ||||||
|             globals.profile = getEnv("NIX_PROFILE", ""); |             globals.profile = getEnv("NIX_PROFILE", ""); | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ DrvInfos queryInstalled(EvalState & state, const Path & userEnv) | ||||||
|     if (pathExists(manifestFile)) { |     if (pathExists(manifestFile)) { | ||||||
|         Value v; |         Value v; | ||||||
|         state.evalFile(manifestFile, v); |         state.evalFile(manifestFile, v); | ||||||
|         Bindings bindings; |         Bindings & bindings(*state.allocBindings(0)); | ||||||
|         getDerivations(state, v, "", bindings, elems, false); |         getDerivations(state, v, "", bindings, elems, false); | ||||||
|     } |     } | ||||||
|     return elems; |     return elems; | ||||||
|  |  | ||||||
|  | @ -159,8 +159,7 @@ int main(int argc, char * * argv) | ||||||
|         EvalState state(searchPath); |         EvalState state(searchPath); | ||||||
|         state.repair = repair; |         state.repair = repair; | ||||||
| 
 | 
 | ||||||
|         Bindings autoArgs; |         Bindings & autoArgs(*evalAutoArgs(state, autoArgs_)); | ||||||
|         evalAutoArgs(state, autoArgs_, autoArgs); |  | ||||||
| 
 | 
 | ||||||
|         if (evalOnly && !wantsReadWrite) |         if (evalOnly && !wantsReadWrite) | ||||||
|             settings.readOnlyMode = true; |             settings.readOnlyMode = true; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue