From 002dfbb2e39346c1535df567b1bd2a091f51cef8 Mon Sep 17 00:00:00 2001 From: eldritch horrors Date: Sun, 28 Sep 2025 00:02:20 +0200 Subject: [PATCH] libexpr: move lambdas to auxiliary storage Change-Id: Ibe4885f17c0ba1634ed6dbca0a45f8bd4619d69b --- lix/libexpr/eval-inline.hh | 9 ++++++++ lix/libexpr/eval.cc | 3 ++- lix/libexpr/value.hh | 36 +++++++++++++------------------ tests/unit/libexpr/value/print.cc | 8 +++---- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/lix/libexpr/eval-inline.hh b/lix/libexpr/eval-inline.hh index a5ae1f761..b095d3d93 100644 --- a/lix/libexpr/eval-inline.hh +++ b/lix/libexpr/eval-inline.hh @@ -26,6 +26,15 @@ inline Value::Value(app_t, EvalMemory & mem, Value & lhs, std::span arg } } +inline Value::Value(lambda_t, EvalMemory & mem, Env & env, ExprLambda & lambda) + : internalType(tAuxiliary) + , _aux_pad(0) +{ + auto lp = mem.allocType(); + *lp = Lambda{{Acb::tLambda}, &env, &lambda}; + _auxiliary = lp; +} + [[gnu::always_inline]] void * EvalMemory::allocBytes(size_t size) { diff --git a/lix/libexpr/eval.cc b/lix/libexpr/eval.cc index 38fa04541..bd70e033b 100644 --- a/lix/libexpr/eval.cc +++ b/lix/libexpr/eval.cc @@ -108,6 +108,7 @@ std::string showType(const Value & v) return v.external()->showType(); case Value::Acb::tFloat: case Value::Acb::tNull: + case Value::Acb::tLambda: return std::string(showType(v.type())); case Value::Acb::tPrimOp: return fmt("the built-in function '%s'", v.primOp()->name); @@ -1415,7 +1416,7 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v) void ExprLambda::eval(EvalState & state, Env & env, Value & v) { - v.mkLambda(&env, this); + v = {NewValueAs::lambda, state.ctx.mem, env, *this}; } namespace { diff --git a/lix/libexpr/value.hh b/lix/libexpr/value.hh index 2e66b0a50..b7e672172 100644 --- a/lix/libexpr/value.hh +++ b/lix/libexpr/value.hh @@ -77,7 +77,6 @@ typedef enum { tList, tThunk, tApp, - tLambda, tAuxiliary, } InternalType; @@ -259,6 +258,7 @@ public: struct String; struct Acb; struct Null; + struct Lambda; static const Null NULL_ACB; @@ -521,10 +521,7 @@ public: /// This takes the environment the lambda is closed over @ref env, and /// the lambda expression itself @ref lambda, which will not be evaluated /// until it is applied. - Value(lambda_t, Env & env, ExprLambda & lambda) - : internalType(tLambda) - , _lambda({ .env = &env, .fun = &lambda }) - { } + Value(lambda_t, EvalMemory & mem, Env & env, ExprLambda & lambda); /// Constructs an evil thunk, whose evaluation represents infinite recursion. explicit Value(blackhole_t) @@ -582,7 +579,10 @@ public: } // type() == nFunction - inline bool isLambda() const { return internalType == tLambda; }; + inline bool isLambda() const + { + return internalType == tAuxiliary && _auxiliary->type == Acb::tLambda; + }; inline bool isPrimOp() const { return internalType == tAuxiliary && _auxiliary->type == Acb::tPrimOp; @@ -690,6 +690,7 @@ public: tFloat, tNull, tPrimOp, + tLambda, } type; }; struct External : Acb @@ -706,6 +707,11 @@ public: { explicit PrimOp(PrimOpDetails && p) : Acb{tPrimOp}, PrimOpDetails(std::move(p)) {} }; + struct Lambda : Acb + { + Env * env; + ExprLambda * fun; + }; union { @@ -737,11 +743,6 @@ public: Expr * expr; } _thunk; App _app; - struct - { - Env * env; - ExprLambda * fun; - } _lambda; struct { const Acb * _auxiliary; uintptr_t _aux_pad; @@ -765,8 +766,6 @@ public: case tAttrs: return nAttrs; case tList: return nList; - case tLambda: - return nFunction; case tAuxiliary: switch (_auxiliary->type) { case Acb::tExternal: @@ -776,6 +775,7 @@ public: case Acb::tNull: return nNull; case Acb::tPrimOp: + case Acb::tLambda: return nFunction; } case tThunk: @@ -868,13 +868,6 @@ public: *this = {NewValueAs::app, *l, *r}; } - inline void mkLambda(Env * e, ExprLambda * f) - { - internalType = tLambda; - _lambda.env = e; - _lambda.fun = f; - } - inline void mkBlackhole() { internalType = tThunk; @@ -992,7 +985,8 @@ public: const auto & lambda() const { - return _lambda; + assert(internalType == tAuxiliary && _auxiliary->type == Acb::tLambda); + return *static_cast(_auxiliary); } const PrimOp * primOp() const diff --git a/tests/unit/libexpr/value/print.cc b/tests/unit/libexpr/value/print.cc index 634f1ecc9..4bb4f26d1 100644 --- a/tests/unit/libexpr/value/print.cc +++ b/tests/unit/libexpr/value/print.cc @@ -110,6 +110,7 @@ TEST_F(ValuePrintingTests, vApp) TEST_F(ValuePrintingTests, vLambda) { + EvalMemory mem; Env env { .up = nullptr, .values = { } @@ -120,8 +121,7 @@ TEST_F(ValuePrintingTests, vLambda) ExprLambda eLambda(posIdx, std::make_unique(), std::make_unique(noPos, NewValueAs::integer, 0)); eLambda.pattern->name = createSymbol("a"); - Value vLambda; - vLambda.mkLambda(&env, &eLambda); + Value vLambda{NewValueAs::lambda, mem, env, eLambda}; test(vLambda, "«lambda @ «none»:1:1»"); @@ -546,6 +546,7 @@ TEST_F(ValuePrintingTests, ansiColorsList) TEST_F(ValuePrintingTests, ansiColorsLambda) { + EvalMemory mem; Env env { .up = nullptr, .values = { } @@ -556,8 +557,7 @@ TEST_F(ValuePrintingTests, ansiColorsLambda) ExprLambda eLambda(posIdx, std::make_unique(), std::make_unique(noPos, NewValueAs::integer, 0)); eLambda.pattern->name = createSymbol("a"); - Value vLambda; - vLambda.mkLambda(&env, &eLambda); + Value vLambda{NewValueAs::lambda, mem, env, eLambda}; test(vLambda, ANSI_BLUE "«lambda @ «none»:1:1»" ANSI_NORMAL,