matsud224 / wamcompiler

Prolog implementation based on Warren's abstract machine
The Unlicense
38 stars 6 forks source link

Anatomy of the remaining bug #4

Closed FemtoEmacs closed 4 years ago

FemtoEmacs commented 4 years ago

I discovered that the bug appears whenever one places the cut after an arithmetic expression or unification. In these two situations, instead of obtaining a number from the stack, the cut returns something like a (REF . -23) or (CON . 1). The problem happens at the send-query definition, when the case clause pass the control to the snippet below.

  (cut (let ( (y (cadr inst)) )
              (when (and *B* *E*
                     (addr< (stack (addr+ *E* 2 y)) *B*))
                (setf *B* (stack (addr+ *E* 2 y)))
                (tidy-trail))
              (setq *P* (cdr *P*))))

Consider the following small Prolog program:

› cat ybug.pl
qua(N, F) :- N < 5, F is N + 1, !.

que(N, F) :- F is N + 1, N < 5, !.

qui(N, 3) :- N < 5, !.

The snippet qui works fine:

> ?- qui(2, F).
F = 3

yes.

However, when I try to execute qua(1, F), the application (stack (addr+ E 2 y)) produces (REF . -23), which is not a number. In consequence, I get the following error:

debugger invoked on a TYPE-ERROR in thread
#<THREAD "main thread" RUNNING {10005184C3}>:
  The value
    (REF . -23)
  is not of type
    NUMBER
  when binding SB-KERNEL::X

If I execute que(1, F), the application (stack (addr E 2 y)) produces (CON . 1) instead of a number. I examined the generated code in the two situations:

* (gethash (cons '|qua| 2) *dispatching-code-table*)
((ALLOCATE) (GET-LEVEL 1) (GET-VARIABLE-PERMANENT 3 1)
 (GET-VARIABLE-PERMANENT 2 2) (PUT-CONSTANT 5 2)
(CALL (< . 2) 3)  (PUT-UNSAFE-VALUE 2 1 3)
(PUT-STRUCTURE (+ . 2) 2)  (SET-LOCAL-VALUE-PERMANENT 3)
(SET-CONSTANT 1) (CALL (|is| . 2) 1) (CUT 1 1)
 (DEALLOCATE) (PROCEED))
T

As you can see, the bug occurs when (CUT 1 1) appears after a (PUT-UNSAFE-VALUE ...) in a clause. I wonder whether it is possible to dereference the value (RED . -23), in order to find the true index. If you don't have a solution, my suggestion is to disallow cuts after (PUT-UNSAFE-VALUE ...). This will be very easy to do, however, it would be nice not to take such a radical course of action.

By the way, I compared wamcompiler with Scryer Prolog, which is written in Rust. Wamcompiler is faster. I think that wamcompiler can be made even faster, if one replaces part of the wamcode by Lisp functions that execute a sequence of many instructions.

I am preparing a documentation for wamcompiler. I wrote a book about Visual Prolog, and I think I can easily adapt it to wamcompiler.

matsud224 commented 4 years ago

This bug was fixed by commit 2724406 (related #5). Thank you for reporting!