From 43fc6c314d520e9b767f5a0a94c52683b56d522c Mon Sep 17 00:00:00 2001 From: Taeer Bar-Yam Date: Sat, 22 Nov 2025 23:42:38 +0100 Subject: [PATCH 1/3] libexpr: ExprCall use std::pmr::vector --- src/libexpr/include/nix/expr/nixexpr.hh | 10 +++++----- src/libexpr/parser.y | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libexpr/include/nix/expr/nixexpr.hh b/src/libexpr/include/nix/expr/nixexpr.hh index 392545069..5121b9d98 100644 --- a/src/libexpr/include/nix/expr/nixexpr.hh +++ b/src/libexpr/include/nix/expr/nixexpr.hh @@ -592,11 +592,11 @@ public: struct ExprCall : Expr { Expr * fun; - std::vector args; + std::pmr::vector args; PosIdx pos; std::optional cursedOrEndPos; // used during parsing to warn about https://github.com/NixOS/nix/issues/11118 - ExprCall(const PosIdx & pos, Expr * fun, std::vector && args) + ExprCall(const PosIdx & pos, Expr * fun, std::pmr::vector && args) : fun(fun) , args(args) , pos(pos) @@ -604,7 +604,7 @@ struct ExprCall : Expr { } - ExprCall(const PosIdx & pos, Expr * fun, std::vector && args, PosIdx && cursedOrEndPos) + ExprCall(const PosIdx & pos, Expr * fun, std::pmr::vector && args, PosIdx && cursedOrEndPos) : fun(fun) , args(args) , pos(pos) @@ -836,7 +836,7 @@ public: // we define some calls to add explicitly so that the argument can be passed in as initializer lists template [[gnu::always_inline]] - C * add(const PosIdx & pos, Expr * fun, std::vector && args) + C * add(const PosIdx & pos, Expr * fun, std::pmr::vector && args) requires(std::same_as) { return alloc.new_object(pos, fun, std::move(args)); @@ -844,7 +844,7 @@ public: template [[gnu::always_inline]] - C * add(const PosIdx & pos, Expr * fun, std::vector && args, PosIdx && cursedOrEndPos) + C * add(const PosIdx & pos, Expr * fun, std::pmr::vector && args, PosIdx && cursedOrEndPos) requires(std::same_as) { return alloc.new_object(pos, fun, std::move(args), std::move(cursedOrEndPos)); diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 3cfc6f936..c4333eced 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -129,7 +129,7 @@ static Expr * makeCall(Exprs & exprs, PosIdx pos, Expr * fn, Expr * arg) { %type start expr expr_function expr_if expr_op %type expr_select expr_simple expr_app %type expr_pipe_from expr_pipe_into -%type > list +%type > list %type binds binds1 %type formals formal_set %type formal From 484f40fc6495620fad728a7f5101184448b1a6e0 Mon Sep 17 00:00:00 2001 From: Taeer Bar-Yam Date: Sun, 23 Nov 2025 00:05:07 +0100 Subject: [PATCH 2/3] libexpr: make ExprCall::args an std::optional --- src/libexpr/eval.cc | 6 +++--- src/libexpr/include/nix/expr/nixexpr.hh | 5 ++++- src/libexpr/nixexpr.cc | 4 ++-- src/libexpr/parser.y | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 0a6b199bf..29aa11035 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1751,9 +1751,9 @@ void ExprCall::eval(EvalState & state, Env & env, Value & v) // 4: about 60 // 5: under 10 // This excluded attrset lambdas (`{...}:`). Contributions of mixed lambdas appears insignificant at ~150 total. - SmallValueVector<4> vArgs(args.size()); - for (size_t i = 0; i < args.size(); ++i) - vArgs[i] = args[i]->maybeThunk(state, env); + SmallValueVector<4> vArgs(args->size()); + for (size_t i = 0; i < args->size(); ++i) + vArgs[i] = (*args)[i]->maybeThunk(state, env); state.callFunction(vFun, vArgs, v, pos); } diff --git a/src/libexpr/include/nix/expr/nixexpr.hh b/src/libexpr/include/nix/expr/nixexpr.hh index 5121b9d98..e4880a3fb 100644 --- a/src/libexpr/include/nix/expr/nixexpr.hh +++ b/src/libexpr/include/nix/expr/nixexpr.hh @@ -592,7 +592,10 @@ public: struct ExprCall : Expr { Expr * fun; - std::pmr::vector args; + /** + * args will never be null. See comment on ExprAttrs::AttrDefs below. + */ + std::optional> args; PosIdx pos; std::optional cursedOrEndPos; // used during parsing to warn about https://github.com/NixOS/nix/issues/11118 diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 3de5bdcb8..34d286f4e 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -191,7 +191,7 @@ void ExprCall::show(const SymbolTable & symbols, std::ostream & str) const { str << '('; fun->show(symbols, str); - for (auto e : args) { + for (auto e : *args) { str << ' '; e->show(symbols, str); } @@ -490,7 +490,7 @@ void ExprCall::bindVars(EvalState & es, const std::shared_ptr & es.exprEnvs.insert(std::make_pair(this, env)); fun->bindVars(es, env); - for (auto e : args) + for (auto e : *args) e->bindVars(es, env); } diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index c4333eced..a9166c5b5 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -115,7 +115,7 @@ static void setDocPosition(const LexerState & lexerState, ExprLambda * lambda, P static Expr * makeCall(Exprs & exprs, PosIdx pos, Expr * fn, Expr * arg) { if (auto e2 = dynamic_cast(fn)) { - e2->args.push_back(arg); + e2->args->push_back(arg); return fn; } return exprs.add(pos, fn, {arg}); From dbfe6318b3a38294c27546a1d454767092f5346e Mon Sep 17 00:00:00 2001 From: Taeer Bar-Yam Date: Sun, 23 Nov 2025 00:05:34 +0100 Subject: [PATCH 3/3] libexpr: move ExprCall storage to the arena --- src/libexpr/nixexpr.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 34d286f4e..37e22c466 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -486,6 +486,12 @@ void ExprLambda::bindVars(EvalState & es, const std::shared_ptr void ExprCall::bindVars(EvalState & es, const std::shared_ptr & env) { + // Move storage into the Exprs arena + { + auto arena = es.mem.exprs.alloc; + std::pmr::vector newArgs{std::move(*args), arena}; + args.emplace(std::move(newArgs), arena); + } if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env));