Skip to content

Commit c79b801

Browse files
authored
Merge pull request #13407 from xokdvium/smaller-value
libexpr: Reduce the size of Value down to 16 bytes (on 64 bit systems)
2 parents 04a731b + 5a20a48 commit c79b801

File tree

18 files changed

+976
-308
lines changed

18 files changed

+976
-308
lines changed

maintainers/flake-module.nix

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,6 @@
256256
''^src/libexpr/include/nix/expr/value-to-json\.hh$''
257257
''^src/libexpr/value-to-xml\.cc$''
258258
''^src/libexpr/include/nix/expr/value-to-xml\.hh$''
259-
''^src/libexpr/include/nix/expr/value\.hh$''
260259
''^src/libexpr/value/context\.cc$''
261260
''^src/libexpr/include/nix/expr/value/context\.hh$''
262261
''^src/libfetchers/attrs\.cc$''

src/libexpr-c/nix_api_value.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ nix_value * nix_get_list_byidx(nix_c_context * context, const nix_value * value,
324324
try {
325325
auto & v = check_value_in(value);
326326
assert(v.type() == nix::nList);
327-
auto * p = v.listElems()[ix];
327+
auto * p = v.listView()[ix];
328328
nix_gc_incref(nullptr, p);
329329
if (p != nullptr)
330330
state->state.forceValue(*p, nix::noPos);

src/libexpr-tests/primops.cc

Lines changed: 54 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,8 @@ namespace nix {
150150
TEST_F(PrimOpTest, attrValues) {
151151
auto v = eval("builtins.attrValues { x = \"foo\"; a = 1; }");
152152
ASSERT_THAT(v, IsListOfSize(2));
153-
ASSERT_THAT(*v.listElems()[0], IsIntEq(1));
154-
ASSERT_THAT(*v.listElems()[1], IsStringEq("foo"));
153+
ASSERT_THAT(*v.listView()[0], IsIntEq(1));
154+
ASSERT_THAT(*v.listView()[1], IsStringEq("foo"));
155155
}
156156

157157
TEST_F(PrimOpTest, getAttr) {
@@ -250,8 +250,8 @@ namespace nix {
250250
TEST_F(PrimOpTest, catAttrs) {
251251
auto v = eval("builtins.catAttrs \"a\" [{a = 1;} {b = 0;} {a = 2;}]");
252252
ASSERT_THAT(v, IsListOfSize(2));
253-
ASSERT_THAT(*v.listElems()[0], IsIntEq(1));
254-
ASSERT_THAT(*v.listElems()[1], IsIntEq(2));
253+
ASSERT_THAT(*v.listView()[0], IsIntEq(1));
254+
ASSERT_THAT(*v.listView()[1], IsIntEq(2));
255255
}
256256

257257
TEST_F(PrimOpTest, functionArgs) {
@@ -320,7 +320,8 @@ namespace nix {
320320
TEST_F(PrimOpTest, tail) {
321321
auto v = eval("builtins.tail [ 3 2 1 0 ]");
322322
ASSERT_THAT(v, IsListOfSize(3));
323-
for (const auto [n, elem] : enumerate(v.listItems()))
323+
auto listView = v.listView();
324+
for (const auto [n, elem] : enumerate(listView))
324325
ASSERT_THAT(*elem, IsIntEq(2 - static_cast<int>(n)));
325326
}
326327

@@ -331,17 +332,17 @@ namespace nix {
331332
TEST_F(PrimOpTest, map) {
332333
auto v = eval("map (x: \"foo\" + x) [ \"bar\" \"bla\" \"abc\" ]");
333334
ASSERT_THAT(v, IsListOfSize(3));
334-
auto elem = v.listElems()[0];
335+
auto elem = v.listView()[0];
335336
ASSERT_THAT(*elem, IsThunk());
336337
state.forceValue(*elem, noPos);
337338
ASSERT_THAT(*elem, IsStringEq("foobar"));
338339

339-
elem = v.listElems()[1];
340+
elem = v.listView()[1];
340341
ASSERT_THAT(*elem, IsThunk());
341342
state.forceValue(*elem, noPos);
342343
ASSERT_THAT(*elem, IsStringEq("foobla"));
343344

344-
elem = v.listElems()[2];
345+
elem = v.listView()[2];
345346
ASSERT_THAT(*elem, IsThunk());
346347
state.forceValue(*elem, noPos);
347348
ASSERT_THAT(*elem, IsStringEq("fooabc"));
@@ -350,7 +351,7 @@ namespace nix {
350351
TEST_F(PrimOpTest, filter) {
351352
auto v = eval("builtins.filter (x: x == 2) [ 3 2 3 2 3 2 ]");
352353
ASSERT_THAT(v, IsListOfSize(3));
353-
for (const auto elem : v.listItems())
354+
for (const auto elem : v.listView())
354355
ASSERT_THAT(*elem, IsIntEq(2));
355356
}
356357

@@ -367,7 +368,8 @@ namespace nix {
367368
TEST_F(PrimOpTest, concatLists) {
368369
auto v = eval("builtins.concatLists [[1 2] [3 4]]");
369370
ASSERT_THAT(v, IsListOfSize(4));
370-
for (const auto [i, elem] : enumerate(v.listItems()))
371+
auto listView = v.listView();
372+
for (const auto [i, elem] : enumerate(listView))
371373
ASSERT_THAT(*elem, IsIntEq(static_cast<int>(i)+1));
372374
}
373375

@@ -405,7 +407,8 @@ namespace nix {
405407
auto v = eval("builtins.genList (x: x + 1) 3");
406408
ASSERT_EQ(v.type(), nList);
407409
ASSERT_EQ(v.listSize(), 3u);
408-
for (const auto [i, elem] : enumerate(v.listItems())) {
410+
auto listView = v.listView();
411+
for (const auto [i, elem] : enumerate(listView)) {
409412
ASSERT_THAT(*elem, IsThunk());
410413
state.forceValue(*elem, noPos);
411414
ASSERT_THAT(*elem, IsIntEq(static_cast<int>(i)+1));
@@ -418,7 +421,8 @@ namespace nix {
418421
ASSERT_EQ(v.listSize(), 6u);
419422

420423
const std::vector<int> numbers = { 42, 77, 147, 249, 483, 526 };
421-
for (const auto [n, elem] : enumerate(v.listItems()))
424+
auto listView = v.listView();
425+
for (const auto [n, elem] : enumerate(listView))
422426
ASSERT_THAT(*elem, IsIntEq(numbers[n]));
423427
}
424428

@@ -429,17 +433,17 @@ namespace nix {
429433
auto right = v.attrs()->get(createSymbol("right"));
430434
ASSERT_NE(right, nullptr);
431435
ASSERT_THAT(*right->value, IsListOfSize(2));
432-
ASSERT_THAT(*right->value->listElems()[0], IsIntEq(23));
433-
ASSERT_THAT(*right->value->listElems()[1], IsIntEq(42));
436+
ASSERT_THAT(*right->value->listView()[0], IsIntEq(23));
437+
ASSERT_THAT(*right->value->listView()[1], IsIntEq(42));
434438

435439
auto wrong = v.attrs()->get(createSymbol("wrong"));
436440
ASSERT_NE(wrong, nullptr);
437441
ASSERT_EQ(wrong->value->type(), nList);
438442
ASSERT_EQ(wrong->value->listSize(), 3u);
439443
ASSERT_THAT(*wrong->value, IsListOfSize(3));
440-
ASSERT_THAT(*wrong->value->listElems()[0], IsIntEq(1));
441-
ASSERT_THAT(*wrong->value->listElems()[1], IsIntEq(9));
442-
ASSERT_THAT(*wrong->value->listElems()[2], IsIntEq(3));
444+
ASSERT_THAT(*wrong->value->listView()[0], IsIntEq(1));
445+
ASSERT_THAT(*wrong->value->listView()[1], IsIntEq(9));
446+
ASSERT_THAT(*wrong->value->listView()[2], IsIntEq(3));
443447
}
444448

445449
TEST_F(PrimOpTest, concatMap) {
@@ -448,7 +452,8 @@ namespace nix {
448452
ASSERT_EQ(v.listSize(), 6u);
449453

450454
const std::vector<int> numbers = { 1, 2, 0, 3, 4, 0 };
451-
for (const auto [n, elem] : enumerate(v.listItems()))
455+
auto listView = v.listView();
456+
for (const auto [n, elem] : enumerate(listView))
452457
ASSERT_THAT(*elem, IsIntEq(numbers[n]));
453458
}
454459

@@ -682,7 +687,8 @@ namespace nix {
682687
ASSERT_THAT(v, IsListOfSize(4));
683688

684689
const std::vector<std::string_view> strings = { "1", "2", "3", "git" };
685-
for (const auto [n, p] : enumerate(v.listItems()))
690+
auto listView = v.listView();
691+
for (const auto [n, p] : enumerate(listView))
686692
ASSERT_THAT(*p, IsStringEq(strings[n]));
687693
}
688694

@@ -772,67 +778,67 @@ namespace nix {
772778
auto v = eval("builtins.split \"(a)b\" \"abc\"");
773779
ASSERT_THAT(v, IsListOfSize(3));
774780

775-
ASSERT_THAT(*v.listElems()[0], IsStringEq(""));
781+
ASSERT_THAT(*v.listView()[0], IsStringEq(""));
776782

777-
ASSERT_THAT(*v.listElems()[1], IsListOfSize(1));
778-
ASSERT_THAT(*v.listElems()[1]->listElems()[0], IsStringEq("a"));
783+
ASSERT_THAT(*v.listView()[1], IsListOfSize(1));
784+
ASSERT_THAT(*v.listView()[1]->listView()[0], IsStringEq("a"));
779785

780-
ASSERT_THAT(*v.listElems()[2], IsStringEq("c"));
786+
ASSERT_THAT(*v.listView()[2], IsStringEq("c"));
781787
}
782788

783789
TEST_F(PrimOpTest, split2) {
784790
// v is expected to be a list [ "" [ "a" ] "b" [ "c"] "" ]
785791
auto v = eval("builtins.split \"([ac])\" \"abc\"");
786792
ASSERT_THAT(v, IsListOfSize(5));
787793

788-
ASSERT_THAT(*v.listElems()[0], IsStringEq(""));
794+
ASSERT_THAT(*v.listView()[0], IsStringEq(""));
789795

790-
ASSERT_THAT(*v.listElems()[1], IsListOfSize(1));
791-
ASSERT_THAT(*v.listElems()[1]->listElems()[0], IsStringEq("a"));
796+
ASSERT_THAT(*v.listView()[1], IsListOfSize(1));
797+
ASSERT_THAT(*v.listView()[1]->listView()[0], IsStringEq("a"));
792798

793-
ASSERT_THAT(*v.listElems()[2], IsStringEq("b"));
799+
ASSERT_THAT(*v.listView()[2], IsStringEq("b"));
794800

795-
ASSERT_THAT(*v.listElems()[3], IsListOfSize(1));
796-
ASSERT_THAT(*v.listElems()[3]->listElems()[0], IsStringEq("c"));
801+
ASSERT_THAT(*v.listView()[3], IsListOfSize(1));
802+
ASSERT_THAT(*v.listView()[3]->listView()[0], IsStringEq("c"));
797803

798-
ASSERT_THAT(*v.listElems()[4], IsStringEq(""));
804+
ASSERT_THAT(*v.listView()[4], IsStringEq(""));
799805
}
800806

801807
TEST_F(PrimOpTest, split3) {
802808
auto v = eval("builtins.split \"(a)|(c)\" \"abc\"");
803809
ASSERT_THAT(v, IsListOfSize(5));
804810

805811
// First list element
806-
ASSERT_THAT(*v.listElems()[0], IsStringEq(""));
812+
ASSERT_THAT(*v.listView()[0], IsStringEq(""));
807813

808814
// 2nd list element is a list [ "" null ]
809-
ASSERT_THAT(*v.listElems()[1], IsListOfSize(2));
810-
ASSERT_THAT(*v.listElems()[1]->listElems()[0], IsStringEq("a"));
811-
ASSERT_THAT(*v.listElems()[1]->listElems()[1], IsNull());
815+
ASSERT_THAT(*v.listView()[1], IsListOfSize(2));
816+
ASSERT_THAT(*v.listView()[1]->listView()[0], IsStringEq("a"));
817+
ASSERT_THAT(*v.listView()[1]->listView()[1], IsNull());
812818

813819
// 3rd element
814-
ASSERT_THAT(*v.listElems()[2], IsStringEq("b"));
820+
ASSERT_THAT(*v.listView()[2], IsStringEq("b"));
815821

816822
// 4th element is a list: [ null "c" ]
817-
ASSERT_THAT(*v.listElems()[3], IsListOfSize(2));
818-
ASSERT_THAT(*v.listElems()[3]->listElems()[0], IsNull());
819-
ASSERT_THAT(*v.listElems()[3]->listElems()[1], IsStringEq("c"));
823+
ASSERT_THAT(*v.listView()[3], IsListOfSize(2));
824+
ASSERT_THAT(*v.listView()[3]->listView()[0], IsNull());
825+
ASSERT_THAT(*v.listView()[3]->listView()[1], IsStringEq("c"));
820826

821827
// 5th element is the empty string
822-
ASSERT_THAT(*v.listElems()[4], IsStringEq(""));
828+
ASSERT_THAT(*v.listView()[4], IsStringEq(""));
823829
}
824830

825831
TEST_F(PrimOpTest, split4) {
826832
auto v = eval("builtins.split \"([[:upper:]]+)\" \" FOO \"");
827833
ASSERT_THAT(v, IsListOfSize(3));
828-
auto first = v.listElems()[0];
829-
auto second = v.listElems()[1];
830-
auto third = v.listElems()[2];
834+
auto first = v.listView()[0];
835+
auto second = v.listView()[1];
836+
auto third = v.listView()[2];
831837

832838
ASSERT_THAT(*first, IsStringEq(" "));
833839

834840
ASSERT_THAT(*second, IsListOfSize(1));
835-
ASSERT_THAT(*second->listElems()[0], IsStringEq("FOO"));
841+
ASSERT_THAT(*second->listView()[0], IsStringEq("FOO"));
836842

837843
ASSERT_THAT(*third, IsStringEq(" "));
838844
}
@@ -850,14 +856,14 @@ namespace nix {
850856
TEST_F(PrimOpTest, match3) {
851857
auto v = eval("builtins.match \"a(b)(c)\" \"abc\"");
852858
ASSERT_THAT(v, IsListOfSize(2));
853-
ASSERT_THAT(*v.listElems()[0], IsStringEq("b"));
854-
ASSERT_THAT(*v.listElems()[1], IsStringEq("c"));
859+
ASSERT_THAT(*v.listView()[0], IsStringEq("b"));
860+
ASSERT_THAT(*v.listView()[1], IsStringEq("c"));
855861
}
856862

857863
TEST_F(PrimOpTest, match4) {
858864
auto v = eval("builtins.match \"[[:space:]]+([[:upper:]]+)[[:space:]]+\" \" FOO \"");
859865
ASSERT_THAT(v, IsListOfSize(1));
860-
ASSERT_THAT(*v.listElems()[0], IsStringEq("FOO"));
866+
ASSERT_THAT(*v.listView()[0], IsStringEq("FOO"));
861867
}
862868

863869
TEST_F(PrimOpTest, match5) {
@@ -874,7 +880,8 @@ namespace nix {
874880

875881
// ensure that the list is sorted
876882
const std::vector<std::string_view> expected { "a", "x", "y", "z" };
877-
for (const auto [n, elem] : enumerate(v.listItems()))
883+
auto listView = v.listView();
884+
for (const auto [n, elem] : enumerate(listView))
878885
ASSERT_THAT(*elem, IsStringEq(expected[n]));
879886
}
880887

src/libexpr/attr-path.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::strin
9595
if (*attrIndex >= v->listSize())
9696
throw AttrPathNotFound("list index %1% in selection path '%2%' is out of range", *attrIndex, attrPath);
9797

98-
v = v->listElems()[*attrIndex];
98+
v = v->listView()[*attrIndex];
9999
pos = noPos;
100100
}
101101

src/libexpr/eval-cache.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ std::vector<std::string> AttrCursor::getListOfStrings()
721721

722722
std::vector<std::string> res;
723723

724-
for (auto & elem : v.listItems())
724+
for (auto elem : v.listView())
725725
res.push_back(std::string(root->state.forceStringNoCtx(*elem, noPos, "while evaluating an attribute for caching")));
726726

727727
if (root->db)

src/libexpr/eval-gc.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "nix/util/config-global.hh"
55
#include "nix/util/serialise.hh"
66
#include "nix/expr/eval-gc.hh"
7+
#include "nix/expr/value.hh"
78

89
#include "expr-config-private.hh"
910

@@ -52,6 +53,13 @@ static inline void initGCReal()
5253

5354
GC_INIT();
5455

56+
/* Register valid displacements in case we are using alignment niches
57+
for storing the type information. This way tagged pointers are considered
58+
to be valid, even when they are not aligned. */
59+
if constexpr (detail::useBitPackedValueStorage<sizeof(void *)>)
60+
for (std::size_t i = 1; i < sizeof(std::uintptr_t); ++i)
61+
GC_register_displacement(i);
62+
5563
GC_set_oom_fn(oomHandler);
5664

5765
/* Set the initial heap size to something fairly big (25% of

0 commit comments

Comments
 (0)