1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-15 15:02:42 +01:00

Remove a word from Env

This commit is contained in:
Eelco Dolstra 2019-04-23 01:11:50 +02:00
parent ae5b76a5a4
commit e392ff53e9
4 changed files with 55 additions and 31 deletions

View file

@ -523,8 +523,6 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
{
for (size_t l = var.level; l; --l, env = env->up) ;
assert(((Object *) env)->type == tEnv);
if (!var.fromWith) {
auto v = env->values[var.displ];
if (v) gc.assertObject(v);
@ -532,12 +530,12 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
}
while (1) {
if (env->type == Env::HasWithExpr) {
if (env->type == tWithExprEnv) {
if (noEval) return 0;
auto v = allocValue();
evalAttrs(*env->up, (Expr *) env->values[0], *v);
env->values[0] = v;
env->type = Env::HasWithAttrs;
env->type = tWithAttrsEnv;
}
Bindings::iterator j = env->values[0]->attrs->find(var.name);
if (j != env->values[0]->attrs->end()) {
@ -545,9 +543,9 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
gc.assertObject(j->value);
return j->value;
}
if (!env->prevWith)
if (!env->getPrevWith())
throwUndefinedVarError("undefined variable '%1%' at %2%", var.name, var.pos);
for (size_t l = env->prevWith; l; --l, env = env->up) ;
for (size_t l = env->getPrevWith(); l; --l, env = env->up) ;
}
}
@ -559,15 +557,11 @@ Ptr<Value> EvalState::allocValue()
}
Ptr<Env> EvalState::allocEnv(size_t size)
Ptr<Env> EvalState::allocEnv(size_t size, size_t prevWith, Tag type)
{
if (size > std::numeric_limits<decltype(Env::size)>::max()) // FIXME
throw Error("environment size %d is too big", size);
nrEnvs++;
nrValuesInEnvs += size;
return gc.alloc<Env>(Env::wordsFor(size), size);
return gc.alloc<Env>(Env::wordsFor(size), type, size, prevWith);
}
@ -1181,12 +1175,9 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
void ExprWith::eval(EvalState & state, Env & env, Value & v)
{
auto env2 = state.allocEnv(1);
auto env2 = state.allocEnv(1, prevWith, tWithExprEnv);
env2->up = &env;
env2->prevWith = prevWith;
env2->type = Env::HasWithExpr;
env2->values[0] = (Value *) attrs;
body->eval(state, env2, v);
}
@ -1880,10 +1871,10 @@ size_t valueSize(Value & v)
if (seen.find(&env) != seen.end()) return 0;
seen.insert(&env);
size_t sz = sizeof(Env) + sizeof(Value *) * env.size;
size_t sz = sizeof(Env) + sizeof(Value *) * env.getSize();
if (env.type != Env::HasWithExpr)
for (size_t i = 0; i < env.size; ++i)
if (env.type != tWithExprEnv)
for (size_t i = 0; i < env.getSize(); ++i)
if (env.values[i])
sz += doValue(*env.values[i]);

View file

@ -36,16 +36,23 @@ struct PrimOp
struct Env : Object
{
Env * up;
// FIXME: use misc field
unsigned short size; // used by valueSize
unsigned short prevWith:14; // nr of levels up to next `with' environment
enum { Plain = 0, HasWithExpr, HasWithAttrs } type:2; // FIXME: fold into type?
Value * values[0];
private:
Env(unsigned short size) : Object(tEnv, 0), size(size) {
for (auto i = 0; i < size; i++)
constexpr static size_t maxSize = 1 << 16;
constexpr static size_t maxPrevWith = 1 << 10;
Env(Tag type, size_t size, size_t prevWith)
: Object(type, size | (prevWith << 16))
{
if (size >= maxSize)
throw Error("environment size %d is too big", size);
if (prevWith >= maxPrevWith)
throw Error("too many nesting levels");
for (size_t i = 0; i < size; i++)
values[i] = nullptr;
}
@ -53,14 +60,24 @@ private:
public:
unsigned short getPrevWith() const
{
return getMisc() >> 16;
}
unsigned short getSize() const
{
return getMisc() & 0xffff;
}
Size words() const
{
return wordsFor(size);
return wordsFor(getSize());
}
static Size wordsFor(unsigned short size)
{
return 3 + size; // FIXME
return 2 + size;
}
};
@ -276,7 +293,7 @@ public:
/* Allocation primitives. */
Ptr<Value> allocValue();
Ptr<Env> allocEnv(size_t size);
Ptr<Env> allocEnv(size_t size, size_t prevWith = 0, Tag type = tEnv);
// Note: the resulting Value is only reachable as long as vAttrs
// is reachable.

View file

@ -82,9 +82,21 @@ void GC::gc()
case tEnv: {
auto obj2 = (Env *) obj;
push(obj2->up);
if (obj2->type != Env::HasWithExpr)
for (auto i = obj2->values; i < obj2->values + obj2->size; ++i)
push(*i);
for (auto i = obj2->values; i < obj2->values + obj2->getSize(); ++i)
push(*i);
break;
}
case tWithExprEnv: {
auto obj2 = (Env *) obj;
push(obj2->up);
break;
}
case tWithAttrsEnv: {
auto obj2 = (Env *) obj;
push(obj2->up);
push(obj2->values[0]);
break;
}
@ -229,6 +241,8 @@ std::pair<Size, Size> GC::Arena::freeUnmarked()
objSize = ((PtrList<Value> *) obj)->words();
break;
case tEnv:
case tWithExprEnv:
case tWithAttrsEnv:
objSize = ((Env *) obj)->words();
break;
default:

View file

@ -18,6 +18,8 @@ enum Tag {
tBindings,
tValueList,
tEnv,
tWithExprEnv,
tWithAttrsEnv,
// Value tags
tInt,