Skip to content

Commit 327e8ba

Browse files
authored
Merge pull request #14584 from Radvendii/allocbytes-stringdata
libexpr: use allocBytes() to allocate StringData
2 parents d5d4baf + 7cd3252 commit 327e8ba

File tree

20 files changed

+136
-109
lines changed

20 files changed

+136
-109
lines changed

src/libcmd/common-eval-args.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,9 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
168168
? state.rootPath(absPath(getCommandBaseDir()))
169169
: state.rootPath(".")));
170170
},
171-
[&](const AutoArgString & arg) { v->mkString(arg.s); },
172-
[&](const AutoArgFile & arg) { v->mkString(readFile(arg.path.string())); },
173-
[&](const AutoArgStdin & arg) { v->mkString(readFile(STDIN_FILENO)); }},
171+
[&](const AutoArgString & arg) { v->mkString(arg.s, state.mem); },
172+
[&](const AutoArgFile & arg) { v->mkString(readFile(arg.path.string()), state.mem); },
173+
[&](const AutoArgStdin & arg) { v->mkString(readFile(STDIN_FILENO), state.mem); }},
174174
arg);
175175
res.insert(state.symbols.create(name), v);
176176
}

src/libexpr-c/nix_api_expr.cc

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ nix_err nix_expr_eval_from_string(
6969
context->last_err_code = NIX_OK;
7070
try {
7171
nix::Expr * parsedExpr = state->state.parseExprFromString(expr, state->state.rootPath(nix::CanonPath(path)));
72-
state->state.eval(parsedExpr, value->value);
73-
state->state.forceValue(value->value, nix::noPos);
72+
state->state.eval(parsedExpr, *value->value);
73+
state->state.forceValue(*value->value, nix::noPos);
7474
}
7575
NIXC_CATCH_ERRS
7676
}
@@ -80,8 +80,8 @@ nix_err nix_value_call(nix_c_context * context, EvalState * state, Value * fn, n
8080
if (context)
8181
context->last_err_code = NIX_OK;
8282
try {
83-
state->state.callFunction(fn->value, arg->value, value->value, nix::noPos);
84-
state->state.forceValue(value->value, nix::noPos);
83+
state->state.callFunction(*fn->value, *arg->value, *value->value, nix::noPos);
84+
state->state.forceValue(*value->value, nix::noPos);
8585
}
8686
NIXC_CATCH_ERRS
8787
}
@@ -91,9 +91,15 @@ nix_err nix_value_call_multi(
9191
{
9292
if (context)
9393
context->last_err_code = NIX_OK;
94+
95+
std::vector<nix::Value *> internal_args;
96+
internal_args.reserve(nargs);
97+
for (size_t i = 0; i < nargs; i++)
98+
internal_args.push_back(args[i]->value);
99+
94100
try {
95-
state->state.callFunction(fn->value, {(nix::Value **) args, nargs}, value->value, nix::noPos);
96-
state->state.forceValue(value->value, nix::noPos);
101+
state->state.callFunction(*fn->value, {internal_args.data(), nargs}, *value->value, nix::noPos);
102+
state->state.forceValue(*value->value, nix::noPos);
97103
}
98104
NIXC_CATCH_ERRS
99105
}
@@ -103,7 +109,7 @@ nix_err nix_value_force(nix_c_context * context, EvalState * state, nix_value *
103109
if (context)
104110
context->last_err_code = NIX_OK;
105111
try {
106-
state->state.forceValue(value->value, nix::noPos);
112+
state->state.forceValue(*value->value, nix::noPos);
107113
}
108114
NIXC_CATCH_ERRS
109115
}
@@ -113,7 +119,7 @@ nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, nix_val
113119
if (context)
114120
context->last_err_code = NIX_OK;
115121
try {
116-
state->state.forceValueDeep(value->value);
122+
state->state.forceValueDeep(*value->value);
117123
}
118124
NIXC_CATCH_ERRS
119125
}

src/libexpr-c/nix_api_expr_internal.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,13 @@ struct ListBuilder
3939

4040
struct nix_value
4141
{
42-
nix::Value value;
42+
nix::Value * value;
43+
/**
44+
* As we move to a managed heap, we need EvalMemory in more places. Ideally, we would take in EvalState or
45+
* EvalMemory as an argument when we need it, but we don't want to make changes to the stable C api, so we stuff it
46+
* into the nix_value that will get passed in to the relevant functions.
47+
*/
48+
nix::EvalMemory * mem;
4349
};
4450

4551
struct nix_string_return

src/libexpr-c/nix_api_value.cc

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ static const nix::Value & check_value_not_null(const nix_value * value)
2020
if (!value) {
2121
throw std::runtime_error("nix_value is null");
2222
}
23-
return *((const nix::Value *) value);
23+
return *value->value;
2424
}
2525

2626
static nix::Value & check_value_not_null(nix_value * value)
2727
{
2828
if (!value) {
2929
throw std::runtime_error("nix_value is null");
3030
}
31-
return value->value;
31+
return *value->value;
3232
}
3333

3434
static const nix::Value & check_value_in(const nix_value * value)
@@ -58,9 +58,14 @@ static nix::Value & check_value_out(nix_value * value)
5858
return v;
5959
}
6060

61-
static inline nix_value * as_nix_value_ptr(nix::Value * v)
61+
static inline nix_value * new_nix_value(nix::Value * v, nix::EvalMemory & mem)
6262
{
63-
return reinterpret_cast<nix_value *>(v);
63+
nix_value * ret = new (mem.allocBytes(sizeof(nix_value))) nix_value{
64+
.value = v,
65+
.mem = &mem,
66+
};
67+
nix_gc_incref(nullptr, ret);
68+
return ret;
6469
}
6570

6671
/**
@@ -69,7 +74,13 @@ static inline nix_value * as_nix_value_ptr(nix::Value * v)
6974
* Deals with errors and converts arguments from C++ into C types.
7075
*/
7176
static void nix_c_primop_wrapper(
72-
PrimOpFun f, void * userdata, nix::EvalState & state, const nix::PosIdx pos, nix::Value ** args, nix::Value & v)
77+
PrimOpFun f,
78+
void * userdata,
79+
int arity,
80+
nix::EvalState & state,
81+
const nix::PosIdx pos,
82+
nix::Value ** args,
83+
nix::Value & v)
7384
{
7485
nix_c_context ctx;
7586

@@ -85,8 +96,15 @@ static void nix_c_primop_wrapper(
8596
// ok because we don't see a need for this yet (e.g. inspecting thunks,
8697
// or maybe something to make blackholes work better; we don't know).
8798
nix::Value vTmp;
99+
nix_value * vTmpPtr = new_nix_value(&vTmp, state.mem);
88100

89-
f(userdata, &ctx, (EvalState *) &state, (nix_value **) args, (nix_value *) &vTmp);
101+
std::vector<nix_value *> external_args;
102+
external_args.reserve(arity);
103+
for (int i = 0; i < arity; i++) {
104+
nix_value * external_arg = new_nix_value(args[i], state.mem);
105+
external_args.push_back(external_arg);
106+
}
107+
f(userdata, &ctx, (EvalState *) &state, external_args.data(), vTmpPtr);
90108

91109
if (ctx.last_err_code != NIX_OK) {
92110
/* TODO: Throw different errors depending on the error code */
@@ -135,7 +153,7 @@ PrimOp * nix_alloc_primop(
135153
.args = {},
136154
.arity = (size_t) arity,
137155
.doc = doc,
138-
.fun = std::bind(nix_c_primop_wrapper, fun, user_data, _1, _2, _3, _4)};
156+
.fun = std::bind(nix_c_primop_wrapper, fun, user_data, arity, _1, _2, _3, _4)};
139157
if (args)
140158
for (size_t i = 0; args[i]; i++)
141159
p->args.emplace_back(*args);
@@ -160,8 +178,7 @@ nix_value * nix_alloc_value(nix_c_context * context, EvalState * state)
160178
if (context)
161179
context->last_err_code = NIX_OK;
162180
try {
163-
nix_value * res = as_nix_value_ptr(state->state.allocValue());
164-
nix_gc_incref(nullptr, res);
181+
nix_value * res = new_nix_value(state->state.allocValue(), state->state.mem);
165182
return res;
166183
}
167184
NIXC_CATCH_ERRS_NULL
@@ -331,10 +348,10 @@ nix_value * nix_get_list_byidx(nix_c_context * context, const nix_value * value,
331348
return nullptr;
332349
}
333350
auto * p = v.listView()[ix];
334-
nix_gc_incref(nullptr, p);
335-
if (p != nullptr)
336-
state->state.forceValue(*p, nix::noPos);
337-
return as_nix_value_ptr(p);
351+
if (p == nullptr)
352+
return nullptr;
353+
state->state.forceValue(*p, nix::noPos);
354+
return new_nix_value(p, state->state.mem);
338355
}
339356
NIXC_CATCH_ERRS_NULL
340357
}
@@ -352,9 +369,8 @@ nix_get_list_byidx_lazy(nix_c_context * context, const nix_value * value, EvalSt
352369
return nullptr;
353370
}
354371
auto * p = v.listView()[ix];
355-
nix_gc_incref(nullptr, p);
356372
// Note: intentionally NOT calling forceValue() to keep the element lazy
357-
return as_nix_value_ptr(p);
373+
return new_nix_value(p, state->state.mem);
358374
}
359375
NIXC_CATCH_ERRS_NULL
360376
}
@@ -369,9 +385,8 @@ nix_value * nix_get_attr_byname(nix_c_context * context, const nix_value * value
369385
nix::Symbol s = state->state.symbols.create(name);
370386
auto attr = v.attrs()->get(s);
371387
if (attr) {
372-
nix_gc_incref(nullptr, attr->value);
373388
state->state.forceValue(*attr->value, nix::noPos);
374-
return as_nix_value_ptr(attr->value);
389+
return new_nix_value(attr->value, state->state.mem);
375390
}
376391
nix_set_err_msg(context, NIX_ERR_KEY, "missing attribute");
377392
return nullptr;
@@ -390,9 +405,8 @@ nix_get_attr_byname_lazy(nix_c_context * context, const nix_value * value, EvalS
390405
nix::Symbol s = state->state.symbols.create(name);
391406
auto attr = v.attrs()->get(s);
392407
if (attr) {
393-
nix_gc_incref(nullptr, attr->value);
394408
// Note: intentionally NOT calling forceValue() to keep the attribute lazy
395-
return as_nix_value_ptr(attr->value);
409+
return new_nix_value(attr->value, state->state.mem);
396410
}
397411
nix_set_err_msg(context, NIX_ERR_KEY, "missing attribute");
398412
return nullptr;
@@ -440,9 +454,8 @@ nix_get_attr_byidx(nix_c_context * context, nix_value * value, EvalState * state
440454
}
441455
const nix::Attr & a = (*v.attrs())[i];
442456
*name = state->state.symbols[a.name].c_str();
443-
nix_gc_incref(nullptr, a.value);
444457
state->state.forceValue(*a.value, nix::noPos);
445-
return as_nix_value_ptr(a.value);
458+
return new_nix_value(a.value, state->state.mem);
446459
}
447460
NIXC_CATCH_ERRS_NULL
448461
}
@@ -461,9 +474,8 @@ nix_value * nix_get_attr_byidx_lazy(
461474
}
462475
const nix::Attr & a = (*v.attrs())[i];
463476
*name = state->state.symbols[a.name].c_str();
464-
nix_gc_incref(nullptr, a.value);
465477
// Note: intentionally NOT calling forceValue() to keep the attribute lazy
466-
return as_nix_value_ptr(a.value);
478+
return new_nix_value(a.value, state->state.mem);
467479
}
468480
NIXC_CATCH_ERRS_NULL
469481
}
@@ -503,7 +515,7 @@ nix_err nix_init_string(nix_c_context * context, nix_value * value, const char *
503515
context->last_err_code = NIX_OK;
504516
try {
505517
auto & v = check_value_out(value);
506-
v.mkString(std::string_view(str));
518+
v.mkString(std::string_view(str), *value->mem);
507519
}
508520
NIXC_CATCH_ERRS
509521
}
@@ -514,7 +526,7 @@ nix_err nix_init_path_string(nix_c_context * context, EvalState * s, nix_value *
514526
context->last_err_code = NIX_OK;
515527
try {
516528
auto & v = check_value_out(value);
517-
v.mkPath(s->state.rootPath(nix::CanonPath(str)));
529+
v.mkPath(s->state.rootPath(nix::CanonPath(str)), s->state.mem);
518530
}
519531
NIXC_CATCH_ERRS
520532
}

src/libexpr-tests/json.cc

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

src/libexpr-tests/value/print.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ struct StringPrintingTests : LibExprTest
268268
void test(std::string_view literal, std::string_view expected, unsigned int maxLength, A... args)
269269
{
270270
Value v;
271-
v.mkString(literal);
271+
v.mkString(literal, state.mem);
272272

273273
std::stringstream out;
274274
printValue(state, out, v, PrintOptions{.maxStringLength = maxLength});
@@ -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(state.rootPath(CanonPath("puppy")), state.mem);
357357

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

src/libexpr/eval.cc

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,20 +81,20 @@ static const char * makeImmutableString(std::string_view s)
8181
return t;
8282
}
8383

84-
StringData & StringData::alloc(size_t size)
84+
StringData & StringData::alloc(EvalMemory & mem, size_t size)
8585
{
86-
void * t = GC_MALLOC_ATOMIC(sizeof(StringData) + size + 1);
86+
void * t = mem.allocBytes(sizeof(StringData) + size + 1);
8787
if (!t)
8888
throw std::bad_alloc();
8989
auto res = new (t) StringData(size);
9090
return *res;
9191
}
9292

93-
const StringData & StringData::make(std::string_view s)
93+
const StringData & StringData::make(EvalMemory & mem, std::string_view s)
9494
{
9595
if (s.empty())
9696
return ""_sds;
97-
auto & res = alloc(s.size());
97+
auto & res = alloc(mem, s.size());
9898
std::memcpy(&res.data_, s.data(), s.size());
9999
res.data_[s.size()] = '\0';
100100
return res;
@@ -849,9 +849,9 @@ DebugTraceStacker::DebugTraceStacker(EvalState & evalState, DebugTrace t)
849849
evalState.runDebugRepl(nullptr, trace.env, trace.expr);
850850
}
851851

852-
void Value::mkString(std::string_view s)
852+
void Value::mkString(std::string_view s, EvalMemory & mem)
853853
{
854-
mkStringNoCopy(StringData::make(s));
854+
mkStringNoCopy(StringData::make(mem, s));
855855
}
856856

857857
Value::StringWithContext::Context *
@@ -862,23 +862,23 @@ Value::StringWithContext::Context::fromBuilder(const NixStringContext & context,
862862

863863
auto ctx = new (mem.allocBytes(sizeof(Context) + context.size() * sizeof(value_type))) Context(context.size());
864864
std::ranges::transform(
865-
context, ctx->elems, [](const NixStringContextElem & elt) { return &StringData::make(elt.to_string()); });
865+
context, ctx->elems, [&](const NixStringContextElem & elt) { return &StringData::make(mem, elt.to_string()); });
866866
return ctx;
867867
}
868868

869869
void Value::mkString(std::string_view s, const NixStringContext & context, EvalMemory & mem)
870870
{
871-
mkStringNoCopy(StringData::make(s), Value::StringWithContext::Context::fromBuilder(context, mem));
871+
mkStringNoCopy(StringData::make(mem, s), Value::StringWithContext::Context::fromBuilder(context, mem));
872872
}
873873

874874
void Value::mkStringMove(const StringData & s, const NixStringContext & context, EvalMemory & mem)
875875
{
876876
mkStringNoCopy(s, Value::StringWithContext::Context::fromBuilder(context, mem));
877877
}
878878

879-
void Value::mkPath(const SourcePath & path)
879+
void Value::mkPath(const SourcePath & path, EvalMemory & mem)
880880
{
881-
mkPath(&*path.accessor, StringData::make(path.path.abs()));
881+
mkPath(&*path.accessor, StringData::make(mem, path.path.abs()));
882882
}
883883

884884
inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
@@ -943,7 +943,7 @@ void EvalState::mkPos(Value & v, PosIdx p)
943943
auto origin = positions.originOf(p);
944944
if (auto path = std::get_if<SourcePath>(&origin)) {
945945
auto attrs = buildBindings(3);
946-
attrs.alloc(s.file).mkString(path->path.abs());
946+
attrs.alloc(s.file).mkString(path->path.abs(), mem);
947947
makePositionThunks(*this, p, attrs.alloc(s.line), attrs.alloc(s.column));
948948
v.mkAttrs(attrs);
949949
} else
@@ -2139,9 +2139,9 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
21392139
for (const auto & part : strings) {
21402140
resultStr += *part;
21412141
}
2142-
v.mkPath(state.rootPath(CanonPath(resultStr)));
2142+
v.mkPath(state.rootPath(CanonPath(resultStr)), state.mem);
21432143
} else {
2144-
auto & resultStr = StringData::alloc(sSize);
2144+
auto & resultStr = StringData::alloc(state.mem, sSize);
21452145
auto * tmp = resultStr.data();
21462146
for (const auto & part : strings) {
21472147
std::memcpy(tmp, part->data(), part->size());

0 commit comments

Comments
 (0)