refactor(tvix): completely remove boehm gc
We have decided that leaking memory is a better fate than random, non-debuggable memory corruption. Future CLs will begin changing various fields to std::unique_ptr and std::shared_ptr. It turns out that disabling the GC does not have disasterous impact. The Nix evaluator only runs on the client CLI, never in any long- running process. Even the REPL does not leak too badly under this change, because it uses one EvalState for the duration of the REPL. Building an explicitly tracing garbage collector is likely in the future of this project, but that giant amount of work cannot be done under a nix evaluator that is constantly crashing. We need to restore development velocity here, and this is the best way we've figured out to do it. Change-Id: I2fcda8fcee853c15a9a5e22eca7c5a784bc2bf76 Reviewed-on: https://cl.tvl.fyi/c/depot/+/1720 Reviewed-by: glittershark <grfn@gws.fyi> Reviewed-by: tazjin <mail@tazj.in> Tested-by: BuildkiteCI
This commit is contained in:
parent
d4f5fcef66
commit
72e61aa584
15 changed files with 51 additions and 170 deletions
7
third_party/nix/default.nix
vendored
7
third_party/nix/default.nix
vendored
|
@ -12,12 +12,6 @@ let
|
||||||
customMemoryManagement = false;
|
customMemoryManagement = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
# TODO(tazjin): this is copied from the original derivation, but what
|
|
||||||
# is it for?
|
|
||||||
largeBoehm = pkgs.boehmgc.override {
|
|
||||||
enableLargeConfig = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
src = ./.;
|
src = ./.;
|
||||||
|
|
||||||
# Proto generation in CMake is theoretically possible, but that is
|
# Proto generation in CMake is theoretically possible, but that is
|
||||||
|
@ -84,7 +78,6 @@ in lib.fix (self: pkgs.llvmPackages.libcxxStdenv.mkDerivation {
|
||||||
|
|
||||||
propagatedBuildInputs = with pkgs; [
|
propagatedBuildInputs = with pkgs; [
|
||||||
boost
|
boost
|
||||||
largeBoehm
|
|
||||||
];
|
];
|
||||||
|
|
||||||
configurePhase = ''
|
configurePhase = ''
|
||||||
|
|
2
third_party/nix/src/libexpr/CMakeLists.txt
vendored
2
third_party/nix/src/libexpr/CMakeLists.txt
vendored
|
@ -75,8 +75,6 @@ target_link_libraries(nixexpr
|
||||||
absl::flat_hash_set
|
absl::flat_hash_set
|
||||||
absl::node_hash_set
|
absl::node_hash_set
|
||||||
absl::strings
|
absl::strings
|
||||||
gc
|
|
||||||
gccpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
configure_file("nix-expr.pc.in" "${PROJECT_BINARY_DIR}/nix-expr.pc" @ONLY)
|
configure_file("nix-expr.pc.in" "${PROJECT_BINARY_DIR}/nix-expr.pc" @ONLY)
|
||||||
|
|
3
third_party/nix/src/libexpr/attr-set.cc
vendored
3
third_party/nix/src/libexpr/attr-set.cc
vendored
|
@ -3,7 +3,6 @@
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
#include <absl/container/btree_map.h>
|
#include <absl/container/btree_map.h>
|
||||||
#include <gc/gc_cpp.h>
|
|
||||||
#include <glog/logging.h>
|
#include <glog/logging.h>
|
||||||
|
|
||||||
#include "libexpr/eval-inline.hh"
|
#include "libexpr/eval-inline.hh"
|
||||||
|
@ -61,7 +60,7 @@ Bindings* Bindings::NewGC(size_t capacity) {
|
||||||
return &ZERO_BINDINGS;
|
return &ZERO_BINDINGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new (GC) Bindings;
|
return new Bindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bindings* Bindings::Merge(const Bindings& lhs, const Bindings& rhs) {
|
Bindings* Bindings::Merge(const Bindings& lhs, const Bindings& rhs) {
|
||||||
|
|
11
third_party/nix/src/libexpr/attr-set.hh
vendored
11
third_party/nix/src/libexpr/attr-set.hh
vendored
|
@ -2,7 +2,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <absl/container/btree_map.h>
|
#include <absl/container/btree_map.h>
|
||||||
#include <gc/gc_allocator.h>
|
|
||||||
|
|
||||||
#include "libexpr/nixexpr.hh"
|
#include "libexpr/nixexpr.hh"
|
||||||
#include "libexpr/symbol-table.hh"
|
#include "libexpr/symbol-table.hh"
|
||||||
|
@ -14,7 +13,7 @@ class EvalState;
|
||||||
struct Value;
|
struct Value;
|
||||||
|
|
||||||
/* Map one attribute name to its value. */
|
/* Map one attribute name to its value. */
|
||||||
struct Attr : public gc {
|
struct Attr {
|
||||||
Symbol name;
|
Symbol name;
|
||||||
Value* value; // TODO(tazjin): Who owns this?
|
Value* value; // TODO(tazjin): Who owns this?
|
||||||
Pos* pos; // TODO(tazjin): Who owns this?
|
Pos* pos; // TODO(tazjin): Who owns this?
|
||||||
|
@ -22,13 +21,9 @@ struct Attr : public gc {
|
||||||
: name(name), value(value), pos(pos){};
|
: name(name), value(value), pos(pos){};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Convenience alias for the backing map, with the garbage-collecting
|
using AttributeMap = absl::btree_map<Symbol, Attr>;
|
||||||
// allocator explicitly specified.
|
|
||||||
using AttributeMap =
|
|
||||||
absl::btree_map<Symbol, Attr, std::less<Symbol>,
|
|
||||||
traceable_allocator<std::pair<const Symbol, Attr>>>;
|
|
||||||
|
|
||||||
class Bindings : public gc {
|
class Bindings {
|
||||||
public:
|
public:
|
||||||
typedef AttributeMap::iterator iterator;
|
typedef AttributeMap::iterator iterator;
|
||||||
|
|
||||||
|
|
82
third_party/nix/src/libexpr/eval.cc
vendored
82
third_party/nix/src/libexpr/eval.cc
vendored
|
@ -11,13 +11,9 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
#define GC_INCLUDE_NEW
|
|
||||||
|
|
||||||
#include <absl/base/call_once.h>
|
#include <absl/base/call_once.h>
|
||||||
#include <absl/container/flat_hash_set.h>
|
#include <absl/container/flat_hash_set.h>
|
||||||
#include <absl/strings/match.h>
|
#include <absl/strings/match.h>
|
||||||
#include <gc/gc.h>
|
|
||||||
#include <gc/gc_cpp.h>
|
|
||||||
#include <glog/logging.h>
|
#include <glog/logging.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
@ -38,52 +34,7 @@
|
||||||
namespace nix {
|
namespace nix {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Called when the Boehm GC runs out of memory.
|
void ConfigureGc() { /* This function intentionally left blank. */
|
||||||
static void* BoehmOomHandler(size_t requested) {
|
|
||||||
/* Convert this to a proper C++ exception. */
|
|
||||||
LOG(FATAL) << "Garbage collector ran out of memory; requested " << requested
|
|
||||||
<< " bytes";
|
|
||||||
throw std::bad_alloc();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigureBoehmGc() {
|
|
||||||
/* Don't look for interior pointers. This reduces the odds of
|
|
||||||
misdetection a bit. */
|
|
||||||
GC_set_all_interior_pointers(0);
|
|
||||||
|
|
||||||
/* We don't have any roots in data segments, so don't scan from
|
|
||||||
there. */
|
|
||||||
GC_set_no_dls(1);
|
|
||||||
|
|
||||||
GC_INIT();
|
|
||||||
|
|
||||||
GC_set_oom_fn(BoehmOomHandler);
|
|
||||||
|
|
||||||
/* Set the initial heap size to something fairly big (25% of
|
|
||||||
physical RAM, up to a maximum of 384 MiB) so that in most cases
|
|
||||||
we don't need to garbage collect at all. (Collection has a
|
|
||||||
fairly significant overhead.) The heap size can be overridden
|
|
||||||
through libgc's GC_INITIAL_HEAP_SIZE environment variable. We
|
|
||||||
should probably also provide a nix.conf setting for this. Note
|
|
||||||
that GC_expand_hp() causes a lot of virtual, but not physical
|
|
||||||
(resident) memory to be allocated. This might be a problem on
|
|
||||||
systems that don't overcommit. */
|
|
||||||
if (getenv("GC_INITIAL_HEAP_SIZE") == nullptr) {
|
|
||||||
size_t size = 32 * 1024 * 1024;
|
|
||||||
#if HAVE_SYSCONF && defined(_SC_PAGESIZE) && defined(_SC_PHYS_PAGES)
|
|
||||||
size_t maxSize = 384 * 1024 * 1024;
|
|
||||||
long pageSize = sysconf(_SC_PAGESIZE);
|
|
||||||
long pages = sysconf(_SC_PHYS_PAGES);
|
|
||||||
if (pageSize != -1) {
|
|
||||||
size = (pageSize * pages) / 4;
|
|
||||||
} // 25% of RAM
|
|
||||||
if (size > maxSize) {
|
|
||||||
size = maxSize;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
DLOG(INFO) << "setting initial heap size to " << size << " bytes";
|
|
||||||
GC_expand_hp(size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -92,13 +43,13 @@ namespace expr {
|
||||||
|
|
||||||
absl::once_flag gc_flag;
|
absl::once_flag gc_flag;
|
||||||
|
|
||||||
void InitGC() { absl::call_once(gc_flag, &ConfigureBoehmGc); }
|
void InitGC() { absl::call_once(gc_flag, &ConfigureGc); }
|
||||||
|
|
||||||
} // namespace expr
|
} // namespace expr
|
||||||
|
|
||||||
static char* dupString(const char* s) {
|
static char* dupString(const char* s) {
|
||||||
char* t;
|
char* t;
|
||||||
t = GC_STRDUP(s);
|
t = strdup(s);
|
||||||
if (t == nullptr) {
|
if (t == nullptr) {
|
||||||
throw std::bad_alloc();
|
throw std::bad_alloc();
|
||||||
}
|
}
|
||||||
|
@ -106,7 +57,7 @@ static char* dupString(const char* s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Value*> allocRootValue(Value* v) {
|
std::shared_ptr<Value*> allocRootValue(Value* v) {
|
||||||
return std::allocate_shared<Value*>(traceable_allocator<Value*>(), v);
|
return std::make_shared<Value*>(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void printValue(std::ostream& str, std::set<const Value*>& active,
|
static void printValue(std::ostream& str, std::set<const Value*>& active,
|
||||||
|
@ -489,7 +440,7 @@ Value* EvalState::addPrimOp(const std::string& name, size_t arity,
|
||||||
Symbol sym = symbols.Create(name2);
|
Symbol sym = symbols.Create(name2);
|
||||||
// Even though PrimOp doesn't need tracing, it needs to be collected.
|
// Even though PrimOp doesn't need tracing, it needs to be collected.
|
||||||
v->type = tPrimOp;
|
v->type = tPrimOp;
|
||||||
v->primOp = new (GC) PrimOp(primOp, arity, sym);
|
v->primOp = new PrimOp(primOp, arity, sym);
|
||||||
staticBaseEnv.vars[symbols.Create(name)] = baseEnvDispl;
|
staticBaseEnv.vars[symbols.Create(name)] = baseEnvDispl;
|
||||||
baseEnv.values[baseEnvDispl++] = v;
|
baseEnv.values[baseEnvDispl++] = v;
|
||||||
baseEnv.values[0]->attrs->push_back(Attr(sym, v));
|
baseEnv.values[0]->attrs->push_back(Attr(sym, v));
|
||||||
|
@ -631,7 +582,7 @@ inline Value* EvalState::lookupVar(Env* env, const ExprVar& var, bool noEval) {
|
||||||
|
|
||||||
Value* EvalState::allocValue() {
|
Value* EvalState::allocValue() {
|
||||||
nrValues++;
|
nrValues++;
|
||||||
return new (GC) Value;
|
return new Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Env& EvalState::allocEnv(size_t size) {
|
Env& EvalState::allocEnv(size_t size) {
|
||||||
|
@ -655,7 +606,7 @@ void EvalState::mkList(Value& v, NixList* list) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EvalState::mkList(Value& v, size_t size) {
|
void EvalState::mkList(Value& v, size_t size) {
|
||||||
EvalState::mkList(v, new (GC) NixList(size));
|
EvalState::mkList(v, new NixList(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long nrThunks = 0;
|
unsigned long nrThunks = 0;
|
||||||
|
@ -1262,7 +1213,7 @@ void ExprOpConcatLists::eval(EvalState& state, Env& env, Value& v) {
|
||||||
void EvalState::concatLists(Value& v, const NixList& lists, const Pos& pos) {
|
void EvalState::concatLists(Value& v, const NixList& lists, const Pos& pos) {
|
||||||
nrListConcats++;
|
nrListConcats++;
|
||||||
|
|
||||||
auto outlist = new (GC) NixList();
|
auto outlist = new NixList();
|
||||||
|
|
||||||
for (Value* list : lists) {
|
for (Value* list : lists) {
|
||||||
forceList(*list, pos);
|
forceList(*list, pos);
|
||||||
|
@ -1344,10 +1295,7 @@ void ExprPos::eval(EvalState& state, Env& env, Value& v) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using traceable_flat_hash_set =
|
using traceable_flat_hash_set = absl::flat_hash_set<T>;
|
||||||
absl::flat_hash_set<T, absl::container_internal::hash_default_hash<T>,
|
|
||||||
absl::container_internal::hash_default_eq<T>,
|
|
||||||
traceable_allocator<T>>;
|
|
||||||
|
|
||||||
void EvalState::forceValueDeep(Value& v) {
|
void EvalState::forceValueDeep(Value& v) {
|
||||||
traceable_flat_hash_set<const Value*> seen;
|
traceable_flat_hash_set<const Value*> seen;
|
||||||
|
@ -1713,11 +1661,6 @@ void EvalState::printStats() {
|
||||||
uint64_t bAttrsets =
|
uint64_t bAttrsets =
|
||||||
nrAttrsets * sizeof(Bindings) + nrAttrsInAttrsets * sizeof(Attr);
|
nrAttrsets * sizeof(Bindings) + nrAttrsInAttrsets * sizeof(Attr);
|
||||||
|
|
||||||
#if HAVE_BOEHMGC
|
|
||||||
GC_word heapSize;
|
|
||||||
GC_word totalBytes;
|
|
||||||
GC_get_heap_usage_safe(&heapSize, nullptr, nullptr, nullptr, &totalBytes);
|
|
||||||
#endif
|
|
||||||
if (showStats) {
|
if (showStats) {
|
||||||
auto outPath = getEnv("NIX_SHOW_STATS_PATH", "-");
|
auto outPath = getEnv("NIX_SHOW_STATS_PATH", "-");
|
||||||
std::fstream fs;
|
std::fstream fs;
|
||||||
|
@ -1768,13 +1711,6 @@ void EvalState::printStats() {
|
||||||
topObj.attr("nrLookups", nrLookups);
|
topObj.attr("nrLookups", nrLookups);
|
||||||
topObj.attr("nrPrimOpCalls", nrPrimOpCalls);
|
topObj.attr("nrPrimOpCalls", nrPrimOpCalls);
|
||||||
topObj.attr("nrFunctionCalls", nrFunctionCalls);
|
topObj.attr("nrFunctionCalls", nrFunctionCalls);
|
||||||
#if HAVE_BOEHMGC
|
|
||||||
{
|
|
||||||
auto gc = topObj.object("gc");
|
|
||||||
gc.attr("heapSize", heapSize);
|
|
||||||
gc.attr("totalBytes", totalBytes);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (countCalls) {
|
if (countCalls) {
|
||||||
{
|
{
|
||||||
|
|
25
third_party/nix/src/libexpr/eval.hh
vendored
25
third_party/nix/src/libexpr/eval.hh
vendored
|
@ -5,9 +5,6 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <gc/gc_allocator.h>
|
|
||||||
#include <gc/gc_cpp.h>
|
|
||||||
|
|
||||||
#include "libexpr/attr-set.hh"
|
#include "libexpr/attr-set.hh"
|
||||||
#include "libexpr/nixexpr.hh"
|
#include "libexpr/nixexpr.hh"
|
||||||
#include "libexpr/symbol-table.hh"
|
#include "libexpr/symbol-table.hh"
|
||||||
|
@ -39,16 +36,14 @@ struct PrimOp {
|
||||||
: fun(fun), arity(arity), name(name) {}
|
: fun(fun), arity(arity), name(name) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Env : public gc {
|
struct Env {
|
||||||
Env(unsigned short size) : size(size) {
|
Env(unsigned short size) : size(size) { values = std::vector<Value*>(size); }
|
||||||
values = std::vector<Value*, traceable_allocator<Value*>>(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
Env* up;
|
Env* up;
|
||||||
unsigned short size; // used by ‘valueSize’
|
unsigned short size; // used by ‘valueSize’
|
||||||
unsigned short prevWith : 14; // nr of levels up to next `with' environment
|
unsigned short prevWith : 14; // nr of levels up to next `with' environment
|
||||||
enum { Plain = 0, HasWithExpr, HasWithAttrs } type : 2;
|
enum { Plain = 0, HasWithExpr, HasWithAttrs } type : 2;
|
||||||
std::vector<Value*, traceable_allocator<Value*>> values;
|
std::vector<Value*> values;
|
||||||
Expr* withAttrsExpr = nullptr;
|
Expr* withAttrsExpr = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -63,14 +58,12 @@ typedef std::map<Path, Path> SrcToStore;
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& str, const Value& v);
|
std::ostream& operator<<(std::ostream& str, const Value& v);
|
||||||
|
|
||||||
typedef std::pair<std::string, std::string> SearchPathElem;
|
using SearchPathElem = std::pair<std::string, std::string>;
|
||||||
typedef std::list<SearchPathElem> SearchPath;
|
using SearchPath = std::list<SearchPathElem>;
|
||||||
|
|
||||||
typedef std::map<Path, Expr*, std::less<Path>,
|
using FileParseCache = std::map<Path, Expr*>;
|
||||||
traceable_allocator<std::pair<const Path, Expr*>>>
|
|
||||||
FileParseCache;
|
|
||||||
|
|
||||||
class EvalState : public gc {
|
class EvalState {
|
||||||
public:
|
public:
|
||||||
SymbolTable symbols;
|
SymbolTable symbols;
|
||||||
|
|
||||||
|
@ -100,9 +93,7 @@ class EvalState : public gc {
|
||||||
FileParseCache fileParseCache;
|
FileParseCache fileParseCache;
|
||||||
|
|
||||||
/* A cache from path names to values. */
|
/* A cache from path names to values. */
|
||||||
typedef std::map<Path, Value, std::less<Path>,
|
using FileEvalCache = std::map<Path, Value>;
|
||||||
traceable_allocator<std::pair<const Path, Value>>>
|
|
||||||
FileEvalCache;
|
|
||||||
FileEvalCache fileEvalCache;
|
FileEvalCache fileEvalCache;
|
||||||
|
|
||||||
SearchPath searchPath;
|
SearchPath searchPath;
|
||||||
|
|
6
third_party/nix/src/libexpr/get-drvs.hh
vendored
6
third_party/nix/src/libexpr/get-drvs.hh
vendored
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
struct DrvInfo : public gc {
|
struct DrvInfo {
|
||||||
public:
|
public:
|
||||||
typedef std::map<std::string, Path> Outputs;
|
typedef std::map<std::string, Path> Outputs;
|
||||||
|
|
||||||
|
@ -67,11 +67,7 @@ struct DrvInfo : public gc {
|
||||||
bool hasFailed() { return failed; };
|
bool hasFailed() { return failed; };
|
||||||
};
|
};
|
||||||
|
|
||||||
#if HAVE_BOEHMGC
|
|
||||||
typedef std::list<DrvInfo, traceable_allocator<DrvInfo> > DrvInfos;
|
|
||||||
#else
|
|
||||||
typedef std::list<DrvInfo> DrvInfos;
|
typedef std::list<DrvInfo> DrvInfos;
|
||||||
#endif
|
|
||||||
|
|
||||||
/* If value `v' denotes a derivation, return a DrvInfo object
|
/* If value `v' denotes a derivation, return a DrvInfo object
|
||||||
describing it. Otherwise return nothing. */
|
describing it. Otherwise return nothing. */
|
||||||
|
|
30
third_party/nix/src/libexpr/nixexpr.hh
vendored
30
third_party/nix/src/libexpr/nixexpr.hh
vendored
|
@ -73,19 +73,16 @@ struct StaticEnv;
|
||||||
|
|
||||||
/* An attribute path is a sequence of attribute names. */
|
/* An attribute path is a sequence of attribute names. */
|
||||||
using AttrName = std::variant<Symbol, Expr*>;
|
using AttrName = std::variant<Symbol, Expr*>;
|
||||||
|
using AttrPath = std::vector<AttrName>;
|
||||||
|
using AttrNameVector = std::vector<AttrName>;
|
||||||
|
|
||||||
typedef std::vector<AttrName, traceable_allocator<AttrName>> AttrPath;
|
using VectorExprs = std::vector<nix::Expr*>;
|
||||||
|
|
||||||
using AttrNameVector =
|
|
||||||
std::vector<nix::AttrName, traceable_allocator<nix::AttrName>>;
|
|
||||||
|
|
||||||
using VectorExprs = std::vector<nix::Expr*, traceable_allocator<nix::Expr*>>;
|
|
||||||
|
|
||||||
std::string showAttrPath(const AttrPath& attrPath);
|
std::string showAttrPath(const AttrPath& attrPath);
|
||||||
|
|
||||||
/* Abstract syntax of Nix expressions. */
|
/* Abstract syntax of Nix expressions. */
|
||||||
|
|
||||||
struct Expr : public gc {
|
struct Expr {
|
||||||
virtual ~Expr(){};
|
virtual ~Expr(){};
|
||||||
virtual void show(std::ostream& str) const;
|
virtual void show(std::ostream& str) const;
|
||||||
virtual void bindVars(const StaticEnv& env);
|
virtual void bindVars(const StaticEnv& env);
|
||||||
|
@ -191,7 +188,7 @@ struct ExprOpHasAttr : Expr {
|
||||||
struct ExprAttrs : Expr {
|
struct ExprAttrs : Expr {
|
||||||
bool recursive;
|
bool recursive;
|
||||||
|
|
||||||
struct AttrDef : public gc {
|
struct AttrDef {
|
||||||
bool inherited;
|
bool inherited;
|
||||||
Expr* e;
|
Expr* e;
|
||||||
Pos pos;
|
Pos pos;
|
||||||
|
@ -201,22 +198,17 @@ struct ExprAttrs : Expr {
|
||||||
AttrDef(){};
|
AttrDef(){};
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef absl::flat_hash_map<
|
using AttrDefs = absl::flat_hash_map<Symbol, AttrDef>;
|
||||||
Symbol, AttrDef, absl::container_internal::hash_default_hash<Symbol>,
|
|
||||||
absl::container_internal::hash_default_eq<Symbol>,
|
|
||||||
traceable_allocator<std::pair<const Symbol, AttrDef>>>
|
|
||||||
AttrDefs;
|
|
||||||
AttrDefs attrs;
|
AttrDefs attrs;
|
||||||
|
|
||||||
struct DynamicAttrDef : public gc {
|
struct DynamicAttrDef {
|
||||||
Expr *nameExpr, *valueExpr;
|
Expr *nameExpr, *valueExpr;
|
||||||
Pos pos;
|
Pos pos;
|
||||||
DynamicAttrDef(Expr* nameExpr, Expr* valueExpr, const Pos& pos)
|
DynamicAttrDef(Expr* nameExpr, Expr* valueExpr, const Pos& pos)
|
||||||
: nameExpr(nameExpr), valueExpr(valueExpr), pos(pos){};
|
: nameExpr(nameExpr), valueExpr(valueExpr), pos(pos){};
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<DynamicAttrDef, traceable_allocator<DynamicAttrDef>>
|
using DynamicAttrDefs = std::vector<DynamicAttrDef>;
|
||||||
DynamicAttrDefs;
|
|
||||||
DynamicAttrDefs dynamicAttrs;
|
DynamicAttrDefs dynamicAttrs;
|
||||||
|
|
||||||
ExprAttrs() : recursive(false){};
|
ExprAttrs() : recursive(false){};
|
||||||
|
@ -229,15 +221,15 @@ struct ExprList : Expr {
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Formal : public gc {
|
struct Formal {
|
||||||
Symbol name;
|
Symbol name;
|
||||||
Expr* def; // def = default, not definition
|
Expr* def; // def = default, not definition
|
||||||
Formal(const Symbol& name, Expr* def) : name(name), def(def){};
|
Formal(const Symbol& name, Expr* def) : name(name), def(def){};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Describes structured function arguments (e.g. `{ a }: ...`)
|
// Describes structured function arguments (e.g. `{ a }: ...`)
|
||||||
struct Formals : public gc {
|
struct Formals {
|
||||||
typedef std::list<Formal, traceable_allocator<Formal>> Formals_;
|
using Formals_ = std::list<Formal>;
|
||||||
Formals_ formals;
|
Formals_ formals;
|
||||||
std::set<Symbol> argNames; // used during parsing
|
std::set<Symbol> argNames; // used during parsing
|
||||||
bool ellipsis;
|
bool ellipsis;
|
||||||
|
|
3
third_party/nix/src/libexpr/parser.hh
vendored
3
third_party/nix/src/libexpr/parser.hh
vendored
|
@ -5,7 +5,6 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
#include <gc/gc.h>
|
|
||||||
#include <glog/logging.h>
|
#include <glog/logging.h>
|
||||||
|
|
||||||
#include "libexpr/eval.hh"
|
#include "libexpr/eval.hh"
|
||||||
|
@ -20,7 +19,7 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
struct ParseData : public gc {
|
struct ParseData {
|
||||||
EvalState& state;
|
EvalState& state;
|
||||||
SymbolTable& symbols;
|
SymbolTable& symbols;
|
||||||
Expr* result;
|
Expr* result;
|
||||||
|
|
7
third_party/nix/src/libexpr/parser.y
vendored
7
third_party/nix/src/libexpr/parser.y
vendored
|
@ -15,12 +15,7 @@
|
||||||
#define YY_NO_INPUT 1 // disable unused yyinput features
|
#define YY_NO_INPUT 1 // disable unused yyinput features
|
||||||
#include "libexpr/parser.hh"
|
#include "libexpr/parser.hh"
|
||||||
|
|
||||||
// Allow GC tracing of YY-allocated structures
|
struct YYSTYPE {
|
||||||
#define YYMALLOC GC_MALLOC_UNCOLLECTABLE
|
|
||||||
#define YYFREE GC_FREE
|
|
||||||
#define YYREALLOC GC_REALLOC
|
|
||||||
|
|
||||||
struct YYSTYPE : public gc {
|
|
||||||
union {
|
union {
|
||||||
nix::Expr * e;
|
nix::Expr * e;
|
||||||
nix::ExprList * list;
|
nix::ExprList * list;
|
||||||
|
|
12
third_party/nix/src/libexpr/primops.cc
vendored
12
third_party/nix/src/libexpr/primops.cc
vendored
|
@ -290,11 +290,7 @@ struct CompareValues {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#if HAVE_BOEHMGC
|
|
||||||
typedef std::list<Value*, gc_allocator<Value*>> ValueList;
|
|
||||||
#else
|
|
||||||
typedef std::list<Value*> ValueList;
|
typedef std::list<Value*> ValueList;
|
||||||
#endif
|
|
||||||
|
|
||||||
static void prim_genericClosure(EvalState& state, const Pos& pos, Value** args,
|
static void prim_genericClosure(EvalState& state, const Pos& pos, Value** args,
|
||||||
Value& v) {
|
Value& v) {
|
||||||
|
@ -1603,7 +1599,7 @@ static void prim_sort(EvalState& state, const Pos& pos, Value** args,
|
||||||
state.forceList(*args[1], pos);
|
state.forceList(*args[1], pos);
|
||||||
|
|
||||||
// Copy of the input list which can be sorted in place.
|
// Copy of the input list which can be sorted in place.
|
||||||
auto outlist = new (GC) NixList(*args[1]->list);
|
auto outlist = new NixList(*args[1]->list);
|
||||||
|
|
||||||
std::for_each(outlist->begin(), outlist->end(),
|
std::for_each(outlist->begin(), outlist->end(),
|
||||||
[&](Value* val) { state.forceValue(*val); });
|
[&](Value* val) { state.forceValue(*val); });
|
||||||
|
@ -1633,8 +1629,8 @@ static void prim_partition(EvalState& state, const Pos& pos, Value** args,
|
||||||
state.forceFunction(*args[0], pos);
|
state.forceFunction(*args[0], pos);
|
||||||
state.forceList(*args[1], pos);
|
state.forceList(*args[1], pos);
|
||||||
|
|
||||||
NixList* right = new (GC) NixList();
|
NixList* right = new NixList();
|
||||||
NixList* wrong = new (GC) NixList();
|
NixList* wrong = new NixList();
|
||||||
|
|
||||||
for (Value* elem : *args[1]->list) {
|
for (Value* elem : *args[1]->list) {
|
||||||
state.forceValue(*elem, pos);
|
state.forceValue(*elem, pos);
|
||||||
|
@ -1664,7 +1660,7 @@ static void prim_concatMap(EvalState& state, const Pos& pos, Value** args,
|
||||||
state.forceFunction(*args[0], pos);
|
state.forceFunction(*args[0], pos);
|
||||||
state.forceList(*args[1], pos);
|
state.forceList(*args[1], pos);
|
||||||
|
|
||||||
NixList* outlist = new (GC) NixList;
|
NixList* outlist = new NixList;
|
||||||
|
|
||||||
for (Value* elem : *args[1]->list) {
|
for (Value* elem : *args[1]->list) {
|
||||||
auto out = state.allocValue();
|
auto out = state.allocValue();
|
||||||
|
|
21
third_party/nix/src/libexpr/value.hh
vendored
21
third_party/nix/src/libexpr/value.hh
vendored
|
@ -3,9 +3,6 @@
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <gc/gc_allocator.h>
|
|
||||||
#include <gc/gc_cpp.h>
|
|
||||||
|
|
||||||
#include "libexpr/symbol-table.hh"
|
#include "libexpr/symbol-table.hh"
|
||||||
#include "libutil/types.hh"
|
#include "libutil/types.hh"
|
||||||
|
|
||||||
|
@ -66,32 +63,32 @@ struct Value;
|
||||||
the inputSrcs of the derivations.
|
the inputSrcs of the derivations.
|
||||||
|
|
||||||
For canonicity, the store paths should be in sorted order. */
|
For canonicity, the store paths should be in sorted order. */
|
||||||
struct NixString : public gc {
|
struct NixString {
|
||||||
const char* s;
|
const char* s;
|
||||||
const char** context; // must be in sorted order
|
const char** context; // must be in sorted order
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NixThunk : public gc {
|
struct NixThunk {
|
||||||
Env* env;
|
Env* env;
|
||||||
Expr* expr;
|
Expr* expr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NixApp : public gc {
|
struct NixApp {
|
||||||
Value *left, *right;
|
Value *left, *right;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NixLambda : public gc {
|
struct NixLambda {
|
||||||
Env* env;
|
Env* env;
|
||||||
ExprLambda* fun;
|
ExprLambda* fun;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NixPrimOpApp : public gc {
|
struct NixPrimOpApp {
|
||||||
Value *left, *right;
|
Value *left, *right;
|
||||||
};
|
};
|
||||||
|
|
||||||
using NixList = std::vector<Value*, traceable_allocator<Value*>>;
|
using NixList = std::vector<Value*>;
|
||||||
|
|
||||||
struct Value : public gc {
|
struct Value {
|
||||||
ValueType type;
|
ValueType type;
|
||||||
union { // TODO(tazjin): std::variant
|
union { // TODO(tazjin): std::variant
|
||||||
NixInt integer;
|
NixInt integer;
|
||||||
|
@ -177,9 +174,7 @@ void mkPath(Value& v, const char* s);
|
||||||
not included. */
|
not included. */
|
||||||
size_t valueSize(const Value& v);
|
size_t valueSize(const Value& v);
|
||||||
|
|
||||||
typedef std::map<Symbol, Value*, std::less<Symbol>,
|
using ValueMap = std::map<Symbol, Value*>;
|
||||||
traceable_allocator<std::pair<const Symbol, Value*>>>
|
|
||||||
ValueMap;
|
|
||||||
|
|
||||||
std::shared_ptr<Value*> allocRootValue(Value* v);
|
std::shared_ptr<Value*> allocRootValue(Value* v);
|
||||||
|
|
||||||
|
|
2
third_party/nix/src/nix-env/nix-env.cc
vendored
2
third_party/nix/src/nix-env/nix-env.cc
vendored
|
@ -48,7 +48,7 @@ struct InstallSourceInfo {
|
||||||
Bindings* autoArgs;
|
Bindings* autoArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Globals : public gc {
|
struct Globals {
|
||||||
InstallSourceInfo instSource;
|
InstallSourceInfo instSource;
|
||||||
Path profile;
|
Path profile;
|
||||||
std::shared_ptr<EvalState> state;
|
std::shared_ptr<EvalState> state;
|
||||||
|
|
5
third_party/nix/src/nix/repl.cc
vendored
5
third_party/nix/src/nix/repl.cc
vendored
|
@ -22,9 +22,6 @@
|
||||||
#include "libutil/finally.hh"
|
#include "libutil/finally.hh"
|
||||||
#include "nix/command.hh"
|
#include "nix/command.hh"
|
||||||
|
|
||||||
#define GC_INCLUDE_NEW
|
|
||||||
#include <gc/gc_cpp.h>
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
#define ESC_RED "\033[31m"
|
#define ESC_RED "\033[31m"
|
||||||
|
@ -35,7 +32,7 @@ namespace nix {
|
||||||
#define ESC_CYA "\033[36m"
|
#define ESC_CYA "\033[36m"
|
||||||
#define ESC_END "\033[0m"
|
#define ESC_END "\033[0m"
|
||||||
|
|
||||||
struct NixRepl : gc {
|
struct NixRepl {
|
||||||
std::string curDir;
|
std::string curDir;
|
||||||
EvalState state;
|
EvalState state;
|
||||||
Bindings* autoArgs;
|
Bindings* autoArgs;
|
||||||
|
|
5
third_party/nix/src/tests/attr-set.cc
vendored
5
third_party/nix/src/tests/attr-set.cc
vendored
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
#include <absl/container/btree_map.h>
|
#include <absl/container/btree_map.h>
|
||||||
#include <bits/stdint-intn.h>
|
#include <bits/stdint-intn.h>
|
||||||
#include <gc/gc_cpp.h>
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <rapidcheck.h>
|
#include <rapidcheck.h>
|
||||||
#include <rapidcheck/Assertions.h>
|
#include <rapidcheck/Assertions.h>
|
||||||
|
@ -55,7 +54,7 @@ struct Arbitrary<Value*> {
|
||||||
static Gen<nix::Value*> arbitrary() {
|
static Gen<nix::Value*> arbitrary() {
|
||||||
return gen::apply(
|
return gen::apply(
|
||||||
[](nix::ValueType typ, int i) {
|
[](nix::ValueType typ, int i) {
|
||||||
auto ret = new (GC) Value();
|
auto ret = new Value();
|
||||||
ret->type = typ;
|
ret->type = typ;
|
||||||
ret->integer = i;
|
ret->integer = i;
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -78,7 +77,7 @@ struct Arbitrary<nix::Pos*> {
|
||||||
static Gen<nix::Pos*> arbitrary() {
|
static Gen<nix::Pos*> arbitrary() {
|
||||||
return gen::apply(
|
return gen::apply(
|
||||||
[](unsigned int line, unsigned int column) {
|
[](unsigned int line, unsigned int column) {
|
||||||
return new (GC) Pos({}, line, column);
|
return new Pos({}, line, column);
|
||||||
},
|
},
|
||||||
gen::arbitrary<unsigned int>(), gen::arbitrary<unsigned int>());
|
gen::arbitrary<unsigned int>(), gen::arbitrary<unsigned int>());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue