Skip to content

Commit b593578

Browse files
committed
Properly comment rebind's algorithm
1 parent 9176004 commit b593578

File tree

2 files changed

+22
-3
lines changed

2 files changed

+22
-3
lines changed

vm/vm/main/store.hh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ void UnstableNode::copy(VM vm, StableNode& from) {
9797
make<Reference>(vm, &from);
9898
}
9999

100+
// WARNING This code is highly sensitive for StructuralDualWalk::rebind in unify.cc
100101
void UnstableNode::copy(VM vm, UnstableNode& from) {
101102
if (from.isCopyable()) {
102103
set(from);
@@ -207,6 +208,7 @@ void RichNode::ensureStable(VM vm) {
207208
}
208209
}
209210

211+
// WARNING This code is highly sensitive for StructuralDualWalk::rebind in unify.cc
210212
void RichNode::reinit(VM vm, StableNode& from) {
211213
if (node() == &from) {
212214
// do nothing
@@ -217,6 +219,7 @@ void RichNode::reinit(VM vm, StableNode& from) {
217219
}
218220
}
219221

222+
// WARNING This code is highly sensitive for StructuralDualWalk::rebind in unify.cc
220223
void RichNode::reinit(VM vm, UnstableNode& from) {
221224
if (node() == &from) {
222225
// do nothing
@@ -231,6 +234,7 @@ void RichNode::reinit(VM vm, UnstableNode&& from) {
231234
node()->set(from);
232235
}
233236

237+
// WARNING This code is highly sensitive for StructuralDualWalk::rebind in unify.cc
234238
void RichNode::reinit(VM vm, RichNode from) {
235239
if (from.isStable())
236240
reinit(vm, from.asStable());

vm/vm/main/unify.cc

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -465,14 +465,29 @@ bool StructuralDualWalk::processPair(VM vm, RichNode left, RichNode right) {
465465
}
466466

467467
void StructuralDualWalk::rebind(VM vm, RichNode left, RichNode right) {
468-
// XXX: The test is to work around `a.reinit(vm, b)` where `b` is sometimes
469-
// modified. It is better to reinit Unstable nodes than Stable ones anyway.
470-
// See #312 for details.
468+
// When given a Stable and an Unstable node, reinit will always alias the
469+
// unstable node to the stable one, even if it is called on the stable one.
470+
// In particular, it means that it can modify its argument, and not this.
471+
// In that case, we need to backup the variable that will be modified.
472+
// See #312 and #315 for details.
473+
//
474+
// In particular, StableNode.reinit(vm, UnstableNode) must never be called as
475+
// it updates both `left` and `right` and breaks our backup system.
476+
// To avoid that, we always call reinit on the less stable node we have.
471477
if (right.isStable()) {
478+
// `right` is stable, backup `left` because it will be aliased.
472479
rebindTrail.push_back(vm, left.makeBackup());
480+
// If both are stable, `left` must be modified (because that's the one we
481+
// have a backup for). That is why we call `left`'s reinit.
473482
left.reinit(vm, right);
474483
} else {
484+
// `right` is unstable, backup it as it will be aliased.
475485
rebindTrail.push_back(vm, right.makeBackup());
486+
// If both are unstable, they are both aliased to a stable node
487+
// initialised with reinit's second arg (`left` in this case).
488+
// By calling `right`'s reinit, we ensure that `left` is still valid
489+
// after a rollback. This leaves around an unnecessary indirection from
490+
// `left` to the new stable node, but it is the price to pay for eagerness.
476491
right.reinit(vm, left);
477492
}
478493
}

0 commit comments

Comments
 (0)