Skip to content

Commit d6a158e

Browse files
committed
libexpr: move eval memory allocation to own struct
Co-authored-by: eldritch horrors <[email protected]> https://git.lix.systems/lix-project/lix/commit/f5754dc90ae9b1207656d0e29ad2704d3ef1e554
1 parent 4609528 commit d6a158e

File tree

25 files changed

+169
-132
lines changed

25 files changed

+169
-132
lines changed

src/libcmd/common-eval-args.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
155155
{
156156
auto res = state.buildBindings(autoArgs.size());
157157
for (auto & [name, arg] : autoArgs) {
158-
auto v = state.allocValue();
158+
auto v = state.mem.allocValue();
159159
std::visit(
160160
overloaded{
161161
[&](const AutoArgExpr & arg) {

src/libcmd/installables.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ ref<eval_cache::EvalCache> openEvalCache(EvalState & state, std::shared_ptr<flak
454454
if (getEnv("NIX_ALLOW_EVAL").value_or("1") == "0")
455455
throw Error("not everything is cached, but evaluation is not allowed");
456456

457-
auto vFlake = state.allocValue();
457+
auto vFlake = state.mem.allocValue();
458458
flake::callFlake(state, *lockedFlake, *vFlake);
459459

460460
state.forceAttrs(*vFlake, noPos, "while parsing cached flake data");
@@ -495,7 +495,7 @@ Installables SourceExprCommand::parseInstallables(ref<Store> store, std::vector<
495495
}
496496

497497
auto state = getEvalState();
498-
auto vFile = state->allocValue();
498+
auto vFile = state->mem.allocValue();
499499

500500
if (file == "-") {
501501
auto e = state->parseStdin();

src/libcmd/repl.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
697697
if (p != std::string::npos && p < line.size() && line[p + 1] != '='
698698
&& isVarName(name = removeWhitespace(line.substr(0, p)))) {
699699
Expr * e = parseString(line.substr(p + 1));
700-
Value & v(*state->allocValue());
700+
Value & v(*state->mem.allocValue());
701701
v.mkThunk(env, e);
702702
addVarToScope(state->symbols.create(name), v);
703703
} else {
@@ -760,7 +760,7 @@ void NixRepl::loadFlake(const std::string & flakeRefS)
760760

761761
void NixRepl::initEnv()
762762
{
763-
env = &state->allocEnv(envSize);
763+
env = &state->mem.allocEnv(envSize);
764764
env->up = &state->baseEnv;
765765
displ = 0;
766766
staticEnv->vars.clear();

src/libexpr-c/nix_api_value.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ nix_value * nix_alloc_value(nix_c_context * context, EvalState * state)
160160
if (context)
161161
context->last_err_code = NIX_OK;
162162
try {
163-
nix_value * res = as_nix_value_ptr(state->state.allocValue());
163+
nix_value * res = as_nix_value_ptr(state->state.mem.allocValue());
164164
nix_gc_incref(nullptr, res);
165165
return res;
166166
}
@@ -679,7 +679,7 @@ nix_err nix_bindings_builder_insert(nix_c_context * context, BindingsBuilder * b
679679
context->last_err_code = NIX_OK;
680680
try {
681681
auto & v = check_value_not_null(value);
682-
nix::Symbol s = bb->builder.state.get().symbols.create(name);
682+
nix::Symbol s = bb->builder.symbols.get().create(name);
683683
bb->builder.insert(s, &v);
684684
}
685685
NIXC_CATCH_ERRS

src/libexpr-tests/derived-path.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ TEST_F(DerivedPathExpressionTest, force_init) {}
2222

2323
RC_GTEST_FIXTURE_PROP(DerivedPathExpressionTest, prop_opaque_path_round_trip, (const SingleDerivedPath::Opaque & o))
2424
{
25-
auto * v = state.allocValue();
25+
auto * v = state.mem.allocValue();
2626
state.mkStorePathString(o.path, *v);
2727
auto d = state.coerceToSingleDerivedPath(noPos, *v, "");
2828
RC_ASSERT(SingleDerivedPath{o} == d);
@@ -41,7 +41,7 @@ RC_GTEST_FIXTURE_PROP(
4141
ExperimentalFeatureSettings mockXpSettings;
4242
mockXpSettings.set("experimental-features", "ca-derivations dynamic-derivations");
4343

44-
auto * v = state.allocValue();
44+
auto * v = state.mem.allocValue();
4545
state.mkOutputString(*v, b, std::nullopt, mockXpSettings);
4646
auto [d, _] = state.coerceToSingleDerivedPathUnchecked(noPos, *v, "", mockXpSettings);
4747
RC_ASSERT(SingleDerivedPath{b} == d);
@@ -55,7 +55,7 @@ RC_GTEST_FIXTURE_PROP(
5555
ExperimentalFeatureSettings mockXpSettings;
5656
mockXpSettings.set("experimental-features", "dynamic-derivations");
5757

58-
auto * v = state.allocValue();
58+
auto * v = state.mem.allocValue();
5959
state.mkOutputString(*v, b, outPath, mockXpSettings);
6060
auto [d, _] = state.coerceToSingleDerivedPathUnchecked(noPos, *v, "", mockXpSettings);
6161
RC_ASSERT(SingleDerivedPath{b} == d);

src/libexpr/attr-path.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ findAlongAttrPath(EvalState & state, const std::string & attrPath, Bindings & au
5252
auto attrIndex = string2Int<unsigned int>(attr);
5353

5454
/* Evaluate the expression. */
55-
Value * vNew = state.allocValue();
55+
Value * vNew = state.mem.allocValue();
5656
state.autoCallFunction(autoArgs, *v, *vNew);
5757
v = vNew;
5858
state.forceValue(*v, noPos);

src/libexpr/attr-set.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,27 @@ Bindings Bindings::emptyBindings;
1010
/* Allocate a new array of attributes for an attribute set with a specific
1111
capacity. The space is implicitly reserved after the Bindings
1212
structure. */
13-
Bindings * EvalState::allocBindings(size_t capacity)
13+
Bindings * EvalMemory::allocBindings(size_t capacity)
1414
{
1515
if (capacity == 0)
1616
return &Bindings::emptyBindings;
1717
if (capacity > std::numeric_limits<Bindings::size_type>::max())
1818
throw Error("attribute set of size %d is too big", capacity);
19-
nrAttrsets++;
20-
nrAttrsInAttrsets += capacity;
19+
stats.nrAttrsets++;
20+
stats.nrAttrsInAttrsets += capacity;
2121
return new (allocBytes(sizeof(Bindings) + sizeof(Attr) * capacity)) Bindings();
2222
}
2323

2424
Value & BindingsBuilder::alloc(Symbol name, PosIdx pos)
2525
{
26-
auto value = state.get().allocValue();
26+
auto value = mem.get().allocValue();
2727
bindings->push_back(Attr(name, value, pos));
2828
return *value;
2929
}
3030

3131
Value & BindingsBuilder::alloc(std::string_view name, PosIdx pos)
3232
{
33-
return alloc(state.get().symbols.create(name), pos);
33+
return alloc(symbols.get().create(name), pos);
3434
}
3535

3636
void Bindings::sort()

src/libexpr/eval.cc

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,15 @@ static Symbol getName(const AttrName & name, EvalState & state, Env & env)
194194

195195
static constexpr size_t BASE_ENV_SIZE = 128;
196196

197+
EvalMemory::EvalMemory()
198+
#if NIX_USE_BOEHMGC
199+
: valueAllocCache(std::allocate_shared<void *>(traceable_allocator<void *>(), nullptr))
200+
, env1AllocCache(std::allocate_shared<void *>(traceable_allocator<void *>(), nullptr))
201+
#endif
202+
{
203+
assertGCInitialized();
204+
}
205+
197206
EvalState::EvalState(
198207
const LookupPath & lookupPathFromArguments,
199208
ref<Store> store,
@@ -273,23 +282,14 @@ EvalState::EvalState(
273282
, importResolutionCache(make_ref<decltype(importResolutionCache)::element_type>())
274283
, fileEvalCache(make_ref<decltype(fileEvalCache)::element_type>())
275284
, regexCache(makeRegexCache())
276-
#if NIX_USE_BOEHMGC
277-
, valueAllocCache(std::allocate_shared<void *>(traceable_allocator<void *>(), nullptr))
278-
, env1AllocCache(std::allocate_shared<void *>(traceable_allocator<void *>(), nullptr))
279-
, baseEnvP(std::allocate_shared<Env *>(traceable_allocator<Env *>(), &allocEnv(BASE_ENV_SIZE)))
280-
, baseEnv(**baseEnvP)
281-
#else
282-
, baseEnv(allocEnv(BASE_ENV_SIZE))
283-
#endif
285+
, baseEnv(mem.allocEnv(BASE_ENV_SIZE))
284286
, staticBaseEnv{std::make_shared<StaticEnv>(nullptr, nullptr)}
285287
{
286288
corepkgsFS->setPathDisplay("<nix", ">");
287289
internalFS->setPathDisplay("«nix-internal»", "");
288290

289291
countCalls = getEnv("NIX_COUNT_CALLS").value_or("0") != "0";
290292

291-
assertGCInitialized();
292-
293293
static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes");
294294
static_assert(sizeof(Counter) == 64, "counters must be 64 bytes");
295295

@@ -423,7 +423,7 @@ void EvalState::checkURI(const std::string & uri)
423423

424424
Value * EvalState::addConstant(const std::string & name, Value & v, Constant info)
425425
{
426-
Value * v2 = allocValue();
426+
Value * v2 = mem.allocValue();
427427
*v2 = v;
428428
addConstant(name, v2, info);
429429
return v2;
@@ -489,7 +489,7 @@ Value * EvalState::addPrimOp(PrimOp && primOp)
489489
the primop to a dummy value. */
490490
if (primOp.arity == 0) {
491491
primOp.arity = 1;
492-
auto vPrimOp = allocValue();
492+
auto vPrimOp = mem.allocValue();
493493
vPrimOp->mkPrimOp(new PrimOp(primOp));
494494
Value v;
495495
v.mkApp(vPrimOp, vPrimOp);
@@ -506,7 +506,7 @@ Value * EvalState::addPrimOp(PrimOp && primOp)
506506
if (hasPrefix(primOp.name, "__"))
507507
primOp.name = primOp.name.substr(2);
508508

509-
Value * v = allocValue();
509+
Value * v = mem.allocValue();
510510
v->mkPrimOp(new PrimOp(primOp));
511511

512512
if (primOp.internal)
@@ -885,11 +885,10 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
885885
}
886886
}
887887

888-
ListBuilder::ListBuilder(EvalState & state, size_t size)
888+
ListBuilder::ListBuilder(size_t size)
889889
: size(size)
890890
, elems(size <= 2 ? inlineElems : (Value **) allocBytes(size * sizeof(Value *)))
891891
{
892-
state.nrListElems += size;
893892
}
894893

895894
Value * EvalState::getBool(bool b)
@@ -990,7 +989,7 @@ void EvalState::mkSingleDerivedPathString(const SingleDerivedPath & p, Value & v
990989

991990
Value * Expr::maybeThunk(EvalState & state, Env & env)
992991
{
993-
Value * v = state.allocValue();
992+
Value * v = state.mem.allocValue();
994993
mkThunk(*v, env, this);
995994
return v;
996995
}
@@ -1100,7 +1099,7 @@ void EvalState::evalFile(const SourcePath & path, Value & v, bool mustBeTrivial)
11001099
*resolvedPath,
11011100
nullptr,
11021101
[&](auto & i) {
1103-
vExpr = allocValue();
1102+
vExpr = mem.allocValue();
11041103
vExpr->mkThunk(&baseEnv, expr);
11051104
i.second = vExpr;
11061105
},
@@ -1183,7 +1182,7 @@ void ExprPath::eval(EvalState & state, Env & env, Value & v)
11831182

11841183
Env * ExprAttrs::buildInheritFromEnv(EvalState & state, Env & up)
11851184
{
1186-
Env & inheritEnv = state.allocEnv(inheritFromExprs->size());
1185+
Env & inheritEnv = state.mem.allocEnv(inheritFromExprs->size());
11871186
inheritEnv.up = &up;
11881187

11891188
Displacement displ = 0;
@@ -1202,7 +1201,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
12021201
if (recursive) {
12031202
/* Create a new environment that contains the attributes in
12041203
this `rec'. */
1205-
Env & env2(state.allocEnv(attrs.size()));
1204+
Env & env2(state.mem.allocEnv(attrs.size()));
12061205
env2.up = &env;
12071206
dynamicEnv = &env2;
12081207
Env * inheritEnv = inheritFromExprs ? buildInheritFromEnv(state, env2) : nullptr;
@@ -1217,7 +1216,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
12171216
for (auto & i : attrs) {
12181217
Value * vAttr;
12191218
if (hasOverrides && i.second.kind != AttrDef::Kind::Inherited) {
1220-
vAttr = state.allocValue();
1219+
vAttr = state.mem.allocValue();
12211220
mkThunk(*vAttr, *i.second.chooseByKind(&env2, &env, inheritEnv), i.second.e);
12221221
} else
12231222
vAttr = i.second.e->maybeThunk(state, *i.second.chooseByKind(&env2, &env, inheritEnv));
@@ -1294,7 +1293,7 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
12941293
{
12951294
/* Create a new environment that contains the attributes in this
12961295
`let'. */
1297-
Env & env2(state.allocEnv(attrs->attrs.size()));
1296+
Env & env2(state.mem.allocEnv(attrs->attrs.size()));
12981297
env2.up = &env;
12991298

13001299
Env * inheritEnv = attrs->inheritFromExprs ? attrs->buildInheritFromEnv(state, env2) : nullptr;
@@ -1485,7 +1484,7 @@ void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes,
14851484
auto makeAppChain = [&]() {
14861485
vRes = vCur;
14871486
for (auto arg : args) {
1488-
auto fun2 = allocValue();
1487+
auto fun2 = mem.allocValue();
14891488
*fun2 = vRes;
14901489
vRes.mkPrimOpApp(fun2, arg);
14911490
}
@@ -1500,7 +1499,7 @@ void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes,
15001499
ExprLambda & lambda(*vCur.lambda().fun);
15011500

15021501
auto size = (!lambda.arg ? 0 : 1) + (lambda.hasFormals() ? lambda.formals->formals.size() : 0);
1503-
Env & env2(allocEnv(size));
1502+
Env & env2(mem.allocEnv(size));
15041503
env2.up = vCur.lambda().env;
15051504

15061505
Displacement displ = 0;
@@ -1683,7 +1682,7 @@ void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes,
16831682
/* 'vCur' may be allocated on the stack of the calling
16841683
function, but for functors we may keep a reference, so
16851684
heap-allocate a copy and use that instead. */
1686-
Value * args2[] = {allocValue(), args[0]};
1685+
Value * args2[] = {mem.allocValue(), args[0]};
16871686
*args2[0] = vCur;
16881687
try {
16891688
callFunction(*functor->value, args2, vCur, functor->pos);
@@ -1743,7 +1742,7 @@ void EvalState::autoCallFunction(const Bindings & args, Value & fun, Value & res
17431742
if (fun.type() == nAttrs) {
17441743
auto found = fun.attrs()->get(s.functor);
17451744
if (found) {
1746-
Value * v = allocValue();
1745+
Value * v = mem.allocValue();
17471746
callFunction(*found->value, fun, *v, pos);
17481747
forceValue(*v, pos);
17491748
return autoCallFunction(args, *v, res);
@@ -1784,12 +1783,12 @@ values, or passed explicitly with '--arg' or '--argstr'. See
17841783
}
17851784
}
17861785

1787-
callFunction(fun, allocValue()->mkAttrs(attrs), res, pos);
1786+
callFunction(fun, mem.allocValue()->mkAttrs(attrs), res, pos);
17881787
}
17891788

17901789
void ExprWith::eval(EvalState & state, Env & env, Value & v)
17911790
{
1792-
Env & env2(state.allocEnv(1));
1791+
Env & env2(state.mem.allocEnv(1));
17931792
env2.up = &env;
17941793
env2.values[0] = attrs->maybeThunk(state, env);
17951794

@@ -2916,10 +2915,12 @@ void EvalState::printStatistics()
29162915
std::chrono::microseconds cpuTimeDuration = getCpuUserTime();
29172916
float cpuTime = std::chrono::duration_cast<std::chrono::duration<float>>(cpuTimeDuration).count();
29182917

2919-
uint64_t bEnvs = nrEnvs * sizeof(Env) + nrValuesInEnvs * sizeof(Value *);
2920-
uint64_t bLists = nrListElems * sizeof(Value *);
2921-
uint64_t bValues = nrValues * sizeof(Value);
2922-
uint64_t bAttrsets = nrAttrsets * sizeof(Bindings) + nrAttrsInAttrsets * sizeof(Attr);
2918+
auto memstats = mem.getStats();
2919+
2920+
uint64_t bEnvs = memstats.nrEnvs * sizeof(Env) + memstats.nrValuesInEnvs * sizeof(Value *);
2921+
uint64_t bLists = memstats.nrListElems * sizeof(Value *);
2922+
uint64_t bValues = memstats.nrValues * sizeof(Value);
2923+
uint64_t bAttrsets = memstats.nrAttrsets * sizeof(Bindings) + memstats.nrAttrsInAttrsets * sizeof(Attr);
29232924

29242925
#if NIX_USE_BOEHMGC
29252926
GC_word heapSize, totalBytes;
@@ -2945,28 +2946,28 @@ void EvalState::printStatistics()
29452946
#endif
29462947
};
29472948
topObj["envs"] = {
2948-
{"number", nrEnvs.load()},
2949-
{"elements", nrValuesInEnvs.load()},
2949+
{"number", memstats.nrEnvs.load()},
2950+
{"elements", memstats.nrValuesInEnvs.load()},
29502951
{"bytes", bEnvs},
29512952
};
29522953
topObj["nrExprs"] = Expr::nrExprs.load();
29532954
topObj["list"] = {
2954-
{"elements", nrListElems.load()},
2955+
{"elements", memstats.nrListElems.load()},
29552956
{"bytes", bLists},
29562957
{"concats", nrListConcats.load()},
29572958
};
29582959
topObj["values"] = {
2959-
{"number", nrValues.load()},
2960+
{"number", memstats.nrValues.load()},
29602961
{"bytes", bValues},
29612962
};
29622963
topObj["symbols"] = {
29632964
{"number", symbols.size()},
29642965
{"bytes", symbols.totalSize()},
29652966
};
29662967
topObj["sets"] = {
2967-
{"number", nrAttrsets.load()},
2968+
{"number", memstats.nrAttrsets.load()},
29682969
{"bytes", bAttrsets},
2969-
{"elements", nrAttrsInAttrsets.load()},
2970+
{"elements", memstats.nrAttrsInAttrsets.load()},
29702971
};
29712972
topObj["sizes"] = {
29722973
{"Env", sizeof(Env)},

0 commit comments

Comments
 (0)