Skip to content

Commit

Permalink
Allocate LazyBinOp values separately from Value
Browse files Browse the repository at this point in the history
So as to not increase the sizeof(Value) from 24 bytes to 40 bytes
  • Loading branch information
infinisil committed Oct 21, 2020
1 parent 5b1ef7b commit 152048d
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 44 deletions.
14 changes: 4 additions & 10 deletions src/libexpr/eval-inline.hh
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,14 @@ void EvalState::forceValue(Value & v, const Pos & pos)
}
}
else if (v.type == tLazyBinOp) {
Env * env = v.lazyBinOp.env;
ExprLazyBinOp * expr = v.lazyBinOp.expr;
Value * left = v.lazyBinOp.left;
Value * right = v.lazyBinOp.right;
Value::LazyBinOp * lazyBinOp = v.lazyBinOp;
try {
v.type = tBlackhole;
//checkInterrupt();
expr->evalLazyBinOp(*this, *env, v);
lazyBinOp->expr->evalLazyBinOp(*this, *lazyBinOp->env, v);
} catch (...) {
v.type = tLazyBinOp;
v.lazyBinOp.env = env;
v.lazyBinOp.expr = expr;
v.lazyBinOp.left = left;
v.lazyBinOp.right = right;
v.lazyBinOp = lazyBinOp;
throw;
}
}
Expand All @@ -78,7 +72,7 @@ Attr * EvalState::evalValueAttr(Value & v, const Symbol & name, const Pos & pos)
return v.thunk.expr->evalAttr(*this, *v.thunk.env, v, name);
}
else if (v.type == tLazyBinOp) {
return v.lazyBinOp.expr->evalLazyBinOpAttr(*this, *v.lazyBinOp.env, v, name);
return v.lazyBinOp->expr->evalLazyBinOpAttr(*this, *v.lazyBinOp->env, v, name);
}
else if (v.type == tApp) {
return callFunctionAttr(*v.app.left, *v.app.right, v, name, pos);
Expand Down
71 changes: 43 additions & 28 deletions src/libexpr/eval.cc
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,12 @@ Value * EvalState::allocValue()
return v;
}

Value::LazyBinOp * EvalState::allocLazyBinOpValue()
{
nrLazyBinOpValues++;
auto v = (Value::LazyBinOp *) allocBytes(sizeof(Value::LazyBinOp));
return v;
}

Env & EvalState::allocEnv(size_t size)
{
Expand Down Expand Up @@ -1836,17 +1842,17 @@ void ExprOpUpdate::updateAttrs(EvalState & state, const Value & v1, const Value
void ExprOpUpdate::evalLazyBinOp(EvalState & state, Env & env, Value & v)
{
Value v1;
if (v.type == tLazyBinOp && v.lazyBinOp.left) {
state.forceAttrs(*v.lazyBinOp.left);
v1 = *v.lazyBinOp.left;
if (v.type == tLazyBinOp && v.lazyBinOp->left) {
state.forceAttrs(*v.lazyBinOp->left);
v1 = *v.lazyBinOp->left;
} else {
state.evalAttrs(env, e1, v1);
}

Value v2;
if (v.type == tLazyBinOp && v.lazyBinOp.right) {
state.forceAttrs(*v.lazyBinOp.right);
v2 = *v.lazyBinOp.right;
if (v.type == tLazyBinOp && v.lazyBinOp->right) {
state.forceAttrs(*v.lazyBinOp->right);
v2 = *v.lazyBinOp->right;
} else {
state.evalAttrs(env, e2, v2);
}
Expand All @@ -1864,11 +1870,12 @@ Attr * ExprOpUpdate::evalLazyBinOpAttr(EvalState & state, Env & env, Value & v,
Attr * onRight = e2->evalAttr(state, env, v2, name);
if (onRight) {
v.type = tLazyBinOp;
v.lazyBinOp.expr = this;
v.lazyBinOp.env = &env;
v.lazyBinOp.left = nullptr;
v.lazyBinOp.right = state.allocValue();
*v.lazyBinOp.right = v2;
v.lazyBinOp = state.allocLazyBinOpValue();
v.lazyBinOp->expr = this;
v.lazyBinOp->env = &env;
v.lazyBinOp->left = nullptr;
v.lazyBinOp->right = state.allocValue();
*v.lazyBinOp->right = v2;
return onRight;
} else {
Value v1;
Expand All @@ -1878,39 +1885,40 @@ Attr * ExprOpUpdate::evalLazyBinOpAttr(EvalState & state, Env & env, Value & v,
return onLeft;
} else {
v.type = tLazyBinOp;
v.lazyBinOp.expr = this;
v.lazyBinOp.env = &env;
v.lazyBinOp.left = state.allocValue();
*v.lazyBinOp.left = v1;
v.lazyBinOp.right = state.allocValue();
*v.lazyBinOp.right = v2;
v.lazyBinOp = state.allocLazyBinOpValue();
v.lazyBinOp->expr = this;
v.lazyBinOp->env = &env;
v.lazyBinOp->left = state.allocValue();
*v.lazyBinOp->left = v1;
v.lazyBinOp->right = state.allocValue();
*v.lazyBinOp->right = v2;
return onLeft;
}
}
} else {
// We know that v.type == tLazyBinOp and that v.lazyBinOp.right != nullptr because that's all the above case can return

Attr * onRight = state.evalValueAttr(*v.lazyBinOp.right, name, pos);
Attr * onRight = state.evalValueAttr(*v.lazyBinOp->right, name, pos);
if (onRight) {
if (v.lazyBinOp.right->type == tAttrs && v.lazyBinOp.left && v.lazyBinOp.left->type == tAttrs) {
updateAttrs(state, *v.lazyBinOp.left, *v.lazyBinOp.right, v);
if (v.lazyBinOp->right->type == tAttrs && v.lazyBinOp->left && v.lazyBinOp->left->type == tAttrs) {
updateAttrs(state, *v.lazyBinOp->left, *v.lazyBinOp->right, v);
}
return onRight;
} else {
if (v.lazyBinOp.left) {
Attr * onLeft = state.evalValueAttr(*v.lazyBinOp.left, name, pos);
if (v.lazyBinOp.right->type == tAttrs && v.lazyBinOp.left->type == tAttrs) {
updateAttrs(state, *v.lazyBinOp.left, *v.lazyBinOp.right, v);
if (v.lazyBinOp->left) {
Attr * onLeft = state.evalValueAttr(*v.lazyBinOp->left, name, pos);
if (v.lazyBinOp->right->type == tAttrs && v.lazyBinOp->left->type == tAttrs) {
updateAttrs(state, *v.lazyBinOp->left, *v.lazyBinOp->right, v);
}
return onLeft;
} else {
Value v1;
Attr * onLeft = e1->evalAttr(state, env, v1, name);
if (v1.type == tAttrs && v.lazyBinOp.right->type == tAttrs) {
updateAttrs(state, v1, *v.lazyBinOp.right, v);
if (v1.type == tAttrs && v.lazyBinOp->right->type == tAttrs) {
updateAttrs(state, v1, *v.lazyBinOp->right, v);
} else {
v.lazyBinOp.left = state.allocValue();
*v.lazyBinOp.left = v1;
v.lazyBinOp->left = state.allocValue();
*v.lazyBinOp->left = v1;
}
return onLeft;
}
Expand Down Expand Up @@ -2386,6 +2394,7 @@ void EvalState::printStats()
uint64_t bEnvs = nrEnvs * sizeof(Env) + nrValuesInEnvs * sizeof(Value *);
uint64_t bLists = nrListElems * sizeof(Value *);
uint64_t bValues = nrValues * sizeof(Value);
uint64_t bLazyBinOpValues = nrLazyBinOpValues * sizeof(Value::LazyBinOp);
uint64_t bAttrsets = nrAttrsets * sizeof(Bindings) + nrAttrsInAttrsets * sizeof(Attr);

#if HAVE_BOEHMGC
Expand Down Expand Up @@ -2416,6 +2425,11 @@ void EvalState::printStats()
values.attr("number", nrValues);
values.attr("bytes", bValues);
}
{
auto lazyBinOpValues = topObj.object("lazyBinOpValues");
lazyBinOpValues.attr("number", nrLazyBinOpValues);
lazyBinOpValues.attr("bytes", bLazyBinOpValues);
}
{
auto syms = topObj.object("symbols");
syms.attr("number", symbols.size());
Expand All @@ -2431,6 +2445,7 @@ void EvalState::printStats()
auto sizes = topObj.object("sizes");
sizes.attr("Env", sizeof(Env));
sizes.attr("Value", sizeof(Value));
sizes.attr("Value::LazyBinOp", sizeof(Value::LazyBinOp));
sizes.attr("Bindings", sizeof(Bindings));
sizes.attr("Attr", sizeof(Attr));
}
Expand Down
2 changes: 2 additions & 0 deletions src/libexpr/eval.hh
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ public:

/* Allocation primitives. */
Value * allocValue();
Value::LazyBinOp * allocLazyBinOpValue();
Env & allocEnv(size_t size);

Value * allocAttr(Value & vAttrs, const Symbol & name);
Expand All @@ -319,6 +320,7 @@ private:
unsigned long nrEnvs = 0;
unsigned long nrValuesInEnvs = 0;
unsigned long nrValues = 0;
unsigned long nrLazyBinOpValues = 0;
unsigned long nrListElems = 0;
unsigned long nrAttrsets = 0;
unsigned long nrAttrsInAttrsets = 0;
Expand Down
16 changes: 10 additions & 6 deletions src/libexpr/value.hh
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@ std::ostream & operator << (std::ostream & str, const ExternalValueBase & v);

struct Value
{

// Stored separately from Value as to not increase sizeof(Value)
struct LazyBinOp {
Env * env;
ExprLazyBinOp * expr;
Value * left;
Value * right;
};

ValueType type;
union
{
Expand Down Expand Up @@ -134,12 +143,7 @@ struct Value
Env * env;
Expr * expr;
} thunk;
struct {
Env * env;
ExprLazyBinOp * expr;
Value * left;
Value * right;
} lazyBinOp;
LazyBinOp * lazyBinOp;
struct {
Value * left, * right;
} app;
Expand Down

0 comments on commit 152048d

Please sign in to comment.