Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/libcmd/include/nix/cmd/installable-attr-path.hh
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@

#include <regex>
#include <queue>
#include "nix/expr/root-value.hh"

namespace nix {

class InstallableAttrPath : public InstallableValue
{
SourceExprCommand & cmd;
RootValue v;
UniqueRootValue v;
std::string attrPath;
ExtendedOutputsSpec extendedOutputsSpec;

Expand Down
2 changes: 1 addition & 1 deletion src/libcmd/installable-attr-path.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ InstallableAttrPath::InstallableAttrPath(
ExtendedOutputsSpec extendedOutputsSpec)
: InstallableValue(state)
, cmd(cmd)
, v(allocRootValue(v))
, v(UniqueRootValue(v))
, attrPath(attrPath)
, extendedOutputsSpec(std::move(extendedOutputsSpec))
{
Expand Down
4 changes: 2 additions & 2 deletions src/libcmd/repl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ void NixRepl::loadDebugTraceEnv(DebugTrace & dt)

// add staticenv vars.
for (auto & [name, value] : *(vm.get()))
addVarToScope(state->symbols.create(name), *value);
addVarToScope(state->symbols.create(name), **value);
}
}

Expand Down Expand Up @@ -931,7 +931,7 @@ ReplExitStatus AbstractNixRepl::runSimple(ref<EvalState> evalState, const ValMap

// add 'extra' vars.
for (auto & [name, value] : extraEnv)
repl->addVarToScope(repl->state->symbols.create(name), *value);
repl->addVarToScope(repl->state->symbols.create(name), **value);

return repl->mainLoop();
}
Expand Down
8 changes: 4 additions & 4 deletions src/libexpr/eval-cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ Value * EvalCache::getRootValue()
{
if (!value) {
debug("getting root value");
value = allocRootValue(rootLoader());
value = UniqueRootValue(rootLoader());
}
return *value;
}
Expand All @@ -378,7 +378,7 @@ AttrCursor::AttrCursor(
, cachedValue(std::move(cachedValue))
{
if (value)
_value = allocRootValue(value);
_value = UniqueRootValue(value);
}

AttrKey AttrCursor::getKey()
Expand All @@ -401,9 +401,9 @@ Value & AttrCursor::getValue()
auto attr = vParent.attrs()->get(parent->second);
if (!attr)
throw Error("attribute '%s' is unexpectedly missing", getAttrPathStr());
_value = allocRootValue(attr->value);
_value = UniqueRootValue(attr->value);
} else
_value = allocRootValue(root->getRootValue());
_value = UniqueRootValue(root->getRootValue());
}
return **_value;
}
Expand Down
29 changes: 14 additions & 15 deletions src/libexpr/eval.cc
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,6 @@ const StringData & StringData::make(EvalMemory & mem, std::string_view s)
return res;
}

RootValue allocRootValue(Value * v)
{
return std::allocate_shared<Value *>(traceable_allocator<Value *>(), v);
}

// Pretty print types for assertion errors
std::ostream & operator<<(std::ostream & os, const ValueType t)
{
Expand Down Expand Up @@ -580,7 +575,7 @@ Value * EvalState::addPrimOp(PrimOp && primOp)
v->mkPrimOp(new PrimOp(primOp));

if (primOp.internal)
internalPrimOps.emplace(primOp.name, v);
internalPrimOps.emplace(primOp.name, UniqueRootValue(v));
else {
staticBaseEnv->vars.emplace_back(envName, baseEnvDispl);
baseEnv.values[baseEnvDispl++] = v;
Expand Down Expand Up @@ -754,11 +749,11 @@ void mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const En
if (se.isWith && env.values[0]->isFinished()) {
// add 'with' bindings.
for (auto & j : *env.values[0]->attrs())
vm.insert_or_assign(std::string(st[j.name]), j.value);
vm.insert_or_assign(std::string(st[j.name]), UniqueRootValue(j.value));
} else {
// iterate through staticenv bindings and add them.
for (auto & i : se.vars)
vm.insert_or_assign(std::string(st[i.first]), env.values[i.second]);
vm.insert_or_assign(std::string(st[i.first]), UniqueRootValue(env.values[i.second]));
}
}
}
Expand Down Expand Up @@ -1167,24 +1162,28 @@ void EvalState::evalFile(const SourcePath & path, Value & v, bool mustBeTrivial)
importResolutionCache->emplace(path, *resolvedPath);
}

if (auto v2 = getConcurrent(*fileEvalCache, *resolvedPath)) {
forceValue(**v2, noPos);
v = **v2;
return;
{
Value * v2 = nullptr;
fileEvalCache->cvisit(*resolvedPath, [&](auto & i) { v2 = *i.second; });
if (v2) {
forceValue(*v2, noPos);
v = *v2;
return;
Comment thread
edolstra marked this conversation as resolved.
}
}

Value * vExpr;
ExprParseFile expr{*resolvedPath, mustBeTrivial};

fileEvalCache->try_emplace_and_cvisit(
*resolvedPath,
nullptr,
UniqueRootValue(nullptr),
[&](auto & i) {
vExpr = allocValue();
vExpr->mkThunk(&baseEnv, &expr);
i.second = vExpr;
*i.second = vExpr;
},
[&](auto & i) { vExpr = i.second; });
[&](auto & i) { vExpr = *i.second; });

forceValue(*vExpr, noPos);

Expand Down
5 changes: 3 additions & 2 deletions src/libexpr/include/nix/expr/eval-cache.hh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <functional>
#include <variant>
#include "nix/expr/root-value.hh"

namespace nix::eval_cache {

Expand Down Expand Up @@ -44,7 +45,7 @@ public:
private:
typedef fun<Value *()> RootLoader;
RootLoader rootLoader;
RootValue value;
UniqueRootValue value;

Value * getRootValue();

Expand Down Expand Up @@ -111,7 +112,7 @@ public:
private:
using Parent = std::optional<std::pair<ref<AttrCursor>, Symbol>>;
const Parent parent;
RootValue _value;
UniqueRootValue _value;
std::optional<std::pair<AttrId, AttrValue>> cachedValue;

AttrKey getKey();
Expand Down
21 changes: 4 additions & 17 deletions src/libexpr/include/nix/expr/eval.hh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "nix/expr/eval-profiler.hh"
#include "nix/util/types.hh"
#include "nix/expr/value.hh"
#include "nix/expr/root-value.hh"
#include "nix/expr/nixexpr.hh"
#include "nix/expr/symbol-table.hh"
#include "nix/util/configuration.hh"
Expand Down Expand Up @@ -167,9 +168,7 @@ struct Constant
bool impureOnly = false;
};

typedef std::
map<std::string, Value *, std::less<std::string>, traceable_allocator<std::pair<const std::string, Value *>>>
ValMap;
typedef std::map<std::string, UniqueRootValue> ValMap;

typedef boost::unordered_flat_map<PosIdx, DocComment, std::hash<PosIdx>> DocCommentMap;

Expand Down Expand Up @@ -473,13 +472,7 @@ private:
/**
* A cache from resolved paths to values.
*/
const ref<boost::concurrent_flat_map<
SourcePath,
Value *,
std::hash<SourcePath>,
std::equal_to<SourcePath>,
traceable_allocator<std::pair<const SourcePath, Value *>>>>
fileEvalCache;
const ref<boost::concurrent_flat_map<SourcePath, UniqueRootValue>> fileEvalCache;

/**
* Associate source positions of certain AST nodes with their preceding doc comment, if they have one.
Expand Down Expand Up @@ -817,13 +810,7 @@ public:
/**
* Internal primops not exposed to the user.
*/
boost::unordered_flat_map<
std::string,
Value *,
StringViewHash,
std::equal_to<>,
traceable_allocator<std::pair<const std::string, Value *>>>
internalPrimOps;
boost::unordered_flat_map<std::string, UniqueRootValue, StringViewHash> internalPrimOps;

/**
* Name and documentation about every constant.
Expand Down
1 change: 1 addition & 0 deletions src/libexpr/include/nix/expr/get-drvs.hh
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ private:
*/
bool failed = false;

// FIXME: make this a UniqueRootValue.
const Bindings *attrs = nullptr, *meta = nullptr;
Comment thread
edolstra marked this conversation as resolved.

const Bindings * getMeta();
Expand Down
1 change: 1 addition & 0 deletions src/libexpr/include/nix/expr/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ headers = [ config_pub_h ] + files(
'print.hh',
'provenance.hh',
'repl-exit-status.hh',
'root-value.hh',
'search-path.hh',
'static-string-data.hh',
'symbol-table.hh',
Expand Down
96 changes: 96 additions & 0 deletions src/libexpr/include/nix/expr/root-value.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#pragma once
///@file

#include <memory>
#include <utility>

namespace nix {

struct Value;

/**
* Allocate a slot from the root value pool, i.e. a GC-visible
* `Value *` cell that keeps the value it points to alive across
* garbage collections. Use `UniqueRootValue`/`RootValue` rather than
* calling this directly.
*/
Value ** allocRootValueSlot(Value * v);

/**
* Clear the given slot and return it to the root value pool.
*/
void freeRootValueSlot(Value ** slot);

/**
* A move-only handle rooting a Value, i.e. keeping it and everything
* reachable from it alive across garbage collections. Prefer this
* over `RootValue` unless the handle must be copyable (e.g. when it's
* captured in a `std::function`-backed lambda).
*/
class UniqueRootValue
{
Value ** slot = nullptr;

public:
UniqueRootValue() = default;

explicit UniqueRootValue(Value * v)
: slot(allocRootValueSlot(v))
{
}

UniqueRootValue(const UniqueRootValue &) = delete;
UniqueRootValue & operator=(const UniqueRootValue &) = delete;

UniqueRootValue(UniqueRootValue && other) noexcept
: slot(std::exchange(other.slot, nullptr))
{
}

UniqueRootValue & operator=(UniqueRootValue && other) noexcept
{
if (this == &other)
return *this;
if (slot)
freeRootValueSlot(slot);
slot = std::exchange(other.slot, nullptr);
return *this;
Comment thread
edolstra marked this conversation as resolved.
}

~UniqueRootValue()
{
if (slot)
freeRootValueSlot(slot);
}

/**
* Release the slot, i.e. stop rooting the value.
*/
void reset()
{
if (slot) {
freeRootValueSlot(slot);
slot = nullptr;
}
}

Value *& operator*() const
{
return *slot;
}

explicit operator bool() const
{
return slot != nullptr;
}
};

/**
* A copyable, shared handle rooting a Value. Only use this instead of
* `UniqueRootValue` if the handle must be copyable.
*/
typedef std::shared_ptr<Value *> RootValue;

RootValue allocRootValue(Value * v);

} // namespace nix
8 changes: 1 addition & 7 deletions src/libexpr/include/nix/expr/value.hh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <memory_resource>
#include <exception>
#include <span>
#include <utility>
#include <string_view>
#include <type_traits>
#include <concepts>
Expand Down Expand Up @@ -1541,12 +1542,5 @@ typedef boost::unordered_flat_map<
traceable_allocator<std::pair<const Symbol, Value *>>>
ValueMap;

/**
* A value allocated in traceable memory.
*/
typedef std::shared_ptr<Value *> RootValue;

RootValue allocRootValue(Value * v);

void forceNoNullByte(std::string_view s, std::function<Pos()> = nullptr);
} // namespace nix
10 changes: 5 additions & 5 deletions src/libexpr/json-to-value.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class JSONSax : nlohmann::json_sax<json>
{
protected:
std::unique_ptr<JSONState> parent;
RootValue v;
UniqueRootValue v;
public:
virtual std::unique_ptr<JSONState> resolve(EvalState &)
{
Expand All @@ -31,7 +31,7 @@ class JSONSax : nlohmann::json_sax<json>
}

explicit JSONState(Value * v)
: v(allocRootValue(v))
: v(UniqueRootValue(v))
{
}

Expand All @@ -40,7 +40,7 @@ class JSONSax : nlohmann::json_sax<json>
Value & value(EvalState & state)
{
if (!v)
v = allocRootValue(state.allocValue());
v = UniqueRootValue(state.allocValue());
return **v;
}

Expand All @@ -65,7 +65,7 @@ class JSONSax : nlohmann::json_sax<json>

void add() override
{
v = nullptr;
v.reset();
}
public:
void key(string_t & name, EvalState & state)
Expand All @@ -91,7 +91,7 @@ class JSONSax : nlohmann::json_sax<json>
void add() override
{
values.push_back(*v);
v = nullptr;
v.reset();
}
public:
JSONListState(std::unique_ptr<JSONState> && p, std::size_t reserve)
Expand Down
Loading
Loading