Skip to content

Commit a1262c2

Browse files
committed
libexpr: Remove the source accessor from path values and ExprPaths
Co-authored-by: Eelco Dolstra <[email protected]> We can use the rootFS accessor for everything and just mount any other accessor (like corepkgsFS) on top of that. 1. removes 16 bytes per ExprPath 2. enables us in the future to shrink path value payload to 8 bytes 3. enables us in the future to directly refer to path values where we are currently referring to ExrPaths that forward us to a path value 4. enables getting rid of enable_shared_from_this<SourceAccessor>
1 parent e6f9778 commit a1262c2

File tree

20 files changed

+71
-87
lines changed

20 files changed

+71
-87
lines changed

src/libcmd/installable-value.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ std::optional<DerivedPathWithInfo>
4343
InstallableValue::trySinglePathToDerivedPaths(Value & v, const PosIdx pos, std::string_view errorCtx)
4444
{
4545
if (v.type() == nPath) {
46-
auto storePath = fetchToStore(state->fetchSettings, *state->store, v.path(), FetchMode::Copy);
46+
auto storePath = fetchToStore(state->fetchSettings, *state->store, state->rootPath(v.path()), FetchMode::Copy);
4747
return {{
4848
.path =
4949
DerivedPath::Opaque{

src/libexpr-c/nix_api_value.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ nix_err nix_init_path_string(nix_c_context * context, EvalState * s, nix_value *
514514
context->last_err_code = NIX_OK;
515515
try {
516516
auto & v = check_value_out(value);
517-
v.mkPath(s->state.rootPath(nix::CanonPath(str)));
517+
v.mkPath(nix::CanonPath(str));
518518
}
519519
NIXC_CATCH_ERRS
520520
}

src/libexpr-test-support/include/nix/expr/tests/libexpr.hh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ MATCHER_P(IsPathEq, p, fmt("Is a path equal to \"%1%\"", p))
139139
return false;
140140
} else {
141141
auto path = arg.path();
142-
if (path.path != CanonPath(p)) {
143-
*result_listener << "Expected a path that equals \"" << p << "\" but got: " << path.path;
142+
if (path != CanonPath(p)) {
143+
*result_listener << "Expected a path that equals \"" << p << "\" but got: " << path;
144144
return false;
145145
}
146146
}

src/libexpr-tests/json.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ TEST_F(JSONValueTest, StringQuotes)
7272
TEST_F(JSONValueTest, DISABLED_Path)
7373
{
7474
Value v;
75-
v.mkPath(state.rootPath(CanonPath("/test")));
75+
v.mkPath("/test");
7676
ASSERT_EQ(getJSONValue(v), "\"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x\"");
7777
}
7878
} /* namespace nix */

src/libexpr-tests/value/print.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ TEST_F(ValuePrintingTests, ansiColorsStringElided)
353353
TEST_F(ValuePrintingTests, ansiColorsPath)
354354
{
355355
Value v;
356-
v.mkPath(state.rootPath(CanonPath("puppy")));
356+
v.mkPath("/puppy");
357357

358358
test(v, ANSI_GREEN "/puppy" ANSI_NORMAL, PrintOptions{.ansiColors = true});
359359
}

src/libexpr/eval-cache.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -408,8 +408,8 @@ Value & AttrCursor::forceValue()
408408
if (v.type() == nString)
409409
cachedValue = {root->db->setString(getKey(), v.c_str(), v.context()), string_t{v.c_str(), {}}};
410410
else if (v.type() == nPath) {
411-
auto path = v.path().path;
412-
cachedValue = {root->db->setString(getKey(), path.abs()), string_t{path.abs(), {}}};
411+
auto path = v.path().abs();
412+
cachedValue = {root->db->setString(getKey(), path), string_t{path, {}}};
413413
} else if (v.type() == nBool)
414414
cachedValue = {root->db->setBool(getKey(), v.boolean()), v.boolean()};
415415
else if (v.type() == nInt)
@@ -541,7 +541,7 @@ std::string AttrCursor::getString()
541541
if (v.type() != nString && v.type() != nPath)
542542
root->state.error<TypeError>("'%s' is not a string but %s", getAttrPathStr(), showType(v)).debugThrow();
543543

544-
return v.type() == nString ? v.c_str() : v.path().to_string();
544+
return v.type() == nString ? v.c_str() : v.path().abs();
545545
}
546546

547547
string_t AttrCursor::getStringWithContext()
@@ -582,7 +582,7 @@ string_t AttrCursor::getStringWithContext()
582582
copyContext(v, context);
583583
return {v.c_str(), std::move(context)};
584584
} else if (v.type() == nPath)
585-
return {v.path().to_string(), {}};
585+
return {v.path().abs(), {}};
586586
else
587587
root->state.error<TypeError>("'%s' is not a string but %s", getAttrPathStr(), showType(v)).debugThrow();
588588
}

src/libexpr/eval.cc

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,8 @@ EvalState::EvalState(
213213
, settings{settings}
214214
, symbols(StaticEvalSymbols::staticSymbolTable())
215215
, repair(NoRepair)
216+
, corepkgsFS(make_ref<MemorySourceAccessor>())
217+
, corepkgsPath(StorePath::random("source"))
216218
, storeFS(makeMountedSourceAccessor({
217219
{CanonPath::root, makeEmptySourceAccessor()},
218220
/* In the pure eval case, we can simply require
@@ -266,7 +268,6 @@ EvalState::EvalState(
266268

267269
return accessor;
268270
}())
269-
, corepkgsFS(make_ref<MemorySourceAccessor>())
270271
, internalFS(make_ref<MemorySourceAccessor>())
271272
, derivationInternal{corepkgsFS->addFile(
272273
CanonPath("derivation-internal.nix"),
@@ -293,6 +294,9 @@ EvalState::EvalState(
293294
corepkgsFS->setPathDisplay("<nix", ">");
294295
internalFS->setPathDisplay("«nix-internal»", "");
295296

297+
storeFS->mount(CanonPath(store->printStorePath(corepkgsPath)), corepkgsFS);
298+
allowPath(corepkgsPath);
299+
296300
countCalls = getEnv("NIX_COUNT_CALLS").value_or("0") != "0";
297301

298302
static_assert(sizeof(Env) <= 16, "environment must be <= 16 bytes");
@@ -852,9 +856,9 @@ void Value::mkStringMove(const char * s, const NixStringContext & context)
852856
mkStringNoCopy(s, encodeContext(context));
853857
}
854858

855-
void Value::mkPath(const SourcePath & path)
859+
void Value::mkPath(const CanonPath & path)
856860
{
857-
mkPath(&*path.accessor, makeImmutableString(path.path.abs()));
861+
mkPath(makeImmutableString(path.abs()));
858862
}
859863

860864
inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
@@ -2127,7 +2131,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
21272131
.atPos(pos)
21282132
.withFrame(env, *this)
21292133
.debugThrow();
2130-
v.mkPath(state.rootPath(CanonPath(str())));
2134+
v.mkPath(CanonPath(str()));
21312135
} else
21322136
v.mkStringMove(c_str(), context);
21332137
}
@@ -2388,8 +2392,8 @@ BackedStringView EvalState::coerceToString(
23882392
? // FIXME: hack to preserve path literals that end in a
23892393
// slash, as in /foo/${x}.
23902394
v.pathStr()
2391-
: copyToStore ? store->printStorePath(copyPathToStore(context, v.path()))
2392-
: std::string(v.path().path.abs());
2395+
: copyToStore ? store->printStorePath(copyPathToStore(context, rootPath(v.path())))
2396+
: std::string(v.path().abs());
23932397
}
23942398

23952399
if (v.type() == nAttrs) {
@@ -2498,7 +2502,7 @@ SourcePath EvalState::coerceToPath(const PosIdx pos, Value & v, NixStringContext
24982502

24992503
/* Handle path values directly, without coercing to a string. */
25002504
if (v.type() == nPath)
2501-
return v.path();
2505+
return rootPath(v.path());
25022506

25032507
/* Similarly, handle __toString where the result may be a path
25042508
value. */
@@ -2652,13 +2656,6 @@ void EvalState::assertEqValues(Value & v1, Value & v2, const PosIdx pos, std::st
26522656
return;
26532657

26542658
case nPath:
2655-
if (v1.pathAccessor() != v2.pathAccessor()) {
2656-
error<AssertionError>(
2657-
"path '%s' is not equal to path '%s' because their accessors are different",
2658-
ValuePrinter(*this, v1, errorPrintOptions),
2659-
ValuePrinter(*this, v2, errorPrintOptions))
2660-
.debugThrow();
2661-
}
26622659
if (strcmp(v1.pathStr(), v2.pathStr()) != 0) {
26632660
error<AssertionError>(
26642661
"path '%s' is not equal to path '%s'",
@@ -2828,9 +2825,7 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
28282825
return strcmp(v1.c_str(), v2.c_str()) == 0;
28292826

28302827
case nPath:
2831-
return
2832-
// FIXME: compare accessors by their fingerprint.
2833-
v1.pathAccessor() == v2.pathAccessor() && strcmp(v1.pathStr(), v2.pathStr()) == 0;
2828+
return strcmp(v1.pathStr(), v2.pathStr()) == 0;
28342829

28352830
case nNull:
28362831
return true;
@@ -3136,7 +3131,7 @@ SourcePath EvalState::findFile(const LookupPath & lookupPath, const std::string_
31363131
}
31373132

31383133
if (hasPrefix(path, "nix/"))
3139-
return {corepkgsFS, CanonPath(path.substr(3))};
3134+
return rootPath(CanonPath(store->printStorePath(corepkgsPath)) / CanonPath(path.substr(3)));
31403135

31413136
error<ThrownError>(
31423137
settings.pureEval ? "cannot look up '<%s>' in pure evaluation mode (use '--impure' to override)"

src/libexpr/include/nix/expr/eval.hh

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,13 @@ public:
382382
*/
383383
RepairFlag repair;
384384

385+
/**
386+
* The in-memory filesystem for <nix/...> paths.
387+
*/
388+
const ref<MemorySourceAccessor> corepkgsFS;
389+
390+
const StorePath corepkgsPath;
391+
385392
/**
386393
* The accessor corresponding to `store`.
387394
*/
@@ -392,11 +399,6 @@ public:
392399
*/
393400
const ref<SourceAccessor> rootFS;
394401

395-
/**
396-
* The in-memory filesystem for <nix/...> paths.
397-
*/
398-
const ref<MemorySourceAccessor> corepkgsFS;
399-
400402
/**
401403
* In-memory filesystem for internal, non-user-callable Nix
402404
* expressions like `derivation.nix`.

src/libexpr/include/nix/expr/nixexpr.hh

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,21 +211,19 @@ struct ExprString : Expr
211211

212212
struct ExprPath : Expr
213213
{
214-
ref<SourceAccessor> accessor;
215214
Value v;
216215

217-
ExprPath(std::pmr::polymorphic_allocator<char> & alloc, ref<SourceAccessor> accessor, std::string_view sv)
218-
: accessor(accessor)
216+
ExprPath(std::pmr::polymorphic_allocator<char> & alloc, std::string_view sv)
219217
{
220218
auto len = sv.length();
221219
if (len == 0) {
222-
v.mkPath(&*accessor, "");
220+
v.mkPath("");
223221
return;
224222
}
225223
char * s = alloc.allocate(len + 1);
226224
sv.copy(s, len);
227225
s[len] = '\0';
228-
v.mkPath(&*accessor, s);
226+
v.mkPath(s);
229227
}
230228

231229
Value * maybeThunk(EvalState & state, Env & env) override;

src/libexpr/include/nix/expr/value.hh

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ typedef enum {
3939
tExternal,
4040
tPrimOp,
4141
tAttrs,
42+
tPath,
4243
/* layout: Pair of pointers payload */
4344
tListSmall,
4445
tPrimOpApp,
@@ -48,7 +49,6 @@ typedef enum {
4849
/* layout: Single untaggable field */
4950
tListN,
5051
tString,
51-
tPath,
5252
} InternalType;
5353

5454
/**
@@ -225,7 +225,6 @@ struct ValueBase
225225

226226
struct Path
227227
{
228-
SourceAccessor * accessor;
229228
const char * path;
230229
};
231230

@@ -415,7 +414,7 @@ class alignas(16) ValueStorage<ptrSize, std::enable_if_t<detail::useBitPackedVal
415414
* That leaves the first 8 bytes free for storing the InternalType in the upper
416415
* bits.
417416
*
418-
* PrimaryDiscriminator::pdListN - pdPath - Only has 3 available padding bits
417+
* PrimaryDiscriminator::pdListN - pdString - Only has 3 available padding bits
419418
* because:
420419
* - tListN needs a size, whose lower bits we can't borrow.
421420
* - tString and tPath have C-string fields, which don't necessarily need to
@@ -436,7 +435,6 @@ class alignas(16) ValueStorage<ptrSize, std::enable_if_t<detail::useBitPackedVal
436435
/* The order of these enumations must be the same as in InternalType. */
437436
pdListN, //< layout: Single untaggable field.
438437
pdString,
439-
pdPath,
440438
pdPairOfPointers, //< layout: Pair of pointers payload
441439
};
442440

@@ -469,7 +467,7 @@ class alignas(16) ValueStorage<ptrSize, std::enable_if_t<detail::useBitPackedVal
469467
template<PrimaryDiscriminator discriminator, typename T, typename U>
470468
void setUntaggablePayload(T * firstPtrField, U untaggableField) noexcept
471469
{
472-
static_assert(discriminator >= pdListN && discriminator <= pdPath);
470+
static_assert(discriminator >= pdListN && discriminator <= pdString);
473471
auto firstFieldPayload = std::bit_cast<PackedPointer>(firstPtrField);
474472
assertAligned(firstFieldPayload);
475473
payload[0] = static_cast<int>(discriminator) | firstFieldPayload;
@@ -515,7 +513,6 @@ protected:
515513
/* The order must match that of the enumerations defined in InternalType. */
516514
case pdListN:
517515
case pdString:
518-
case pdPath:
519516
return static_cast<InternalType>(tListN + (pd - pdListN));
520517
case pdPairOfPointers:
521518
return static_cast<InternalType>(tListSmall + (payload[1] & discriminatorMask));
@@ -578,6 +575,11 @@ protected:
578575
attrs = std::bit_cast<Bindings *>(payload[1]);
579576
}
580577

578+
void getStorage(Path & path) const noexcept
579+
{
580+
path.path = std::bit_cast<const char *>(payload[1]);
581+
}
582+
581583
void getStorage(List & list) const noexcept
582584
{
583585
list.elems = untagPointer<decltype(list.elems)>(payload[0]);
@@ -590,12 +592,6 @@ protected:
590592
string.c_str = std::bit_cast<const char *>(payload[1]);
591593
}
592594

593-
void getStorage(Path & path) const noexcept
594-
{
595-
path.accessor = untagPointer<decltype(path.accessor)>(payload[0]);
596-
path.path = std::bit_cast<const char *>(payload[1]);
597-
}
598-
599595
void setStorage(NixInt integer) noexcept
600596
{
601597
setSingleDWordPayload<tInt>(integer.value);
@@ -631,6 +627,11 @@ protected:
631627
setSingleDWordPayload<tAttrs>(std::bit_cast<PackedPointer>(bindings));
632628
}
633629

630+
void setStorage(Path path) noexcept
631+
{
632+
setSingleDWordPayload<tPath>(std::bit_cast<PackedPointer>(path.path));
633+
}
634+
634635
void setStorage(List list) noexcept
635636
{
636637
setUntaggablePayload<pdListN>(list.elems, list.size);
@@ -640,11 +641,6 @@ protected:
640641
{
641642
setUntaggablePayload<pdString>(string.context, string.c_str);
642643
}
643-
644-
void setStorage(Path path) noexcept
645-
{
646-
setUntaggablePayload<pdPath>(path.accessor, path.path);
647-
}
648644
};
649645

650646
/**
@@ -1002,11 +998,11 @@ public:
1002998

1003999
void mkStringMove(const char * s, const NixStringContext & context);
10041000

1005-
void mkPath(const SourcePath & path);
1001+
void mkPath(const CanonPath & path);
10061002

1007-
inline void mkPath(SourceAccessor * accessor, const char * path) noexcept
1003+
inline void mkPath(const char * path) noexcept
10081004
{
1009-
setStorage(Path{.accessor = accessor, .path = path});
1005+
setStorage(Path{.path = path});
10101006
}
10111007

10121008
inline void mkNull() noexcept
@@ -1102,9 +1098,9 @@ public:
11021098
*/
11031099
bool isTrivial() const;
11041100

1105-
SourcePath path() const
1101+
CanonPath path() const
11061102
{
1107-
return SourcePath(ref(pathAccessor()->shared_from_this()), CanonPath(CanonPath::unchecked_t(), pathStr()));
1103+
return CanonPath(CanonPath::unchecked_t(), pathStr());
11081104
}
11091105

11101106
std::string_view string_view() const noexcept
@@ -1176,11 +1172,6 @@ public:
11761172
{
11771173
return getStorage<Path>().path;
11781174
}
1179-
1180-
SourceAccessor * pathAccessor() const noexcept
1181-
{
1182-
return getStorage<Path>().accessor;
1183-
}
11841175
};
11851176

11861177
extern ExprBlackHole eBlackHole;

0 commit comments

Comments
 (0)