1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-25 14:51:16 +02:00

store Symbols in a table as well, like positions

this slightly increases the amount of memory used for any given symbol, but this
increase is more than made up for if the symbol is referenced more than once in
the EvalState that holds it. on average every symbol should be referenced at
least twice (once to introduce a binding, once to use it), so we expect no
increase in memory on average.

symbol tables are limited to 2³² entries like position tables, and similar
arguments apply to why overflow is not likely: 2³² symbols would require as many
string instances (at 24 bytes each) and map entries (at 24 bytes or more each,
assuming that the map holds on average at most one item per bucket as the docs
say). a full symbol table would require at least 192GB of memory just for
symbols, which is well out of reach. (an ofborg eval of nixpks today creates
less than a million symbols!)
This commit is contained in:
pennae 2022-03-05 14:40:24 +01:00
parent 00a3280232
commit 8775be3393
32 changed files with 525 additions and 448 deletions

View file

@ -125,15 +125,15 @@ struct StaticEnv;
/* An attribute path is a sequence of attribute names. */
struct AttrName
{
Symbol symbol;
SymbolIdx symbol;
Expr * expr;
AttrName(const Symbol & s) : symbol(s) {};
AttrName(const SymbolIdx & s) : symbol(s) {};
AttrName(Expr * e) : expr(e) {};
};
typedef std::vector<AttrName> AttrPath;
std::string showAttrPath(const AttrPath & attrPath);
std::string showAttrPath(const SymbolTable & symbols, const AttrPath & attrPath);
/* Abstract syntax of Nix expressions. */
@ -141,19 +141,17 @@ std::string showAttrPath(const AttrPath & attrPath);
struct Expr
{
virtual ~Expr() { };
virtual void show(std::ostream & str) const;
virtual void bindVars(const PosTable & pt, const StaticEnv & env);
virtual void show(const SymbolTable & symbols, std::ostream & str) const;
virtual void bindVars(const EvalState & es, const StaticEnv & env);
virtual void eval(EvalState & state, Env & env, Value & v);
virtual Value * maybeThunk(EvalState & state, Env & env);
virtual void setName(Symbol & name);
virtual void setName(SymbolIdx name);
};
std::ostream & operator << (std::ostream & str, const Expr & e);
#define COMMON_METHODS \
void show(std::ostream & str) const; \
void show(const SymbolTable & symbols, std::ostream & str) const; \
void eval(EvalState & state, Env & env, Value & v); \
void bindVars(const PosTable & pt, const StaticEnv & env);
void bindVars(const EvalState & es, const StaticEnv & env);
struct ExprInt : Expr
{
@ -197,7 +195,7 @@ typedef uint32_t Displacement;
struct ExprVar : Expr
{
PosIdx pos;
Symbol name;
SymbolIdx name;
/* Whether the variable comes from an environment (e.g. a rec, let
or function argument) or from a "with". */
@ -212,8 +210,8 @@ struct ExprVar : Expr
Level level;
Displacement displ;
ExprVar(const Symbol & name) : name(name) { };
ExprVar(const PosIdx & pos, const Symbol & name) : pos(pos), name(name) { };
ExprVar(const SymbolIdx & name) : name(name) { };
ExprVar(const PosIdx & pos, const SymbolIdx & name) : pos(pos), name(name) { };
COMMON_METHODS
Value * maybeThunk(EvalState & state, Env & env);
};
@ -224,7 +222,7 @@ struct ExprSelect : Expr
Expr * e, * def;
AttrPath attrPath;
ExprSelect(const PosIdx & pos, Expr * e, const AttrPath & attrPath, Expr * def) : pos(pos), e(e), def(def), attrPath(attrPath) { };
ExprSelect(const PosIdx & pos, Expr * e, const Symbol & name) : pos(pos), e(e), def(0) { attrPath.push_back(AttrName(name)); };
ExprSelect(const PosIdx & pos, Expr * e, const SymbolIdx & name) : pos(pos), e(e), def(0) { attrPath.push_back(AttrName(name)); };
COMMON_METHODS
};
@ -249,7 +247,7 @@ struct ExprAttrs : Expr
: inherited(inherited), e(e), pos(pos) { };
AttrDef() { };
};
typedef std::map<Symbol, AttrDef> AttrDefs;
typedef std::map<SymbolIdx, AttrDef> AttrDefs;
AttrDefs attrs;
struct DynamicAttrDef {
Expr * nameExpr, * valueExpr;
@ -274,9 +272,8 @@ struct ExprList : Expr
struct Formal
{
PosIdx pos;
Symbol name;
SymbolIdx name;
Expr * def;
Formal(const PosIdx & pos, const Symbol & name, Expr * def) : pos(pos), name(name), def(def) { };
};
struct Formals
@ -285,18 +282,19 @@ struct Formals
Formals_ formals;
bool ellipsis;
bool has(Symbol arg) const {
bool has(SymbolIdx arg) const {
auto it = std::lower_bound(formals.begin(), formals.end(), arg,
[] (const Formal & f, const Symbol & sym) { return f.name < sym; });
[] (const Formal & f, const SymbolIdx & sym) { return f.name < sym; });
return it != formals.end() && it->name == arg;
}
std::vector<Formal> lexicographicOrder() const
std::vector<Formal> lexicographicOrder(const SymbolTable & symbols) const
{
std::vector<Formal> result(formals.begin(), formals.end());
std::sort(result.begin(), result.end(),
[] (const Formal & a, const Formal & b) {
return std::string_view(a.name) < std::string_view(b.name);
[&] (const Formal & a, const Formal & b) {
std::string_view sa = symbols[a.name], sb = symbols[b.name];
return sa < sb;
});
return result;
}
@ -305,16 +303,20 @@ struct Formals
struct ExprLambda : Expr
{
PosIdx pos;
Symbol name;
Symbol arg;
SymbolIdx name;
SymbolIdx arg;
Formals * formals;
Expr * body;
ExprLambda(const PosIdx & pos, const Symbol & arg, Formals * formals, Expr * body)
ExprLambda(PosIdx pos, SymbolIdx arg, Formals * formals, Expr * body)
: pos(pos), arg(arg), formals(formals), body(body)
{
};
void setName(Symbol & name);
std::string showNamePos(const PosTable & pt) const;
ExprLambda(PosIdx pos, Formals * formals, Expr * body)
: pos(pos), formals(formals), body(body)
{
}
void setName(SymbolIdx name);
std::string showNamePos(const EvalState & state) const;
inline bool hasFormals() const { return formals != nullptr; }
COMMON_METHODS
};
@ -377,13 +379,13 @@ struct ExprOpNot : Expr
Expr * e1, * e2; \
name(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; \
name(const PosIdx & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; \
void show(std::ostream & str) const \
void show(const SymbolTable & symbols, std::ostream & str) const \
{ \
str << "(" << *e1 << " " s " " << *e2 << ")"; \
str << "("; e1->show(symbols, str); str << " " s " "; e2->show(symbols, str); str << ")"; \
} \
void bindVars(const PosTable & pt, const StaticEnv & env) \
void bindVars(const EvalState & es, const StaticEnv & env) \
{ \
e1->bindVars(pt, env); e2->bindVars(pt, env); \
e1->bindVars(es, env); e2->bindVars(es, env); \
} \
void eval(EvalState & state, Env & env, Value & v); \
};
@ -423,7 +425,7 @@ struct StaticEnv
const StaticEnv * up;
// Note: these must be in sorted order.
typedef std::vector<std::pair<Symbol, Displacement>> Vars;
typedef std::vector<std::pair<SymbolIdx, Displacement>> Vars;
Vars vars;
StaticEnv(bool isWith, const StaticEnv * up, size_t expectedSize = 0) : isWith(isWith), up(up) {
@ -447,7 +449,7 @@ struct StaticEnv
vars.erase(it, end);
}
Vars::const_iterator find(const Symbol & name) const
Vars::const_iterator find(const SymbolIdx & name) const
{
Vars::value_type key(name, 0);
auto i = std::lower_bound(vars.begin(), vars.end(), key);