Skip to content

Commit e200085

Browse files
committed
add backward looking cyclicity check for variables in cycle detecting stackless iterator (#2111, #2117)
1 parent 3a6aee7 commit e200085

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

src/machine/gc.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,15 @@ 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)
16+
where
17+
Self: Sized {}
18+
fn detect_list_tail_cycle(_iter: &mut StacklessPreOrderHeapIter<Self>) where Self: Sized {}
1519
fn list_head_cycle_detecting_backward(
1620
iter: &mut StacklessPreOrderHeapIter<Self>,
1721
) -> bool where Self: Sized {
1822
iter.backward()
1923
}
20-
fn detect_list_tail_cycle(_iter: &mut StacklessPreOrderHeapIter<Self>) where Self: Sized {}
2124
}
2225

2326
pub(crate) struct IteratorUMP {
@@ -89,15 +92,21 @@ impl UnmarkPolicy for CycleDetectorUMP {
8992
iter: &mut StacklessPreOrderHeapIter<Self>,
9093
) -> bool {
9194
if !iter.iter_state.cycle_detected && iter.iter_state.mark_phase {
92-
iter.iter_state.cycle_detected = iter.detect_list_cycle();
95+
iter.iter_state.cycle_detected = iter.detect_list_cycle(iter.current);
9396
}
9497

9598
iter.backward()
9699
}
97100

98101
fn detect_list_tail_cycle(iter: &mut StacklessPreOrderHeapIter<Self>) {
99102
if iter.iter_state.mark_phase && !iter.iter_state.cycle_detected {
100-
iter.iter_state.cycle_detected = iter.detect_list_cycle();
103+
iter.iter_state.cycle_detected = iter.detect_list_cycle(iter.current);
104+
}
105+
}
106+
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 {
109+
iter.iter_state.cycle_detected = iter.detect_list_cycle(next);
101110
}
102111
}
103112
}
@@ -200,20 +209,20 @@ impl<'a> StacklessPreOrderHeapIter<'a, CycleDetectorUMP> {
200209
self.iter_state.cycle_detected
201210
}
202211

203-
pub(crate) fn detect_list_cycle(&self) -> bool {
212+
pub(crate) fn detect_list_cycle(&self, next: usize) -> bool {
204213
use crate::machine::system_calls::BrentAlgState;
205214

206215
let mut brent_alg_st = BrentAlgState::new(self.current);
207216

208217
while self.heap[brent_alg_st.hare].get_mark_bit() {
209218
let temp = self.heap[brent_alg_st.hare].get_value() as usize;
210219

211-
if brent_alg_st.step(temp).is_some() || temp == self.current {
220+
if brent_alg_st.step(temp).is_some() || temp == next {
212221
return true;
213222
}
214223

215224
if temp == self.start {
216-
return self.heap[temp].get_value() == self.current as u64;
225+
break;
217226
}
218227
}
219228

@@ -272,7 +281,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
272281
#[inline]
273282
fn is_cyclic(&self, var_current: usize, var_next: usize) -> bool {
274283
if self.heap[var_next].is_var() {
275-
!self.heap[var_next].get_forwarding_bit() && var_current != var_next
284+
self.heap[var_next].get_mark_bit() && var_current != var_next
276285
} else if self.heap[var_next].is_ref() {
277286
self.heap[var_next].get_mark_bit()
278287
} else {
@@ -296,6 +305,8 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
296305
}
297306

298307
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);
299310
}
300311

301312
if self.next < self.heap.len() as u64 {
@@ -315,6 +326,8 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
315326
}
316327

317328
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);
318331
}
319332

320333
if self.next < self.heap.len() as u64 {

src/tests/acyclic_term.pl

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
D=[_E|C],
2525
A=[C|D].
2626

27+
term6(A) :-
28+
A=[B|B],
29+
B=[C|C].
30+
2731
test("acyclic_term_1", (
2832
L = [_Y,[M,B],B|M], acyclic_term(L)
2933
)).
@@ -165,6 +169,10 @@
165169
term5(A), \+ acyclic_term(A)
166170
)).
167171

172+
test("acyclic_term#2111_6", (
173+
term6(A), acyclic_term(A)
174+
)).
175+
168176
test("acyclic_term#2113", (
169177
A=[]*B,B=[]*B, \+ acyclic_term(A)
170178
)).
@@ -177,6 +185,10 @@
177185
A=B*B,B=[]*[], acyclic_term(A)
178186
)).
179187

188+
test("acyclic_term#2117", (
189+
A=[]*A,B=[]*A, \+ acyclic_term(B)
190+
)).
191+
180192
main :-
181193
findall(test(Name, Goal), test(Name, Goal), Tests),
182194
run_tests(Tests, Failed),
@@ -188,7 +200,7 @@
188200
run_tests_quiet(Tests, Failed),
189201
( Failed = [] ->
190202
format("All tests passed", [])
191-
; format("Some tests failed", [])
203+
; format("Some tests failed: ~w~n", [Failed])
192204
),
193205
halt.
194206

0 commit comments

Comments
 (0)