Skip to content

Commit dff2e73

Browse files
committed
more eagerly check for cyclicity of variables in cycle detecting stackless iterator (#2121)
1 parent e200085 commit dff2e73

File tree

2 files changed

+33
-17
lines changed

2 files changed

+33
-17
lines changed

src/machine/gc.rs

+22-16
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub(crate) trait UnmarkPolicy {
1212
fn invert_marker(iter: &mut StacklessPreOrderHeapIter<Self>) where Self: Sized;
1313
fn cycle_detected(&mut self) where Self: Sized;
1414
fn mark_phase(&self) -> bool;
15-
fn var_rooted_cycle(_iter: &mut StacklessPreOrderHeapIter<Self>, _var_loc: usize, _next: usize)
15+
fn var_rooted_cycle(_iter: &mut StacklessPreOrderHeapIter<Self>, _next: usize)
1616
where
1717
Self: Sized {}
1818
fn detect_list_tail_cycle(_iter: &mut StacklessPreOrderHeapIter<Self>) where Self: Sized {}
@@ -104,8 +104,8 @@ impl UnmarkPolicy for CycleDetectorUMP {
104104
}
105105
}
106106

107-
fn var_rooted_cycle(iter: &mut StacklessPreOrderHeapIter<Self>, var_loc: usize, next: usize) {
108-
if var_loc != next && iter.iter_state.mark_phase && !iter.iter_state.cycle_detected {
107+
fn var_rooted_cycle(iter: &mut StacklessPreOrderHeapIter<Self>, next: usize) {
108+
if iter.current != next && iter.iter_state.mark_phase && !iter.iter_state.cycle_detected {
109109
iter.iter_state.cycle_detected = iter.detect_list_cycle(next);
110110
}
111111
}
@@ -279,9 +279,13 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
279279
}
280280

281281
#[inline]
282-
fn is_cyclic(&self, var_current: usize, var_next: usize) -> bool {
282+
fn is_cyclic(&self, var_current: usize, var_next: usize, var_f: bool) -> bool {
283283
if self.heap[var_next].is_var() {
284-
self.heap[var_next].get_mark_bit() && var_current != var_next
284+
// the third conjunct covers the case where var_current
285+
// was just unforwarded by forward_var() and so
286+
// self.current + 1 == var_current. see acyclic_term#2121
287+
// & acyclic_term_30 for examples of how this occurs.
288+
self.heap[var_next].get_mark_bit() && var_current != var_next && !var_f
285289
} else if self.heap[var_next].is_ref() {
286290
self.heap[var_next].get_mark_bit()
287291
} else {
@@ -298,15 +302,18 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
298302
HeapCellValueTag::AttrVar => {
299303
let next = self.next;
300304
let current = self.current;
305+
let f = self.heap[self.current].get_forwarding_bit();
306+
307+
if self.heap[next as usize].get_mark_bit() == self.iter_state.mark_phase() {
308+
UMP::var_rooted_cycle(self, next as usize);
309+
}
301310

302311
if let Some(cell) = UMP::forward_attr_var(self) {
303-
if self.is_cyclic(current, next as usize) {
312+
if self.is_cyclic(current, next as usize, f) {
304313
self.iter_state.cycle_detected();
305314
}
306315

307316
return Some(cell);
308-
} else if self.heap[next as usize].get_mark_bit() == self.iter_state.mark_phase() {
309-
UMP::var_rooted_cycle(self, current, next as usize);
310317
}
311318

312319
if self.next < self.heap.len() as u64 {
@@ -319,15 +326,18 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
319326
HeapCellValueTag::Var => {
320327
let next = self.next;
321328
let current = self.current;
329+
let f = self.heap[self.current].get_forwarding_bit();
330+
331+
if self.heap[next as usize].get_mark_bit() == self.iter_state.mark_phase() {
332+
UMP::var_rooted_cycle(self, next as usize);
333+
}
322334

323335
if let Some(cell) = self.forward_var() {
324-
if self.is_cyclic(current, next as usize) {
336+
if self.is_cyclic(current, next as usize, f) {
325337
self.iter_state.cycle_detected();
326338
}
327339

328340
return Some(cell);
329-
} else if self.heap[next as usize].get_mark_bit() == self.iter_state.mark_phase() {
330-
UMP::var_rooted_cycle(self, current, next as usize);
331341
}
332342

333343
if self.next < self.heap.len() as u64 {
@@ -462,11 +472,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
462472
}
463473
}
464474
} else {
465-
if self.heap[self.current].get_tag() == HeapCellValueTag::Lis {
466-
if UMP::list_head_cycle_detecting_backward(self) {
467-
return None;
468-
}
469-
} else if self.backward() {
475+
if self.backward() {
470476
return None;
471477
}
472478
}

src/tests/acyclic_term.pl

+11-1
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,11 @@
149149
acyclic_term(B), acyclic_term(Y)
150150
)).
151151

152+
test("acyclic_term_30", (
153+
A=str(B,B,B), C=str(A,_D,B), acyclic_term(C),
154+
acyclic_term(A), acyclic_term(B)
155+
)).
156+
152157
test("acyclic_term#2111_1", (
153158
term1(A), \+ acyclic_term(A)
154159
)).
@@ -189,6 +194,11 @@
189194
A=[]*A,B=[]*A, \+ acyclic_term(B)
190195
)).
191196

197+
test("acyclic_term#2121", (
198+
A=B*B, C=A*B, acyclic_term(C),
199+
acyclic_term(A), acyclic_term(B)
200+
)).
201+
192202
main :-
193203
findall(test(Name, Goal), test(Name, Goal), Tests),
194204
run_tests(Tests, Failed),
@@ -200,7 +210,7 @@
200210
run_tests_quiet(Tests, Failed),
201211
( Failed = [] ->
202212
format("All tests passed", [])
203-
; format("Some tests failed: ~w~n", [Failed])
213+
; format("Some tests failed", [])
204214
),
205215
halt.
206216

0 commit comments

Comments
 (0)